From 0eb2fd82d5f2dcbf54baf5b7ca5fc0285cb3a9ea Mon Sep 17 00:00:00 2001 From: Pierre Boutillier Date: Sat, 18 Sep 2021 11:29:40 +0200 Subject: [PATCH 1/9] Proto/Test: open modules in dune to ease snapshotting --- .../lib_benchmarks_proto/michelson_generation.mli | 9 +++------ src/proto_alpha/lib_protocol/test/dune | 1 + .../lib_protocol/test/test_script_typed_ir_size.ml | 11 +++-------- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/proto_alpha/lib_benchmarks_proto/michelson_generation.mli b/src/proto_alpha/lib_benchmarks_proto/michelson_generation.mli index ee299184b54b..3e444c15dbc1 100644 --- a/src/proto_alpha/lib_benchmarks_proto/michelson_generation.mli +++ b/src/proto_alpha/lib_benchmarks_proto/michelson_generation.mli @@ -76,8 +76,7 @@ val load : filename:string -> michelson_data list (** [base_type_to_michelson_type] converts a type as produced by the type inference engine in {!Tezos_benchmark_type_inference_alpha.Inference} to a type in IR form. *) -val base_type_to_michelson_type : - Tezos_benchmark_type_inference_alpha.Type.Base.t -> Script_repr.expr +val base_type_to_michelson_type : Type.Base.t -> Script_repr.expr (** [michelson_type_list_to_ex_stack_ty] converts a list of types in Micheline form to a stack type in IR form. *) @@ -98,9 +97,7 @@ val michelson_type_to_ex_ty : type inference engine in {!Tezos_benchmark_type_inference_alpha.Inference} into a type in IR form. *) val base_type_to_ex_ty : - Tezos_benchmark_type_inference_alpha.Type.Base.t -> - Alpha_context.t -> - Script_ir_translator.ex_ty * Alpha_context.t + Type.Base.t -> Alpha_context.t -> Script_ir_translator.ex_ty * Alpha_context.t (** [stack_type_to_ex_stack_ty] converts a stack type as produced by the type inference engine in {!Tezos_benchmark_type_inference_alpha.Inference} @@ -108,7 +105,7 @@ val base_type_to_ex_ty : @raise Failure if a stack type variable occurs in the argument. *) val stack_type_to_ex_stack_ty : - Tezos_benchmark_type_inference_alpha.Type.Stack.t -> + Type.Stack.t -> Alpha_context.t -> Script_ir_translator.ex_stack_ty * Alpha_context.t diff --git a/src/proto_alpha/lib_protocol/test/dune b/src/proto_alpha/lib_protocol/test/dune index 14fd104dabbf..18393eb10998 100644 --- a/src/proto_alpha/lib_protocol/test/dune +++ b/src/proto_alpha/lib_protocol/test/dune @@ -28,6 +28,7 @@ -open Tezos_protocol_plugin_alpha -open Tezos_protocol_environment_alpha -open Tezos_benchmark_alpha + -open Tezos_benchmark_type_inference_alpha -open Tezos_alpha_test_helpers -open Tezos_base_test_helpers))) diff --git a/src/proto_alpha/lib_protocol/test/test_script_typed_ir_size.ml b/src/proto_alpha/lib_protocol/test/test_script_typed_ir_size.ml index f939b1d7e783..26ab34703bd2 100644 --- a/src/proto_alpha/lib_protocol/test/test_script_typed_ir_size.ml +++ b/src/proto_alpha/lib_protocol/test/test_script_typed_ir_size.ml @@ -31,7 +31,6 @@ Subject: Script_typed_ir computes good approximation of values' sizes *) -open Tezos_benchmark_alpha open Protocol (* @@ -118,16 +117,12 @@ module Samplers = struct let generator = Gen.generator ~burn_in:(500 * 7) - let base_type_to_michelson_type - (typ : Tezos_benchmark_type_inference_alpha.Type.Base.t) = - let open Tezos_benchmark_type_inference_alpha in + let base_type_to_michelson_type (typ : Type.Base.t) = let typ = Mikhailsky.map_var (fun _ -> Mikhailsky.unit_ty) typ in Mikhailsky.to_michelson typ (* Convert a Mikhailsky stack to a list of Micheline-encoded types *) - let rec stack_type_to_michelson_type_list - (typ : Tezos_benchmark_type_inference_alpha.Type.Stack.t) = - let open Tezos_benchmark_type_inference_alpha in + let rec stack_type_to_michelson_type_list (typ : Type.Stack.t) = let node = typ.node in match node with | Type.Stack.Stack_var_t _ -> @@ -201,7 +196,7 @@ module Printers = struct f ctxt >>= wrap >>=? fun node -> let printable = Micheline_printer.printable - Tezos_protocol_alpha.Protocol.Michelson_v1_primitives.string_of_prim + Protocol.Michelson_v1_primitives.string_of_prim node in let b = Buffer.create 13 in -- GitLab From b6dc717c06f40c28c5d932cb05dc323a0a4a7981 Mon Sep 17 00:00:00 2001 From: Pierre Boutillier Date: Sun, 19 Sep 2021 18:17:51 +0200 Subject: [PATCH 2/9] Proto/Test: abstract proto name to ease snapshoting in GTOC tests --- .../test/helpers/test_global_constants.ml | 7 +++++-- .../test/test_global_constants_storage.ml | 11 +++++++---- .../test/unit/test_global_constants_storage.ml | 16 +++++++--------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/helpers/test_global_constants.ml b/src/proto_alpha/lib_protocol/test/helpers/test_global_constants.ml index 38965a85ae78..84039ceeb4ff 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/test_global_constants.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/test_global_constants.ml @@ -43,8 +43,11 @@ let assert_expr_equal loc = "Michelson Expressions Not Equal" Michelson_v1_printer.print_expr -let assert_error_id loc id result = - let test err = (Error_monad.find_info_of_error err).id = id in +let assert_proto_error_id loc id result = + let test err = + (Error_monad.find_info_of_error err).id + = "proto." ^ Protocol.name ^ "." ^ id + in Assert.error ~loc result test let assert_ok_lwt x = diff --git a/src/proto_alpha/lib_protocol/test/test_global_constants_storage.ml b/src/proto_alpha/lib_protocol/test/test_global_constants_storage.ml index 3a384a815690..e9c1f74cefc7 100644 --- a/src/proto_alpha/lib_protocol/test/test_global_constants_storage.ml +++ b/src/proto_alpha/lib_protocol/test/test_global_constants_storage.ml @@ -46,8 +46,11 @@ let assert_expr_equal loc = "Michelson Expressions Not Equal" Michelson_v1_printer.print_expr -let assert_error_id loc id result = - let test err = (Error_monad.find_info_of_error err).id = id in +let assert_proto_error_id loc id result = + let test err = + (Error_monad.find_info_of_error err).id + = "proto." ^ Protocol.name ^ "." ^ id + in Assert.error ~loc result test let expr_to_hash expr = @@ -99,7 +102,7 @@ let test_registration_of_bad_expr_fails () = ~value:(Script_repr.lazy_expr expr) >>=? fun op -> Incremental.add_operation b op - >>= assert_error_id __LOC__ "proto.alpha.Badly_formed_constant_expression" + >>= assert_proto_error_id __LOC__ "Badly_formed_constant_expression" (* You cannot register the same expression twice. *) let test_no_double_register () = @@ -119,7 +122,7 @@ let test_no_double_register () = ~value:(Script_repr.lazy_expr expr) >>=? fun op -> Incremental.add_operation b op - >>= assert_error_id __LOC__ "proto.alpha.Expression_already_registered" + >>= assert_proto_error_id __LOC__ "Expression_already_registered" let tests = [ diff --git a/src/proto_alpha/lib_protocol/test/unit/test_global_constants_storage.ml b/src/proto_alpha/lib_protocol/test/unit/test_global_constants_storage.ml index cfb07c758e30..774e3c7cd12d 100644 --- a/src/proto_alpha/lib_protocol/test/unit/test_global_constants_storage.ml +++ b/src/proto_alpha/lib_protocol/test/unit/test_global_constants_storage.ml @@ -54,7 +54,7 @@ let test_get_on_nonexistent_fails = expr_to_hash expr |> Environment.wrap_tzresult >>?= fun hash -> Global_constants_storage.get context hash >|= Environment.wrap_tzresult - >>= assert_error_id __LOC__ "proto.alpha.Nonexistent_global") + >>= assert_proto_error_id __LOC__ "Nonexistent_global") (** If registering an expression yields a hash [h] and context [c], then [get c h] should yield the original expression. *) @@ -84,7 +84,7 @@ let test_register_fails_with_unregistered_references = create_context () >>=? fun context -> Global_constants_storage.register context prim_with_constant >|= Environment.wrap_tzresult - >>= assert_error_id __LOC__ "proto.alpha.Nonexistent_global") + >>= assert_proto_error_id __LOC__ "Nonexistent_global") (** Same test as [test_register_fails_with_unregistered_references] but with random values. *) @@ -98,7 +98,7 @@ let test_register_fails_with_unregistered_references_pbt = assume_expr_not_too_large expr ; Global_constants_storage.register context expr >|= Environment.wrap_tzresult - >>= assert_error_id __LOC__ "proto.alpha.Nonexistent_global") + >>= assert_proto_error_id __LOC__ "Nonexistent_global") let rec grow n node = match n with n when n <= 0 -> node | n -> grow (n - 1) (Seq (-1, [node])) @@ -117,7 +117,7 @@ let test_register_fails_if_too_deep = create_context () >>=? fun context -> Global_constants_storage.register context vdeep_expr >|= Environment.wrap_tzresult - >>= assert_error_id __LOC__ "proto.alpha.Expression_too_deep") + >>= assert_proto_error_id __LOC__ "Expression_too_deep") (** [expand] on an expression containing a nonexistent global constant returns an error. *) @@ -132,7 +132,7 @@ let test_expand_nonexistent_fails = assume_expr_not_too_large expr ; Global_constants_storage.expand context expr >|= Environment.wrap_tzresult - >>= assert_error_id __LOC__ "proto.alpha.Nonexistent_global" + >>= assert_proto_error_id __LOC__ "Nonexistent_global" (** Expanding an expression without constants should yield the same expression. *) let test_expand_no_constants = @@ -240,9 +240,7 @@ let test_expand_reject_ill_formed = let expected = Expr.from_string expr in Global_constants_storage.expand context expected >|= Environment.wrap_tzresult - >>= assert_error_id - __LOC__ - "proto.alpha.Badly_formed_constant_expression" + >>= assert_proto_error_id __LOC__ "Badly_formed_constant_expression" in (* constant with an argument other than String fails *) test "constant 9" >>=? fun () -> @@ -293,7 +291,7 @@ let test_reject_use_of_inner_constant = (Expr.from_string @@ Format.sprintf "{ constant (constant \"%s\") } " hash) >|= Environment.wrap_tzresult - >>= assert_error_id __LOC__ "proto.alpha.Badly_formed_constant_expression") + >>= assert_proto_error_id __LOC__ "Badly_formed_constant_expression") (** [test_expand] accepts an expression [stored] to be registered in the store, an expression [expr] that includes a template slot for -- GitLab From 808707495603fcdba52be1409401436e2859b511 Mon Sep 17 00:00:00 2001 From: Romain Bardou Date: Mon, 20 Sep 2021 09:51:29 +0200 Subject: [PATCH 3/9] Scripts: link_protocol.sh also updates proxy_server --- scripts/link_protocol.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/link_protocol.sh b/scripts/link_protocol.sh index d42556b2dc35..3fc89e5fbdc7 100755 --- a/scripts/link_protocol.sh +++ b/scripts/link_protocol.sh @@ -143,3 +143,12 @@ duplicate_and_replace_only_1_occ -${pattern} -${replacement} \ src/bin_codec/dune duplicate_and_replace -${pattern} -${replacement} \ src/bin_codec/tezos-codec.opam + +# activate in proxy +duplicate_and_replace_when_3_occ -${pattern} -${replacement} \ + src/bin_proxy_server/dune +duplicate_and_replace_only_1_occ -${pattern} -${replacement} \ + src/bin_proxy_server/dune +# TODO: currently there is no protocol in the .opam, but there should be +#duplicate_and_replace -${pattern} -${replacement} \ +# src/bin_proxy_server/tezos-proxy-server.opam -- GitLab From 67a2552f4d1d6c73938b1bfbb673cd19a58779c0 Mon Sep 17 00:00:00 2001 From: vbot Date: Fri, 17 Sep 2021 16:27:30 +0200 Subject: [PATCH 4/9] Hangzhou: vanity nonce --- src/proto_alpha/lib_protocol/main.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/proto_alpha/lib_protocol/main.ml b/src/proto_alpha/lib_protocol/main.ml index 0065f88ca92c..d134876737f2 100644 --- a/src/proto_alpha/lib_protocol/main.ml +++ b/src/proto_alpha/lib_protocol/main.ml @@ -494,4 +494,4 @@ let value_of_key ~chain_id:_ ~predecessor_context:ctxt ~predecessor_timestamp Alpha_context.prepare ~level ~predecessor_timestamp ~timestamp ~fitness ctxt >>=? fun (ctxt, _, _) -> return (Apply.value_of_key ctxt) -(* Vanity nonce: TBD *) +(* Vanity nonce: 0105005008491999 *) -- GitLab From f7eb289e56825532ac175eb986aa195149e68d11 Mon Sep 17 00:00:00 2001 From: Romain Bardou Date: Fri, 17 Sep 2021 17:22:42 +0200 Subject: [PATCH 5/9] Protocol: Hangzhou --- .gitlab/ci/integration.yml | 126 + .gitlab/ci/opam.yml | 110 + .gitlab/ci/unittest.yml | 11 +- active_protocol_versions | 1 + docs/011/cli-commands.rst | 50 + docs/011/consensus.rst | 363 + docs/011/glossary.rst | 178 + docs/011/liquidity_baking.rst | 49 + docs/011/michelson.rst | 3806 +++++++++ docs/011/proof_of_stake.rst | 203 + docs/011/sapling.rst | 496 ++ docs/011/timelock.rst | 129 + docs/011/voting.rst | 328 + docs/index.rst | 16 + docs/protocols/011_hangzhou.rst | 179 + sandbox.Makefile | 24 +- src/bin_client/dune | 12 + src/bin_client/tezos-client.opam | 3 + src/bin_codec/dune | 4 + src/bin_codec/tezos-codec.opam | 1 + src/bin_node/dune | 8 + src/bin_node/tezos-node.opam | 2 + src/bin_proxy_server/dune | 8 + .../final_protocol_versions | 3 +- .../bin_accuser/.ocamlformat | 17 + src/proto_011_PtHangzH/bin_accuser/dune | 20 + .../bin_accuser/dune-project | 3 + .../bin_accuser/main_accuser_011_PtHangzH.ml | 38 + .../tezos-accuser-011-PtHangzH.opam | 20 + src/proto_011_PtHangzH/bin_baker/.ocamlformat | 17 + src/proto_011_PtHangzH/bin_baker/dune | 20 + src/proto_011_PtHangzH/bin_baker/dune-project | 3 + .../bin_baker/main_baker_011_PtHangzH.ml | 47 + .../bin_baker/tezos-baker-011-PtHangzH.opam | 20 + .../bin_endorser/.ocamlformat | 17 + src/proto_011_PtHangzH/bin_endorser/dune | 20 + .../bin_endorser/dune-project | 3 + .../main_endorser_011_PtHangzH.ml | 38 + .../tezos-endorser-011-PtHangzH.opam | 20 + .../lib_benchmark/.ocamlformat | 17 + .../lib_benchmark/README.md | 42 + .../lib_benchmark/autocomp.ml | 380 + src/proto_011_PtHangzH/lib_benchmark/dune | 26 + .../lib_benchmark/dune-project | 3 + .../lib_benchmark/execution_context.ml | 93 + .../lib_benchmark/generators.ml | 146 + .../lib_benchmark/kernel.ml | 39 + .../lib_benchmark_type_inference/.ocamlformat | 17 + .../lib_benchmark_type_inference/dune | 17 + .../lib_benchmark_type_inference/dune-project | 3 + .../lib_benchmark_type_inference/inference.ml | 1150 +++ .../inference.mli | 145 + .../lib_benchmark_type_inference/int_map.ml | 26 + .../mikhailsky.ml | 422 + .../mikhailsky.mli | 330 + .../mikhailsky_prim.ml | 570 ++ .../lib_benchmark_type_inference/monads.ml | 83 + .../lib_benchmark_type_inference/stores.ml | 85 + .../test/.ocamlformat | 17 + .../lib_benchmark_type_inference/test/dune | 10 + .../test/test_inference.ml | 637 ++ .../test/test_uf.ml | 63 + ...benchmark-type-inference-011-PtHangzH.opam | 24 + .../lib_benchmark_type_inference/type.ml | 201 + .../lib_benchmark_type_inference/type.mli | 111 + .../lib_benchmark_type_inference/uf.ml | 99 + .../lib_benchmark/micheline_sampler.ml | 110 + .../lib_benchmark/micheline_sampler.mli | 70 + .../lib_benchmark/michelson.ml | 232 + .../lib_benchmark/michelson_samplers.ml | 795 ++ .../lib_benchmark/michelson_samplers_base.ml | 122 + .../michelson_samplers_parameters.ml | 96 + src/proto_011_PtHangzH/lib_benchmark/rules.ml | 968 +++ .../lib_benchmark/sampler.ml | 101 + .../lib_benchmark/sampling_helpers.ml | 41 + .../lib_benchmark/state_space.ml | 71 + .../lib_benchmark/test/.ocamlformat | 17 + .../lib_benchmark/test/dune | 40 + .../lib_benchmark/test/test_autocompletion.ml | 123 + .../lib_benchmark/test/test_distribution.ml | 170 + .../lib_benchmark/test/test_helpers.ml | 123 + .../lib_benchmark/test/test_sampling_code.ml | 98 + .../lib_benchmark/test/test_sampling_data.ml | 94 + .../tezos-benchmark-011-PtHangzH.opam | 32 + .../lib_benchmarks_proto/.ocamlformat | 17 + .../lib_benchmarks_proto/cache_benchmarks.ml | 195 + .../lib_benchmarks_proto/dune | 31 + .../lib_benchmarks_proto/dune-project | 3 + .../encodings_benchmarks.ml | 439 ++ .../lib_benchmarks_proto/gas_helpers.ml | 36 + .../global_constants_storage_benchmarks.ml | 727 ++ .../interpreter_benchmarks.ml | 3079 ++++++++ .../lib_benchmarks_proto/interpreter_model.ml | 543 ++ .../interpreter_workload.ml | 1596 ++++ .../michelson_commands.ml | 200 + .../michelson_generation.ml | 224 + .../michelson_generation.mli | 124 + .../lib_benchmarks_proto/michelson_types.ml | 138 + .../registration_helpers.ml | 37 + .../sapling_benchmarks.ml | 152 + .../lib_benchmarks_proto/sapling_commands.ml | 134 + .../sapling_generation.ml | 564 ++ .../script_repr_benchmarks.ml | 111 + .../script_typed_ir_size_benchmarks.ml | 342 + .../lib_benchmarks_proto/size.ml | 204 + .../lib_benchmarks_proto/tags.ml | 32 + .../tezos-benchmarks-proto-011-PtHangzH.opam | 28 + .../translator_benchmarks.ml | 775 ++ .../lib_benchmarks_proto/translator_model.ml | 68 + .../translator_workload.ml | 186 + .../lib_client/.ocamlformat | 17 + .../lib_client/annotated_manager_operation.ml | 123 + .../annotated_manager_operation.mli | 98 + .../lib_client/client_proto_args.ml | 533 ++ .../lib_client/client_proto_args.mli | 133 + .../lib_client/client_proto_context.ml | 711 ++ .../lib_client/client_proto_context.mli | 363 + .../lib_client/client_proto_contracts.ml | 156 + .../lib_client/client_proto_contracts.mli | 74 + .../lib_client/client_proto_fa12.ml | 974 +++ .../lib_client/client_proto_fa12.mli | 157 + .../lib_client/client_proto_multisig.ml | 1211 +++ .../lib_client/client_proto_multisig.mli | 150 + .../lib_client/client_proto_programs.ml | 296 + .../lib_client/client_proto_programs.mli | 202 + .../lib_client/client_proto_utils.ml | 55 + .../lib_client/client_proto_utils.mli | 40 + src/proto_011_PtHangzH/lib_client/dune | 24 + .../lib_client/dune-project | 3 + .../lib_client/injection.ml | 958 +++ .../lib_client/injection.mli | 105 + src/proto_011_PtHangzH/lib_client/light.ml | 37 + src/proto_011_PtHangzH/lib_client/limit.ml | 64 + src/proto_011_PtHangzH/lib_client/limit.mli | 49 + .../lib_client/managed_contract.ml | 321 + .../lib_client/managed_contract.mli | 125 + .../lib_client/michelson_v1_emacs.ml | 234 + .../lib_client/michelson_v1_emacs.mli | 39 + .../lib_client/michelson_v1_entrypoints.ml | 216 + .../lib_client/michelson_v1_entrypoints.mli | 108 + .../lib_client/michelson_v1_error_reporter.ml | 773 ++ .../michelson_v1_error_reporter.mli | 32 + .../lib_client/michelson_v1_helpers.ml | 60 + .../lib_client/michelson_v1_macros.ml | 1519 ++++ .../lib_client/michelson_v1_macros.mli | 86 + .../lib_client/michelson_v1_parser.ml | 103 + .../lib_client/michelson_v1_parser.mli | 55 + .../lib_client/michelson_v1_printer.ml | 241 + .../lib_client/michelson_v1_printer.mli | 65 + src/proto_011_PtHangzH/lib_client/mockup.ml | 992 +++ .../lib_client/operation_result.ml | 567 ++ .../lib_client/operation_result.mli | 35 + .../lib_client/protocol_client_context.ml | 281 + src/proto_011_PtHangzH/lib_client/proxy.ml | 183 + .../lib_client/test/.ocamlformat | 17 + .../lib_client/test/assert.ml | 37 + src/proto_011_PtHangzH/lib_client/test/dune | 17 + .../test/test_client_proto_context.ml | 71 + .../test/test_client_proto_contracts.ml | 94 + .../test/test_michelson_v1_macros.ml | 1359 ++++ .../lib_client/test/test_proxy.ml | 89 + .../lib_client/tezos-client-011-PtHangzH.opam | 31 + .../lib_client_commands/.ocamlformat | 17 + .../alpha_commands_registration.ml | 38 + .../client_proto_context_commands.ml | 1770 +++++ .../client_proto_contracts_commands.ml | 87 + .../client_proto_fa12_commands.ml | 757 ++ .../client_proto_mockup_commands.ml | 81 + .../client_proto_mockup_commands.mli | 26 + .../client_proto_multisig_commands.ml | 1129 +++ .../client_proto_multisig_commands.mli | 26 + .../client_proto_programs_commands.ml | 955 +++ .../client_proto_programs_commands.mli | 26 + .../client_proto_stresstest_commands.ml | 847 ++ .../client_proto_utils_commands.ml | 105 + .../client_proto_utils_commands.mli | 26 + .../lib_client_commands/dune | 57 + .../lib_client_commands/dune-project | 3 + ...nt-011-PtHangzH-commands-registration.opam | 24 + .../tezos-client-011-PtHangzH-commands.opam | 22 + .../lib_client_sapling/.ocamlformat | 17 + .../client_sapling_commands.ml | 796 ++ .../client_sapling_commands.mli | 23 + .../lib_client_sapling/context.ml | 553 ++ .../lib_client_sapling/context.mli | 157 + .../lib_client_sapling/dune | 19 + .../lib_client_sapling/dune-project | 3 + .../tezos-client-sapling-011-PtHangzH.opam | 24 + .../lib_client_sapling/wallet.ml | 126 + .../lib_client_sapling/wallet.mli | 75 + .../lib_delegate/.ocamlformat | 17 + .../lib_delegate/client_baking_blocks.ml | 204 + .../lib_delegate/client_baking_blocks.mli | 71 + .../client_baking_denunciation.ml | 309 + .../client_baking_denunciation.mli | 30 + .../lib_delegate/client_baking_endorsement.ml | 275 + .../client_baking_endorsement.mli | 48 + .../lib_delegate/client_baking_files.ml | 55 + .../lib_delegate/client_baking_files.mli | 36 + .../lib_delegate/client_baking_forge.ml | 1665 ++++ .../lib_delegate/client_baking_forge.mli | 110 + .../client_baking_highwatermarks.ml | 115 + .../client_baking_highwatermarks.mli | 63 + .../lib_delegate/client_baking_lib.ml | 160 + .../lib_delegate/client_baking_lib.mli | 72 + .../lib_delegate/client_baking_nonces.ml | 147 + .../lib_delegate/client_baking_nonces.mli | 81 + .../lib_delegate/client_baking_pow.ml | 82 + .../lib_delegate/client_baking_pow.mli | 42 + .../lib_delegate/client_baking_revelation.ml | 54 + .../lib_delegate/client_baking_revelation.mli | 35 + .../lib_delegate/client_baking_scheduling.ml | 127 + .../lib_delegate/client_baking_scheduling.mli | 56 + .../lib_delegate/client_baking_simulator.ml | 114 + .../lib_delegate/client_baking_simulator.mli | 59 + .../lib_delegate/client_daemon.ml | 142 + .../lib_delegate/client_daemon.mli | 61 + .../lib_delegate/delegate_commands.ml | 370 + .../lib_delegate/delegate_commands.mli | 32 + .../delegate_commands_registration.ml | 29 + .../lib_delegate/delegate_events.ml | 769 ++ src/proto_011_PtHangzH/lib_delegate/dune | 87 + .../lib_delegate/dune-project | 3 + .../lib_delegate/logging.ml | 153 + .../lib_delegate/logging.mli | 80 + .../tezos-accuser-011-PtHangzH-commands.opam | 23 + .../tezos-baking-011-PtHangzH-commands.opam | 24 + .../tezos-baking-011-PtHangzH.opam | 26 + .../tezos-endorser-011-PtHangzH-commands.opam | 23 + .../lib_parameters/.ocamlformat | 17 + .../lib_parameters/default_parameters.ml | 166 + .../lib_parameters/default_parameters.mli | 45 + src/proto_011_PtHangzH/lib_parameters/dune | 41 + .../lib_parameters/dune-project | 3 + src/proto_011_PtHangzH/lib_parameters/gen.ml | 61 + ...ezos-protocol-011-PtHangzH-parameters.opam | 18 + .../lib_plugin/.ocamlformat | 17 + src/proto_011_PtHangzH/lib_plugin/dune | 23 + .../lib_plugin/dune-project | 3 + src/proto_011_PtHangzH/lib_plugin/plugin.ml | 2528 ++++++ .../lib_plugin/plugin_registerer.ml | 31 + ...otocol-plugin-011-PtHangzH-registerer.opam | 18 + .../tezos-protocol-plugin-011-PtHangzH.opam | 17 + .../lib_protocol/.ocamlformat | 17 + .../lib_protocol/TEZOS_PROTOCOL | 113 + .../lib_protocol/alpha_context.ml | 548 ++ .../lib_protocol/alpha_context.mli | 2095 +++++ .../lib_protocol/alpha_services.ml | 194 + .../lib_protocol/alpha_services.mli | 81 + .../lib_protocol/amendment.ml | 264 + .../lib_protocol/amendment.mli | 81 + src/proto_011_PtHangzH/lib_protocol/apply.ml | 1720 +++++ src/proto_011_PtHangzH/lib_protocol/apply.mli | 182 + .../lib_protocol/apply_results.ml | 1345 ++++ .../lib_protocol/apply_results.mli | 220 + src/proto_011_PtHangzH/lib_protocol/baking.ml | 467 ++ .../lib_protocol/baking.mli | 165 + .../lib_protocol/blinded_public_key_hash.ml | 60 + .../lib_protocol/blinded_public_key_hash.mli | 45 + .../lib_protocol/block_header_repr.ml | 149 + .../lib_protocol/block_header_repr.mli | 65 + .../lib_protocol/bootstrap_storage.ml | 131 + .../lib_protocol/bootstrap_storage.mli | 39 + .../lib_protocol/cache_costs.ml | 52 + .../lib_protocol/cache_costs.mli | 32 + .../lib_protocol/cache_memory_helpers.ml | 168 + .../lib_protocol/commitment_repr.ml | 36 + .../lib_protocol/commitment_repr.mli | 31 + .../lib_protocol/commitment_storage.ml | 34 + .../lib_protocol/commitment_storage.mli | 33 + .../lib_protocol/constants_repr.ml | 499 ++ .../lib_protocol/constants_repr.mli | 166 + .../lib_protocol/constants_services.ml | 60 + .../lib_protocol/constants_services.mli | 34 + .../lib_protocol/constants_storage.ml | 138 + .../lib_protocol/constants_storage.mli | 84 + .../lib_protocol/contract_hash.ml | 45 + .../lib_protocol/contract_hash.mli | 29 + .../lib_protocol/contract_repr.ml | 213 + .../lib_protocol/contract_repr.mli | 99 + .../lib_protocol/contract_services.ml | 516 ++ .../lib_protocol/contract_services.mli | 126 + .../lib_protocol/contract_storage.ml | 744 ++ .../lib_protocol/contract_storage.mli | 185 + .../lib_protocol/contracts/cpmm.bin | 1 + .../lib_protocol/contracts/cpmm.mligo | 388 + .../lib_protocol/contracts/cpmm.tz | 929 +++ .../lib_protocol/contracts/lqt.bin | 1 + .../lib_protocol/contracts/lqt.mligo | 164 + .../lib_protocol/contracts/lqt.tz | 327 + .../lib_protocol/coq-of-ocaml/README.md | 11 + .../lib_protocol/coq-of-ocaml/config.json | 250 + .../lib_protocol/cycle_repr.ml | 87 + .../lib_protocol/cycle_repr.mli | 56 + .../lib_protocol/delegate_services.ml | 390 + .../lib_protocol/delegate_services.mli | 117 + .../lib_protocol/delegate_storage.ml | 568 ++ .../lib_protocol/delegate_storage.mli | 181 + src/proto_011_PtHangzH/lib_protocol/dune | 1 + .../lib_protocol/dune-project | 3 + src/proto_011_PtHangzH/lib_protocol/dune.inc | 621 ++ .../lib_protocol/fees_storage.ml | 139 + .../lib_protocol/fees_storage.mli | 67 + .../lib_protocol/fitness_repr.ml | 61 + .../lib_protocol/fitness_repr.mli | 29 + .../lib_protocol/fitness_storage.ml | 30 + .../lib_protocol/fitness_storage.mli | 29 + .../lib_protocol/fixed_point_repr.ml | 94 + .../lib_protocol/fixed_point_repr.mli | 105 + .../lib_protocol/gas_limit_repr.ml | 210 + .../lib_protocol/gas_limit_repr.mli | 110 + .../lib_protocol/global_constants_costs.ml | 47 + .../lib_protocol/global_constants_costs.mli | 34 + .../lib_protocol/global_constants_storage.ml | 270 + .../lib_protocol/global_constants_storage.mli | 150 + .../lib_protocol/init_storage.ml | 311 + .../lib_protocol/init_storage.mli | 57 + .../lib_protocol/lazy_storage_diff.ml | 439 ++ .../lib_protocol/lazy_storage_diff.mli | 71 + .../lib_protocol/lazy_storage_kind.ml | 325 + .../lib_protocol/lazy_storage_kind.mli | 178 + .../lib_protocol/level_repr.ml | 301 + .../lib_protocol/level_repr.mli | 113 + .../lib_protocol/level_storage.ml | 110 + .../lib_protocol/level_storage.mli | 63 + .../lib_protocol/liquidity_baking_cpmm.ml | 11 + .../lib_protocol/liquidity_baking_lqt.ml | 11 + .../liquidity_baking_migration.ml | 217 + .../liquidity_baking_migration.mli | 33 + .../lib_protocol/liquidity_baking_repr.ml | 71 + .../lib_protocol/liquidity_baking_repr.mli | 36 + src/proto_011_PtHangzH/lib_protocol/main.ml | 497 ++ src/proto_011_PtHangzH/lib_protocol/main.mli | 87 + .../lib_protocol/manager_repr.ml | 52 + .../lib_protocol/manager_repr.mli | 38 + .../lib_protocol/michelson_v1_gas.ml | 1820 +++++ .../lib_protocol/michelson_v1_gas.mli | 543 ++ .../lib_protocol/michelson_v1_primitives.ml | 794 ++ .../lib_protocol/michelson_v1_primitives.mli | 220 + .../lib_protocol/migration_repr.ml | 62 + .../lib_protocol/migration_repr.mli | 39 + src/proto_011_PtHangzH/lib_protocol/misc.ml | 86 + src/proto_011_PtHangzH/lib_protocol/misc.mli | 47 + .../lib_protocol/nonce_hash.ml | 45 + .../lib_protocol/nonce_hash.mli | 31 + .../lib_protocol/nonce_storage.ml | 127 + .../lib_protocol/nonce_storage.mli | 58 + .../lib_protocol/operation_repr.ml | 955 +++ .../lib_protocol/operation_repr.mli | 317 + .../lib_protocol/parameters_repr.ml | 131 + .../lib_protocol/parameters_repr.mli | 56 + .../lib_protocol/path_encoding.ml | 57 + .../lib_protocol/path_encoding.mli | 48 + .../lib_protocol/period_repr.ml | 157 + .../lib_protocol/period_repr.mli | 73 + .../lib_protocol/raw_context.ml | 996 +++ .../lib_protocol/raw_context.mli | 221 + .../lib_protocol/raw_context_intf.ml | 259 + .../lib_protocol/raw_level_repr.ml | 99 + .../lib_protocol/raw_level_repr.mli | 58 + .../lib_protocol/receipt_repr.ml | 149 + .../lib_protocol/receipt_repr.mli | 52 + .../lib_protocol/roll_repr.ml | 56 + .../lib_protocol/roll_repr.mli | 44 + .../lib_protocol/roll_storage.ml | 491 ++ .../lib_protocol/roll_storage.mli | 260 + .../lib_protocol/sapling_repr.ml | 200 + .../lib_protocol/sapling_services.ml | 103 + .../lib_protocol/sapling_storage.ml | 489 ++ .../lib_protocol/sapling_validator.ml | 108 + .../lib_protocol/saturation_repr.ml | 170 + .../lib_protocol/saturation_repr.mli | 204 + .../lib_protocol/script_cache.ml | 109 + .../lib_protocol/script_cache.mli | 81 + .../lib_protocol/script_comparable.ml | 89 + .../lib_protocol/script_comparable.mli | 29 + .../lib_protocol/script_expr_hash.ml | 44 + .../lib_protocol/script_expr_hash.mli | 31 + .../lib_protocol/script_int_repr.ml | 104 + .../lib_protocol/script_int_repr.mli | 155 + .../lib_protocol/script_interpreter.ml | 1825 +++++ .../lib_protocol/script_interpreter.mli | 166 + .../lib_protocol/script_interpreter_defs.ml | 962 +++ .../lib_protocol/script_ir_annot.ml | 513 ++ .../lib_protocol/script_ir_annot.mli | 217 + .../lib_protocol/script_ir_translator.ml | 6797 +++++++++++++++++ .../lib_protocol/script_ir_translator.mli | 479 ++ .../lib_protocol/script_list.ml | 32 + .../lib_protocol/script_list.mli | 31 + .../lib_protocol/script_map.ml | 90 + .../lib_protocol/script_map.mli | 49 + .../lib_protocol/script_repr.ml | 304 + .../lib_protocol/script_repr.mli | 109 + .../lib_protocol/script_set.ml | 75 + .../lib_protocol/script_set.mli | 37 + .../lib_protocol/script_string_repr.ml | 77 + .../lib_protocol/script_string_repr.mli | 46 + .../lib_protocol/script_tc_errors.ml | 204 + .../script_tc_errors_registration.ml | 814 ++ .../script_tc_errors_registration.mli | 34 + .../lib_protocol/script_timestamp_repr.ml | 53 + .../lib_protocol/script_timestamp_repr.mli | 65 + .../lib_protocol/script_typed_ir.ml | 2184 ++++++ .../lib_protocol/script_typed_ir.mli | 1579 ++++ .../lib_protocol/script_typed_ir_size.ml | 766 ++ .../lib_protocol/script_typed_ir_size.mli | 71 + .../script_typed_ir_size_costs.ml | 34 + .../script_typed_ir_size_costs.mli | 28 + .../lib_protocol/seed_repr.ml | 132 + .../lib_protocol/seed_repr.mli | 100 + .../lib_protocol/seed_storage.ml | 132 + .../lib_protocol/seed_storage.mli | 47 + .../lib_protocol/services_registration.ml | 121 + .../lib_protocol/services_registration.mli | 127 + .../lib_protocol/state_hash.ml | 44 + .../lib_protocol/state_hash.mli | 30 + .../lib_protocol/storage.ml | 1329 ++++ .../lib_protocol/storage.mli | 532 ++ .../lib_protocol/storage_costs.ml | 43 + .../lib_protocol/storage_costs.mli | 30 + .../lib_protocol/storage_description.ml | 388 + .../lib_protocol/storage_description.mli | 93 + .../lib_protocol/storage_functors.ml | 1085 +++ .../lib_protocol/storage_functors.mli | 122 + .../lib_protocol/storage_sigs.ml | 383 + .../lib_protocol/test/.ocamlformat | 17 + .../test/contracts/big_interpreter_stack.tz | 5 + .../test/contracts/sapling_contract.tz | 69 + .../test/contracts/sapling_contract_double.tz | 33 + .../test/contracts/sapling_contract_drop.tz | 14 + .../test/contracts/sapling_contract_send.tz | 20 + .../sapling_contract_state_as_arg.tz | 18 + .../contracts/sapling_push_sapling_state.tz | 11 + .../contracts/sapling_use_existing_state.tz | 12 + .../test/contracts/temp_big_maps.tz | 81 + .../lib_protocol/test/contracts/timelock.tz | 31 + src/proto_011_PtHangzH/lib_protocol/test/dune | 82 + .../lib_protocol/test/helpers/.ocamlformat | 17 + .../lib_protocol/test/helpers/README.md | 3 + .../lib_protocol/test/helpers/account.ml | 113 + .../lib_protocol/test/helpers/account.mli | 66 + .../lib_protocol/test/helpers/assert.ml | 167 + .../lib_protocol/test/helpers/block.ml | 680 ++ .../lib_protocol/test/helpers/block.mli | 218 + .../lib_protocol/test/helpers/context.ml | 340 + .../lib_protocol/test/helpers/context.mli | 157 + .../test/helpers/contract_helpers.ml | 73 + .../lib_protocol/test/helpers/cpmm_logic.ml | 102 + .../lib_protocol/test/helpers/cpmm_repr.ml | 384 + .../lib_protocol/test/helpers/dune | 24 + .../lib_protocol/test/helpers/dune-project | 3 + .../lib_protocol/test/helpers/expr.ml | 40 + .../lib_protocol/test/helpers/expr_common.ml | 82 + .../lib_protocol/test/helpers/incremental.ml | 209 + .../lib_protocol/test/helpers/incremental.mli | 62 + .../helpers/liquidity_baking_generator.ml | 351 + .../helpers/liquidity_baking_generator.mli | 77 + .../test/helpers/liquidity_baking_machine.ml | 1324 ++++ .../test/helpers/liquidity_baking_machine.mli | 387 + .../test/helpers/lqt_fa12_repr.ml | 252 + .../lib_protocol/test/helpers/nonce.ml | 35 + .../lib_protocol/test/helpers/nonce.mli | 33 + .../lib_protocol/test/helpers/op.ml | 417 + .../lib_protocol/test/helpers/op.mli | 152 + .../lib_protocol/test/helpers/rewards.ml | 1641 ++++ .../test/helpers/sapling_helpers.ml | 383 + .../test/helpers/script_big_map.ml | 30 + .../test/helpers/script_big_map.mli | 44 + .../lib_protocol/test/helpers/script_list.ml | 29 + .../lib_protocol/test/helpers/script_list.mli | 28 + .../lib_protocol/test/helpers/script_map.ml | 36 + .../lib_protocol/test/helpers/script_map.mli | 31 + .../lib_protocol/test/helpers/script_set.ml | 31 + .../lib_protocol/test/helpers/script_set.mli | 32 + .../test/helpers/test_global_constants.ml | 327 + .../lib_protocol/test/helpers/test_tez.ml | 59 + .../lib_protocol/test/helpers/testable.ml | 38 + .../tezos-011-PtHangzH-test-helpers.opam | 25 + .../lib_protocol/test/liquidity_baking_pbt.ml | 300 + .../lib_protocol/test/main.ml | 72 + .../lib_protocol/test/saturation_fuzzing.ml | 183 + .../lib_protocol/test/test_activation.ml | 584 ++ .../lib_protocol/test/test_baking.ml | 286 + .../lib_protocol/test/test_baking_module.ml | 175 + .../test/test_combined_operations.ml | 332 + .../lib_protocol/test/test_constants.ml | 94 + .../lib_protocol/test/test_delegation.ml | 1561 ++++ .../lib_protocol/test/test_double_baking.ml | 197 + .../test/test_double_endorsement.ml | 239 + .../lib_protocol/test/test_endorsement.ml | 684 ++ .../lib_protocol/test/test_failing_noop.ml | 62 + .../lib_protocol/test/test_fixed_point.ml | 174 + .../lib_protocol/test/test_gas_costs.ml | 289 + .../lib_protocol/test/test_gas_levels.ml | 483 ++ .../lib_protocol/test/test_gas_properties.ml | 139 + .../test/test_global_constants_storage.ml | 138 + .../lib_protocol/test/test_helpers_rpcs.ml | 69 + .../lib_protocol/test/test_interpretation.ml | 246 + .../test/test_lazy_storage_diff.ml | 141 + .../lib_protocol/test/test_level_module.ml | 275 + .../test/test_liquidity_baking.ml | 527 ++ .../lib_protocol/test/test_origination.ml | 239 + .../lib_protocol/test/test_qty.ml | 159 + .../lib_protocol/test/test_reveal.ml | 108 + .../lib_protocol/test/test_rolls.ml | 306 + .../lib_protocol/test/test_sapling.ml | 1136 +++ .../lib_protocol/test/test_saturation.ml | 217 + .../test/test_script_comparison.ml | 365 + .../test/test_script_typed_ir_size.ml | 429 ++ .../lib_protocol/test/test_seed.ml | 460 ++ .../lib_protocol/test/test_storage.ml | 224 + .../lib_protocol/test/test_temp_big_maps.ml | 100 + .../lib_protocol/test/test_tez_repr.ml | 139 + .../lib_protocol/test/test_time_repr.ml | 44 + .../lib_protocol/test/test_timelock.ml | 179 + .../lib_protocol/test/test_transfer.ml | 642 ++ .../lib_protocol/test/test_typechecking.ml | 906 +++ .../lib_protocol/test/test_voting.ml | 1129 +++ .../lib_protocol/test/unit/.ocamlformat | 17 + .../lib_protocol/test/unit/dune | 24 + .../lib_protocol/test/unit/main.ml | 60 + .../test/unit/test_alpha_context.ml | 129 + .../test/unit/test_contract_repr.ml | 161 + .../unit/test_global_constants_storage.ml | 413 + .../test/unit/test_operation_repr.ml | 112 + .../test/unit/test_raw_level_repr.ml | 175 + .../lib_protocol/test/unit/test_tez_repr.ml | 202 + .../lib_protocol/tez_repr.ml | 240 + .../lib_protocol/tez_repr.mli | 96 + .../tezos-embedded-protocol-011-PtHangzH.opam | 25 + .../tezos-protocol-011-PtHangzH-tests.opam | 36 + .../tezos-protocol-011-PtHangzH.opam | 23 + .../tezos-protocol-functor-011-PtHangzH.opam | 24 + .../lib_protocol/time_repr.ml | 66 + .../lib_protocol/time_repr.mli | 48 + .../lib_protocol/vote_repr.ml | 42 + .../lib_protocol/vote_repr.mli | 33 + .../lib_protocol/vote_storage.ml | 161 + .../lib_protocol/vote_storage.mli | 116 + .../lib_protocol/voting_period_repr.ml | 175 + .../lib_protocol/voting_period_repr.mli | 82 + .../lib_protocol/voting_period_storage.ml | 191 + .../lib_protocol/voting_period_storage.mli | 51 + .../lib_protocol/voting_services.ml | 152 + .../lib_protocol/voting_services.mli | 60 + tests_python/contracts_011/attic/accounts.tz | 54 + tests_python/contracts_011/attic/add1.tz | 7 + tests_python/contracts_011/attic/add1_list.tz | 6 + .../contracts_011/attic/after_strategy.tz | 3 + tests_python/contracts_011/attic/always.tz | 4 + tests_python/contracts_011/attic/append.tz | 8 + tests_python/contracts_011/attic/at_least.tz | 6 + tests_python/contracts_011/attic/auction.tz | 8 + .../contracts_011/attic/bad_lockup.tz | 6 + .../contracts_011/attic/big_map_union.tz | 8 + .../contracts_011/attic/cadr_annotation.tz | 3 + tests_python/contracts_011/attic/concat.tz | 7 + .../contracts_011/attic/conditionals.tz | 9 + .../contracts_011/attic/cons_twice.tz | 9 + tests_python/contracts_011/attic/cps_fact.tz | 16 + .../contracts_011/attic/create_add1_lists.tz | 14 + .../contracts_011/attic/data_publisher.tz | 8 + tests_python/contracts_011/attic/dispatch.tz | 9 + tests_python/contracts_011/attic/empty.tz | 3 + .../contracts_011/attic/fail_amount.tz | 6 + tests_python/contracts_011/attic/faucet.tz | 7 + tests_python/contracts_011/attic/forward.tz | 150 + tests_python/contracts_011/attic/id.tz | 3 + .../contracts_011/attic/infinite_loop.tz | 3 + .../contracts_011/attic/insertion_sort.tz | 16 + .../contracts_011/attic/int_publisher.tz | 17 + .../contracts_011/attic/king_of_tez.tz | 19 + .../attic/list_of_transactions.tz | 8 + tests_python/contracts_011/attic/queue.tz | 24 + .../contracts_011/attic/reduce_map.tz | 16 + .../contracts_011/attic/reentrancy.tz | 7 + tests_python/contracts_011/attic/reservoir.tz | 25 + .../attic/scrutable_reservoir.tz | 67 + .../contracts_011/attic/spawn_identities.tz | 20 + .../entrypoints/big_map_entrypoints.tz | 31 + .../entrypoints/delegatable_target.tz | 79 + .../contracts_011/entrypoints/manager.tz | 31 + .../entrypoints/no_default_target.tz | 11 + .../entrypoints/no_entrypoint_target.tz | 11 + .../entrypoints/rooted_target.tz | 11 + .../entrypoints/simple_entrypoints.tz | 4 + .../contracts_011/ill_typed/badly_indented.tz | 3 + .../contracts_011/ill_typed/big_dip.tz | 4 + .../contracts_011/ill_typed/big_drop.tz | 4 + .../contracts_011/ill_typed/big_map_arity.tz | 5 + .../contracts_011/ill_typed/chain_id_arity.tz | 3 + tests_python/contracts_011/ill_typed/comb0.tz | 3 + tests_python/contracts_011/ill_typed/comb1.tz | 3 + .../ill_typed/contract_annotation_default.tz | 11 + tests_python/contracts_011/ill_typed/dup0.tz | 3 + .../ill_typed/failwith_big_map.tz | 22 + .../ill_typed/invalid_self_entrypoint.tz | 10 + .../ill_typed/missing_only_code_field.tz | 2 + .../ill_typed/missing_only_parameter_field.tz | 4 + .../ill_typed/missing_only_storage_field.tz | 4 + .../missing_parameter_and_storage_fields.tz | 3 + .../ill_typed/multiple_code_field.tz | 6 + .../ill_typed/multiple_parameter_field.tz | 6 + .../multiple_storage_and_code_fields.tz | 7 + .../ill_typed/multiple_storage_field.tz | 6 + .../contracts_011/ill_typed/never_literal.tz | 6 + .../contracts_011/ill_typed/pack_big_map.tz | 7 + .../contracts_011/ill_typed/pack_operation.tz | 20 + .../ill_typed/pack_sapling_state.tz | 13 + .../push_big_map_with_id_with_parens.tz | 10 + .../push_big_map_with_id_without_parens.tz | 11 + ...ng_build_empty_state_with_int_parameter.tz | 10 + .../ill_typed/set_update_non_comparable.tz | 9 + .../ill_typed/stack_bottom_undig2able.tz | 5 + .../ill_typed/stack_bottom_undigable.tz | 6 + .../ill_typed/stack_bottom_undip2able.tz | 6 + .../ill_typed/stack_bottom_undipable.tz | 5 + .../ill_typed/stack_bottom_undropable.tz | 5 + .../ill_typed/stack_bottom_undug2able.tz | 5 + .../ill_typed/stack_bottom_undugable.tz | 6 + .../ill_typed/stack_bottom_undup2able.tz | 5 + .../ill_typed/stack_bottom_unfailwithable.tz | 6 + .../ill_typed/stack_bottom_ungetable.tz | 6 + .../ill_typed/stack_bottom_unleftable.tz | 6 + .../ill_typed/stack_bottom_unpairable.tz | 6 + .../ill_typed/stack_bottom_unpopable.tz | 10 + .../stack_bottom_unpopable_in_lambda.tz | 10 + .../ill_typed/stack_bottom_unrightable.tz | 6 + .../contracts_011/ill_typed/ticket_apply.tz | 17 + .../contracts_011/ill_typed/ticket_dup.tz | 3 + .../ill_typed/ticket_in_ticket.tz | 16 + .../contracts_011/ill_typed/ticket_unpack.tz | 5 + .../contracts_011/ill_typed/uncomb0.tz | 3 + .../contracts_011/ill_typed/uncomb1.tz | 3 + .../ill_typed/unpack_sapling_state.tz | 12 + .../unpair_field_annotation_mismatch.tz | 10 + .../view_op_bad_name_invalid_char_set.tz | 3 + .../view_op_bad_name_invalid_type.tz | 3 + .../view_op_bad_name_non_printable_char.tz | 3 + .../ill_typed/view_op_bad_name_too_long.tz | 4 + .../ill_typed/view_op_bad_return_type.tz | 3 + .../ill_typed/view_op_dupable_type.tz | 3 + .../ill_typed/view_op_invalid_arity.tz | 3 + .../ill_typed/view_op_lazy_storage.tz | 8 + .../ill_typed/view_op_lazy_storage_type.tz | 8 + .../ill_typed/view_toplevel_bad_input_type.tz | 4 + ...view_toplevel_bad_name_invalid_char_set.tz | 5 + .../view_toplevel_bad_name_invalid_type.tz | 4 + ...ew_toplevel_bad_name_non_printable_char.tz | 4 + .../view_toplevel_bad_name_too_long.tz | 4 + .../view_toplevel_bad_return_type.tz | 4 + .../ill_typed/view_toplevel_bad_type.tz | 7 + .../view_toplevel_dupable_type_input.tz | 5 + .../view_toplevel_dupable_type_output.tz | 4 + .../view_toplevel_duplicated_name.tz | 5 + .../ill_typed/view_toplevel_invalid_arity.tz | 4 + .../view_toplevel_lazy_storage_input.tz | 4 + .../view_toplevel_lazy_storage_output.tz | 4 + .../contracts_011/legacy/create_account.tz | 29 + .../contracts_011/legacy/create_contract.tz | 18 + .../legacy/create_contract_flags.tz | 26 + .../legacy/create_contract_rootname.tz | 18 + .../contracts_011/legacy/originator.tz | 16 + .../contracts_011/legacy/steps_to_quota.tz | 12 + tests_python/contracts_011/macros/assert.tz | 3 + .../contracts_011/macros/assert_cmpeq.tz | 3 + .../contracts_011/macros/assert_cmpge.tz | 3 + .../contracts_011/macros/assert_cmpgt.tz | 3 + .../contracts_011/macros/assert_cmple.tz | 3 + .../contracts_011/macros/assert_cmplt.tz | 3 + .../contracts_011/macros/assert_cmpneq.tz | 3 + .../contracts_011/macros/assert_eq.tz | 3 + .../contracts_011/macros/assert_ge.tz | 3 + .../contracts_011/macros/assert_gt.tz | 3 + .../contracts_011/macros/assert_le.tz | 3 + .../contracts_011/macros/assert_lt.tz | 3 + .../contracts_011/macros/assert_neq.tz | 3 + .../contracts_011/macros/big_map_get_add.tz | 7 + .../contracts_011/macros/big_map_mem.tz | 5 + .../contracts_011/macros/build_list.tz | 6 + .../contracts_011/macros/carn_and_cdrn.tz | 26 + tests_python/contracts_011/macros/compare.tz | 9 + .../contracts_011/macros/compare_bytes.tz | 9 + tests_python/contracts_011/macros/fail.tz | 5 + .../contracts_011/macros/guestbook.tz | 10 + .../contracts_011/macros/macro_annotations.tz | 6 + .../contracts_011/macros/map_caddaadr.tz | 4 + .../contracts_011/macros/max_in_list.tz | 9 + tests_python/contracts_011/macros/min.tz | 11 + .../contracts_011/macros/pair_macro.tz | 6 + .../contracts_011/macros/set_caddaadr.tz | 5 + .../contracts_011/macros/take_my_money.tz | 9 + .../contracts_011/macros/unpair_macro.tz | 9 + .../mini_scenarios/authentication.tz | 30 + .../mini_scenarios/big_map_entrypoints.tz | 31 + .../mini_scenarios/big_map_magic.tz | 41 + .../mini_scenarios/big_map_read.tz | 9 + .../mini_scenarios/big_map_store.tz | 8 + .../mini_scenarios/big_map_write.tz | 10 + .../mini_scenarios/create_contract.tz | 33 + .../mini_scenarios/create_contract_simple.tz | 14 + .../mini_scenarios/default_account.tz | 9 + .../execution_order_appender.tz | 17 + .../mini_scenarios/execution_order_caller.tz | 17 + .../mini_scenarios/execution_order_storer.tz | 4 + .../mini_scenarios/fa12_reference.tz | 749 ++ .../mini_scenarios/generic_multisig.tz | 92 + .../contracts_011/mini_scenarios/groth16.tz | 74 + .../contracts_011/mini_scenarios/hardlimit.tz | 5 + .../mini_scenarios/legacy_multisig.tz | 78 + .../contracts_011/mini_scenarios/lockup.tz | 19 + .../mini_scenarios/lqt_fa12.mligo.tz | 328 + .../mini_scenarios/multiple_en2.tz | 77 + .../multiple_entrypoints_counter.tz | 29 + .../mini_scenarios/parameterized_multisig.tz | 24 + .../contracts_011/mini_scenarios/replay.tz | 8 + .../mini_scenarios/reveal_signed_preimage.tz | 13 + .../mini_scenarios/self_address_receiver.tz | 12 + .../mini_scenarios/self_address_sender.tz | 17 + .../mini_scenarios/ticket_builder_fungible.tz | 40 + .../ticket_builder_non_fungible.tz | 47 + .../mini_scenarios/ticket_wallet_fungible.tz | 88 + .../ticket_wallet_non_fungible.tz | 61 + .../mini_scenarios/tzip4_view.tz | 7 + .../mini_scenarios/vote_for_delegate.tz | 30 + .../mini_scenarios/weather_insurance.tz | 19 + .../contracts_011/mini_scenarios/xcat.tz | 48 + .../contracts_011/mini_scenarios/xcat_dapp.tz | 79 + .../contracts_011/non_regression/bug_262.tz | 5 + .../non_regression/pairk_annot.tz | 7 + tests_python/contracts_011/opcodes/abs.tz | 5 + tests_python/contracts_011/opcodes/add.tz | 25 + .../contracts_011/opcodes/add_bls12_381_fr.tz | 3 + .../contracts_011/opcodes/add_bls12_381_g1.tz | 3 + .../contracts_011/opcodes/add_bls12_381_g2.tz | 3 + .../opcodes/add_delta_timestamp.tz | 3 + .../opcodes/add_timestamp_delta.tz | 3 + tests_python/contracts_011/opcodes/address.tz | 3 + tests_python/contracts_011/opcodes/and.tz | 3 + .../contracts_011/opcodes/and_binary.tz | 27 + .../contracts_011/opcodes/and_logical_1.tz | 3 + tests_python/contracts_011/opcodes/balance.tz | 3 + .../contracts_011/opcodes/big_map_mem_nat.tz | 7 + .../opcodes/big_map_mem_string.tz | 7 + .../contracts_011/opcodes/big_map_to_self.tz | 22 + .../bls12_381_fr_push_bytes_not_padded.tz | 9 + .../opcodes/bls12_381_fr_push_nat.tz | 9 + .../opcodes/bls12_381_fr_to_int.tz | 8 + .../opcodes/bls12_381_fr_to_mutez.tz | 12 + .../opcodes/bls12_381_fr_z_int.tz | 8 + .../opcodes/bls12_381_fr_z_nat.tz | 8 + .../opcodes/bls12_381_z_fr_int.tz | 9 + .../opcodes/bls12_381_z_fr_nat.tz | 9 + tests_python/contracts_011/opcodes/bytes.tz | 11 + tests_python/contracts_011/opcodes/car.tz | 3 + tests_python/contracts_011/opcodes/cdr.tz | 3 + .../contracts_011/opcodes/chain_id.tz | 3 + .../contracts_011/opcodes/chain_id_store.tz | 3 + .../contracts_011/opcodes/check_signature.tz | 10 + .../contracts_011/opcodes/comb-get.tz | 27 + .../contracts_011/opcodes/comb-literals.tz | 9 + .../contracts_011/opcodes/comb-set-2.tz | 10 + .../contracts_011/opcodes/comb-set.tz | 10 + tests_python/contracts_011/opcodes/comb.tz | 9 + tests_python/contracts_011/opcodes/compare.tz | 52 + .../contracts_011/opcodes/compare_big_type.tz | 20 + .../opcodes/compare_big_type2.tz | 22 + .../contracts_011/opcodes/comparisons.tz | 15 + .../contracts_011/opcodes/concat_hello.tz | 4 + .../opcodes/concat_hello_bytes.tz | 4 + .../contracts_011/opcodes/concat_list.tz | 5 + tests_python/contracts_011/opcodes/cons.tz | 3 + .../contracts_011/opcodes/contains_all.tz | 7 + .../contracts_011/opcodes/contract.tz | 11 + .../contracts_011/opcodes/create_contract.tz | 14 + .../opcodes/create_contract_rootname.tz | 15 + .../opcodes/create_contract_rootname_alt.tz | 14 + .../opcodes/create_contract_with_view.tz | 17 + .../contracts_011/opcodes/diff_timestamps.tz | 3 + tests_python/contracts_011/opcodes/dig_eq.tz | 14 + tests_python/contracts_011/opcodes/dign.tz | 3 + tests_python/contracts_011/opcodes/dip.tz | 8 + tests_python/contracts_011/opcodes/dipn.tz | 3 + tests_python/contracts_011/opcodes/dropn.tz | 3 + tests_python/contracts_011/opcodes/dugn.tz | 3 + tests_python/contracts_011/opcodes/dup-n.tz | 18 + tests_python/contracts_011/opcodes/ediv.tz | 13 + .../contracts_011/opcodes/ediv_mutez.tz | 12 + .../contracts_011/opcodes/empty_map.tz | 6 + .../contracts_011/opcodes/exec_concat.tz | 7 + tests_python/contracts_011/opcodes/first.tz | 3 + .../opcodes/get_and_update_big_map.tz | 9 + .../opcodes/get_and_update_map.tz | 9 + .../opcodes/get_big_map_value.tz | 6 + .../contracts_011/opcodes/get_map_value.tz | 3 + .../opcodes/hash_consistency_checker.tz | 3 + .../contracts_011/opcodes/hash_key.tz | 3 + .../contracts_011/opcodes/hash_string.tz | 3 + tests_python/contracts_011/opcodes/if.tz | 3 + tests_python/contracts_011/opcodes/if_some.tz | 3 + tests_python/contracts_011/opcodes/int.tz | 5 + tests_python/contracts_011/opcodes/keccak.tz | 8 + .../contracts_011/opcodes/left_right.tz | 3 + tests_python/contracts_011/opcodes/level.tz | 3 + .../contracts_011/opcodes/list_concat.tz | 3 + .../opcodes/list_concat_bytes.tz | 3 + tests_python/contracts_011/opcodes/list_id.tz | 3 + .../contracts_011/opcodes/list_id_map.tz | 3 + .../contracts_011/opcodes/list_iter.tz | 5 + .../contracts_011/opcodes/list_map_block.tz | 5 + .../contracts_011/opcodes/list_size.tz | 3 + .../contracts_011/opcodes/loop_left.tz | 7 + tests_python/contracts_011/opcodes/map_car.tz | 5 + tests_python/contracts_011/opcodes/map_id.tz | 3 + .../contracts_011/opcodes/map_iter.tz | 7 + tests_python/contracts_011/opcodes/map_map.tz | 8 + .../opcodes/map_map_sideeffect.tz | 12 + .../contracts_011/opcodes/map_mem_nat.tz | 7 + .../contracts_011/opcodes/map_mem_string.tz | 7 + .../contracts_011/opcodes/map_size.tz | 3 + .../opcodes/merge_comparable_pairs.tz | 14 + tests_python/contracts_011/opcodes/mul.tz | 48 + .../contracts_011/opcodes/mul_bls12_381_fr.tz | 3 + .../contracts_011/opcodes/mul_bls12_381_g1.tz | 3 + .../contracts_011/opcodes/mul_bls12_381_g2.tz | 3 + .../contracts_011/opcodes/mul_overflow.tz | 18 + tests_python/contracts_011/opcodes/munch.tz | 14 + .../opcodes/mutez_to_bls12_381_fr.tz | 14 + tests_python/contracts_011/opcodes/neg.tz | 8 + .../contracts_011/opcodes/neg_bls12_381_fr.tz | 3 + .../contracts_011/opcodes/neg_bls12_381_g1.tz | 3 + .../contracts_011/opcodes/neg_bls12_381_g2.tz | 3 + tests_python/contracts_011/opcodes/none.tz | 3 + tests_python/contracts_011/opcodes/noop.tz | 3 + tests_python/contracts_011/opcodes/not.tz | 3 + .../contracts_011/opcodes/not_binary.tz | 12 + tests_python/contracts_011/opcodes/or.tz | 3 + .../contracts_011/opcodes/or_binary.tz | 9 + .../opcodes/originate_big_map.tz | 3 + .../contracts_011/opcodes/packunpack.tz | 6 + .../contracts_011/opcodes/packunpack_rev.tz | 43 + .../opcodes/packunpack_rev_cty.tz | 31 + tests_python/contracts_011/opcodes/pair_id.tz | 3 + .../contracts_011/opcodes/pairing_check.tz | 3 + tests_python/contracts_011/opcodes/pexec.tz | 6 + tests_python/contracts_011/opcodes/pexec_2.tz | 11 + tests_python/contracts_011/opcodes/proxy.tz | 13 + tests_python/contracts_011/opcodes/ret_int.tz | 3 + tests_python/contracts_011/opcodes/reverse.tz | 5 + .../contracts_011/opcodes/reverse_loop.tz | 5 + .../opcodes/sapling_empty_state.tz | 3 + tests_python/contracts_011/opcodes/self.tz | 3 + .../contracts_011/opcodes/self_address.tz | 11 + .../opcodes/self_with_default_entrypoint.tz | 19 + .../opcodes/self_with_entrypoint.tz | 26 + tests_python/contracts_011/opcodes/sender.tz | 8 + tests_python/contracts_011/opcodes/set_car.tz | 3 + tests_python/contracts_011/opcodes/set_cdr.tz | 3 + .../contracts_011/opcodes/set_delegate.tz | 9 + tests_python/contracts_011/opcodes/set_id.tz | 3 + .../contracts_011/opcodes/set_iter.tz | 3 + .../contracts_011/opcodes/set_member.tz | 3 + .../contracts_011/opcodes/set_size.tz | 3 + tests_python/contracts_011/opcodes/sha3.tz | 8 + tests_python/contracts_011/opcodes/shifts.tz | 18 + tests_python/contracts_011/opcodes/slice.tz | 5 + .../contracts_011/opcodes/slice_bytes.tz | 5 + tests_python/contracts_011/opcodes/slices.tz | 11 + tests_python/contracts_011/opcodes/source.tz | 10 + .../contracts_011/opcodes/split_bytes.tz | 16 + .../contracts_011/opcodes/split_string.tz | 16 + .../opcodes/store_bls12_381_fr.tz | 3 + .../opcodes/store_bls12_381_g1.tz | 3 + .../opcodes/store_bls12_381_g2.tz | 3 + .../contracts_011/opcodes/store_input.tz | 3 + .../contracts_011/opcodes/store_now.tz | 3 + tests_python/contracts_011/opcodes/str_id.tz | 3 + .../opcodes/sub_timestamp_delta.tz | 3 + tests_python/contracts_011/opcodes/subset.tz | 12 + .../contracts_011/opcodes/tez_add_sub.tz | 5 + .../contracts_011/opcodes/ticket_bad.tz | 5 + .../contracts_011/opcodes/ticket_big_store.tz | 3 + .../contracts_011/opcodes/ticket_join.tz | 7 + .../contracts_011/opcodes/ticket_read.tz | 8 + .../contracts_011/opcodes/ticket_split.tz | 11 + .../contracts_011/opcodes/ticket_store-2.tz | 3 + .../contracts_011/opcodes/ticket_store.tz | 3 + .../contracts_011/opcodes/ticketer-2.tz | 9 + .../contracts_011/opcodes/ticketer.tz | 10 + .../contracts_011/opcodes/transfer_amount.tz | 3 + .../contracts_011/opcodes/transfer_tokens.tz | 5 + tests_python/contracts_011/opcodes/uncomb.tz | 8 + tests_python/contracts_011/opcodes/unpair.tz | 71 + .../contracts_011/opcodes/update_big_map.tz | 6 + .../contracts_011/opcodes/utxo_read.tz | 9 + tests_python/contracts_011/opcodes/utxor.tz | 24 + .../contracts_011/opcodes/view_fib.tz | 9 + .../opcodes/view_mutual_recursion.tz | 11 + .../contracts_011/opcodes/view_op_add.tz | 3 + .../contracts_011/opcodes/view_op_constant.tz | 3 + .../contracts_011/opcodes/view_op_id.tz | 4 + .../opcodes/view_op_nonexistent_addr.tz | 5 + .../opcodes/view_op_nonexistent_func.tz | 3 + .../opcodes/view_op_test_step_contants.tz | 8 + ...iew_op_toplevel_inconsistent_input_type.tz | 3 + ...ew_op_toplevel_inconsistent_output_type.tz | 3 + .../contracts_011/opcodes/view_rec.tz | 12 + .../opcodes/view_toplevel_lib.tz | 67 + .../contracts_011/opcodes/voting_power.tz | 7 + tests_python/contracts_011/opcodes/xor.tz | 13 + tests_python/tests_011/__init__.py | 0 ...contract.TestNormalize::test_normalize.out | 8 + ...tNormalize::test_normalize_legacy_flag.out | 8 + ...Normalize::test_normalize_script[None].out | 10 + ...lize::test_normalize_script[Optimized].out | 10 + ...est_normalize_script[Optimized_legacy].out | 12 + ...alize::test_normalize_script[Readable].out | 10 + ...e_type[list (pair nat int bool bytes)].out | 3 + ...rmalize_type[list (pair nat int bool)].out | 3 + ...st_normalize_type[list (pair nat int)].out | 3 + ...rmalize::test_normalize_type[list nat].out | 3 + ...estNormalize::test_normalize_type[nat].out | 3 + ...ormalize_type[pair nat int bool bytes].out | 3 + ...test_normalize_type[pair nat int bool].out | 3 + ...ize::test_normalize_type[pair nat int].out | 3 + ...e::test_normalize_unparsing_mode[None].out | 3 + ...st_normalize_unparsing_mode[Optimized].out | 3 + ...alize_unparsing_mode[Optimized_legacy].out | 5 + ...est_normalize_unparsing_mode[Readable].out | 3 + ..._hash[client_regtest_custom_scrubber0].out | 282 + ...st_contract_hash[opcodes--view_fac.tz].out | 3 + ...st_contract_hash[opcodes--view_fib.tz].out | 3 + ...ash[opcodes--view_mutual_recursion.tz].out | 3 + ...contract_hash[opcodes--view_op_add.tz].out | 3 + ..._contract_hash[opcodes--view_op_id.tz].out | 3 + ...[opcodes--view_op_nonexistent_addr.tz].out | 3 + ...[opcodes--view_op_nonexistent_func.tz].out | 3 + ...pcodes--view_op_test_step_contants.tz].out | 3 + ...p_toplevel_inconsistent_input_type.tz].out | 3 + ..._toplevel_inconsistent_output_type.tz].out | 3 + ...st_contract_hash[opcodes--view_rec.tz].out | 3 + ...ct_hash[opcodes--view_toplevel_lib.tz].out | 3 + ...::test_self_address_originate_receiver.out | 50 + ...er::test_self_address_originate_sender.out | 50 + ...ddressTransfer::test_send_self_address.out | 42 + ...81.TestBls12_381::test_add_one_one[Fr].out | 9 + ...81.TestBls12_381::test_add_one_one[G1].out | 9 + ...81.TestBls12_381::test_add_one_one[G2].out | 9 + ...TestBls12_381::test_add_one_random[Fr].out | 72 + ...TestBls12_381::test_add_one_random[G1].out | 72 + ...TestBls12_381::test_add_one_random[G2].out | 72 + ...1.TestBls12_381::test_add_one_zero[Fr].out | 9 + ...1.TestBls12_381::test_add_one_zero[G1].out | 9 + ...1.TestBls12_381::test_add_one_zero[G2].out | 9 + ...TestBls12_381::test_add_random_one[Fr].out | 72 + ...TestBls12_381::test_add_random_one[G1].out | 72 + ...TestBls12_381::test_add_random_one[G2].out | 72 + ...tBls12_381::test_add_random_random[Fr].out | 72 + ...tBls12_381::test_add_random_random[G1].out | 72 + ...tBls12_381::test_add_random_random[G2].out | 72 + ...estBls12_381::test_add_random_zero[Fr].out | 72 + ...estBls12_381::test_add_random_zero[G1].out | 72 + ...estBls12_381::test_add_random_zero[G2].out | 72 + ...1.TestBls12_381::test_add_zero_one[Fr].out | 9 + ...1.TestBls12_381::test_add_zero_one[G1].out | 9 + ...1.TestBls12_381::test_add_zero_one[G2].out | 9 + ...estBls12_381::test_add_zero_random[Fr].out | 72 + ...estBls12_381::test_add_zero_random[G1].out | 72 + ...estBls12_381::test_add_zero_random[G2].out | 72 + ....TestBls12_381::test_add_zero_zero[Fr].out | 9 + ....TestBls12_381::test_add_zero_zero[G1].out | 9 + ....TestBls12_381::test_add_zero_zero[G2].out | 9 + ...fr_bytes_parameters_more_than_32_bytes.out | 8 + ..._bls12_381.TestBls12_381::test_groth16.out | 9 + ...81.TestBls12_381::test_mul_one_one[Fr].out | 9 + ...81.TestBls12_381::test_mul_one_one[G1].out | 9 + ...81.TestBls12_381::test_mul_one_one[G2].out | 9 + ...TestBls12_381::test_mul_one_random[Fr].out | 72 + ...TestBls12_381::test_mul_one_random[G1].out | 72 + ...TestBls12_381::test_mul_one_random[G2].out | 72 + ...1.TestBls12_381::test_mul_one_zero[Fr].out | 9 + ...1.TestBls12_381::test_mul_one_zero[G1].out | 9 + ...1.TestBls12_381::test_mul_one_zero[G2].out | 9 + ...TestBls12_381::test_mul_random_one[Fr].out | 72 + ...TestBls12_381::test_mul_random_one[G1].out | 72 + ...TestBls12_381::test_mul_random_one[G2].out | 72 + ...tBls12_381::test_mul_random_random[Fr].out | 72 + ...tBls12_381::test_mul_random_random[G1].out | 72 + ...tBls12_381::test_mul_random_random[G2].out | 72 + ...estBls12_381::test_mul_random_zero[Fr].out | 72 + ...estBls12_381::test_mul_random_zero[G1].out | 72 + ...estBls12_381::test_mul_random_zero[G2].out | 72 + ...1.TestBls12_381::test_mul_zero_one[Fr].out | 9 + ...1.TestBls12_381::test_mul_zero_one[G1].out | 9 + ...1.TestBls12_381::test_mul_zero_one[G2].out | 9 + ...estBls12_381::test_mul_zero_random[Fr].out | 72 + ...estBls12_381::test_mul_zero_random[G1].out | 72 + ...estBls12_381::test_mul_zero_random[G2].out | 72 + ....TestBls12_381::test_mul_zero_zero[Fr].out | 9 + ....TestBls12_381::test_mul_zero_zero[G1].out | 9 + ....TestBls12_381::test_mul_zero_zero[G2].out | 9 + ...12_381.TestBls12_381::test_neg_one[Fr].out | 9 + ...12_381.TestBls12_381::test_neg_one[G1].out | 9 + ...12_381.TestBls12_381::test_neg_one[G2].out | 9 + ...381.TestBls12_381::test_neg_random[Fr].out | 72 + ...381.TestBls12_381::test_neg_random[G1].out | 72 + ...381.TestBls12_381::test_neg_random[G2].out | 72 + ...2_381.TestBls12_381::test_neg_zero[Fr].out | 9 + ...2_381.TestBls12_381::test_neg_zero[G1].out | 9 + ...2_381.TestBls12_381::test_neg_zero[G2].out | 9 + ...381.TestBls12_381::test_pairing_neg_g1.out | 72 + ...381.TestBls12_381::test_pairing_neg_g2.out | 72 + ...12_381.TestBls12_381::test_pairing_nil.out | 9 + ...81.TestBls12_381::test_pairing_one_one.out | 9 + ...TestBls12_381::test_pairing_one_random.out | 72 + ...1.TestBls12_381::test_pairing_one_zero.out | 9 + ...TestBls12_381::test_pairing_random_one.out | 72 + ...tBls12_381::test_pairing_random_random.out | 72 + ...estBls12_381::test_pairing_random_zero.out | 72 + ...1.TestBls12_381::test_pairing_zero_one.out | 9 + ...estBls12_381::test_pairing_zero_random.out | 72 + ....TestBls12_381::test_pairing_zero_zero.out | 9 + ...tBls12_381::test_signature_aggregation.out | 142 + ..._381.TestBls12_381::test_store_one[Fr].out | 9 + ..._381.TestBls12_381::test_store_one[G1].out | 9 + ..._381.TestBls12_381::test_store_one[G2].out | 9 + ...1.TestBls12_381::test_store_random[Fr].out | 72 + ...1.TestBls12_381::test_store_random[G1].out | 72 + ...1.TestBls12_381::test_store_random[G2].out | 72 + ...381.TestBls12_381::test_store_zero[Fr].out | 9 + ...381.TestBls12_381::test_store_zero[G1].out | 9 + ...381.TestBls12_381::test_store_zero[G2].out | 9 + ...est_macro_expansion[macros--assert.tz].out | 9 + ...cro_expansion[macros--assert_cmpeq.tz].out | 12 + ...cro_expansion[macros--assert_cmpge.tz].out | 12 + ...cro_expansion[macros--assert_cmpgt.tz].out | 12 + ...cro_expansion[macros--assert_cmple.tz].out | 12 + ...cro_expansion[macros--assert_cmplt.tz].out | 12 + ...ro_expansion[macros--assert_cmpneq.tz].out | 12 + ..._macro_expansion[macros--assert_eq.tz].out | 13 + ..._macro_expansion[macros--assert_ge.tz].out | 13 + ..._macro_expansion[macros--assert_gt.tz].out | 13 + ..._macro_expansion[macros--assert_le.tz].out | 13 + ..._macro_expansion[macros--assert_lt.tz].out | 13 + ...macro_expansion[macros--assert_neq.tz].out | 13 + ..._expansion[macros--big_map_get_add.tz].out | 23 + ...acro_expansion[macros--big_map_mem.tz].out | 14 + ...macro_expansion[macros--build_list.tz].out | 24 + ...ro_expansion[macros--carn_and_cdrn.tz].out | 29 + ...st_macro_expansion[macros--compare.tz].out | 22 + ...ro_expansion[macros--compare_bytes.tz].out | 22 + ...:test_macro_expansion[macros--fail.tz].out | 3 + ..._macro_expansion[macros--guestbook.tz].out | 18 + ...xpansion[macros--macro_annotations.tz].out | 13 + ...cro_expansion[macros--map_caddaadr.tz].out | 40 + ...acro_expansion[macros--max_in_list.tz].out | 17 + ...::test_macro_expansion[macros--min.tz].out | 13 + ...macro_expansion[macros--pair_macro.tz].out | 18 + ...cro_expansion[macros--set_caddaadr.tz].out | 33 + ...ro_expansion[macros--take_my_money.tz].out | 14 + ...cro_expansion[macros--unpair_macro.tz].out | 20 + ...ination::test_big_map_origination_diff.out | 29 + ...igination::test_big_map_origination_id.out | 27 + ...tion::test_big_map_origination_literal.out | 48 + ...rigination::test_big_map_transfer_diff.out | 23 + ...pOrigination::test_big_map_transfer_id.out | 22 + ...s.TestContractOnchainLevel::test_level.out | 121 + ...actOnchainOpcodes::test_contract_fails.out | 2 + ...tContractOnchainOpcodes::test_gen_keys.out | 2 + ...ontractOnchainOpcodes::test_init_proxy.out | 51 + ...s.TestContractOnchainOpcodes::test_now.out | 2 + ....TestContractOnchainOpcodes::test_self.out | 2 + ...estContractOnchainOpcodes::test_sender.out | 2 + ...tractOnchainOpcodes::test_set_delegate.out | 121 + ...TestContractOnchainOpcodes::test_slice.out | 85 + ...\"spsig1PPUFZucuAQybs5wsqs.818025e860.out" | 66 + ...0e55c43a9a857214d8761e67b75.2d6806d54e.out | 66 + ...0e55c43a9a857214d8761e67b75.378d03ae2d.out | 66 + ...0e55c43a9a857214d8761e67b75.57fdc7ad1c.out | 66 + ...0e55c43a9a857214d8761e67b75.c583c796bf.out | 66 + ...ef0e55c43a9a857214d8761e67b.7da5c9014e.out | 45 + ...estContractOnchainOpcodes::test_source.out | 117 + ...ntractOnchainOpcodes::test_split_bytes.out | 135 + ...tractOnchainOpcodes::test_split_string.out | 135 + ...ntractOnchainOpcodes::test_store_input.out | 180 + ...trace_origination[compare_big_type.tz].out | 91 + ...race_origination[compare_big_type2.tz].out | 95 + ...ctOnchainOpcodes::test_transfer_amount.out | 80 + ...ctOnchainOpcodes::test_transfer_tokens.out | 232 + ...(Some 4) {})-\"hello\"-(Pa.f6092ac5d6.out" | 35 + ...(Some 5) { Elt \"hello\" 4.0427752f13.out" | 35 + ...(Some 5) { Elt \"hello\" 4.0793dc66d5.out" | 36 + ...None { Elt \"1\" 1 ; .df114499b8.out" | 36 + ...None { Elt \"1\" 1 ; .f9bea98de9.out" | 36 + ...None { Elt \"hello\" 4 })-.1db12cd837.out" | 35 + ...None {})-\"hello\"-(Pair N.6fc7d0acf2.out" | 35 + ..." \"one\" ; Elt \"2\" \"tw.524c5459f8.out" | 46 + ...ello\" \"hi\" } None)-\"\".33eba403e7.out" | 45 + ...hello\" \"hi\" } None)-\"h.a5cd1005c9.out" | 45 + ...one\" ; Elt \"2\" \"two\" .6f3d35b151.out" | 36 + ...one\" ; Elt \"2\" \"two\" .76aeaa0706.out" | 48 + ...one\" ; Elt \"2\" \"two\" .7e7197f248.out" | 48 + ...one\" ; Elt \"2\" \"two\" .7ef2c415a7.out" | 49 + ...one\" ; Elt \"2\" \"two\" .b688cc94a7.out" | 49 + ...one\" ; Elt \"2\" \"two\" .c68db221ed.out" | 48 + ...erflow[mul_overflow.tz-Unit-Left Unit].out | 26 + ...rflow[mul_overflow.tz-Unit-Right Unit].out | 26 + ...ow[shifts.tz-None-(Left (Pair 1 257))].out | 26 + ...[shifts.tz-None-(Left (Pair 123 257))].out | 26 + ...w[shifts.tz-None-(Right (Pair 1 257))].out | 26 + ...shifts.tz-None-(Right (Pair 123 257))].out | 26 + ...TestContractOpcodes::test_balance[0.5].out | 21 + ...s.TestContractOpcodes::test_balance[0].out | 21 + ...estContractOpcodes::test_balance[1000].out | 21 + ...s.TestContractOpcodes::test_balance[1].out | 21 + ...stContractOpcodes::test_balance[1e-06].out | 21 + ...s.TestContractOpcodes::test_balance[5].out | 21 + ...Opcodes::test_balance[8000000000000.0].out | 21 + ... \"two\" }) )-(Right (Righ.7492e8cdea.out" | 90 + ... \"two\" }))-(Left Unit)-(.21b30dd90f.out" | 44 + ... \"two\" }))-(Right (Left .2873ef610c.out" | 39 + ... \"two\" }))-(Right (Left .8a6f480005.out" | 35 + ... \"two\" }))-(Right (Right.d336ca1903.out" | 83 + ...Pair \"foo\" \"bar\" } { P.7f2ee47600.out" | 135 + ...tContractOpcodes::test_check_signature.out | 241 + ...tract_input_output[abs.tz-Unit-0-Unit].out | 38 + ....tz-Unit-12039123919239192312931-Unit].out | 38 + ...act_input_output[abs.tz-Unit-948-Unit].out | 38 + ...ct_input_output[add.tz-Unit-Unit-Unit].out | 211 + ...r 0x00 0x00-(Some 0x0000000.3c2de60480.out | 30 + ...r 0x01 0x00-(Some 0x0100000.12b2c1172b.out | 30 + ...r 0x010000 0x00-(Some 0x010.0e44fc6f40.out | 30 + ...r 0x010000 0x010000-(Some 0.7e0ed229a3.out | 30 + ...air -100 100)-(Some \"1970.7c1b1e4e5b.out" | 36 + ...air 0 \"1970-01-01T00:00:0.528ed42c01.out" | 36 + ...air 100 100)-(Some \"1970-.6566111ad2.out" | 36 + ...air \"1970-01-01T00:00:00Z.72c424f3da.out" | 36 + ...air 100 -100)-(Some \"1970.7c4b12e9aa.out" | 36 + ...air 100 100)-(Some \"1970-.af32743640.out" | 36 + ...dhe2Kb8ZdTrdNy4bFNyScx5\"-.f9045c3a04.out" | 23 + ...-None-(Pair False False)-(Some False)].out | 31 + ...z-None-(Pair False True)-(Some False)].out | 31 + ...z-None-(Pair True False)-(Some False)].out | 31 + ....tz-None-(Pair True True)-(Some True)].out | 31 + ...t_output[and_binary.tz-Unit-Unit-Unit].out | 93 + ...l_1.tz-False-(Pair False False)-False].out | 24 + ...al_1.tz-False-(Pair False True)-False].out | 24 + ...al_1.tz-False-(Pair True False)-False].out | 24 + ...ical_1.tz-False-(Pair True True)-True].out | 24 + ...put[balance.tz-111-Unit-4000000000000].out | 21 + ...lt 0 1 } None)-1-(Pair 4 (S.2292d6ce17.out | 43 + ...lt 0 1 } None)-1-(Pair 4 (S.dda583f5e9.out | 43 + ...lt 1 0 } None)-1-(Pair 4 (S.6d753598ba.out | 43 + ...lt 1 0 } None)-1-(Pair 4 (S.73700321f8.out | 43 + ...lt 1 4 ; Elt 2 11 } None)-1.1182eca937.out | 44 + ...lt 1 4 ; Elt 2 11 } None)-1.2ea67af009.out | 44 + ...lt 1 4 ; Elt 2 11 } None)-2.1eead33885.out | 44 + ...lt 1 4 ; Elt 2 11 } None)-2.47f55c94c8.out | 44 + ...lt 1 4 ; Elt 2 11 } None)-3.7f1f2ab27d.out | 44 + ...lt 1 4 ; Elt 2 11 } None)-3.a3c5c126ce.out | 44 + ...air {} None)-1-(Pair 4 (Some False))0].out | 42 + ...air {} None)-1-(Pair 4 (Some False))1].out | 42 + ... \"bar\" 4 ; Elt \"foo\" 1.4be99ce05d.out" | 44 + ... \"bar\" 4 ; Elt \"foo\" 1.50c0e0ff8b.out" | 44 + ... \"bar\" 4 ; Elt \"foo\" 1.775c22b027.out" | 44 + ... \"foo\" 0 } None)-\"foo\".968709d39d.out" | 43 + ... \"foo\" 1 } None)-\"bar\".cdcfaf9d09.out" | 43 + ... None)-\"bar\"-(Pair 4 (Some False))].out" | 42 + ...padded.tz-None-Unit-(Some 0.9b6e8bcbd3.out | 24 + ...e-Unit-(Some 0x100000000000.d1219ca789.out | 24 + ...utput[bls12_381_fr_to_int.tz-0-0x00-0].out | 21 + ...utput[bls12_381_fr_to_int.tz-0-0x01-1].out | 21 + ...8db8e57af88d9576acd181b89f2.7a85c336ff.out | 22 + ...9e8abf8dc324a010007addde986.b821eb26b3.out | 22 + ...ut[bls12_381_fr_to_mutez.tz-0-0x10-16].out | 32 + ...000000000000000000000000000.0accef5bef.out | 22 + ...000000000000000000000000000.0ecc537252.out | 22 + ...000000000000000000000000000.2229b767cd.out | 22 + ...000000000000000000000000000.2ff549b46b.out | 22 + ...000000000000000000000000000.bf8a711be6.out | 23 + ...000000000000000000000000000.d41cbb044b.out | 22 + ...a5ad0a633e4880d2296f08ec5c1.a50412e458.out | 23 + ...cd0fa853810e356f1eb79721e80.f3a349c4a7.out | 23 + ...be1766f92cd82c5e5135c374a03.1b9676e4c2.out | 23 + ...be1766f92cd82c5e5135c374a03.e966dc6de5.out | 23 + ...000000000000000000000000000.964835cc43.out | 22 + ...000000000000000000000000000.b25ea709fb.out | 22 + ...000000000000000000000000000.eae36753ea.out | 23 + ...000000000000000000000000000.ee57dac8f7.out | 22 + ...a5ad0a633e4880d2296f08ec5c1.928f6d4b93.out | 23 + ...cd0fa853810e356f1eb79721e80.bd5800f6b8.out | 23 + ...be1766f92cd82c5e5135c374a03.00e897789a.out | 23 + ...be1766f92cd82c5e5135c374a03.a4697eaa13.out | 23 + ...000000000000000000000000000.0177355bbf.out | 25 + ...000000000000000000000000000.744166c609.out | 25 + ...000000000000000000000000000.9f3c5cdc6a.out | 25 + ...000000000000000000000000000.a54cb341ba.out | 25 + ...000000000000000000000000000.b0dc584c94.out | 25 + ...000000000000000000000000000.bddcad090c.out | 26 + ...a5ad0a633e4880d2296f08ec5c1.92c153eb47.out | 26 + ...cd0fa853810e356f1eb79721e80.290ab49d11.out | 26 + ...be1766f92cd82c5e5135c374a03.69f3589a06.out | 26 + ...be1766f92cd82c5e5135c374a03.fee3c5cf43.out | 26 + ...000000000000000000000000000.1bccc033e8.out | 26 + ...000000000000000000000000000.40958700fe.out | 25 + ...000000000000000000000000000.6c62b03d78.out | 25 + ...000000000000000000000000000.d23f269341.out | 25 + ...a5ad0a633e4880d2296f08ec5c1.927f808504.out | 26 + ...cd0fa853810e356f1eb79721e80.0c114c956a.out | 26 + ...be1766f92cd82c5e5135c374a03.03c4f38e68.out | 26 + ...be1766f92cd82c5e5135c374a03.8ed19cfdd9.out | 26 + ...input_output[car.tz-0-(Pair 34 17)-34].out | 21 + ...input_output[cdr.tz-0-(Pair 34 17)-17].out | 21 + ...prcVkpaWU\")-Unit-(Some \".8420090f97.out" | 23 + ...770)-Unit-(Some \"NetXdQprcVkpaWU\")].out" | 23 + ...None-Unit-(Some \"NetXdQprcVkpaWU\")].out" | 23 + ...mb-get.tz-Unit-(Pair 1 4 2 Unit)-Unit].out | 123 + ... Unit)-(Some (Pair 2 4 \"t.886cc365c6.out" | 36 + ...r 1 4 2 Unit)-Unit-(Pair 2 12 8 Unit)].out | 39 + ...omb.tz-(Pair 0 0 0)-Unit-(Pair 1 2 3)].out | 30 + ...nput_output[compare.tz-Unit-Unit-Unit].out | 398 + ...; -1 ; 0 ; 1 ; 9999999 }-{ .bbaa8924d2.out | 350 + ...-{ \"World!\" }-{ \"Hello World!\" }].out" | 28 + ..."test2\" }-{ \"Hello test1.c27e8c3ee6.out" | 35 + ...input_output[concat_hello.tz-{}-{}-{}].out | 21 + ...}-{ 0xab ; 0xcd }-{ 0xffab ; 0xffcd }].out | 35 + ...hello_bytes.tz-{}-{ 0xcd }-{ 0xffcd }].out | 28 + ...output[concat_hello_bytes.tz-{}-{}-{}].out | 21 + ...; \"World\" ; \"!\" }-\"He.0c7b4cd53c.out" | 119 + ...\"-{ \"a\" ; \"b\" ; \"c\" }-\"abc\"].out" | 96 + ...t_output[concat_list.tz-\"\"-{}-\"\"].out" | 27 + ...ns.tz-{ -5 ; 10 }-99-{ 99 ; -5 ; 10 }].out | 22 + ..._output[cons.tz-{ 10 }--5-{ -5 ; 10 }].out | 22 + ...act_input_output[cons.tz-{}-10-{ 10 }].out | 22 + ...ir { \"A\" } { \"B\" })-(Some False)].out" | 166 + ...\"B\" ; \"asdf\" ; \"C\" }.4360bbe5d0.out" | 410 + ...\"C\" ; \"asdf\" } { \"B\".ff6e4785ee.out" | 437 ++ ...air { \"B\" } { \"B\" })-(Some True)].out" | 166 + ...ir { \"c\" } { \"B\" })-(Some False)].out" | 166 + ..._all.tz-None-(Pair {} {})-(Some True)].out | 63 + ...wnzENRdhe2Kb8ZdTrdNy4bFNyScx5\"-Unit].out" | 29 + ...Some \"KT1Mjjcb6tmSsLm7Cb3.c3984fbc14.out" | 49 + ...970-01-01T00:03:20Z\" \"19.90e9215d17.out" | 34 + ...t[diff_timestamps.tz-111-(Pair 0 0)-0].out | 34 + ...[diff_timestamps.tz-111-(Pair 0 1)--1].out | 34 + ...t[diff_timestamps.tz-111-(Pair 1 0)-1].out | 34 + ...r 16 (Pair 15 (Pair 14 (Pai.2794d4782e.out | 3431 +++++++++ ... 3 (Pair 12 (Pair 16 (Pair .d473151c0f.out | 3431 +++++++++ ...air (Pair (Pair (Pair 1 2) 3) 4) 5)-5].out | 61 + ...p.tz-(Pair 0 0)-(Pair 1 1)-(Pair 1 2)].out | 36 + ...z-(Pair 0 0)-(Pair 15 9)-(Pair 15 24)].out | 36 + ...air (Pair (Pair (Pair 1 2) 3) 4) 5)-6].out | 93 + ...air (Pair (Pair (Pair 1 2) 3) 4) 5)-5].out | 39 + ...air (Pair (Pair (Pair 1 2) 3) 4) 5)-1].out | 57 + ..._input_output[dup-n.tz-Unit-Unit-Unit].out | 248 + ... None)-(Pair -8 2)-(Pair (S.ecc0e72cbb.out | 142 + ... None)-(Pair 10 -3)-(Pair (.3caea50555.out | 142 + ... None)-(Pair 10 0)-(Pair No.f9448c04fb.out | 142 + ... None)-(Pair 10 (Left 0))-(Left None)].out | 37 + ...air 10 (Left 10))-(Left (So.f782cc1dec.out | 37 + ...air 10 (Left 3))-(Left (Som.016b4db96c.out | 37 + ...one)-(Pair 10 (Right 0))-(Right None)].out | 37 + ...air 10 (Right 10))-(Right (.e705a30e07.out | 37 + ...air 10 (Right 3))-(Right (S.44485eda6a.out | 37 + ...air 5 (Right 10))-(Right (S.8ab987af15.out | 37 + ...-{}-Unit-{ Elt \"hello\" \"world\" }].out" | 33 + ...t[exec_concat.tz-\"?\"-\"\"-\"_abc\"].out" | 48 + ...oncat.tz-\"?\"-\"test\"-\"test_abc\"].out" | 48 + ...tput[first.tz-111-{ 1 ; 2 ; 3 ; 4 }-1].out | 30 + ...act_input_output[first.tz-111-{ 4 }-4].out | 30 + ...me 4) {})-\"hello\"-(Pair .161d86cef6.out" | 34 + ...me 5) { Elt \"hello\" 4 }).684ab7e326.out" | 34 + ...me 5) { Elt \"hello\" 4 }).d49817fb83.out" | 34 + ...e { Elt \"1\" 1 ; .6900b1da14.out" | 34 + ...e { Elt \"1\" 1 ; .bca0ede8be.out" | 34 + ... { Elt \"hello\" 4 })-\"he.c1b4e1d6dc.out" | 34 + ...ir None {})-\"hello\"-(Pair None {})].out" | 34 + ... \"1\" \"one\" ; .bc4127094e.out" | 41 + ..."hello\" \"hi\" })-\"\"-(P.0c03056487.out" | 41 + ...\"hello\" \"hi\" })-\"hell.cc45544c66.out" | 41 + ...nW72KG6RoHtYW7p12T6GKc7nAb.613ad6b637.out" | 23 + ...2m2muMxViSM47MPsGQzmyjnNTa.da50984e8d.out" | 23 + ...xb4c26c20de52a4eaf0d8a340d.2bba28b0bf.out" | 23 + ...-0x46fdbcb4ea4eadad5615cda.acc82cd954.out" | 23 + ..._output[if.tz-None-False-(Some False)].out | 27 + ...ut_output[if.tz-None-True-(Some True)].out | 27 + ....tz-\"?\"-(Some \"hello\")-\"hello\"].out" | 23 + ...ut_output[if_some.tz-\"?\"-None-\"\"].out" | 25 + ...t_input_output[int.tz-None-0-(Some 0)].out | 23 + ...t_input_output[int.tz-None-1-(Some 1)].out | 23 + ...t_output[int.tz-None-9999-(Some 9999)].out | 23 + ...c20776f726c6421-(Some 0xb6e.34c02678c9.out | 24 + ...Left \"X\")-(Left True)-(Right True)].out" | 25 + ...ft \"X\")-(Right \"a\")-(Left \"a\")].out" | 25 + ...ract_input_output[level.tz-111-Unit-1].out | 21 + ...{ \"d\" ; \"e\" ; \"f\" }-\"abcdef\"].out" | 27 + ...ut[list_concat.tz-\"abc\"-{}-\"abc\"].out" | 27 + ...tz-0x-{ 0x00 ; 0x11 ; 0x00 }-0x001100].out | 27 + ..._output[list_concat_bytes.tz-0x-{}-0x].out | 27 + ...b-{ 0xcd ; 0xef ; 0x00 }-0x00abcdef00].out | 27 + ...list_concat_bytes.tz-0xabcd-{}-0xabcd].out | 27 + ... ; \"3\" }-{ \"1\" ; \"2\" ; \"3\" }].out" | 19 + ... ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" | 19 + ...input_output[list_id.tz-{\"\"}-{}-{}].out" | 19 + ... ; \"3\" }-{ \"1\" ; \"2\" ; \"3\" }].out" | 27 + ... ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" | 27 + ...t_output[list_id_map.tz-{\"\"}-{}-{}].out" | 21 + ...tput[list_iter.tz-0-{ 10 ; 2 ; 1 }-20].out | 42 + ...tput[list_iter.tz-0-{ 3 ; 6 ; 9 }-162].out | 42 + ...}-{ 1 ; 1 ; 1 ; 1 }-{ 1 ; 2 ; 3 ; 4 }].out | 136 + ...}-{ 1 ; 2 ; 3 ; 0 }-{ 1 ; 3 ; 5 ; 3 }].out | 136 + ...ut_output[list_map_block.tz-{0}-{}-{}].out | 36 + ...ze.tz-111-{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }-6].out | 21 + ...tput[list_size.tz-111-{ 1 ; 2 ; 3 }-3].out | 21 + ...input_output[list_size.tz-111-{ 1 }-1].out | 21 + ...ct_input_output[list_size.tz-111-{}-0].out | 21 + ... ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" | 163 + ...put_output[loop_left.tz-{\"\"}-{}-{}].out" | 52 + ...0 0 ; Elt 3 4 }-{ Elt 0 0 ; Elt 3 4 }].out | 19 + ...[map_id.tz-{}-{ Elt 0 0 }-{ Elt 0 0 }].out | 19 + ...[map_id.tz-{}-{ Elt 0 1 }-{ Elt 0 1 }].out | 19 + ... Elt 0 100 ; Elt 2 100 }-(Pair 2 200)].out | 152 + ...-{ Elt 1 1 ; Elt 2 100 }-(Pair 3 101)].out | 152 + ...foo\" 1 }-15-{ Elt \"bar\".12b9d73d5a.out" | 68 + ...lt \"foo\" 1 }-10-{ Elt \"foo\" 11 }].out" | 50 + ...ract_input_output[map_map.tz-{}-10-{}].out | 32 + ... 1 } None)-1-(Pair { Elt 0 .7396e5f090.out | 42 + ... 0 } None)-1-(Pair { Elt 1 .cef8ce601a.out | 42 + ... 4 ; Elt 2 11 } None)-1-(Pa.1a55a5bfa5.out | 42 + ... 4 ; Elt 2 11 } None)-2-(Pa.89cc24d256.out | 42 + ... 4 ; Elt 2 11 } None)-3-(Pa.2fba3165c0.out | 42 + ...air {} None)-1-(Pair {} (Some False))].out | 42 + ...ar\" 4 ; Elt \"foo\" 11 } .6d625e02a5.out" | 42 + ...ar\" 4 ; Elt \"foo\" 11 } .a7e3837a82.out" | 42 + ...ar\" 4 ; Elt \"foo\" 11 } .c7716fe79e.out" | 42 + ...oo\" 0 } None)-\"foo\"-(Pa.7861a3b1e2.out" | 42 + ...oo\" 1 } None)-\"bar\"-(Pa.fa8366e8a8.out" | 42 + ...None)-\"bar\"-(Pair {} (Some False))].out" | 42 + ... \"b\" 2 ; Elt \"c\" 3 ; .1da2c2c3fa.out" | 21 + ...\" 1 ; Elt \"b\" 2 ; Elt \"c\" 3 }-3].out" | 21 + ...ut[map_size.tz-111-{ Elt \"a\" 1 }-1].out" | 21 + ...act_input_output[map_size.tz-111-{}-0].out | 21 + ...ct_input_output[mul.tz-Unit-Unit-Unit].out | 131 + ...0-257-0x0101000000000000000.be11332c7f.out | 38 + ...2-16-0x10000000000000000000.8230fb4fac.out | 38 + ...act_input_output[neg.tz-0-(Left -2)-2].out | 25 + ...ract_input_output[neg.tz-0-(Left 0)-0].out | 25 + ...act_input_output[neg.tz-0-(Left 2)--2].out | 25 + ...act_input_output[neg.tz-0-(Right 0)-0].out | 25 + ...ct_input_output[neg.tz-0-(Right 2)--2].out | 25 + ...nput_output[none.tz-Some 10-Unit-None].out | 21 + ..._output[not.tz-None-False-(Some True)].out | 23 + ..._output[not.tz-None-True-(Some False)].out | 23 + ...not_binary.tz-None-(Left -8)-(Some 7)].out | 27 + ...not_binary.tz-None-(Left -9)-(Some 8)].out | 27 + ...not_binary.tz-None-(Left 0)-(Some -1)].out | 27 + ...not_binary.tz-None-(Left 7)-(Some -8)].out | 27 + ...not_binary.tz-None-(Left 8)-(Some -9)].out | 27 + ...ot_binary.tz-None-(Right 0)-(Some -1)].out | 27 + ...ot_binary.tz-None-(Right 7)-(Some -8)].out | 27 + ...ot_binary.tz-None-(Right 8)-(Some -9)].out | 27 + ...-None-(Pair False False)-(Some False)].out | 35 + ...tz-None-(Pair False True)-(Some True)].out | 35 + ...tz-None-(Pair True False)-(Some True)].out | 35 + ....tz-None-(Pair True True)-(Some True)].out | 35 + ...or_binary.tz-None-(Pair 0 8)-(Some 8)].out | 26 + ..._binary.tz-None-(Pair 14 1)-(Some 15)].out | 26 + ..._binary.tz-None-(Pair 15 4)-(Some 15)].out | 26 + ...r_binary.tz-None-(Pair 4 8)-(Some 12)].out | 26 + ...or_binary.tz-None-(Pair 7 7)-(Some 7)].out | 26 + ...or_binary.tz-None-(Pair 8 0)-(Some 8)].out | 26 + ... (Pair 1 (Pair \"foobar\".368bdfd73a.out" | 845 ++ ... (Pair 1 (Pair \"foobar\".735d9ae802.out" | 845 ++ ...ir \"edpkuBknW28nW72KG6RoH.1ac5de50fb.out" | 1194 +++ ...ir \"edpkuBknW28nW72KG6RoH.4e20b52378.out" | 1032 +++ ...alse False)-(Some (Pair False False))].out | 21 + ... False True)-(Some (Pair False True))].out | 21 + ... True False)-(Some (Pair True False))].out | 21 + ...ir True True)-(Some (Pair True True))].out | 21 + ...ntract_input_output[pexec.tz-14-38-52].out | 47 + ... 0 ; 1 ; 2 ; 3}-4-{ 0 ; 7 ; 14 ; 21 }].out | 282 + ...utput[ret_int.tz-None-Unit-(Some 300)].out | 23 + ... ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" | 42 + ...input_output[reverse.tz-{\"\"}-{}-{}].out" | 27 + ... ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" | 131 + ..._output[reverse_loop.tz-{\"\"}-{}-{}].out" | 50 + ...tput[sapling_empty_state.tz-{}-Unit-0].out | 21 + ...output[self_address.tz-Unit-Unit-Unit].out | 46 + ..._default_entrypoint.tz-Unit-Unit-Unit].out | 47 + ...entrypoint.tz-Unit-Left (Left 0)-Unit].out | 93 + ...Pair \"hello\" 0)-\"\"-(Pair \"\" 0)].out" | 49 + ..."hello\" 0)-\"abc\"-(Pair \"abc\" 0)].out" | 49 + ...lo\" 0)-\"world\"-(Pair \"world\" 0)].out" | 49 + ...ir \"hello\" 0)-1-(Pair \"hello\" 1)].out" | 46 + ... \"hello\" 500)-3-(Pair \"hello\" 3)].out" | 46 + ..."hello\" 7)-100-(Pair \"hello\" 100)].out" | 46 + ... ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" | 19 + ...; \"bcde\" }-{ \"asdf\" ; \"bcde\" }].out" | 19 + ...tract_input_output[set_id.tz-{}-{}-{}].out | 19 + ..._iter.tz-111-{ -100 ; 1 ; 2 ; 3 }--94].out | 47 + ..._input_output[set_iter.tz-111-{ 1 }-1].out | 32 + ...act_input_output[set_iter.tz-111-{}-0].out | 27 + ..."World\" } None)-\"\"-(Pai.3d2044726e.out" | 61 + ...)-\"Hi\"-(Pair { \"Hi\" } .564beb9251.out" | 61 + ... None)-\"Hi\"-(Pair {} (Some False))].out" | 61 + ...ze.tz-111-{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }-6].out | 21 + ...utput[set_size.tz-111-{ 1 ; 2 ; 3 }-3].out | 21 + ..._input_output[set_size.tz-111-{ 1 }-1].out | 21 + ...act_input_output[set_size.tz-111-{}-0].out | 21 + ...0776f726c6421-(Some 0xf345a.a07ae9dddf.out | 24 + ...ts.tz-None-(Left (Pair 0 0))-(Some 0)].out | 30 + ...ts.tz-None-(Left (Pair 0 1))-(Some 0)].out | 30 + ...ts.tz-None-(Left (Pair 1 2))-(Some 4)].out | 30 + ....tz-None-(Left (Pair 15 2))-(Some 60)].out | 30 + ...s.tz-None-(Left (Pair 8 1))-(Some 16)].out | 30 + ...s.tz-None-(Right (Pair 0 0))-(Some 0)].out | 30 + ...s.tz-None-(Right (Pair 0 1))-(Some 0)].out | 30 + ...s.tz-None-(Right (Pair 1 2))-(Some 0)].out | 30 + ....tz-None-(Right (Pair 15 2))-(Some 3)].out | 30 + ...s.tz-None-(Right (Pair 8 1))-(Some 4)].out | 30 + ...ut_output[slice.tz-None-Pair 0 0-None].out | 31 + ...tz-Some \"Foo\"-Pair 0 0-(Some \"\")].out" | 37 + ...slice.tz-Some \"Foo\"-Pair 0 10-None].out" | 37 + ...-Some \"Foo\"-Pair 0 2-(Some \"Fo\")].out" | 37 + ...z-Some \"Foo\"-Pair 1 1-(Some \"o\")].out" | 37 + ...[slice.tz-Some \"Foo\"-Pair 1 3-None].out" | 37 + ...slice.tz-Some \"Foo\"-Pair 10 5-None].out" | 37 + ...FooFooFooFooFooFooFooFooFo.c508d67bb0.out" | 38 + ...put[slice_bytes.tz-None-Pair 0 1-None].out | 31 + ...s.tz-Some 0xaabbcc-Pair 0 0-(Some 0x)].out | 37 + ...tz-Some 0xaabbcc-Pair 0 1-(Some 0xaa)].out | 37 + ...z-Some 0xaabbcc-Pair 1 1-(Some 0xbb)0].out | 37 + ...z-Some 0xaabbcc-Pair 1 1-(Some 0xbb)1].out | 37 + ...-Some 0xaabbcc-Pair 1 2-(Some 0xbbcc)].out | 37 + ..._bytes.tz-Some 0xaabbcc-Pair 1 3-None].out | 37 + ...aabbccaabbccaabbccaabbccaab.df5895de85.out | 38 + ...d.tz-None-\"Hello\"-(Some \"Hello\")].out" | 21 + ..._id.tz-None-\"abcd\"-(Some \"abcd\")].out" | 21 + ...r 100 -100)-\"1970-01-01T00:03:20Z\"].out" | 34 + ...ir 100 100)-\"1970-01-01T00:00:00Z\"].out" | 34 + ...Pair 100 200000000000000000.3db82d2c25.out | 34 + ...00000 1000000)-(Some (Pair .b461aa042b.out | 67 + ...10000 1010000)-(Some (Pair .1e8cf7679c.out | 67 + ...t_output[uncomb.tz-0-(Pair 1 4 2)-142].out | 50 + ...input_output[unpair.tz-Unit-Unit-Unit].out | 462 ++ ...dpkuBknW28nW72KG6RoHtYW7p1.b2c677ad7b.out" | 32 + ...Pair False False)-(Some (Left False))].out | 32 + ... (Pair False True)-(Some (Left True))].out | 32 + ... (Pair True False)-(Some (Left True))].out | 32 + ... (Pair True True)-(Some (Left False))].out | 32 + ...one-Right (Pair 0 0)-(Some (Right 0))].out | 32 + ...one-Right (Pair 0 1)-(Some (Right 1))].out | 32 + ...one-Right (Pair 1 0)-(Some (Right 1))].out | 32 + ...one-Right (Pair 1 1)-(Some (Right 0))].out | 32 + ...-Right (Pair 42 21)-(Some (Right 63))].out | 32 + ...-Right (Pair 42 63)-(Some (Right 21))].out | 32 + ...s::test_hash_consistency_michelson_cli.out | 23 + ...bar\" 5 ; Elt \"foo\" 1 } .480b9afc63.out" | 9 + ...\"foo\" 1 } 1)-10-(Pair { .811573b5a7.out" | 9 + ...eeffect.tz-(Pair {} 0)-10-(Pair {} 0)].out | 9 + ...s.TestContractOpcodes::test_packunpack.out | 106 + ...roveTransferRemove::test_add_liquidity.out | 80 + ...ddApproveTransferRemove::test_approval.out | 40 + ...TransferRemove::test_approved_transfer.out | 41 + ...roveTransferRemove::test_call_approve1.out | 40 + ...roveTransferRemove::test_call_approve2.out | 40 + ...roveTransferRemove::test_call_approve3.out | 40 + ...TransferRemove::test_call_mint_or_burn.out | 39 + ...pproveTransferRemove::test_dex_storage.out | 7 + ...pproveTransferRemove::test_lqt_storage.out | 3 + ...eTransferRemove::test_remove_liquidity.out | 79 + ...stAddApproveTransferRemove::test_setup.out | 8 + ...pproveTransferRemove::test_tok_storage.out | 3 + ..._baking.TestTrades::test_add_liquidity.out | 80 + ...uidity_baking.TestTrades::test_buy_tok.out | 72 + ..._baking.TestTrades::test_call_approve1.out | 40 + ..._baking.TestTrades::test_call_approve2.out | 40 + ..._baking.TestTrades::test_call_approve3.out | 40 + ...ing.TestTrades::test_call_mint_or_burn.out | 39 + ...ty_baking.TestTrades::test_dex_storage.out | 7 + ...ty_baking.TestTrades::test_lqt_storage.out | 3 + ...idity_baking.TestTrades::test_sell_tok.out | 74 + ...iquidity_baking.TestTrades::test_setup.out | 8 + ...ty_baking.TestTrades::test_tok_storage.out | 3 + ...idity_baking.TestTrades::test_transfer.out | 42 + tests_python/tests_011/conftest.py | 146 + tests_python/tests_011/contract_paths.py | 20 + .../tests_011/per_block_vote_files/false.json | 1 + .../per_block_vote_files/invalid.json | 1 + .../per_block_vote_files/non_boolean.json | 1 + .../tests_011/per_block_vote_files/true.json | 1 + .../per_block_vote_files/wrong_key.json | 1 + tests_python/tests_011/protocol.py | 22 + tests_python/tests_011/test_accuser.py | 123 + tests_python/tests_011/test_baker_endorser.py | 117 + tests_python/tests_011/test_basic.py | 495 ++ tests_python/tests_011/test_binaries.py | 48 + .../test_block_times_ideal_scenario.py | 146 + tests_python/tests_011/test_bootstrap.py | 212 + tests_python/tests_011/test_client.py | 35 + .../tests_011/test_client_without_node.py | 450 ++ tests_python/tests_011/test_codec.py | 23 + tests_python/tests_011/test_contract.py | 2134 ++++++ .../tests_011/test_contract_annotations.py | 88 + tests_python/tests_011/test_contract_baker.py | 52 + .../tests_011/test_contract_bls12_381.py | 315 + .../tests_011/test_contract_macros.py | 447 ++ .../test_contract_onchain_opcodes.py | 1309 ++++ .../tests_011/test_contract_opcodes.py | 1905 +++++ tests_python/tests_011/test_cors.py | 47 + tests_python/tests_011/test_crypto.py | 47 + .../tests_011/test_double_endorsement.py | 115 + tests_python/tests_011/test_fa12.py | 352 + tests_python/tests_011/test_forge_block.py | 46 + tests_python/tests_011/test_fork.py | 85 + tests_python/tests_011/test_injection.py | 103 + .../tests_011/test_legacy_snapshots.py | 353 + tests_python/tests_011/test_legacy_upgrade.py | 214 + .../tests_011/test_liquidity_baking.py | 279 + tests_python/tests_011/test_many_bakers.py | 40 + tests_python/tests_011/test_many_nodes.py | 63 + tests_python/tests_011/test_mempool.py | 66 + tests_python/tests_011/test_migration.py | 204 + .../tests_011/test_migration_flattening.py | 183 + tests_python/tests_011/test_mockup.py | 720 ++ .../tests_011/test_multinode_snapshot.py | 753 ++ .../test_multinode_storage_reconstruction.py | 177 + .../tests_011/test_multiple_transfers.py | 133 + tests_python/tests_011/test_multisig.py | 620 ++ .../tests_011/test_nonce_seed_revelation.py | 108 + tests_python/tests_011/test_openapi.py | 73 + tests_python/tests_011/test_p2p.py | 147 + .../tests_011/test_per_block_votes.py | 119 + .../tests_011/test_perf_endorsement.py | 83 + tests_python/tests_011/test_programs.py | 97 + .../tests_011/test_proto_demo_counter.py | 88 + .../test_proto_demo_noops_manual_bake.py | 97 + tests_python/tests_011/test_rpc.py | 644 ++ tests_python/tests_011/test_sapling.py | 946 +++ .../tests_011/test_slice_fails_params.txt | 5 + .../tests_011/test_slice_success_params.txt | 1 + tests_python/tests_011/test_tls.py | 23 + tests_python/tests_011/test_voting.py | 249 + tests_python/tests_011/test_voting_full.py | 175 + tests_python/tests_alpha/protocol.py | 6 +- tests_python/tools/constants.py | 5 + 1546 files changed, 189365 insertions(+), 17 deletions(-) create mode 100644 docs/011/cli-commands.rst create mode 100644 docs/011/consensus.rst create mode 100644 docs/011/glossary.rst create mode 100644 docs/011/liquidity_baking.rst create mode 100644 docs/011/michelson.rst create mode 100644 docs/011/proof_of_stake.rst create mode 100644 docs/011/sapling.rst create mode 100644 docs/011/timelock.rst create mode 100644 docs/011/voting.rst create mode 100644 docs/protocols/011_hangzhou.rst create mode 100644 src/proto_011_PtHangzH/bin_accuser/.ocamlformat create mode 100644 src/proto_011_PtHangzH/bin_accuser/dune create mode 100644 src/proto_011_PtHangzH/bin_accuser/dune-project create mode 100644 src/proto_011_PtHangzH/bin_accuser/main_accuser_011_PtHangzH.ml create mode 100644 src/proto_011_PtHangzH/bin_accuser/tezos-accuser-011-PtHangzH.opam create mode 100644 src/proto_011_PtHangzH/bin_baker/.ocamlformat create mode 100644 src/proto_011_PtHangzH/bin_baker/dune create mode 100644 src/proto_011_PtHangzH/bin_baker/dune-project create mode 100644 src/proto_011_PtHangzH/bin_baker/main_baker_011_PtHangzH.ml create mode 100644 src/proto_011_PtHangzH/bin_baker/tezos-baker-011-PtHangzH.opam create mode 100644 src/proto_011_PtHangzH/bin_endorser/.ocamlformat create mode 100644 src/proto_011_PtHangzH/bin_endorser/dune create mode 100644 src/proto_011_PtHangzH/bin_endorser/dune-project create mode 100644 src/proto_011_PtHangzH/bin_endorser/main_endorser_011_PtHangzH.ml create mode 100644 src/proto_011_PtHangzH/bin_endorser/tezos-endorser-011-PtHangzH.opam create mode 100644 src/proto_011_PtHangzH/lib_benchmark/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_benchmark/README.md create mode 100644 src/proto_011_PtHangzH/lib_benchmark/autocomp.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/dune create mode 100644 src/proto_011_PtHangzH/lib_benchmark/dune-project create mode 100644 src/proto_011_PtHangzH/lib_benchmark/execution_context.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/generators.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/kernel.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/dune create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/dune-project create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/inference.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/inference.mli create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/int_map.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/mikhailsky.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/mikhailsky.mli create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/mikhailsky_prim.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/monads.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/stores.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/dune create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/test_inference.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/test_uf.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/tezos-benchmark-type-inference-011-PtHangzH.opam create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/type.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/type.mli create mode 100644 src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/uf.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/micheline_sampler.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/micheline_sampler.mli create mode 100644 src/proto_011_PtHangzH/lib_benchmark/michelson.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/michelson_samplers.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/michelson_samplers_base.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/michelson_samplers_parameters.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/rules.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/sampler.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/sampling_helpers.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/state_space.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/test/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_benchmark/test/dune create mode 100644 src/proto_011_PtHangzH/lib_benchmark/test/test_autocompletion.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/test/test_distribution.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/test/test_helpers.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/test/test_sampling_code.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/test/test_sampling_data.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmark/tezos-benchmark-011-PtHangzH.opam create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/cache_benchmarks.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/dune create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/dune-project create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/encodings_benchmarks.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/gas_helpers.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/global_constants_storage_benchmarks.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/interpreter_benchmarks.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/interpreter_model.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/interpreter_workload.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_commands.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_generation.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_generation.mli create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_types.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/registration_helpers.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/sapling_benchmarks.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/sapling_commands.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/sapling_generation.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/script_repr_benchmarks.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/script_typed_ir_size_benchmarks.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/size.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/tags.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/tezos-benchmarks-proto-011-PtHangzH.opam create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/translator_benchmarks.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/translator_model.ml create mode 100644 src/proto_011_PtHangzH/lib_benchmarks_proto/translator_workload.ml create mode 100644 src/proto_011_PtHangzH/lib_client/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_client/annotated_manager_operation.ml create mode 100644 src/proto_011_PtHangzH/lib_client/annotated_manager_operation.mli create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_args.ml create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_args.mli create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_context.ml create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_context.mli create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_contracts.ml create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_contracts.mli create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_fa12.ml create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_fa12.mli create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_multisig.ml create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_multisig.mli create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_programs.ml create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_programs.mli create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_utils.ml create mode 100644 src/proto_011_PtHangzH/lib_client/client_proto_utils.mli create mode 100644 src/proto_011_PtHangzH/lib_client/dune create mode 100644 src/proto_011_PtHangzH/lib_client/dune-project create mode 100644 src/proto_011_PtHangzH/lib_client/injection.ml create mode 100644 src/proto_011_PtHangzH/lib_client/injection.mli create mode 100644 src/proto_011_PtHangzH/lib_client/light.ml create mode 100644 src/proto_011_PtHangzH/lib_client/limit.ml create mode 100644 src/proto_011_PtHangzH/lib_client/limit.mli create mode 100644 src/proto_011_PtHangzH/lib_client/managed_contract.ml create mode 100644 src/proto_011_PtHangzH/lib_client/managed_contract.mli create mode 100644 src/proto_011_PtHangzH/lib_client/michelson_v1_emacs.ml create mode 100644 src/proto_011_PtHangzH/lib_client/michelson_v1_emacs.mli create mode 100644 src/proto_011_PtHangzH/lib_client/michelson_v1_entrypoints.ml create mode 100644 src/proto_011_PtHangzH/lib_client/michelson_v1_entrypoints.mli create mode 100644 src/proto_011_PtHangzH/lib_client/michelson_v1_error_reporter.ml create mode 100644 src/proto_011_PtHangzH/lib_client/michelson_v1_error_reporter.mli create mode 100644 src/proto_011_PtHangzH/lib_client/michelson_v1_helpers.ml create mode 100644 src/proto_011_PtHangzH/lib_client/michelson_v1_macros.ml create mode 100644 src/proto_011_PtHangzH/lib_client/michelson_v1_macros.mli create mode 100644 src/proto_011_PtHangzH/lib_client/michelson_v1_parser.ml create mode 100644 src/proto_011_PtHangzH/lib_client/michelson_v1_parser.mli create mode 100644 src/proto_011_PtHangzH/lib_client/michelson_v1_printer.ml create mode 100644 src/proto_011_PtHangzH/lib_client/michelson_v1_printer.mli create mode 100644 src/proto_011_PtHangzH/lib_client/mockup.ml create mode 100644 src/proto_011_PtHangzH/lib_client/operation_result.ml create mode 100644 src/proto_011_PtHangzH/lib_client/operation_result.mli create mode 100644 src/proto_011_PtHangzH/lib_client/protocol_client_context.ml create mode 100644 src/proto_011_PtHangzH/lib_client/proxy.ml create mode 100644 src/proto_011_PtHangzH/lib_client/test/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_client/test/assert.ml create mode 100644 src/proto_011_PtHangzH/lib_client/test/dune create mode 100644 src/proto_011_PtHangzH/lib_client/test/test_client_proto_context.ml create mode 100644 src/proto_011_PtHangzH/lib_client/test/test_client_proto_contracts.ml create mode 100644 src/proto_011_PtHangzH/lib_client/test/test_michelson_v1_macros.ml create mode 100644 src/proto_011_PtHangzH/lib_client/test/test_proxy.ml create mode 100644 src/proto_011_PtHangzH/lib_client/tezos-client-011-PtHangzH.opam create mode 100644 src/proto_011_PtHangzH/lib_client_commands/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_client_commands/alpha_commands_registration.ml create mode 100644 src/proto_011_PtHangzH/lib_client_commands/client_proto_context_commands.ml create mode 100644 src/proto_011_PtHangzH/lib_client_commands/client_proto_contracts_commands.ml create mode 100644 src/proto_011_PtHangzH/lib_client_commands/client_proto_fa12_commands.ml create mode 100644 src/proto_011_PtHangzH/lib_client_commands/client_proto_mockup_commands.ml create mode 100644 src/proto_011_PtHangzH/lib_client_commands/client_proto_mockup_commands.mli create mode 100644 src/proto_011_PtHangzH/lib_client_commands/client_proto_multisig_commands.ml create mode 100644 src/proto_011_PtHangzH/lib_client_commands/client_proto_multisig_commands.mli create mode 100644 src/proto_011_PtHangzH/lib_client_commands/client_proto_programs_commands.ml create mode 100644 src/proto_011_PtHangzH/lib_client_commands/client_proto_programs_commands.mli create mode 100644 src/proto_011_PtHangzH/lib_client_commands/client_proto_stresstest_commands.ml create mode 100644 src/proto_011_PtHangzH/lib_client_commands/client_proto_utils_commands.ml create mode 100644 src/proto_011_PtHangzH/lib_client_commands/client_proto_utils_commands.mli create mode 100644 src/proto_011_PtHangzH/lib_client_commands/dune create mode 100644 src/proto_011_PtHangzH/lib_client_commands/dune-project create mode 100644 src/proto_011_PtHangzH/lib_client_commands/tezos-client-011-PtHangzH-commands-registration.opam create mode 100644 src/proto_011_PtHangzH/lib_client_commands/tezos-client-011-PtHangzH-commands.opam create mode 100644 src/proto_011_PtHangzH/lib_client_sapling/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_client_sapling/client_sapling_commands.ml create mode 100644 src/proto_011_PtHangzH/lib_client_sapling/client_sapling_commands.mli create mode 100644 src/proto_011_PtHangzH/lib_client_sapling/context.ml create mode 100644 src/proto_011_PtHangzH/lib_client_sapling/context.mli create mode 100644 src/proto_011_PtHangzH/lib_client_sapling/dune create mode 100644 src/proto_011_PtHangzH/lib_client_sapling/dune-project create mode 100644 src/proto_011_PtHangzH/lib_client_sapling/tezos-client-sapling-011-PtHangzH.opam create mode 100644 src/proto_011_PtHangzH/lib_client_sapling/wallet.ml create mode 100644 src/proto_011_PtHangzH/lib_client_sapling/wallet.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_blocks.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_blocks.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_denunciation.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_denunciation.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_endorsement.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_endorsement.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_files.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_files.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_forge.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_forge.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_highwatermarks.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_highwatermarks.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_lib.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_lib.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_nonces.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_nonces.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_pow.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_pow.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_revelation.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_revelation.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_scheduling.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_scheduling.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_simulator.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_baking_simulator.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_daemon.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/client_daemon.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/delegate_commands.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/delegate_commands.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/delegate_commands_registration.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/delegate_events.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/dune create mode 100644 src/proto_011_PtHangzH/lib_delegate/dune-project create mode 100644 src/proto_011_PtHangzH/lib_delegate/logging.ml create mode 100644 src/proto_011_PtHangzH/lib_delegate/logging.mli create mode 100644 src/proto_011_PtHangzH/lib_delegate/tezos-accuser-011-PtHangzH-commands.opam create mode 100644 src/proto_011_PtHangzH/lib_delegate/tezos-baking-011-PtHangzH-commands.opam create mode 100644 src/proto_011_PtHangzH/lib_delegate/tezos-baking-011-PtHangzH.opam create mode 100644 src/proto_011_PtHangzH/lib_delegate/tezos-endorser-011-PtHangzH-commands.opam create mode 100644 src/proto_011_PtHangzH/lib_parameters/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_parameters/default_parameters.ml create mode 100644 src/proto_011_PtHangzH/lib_parameters/default_parameters.mli create mode 100644 src/proto_011_PtHangzH/lib_parameters/dune create mode 100644 src/proto_011_PtHangzH/lib_parameters/dune-project create mode 100644 src/proto_011_PtHangzH/lib_parameters/gen.ml create mode 100644 src/proto_011_PtHangzH/lib_parameters/tezos-protocol-011-PtHangzH-parameters.opam create mode 100644 src/proto_011_PtHangzH/lib_plugin/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_plugin/dune create mode 100644 src/proto_011_PtHangzH/lib_plugin/dune-project create mode 100644 src/proto_011_PtHangzH/lib_plugin/plugin.ml create mode 100644 src/proto_011_PtHangzH/lib_plugin/plugin_registerer.ml create mode 100644 src/proto_011_PtHangzH/lib_plugin/tezos-protocol-plugin-011-PtHangzH-registerer.opam create mode 100644 src/proto_011_PtHangzH/lib_plugin/tezos-protocol-plugin-011-PtHangzH.opam create mode 100644 src/proto_011_PtHangzH/lib_protocol/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_protocol/TEZOS_PROTOCOL create mode 100644 src/proto_011_PtHangzH/lib_protocol/alpha_context.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/alpha_context.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/alpha_services.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/alpha_services.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/amendment.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/amendment.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/apply.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/apply.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/apply_results.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/apply_results.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/baking.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/baking.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/blinded_public_key_hash.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/blinded_public_key_hash.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/block_header_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/block_header_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/bootstrap_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/bootstrap_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/cache_costs.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/cache_costs.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/cache_memory_helpers.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/commitment_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/commitment_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/commitment_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/commitment_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/constants_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/constants_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/constants_services.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/constants_services.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/constants_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/constants_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/contract_hash.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/contract_hash.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/contract_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/contract_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/contract_services.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/contract_services.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/contract_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/contract_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/contracts/cpmm.bin create mode 100644 src/proto_011_PtHangzH/lib_protocol/contracts/cpmm.mligo create mode 100644 src/proto_011_PtHangzH/lib_protocol/contracts/cpmm.tz create mode 100644 src/proto_011_PtHangzH/lib_protocol/contracts/lqt.bin create mode 100644 src/proto_011_PtHangzH/lib_protocol/contracts/lqt.mligo create mode 100644 src/proto_011_PtHangzH/lib_protocol/contracts/lqt.tz create mode 100644 src/proto_011_PtHangzH/lib_protocol/coq-of-ocaml/README.md create mode 100644 src/proto_011_PtHangzH/lib_protocol/coq-of-ocaml/config.json create mode 100644 src/proto_011_PtHangzH/lib_protocol/cycle_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/cycle_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/delegate_services.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/delegate_services.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/delegate_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/delegate_storage.mli create mode 120000 src/proto_011_PtHangzH/lib_protocol/dune create mode 100644 src/proto_011_PtHangzH/lib_protocol/dune-project create mode 100644 src/proto_011_PtHangzH/lib_protocol/dune.inc create mode 100644 src/proto_011_PtHangzH/lib_protocol/fees_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/fees_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/fitness_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/fitness_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/fitness_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/fitness_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/fixed_point_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/fixed_point_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/gas_limit_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/gas_limit_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/global_constants_costs.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/global_constants_costs.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/global_constants_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/global_constants_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/init_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/init_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/lazy_storage_diff.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/lazy_storage_diff.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/lazy_storage_kind.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/lazy_storage_kind.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/level_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/level_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/level_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/level_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/liquidity_baking_cpmm.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/liquidity_baking_lqt.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/liquidity_baking_migration.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/liquidity_baking_migration.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/liquidity_baking_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/liquidity_baking_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/main.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/main.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/manager_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/manager_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/michelson_v1_gas.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/michelson_v1_gas.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/michelson_v1_primitives.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/michelson_v1_primitives.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/migration_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/migration_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/misc.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/misc.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/nonce_hash.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/nonce_hash.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/nonce_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/nonce_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/operation_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/operation_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/parameters_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/parameters_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/path_encoding.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/path_encoding.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/period_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/period_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/raw_context.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/raw_context.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/raw_context_intf.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/raw_level_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/raw_level_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/receipt_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/receipt_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/roll_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/roll_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/roll_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/roll_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/sapling_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/sapling_services.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/sapling_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/sapling_validator.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/saturation_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/saturation_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_cache.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_cache.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_comparable.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_comparable.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_expr_hash.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_expr_hash.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_int_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_int_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_interpreter.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_interpreter.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_interpreter_defs.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_ir_annot.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_ir_annot.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_ir_translator.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_ir_translator.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_list.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_list.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_map.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_map.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_set.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_set.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_string_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_string_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_tc_errors.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_tc_errors_registration.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_tc_errors_registration.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_timestamp_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_timestamp_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_typed_ir.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_typed_ir.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size_costs.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size_costs.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/seed_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/seed_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/seed_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/seed_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/services_registration.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/services_registration.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/state_hash.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/state_hash.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/storage_costs.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/storage_costs.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/storage_description.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/storage_description.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/storage_functors.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/storage_functors.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/storage_sigs.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/contracts/big_interpreter_stack.tz create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract.tz create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_double.tz create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_drop.tz create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_send.tz create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_state_as_arg.tz create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_push_sapling_state.tz create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_use_existing_state.tz create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/contracts/temp_big_maps.tz create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/contracts/timelock.tz create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/dune create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/README.md create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/account.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/account.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/assert.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/block.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/block.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/context.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/context.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/contract_helpers.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/cpmm_logic.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/cpmm_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/dune create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/dune-project create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/expr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/expr_common.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/incremental.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/incremental.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_generator.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_generator.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_machine.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_machine.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/lqt_fa12_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/nonce.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/nonce.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/op.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/op.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/rewards.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/sapling_helpers.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/script_big_map.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/script_big_map.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/script_list.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/script_list.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/script_map.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/script_map.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/script_set.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/script_set.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/test_global_constants.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/test_tez.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/testable.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/helpers/tezos-011-PtHangzH-test-helpers.opam create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/liquidity_baking_pbt.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/main.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/saturation_fuzzing.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_activation.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_baking.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_baking_module.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_combined_operations.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_constants.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_delegation.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_double_baking.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_double_endorsement.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_endorsement.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_failing_noop.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_fixed_point.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_gas_costs.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_gas_levels.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_gas_properties.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_global_constants_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_helpers_rpcs.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_interpretation.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_lazy_storage_diff.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_level_module.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_liquidity_baking.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_origination.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_qty.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_reveal.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_rolls.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_sapling.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_saturation.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_script_comparison.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_script_typed_ir_size.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_seed.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_temp_big_maps.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_tez_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_time_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_timelock.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_transfer.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_typechecking.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/test_voting.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/unit/.ocamlformat create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/unit/dune create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/unit/main.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/unit/test_alpha_context.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/unit/test_contract_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/unit/test_global_constants_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/unit/test_operation_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/unit/test_raw_level_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/test/unit/test_tez_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/tez_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/tez_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/tezos-embedded-protocol-011-PtHangzH.opam create mode 100644 src/proto_011_PtHangzH/lib_protocol/tezos-protocol-011-PtHangzH-tests.opam create mode 100644 src/proto_011_PtHangzH/lib_protocol/tezos-protocol-011-PtHangzH.opam create mode 100644 src/proto_011_PtHangzH/lib_protocol/tezos-protocol-functor-011-PtHangzH.opam create mode 100644 src/proto_011_PtHangzH/lib_protocol/time_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/time_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/vote_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/vote_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/vote_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/vote_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/voting_period_repr.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/voting_period_repr.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/voting_period_storage.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/voting_period_storage.mli create mode 100644 src/proto_011_PtHangzH/lib_protocol/voting_services.ml create mode 100644 src/proto_011_PtHangzH/lib_protocol/voting_services.mli create mode 100644 tests_python/contracts_011/attic/accounts.tz create mode 100644 tests_python/contracts_011/attic/add1.tz create mode 100644 tests_python/contracts_011/attic/add1_list.tz create mode 100644 tests_python/contracts_011/attic/after_strategy.tz create mode 100644 tests_python/contracts_011/attic/always.tz create mode 100644 tests_python/contracts_011/attic/append.tz create mode 100644 tests_python/contracts_011/attic/at_least.tz create mode 100644 tests_python/contracts_011/attic/auction.tz create mode 100644 tests_python/contracts_011/attic/bad_lockup.tz create mode 100644 tests_python/contracts_011/attic/big_map_union.tz create mode 100644 tests_python/contracts_011/attic/cadr_annotation.tz create mode 100644 tests_python/contracts_011/attic/concat.tz create mode 100644 tests_python/contracts_011/attic/conditionals.tz create mode 100644 tests_python/contracts_011/attic/cons_twice.tz create mode 100644 tests_python/contracts_011/attic/cps_fact.tz create mode 100644 tests_python/contracts_011/attic/create_add1_lists.tz create mode 100644 tests_python/contracts_011/attic/data_publisher.tz create mode 100644 tests_python/contracts_011/attic/dispatch.tz create mode 100644 tests_python/contracts_011/attic/empty.tz create mode 100644 tests_python/contracts_011/attic/fail_amount.tz create mode 100644 tests_python/contracts_011/attic/faucet.tz create mode 100644 tests_python/contracts_011/attic/forward.tz create mode 100644 tests_python/contracts_011/attic/id.tz create mode 100644 tests_python/contracts_011/attic/infinite_loop.tz create mode 100644 tests_python/contracts_011/attic/insertion_sort.tz create mode 100644 tests_python/contracts_011/attic/int_publisher.tz create mode 100644 tests_python/contracts_011/attic/king_of_tez.tz create mode 100644 tests_python/contracts_011/attic/list_of_transactions.tz create mode 100644 tests_python/contracts_011/attic/queue.tz create mode 100644 tests_python/contracts_011/attic/reduce_map.tz create mode 100644 tests_python/contracts_011/attic/reentrancy.tz create mode 100644 tests_python/contracts_011/attic/reservoir.tz create mode 100644 tests_python/contracts_011/attic/scrutable_reservoir.tz create mode 100644 tests_python/contracts_011/attic/spawn_identities.tz create mode 100644 tests_python/contracts_011/entrypoints/big_map_entrypoints.tz create mode 100644 tests_python/contracts_011/entrypoints/delegatable_target.tz create mode 100644 tests_python/contracts_011/entrypoints/manager.tz create mode 100644 tests_python/contracts_011/entrypoints/no_default_target.tz create mode 100644 tests_python/contracts_011/entrypoints/no_entrypoint_target.tz create mode 100644 tests_python/contracts_011/entrypoints/rooted_target.tz create mode 100644 tests_python/contracts_011/entrypoints/simple_entrypoints.tz create mode 100644 tests_python/contracts_011/ill_typed/badly_indented.tz create mode 100644 tests_python/contracts_011/ill_typed/big_dip.tz create mode 100644 tests_python/contracts_011/ill_typed/big_drop.tz create mode 100644 tests_python/contracts_011/ill_typed/big_map_arity.tz create mode 100644 tests_python/contracts_011/ill_typed/chain_id_arity.tz create mode 100644 tests_python/contracts_011/ill_typed/comb0.tz create mode 100644 tests_python/contracts_011/ill_typed/comb1.tz create mode 100644 tests_python/contracts_011/ill_typed/contract_annotation_default.tz create mode 100644 tests_python/contracts_011/ill_typed/dup0.tz create mode 100644 tests_python/contracts_011/ill_typed/failwith_big_map.tz create mode 100644 tests_python/contracts_011/ill_typed/invalid_self_entrypoint.tz create mode 100644 tests_python/contracts_011/ill_typed/missing_only_code_field.tz create mode 100644 tests_python/contracts_011/ill_typed/missing_only_parameter_field.tz create mode 100644 tests_python/contracts_011/ill_typed/missing_only_storage_field.tz create mode 100644 tests_python/contracts_011/ill_typed/missing_parameter_and_storage_fields.tz create mode 100644 tests_python/contracts_011/ill_typed/multiple_code_field.tz create mode 100644 tests_python/contracts_011/ill_typed/multiple_parameter_field.tz create mode 100644 tests_python/contracts_011/ill_typed/multiple_storage_and_code_fields.tz create mode 100644 tests_python/contracts_011/ill_typed/multiple_storage_field.tz create mode 100644 tests_python/contracts_011/ill_typed/never_literal.tz create mode 100644 tests_python/contracts_011/ill_typed/pack_big_map.tz create mode 100644 tests_python/contracts_011/ill_typed/pack_operation.tz create mode 100644 tests_python/contracts_011/ill_typed/pack_sapling_state.tz create mode 100644 tests_python/contracts_011/ill_typed/push_big_map_with_id_with_parens.tz create mode 100644 tests_python/contracts_011/ill_typed/push_big_map_with_id_without_parens.tz create mode 100644 tests_python/contracts_011/ill_typed/sapling_build_empty_state_with_int_parameter.tz create mode 100644 tests_python/contracts_011/ill_typed/set_update_non_comparable.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_undig2able.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_undigable.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_undip2able.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_undipable.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_undropable.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_undug2able.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_undugable.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_undup2able.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_unfailwithable.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_ungetable.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_unleftable.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_unpairable.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_unpopable.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_unpopable_in_lambda.tz create mode 100644 tests_python/contracts_011/ill_typed/stack_bottom_unrightable.tz create mode 100644 tests_python/contracts_011/ill_typed/ticket_apply.tz create mode 100644 tests_python/contracts_011/ill_typed/ticket_dup.tz create mode 100644 tests_python/contracts_011/ill_typed/ticket_in_ticket.tz create mode 100644 tests_python/contracts_011/ill_typed/ticket_unpack.tz create mode 100644 tests_python/contracts_011/ill_typed/uncomb0.tz create mode 100644 tests_python/contracts_011/ill_typed/uncomb1.tz create mode 100644 tests_python/contracts_011/ill_typed/unpack_sapling_state.tz create mode 100644 tests_python/contracts_011/ill_typed/unpair_field_annotation_mismatch.tz create mode 100644 tests_python/contracts_011/ill_typed/view_op_bad_name_invalid_char_set.tz create mode 100644 tests_python/contracts_011/ill_typed/view_op_bad_name_invalid_type.tz create mode 100644 tests_python/contracts_011/ill_typed/view_op_bad_name_non_printable_char.tz create mode 100644 tests_python/contracts_011/ill_typed/view_op_bad_name_too_long.tz create mode 100644 tests_python/contracts_011/ill_typed/view_op_bad_return_type.tz create mode 100644 tests_python/contracts_011/ill_typed/view_op_dupable_type.tz create mode 100644 tests_python/contracts_011/ill_typed/view_op_invalid_arity.tz create mode 100644 tests_python/contracts_011/ill_typed/view_op_lazy_storage.tz create mode 100644 tests_python/contracts_011/ill_typed/view_op_lazy_storage_type.tz create mode 100644 tests_python/contracts_011/ill_typed/view_toplevel_bad_input_type.tz create mode 100644 tests_python/contracts_011/ill_typed/view_toplevel_bad_name_invalid_char_set.tz create mode 100644 tests_python/contracts_011/ill_typed/view_toplevel_bad_name_invalid_type.tz create mode 100644 tests_python/contracts_011/ill_typed/view_toplevel_bad_name_non_printable_char.tz create mode 100644 tests_python/contracts_011/ill_typed/view_toplevel_bad_name_too_long.tz create mode 100644 tests_python/contracts_011/ill_typed/view_toplevel_bad_return_type.tz create mode 100644 tests_python/contracts_011/ill_typed/view_toplevel_bad_type.tz create mode 100644 tests_python/contracts_011/ill_typed/view_toplevel_dupable_type_input.tz create mode 100644 tests_python/contracts_011/ill_typed/view_toplevel_dupable_type_output.tz create mode 100644 tests_python/contracts_011/ill_typed/view_toplevel_duplicated_name.tz create mode 100644 tests_python/contracts_011/ill_typed/view_toplevel_invalid_arity.tz create mode 100644 tests_python/contracts_011/ill_typed/view_toplevel_lazy_storage_input.tz create mode 100644 tests_python/contracts_011/ill_typed/view_toplevel_lazy_storage_output.tz create mode 100644 tests_python/contracts_011/legacy/create_account.tz create mode 100644 tests_python/contracts_011/legacy/create_contract.tz create mode 100644 tests_python/contracts_011/legacy/create_contract_flags.tz create mode 100644 tests_python/contracts_011/legacy/create_contract_rootname.tz create mode 100644 tests_python/contracts_011/legacy/originator.tz create mode 100644 tests_python/contracts_011/legacy/steps_to_quota.tz create mode 100644 tests_python/contracts_011/macros/assert.tz create mode 100644 tests_python/contracts_011/macros/assert_cmpeq.tz create mode 100644 tests_python/contracts_011/macros/assert_cmpge.tz create mode 100644 tests_python/contracts_011/macros/assert_cmpgt.tz create mode 100644 tests_python/contracts_011/macros/assert_cmple.tz create mode 100644 tests_python/contracts_011/macros/assert_cmplt.tz create mode 100644 tests_python/contracts_011/macros/assert_cmpneq.tz create mode 100644 tests_python/contracts_011/macros/assert_eq.tz create mode 100644 tests_python/contracts_011/macros/assert_ge.tz create mode 100644 tests_python/contracts_011/macros/assert_gt.tz create mode 100644 tests_python/contracts_011/macros/assert_le.tz create mode 100644 tests_python/contracts_011/macros/assert_lt.tz create mode 100644 tests_python/contracts_011/macros/assert_neq.tz create mode 100644 tests_python/contracts_011/macros/big_map_get_add.tz create mode 100644 tests_python/contracts_011/macros/big_map_mem.tz create mode 100644 tests_python/contracts_011/macros/build_list.tz create mode 100644 tests_python/contracts_011/macros/carn_and_cdrn.tz create mode 100644 tests_python/contracts_011/macros/compare.tz create mode 100644 tests_python/contracts_011/macros/compare_bytes.tz create mode 100644 tests_python/contracts_011/macros/fail.tz create mode 100644 tests_python/contracts_011/macros/guestbook.tz create mode 100644 tests_python/contracts_011/macros/macro_annotations.tz create mode 100644 tests_python/contracts_011/macros/map_caddaadr.tz create mode 100644 tests_python/contracts_011/macros/max_in_list.tz create mode 100644 tests_python/contracts_011/macros/min.tz create mode 100644 tests_python/contracts_011/macros/pair_macro.tz create mode 100644 tests_python/contracts_011/macros/set_caddaadr.tz create mode 100644 tests_python/contracts_011/macros/take_my_money.tz create mode 100644 tests_python/contracts_011/macros/unpair_macro.tz create mode 100644 tests_python/contracts_011/mini_scenarios/authentication.tz create mode 100644 tests_python/contracts_011/mini_scenarios/big_map_entrypoints.tz create mode 100644 tests_python/contracts_011/mini_scenarios/big_map_magic.tz create mode 100644 tests_python/contracts_011/mini_scenarios/big_map_read.tz create mode 100644 tests_python/contracts_011/mini_scenarios/big_map_store.tz create mode 100644 tests_python/contracts_011/mini_scenarios/big_map_write.tz create mode 100644 tests_python/contracts_011/mini_scenarios/create_contract.tz create mode 100644 tests_python/contracts_011/mini_scenarios/create_contract_simple.tz create mode 100644 tests_python/contracts_011/mini_scenarios/default_account.tz create mode 100644 tests_python/contracts_011/mini_scenarios/execution_order_appender.tz create mode 100644 tests_python/contracts_011/mini_scenarios/execution_order_caller.tz create mode 100644 tests_python/contracts_011/mini_scenarios/execution_order_storer.tz create mode 100644 tests_python/contracts_011/mini_scenarios/fa12_reference.tz create mode 100644 tests_python/contracts_011/mini_scenarios/generic_multisig.tz create mode 100644 tests_python/contracts_011/mini_scenarios/groth16.tz create mode 100644 tests_python/contracts_011/mini_scenarios/hardlimit.tz create mode 100644 tests_python/contracts_011/mini_scenarios/legacy_multisig.tz create mode 100644 tests_python/contracts_011/mini_scenarios/lockup.tz create mode 100644 tests_python/contracts_011/mini_scenarios/lqt_fa12.mligo.tz create mode 100644 tests_python/contracts_011/mini_scenarios/multiple_en2.tz create mode 100644 tests_python/contracts_011/mini_scenarios/multiple_entrypoints_counter.tz create mode 100644 tests_python/contracts_011/mini_scenarios/parameterized_multisig.tz create mode 100644 tests_python/contracts_011/mini_scenarios/replay.tz create mode 100644 tests_python/contracts_011/mini_scenarios/reveal_signed_preimage.tz create mode 100644 tests_python/contracts_011/mini_scenarios/self_address_receiver.tz create mode 100644 tests_python/contracts_011/mini_scenarios/self_address_sender.tz create mode 100644 tests_python/contracts_011/mini_scenarios/ticket_builder_fungible.tz create mode 100644 tests_python/contracts_011/mini_scenarios/ticket_builder_non_fungible.tz create mode 100644 tests_python/contracts_011/mini_scenarios/ticket_wallet_fungible.tz create mode 100644 tests_python/contracts_011/mini_scenarios/ticket_wallet_non_fungible.tz create mode 100644 tests_python/contracts_011/mini_scenarios/tzip4_view.tz create mode 100644 tests_python/contracts_011/mini_scenarios/vote_for_delegate.tz create mode 100644 tests_python/contracts_011/mini_scenarios/weather_insurance.tz create mode 100644 tests_python/contracts_011/mini_scenarios/xcat.tz create mode 100644 tests_python/contracts_011/mini_scenarios/xcat_dapp.tz create mode 100644 tests_python/contracts_011/non_regression/bug_262.tz create mode 100644 tests_python/contracts_011/non_regression/pairk_annot.tz create mode 100644 tests_python/contracts_011/opcodes/abs.tz create mode 100644 tests_python/contracts_011/opcodes/add.tz create mode 100644 tests_python/contracts_011/opcodes/add_bls12_381_fr.tz create mode 100644 tests_python/contracts_011/opcodes/add_bls12_381_g1.tz create mode 100644 tests_python/contracts_011/opcodes/add_bls12_381_g2.tz create mode 100644 tests_python/contracts_011/opcodes/add_delta_timestamp.tz create mode 100644 tests_python/contracts_011/opcodes/add_timestamp_delta.tz create mode 100644 tests_python/contracts_011/opcodes/address.tz create mode 100644 tests_python/contracts_011/opcodes/and.tz create mode 100644 tests_python/contracts_011/opcodes/and_binary.tz create mode 100644 tests_python/contracts_011/opcodes/and_logical_1.tz create mode 100644 tests_python/contracts_011/opcodes/balance.tz create mode 100644 tests_python/contracts_011/opcodes/big_map_mem_nat.tz create mode 100644 tests_python/contracts_011/opcodes/big_map_mem_string.tz create mode 100644 tests_python/contracts_011/opcodes/big_map_to_self.tz create mode 100644 tests_python/contracts_011/opcodes/bls12_381_fr_push_bytes_not_padded.tz create mode 100644 tests_python/contracts_011/opcodes/bls12_381_fr_push_nat.tz create mode 100644 tests_python/contracts_011/opcodes/bls12_381_fr_to_int.tz create mode 100644 tests_python/contracts_011/opcodes/bls12_381_fr_to_mutez.tz create mode 100644 tests_python/contracts_011/opcodes/bls12_381_fr_z_int.tz create mode 100644 tests_python/contracts_011/opcodes/bls12_381_fr_z_nat.tz create mode 100644 tests_python/contracts_011/opcodes/bls12_381_z_fr_int.tz create mode 100644 tests_python/contracts_011/opcodes/bls12_381_z_fr_nat.tz create mode 100644 tests_python/contracts_011/opcodes/bytes.tz create mode 100644 tests_python/contracts_011/opcodes/car.tz create mode 100644 tests_python/contracts_011/opcodes/cdr.tz create mode 100644 tests_python/contracts_011/opcodes/chain_id.tz create mode 100644 tests_python/contracts_011/opcodes/chain_id_store.tz create mode 100644 tests_python/contracts_011/opcodes/check_signature.tz create mode 100644 tests_python/contracts_011/opcodes/comb-get.tz create mode 100644 tests_python/contracts_011/opcodes/comb-literals.tz create mode 100644 tests_python/contracts_011/opcodes/comb-set-2.tz create mode 100644 tests_python/contracts_011/opcodes/comb-set.tz create mode 100644 tests_python/contracts_011/opcodes/comb.tz create mode 100644 tests_python/contracts_011/opcodes/compare.tz create mode 100644 tests_python/contracts_011/opcodes/compare_big_type.tz create mode 100644 tests_python/contracts_011/opcodes/compare_big_type2.tz create mode 100644 tests_python/contracts_011/opcodes/comparisons.tz create mode 100644 tests_python/contracts_011/opcodes/concat_hello.tz create mode 100644 tests_python/contracts_011/opcodes/concat_hello_bytes.tz create mode 100644 tests_python/contracts_011/opcodes/concat_list.tz create mode 100644 tests_python/contracts_011/opcodes/cons.tz create mode 100644 tests_python/contracts_011/opcodes/contains_all.tz create mode 100644 tests_python/contracts_011/opcodes/contract.tz create mode 100644 tests_python/contracts_011/opcodes/create_contract.tz create mode 100644 tests_python/contracts_011/opcodes/create_contract_rootname.tz create mode 100644 tests_python/contracts_011/opcodes/create_contract_rootname_alt.tz create mode 100644 tests_python/contracts_011/opcodes/create_contract_with_view.tz create mode 100644 tests_python/contracts_011/opcodes/diff_timestamps.tz create mode 100644 tests_python/contracts_011/opcodes/dig_eq.tz create mode 100644 tests_python/contracts_011/opcodes/dign.tz create mode 100644 tests_python/contracts_011/opcodes/dip.tz create mode 100644 tests_python/contracts_011/opcodes/dipn.tz create mode 100644 tests_python/contracts_011/opcodes/dropn.tz create mode 100644 tests_python/contracts_011/opcodes/dugn.tz create mode 100644 tests_python/contracts_011/opcodes/dup-n.tz create mode 100644 tests_python/contracts_011/opcodes/ediv.tz create mode 100644 tests_python/contracts_011/opcodes/ediv_mutez.tz create mode 100644 tests_python/contracts_011/opcodes/empty_map.tz create mode 100644 tests_python/contracts_011/opcodes/exec_concat.tz create mode 100644 tests_python/contracts_011/opcodes/first.tz create mode 100644 tests_python/contracts_011/opcodes/get_and_update_big_map.tz create mode 100644 tests_python/contracts_011/opcodes/get_and_update_map.tz create mode 100644 tests_python/contracts_011/opcodes/get_big_map_value.tz create mode 100644 tests_python/contracts_011/opcodes/get_map_value.tz create mode 100644 tests_python/contracts_011/opcodes/hash_consistency_checker.tz create mode 100644 tests_python/contracts_011/opcodes/hash_key.tz create mode 100644 tests_python/contracts_011/opcodes/hash_string.tz create mode 100644 tests_python/contracts_011/opcodes/if.tz create mode 100644 tests_python/contracts_011/opcodes/if_some.tz create mode 100644 tests_python/contracts_011/opcodes/int.tz create mode 100644 tests_python/contracts_011/opcodes/keccak.tz create mode 100644 tests_python/contracts_011/opcodes/left_right.tz create mode 100644 tests_python/contracts_011/opcodes/level.tz create mode 100644 tests_python/contracts_011/opcodes/list_concat.tz create mode 100644 tests_python/contracts_011/opcodes/list_concat_bytes.tz create mode 100644 tests_python/contracts_011/opcodes/list_id.tz create mode 100644 tests_python/contracts_011/opcodes/list_id_map.tz create mode 100644 tests_python/contracts_011/opcodes/list_iter.tz create mode 100644 tests_python/contracts_011/opcodes/list_map_block.tz create mode 100644 tests_python/contracts_011/opcodes/list_size.tz create mode 100644 tests_python/contracts_011/opcodes/loop_left.tz create mode 100644 tests_python/contracts_011/opcodes/map_car.tz create mode 100644 tests_python/contracts_011/opcodes/map_id.tz create mode 100644 tests_python/contracts_011/opcodes/map_iter.tz create mode 100644 tests_python/contracts_011/opcodes/map_map.tz create mode 100644 tests_python/contracts_011/opcodes/map_map_sideeffect.tz create mode 100644 tests_python/contracts_011/opcodes/map_mem_nat.tz create mode 100644 tests_python/contracts_011/opcodes/map_mem_string.tz create mode 100644 tests_python/contracts_011/opcodes/map_size.tz create mode 100644 tests_python/contracts_011/opcodes/merge_comparable_pairs.tz create mode 100644 tests_python/contracts_011/opcodes/mul.tz create mode 100644 tests_python/contracts_011/opcodes/mul_bls12_381_fr.tz create mode 100644 tests_python/contracts_011/opcodes/mul_bls12_381_g1.tz create mode 100644 tests_python/contracts_011/opcodes/mul_bls12_381_g2.tz create mode 100644 tests_python/contracts_011/opcodes/mul_overflow.tz create mode 100644 tests_python/contracts_011/opcodes/munch.tz create mode 100644 tests_python/contracts_011/opcodes/mutez_to_bls12_381_fr.tz create mode 100644 tests_python/contracts_011/opcodes/neg.tz create mode 100644 tests_python/contracts_011/opcodes/neg_bls12_381_fr.tz create mode 100644 tests_python/contracts_011/opcodes/neg_bls12_381_g1.tz create mode 100644 tests_python/contracts_011/opcodes/neg_bls12_381_g2.tz create mode 100644 tests_python/contracts_011/opcodes/none.tz create mode 100644 tests_python/contracts_011/opcodes/noop.tz create mode 100644 tests_python/contracts_011/opcodes/not.tz create mode 100644 tests_python/contracts_011/opcodes/not_binary.tz create mode 100644 tests_python/contracts_011/opcodes/or.tz create mode 100644 tests_python/contracts_011/opcodes/or_binary.tz create mode 100644 tests_python/contracts_011/opcodes/originate_big_map.tz create mode 100644 tests_python/contracts_011/opcodes/packunpack.tz create mode 100644 tests_python/contracts_011/opcodes/packunpack_rev.tz create mode 100644 tests_python/contracts_011/opcodes/packunpack_rev_cty.tz create mode 100644 tests_python/contracts_011/opcodes/pair_id.tz create mode 100644 tests_python/contracts_011/opcodes/pairing_check.tz create mode 100644 tests_python/contracts_011/opcodes/pexec.tz create mode 100644 tests_python/contracts_011/opcodes/pexec_2.tz create mode 100644 tests_python/contracts_011/opcodes/proxy.tz create mode 100644 tests_python/contracts_011/opcodes/ret_int.tz create mode 100644 tests_python/contracts_011/opcodes/reverse.tz create mode 100644 tests_python/contracts_011/opcodes/reverse_loop.tz create mode 100644 tests_python/contracts_011/opcodes/sapling_empty_state.tz create mode 100644 tests_python/contracts_011/opcodes/self.tz create mode 100644 tests_python/contracts_011/opcodes/self_address.tz create mode 100644 tests_python/contracts_011/opcodes/self_with_default_entrypoint.tz create mode 100644 tests_python/contracts_011/opcodes/self_with_entrypoint.tz create mode 100644 tests_python/contracts_011/opcodes/sender.tz create mode 100644 tests_python/contracts_011/opcodes/set_car.tz create mode 100644 tests_python/contracts_011/opcodes/set_cdr.tz create mode 100644 tests_python/contracts_011/opcodes/set_delegate.tz create mode 100644 tests_python/contracts_011/opcodes/set_id.tz create mode 100644 tests_python/contracts_011/opcodes/set_iter.tz create mode 100644 tests_python/contracts_011/opcodes/set_member.tz create mode 100644 tests_python/contracts_011/opcodes/set_size.tz create mode 100644 tests_python/contracts_011/opcodes/sha3.tz create mode 100644 tests_python/contracts_011/opcodes/shifts.tz create mode 100644 tests_python/contracts_011/opcodes/slice.tz create mode 100644 tests_python/contracts_011/opcodes/slice_bytes.tz create mode 100644 tests_python/contracts_011/opcodes/slices.tz create mode 100644 tests_python/contracts_011/opcodes/source.tz create mode 100644 tests_python/contracts_011/opcodes/split_bytes.tz create mode 100644 tests_python/contracts_011/opcodes/split_string.tz create mode 100644 tests_python/contracts_011/opcodes/store_bls12_381_fr.tz create mode 100644 tests_python/contracts_011/opcodes/store_bls12_381_g1.tz create mode 100644 tests_python/contracts_011/opcodes/store_bls12_381_g2.tz create mode 100644 tests_python/contracts_011/opcodes/store_input.tz create mode 100644 tests_python/contracts_011/opcodes/store_now.tz create mode 100644 tests_python/contracts_011/opcodes/str_id.tz create mode 100644 tests_python/contracts_011/opcodes/sub_timestamp_delta.tz create mode 100644 tests_python/contracts_011/opcodes/subset.tz create mode 100644 tests_python/contracts_011/opcodes/tez_add_sub.tz create mode 100644 tests_python/contracts_011/opcodes/ticket_bad.tz create mode 100644 tests_python/contracts_011/opcodes/ticket_big_store.tz create mode 100644 tests_python/contracts_011/opcodes/ticket_join.tz create mode 100644 tests_python/contracts_011/opcodes/ticket_read.tz create mode 100644 tests_python/contracts_011/opcodes/ticket_split.tz create mode 100644 tests_python/contracts_011/opcodes/ticket_store-2.tz create mode 100644 tests_python/contracts_011/opcodes/ticket_store.tz create mode 100644 tests_python/contracts_011/opcodes/ticketer-2.tz create mode 100644 tests_python/contracts_011/opcodes/ticketer.tz create mode 100644 tests_python/contracts_011/opcodes/transfer_amount.tz create mode 100644 tests_python/contracts_011/opcodes/transfer_tokens.tz create mode 100644 tests_python/contracts_011/opcodes/uncomb.tz create mode 100644 tests_python/contracts_011/opcodes/unpair.tz create mode 100644 tests_python/contracts_011/opcodes/update_big_map.tz create mode 100644 tests_python/contracts_011/opcodes/utxo_read.tz create mode 100644 tests_python/contracts_011/opcodes/utxor.tz create mode 100644 tests_python/contracts_011/opcodes/view_fib.tz create mode 100644 tests_python/contracts_011/opcodes/view_mutual_recursion.tz create mode 100644 tests_python/contracts_011/opcodes/view_op_add.tz create mode 100644 tests_python/contracts_011/opcodes/view_op_constant.tz create mode 100644 tests_python/contracts_011/opcodes/view_op_id.tz create mode 100644 tests_python/contracts_011/opcodes/view_op_nonexistent_addr.tz create mode 100644 tests_python/contracts_011/opcodes/view_op_nonexistent_func.tz create mode 100644 tests_python/contracts_011/opcodes/view_op_test_step_contants.tz create mode 100644 tests_python/contracts_011/opcodes/view_op_toplevel_inconsistent_input_type.tz create mode 100644 tests_python/contracts_011/opcodes/view_op_toplevel_inconsistent_output_type.tz create mode 100644 tests_python/contracts_011/opcodes/view_rec.tz create mode 100644 tests_python/contracts_011/opcodes/view_toplevel_lib.tz create mode 100644 tests_python/contracts_011/opcodes/voting_power.tz create mode 100644 tests_python/contracts_011/opcodes/xor.tz create mode 100644 tests_python/tests_011/__init__.py create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_legacy_flag.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[None].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[Optimized].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[Optimized_legacy].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[Readable].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list (pair nat int bool bytes)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list (pair nat int bool)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list (pair nat int)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list nat].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[nat].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[pair nat int bool bytes].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[pair nat int bool].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[pair nat int].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[None].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[Optimized].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[Optimized_legacy].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[Readable].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[client_regtest_custom_scrubber0].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_fac.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_fib.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_mutual_recursion.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_add.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_id.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_nonexistent_addr.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_nonexistent_func.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_test_step_contants.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_toplevel_inconsistent_input_type.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_toplevel_inconsistent_output_type.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_rec.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_toplevel_lib.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestSelfAddressTransfer::test_self_address_originate_receiver.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestSelfAddressTransfer::test_self_address_originate_sender.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract.TestSelfAddressTransfer::test_send_self_address.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_one[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_one[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_one[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_random[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_random[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_random[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_zero[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_zero[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_zero[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_one[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_one[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_one[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_random[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_random[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_random[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_zero[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_zero[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_zero[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_one[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_one[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_one[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_random[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_random[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_random[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_zero[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_zero[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_zero[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_fr_bytes_parameters_more_than_32_bytes.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_groth16.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_one[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_one[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_one[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_random[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_random[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_random[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_zero[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_zero[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_zero[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_one[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_one[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_one[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_random[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_random[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_random[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_zero[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_zero[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_zero[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_one[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_one[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_one[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_random[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_random[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_random[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_zero[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_zero[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_zero[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_one[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_one[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_one[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_random[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_random[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_random[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_zero[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_zero[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_zero[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_neg_g1.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_neg_g2.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_nil.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_one_one.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_one_random.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_one_zero.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_random_one.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_random_random.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_random_zero.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_zero_one.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_zero_random.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_zero_zero.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_signature_aggregation.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_one[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_one[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_one[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_random[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_random[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_random[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_zero[Fr].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_zero[G1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_zero[G2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpeq.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpge.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpgt.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmple.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmplt.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpneq.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_eq.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_ge.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_gt.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_le.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_lt.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_neq.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--big_map_get_add.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--big_map_mem.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--build_list.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--carn_and_cdrn.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--compare.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--compare_bytes.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--fail.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--guestbook.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--macro_annotations.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--map_caddaadr.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--max_in_list.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--min.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--pair_macro.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--set_caddaadr.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--take_my_money.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--unpair_macro.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_origination_diff.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_origination_id.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_origination_literal.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_transfer_diff.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_transfer_id.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainLevel::test_level.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_contract_fails.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_gen_keys.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_init_proxy.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_now.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_self.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_sender.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_set_delegate.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice.out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0 \"spsig1PPUFZucuAQybs5wsqs.818025e860.out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75.2d6806d54e.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75.378d03ae2d.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75.57fdc7ad1c.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xeaa9ab79e8b84ef0e55c43a9a857214d8761e67b75.c583c796bf.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_success[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b.7da5c9014e.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_source.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_split_bytes.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_split_string.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_store_input.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_trace_origination[compare_big_type.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_trace_origination[compare_big_type2.tz].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_transfer_amount.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_transfer_tokens.out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 4) {})-\"hello\"-(Pa.f6092ac5d6.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 5) { Elt \"hello\" 4.0427752f13.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 5) { Elt \"hello\" 4.0793dc66d5.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt \"1\" 1 ; .df114499b8.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt \"1\" 1 ; .f9bea98de9.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt \"hello\" 4 })-.1db12cd837.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None {})-\"hello\"-(Pair N.6fc7d0acf2.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"tw.524c5459f8.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt \"hello\" \"hi\" } None)-\"\".33eba403e7.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt \"hello\" \"hi\" } None)-\"h.a5cd1005c9.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .6f3d35b151.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .76aeaa0706.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .7e7197f248.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .7ef2c415a7.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .b688cc94a7.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .c68db221ed.out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[mul_overflow.tz-Unit-Left Unit].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[mul_overflow.tz-Unit-Right Unit].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Left (Pair 1 257))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Left (Pair 123 257))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Right (Pair 1 257))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Right (Pair 123 257))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[0.5].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[0].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[1000].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[1e-06].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[5].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[8000000000000.0].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }) )-(Right (Righ.7492e8cdea.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Left Unit)-(.21b30dd90f.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Right (Left .2873ef610c.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Right (Left .8a6f480005.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Right (Right.d336ca1903.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Right Unit)-(Right (Right (Left (Pair { Pair \"foo\" \"bar\" } { P.7f2ee47600.out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_check_signature.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[abs.tz-Unit-0-Unit].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[abs.tz-Unit-12039123919239192312931-Unit].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[abs.tz-Unit-948-Unit].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add.tz-Unit-Unit-Unit].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x00 0x00-(Some 0x0000000.3c2de60480.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x01 0x00-(Some 0x0100000.12b2c1172b.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x010000 0x00-(Some 0x010.0e44fc6f40.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x010000 0x010000-(Some 0.7e0ed229a3.out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair -100 100)-(Some \"1970.7c1b1e4e5b.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair 0 \"1970-01-01T00:00:0.528ed42c01.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair 100 100)-(Some \"1970-.6566111ad2.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair \"1970-01-01T00:00:00Z.72c424f3da.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair 100 -100)-(Some \"1970.7c4b12e9aa.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair 100 100)-(Some \"1970-.af32743640.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[address.tz-None-\"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5\"-.f9045c3a04.out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair False False)-(Some False)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair False True)-(Some False)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair True False)-(Some False)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair True True)-(Some True)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_binary.tz-Unit-Unit-Unit].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair False False)-False].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair False True)-False].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair True False)-False].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair True True)-True].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[balance.tz-111-Unit-4000000000000].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair 4 (S.2292d6ce17.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair 4 (S.dda583f5e9.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair 4 (S.6d753598ba.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair 4 (S.73700321f8.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1.1182eca937.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1.2ea67af009.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2.1eead33885.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2.47f55c94c8.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3.7f1f2ab27d.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3.a3c5c126ce.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair {} None)-1-(Pair 4 (Some False))0].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair {} None)-1-(Pair 4 (Some False))1].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 1.4be99ce05d.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 1.50c0e0ff8b.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 1.775c22b027.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"foo\" 0 } None)-\"foo\".968709d39d.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"foo\" 1 } None)-\"bar\".cdcfaf9d09.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair {} None)-\"bar\"-(Pair 4 (Some False))].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_push_bytes_not_padded.tz-None-Unit-(Some 0.9b6e8bcbd3.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_push_nat.tz-None-Unit-(Some 0x100000000000.d1219ca789.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x00-0].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x01-1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x28db8e57af88d9576acd181b89f2.7a85c336ff.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0xb9e8abf8dc324a010007addde986.b821eb26b3.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_mutez.tz-0-0x10-16].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.0accef5bef.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.0ecc537252.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.2229b767cd.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.2ff549b46b.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.bf8a711be6.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.d41cbb044b.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x4147a5ad0a633e4880d2296f08ec5c1.a50412e458.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x5b0ecd0fa853810e356f1eb79721e80.f3a349c4a7.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x8578be1766f92cd82c5e5135c374a03.1b9676e4c2.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x8578be1766f92cd82c5e5135c374a03.e966dc6de5.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.964835cc43.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.b25ea709fb.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.eae36753ea.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.ee57dac8f7.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x4147a5ad0a633e4880d2296f08ec5c1.928f6d4b93.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x5b0ecd0fa853810e356f1eb79721e80.bd5800f6b8.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x8578be1766f92cd82c5e5135c374a03.00e897789a.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x8578be1766f92cd82c5e5135c374a03.a4697eaa13.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.0177355bbf.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.744166c609.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.9f3c5cdc6a.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.a54cb341ba.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.b0dc584c94.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.bddcad090c.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x4147a5ad0a633e4880d2296f08ec5c1.92c153eb47.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x5b0ecd0fa853810e356f1eb79721e80.290ab49d11.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x8578be1766f92cd82c5e5135c374a03.69f3589a06.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x8578be1766f92cd82c5e5135c374a03.fee3c5cf43.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.1bccc033e8.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.40958700fe.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.6c62b03d78.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.d23f269341.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x4147a5ad0a633e4880d2296f08ec5c1.927f808504.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x5b0ecd0fa853810e356f1eb79721e80.0c114c956a.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x8578be1766f92cd82c5e5135c374a03.03c4f38e68.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x8578be1766f92cd82c5e5135c374a03.8ed19cfdd9.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[car.tz-0-(Pair 34 17)-34].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cdr.tz-0-(Pair 34 17)-17].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[chain_id_store.tz-(Some \"NetXdQprcVkpaWU\")-Unit-(Some \".8420090f97.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[chain_id_store.tz-(Some 0x7a06a770)-Unit-(Some \"NetXdQprcVkpaWU\")].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[chain_id_store.tz-None-Unit-(Some \"NetXdQprcVkpaWU\")].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb-get.tz-Unit-(Pair 1 4 2 Unit)-Unit].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb-set-2.tz-None-(Pair 1 4 2 Unit)-(Some (Pair 2 4 \"t.886cc365c6.out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb-set.tz-(Pair 1 4 2 Unit)-Unit-(Pair 2 12 8 Unit)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb.tz-(Pair 0 0 0)-Unit-(Pair 1 2 3)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[compare.tz-Unit-Unit-Unit].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comparisons.tz-{}-{ -9999999; -1 ; 0 ; 1 ; 9999999 }-{ .bbaa8924d2.out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{ \"World!\" }-{ \"Hello World!\" }].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{ \"test1\" ; \"test2\" }-{ \"Hello test1.c27e8c3ee6.out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{}-{}].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{ 0xab ; 0xcd }-{ 0xffab ; 0xffcd }].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{ 0xcd }-{ 0xffcd }].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{}-{}].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_list.tz-\"\"-{ \"Hello\" ; \" \" ; \"World\" ; \"!\" }-\"He.0c7b4cd53c.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_list.tz-\"\"-{ \"a\" ; \"b\" ; \"c\" }-\"abc\"].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_list.tz-\"\"-{}-\"\"].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cons.tz-{ -5 ; 10 }-99-{ 99 ; -5 ; 10 }].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cons.tz-{ 10 }--5-{ -5 ; 10 }].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cons.tz-{}-10-{ 10 }].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"A\" } { \"B\" })-(Some False)].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"B\" ; \"B\" ; \"asdf\" ; \"C\" }.4360bbe5d0.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"B\" ; \"C\" ; \"asdf\" } { \"B\".ff6e4785ee.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"B\" } { \"B\" })-(Some True)].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"c\" } { \"B\" })-(Some False)].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair {} {})-(Some True)].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contract.tz-Unit-\"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5\"-Unit].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[create_contract.tz-None-Unit-(Some \"KT1Mjjcb6tmSsLm7Cb3.c3984fbc14.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair \"1970-01-01T00:03:20Z\" \"19.90e9215d17.out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 0 0)-0].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 0 1)--1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 1 0)-1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dig_eq.tz-Unit-(Pair 17 (Pair 16 (Pair 15 (Pair 14 (Pai.2794d4782e.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dig_eq.tz-Unit-(Pair 2 (Pair 3 (Pair 12 (Pair 16 (Pair .d473151c0f.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dign.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-5].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dip.tz-(Pair 0 0)-(Pair 1 1)-(Pair 1 2)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dip.tz-(Pair 0 0)-(Pair 15 9)-(Pair 15 24)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dipn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-6].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dropn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-5].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dugn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dup-n.tz-Unit-Unit-Unit].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair -8 2)-(Pair (S.ecc0e72cbb.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair 10 -3)-(Pair (.3caea50555.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair 10 0)-(Pair No.f9448c04fb.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 0))-(Left None)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 10))-(Left (So.f782cc1dec.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 3))-(Left (Som.016b4db96c.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 0))-(Right None)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 10))-(Right (.e705a30e07.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 3))-(Right (S.44485eda6a.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 5 (Right 10))-(Right (S.8ab987af15.out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[empty_map.tz-{}-Unit-{ Elt \"hello\" \"world\" }].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[exec_concat.tz-\"?\"-\"\"-\"_abc\"].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[exec_concat.tz-\"?\"-\"test\"-\"test_abc\"].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[first.tz-111-{ 1 ; 2 ; 3 ; 4 }-1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[first.tz-111-{ 4 }-4].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 4) {})-\"hello\"-(Pair .161d86cef6.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 5) { Elt \"hello\" 4 }).684ab7e326.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 5) { Elt \"hello\" 4 }).d49817fb83.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt \"1\" 1 ; .6900b1da14.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt \"1\" 1 ; .bca0ede8be.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt \"hello\" 4 })-\"he.c1b4e1d6dc.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None {})-\"hello\"-(Pair None {})].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt \"1\" \"one\" ; .bc4127094e.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt \"hello\" \"hi\" })-\"\"-(P.0c03056487.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt \"hello\" \"hi\" })-\"hell.cc45544c66.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_key.tz-None-\"edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAb.613ad6b637.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_key.tz-None-\"edpkuJqtDcA2m2muMxViSM47MPsGQzmyjnNTa.da50984e8d.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_string.tz-0x00-\"12345\"-0xb4c26c20de52a4eaf0d8a340d.2bba28b0bf.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_string.tz-0x00-\"abcdefg\"-0x46fdbcb4ea4eadad5615cda.acc82cd954.out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if.tz-None-False-(Some False)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if.tz-None-True-(Some True)].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if_some.tz-\"?\"-(Some \"hello\")-\"hello\"].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if_some.tz-\"?\"-None-\"\"].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[int.tz-None-0-(Some 0)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[int.tz-None-1-(Some 1)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[int.tz-None-9999-(Some 9999)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[keccak.tz-None-0x48656c6c6f2c20776f726c6421-(Some 0xb6e.34c02678c9.out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[left_right.tz-(Left \"X\")-(Left True)-(Right True)].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[left_right.tz-(Left \"X\")-(Right \"a\")-(Left \"a\")].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[level.tz-111-Unit-1].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat.tz-\"abc\"-{ \"d\" ; \"e\" ; \"f\" }-\"abcdef\"].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat.tz-\"abc\"-{}-\"abc\"].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x-{ 0x00 ; 0x11 ; 0x00 }-0x001100].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x-{}-0x].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x00ab-{ 0xcd ; 0xef ; 0x00 }-0x00abcdef00].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0xabcd-{}-0xabcd].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id.tz-{\"\"}-{ \"1\" ; \"2\" ; \"3\" }-{ \"1\" ; \"2\" ; \"3\" }].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id.tz-{\"\"}-{ \"a\" ; \"b\" ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id.tz-{\"\"}-{}-{}].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id_map.tz-{\"\"}-{ \"1\" ; \"2\" ; \"3\" }-{ \"1\" ; \"2\" ; \"3\" }].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id_map.tz-{\"\"}-{ \"a\" ; \"b\" ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id_map.tz-{\"\"}-{}-{}].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_iter.tz-0-{ 10 ; 2 ; 1 }-20].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_iter.tz-0-{ 3 ; 6 ; 9 }-162].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{ 1 ; 1 ; 1 ; 1 }-{ 1 ; 2 ; 3 ; 4 }].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{ 1 ; 2 ; 3 ; 0 }-{ 1 ; 3 ; 5 ; 3 }].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{}-{}].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }-6].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 ; 2 ; 3 }-3].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 }-1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{}-0].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[loop_left.tz-{\"\"}-{ \"c\" ; \"b\" ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[loop_left.tz-{\"\"}-{}-{}].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 0 ; Elt 3 4 }-{ Elt 0 0 ; Elt 3 4 }].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 0 }-{ Elt 0 0 }].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 1 }-{ Elt 0 1 }].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_iter.tz-(Pair 0 0)-{ Elt 0 100 ; Elt 2 100 }-(Pair 2 200)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_iter.tz-(Pair 0 0)-{ Elt 1 1 ; Elt 2 100 }-(Pair 3 101)].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_map.tz-{ Elt \"bar\" 5 ; Elt \"foo\" 1 }-15-{ Elt \"bar\".12b9d73d5a.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_map.tz-{ Elt \"foo\" 1 }-10-{ Elt \"foo\" 11 }].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_map.tz-{}-10-{}].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair { Elt 0 .7396e5f090.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair { Elt 1 .cef8ce601a.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1-(Pa.1a55a5bfa5.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2-(Pa.89cc24d256.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3-(Pa.2fba3165c0.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair {} None)-1-(Pair {} (Some False))].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 11 } .6d625e02a5.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 11 } .a7e3837a82.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 11 } .c7716fe79e.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"foo\" 0 } None)-\"foo\"-(Pa.7861a3b1e2.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"foo\" 1 } None)-\"bar\"-(Pa.fa8366e8a8.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair {} None)-\"bar\"-(Pair {} (Some False))].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt \"a\" 1 ; Elt \"b\" 2 ; Elt \"c\" 3 ; .1da2c2c3fa.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt \"a\" 1 ; Elt \"b\" 2 ; Elt \"c\" 3 }-3].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt \"a\" 1 }-1].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{}-0].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[mul.tz-Unit-Unit-Unit].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[mutez_to_bls12_381_fr.tz-0x00-257-0x0101000000000000000.be11332c7f.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[mutez_to_bls12_381_fr.tz-0x02-16-0x10000000000000000000.8230fb4fac.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left -2)-2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left 0)-0].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left 2)--2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Right 0)-0].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Right 2)--2].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[none.tz-Some 10-Unit-None].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not.tz-None-False-(Some True)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not.tz-None-True-(Some False)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left -8)-(Some 7)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left -9)-(Some 8)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 0)-(Some -1)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 7)-(Some -8)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 8)-(Some -9)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 0)-(Some -1)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 7)-(Some -8)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 8)-(Some -9)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair False False)-(Some False)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair False True)-(Some True)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair True False)-(Some True)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair True True)-(Some True)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 0 8)-(Some 8)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 14 1)-(Some 15)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 15 4)-(Some 15)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 4 8)-(Some 12)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 7 7)-(Some 7)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 8 0)-(Some 8)].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev.tz-Unit-(Pair -1 (Pair 1 (Pair \"foobar\".368bdfd73a.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev.tz-Unit-(Pair -1 (Pair 1 (Pair \"foobar\".735d9ae802.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev_cty.tz-Unit-(Pair \"edpkuBknW28nW72KG6RoH.1ac5de50fb.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev_cty.tz-Unit-(Pair \"edpkuBknW28nW72KG6RoH.4e20b52378.out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair False False)-(Some (Pair False False))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair False True)-(Some (Pair False True))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair True False)-(Some (Pair True False))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair True True)-(Some (Pair True True))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pexec.tz-14-38-52].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pexec_2.tz-{ 0 ; 1 ; 2 ; 3}-4-{ 0 ; 7 ; 14 ; 21 }].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ret_int.tz-None-Unit-(Some 300)].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse.tz-{\"\"}-{ \"c\" ; \"b\" ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse.tz-{\"\"}-{}-{}].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse_loop.tz-{\"\"}-{ \"c\" ; \"b\" ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse_loop.tz-{\"\"}-{}-{}].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sapling_empty_state.tz-{}-Unit-0].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[self_address.tz-Unit-Unit-Unit].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[self_with_default_entrypoint.tz-Unit-Unit-Unit].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[self_with_entrypoint.tz-Unit-Left (Left 0)-Unit].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair \"hello\" 0)-\"\"-(Pair \"\" 0)].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair \"hello\" 0)-\"abc\"-(Pair \"abc\" 0)].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair \"hello\" 0)-\"world\"-(Pair \"world\" 0)].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair \"hello\" 0)-1-(Pair \"hello\" 1)].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair \"hello\" 500)-3-(Pair \"hello\" 3)].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair \"hello\" 7)-100-(Pair \"hello\" 100)].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{ \"a\" ; \"b\" ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{ \"asdf\" ; \"bcde\" }-{ \"asdf\" ; \"bcde\" }].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{}-{}].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{ -100 ; 1 ; 2 ; 3 }--94].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{ 1 }-1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{}-0].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair { \"Hello\" ; \"World\" } None)-\"\"-(Pai.3d2044726e.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair { \"Hi\" } None)-\"Hi\"-(Pair { \"Hi\" } .564beb9251.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair {} None)-\"Hi\"-(Pair {} (Some False))].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }-6].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 ; 2 ; 3 }-3].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 }-1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{}-0].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sha3.tz-None-0x48656c6c6f2c20776f726c6421-(Some 0xf345a.a07ae9dddf.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 0 0))-(Some 0)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 0 1))-(Some 0)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 1 2))-(Some 4)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 15 2))-(Some 60)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 8 1))-(Some 16)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 0 0))-(Some 0)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 0 1))-(Some 0)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 1 2))-(Some 0)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 15 2))-(Some 3)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 8 1))-(Some 4)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-None-Pair 0 0-None].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 0 0-(Some \"\")].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 0 10-None].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 0 2-(Some \"Fo\")].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 1 1-(Some \"o\")].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 1 3-None].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 10 5-None].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some\"FooFooFooFooFooFooFooFooFooFooFooFooFooFo.c508d67bb0.out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-None-Pair 0 1-None].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 0 0-(Some 0x)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 0 1-(Some 0xaa)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 1-(Some 0xbb)0].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 1-(Some 0xbb)1].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 2-(Some 0xbbcc)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 3-None].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbccaabbccaabbccaabbccaabbccaab.df5895de85.out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[str_id.tz-None-\"Hello\"-(Some \"Hello\")].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[str_id.tz-None-\"abcd\"-(Some \"abcd\")].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 -100)-\"1970-01-01T00:03:20Z\"].out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 100)-\"1970-01-01T00:00:00Z\"].out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 200000000000000000.3db82d2c25.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[tez_add_sub.tz-None-(Pair 2000000 1000000)-(Some (Pair .b461aa042b.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[tez_add_sub.tz-None-(Pair 2310000 1010000)-(Some (Pair .1e8cf7679c.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[uncomb.tz-0-(Pair 1 4 2)-142].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[unpair.tz-Unit-Unit-Unit].out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[voting_power.tz-(Pair 0 0)-\"edpkuBknW28nW72KG6RoHtYW7p1.b2c677ad7b.out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair False False)-(Some (Left False))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair False True)-(Some (Left True))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair True False)-(Some (Left True))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair True True)-(Some (Left False))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 0 0)-(Some (Right 0))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 0 1)-(Some (Right 1))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 1 0)-(Some (Right 1))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 1 1)-(Some (Right 0))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 42 21)-(Some (Right 63))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 42 63)-(Some (Right 21))].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_hash_consistency_michelson_cli.out create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair { Elt \"bar\" 5 ; Elt \"foo\" 1 } .480b9afc63.out" create mode 100644 "tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair { Elt \"foo\" 1 } 1)-10-(Pair { .811573b5a7.out" create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair {} 0)-10-(Pair {} 0)].out create mode 100644 tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_packunpack.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_add_liquidity.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_approval.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_approved_transfer.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_approve1.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_approve2.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_approve3.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_mint_or_burn.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_dex_storage.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_lqt_storage.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_remove_liquidity.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_setup.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_tok_storage.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_add_liquidity.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_buy_tok.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_approve1.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_approve2.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_approve3.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_mint_or_burn.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_dex_storage.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_lqt_storage.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_sell_tok.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_setup.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_tok_storage.out create mode 100644 tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_transfer.out create mode 100644 tests_python/tests_011/conftest.py create mode 100644 tests_python/tests_011/contract_paths.py create mode 100644 tests_python/tests_011/per_block_vote_files/false.json create mode 100644 tests_python/tests_011/per_block_vote_files/invalid.json create mode 100644 tests_python/tests_011/per_block_vote_files/non_boolean.json create mode 100644 tests_python/tests_011/per_block_vote_files/true.json create mode 100644 tests_python/tests_011/per_block_vote_files/wrong_key.json create mode 100644 tests_python/tests_011/protocol.py create mode 100644 tests_python/tests_011/test_accuser.py create mode 100644 tests_python/tests_011/test_baker_endorser.py create mode 100644 tests_python/tests_011/test_basic.py create mode 100644 tests_python/tests_011/test_binaries.py create mode 100644 tests_python/tests_011/test_block_times_ideal_scenario.py create mode 100644 tests_python/tests_011/test_bootstrap.py create mode 100644 tests_python/tests_011/test_client.py create mode 100644 tests_python/tests_011/test_client_without_node.py create mode 100644 tests_python/tests_011/test_codec.py create mode 100644 tests_python/tests_011/test_contract.py create mode 100644 tests_python/tests_011/test_contract_annotations.py create mode 100644 tests_python/tests_011/test_contract_baker.py create mode 100644 tests_python/tests_011/test_contract_bls12_381.py create mode 100644 tests_python/tests_011/test_contract_macros.py create mode 100644 tests_python/tests_011/test_contract_onchain_opcodes.py create mode 100644 tests_python/tests_011/test_contract_opcodes.py create mode 100644 tests_python/tests_011/test_cors.py create mode 100644 tests_python/tests_011/test_crypto.py create mode 100644 tests_python/tests_011/test_double_endorsement.py create mode 100644 tests_python/tests_011/test_fa12.py create mode 100755 tests_python/tests_011/test_forge_block.py create mode 100644 tests_python/tests_011/test_fork.py create mode 100644 tests_python/tests_011/test_injection.py create mode 100644 tests_python/tests_011/test_legacy_snapshots.py create mode 100644 tests_python/tests_011/test_legacy_upgrade.py create mode 100644 tests_python/tests_011/test_liquidity_baking.py create mode 100644 tests_python/tests_011/test_many_bakers.py create mode 100644 tests_python/tests_011/test_many_nodes.py create mode 100644 tests_python/tests_011/test_mempool.py create mode 100644 tests_python/tests_011/test_migration.py create mode 100644 tests_python/tests_011/test_migration_flattening.py create mode 100644 tests_python/tests_011/test_mockup.py create mode 100644 tests_python/tests_011/test_multinode_snapshot.py create mode 100644 tests_python/tests_011/test_multinode_storage_reconstruction.py create mode 100644 tests_python/tests_011/test_multiple_transfers.py create mode 100644 tests_python/tests_011/test_multisig.py create mode 100644 tests_python/tests_011/test_nonce_seed_revelation.py create mode 100644 tests_python/tests_011/test_openapi.py create mode 100644 tests_python/tests_011/test_p2p.py create mode 100644 tests_python/tests_011/test_per_block_votes.py create mode 100644 tests_python/tests_011/test_perf_endorsement.py create mode 100644 tests_python/tests_011/test_programs.py create mode 100644 tests_python/tests_011/test_proto_demo_counter.py create mode 100644 tests_python/tests_011/test_proto_demo_noops_manual_bake.py create mode 100644 tests_python/tests_011/test_rpc.py create mode 100644 tests_python/tests_011/test_sapling.py create mode 100644 tests_python/tests_011/test_slice_fails_params.txt create mode 100644 tests_python/tests_011/test_slice_success_params.txt create mode 100755 tests_python/tests_011/test_tls.py create mode 100644 tests_python/tests_011/test_voting.py create mode 100644 tests_python/tests_011/test_voting_full.py diff --git a/.gitlab/ci/integration.yml b/.gitlab/ci/integration.yml index 5a8bd206131c..640f698dad0c 100644 --- a/.gitlab/ci/integration.yml +++ b/.gitlab/ci/integration.yml @@ -440,6 +440,132 @@ integration:010_voting_full: - poetry run pytest "tests_010/test_voting_full.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/010_voting_full.xml" 2>&1 | tee "tmp/010_voting_full.out" | tail stage: test +integration:011_batch: + extends: .integration_python_template + script: + - poetry run pytest "tests_011" --exitfirst -m "not slow" -s --log-dir=tmp "--junitxml=reports/011_batch.xml" 2>&1 | tee "tmp/011_batch.out" | tail + stage: test + +integration:011_baker_endorser: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_baker_endorser.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_baker_endorser.xml" 2>&1 | tee "tmp/011_baker_endorser.out" | tail + stage: test + +integration:011_block_times_ideal_scenario: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_block_times_ideal_scenario.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_block_times_ideal_scenario.xml" 2>&1 | tee "tmp/011_block_times_ideal_scenario.out" | tail + stage: test + +integration:011_bootstrap: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_bootstrap.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_bootstrap.xml" 2>&1 | tee "tmp/011_bootstrap.out" | tail + stage: test + +integration:011_contract: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_contract.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_contract.xml" 2>&1 | tee "tmp/011_contract.out" | tail + stage: test + +integration:011_contract_annotations: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_contract_annotations.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_contract_annotations.xml" 2>&1 | tee "tmp/011_contract_annotations.out" | tail + stage: test + +integration:011_contract_macros: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_contract_macros.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_contract_macros.xml" 2>&1 | tee "tmp/011_contract_macros.out" | tail + stage: test + +integration:011_contract_onchain_opcodes: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_contract_onchain_opcodes.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_contract_onchain_opcodes.xml" 2>&1 | tee "tmp/011_contract_onchain_opcodes.out" | tail + stage: test + +integration:011_contract_opcodes: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_contract_opcodes.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_contract_opcodes.xml" 2>&1 | tee "tmp/011_contract_opcodes.out" | tail + stage: test + +integration:011_forge_block: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_forge_block.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_forge_block.xml" 2>&1 | tee "tmp/011_forge_block.out" | tail + stage: test + +integration:011_legacy_snapshots: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_legacy_snapshots.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_legacy_snapshots.xml" 2>&1 | tee "tmp/011_legacy_snapshots.out" | tail + stage: test + +integration:011_legacy_upgrade: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_legacy_upgrade.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_legacy_upgrade.xml" 2>&1 | tee "tmp/011_legacy_upgrade.out" | tail + stage: test + +integration:011_many_bakers: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_many_bakers.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_many_bakers.xml" 2>&1 | tee "tmp/011_many_bakers.out" | tail + stage: test + +integration:011_many_nodes: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_many_nodes.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_many_nodes.xml" 2>&1 | tee "tmp/011_many_nodes.out" | tail + stage: test + +integration:011_mempool: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_mempool.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_mempool.xml" 2>&1 | tee "tmp/011_mempool.out" | tail + stage: test + +integration:011_multinode_snapshot: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_multinode_snapshot.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_multinode_snapshot.xml" 2>&1 | tee "tmp/011_multinode_snapshot.out" | tail + stage: test + +integration:011_multinode_storage_reconstruction: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_multinode_storage_reconstruction.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_multinode_storage_reconstruction.xml" 2>&1 | tee "tmp/011_multinode_storage_reconstruction.out" | tail + stage: test + +integration:011_nonce_seed_revelation: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_nonce_seed_revelation.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_nonce_seed_revelation.xml" 2>&1 | tee "tmp/011_nonce_seed_revelation.out" | tail + stage: test + +integration:011_perf_endorsement: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_perf_endorsement.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_perf_endorsement.xml" 2>&1 | tee "tmp/011_perf_endorsement.out" | tail + stage: test + +integration:011_rpc: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_rpc.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_rpc.xml" 2>&1 | tee "tmp/011_rpc.out" | tail + stage: test + +integration:011_voting_full: + extends: .integration_python_template + script: + - poetry run pytest "tests_011/test_voting_full.py" --exitfirst -m "slow" -s --log-dir=tmp "--junitxml=reports/011_voting_full.xml" 2>&1 | tee "tmp/011_voting_full.out" | tail + stage: test + integration:alpha_batch: extends: .integration_python_template script: diff --git a/.gitlab/ci/opam.yml b/.gitlab/ci/opam.yml index 5a67c595378e..cbdcb80c0246 100644 --- a/.gitlab/ci/opam.yml +++ b/.gitlab/ci/opam.yml @@ -46,6 +46,11 @@ opam-bin:tezos-accuser-010-PtGRANAD: variables: package: tezos-accuser-010-PtGRANAD +opam-bin:tezos-accuser-011-PtHangzH: + extends: .opam_bin_template + variables: + package: tezos-accuser-011-PtHangzH + opam-bin:tezos-accuser-alpha: extends: .opam_bin_template variables: @@ -66,6 +71,11 @@ opam-bin:tezos-baker-010-PtGRANAD: variables: package: tezos-baker-010-PtGRANAD +opam-bin:tezos-baker-011-PtHangzH: + extends: .opam_bin_template + variables: + package: tezos-baker-011-PtHangzH + opam-bin:tezos-baker-alpha: extends: .opam_bin_template variables: @@ -96,6 +106,11 @@ opam-bin:tezos-endorser-010-PtGRANAD: variables: package: tezos-endorser-010-PtGRANAD +opam-bin:tezos-endorser-011-PtHangzH: + extends: .opam_bin_template + variables: + package: tezos-endorser-011-PtHangzH + opam-bin:tezos-endorser-alpha: extends: .opam_bin_template variables: @@ -201,6 +216,11 @@ opam:tezos-010-PtGRANAD-test-helpers: variables: package: tezos-010-PtGRANAD-test-helpers +opam:tezos-011-PtHangzH-test-helpers: + extends: .opam_template + variables: + package: tezos-011-PtHangzH-test-helpers + opam:tezos-accuser-008-PtEdo2Zk-commands: extends: .opam_template variables: @@ -216,6 +236,11 @@ opam:tezos-accuser-010-PtGRANAD-commands: variables: package: tezos-accuser-010-PtGRANAD-commands +opam:tezos-accuser-011-PtHangzH-commands: + extends: .opam_template + variables: + package: tezos-accuser-011-PtHangzH-commands + opam:tezos-accuser-alpha-commands: extends: .opam_template variables: @@ -256,6 +281,16 @@ opam:tezos-baking-010-PtGRANAD-commands: variables: package: tezos-baking-010-PtGRANAD-commands +opam:tezos-baking-011-PtHangzH: + extends: .opam_template + variables: + package: tezos-baking-011-PtHangzH + +opam:tezos-baking-011-PtHangzH-commands: + extends: .opam_template + variables: + package: tezos-baking-011-PtHangzH-commands + opam:tezos-baking-alpha: extends: .opam_template variables: @@ -286,6 +321,11 @@ opam:tezos-benchmark-010-PtGRANAD: variables: package: tezos-benchmark-010-PtGRANAD +opam:tezos-benchmark-011-PtHangzH: + extends: .opam_template + variables: + package: tezos-benchmark-011-PtHangzH + opam:tezos-benchmark-alpha: extends: .opam_template variables: @@ -306,6 +346,11 @@ opam:tezos-benchmark-type-inference-010-PtGRANAD: variables: package: tezos-benchmark-type-inference-010-PtGRANAD +opam:tezos-benchmark-type-inference-011-PtHangzH: + extends: .opam_template + variables: + package: tezos-benchmark-type-inference-011-PtHangzH + opam:tezos-benchmark-type-inference-alpha: extends: .opam_template variables: @@ -316,6 +361,11 @@ opam:tezos-benchmarks-proto-010-PtGRANAD: variables: package: tezos-benchmarks-proto-010-PtGRANAD +opam:tezos-benchmarks-proto-011-PtHangzH: + extends: .opam_template + variables: + package: tezos-benchmarks-proto-011-PtHangzH + opam:tezos-benchmarks-proto-alpha: extends: .opam_template variables: @@ -451,6 +501,21 @@ opam:tezos-client-010-PtGRANAD-commands-registration: variables: package: tezos-client-010-PtGRANAD-commands-registration +opam:tezos-client-011-PtHangzH: + extends: .opam_template + variables: + package: tezos-client-011-PtHangzH + +opam:tezos-client-011-PtHangzH-commands: + extends: .opam_template + variables: + package: tezos-client-011-PtHangzH-commands + +opam:tezos-client-011-PtHangzH-commands-registration: + extends: .opam_template + variables: + package: tezos-client-011-PtHangzH-commands-registration + opam:tezos-client-alpha: extends: .opam_template variables: @@ -511,6 +576,11 @@ opam:tezos-client-sapling-010-PtGRANAD: variables: package: tezos-client-sapling-010-PtGRANAD +opam:tezos-client-sapling-011-PtHangzH: + extends: .opam_template + variables: + package: tezos-client-sapling-011-PtHangzH + opam:tezos-client-sapling-alpha: extends: .opam_template variables: @@ -591,6 +661,11 @@ opam:tezos-embedded-protocol-010-PtGRANAD: variables: package: tezos-embedded-protocol-010-PtGRANAD +opam:tezos-embedded-protocol-011-PtHangzH: + extends: .opam_template + variables: + package: tezos-embedded-protocol-011-PtHangzH + opam:tezos-embedded-protocol-alpha: extends: .opam_template variables: @@ -631,6 +706,11 @@ opam:tezos-endorser-010-PtGRANAD-commands: variables: package: tezos-endorser-010-PtGRANAD-commands +opam:tezos-endorser-011-PtHangzH-commands: + extends: .opam_template + variables: + package: tezos-endorser-011-PtHangzH-commands + opam:tezos-endorser-alpha-commands: extends: .opam_template variables: @@ -826,6 +906,21 @@ opam:tezos-protocol-010-PtGRANAD-tests: variables: package: tezos-protocol-010-PtGRANAD-tests +opam:tezos-protocol-011-PtHangzH: + extends: .opam_template + variables: + package: tezos-protocol-011-PtHangzH + +opam:tezos-protocol-011-PtHangzH-parameters: + extends: .opam_template + variables: + package: tezos-protocol-011-PtHangzH-parameters + +opam:tezos-protocol-011-PtHangzH-tests: + extends: .opam_template + variables: + package: tezos-protocol-011-PtHangzH-tests + opam:tezos-protocol-alpha: extends: .opam_template variables: @@ -941,6 +1036,11 @@ opam:tezos-protocol-functor-010-PtGRANAD: variables: package: tezos-protocol-functor-010-PtGRANAD +opam:tezos-protocol-functor-011-PtHangzH: + extends: .opam_template + variables: + package: tezos-protocol-functor-011-PtHangzH + opam:tezos-protocol-functor-alpha: extends: .opam_template variables: @@ -1016,6 +1116,16 @@ opam:tezos-protocol-plugin-010-PtGRANAD-registerer: variables: package: tezos-protocol-plugin-010-PtGRANAD-registerer +opam:tezos-protocol-plugin-011-PtHangzH: + extends: .opam_template + variables: + package: tezos-protocol-plugin-011-PtHangzH + +opam:tezos-protocol-plugin-011-PtHangzH-registerer: + extends: .opam_template + variables: + package: tezos-protocol-plugin-011-PtHangzH-registerer + opam:tezos-protocol-plugin-alpha: extends: .opam_template variables: diff --git a/.gitlab/ci/unittest.yml b/.gitlab/ci/unittest.yml index 3629932ae27b..acc2689b1db2 100644 --- a/.gitlab/ci/unittest.yml +++ b/.gitlab/ci/unittest.yml @@ -62,6 +62,16 @@ unit:010_PtGRANAD: src/proto_010_PtGRANAD/lib_client.test_proto src/proto_010_PtGRANAD/lib_protocol.test_proto +unit:011_PtHangzH: + extends: .unit_test_template + script: + - > + make + src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference.test_proto + src/proto_011_PtHangzH/lib_benchmark.test_proto + src/proto_011_PtHangzH/lib_client.test_proto + src/proto_011_PtHangzH/lib_protocol.test_proto + unit:alpha: extends: .unit_test_template script: @@ -71,7 +81,6 @@ unit:alpha: src/proto_alpha/lib_benchmark.test_proto src/proto_alpha/lib_client.test_proto src/proto_alpha/lib_protocol.test_proto - unit:non-proto: extends: .unit_test_template script: diff --git a/active_protocol_versions b/active_protocol_versions index 7ea3ee3a0a4d..d5bc98d2199e 100644 --- a/active_protocol_versions +++ b/active_protocol_versions @@ -1,4 +1,5 @@ 008-PtEdo2Zk 009-PsFLoren 010-PtGRANAD +011-PtHangzH alpha diff --git a/docs/011/cli-commands.rst b/docs/011/cli-commands.rst new file mode 100644 index 000000000000..b05d85818cdf --- /dev/null +++ b/docs/011/cli-commands.rst @@ -0,0 +1,50 @@ +********************** +Command Line Interface +********************** + +This document is a prettier output of the documentation produced by +the command ``man`` of the different Tezos binaries. You can obtain similar pages +using shell commands such as (:ref:`indicating the appropriate protocol `): + +:: + + tezos-client -protocol man -verbosity 3 + +The rest of this page documents the protocol-dependent tools. +The protocol-independent tools are documented :doc:`here <../shell/cli-commands>`. + + +.. _client_manual_011: + +Client manual +============= + +.. raw:: html + :file: tezos-client.html + + +.. _baker_manual_011: + +Baker manual +============ + +.. raw:: html + :file: tezos-baker.html + + +.. _endorser_manual_011: + +Endorser manual +=============== + +.. raw:: html + :file: tezos-endorser.html + + +.. _accuser_manual_011: + +Accuser manual +============== + +.. raw:: html + :file: tezos-accuser.html diff --git a/docs/011/consensus.rst b/docs/011/consensus.rst new file mode 100644 index 000000000000..76d1c0299796 --- /dev/null +++ b/docs/011/consensus.rst @@ -0,0 +1,363 @@ +The consensus algorithm +======================= + +This document provides a description of Emmy*, the Tezos +:doc:`proof-of-stake` consensus algorithm, as implemented in the +protocol under development. + +History +------- + +Before Emmy*, there was Emmy+ +(introduced in this `blog post `_), +and before Emmy+, there was Emmy, a Nakamoto-style consensus first described in +2014, in the `Tezos whitepaper +`_: + + our proof-of-stake mechanism is a mix of several ideas, including + Slasher, chain-of-activity, and proof-of-burn. + +The specificity of Emmy with respect to other proof-of-stake consensus +algorithms, including some protocols introduced later such as `Ouroboros +`_ and `Snow White +`_, is the combined use of priorities and +endorsements in the so called minimal delay function. Thanks to these concepts, +Emmy offers a better protection against selfish baking and a shorter time to +finality. The time to finality can be measured in terms of the number of +confirmations a user must have seen for a block to be considered as final. We +recall that, being a Nakamoto-style consensus, Emmy provides *probabilistic* +finality. + + +Emmy* +----- + +Emmy* improves Emmy+ in that it brings smaller block times and faster times to +finality. + + +.. _terminology_011: + +Terminology +~~~~~~~~~~~ + +A *block* in the blockchain consists of a header and a list of operations. The +header has a shell part (common to all protocols) and a +protocol-specific part. In Emmy*, :ref:`the protocol-specific part of the +header` contains, most notably, a timestamp, a +priority (a natural number), and the endorsements for the block at the previous +level. *Endorsements* are operations that can be seen as votes for a given +block. Each block is signed. + +Before being endorsed, blocks are baked. *Baking* is the action of producing and +signing a block. Corresponding to these two actions of baking and endorsing, at +each level, two lists of slots are being created: a (conceptually) infinite list +of baking slots and a list of ``ENDORSERS_PER_BLOCK`` endorsing slots (the value of ``ENDORSERS_PER_BLOCK`` is one of the :ref:`parameters of the consensus protocol `). The index +of a baking slot is called a *priority*. Each slot is associated to a +participant. A participant can appear several times in both lists. The selection +of participants is at :ref:`random`, independently for +each slot, and is stake based. + +An endorsement for a block at level :math:`\ell` is *valid* if it is signed by +a participant that has an endorsing slot at level :math:`\ell`. The *endorsing +power* of an endorsement is the number of slots the endorser owns at level :math:`\ell`. The endorsing +power of a block is the sum of the endorsing powers of the endorsements it +contains. + + +Minimal block delay function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +At the heart of Emmy*, there is the minimal block delay function. This function +serves to compute the minimal time between blocks depending on the current +block's priority `p`, and its endorsing power `e`. Namely, Emmy* defines the +minimal block delay function as follows: + +.. _delaystar_011: + +.. math:: + delay^*(p, e) = \begin{cases} + md & \text{ if } p = 0 \wedge w \geq \frac{3}{5} te\\ + delay^+(p, e) & \text{ otherwise} + \end{cases} + +where + +- :math:`md` stands for the minimal block delay, +- :math:`te` stands for the "total endorsing power", and +- :math:`delay^+(p, e)` is the minimal block delay function in Emmy+, namely: + +.. math:: + delay^+(p, e) = bd + dp \cdot p + de \cdot max(0, ie - e) + +where + +- :math:`bd` stands for the minimal time between the blocks, +- :math:`dp` stands for "delay per priority", +- :math:`de` stands for "delay per (missed) endorsement", and +- :math:`ie` stands for the "initial endorsing power". + +The delay function serves to determine if a produced block can +be considered as valid. + +Block validity condition +~~~~~~~~~~~~~~~~~~~~~~~~ + +A block with timestamp :math:`t'`, priority :math:`p`, and +endorsing power :math:`e` is *valid* at level :math:`\ell` if: + +- the endorsements in the block are valid for level :math:`\ell-1`, +- it is signed by the baker that has baking slot :math:`p`, and +- :math:`t' \geq t + delay^+(p,e)`, where :math:`t` is the timestamp of the + previous block. + +We note that, by the definition of the delay function, the higher the priority +and the smaller the endorsing power, the longer it takes before the block is +considered as valid. However, if the block has priority 0 and contains endorsements with endorsing +power at least :math:`ie`, then there is no time penalty. + +Emmy* abstractly +~~~~~~~~~~~~~~~~ + +We refer to someone trying to reach consensus by the generic notion of +participant. Emmy* can be described in an abstract manner as +follows: + +- A participant continuously observes blocks and endorsements. +- A participant always adopts the :ref:`fittest`, that + is, the longest (valid) chain it observes. +- A participant that has at least an endorsement slot at level :math:`\ell`, + emits an endorsement for the first block it observes at level + :math:`\ell`. +- A participant produces a block as soon as it is allowed to, that is, as soon + as it can produce a valid block (see the validity condition above). + +Emmy* concretely +~~~~~~~~~~~~~~~~ + +In Tezos, a participant is a :ref:`delegate` that has at least one +:ref:`roll`, and is :ref:`active`. For simplicity we +just refer to participants as delegates (and omit the "active" and "with rolls" +attributes). A delegate plays two roles: + +- that of a **baker**, that is, it creates blocks, or +- that of an **endorser**, that is, it contributes in agreeing on + a block by **endorsing** that block. + + +.. _emmyp_slot_selection_011: + +To these roles correspond the two types of actions mentioned above, baking and +endorsing. As mentioned above, the baking and endorsing rights of a delegate are +given by its baking, respectively endorsing slots, whose selection is described +:ref:`here`. The mechanism behind baking slots is meant to ensure that +if the delegate whose turn is to bake is for some reason unable to bake, the +next delegate in the list can step up and bake the block. + +.. _emmyp_fitness_and_header_011: + +There are two more notions which are defined abstractly at the level of the +shell and concretized in Emmy*, the :ref:`fitness`, and the +protocol-specific header: + +- the fitness of a block is 1 plus the fitness of the previous block; +- the protocol-specific header of a block has the following fields: + + - ``signature``: a digital signature of the shell and protocol + headers (excluding the signature itself). + - ``priority``: the position in the priority list of delegates + at which the block was baked. + - ``seed_nonce_hash``: a commitment to :ref:`a random number`, used to + generate entropy on the chain. Present in only one out of + ``BLOCKS_PER_COMMITMENT`` (see :ref:`Constants`). + - ``proof_of_work_nonce``: a nonce used to pass a low-difficulty + proof-of-work for the block, as a spam prevention measure. + + +The consensus algorithm is implemented in Tezos in five components: the shell, +the economic protocol, and the three daemons: the baker, the endorser, and the +accuser. + +There are mainly two rules that the shell uses when receiving a new valid block: + +- The shell changes the head of the chain to this new block only if it has a + higher fitness than the current head. +- The shell does not accept a branch whose fork point is in a cycle more than + ``PRESERVED_CYCLES`` in the past. More precisely, if ``n`` is the current + cycle, the last allowed fork point is the first level of cycle + ``n-PRESERVED_CYCLES``. + +The parameter ``PRESERVED_CYCLES`` therefore plays a central role in Tezos: any +block before the last allowed fork level is immutable. + +Finally, the economic protocol provides the rules for when block and +endorsements are valid, as explained above, and defines the economic incentives +of delegates. Finally, the three daemons are responsible for injecting blocks, +endorsements, and respectively accusations (see below) on behalf of delegates. + + +Economic Incentives +~~~~~~~~~~~~~~~~~~~ + +In Emmy*, participation in consensus is rewarded and bad behavior is punished. + +Rewards +^^^^^^^ + +To incentivize participation in the consensus algorithm, delegates are rewarded +for baking and endorsing. The reward for baking a block with priority :math:`p` +and endorsing power :math:`e` is given by the formula +:math:`baking\_reward(p,e)`. The rewards for endorsing a block with priority +:math:`p` and having the corresponding endorsement included in the block is +given by the formula :math:`endorsing\_reward(p,e)`, where :math:`e` is the +endorsement's endorsing power. These reward formulas are as follows: + +.. math:: + baking\_reward(p,e) = \begin{cases} + \frac{e}{te}\cdot \frac{level\_rewards\_prio\_zero}{2} & \mbox{ if } p = 0\\ + \frac{e}{te} \cdot level\_rewards\_prio\_nonzero & \mbox{ otherwise } + \end{cases} + +.. math:: + endorsing\_reward(p,e) = \begin{cases} + baking\_reward(0, e) & \mbox{ if } p = 0\\ + \frac{2}{3} \cdot baking\_reward(0, e) & \mbox{ otherwise } + \end{cases} + +where + +- :math:`level\_rewards\_prio\_zero` and :math:`level\_rewards\_prio\_nonzero` are constants. + +The motivation behind this choice of design is given in the `Carthage blog post +`_. + +Besides the reward for baking, the baker receives all the fees paid for the +transactions included in the baked block. + +Rewards and fees are not distributed immediately, instead they are frozen for a +period of ``PRESERVED_CYCLES``. + +Slashing +^^^^^^^^ + +If a delegate deviates from the consensus rules by baking or endorsing two +different blocks at the same level, we say that a delegate double signs. As a +counter-measure against double signing a *security deposit* is frozen from the +delegate's account. Precisely, each delegate key has an associated security +deposit account. When a delegate bakes or endorses a block the security deposit +is automatically moved to the deposit account where it is frozen for +``PRESERVED_CYCLES`` cycles, after which it is automatically moved back to the +baker's main account. + +The values of the security deposits are ``BLOCK_SECURITY_DEPOSIT`` per block +created and ``ENDORSEMENT_SECURITY_DEPOSIT`` per endorsement slot. + +The evidence for double signing at a given level can be collected by any +:ref:`accuser` and included as an *accusation* operation in a block +for a period of ``PRESERVED_CYCLES``. The inclusion of the accusation leads to +forfeiting the entirety of the security deposits and fees obtained during the +cycle when the double signing was made. Half of this amount is burned, and half +goes to the baker who included the accusation. + +In the current protocol, accusations for the *same* incident can be made several +times after the fact. This means that the deposits and fees for the entire +cycle are forfeited, including any deposit made, or fees earned, after the +incident. Pragmatically, any baker who either double bakes or endorses in a +given cycle should immediately stop both baking and endorsing for the rest of +that cycle. + +.. _cs_constants_011: + +Consensus protocol parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In this section we map the above notation to their corresponding parameter +values. +Note that these parameters are part of the larger set of :ref:`protocol constants `. + +.. list-table:: Mapping + :widths: 55 50 25 + :header-rows: 1 + + * - Notation + - Parameter name + - Parameter value + * - :math:`md` + - ``MINIMAL_BLOCK_DELAY`` + - 30 seconds + * - :math:`bd` + - ``TIME_BETWEEN_BLOCKS[0]`` + - 60 seconds + * - :math:`dp` + - ``TIME_BETWEEN_BLOCKS[1]`` + - 40 seconds + * - :math:`de` + - ``DELAY_PER_MISSING_ENDORSEMENT`` + - 4 seconds + * - :math:`ie` + - ``INITIAL_ENDORSERS`` + - 192 + * - :math:`te` + - ``ENDORSERS_PER_BLOCK`` + - 256 + * - :math:`\frac{level\_rewards\_prio\_zero}{te \cdot 2}` + - ``BAKING_REWARD_PER_ENDORSEMENT[0]`` + - 0.078125 ꜩ + * - :math:`\frac{level\_rewards\_prio\_nonzero}{te}` + - ``BAKING_REWARD_PER_ENDORSEMENT[1]`` + - 0.011719 ꜩ + * - :math:`endorsing\_reward(0,1)` + - ``ENDORSEMENT_REWARD[0]`` + - 0.078125 ꜩ + * - :math:`endorsing\_reward(p,1)` for :math:`p \geq 1` + - ``ENDORSEMENT_REWARD[1]`` + - 0.052083 ꜩ + * - + - ``BLOCK_SECURITY_DEPOSIT`` + - 640 ꜩ + * - + - ``ENDORSEMENT_SECURITY_DEPOSIT`` + - 2.5 ꜩ + +Since blocks are at least ``TIME_BETWEEN_BLOCKS[0]``, that is 30 seconds apart, +and since a cycle has ``BLOCKS_PER_CYCLE``, that is :ref:`8192 +blocks`, a cycle lasts *at least* 2 days, 20 hours, and 16 +minutes, and ``PRESERVED_CYCLES`` cycles, that is 5 cycles, last *at least* 14 +days, 5 hours, and 20 minutes. + +Given that ``MINIMAL_BLOCK_DELAY`` is 30 seconds, :ref:`the minimal block delay +function` says that: + +- if the block is baked at priority 0 and it contains at least 60% of the + endorsements (namely, at least 153 endorsements) then the minimal delay is 30 + seconds; +- otherwise, the higher the priority and the fewer endorsements a block carries + with respect to the 192 endorsements threshold, the longer it takes before it + can be considered valid, where the delay of 60 seconds is incremented by 40 + seconds with each missed priority and with 4 seconds with each missed + endorsement. + + +The value for ``BAKING_REWARD_PER_ENDORSEMENT[0]`` is chosen such that the +inflation from block rewards and endorsement rewards, which is given by +``ENDORSERS_PER_BLOCK`` \* (``ENDORSEMENT_REWARD[0]`` + +``BAKING_REWARD_PER_ENDORSEMENT[0]``) is 80 ꜩ which in turn preserves the 5.51% +annual inflation. + +Since deposits are locked for a period of ``PRESERVED_CYCLES``, one can compute +that at any given time, about ((``BLOCK_SECURITY_DEPOSIT`` + +``ENDORSEMENT_SECURITY_DEPOSIT`` \* ``ENDORSERS_PER_BLOCK``) \* +(``PRESERVED_CYCLES`` + 1) \* ``BLOCKS_PER_CYCLE``) tokens of all staked tokens +should be held as security deposits. For instance, if the amount of staked +tokens is 720,000,000 ꜩ, then roughly 8.74% of this amount is stored in security +deposits. This percentage also gives an indication of the minimal amount of +tokens a delegate should own in order to not miss out on creating a block or an +endorsement. Please refer to :ref:`this section ` +of the documentation for a discussion on (over-)delegation. + + +Further External Resources +-------------------------- + +- Emmy* `TZIP `_ +- Emmy* `analysis `_. diff --git a/docs/011/glossary.rst b/docs/011/glossary.rst new file mode 100644 index 000000000000..edf929d04675 --- /dev/null +++ b/docs/011/glossary.rst @@ -0,0 +1,178 @@ +Glossary +======== + +This glossary is divided in two sections, the first one concerns Tezos, and +the second one concerns the `economic protocol`_. The definitions in the latter +section may be different for other protocol versions. + +Tezos +----- + +.. include:: ../shell/glossary.rst.h + +Protocol +-------- + +_`Accuser` + When a node_ attempts to inject several incompatible blocks (or when it tries + to abuse the network in another similar way), another node_ can make an + accusation: show evidence of attempted abuse. The node_ making the accusation + is the accuser. + + The accuser is awarded some funds from the baking_ deposit of the accused. + + Using the tools provided by Nomadic Labs, accusation is handled by a + separate binary. + +_`Account` + An account is a unique identifier within the protocol. There are different + kinds of accounts (see `Originated account`_ and `Implicit account`_). + + In the Context_, each account is associated with a balance (an amount of + tez available). + +_`Baker` + When a node_ creates a new block_, it is the baker of this block_. + Baking_ rights are distributed to different accounts based on their + available balance. Only a node_ that handles an account_ with baking_ rights + is allowed to bake; blocks created by another node_ are invalid. + The baker selects transactions from the mempool_ to be included in the block_ it bakes. + + Using the tools provided by Nomadic Labs, baking_ is handled by a + separate binary. + +_`Baking`/_`Endorsing rights` + A delegate_ is allowed to bake/endorse a block_ if he holds the + baking/endorsing right for that block_. At the start of a Cycle_, + baking and endorsing rights are computed for all the block_ heights in the + cycle_, based on the proportion of Rolls owned by each accounts. + + For each block_ height, there are several accounts that are allowed to bake. + These different accounts are given different Priorities. + + For each block_ height, there are several accounts that are allowed to + endorse. There can be multiple endorsements per block_. + +_`Burn` + To ensure responsible use of the storage space on the public blockchain, + there are some costs charged to users for consuming storage. These + costs are burnt (i.e., the amount of tez is destroyed). For example, + a per-byte storage cost is burnt for increasing the storage space of a + smart contract; a fixed amount is burnt for allocating a new contract + (which consumes space by storing its address on the blockchain). + + See also `Fee`_. + +_`Constants` + Protocols are parameterized by several parameters called protocol constants, which may vary from one protocol to another or from one network to another. + +_`Contract` + See account_. + +_`Cycle` + A cycle is a set of consecutive blocks. E.g., cycle 12 started at block_ + height 49152 and ended at block_ height 53248. + + Cycles are used as a unit of “time” in the block_ chain. For example, the + different phases in the amendment voting procedures are defined based on + cycles. + +_`Delegate` + An `Implicit account`_ to which an account_ has delegated their baking_ and + `endorsing rights`_. The baking_ rights and `endorsing rights`_ are + calculated based on the total balance of tez that an account_ has been + delegated to. + +_`Delegation` + An operation_ in which an account_ balance is lent to a + delegate_. This increases the delegate_'s rolls and consequently + its Baking_ rights. The delegate_ does not control the funds from + the account_. + +_`Double baking` + When a baker_ signs two different blocks at the same height, it is called + double baking. Double baking is detrimental to the network and might be + indicative of an attempt to double spend. As such, it is punished by the + network: an accuser_ can provide proof of the double baking to be awarded + part of the baker_'s deposit. + +_`Endorser` + When a block_ is created and propagated on the network, nodes that have + `endorsing rights`_ for the matching block_ height can emit an endorsement + operation_. The accounts that emit the block_ are the endorsers of the block_. + Endorsement operations_ are included in the next block_. + + Using the tools provided by Nomadic Labs, endorsement is handled by a + separate binary. + +_`Fee` + To ensure responsible use of computation resources of other nodes, and also to encourage active participation in the consensus protocol, there are some + fees that users pay to bakers for including their operations in blocks. + For example, fees are paid to a baker for operations such as a transaction_ or a revelation of a public key. + + See also `Burn`_. + +_`Gas` + A measure of the number of elementary operations_ performed during + the execution of a `smart contract`_. Gas is used to measure how + much computing power is used to execute a `smart contract`_. + +_`Implicit account` + An account_ that is linked to a public key. Contrary to a `smart + contract`_, an `Implicit account`_ cannot include a script and it + cannot reject incoming transactions. + + If registered, an `Implicit account`_ can act as a delegate_. + + The address of an `Implicit account`_ always starts with the + letters `tz` followed by `1`, `2` or `3` (depending on the + signature scheme) and finally the hash of the public key. + +.. _glossary_michelson_011: + +Michelson + The built-in language used by a `smart contract`_. + +_`Operations` + The main operations in the protocol are transactions (to transfer funds + or to execute smart contracts), accusations, activations, delegations, + endorsements and originations. + +_`Originated account` + See `smart contract`_. + +_`Origination` + An operation_ to create a `smart contract`_. + +_`Priority` + A rank of different baking_ rights. Each rank corresponds to a time span. A + baker_ with baking_ rights at a given priority is only allowed to bake during + the priority's corresponding time span. Baking_ outside of one's designated + priority, results in an invalid block_. + +_`Roll` + An amount of tez (e.g., 8000ꜩ) serving as a unit to determine delegates' + baking_ rights in a cycle_. A delegate_ with twice as many rolls as another + will be given twice as many rights to bake. + +_`Smart contract` + Account_ which is associated to a :ref:`Michelson ` script. They are + created with an explicit origination_ operation and are therefore + sometimes called originated accounts. The address of a smart + contract always starts with the letters ``KT1``. + +_`Transaction` + An operation_ to transfer tez between two accounts, or to run the code of a + `smart contract`_. + +_`Voting period` + Any of the ``proposal``, ``exploration``, ``cooldown``, + ``promotion`` or ``adoption`` stages in the voting procedure when + ammending the `economic protocol`_. + +_`Voting listings` + The list calculated at the beginning of each `voting period`_ that contains + the staking balance (in number of rolls) of each delegate_ that owns more + than one roll_ at that moment. For each delegate_, The voting listings + reflects the weight of the vote emitted by the delegate_ when ammending the + `economic protocol`_. diff --git a/docs/011/liquidity_baking.rst b/docs/011/liquidity_baking.rst new file mode 100644 index 000000000000..2e07ad736031 --- /dev/null +++ b/docs/011/liquidity_baking.rst @@ -0,0 +1,49 @@ +Liquidity Baking +================ + +Liquidity baking incentivizes large amounts of decentralized liquidity provision between tez and tzBTC by minting a small amount of tez every block and depositing it inside of a constant product market making smart-contract. It includes an escape hatch mechanism as a contingency. + +Contracts +~~~~~~~~~ + +During activation of Granada protocol, a constant product market making (CPMM) Michelson contract has been deployed on the chain with address ``KT1TxqZ8QtKvLu3V3JH7Gx58n7Co8pgtpQU5`` as well as an associated liquidity token contract (LQT) with address ``KT1AafHA1C1vk959wvHWBispY9Y2f3fxBUUo``. + +.. warning:: + + while the CPMM and LQT contract originations provide an ``Origination_result``, the LQT contract contains two big maps not included in a `lazy_storage_diff` field. Indexers and other tooling may need manual updates to include these. + +The CPMM maintains a balance of ``a`` tez and ``b`` `tzBTC `_, where tzBTC is the `FA1.2 token `_ found at address ``KT1PWx2mnDueood7fEmfbBDKx1D9BAnnXitn``. The smart contract accepts deposits of ``da`` tez and returns ``db`` tzBTC (or vice versa) where the invariant ``(a + da * (1 - f - n)) * (b - db) = a b`` is preserved, and ``f`` and ``n`` are a fee and burn, set at 0.1% each. Calculations are done with precision of 1000, rounding down on division. + +To implement this contract, we use a fork of the open source code base used by `version two `_ of the "Dexter" project. The implementation of this contract has been `formally verified `_ against its functional specification. The contract code is modified in the following way: + +1. The fee is set to 0.1% only (the fee in Dexter v2 is set to 0.3%). Rationale: given the subsidy it is not necessary to charge a large fee and better to improve liquidity. +2. An additional 0.1% of every trade is burned by being transferred to the null implicit account. Rationale: this mechanism offsets inflation from the subsidy. The inflation is exactly balanced at a daily trade volume of 7.2 million tez. +3. The ability to set a delegate has been removed. Rationale: the subsidy means there is no need for a baker for that contract and having one would create an imbalance. +4. The ability to set a manager has been removed. Rationale: the only privilege of the Dexter manager is to set Dexter's delegate so this role is now unnecessary. + +The LIGO and Michelson code for these contracts, as well as detailed documentation, can be found on `the liquidity baking branch of the Dexter 2 repository `_. + +Subsidy +~~~~~~~ + +At every block in the chain, a small amount of tez is minted and credited to the CPMM contract, and the CPMM's ``%default`` entrypoint is called to update the ``xtz_pool`` balance in its storage. The amount that is minted and sent to the CPMM contract is 1/16th of the rewards for a block of priority 0 with all endorsements; currently these rewards are 40 tez per block so the amount that is sent to the CPMM contract is 2.5 tez per block. + +So the credits to the CPMM contract can be accounted for by indexers, they are included in block metadata as a balance update with a new constructor for ``update_origin``, ``Subsidy``. + +As a safety precaution, the subsidy expires automatically at a given +level called the liquidity baking sunset level. The sunset level can +be renewed periodically by protocol amendment. + +Escape hatch +~~~~~~~~~~~~ + +In addition to the sunset mechanism, an escape hatch is included. At every block, the baker producing the block can choose to include a flag that requests ending the subsidy. The context maintains an exponential moving average of that flag calculated as such with integer arithmetic: + +``e[0] = 0`` +``e[n+1] = (1999 * e[n] // 2000) + (1000 if flag[n] else 0)`` + +If at any block ``e[n] >= 1000000`` then it means that an exponential moving average with a window size on the order of two thousand blocks has had roughly a majority of blocks demanding the end of the subsidy. If that is the case, the subsidy is permanently halted (though it can be reactivated by a protocol upgrade). + +For indicative purposes, if a fraction ``f`` of blocks start signalling the flag, the threshold is reached after roughly ``2*(log(1-1/(2f)) / log(0.999))`` blocks, about 1387 blocks if everyone signals, 1964 blocks if 80% do, 3590 blocks if 60% do, etc. Recall for comparison that assuming two blocks per minute there are 2880 blocks per day. + +The escape hatch can be invoked through a JSON file containing a vote that is repeatedly submitted on each baked block, e.g. ``tezos-baker run with local node ~/.tezos-node alice --votefile "per_block_votes.json"`` where ``per_block_votes.json`` contains just ``{"liquidity_baking_escape_vote": true}``. See also the :ref:`baker man page`. diff --git a/docs/011/michelson.rst b/docs/011/michelson.rst new file mode 100644 index 000000000000..f3a4c19b5c9c --- /dev/null +++ b/docs/011/michelson.rst @@ -0,0 +1,3806 @@ +Michelson: the language of Smart Contracts in Tezos +=================================================== + +This specification gives a detailed formal semantics of the Michelson +language and a short explanation of how smart contracts are executed +and interact in the blockchain. + +The language is stack-based, with high level data types and primitives, +and strict static type checking. Its design cherry picks traits from +several language families. Vigilant readers will notice direct +references to Forth, Scheme, ML and Cat. + +A Michelson program is a series of instructions that are run in +sequence: each instruction receives as input the stack resulting from the +previous instruction, and rewrites it for the next one. The stack +contains both immediate values and heap allocated structures. All values +are immutable and garbage collected. + +The types of the input and output stack are fixed and monomorphic, +and the program is typechecked before being introduced into the system. +No smart contract execution can fail because an instruction has been +executed on a stack of unexpected length or contents. + +This specification gives the complete instruction set, type system and +semantics of the language. It is meant as a precise reference manual, +not an easy introduction. Even though, some examples are provided at +the end of the document and can be read first or at the same time as +the specification. The document also starts with a less formal +explanation of the context: how Michelson code interacts with the +blockchain. + +Semantics of smart contracts and transactions +--------------------------------------------- + +The Tezos ledger currently has two types of accounts that can hold +tokens (and be the destinations of transactions). + + - An implicit account is a non programmable account, whose tokens + are spendable and delegatable by a public key. Its address is + directly the public key hash, and starts with ``tz1``, ``tz2`` or + ``tz3``. + - A smart contract is a programmable account. A transaction to such + an address can provide data, and can fail for reasons decided by + its Michelson code. Its address is a unique hash that depends on + the operation that led to its creation, and starts with ``KT1``. + +From Michelson, they are indistinguishable. A safe way to think about +this is to consider that implicit accounts are smart contracts that +always succeed to receive tokens, and does nothing else. + +Intra-transaction semantics +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Alongside their tokens, smart contracts keep a piece of storage. Both +are ruled by a specific logic specified by a Michelson program. A +transaction to a smart contract will provide an input value and in +option some tokens, and in return, the smart contract can modify its +storage and transfer its tokens. + +The Michelson program receives as input a stack containing a single +pair whose first element is an input value and second element the +content of the storage space. It must return a stack containing a +single pair whose first element is the list of internal operations +that it wants to emit, and second element is the new contents of the +storage space. Alternatively, a Michelson program can fail, explicitly +using a specific opcode, or because something went wrong that could +not be caught by the type system (e.g. gas exhaustion). + +A bit of polymorphism can be used at contract level, with a +lightweight system of named entrypoints: instead of an input value, +the contract can be called with an entrypoint name and an argument, +and these two components are transformed automatically in a simple and +deterministic way to an input value. This feature is available both +for users and from Michelson code. See the dedicated section. + +Inter-transaction semantics +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An operation included in the blockchain is a sequence of "external +operations" signed as a whole by a source address. These operations +are of three kinds: + + - Transactions to transfer tokens to implicit accounts or tokens and + parameters to a smart contract (or, optionally, to a specified + entrypoint of a smart contract). + - Originations to create new smart contracts from its Michelson + source code, an initial amount of tokens transferred from the + source, and an initial storage contents. + - Delegations to assign the tokens of the source to the stake of + another implicit account (without transferring any tokens). + +Smart contracts can also emit "internal operations". These are run +in sequence after the external transaction completes, as in the +following schema for a sequence of two external operations. + +:: + + +------+----------------+-------+----------------+ + | op 1 | internal ops 1 | op 2 | internal ops 2 | + +------+----------------+-------+----------------+ + +Smart contracts called by internal transactions can in turn also emit +internal operation. The interpretation of the internal operations +of a given external operation uses a stack, as in the following +example, also with two external operations. + +:: + + +-----------+---------------+--------------------------+ + | executing | emissions | resulting stack | + +-----------+---------------+--------------------------+ + | op 1 | 1a, 1b, 1c | 1a, 1b, 1c | + | op 1a | 1ai, 1aj | 1ai, 1aj, 1b, 1c | + | op 1ai | | 1aj, 1b, 1c | + | op 1aj | | 1b, 1c | + | op 1b | 1bi | 1bi, 1c | + | op 1bi | | 1c | + | op 1c | | | + | op 2 | 2a, 2b | 2a, 2b | + | op 2a | 2ai | 2ai, 2b | + | op 2ai | 2ai1 | 2ai1, 2b | + | op 2ai1 | | 2b | + | op 2b | 2bi | 2bi | + | op 2bi | 2bi1 | 2bi1 | + | op 2bi1 | 2bi2 | 2bi2 | + | op 2bi2 | | | + +-----------+---------------+--------------------------+ + +Failures +~~~~~~~~ + +All transactions can fail for a few reasons, mostly: + + - Not enough tokens in the source to spend the specified amount. + - The script took too many execution steps. + - The script failed programmatically using the ``FAILWITH`` instruction. + +External transactions can also fail for these additional reasons: + + - The signature of the external operations was wrong. + - The code or initial storage in an origination did not typecheck. + - The parameter in a transfer did not typecheck. + - The destination did not exist. + - The specified entrypoint did not exist. + +All these errors cannot happen in internal transactions, as the type +system catches them at operation creation time. In particular, +Michelson has two types to talk about other accounts: ``address`` and +``contract t``. The ``address`` type merely gives the guarantee that +the value has the form of a Tezos address. The ``contract t`` type, on +the other hand, guarantees that the value is indeed a valid, existing +account whose parameter type is ``t``. To make a transaction from +Michelson, a value of type ``contract t`` must be provided, and the +type system checks that the argument to the transaction is indeed of +type ``t``. Hence, all transactions made from Michelson are well +formed by construction. + +In any case, when a failure happens, either total success or total +failure is guaranteed. If a transaction (internal or external) fails, +then the whole sequence fails and all the effects up to the failure +are reverted. These transactions can still be included in blocks, and +the transaction fees are given to the implicit account who baked the +block. + +Language semantics +------------------ + +This specification explains in a symbolic way the computation performed by the +Michelson interpreter on a given program and initial stack to produce +the corresponding resulting stack. The Michelson interpreter is a pure +function: it only builds a result stack from the elements of an initial +one, without affecting its environment. This semantics is then naturally +given in what is called a big step form: a symbolic definition of a +recursive reference interpreter. This definition takes the form of a +list of rules that cover all the possible inputs of the interpreter +(program and stack), and describe the computation of the corresponding +resulting stacks. + +Rules form and selection +~~~~~~~~~~~~~~~~~~~~~~~~ + +The rules have the main following form. + +:: + + > (syntax pattern) / (initial stack pattern) => (result stack pattern) + iff (conditions) + where (recursions) + and (more recursions) + +The left hand side of the ``=>`` sign is used for selecting the rule. +Given a program and an initial stack, one (and only one) rule can be +selected using the following process. First, the toplevel structure of +the program must match the syntax pattern. This is quite simple since +there are only a few non-trivial patterns to deal with instruction +sequences, and the rest is made of trivial patterns that match one +specific instruction. Then, the initial stack must match the initial +stack pattern. Finally, some rules add extra conditions over the values +in the stack that follow the ``iff`` keyword. Sometimes, several rules +may apply in a given context. In this case, the one that appears first +in this specification is to be selected. If no rule applies, the result +is equivalent to the one for the explicit ``FAILWITH`` instruction. This +case does not happen on well-typed programs, as explained in the next +section. + +The right hand side describes the result of the interpreter if the rule +applies. It consists in a stack pattern, whose parts are either +constants, or elements of the context (program and initial stack) that +have been named on the left hand side of the ``=>`` sign. + +Recursive rules (big step form) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes, the result of interpreting a program is derived from the +result of interpreting another one (as in conditionals or function +calls). In these cases, the rule contains a clause of the following +form. + +:: + + where (intermediate program) / (intermediate stack) => (partial result) + +This means that this rule applies in case interpreting the intermediate +state on the left gives the pattern on the right. + +The left hand sign of the ``=>`` sign is constructed from elements of +the initial state or other partial results, and the right hand side +identify parts that can be used to build the result stack of the rule. + +If the partial result pattern does not actually match the result of the +interpretation, then the result of the whole rule is equivalent to the +one for the explicit ``FAILWITH`` instruction. Again, this case does not +happen on well-typed programs, as explained in the next section. + +Format of patterns +~~~~~~~~~~~~~~~~~~ + +Code patterns are of one of the following syntactical forms. + +- ``INSTR`` (an uppercase identifier) is a simple instruction (e.g. + ``DROP``). +- ``INSTR (arg) ...`` is a compound instruction, whose arguments can be + code, data or type patterns (e.g. ``PUSH nat 3``). +- ``{ (instr) ; ... }`` is a possibly empty sequence of instructions, + (e.g. ``IF { SWAP ; DROP } { DROP }``), nested sequences can drop the + braces. +- ``name`` is a pattern that matches any program and names a part of + the matched program that can be used to build the result. +- ``_`` is a pattern that matches any instruction. + +Stack patterns are of one of the following syntactical forms. + +- ``[FAILED]`` is the special failed state. +- ``[]`` is the empty stack. +- ``(top) : (rest)`` is a stack whose top element is matched by the + data pattern ``(top)`` on the left, and whose remaining elements are + matched by the stack pattern ``(rest)`` on the right (e.g. + ``x : y : rest``). +- ``name`` is a pattern that matches any stack and names it in order to + use it to build the result. +- ``_`` is a pattern that matches any stack. + +Data patterns are of one of the following syntactical forms. + +- integer/natural number literals, (e.g. ``3``). +- string literals, (e.g. ``"contents"``). +- raw byte sequence literals (e.g. ``0xABCDEF42``). +- ``Tag`` (capitalized) is a symbolic constant, (e.g. ``Unit``, + ``True``, ``False``). +- ``(Tag (arg) ...)`` tagged constructed data, (e.g. ``(Pair 3 4)``). +- a code pattern for first class code values. +- ``name`` to name a value in order to use it to build the result. +- ``_`` to match any value. + +The domain of instruction names, symbolic constants and data +constructors is fixed by this specification. Michelson does not let the +programmer introduce its own types. + +Be aware that the syntax used in the specification may differ from +the :ref:`concrete syntax `. In particular +some instructions are annotated with types that are not present in the +concrete language because they are synthesized by the typechecker. + +Shortcuts +~~~~~~~~~ + +Sometimes, it is easier to think (and shorter to write) in terms of +program rewriting than in terms of big step semantics. When it is the +case, and when both are equivalents, we write rules of the form: + +:: + + p / S => S'' + where p' / S' => S'' + +using the following shortcut: + +:: + + p / S => p' / S' + +The concrete language also has some syntax sugar to group some common +sequences of operations as one. This is described in this specification +using a simple regular expression style recursive instruction rewriting. + +.. _michelson_type_system_011: + +Introduction to the type system and notations +--------------------------------------------- + +This specification describes a type system for Michelson. To make things +clear, in particular to readers that are not accustomed to reading +formal programming language specifications, it does not give a +typechecking or inference algorithm. It only gives an intentional +definition of what we consider to be well-typed programs. For each +syntactical form, it describes the stacks that are considered well-typed +inputs, and the resulting outputs. + +The type system is sound, meaning that if a program can be given a type, +then if run on a well-typed input stack, the interpreter will never +apply an interpretation rule on a stack of unexpected length or +contents. Also, it will never reach a state where it cannot select an +appropriate rule to continue the execution. Well-typed programs do not +block, and do not go wrong. + +Type notations +~~~~~~~~~~~~~~ + +The specification introduces notations for the types of values, terms +and stacks. Apart from a subset of value types that appear in the form +of type annotations in some places throughout the language, it is +important to understand that this type language only exists in the +specification. + +A stack type can be written: + +- ``[]`` for the empty stack. +- ``(top) : (rest)`` for the stack whose first value has type ``(top)`` + and queue has stack type ``(rest)``. + +Instructions, programs and primitives of the language are also typed, +their types are written: + +:: + + (type of stack before) -> (type of stack after) + +The types of values in the stack are written: + +- ``identifier`` for a primitive data-type (e.g. ``bool``). +- ``identifier (arg)`` for a parametric data-type with one parameter + type ``(arg)`` (e.g. ``list nat``). +- ``identifier (arg) ...`` for a parametric data-type with several + parameters (e.g. ``map string int``). +- ``[ (type of stack before) -> (type of stack after) ]`` for a code + quotation, (e.g. ``[ int : int : [] -> int : [] ]``). +- ``lambda (arg) (ret)`` is a shortcut for + ``[ (arg) : [] -> (ret) : [] ]``. + +Meta type variables +~~~~~~~~~~~~~~~~~~~ + +The typing rules introduce meta type variables. To be clear, this has +nothing to do with polymorphism, which Michelson does not have. These +variables only live at the specification level, and are used to express +the consistency between the parts of the program. For instance, the +typing rule for the ``IF`` construct introduces meta variables to +express that both branches must have the same type. + +Here are the notations for meta type variables: + +- ``'a`` for a type variable. +- ``'A`` for a stack type variable. +- ``_`` for an anonymous type or stack type variable. + +Typing rules +~~~~~~~~~~~~ + +The system is syntax directed, meaning that it defines a single +typing rule for each syntax construct. A typing rule restricts the type +of input stacks that are authorized for this syntax construct, links the +output type to the input type, and links both of them to the +subexpressions when needed, using meta type variables. + +Typing rules are of the form: + +:: + + (syntax pattern) + :: (type of stack before) -> (type of stack after) [rule-name] + iff (premises) + +Where premises are typing requirements over subprograms or values in the +stack, both of the form ``(x) :: (type)``, meaning that value ``(x)`` +must have type ``(type)``. + +A program is shown well-typed if one can find an instance of a rule that +applies to the toplevel program expression, with all meta type variables +replaced by non variable type expressions, and of which all type +requirements in the premises can be proven well-typed in the same +manner. For the reader unfamiliar with formal type systems, this is +called building a typing derivation. + +Here is an example typing derivation on a small program that computes +``(x+5)*10`` for a given input ``x``, obtained by instantiating the +typing rules for instructions ``PUSH``, ``ADD`` and for the sequence, as +found in the next sections. When instantiating, we replace the ``iff`` +with ``by``. + +:: + + { PUSH nat 5 ; ADD ; PUSH nat 10 ; MUL } + :: [ nat : [] -> nat : [] ] + by { PUSH nat 5 ; ADD } + :: [ nat : [] -> nat : [] ] + by PUSH nat 5 + :: [ nat : [] -> nat : nat : [] ] + by 5 :: nat + and ADD + :: [ nat : nat : [] -> nat : [] ] + and { PUSH nat 10 ; MUL } + :: [ nat : [] -> nat : [] ] + by PUSH nat 10 + :: [ nat : [] -> nat : nat : [] ] + by 10 :: nat + and MUL + :: [ nat : nat : [] -> nat : [] ] + +Producing such a typing derivation can be done in a number of manners, +such as unification or abstract interpretation. In the implementation of +Michelson, this is done by performing a recursive symbolic evaluation of +the program on an abstract stack representing the input type provided by +the programmer, and checking that the resulting symbolic stack is +consistent with the expected result, also provided by the programmer. + +Side note +~~~~~~~~~ + +As with most type systems, it is incomplete. There are programs that +cannot be given a type in this type system, yet that would not go wrong +if executed. This is a necessary compromise to make the type system +usable. Also, it is important to remember that the implementation of +Michelson does not accept as many programs as the type system describes +as well-typed. This is because the implementation uses a simple single +pass typechecking algorithm, and does not handle any form of +polymorphism. + +Core data types and notations +----------------------------- + +- ``string``, ``nat``, ``int`` and ``bytes``: The core primitive + constant types. + +- ``bool``: The type for booleans whose values are ``True`` and + ``False``. + +- ``unit``: The type whose only value is ``Unit``, to use as a + placeholder when some result or parameter is not necessary. For + instance, when the only goal of a contract is to update its storage. + +- ``never``: The empty type. Since ``never`` has no inhabitant, no value of + this type is allowed to occur in a well-typed program. + +- ``list (t)``: A single, immutable, homogeneous linked list, whose + elements are of type ``(t)``, and that we write ``{}`` for the empty + list or ``{ first ; ... }``. In the semantics, we use chevrons to + denote a subsequence of elements. For instance: ``{ head ; }``. + +- ``pair (l) (r)``: A pair of values ``a`` and ``b`` of types ``(l)`` + and ``(r)``, that we write ``(Pair a b)``. + +- ``pair (t{1}) ... (t{n})`` with ``n > 2``: A shorthand for ``pair (t{1}) (pair (t{2}) ... (pair (t{n-1}) (t{n})) ...)``. + +- ``option (t)``: Optional value of type ``(t)`` that we write ``None`` + or ``(Some v)``. + +- ``or (l) (r)``: A union of two types: a value holding either a value + ``a`` of type ``(l)`` or a value ``b`` of type ``(r)``, that we write + ``(Left a)`` or ``(Right b)``. + +- ``set (t)``: Immutable sets of values of type ``(t)`` that we write as + lists ``{ item ; ... }``, of course with their elements unique, and + sorted. + +- ``map (k) (t)``: Immutable maps from keys of type ``(k)`` of values + of type ``(t)`` that we write ``{ Elt key value ; ... }``, with keys + sorted. + +- ``big_map (k) (t)``: Lazily deserialized maps from keys of type + ``(k)`` of values of type ``(t)``. + These maps should be used if you intend to store large amounts of data in a map. + Using ``big_map`` can reduce gas costs significantly compared to standard maps, as data is lazily deserialized. + Note however that individual operations on ``big_map`` have higher gas costs than those over standard maps. + A ``big_map`` also has a lower storage cost than a standard map of the same size, when large keys are used, since only the hash of each key is stored in a ``big_map``. + + A ``big_map`` cannot appear inside another ``big_map``. + See the section on :ref:`operations on big maps ` for a description of the syntax of values of type ``big_map (k) (t)`` and available operations. + +Core instructions +----------------- + +Control structures +~~~~~~~~~~~~~~~~~~ + +- ``FAILWITH``: Explicitly abort the current program. + +:: + + :: 'a : \_ -> \_ + +This special instruction aborts the current program exposing the top +element of the stack in its error message (first rule below). It makes +the output useless since all subsequent instructions will simply +ignore their usual semantics to propagate the failure up to the main +result (second rule below). Its type is thus completely generic. + +:: + + > FAILWITH / a : _ => [FAILED] + > _ / [FAILED] => [FAILED] + +- ``{}``: Empty sequence. + +:: + + :: 'A -> 'A + + > {} / SA => SA + +- ``{ I ; C }``: Sequence. + +:: + + :: 'A -> 'C + iff I :: [ 'A -> 'B ] + C :: [ 'B -> 'C ] + + > I ; C / SA => SC + where I / SA => SB + and C / SB => SC + +- ``IF bt bf``: Conditional branching. + +:: + + :: bool : 'A -> 'B + iff bt :: [ 'A -> 'B ] + bf :: [ 'A -> 'B ] + + > IF bt bf / True : S => bt / S + > IF bt bf / False : S => bf / S + +- ``LOOP body``: A generic loop. + +:: + + :: bool : 'A -> 'A + iff body :: [ 'A -> bool : 'A ] + + > LOOP body / True : S => body ; LOOP body / S + > LOOP body / False : S => S + +- ``LOOP_LEFT body``: A loop with an accumulator. + +:: + + :: (or 'a 'b) : 'A -> 'b : 'A + iff body :: [ 'a : 'A -> (or 'a 'b) : 'A ] + + > LOOP_LEFT body / (Left a) : S => body ; LOOP_LEFT body / a : S + > LOOP_LEFT body / (Right b) : S => b : S + +- ``DIP code``: Runs code protecting the top element of the stack. + +:: + + :: 'b : 'A -> 'b : 'C + iff code :: [ 'A -> 'C ] + + > DIP code / x : S => x : S' + where code / S => S' + +- ``DIP n code``: Runs code protecting the ``n`` topmost elements of + the stack. In particular, ``DIP 0 code`` is equivalent to ``code`` + and ``DIP 1 code`` is equivalent to ``DIP code``. + +:: + + :: 'a{1} : ... : 'a{n} : 'A -> 'a{1} : ... : 'a{n} : 'B + iff code :: [ 'A -> 'B ] + + > DIP n code / x{1} : ... : x{n} : S => x{1} : ... : x{n} : S' + where code / S => S' + +- ``EXEC``: Execute a function from the stack. + +:: + + :: 'a : lambda 'a 'b : 'C -> 'b : 'C + + > EXEC / a : f : S => r : S + where f / a : [] => r : [] + +- ``APPLY``: Partially apply a tuplified function from the stack. + Values that are not both pushable and storable + (values of type ``operation``, ``contract _`` and ``big map _ _``) + cannot be captured by ``APPLY`` (cannot appear in ``'a``). + +:: + + :: 'a : lambda (pair 'a 'b) 'c : 'C -> lambda 'b 'c : 'C + + > APPLY / a : f : S => { PUSH 'a a ; PAIR ; f } : S + +Stack operations +~~~~~~~~~~~~~~~~ + +- ``DROP``: Drop the top element of the stack. + +:: + + :: _ : 'A -> 'A + + > DROP / _ : S => S + +- ``DROP n``: Drop the `n` topmost elements of the stack. In + particular, ``DROP 0`` is a noop and ``DROP 1`` is equivalent to + ``DROP``. + +:: + + :: 'a{1} : ... : 'a{n} : 'A -> 'A + + > DROP n / x{1} : ... : x{n} : S => S + +- ``DUP``: Duplicate the top element of the stack. + +:: + + :: 'a : 'A -> 'a : 'a : 'A + + > DUP / x : S => x : x : S + +- ``DUP n``: Duplicate the N-th element of the stack. `DUP 1` is equivalent to `DUP`. `DUP 0` is rejected. + +:: + + DUP 1 :: 'a : 'A -> 'a : 'a : 'A + + DUP (n+1) :: 'a : 'A -> 'b : 'a : 'A + iff DUP n :: 'A -> 'b : 'A + + > DUP 1 / x : S => x : x : S + + > DUP (n+1) / x : S => y : x : S + iff DUP n / S => y : S + + +- ``SWAP``: Exchange the top two elements of the stack. + +:: + + :: 'a : 'b : 'A -> 'b : 'a : 'A + + > SWAP / x : y : S => y : x : S + +- ``DIG n``: Take the element at depth ``n`` of the stack and move it + on top. The element on top of the stack is at depth ``0`` so that + ``DIG 0`` is a no-op and ``DIG 1`` is equivalent to ``SWAP``. + +:: + + :: 'a{1} : ... : 'a{n} : 'b : 'A -> 'b : 'a{1} : ... : 'a{n} : 'A + + > DIG n / x{1} : ... : x{n} : y : S => y : x{1} : ... : x{n} : S + +- ``DUG n``: Place the element on top of the stack at depth ``n``. The + element on top of the stack is at depth ``0`` so that ``DUG 0`` is a + no-op and ``DUG 1`` is equivalent to ``SWAP``. + +:: + + :: 'b : 'a{1} : ... : 'a{n} : 'A -> 'a{1} : ... : 'a{n} : 'b : 'A + + > DUG n / y : x{1} : ... : x{n} : S => x{1} : ... : x{n} : y : S + +- ``PUSH 'a x``: Push a constant value of a given type onto the stack. + +:: + + :: 'A -> 'a : 'A + iff x :: 'a + + > PUSH 'a x / S => x : S + +- ``LAMBDA 'a 'b code``: Push a lambda with the given parameter type `'a` and return + type `'b` onto the stack. + +:: + + :: 'A -> (lambda 'a 'b) : 'A + + > LAMBDA _ _ code / S => code : S + +Generic comparison +~~~~~~~~~~~~~~~~~~ + +Comparison only works on a class of types that we call comparable. A +``COMPARE`` operation is defined in an ad hoc way for each comparable +type, but the result of compare is always an ``int``, which can in turn +be checked in a generic manner using the following combinators. The +result of ``COMPARE`` is ``0`` if the top two elements of the stack are +equal, negative if the first element in the stack is less than the +second, and positive otherwise. + +- ``EQ``: Checks that the top element of the stack is equal to zero. + +:: + + :: int : 'S -> bool : 'S + + > EQ / 0 : S => True : S + > EQ / v : S => False : S + iff v <> 0 + +- ``NEQ``: Checks that the top element of the stack is not equal to zero. + +:: + + :: int : 'S -> bool : 'S + + > NEQ / 0 : S => False : S + > NEQ / v : S => True : S + iff v <> 0 + +- ``LT``: Checks that the top element of the stack is less than zero. + +:: + + :: int : 'S -> bool : 'S + + > LT / v : S => True : S + iff v < 0 + > LT / v : S => False : S + iff v >= 0 + +- ``GT``: Checks that the top element of the stack is greater than zero. + +:: + + :: int : 'S -> bool : 'S + + > GT / v : S => C / True : S + iff v > 0 + > GT / v : S => C / False : S + iff v <= 0 + +- ``LE``: Checks that the top element of the stack is less than or equal to + zero. + +:: + + :: int : 'S -> bool : 'S + + > LE / v : S => True : S + iff v <= 0 + > LE / v : S => False : S + iff v > 0 + +- ``GE``: Checks that the top of the stack is greater than or equal to + zero. + +:: + + :: int : 'S -> bool : 'S + + > GE / v : S => True : S + iff v >= 0 + > GE / v : S => False : S + iff v < 0 + +Operations +---------- + +Operations on unit +~~~~~~~~~~~~~~~~~~ + +- ``UNIT``: Push a unit value onto the stack. + +:: + + :: 'A -> unit : 'A + + > UNIT / S => Unit : S + +- ``COMPARE``: Unit comparison + +:: + + :: unit : unit : 'S -> int : 'S + + > COMPARE / Unit : Unit : S => 0 : S + +Operations on type never +~~~~~~~~~~~~~~~~~~~~~~~~ + +The type ``never`` is the type of forbidden values. The most prominent +scenario in which ``never`` is used is when implementing a contract +template with no additional entrypoint. A contract template defines a set +of basic entrypoints, and its ``parameter`` declaration contains a type +variable for additional entrypoints in some branch of an union type, or +wrapped inside an option type. Letting this type variable be ``never`` in +a particular implementation indicates that the contract template has not +been extended, and turns the branch in the code that processes the +additional entrypoints into a forbidden branch. + +Values of type ``never`` cannot occur in a well-typed program. However, +they can be abstracted in the ``parameter`` declaration of a contract---or +by using the ``LAMBDA`` operation---thus indicating that the corresponding +branches in the code are forbidden. The type ``never`` also plays a role +when introducing values of union or option type with ``LEFT never``, +``RIGHT never``, or ``NONE never``. In such cases, the created values can +be inspected with the operations ``IF_LEFT``, ``IF_RIGHT``, or +``IF_NONE``, and the corresponding branches in the code are forbidden +branches. + +- ``NEVER``: Close a forbidden branch. + +:: + + :: never : 'A -> 'B + +- ``COMPARE``: Trivial comparison on type ``never`` + +:: + + :: never : never : 'S -> int : 'S + + +Operations on booleans +~~~~~~~~~~~~~~~~~~~~~~ + +- ``OR`` + +:: + + :: bool : bool : 'S -> bool : 'S + + > OR / x : y : S => (x | y) : S + +- ``AND`` + +:: + + :: bool : bool : 'S -> bool : 'S + + > AND / x : y : S => (x & y) : S + +- ``XOR`` + +:: + + :: bool : bool : 'S -> bool : 'S + + > XOR / x : y : S => (x ^ y) : S + +- ``NOT`` + +:: + + :: bool : 'S -> bool : 'S + + > NOT / x : S => ~x : S + +- ``COMPARE``: Boolean comparison + +:: + + :: bool : bool : 'S -> int : 'S + + > COMPARE / False : False : S => 0 : S + > COMPARE / False : True : S => -1 : S + > COMPARE / True : False : S => 1 : S + > COMPARE / True : True : S => 0 : S + +Operations on integers and natural numbers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Integers and naturals are arbitrary-precision, meaning that the only size +limit is gas. + +- ``NEG`` + +:: + + :: int : 'S -> int : 'S + :: nat : 'S -> int : 'S + + > NEG / x : S => -x : S + +- ``ABS`` + +:: + + :: int : 'S -> nat : 'S + + > ABS / x : S => abs (x) : S + +- ``ISNAT`` + +:: + + :: int : 'S -> option nat : 'S + + > ISNAT / x : S => Some (x) : S + iff x >= 0 + + > ISNAT / x : S => None : S + iff x < 0 + +- ``INT`` + +:: + + :: nat : 'S -> int : 'S + + > INT / x : S => x : S + +- ``ADD`` + +:: + + :: int : int : 'S -> int : 'S + :: int : nat : 'S -> int : 'S + :: nat : int : 'S -> int : 'S + :: nat : nat : 'S -> nat : 'S + + > ADD / x : y : S => (x + y) : S + +- ``SUB`` + +:: + + :: int : int : 'S -> int : 'S + :: int : nat : 'S -> int : 'S + :: nat : int : 'S -> int : 'S + :: nat : nat : 'S -> int : 'S + + > SUB / x : y : S => (x - y) : S + +- ``MUL`` + +:: + + :: int : int : 'S -> int : 'S + :: int : nat : 'S -> int : 'S + :: nat : int : 'S -> int : 'S + :: nat : nat : 'S -> nat : 'S + + > MUL / x : y : S => (x * y) : S + +- ``EDIV``: Perform Euclidean division + +:: + + :: int : int : 'S -> option (pair int nat) : 'S + :: int : nat : 'S -> option (pair int nat) : 'S + :: nat : int : 'S -> option (pair int nat) : 'S + :: nat : nat : 'S -> option (pair nat nat) : 'S + + > EDIV / x : 0 : S => None : S + > EDIV / x : y : S => Some (Pair (x / y) (x % y)) : S + iff y <> 0 + +Bitwise logical operators are also available on unsigned integers. + +- ``OR`` + +:: + + :: nat : nat : 'S -> nat : 'S + + > OR / x : y : S => (x | y) : S + +- ``AND``: (also available when the top operand is signed) + +:: + + :: nat : nat : 'S -> nat : 'S + :: int : nat : 'S -> nat : 'S + + > AND / x : y : S => (x & y) : S + +- ``XOR`` + +:: + + :: nat : nat : 'S -> nat : 'S + + > XOR / x : y : S => (x ^ y) : S + +- ``NOT``: Two's complement + +:: + + :: nat : 'S -> int : 'S + :: int : 'S -> int : 'S + + > NOT / x : S => ~x : S + + +The return type of ``NOT`` is an ``int`` and not a ``nat``. This is +because the sign is also negated. The resulting integer is computed +using two's complement. For instance, the boolean negation of ``0`` is +``-1``. To get a natural back, a possibility is to use ``AND`` with an +unsigned mask afterwards. + + +- ``LSL`` + +:: + + :: nat : nat : 'S -> nat : 'S + + > LSL / x : s : S => (x << s) : S + iff s <= 256 + > LSL / x : s : S => [FAILED] + iff s > 256 + +- ``LSR`` + +:: + + :: nat : nat : 'S -> nat : 'S + + > LSR / x : s : S => (x >> s) : S + iff s <= 256 + > LSR / x : s : S => [FAILED] + iff s > 256 + +- ``COMPARE``: Integer/natural comparison + +:: + + :: int : int : 'S -> int : 'S + :: nat : nat : 'S -> int : 'S + + > COMPARE / x : y : S => -1 : S + iff x < y + > COMPARE / x : y : S => 0 : S + iff x = y + > COMPARE / x : y : S => 1 : S + iff x > y + +Operations on strings +~~~~~~~~~~~~~~~~~~~~~ + +Strings are mostly used for naming things without having to rely on +external ID databases. They are restricted to the printable subset of +7-bit ASCII, plus some escaped characters (see section on +constants). So what can be done is basically use string constants as +is, concatenate or splice them, and use them as keys. + + +- ``CONCAT``: String concatenation. + +:: + + :: string : string : 'S -> string : 'S + + > CONCAT / s : t : S => (s ^ t) : S + + :: string list : 'S -> string : 'S + + > CONCAT / {} : S => "" : S + > CONCAT / { s ; } : S => (s ^ r) : S + where CONCAT / { } : S => r : S + +- ``SIZE``: number of characters in a string. + +:: + + :: string : 'S -> nat : 'S + +- ``SLICE``: String access. + +:: + + :: nat : nat : string : 'S -> option string : 'S + + > SLICE / offset : length : s : S => Some ss : S + where ss is the substring of s at the given offset and of the given length + iff offset and (offset + length) are in bounds + > SLICE / offset : length : s : S => None : S + iff offset or (offset + length) are out of bounds + +- ``COMPARE``: Lexicographic comparison. + +:: + + :: string : string : 'S -> int : 'S + + > COMPARE / s : t : S => -1 : S + iff s < t + > COMPARE / s : t : S => 0 : S + iff s = t + > COMPARE / s : t : S => 1 : S + iff s > t + +Operations on pairs and right combs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The type ``pair l r`` is the type of binary pairs composed of a left +element of type ``l`` and a right element of type ``r``. A value of +type ``pair l r`` is written ``Pair x y`` where ``x`` is a value of +type ``l`` and ``y`` is a value of type ``r``. + +To build tuples of length greater than 2, right combs have specific +optimized operations. For any ``n > 2``, the compact notations ``pair +t{0} t{1} ... t{n-2} t{n-1}`` is provided for the type of right combs +``pair t{0} (pair t{1} ... (pair t{n-2} t{n-1}) ...)``. Similarly, the +compact notation ``Pair x{0} x{1} ... x{n-2} x{n-1}`` is provided for +the right-comb value ``Pair x{0} (Pair x{1} ... (Pair x{n-2} x{n-1}) +...)``. Right-comb values can also be written using sequences; ``Pair +x{0} x{1} ... x{n-2} x{n-1}`` can be written ``{x{0}; x{1}; ...; x{n-2}; x{n-1}}``. + +- ``PAIR``: Build a binary pair from the stack's top two elements. + +:: + + :: 'a : 'b : 'S -> pair 'a 'b : 'S + + > PAIR / x : y : S => Pair x y : S + +- ``PAIR n``: Fold ``n`` values on the top of the stack in a right comb. + ``PAIR 0`` and ``PAIR 1`` are rejected. ``PAIR 2`` is equivalent to ``PAIR``. + +:: + + PAIR 2 :: 'a : 'b : 'S -> pair 'a 'b : 'S + PAIR (k+1) :: 'x : 'S -> pair 'x 'y : 'T + iff PAIR k :: 'S -> 'y : 'T + + Or equivalently, for n >= 2, + PAIR n :: 'a{0} : ... : 'a{n-1} : 'A -> pair 'a{0} ... 'a{n-1} : 'A + + > PAIR 2 / x : y : S => Pair x y : S + > PAIR (k+1) / x : S => Pair x y : T + iff PAIR k / S => y : T + + Or equivalently, for n >= 2, + > PAIR n / x{0} : ... : x{n-1} : S => Pair x{0} ... x{n-1} : S + +- ``UNPAIR``: Split a pair into its components. + +:: + + :: pair 'a 'b : 'S -> 'a : 'b : 'S + + > UNPAIR / Pair a b : S => a : b : S + + +- ``UNPAIR n``: Unfold ``n`` values from a right comb on the top of the stack. ``UNPAIR 0`` and ``UNPAIR 1`` are rejected. ``UNPAIR 2`` is equivalent to ``UNPAIR``. + +:: + + UNPAIR 2 :: pair 'a 'b : 'A -> 'a : 'b : 'A + UNPAIR (k+1) :: pair 'a 'b : 'A -> 'a : 'B + iff UNPAIR k :: 'b : 'A -> 'B + + Or equivalently, for n >= 2, + UNPAIR n :: pair 'a{0} ... 'a{n-1} : S -> 'a{0} : ... : 'a{n-1} : S + + > UNPAIR 2 / Pair x y : S => x : y : S + > UNPAIR (k+1) / Pair x y : SA => x : SB + iff UNPAIR k / y : SA => SB + + Or equivalently, for n >= 2, + > UNPAIR n / Pair x{0} ... x{n-1} : S => x{0} : ... : x{n-1} : S + +- ``CAR``: Access the left part of a pair. + +:: + + :: pair 'a _ : 'S -> 'a : 'S + + > CAR / Pair x _ : S => x : S + +- ``CDR``: Access the right part of a pair. + +:: + + :: pair _ 'b : 'S -> 'b : 'S + + > CDR / Pair _ y : S => y : S + +- ``GET k``: Access an element or a sub comb in a right comb. + + The nodes of a right comb of size ``n`` are canonically numbered as follows: + +:: + + 0 + / \ + 1 2 + / \ + 3 4 + / \ + 5 ... + 2n-2 + / \ + 2n-1 2n + + +Or in plain English: + + - The root is numbered with 0, + - The left child of the node numbered by ``k`` is numbered by ``k+1``, and + - The right child of the node numbered by ``k`` is numbered by ``k+2``. + +The ``GET k`` instruction accesses the node numbered by ``k``. In +particular, for a comb of size ``n``, the ``n-1`` first elements are +accessed by ``GET 1``, ``GET 3``, ..., and ``GET (2n-1)`` and the last +element is accessed by ``GET (2n)``. + +:: + + GET 0 :: 'a : 'S -> 'a : 'S + GET 1 :: pair 'x _ : 'S -> 'x : 'S + GET (k+2) :: pair _ 'y : 'S -> 'z : 'S + iff GET k :: 'y : 'S -> 'z : 'S + + Or equivalently, + GET 0 :: 'a : 'S -> 'a : 'S + GET (2k) :: pair 'a{0} ... 'a{k-1} 'a{k} : 'S -> 'a{k} : 'S + GET (2k+1) :: pair 'a{0} ... 'a{k} 'a{k+1} : 'S -> 'a{k} : 'S + + > GET 0 / x : S => x : S + > GET 1 / Pair x _ : S => x : S + > GET (k+2) / Pair _ y : S => GET k / y : S + + Or equivalently, + > GET 0 / x : S => x : S + > GET (2k) / Pair x{0} ... x{k-1} x{k} : 'S -> x{k} : 'S + > GET (2k+1) / Pair x{0} ... x{k} x{k+1} : 'S -> x{k} : 'S + + +- ``UPDATE k``: Update an element or a sub comb in a right comb. The topmost stack element is the new value to insert in the comb, the second stack element is the right comb to update. The meaning of ``k`` is the same as for the ``GET k`` instruction. + +:: + + UPDATE 0 :: 'a : 'b : 'S -> 'a : 'S + UPDATE 1 :: 'a2 : pair 'a1 'b : 'S -> pair 'a2 'b : 'S + UPDATE (k+2) :: 'c : pair 'a 'b1 : 'S -> pair 'a 'b2 : 'S + iff UPDATE k :: 'c : 'b1 : 'S -> 'b2 : 'S + + Or equivalently, + UPDATE 0 :: 'a : 'b : 'S -> 'a : 'S + UPDATE (2k) :: 'c : pair 'a{0} ... 'a{k-1} 'a{k} : 'S -> pair 'a{0} ... 'a{k-1} 'c : 'S + UPDATE (2k+1) :: 'c : pair 'a{0} ... 'a{k} 'a{k+1} : 'S -> pair 'a{0} ... 'a{k-1} 'c 'a{k+1} : 'S + + > UPDATE 0 / x : _ : S => x : S + > UPDATE 1 / x2 : Pair x1 y : S => Pair x2 y : S + > UPDATE (k+2) / z : Pair x y1 : S => Pair x y2 : S + iff UPDATE k / z : y1 : S => y2 : S + + Or equivalently, + > UPDATE 0 / x : _ : S => x : S + > UPDATE (2k) / z : Pair x{0} ... x{k-1} x{k} : 'S => Pair x{0} ... x{k-1} z : 'S + > UPDATE (2k+1) / z : Pair x{0} ... x{k-1} x{k} x{k+1} : 'S => Pair x{0} ... x{k-1} z x{k+1} : 'S + +- ``COMPARE``: Lexicographic comparison. + +:: + + :: pair 'a 'b : pair 'a 'b : 'S -> int : 'S + + > COMPARE / (Pair sa sb) : (Pair ta tb) : S => -1 : S + iff COMPARE / sa : ta : S => -1 : S + > COMPARE / (Pair sa sb) : (Pair ta tb) : S => 1 : S + iff COMPARE / sa : ta : S => 1 : S + > COMPARE / (Pair sa sb) : (Pair ta tb) : S => r : S + iff COMPARE / sa : ta : S => 0 : S + COMPARE / sb : tb : S => r : S + +Operations on sets +~~~~~~~~~~~~~~~~~~ + +- ``EMPTY_SET 'elt``: Build a new, empty set for elements of a given + type. + + The ``'elt`` type must be comparable (the ``COMPARE`` + primitive must be defined over it). + +:: + + :: 'S -> set 'elt : 'S + + > EMPTY_SET _ / S => {} : S + +- ``MEM``: Check for the presence of an element in a set. + +:: + + :: 'elt : set 'elt : 'S -> bool : 'S + + > MEM / x : {} : S => false : S + > MEM / x : { hd ; } : S => r : S + iff COMPARE / x : hd : [] => 1 : [] + where MEM / x : { } : S => r : S + > MEM / x : { hd ; } : S => true : S + iff COMPARE / x : hd : [] => 0 : [] + > MEM / x : { hd ; } : S => false : S + iff COMPARE / x : hd : [] => -1 : [] + +- ``UPDATE``: Inserts or removes an element in a set, replacing a + previous value. + +:: + + :: 'elt : bool : set 'elt : 'S -> set 'elt : 'S + + > UPDATE / x : false : {} : S => {} : S + > UPDATE / x : true : {} : S => { x } : S + > UPDATE / x : v : { hd ; } : S => { hd ; } : S + iff COMPARE / x : hd : [] => 1 : [] + where UPDATE / x : v : { } : S => { } : S + > UPDATE / x : false : { hd ; } : S => { } : S + iff COMPARE / x : hd : [] => 0 : [] + > UPDATE / x : true : { hd ; } : S => { hd ; } : S + iff COMPARE / x : hd : [] => 0 : [] + > UPDATE / x : false : { hd ; } : S => { hd ; } : S + iff COMPARE / x : hd : [] => -1 : [] + > UPDATE / x : true : { hd ; } : S => { x ; hd ; } : S + iff COMPARE / x : hd : [] => -1 : [] + +- ``ITER body``: Apply the body expression to each element of a set. + The body sequence has access to the stack. + +:: + + :: (set 'elt) : 'A -> 'A + iff body :: [ 'elt : 'A -> 'A ] + + > ITER body / {} : S => S + > ITER body / { hd ; } : S => ITER body / { } : S' + iff body / hd : S => S' + + +- ``SIZE``: Get the cardinality of the set. + +:: + + :: set 'elt : 'S -> nat : 'S + + > SIZE / {} : S => 0 : S + > SIZE / { _ ; } : S => 1 + s : S + where SIZE / { } : S => s : S + +Operations on maps +~~~~~~~~~~~~~~~~~~ + +- ``EMPTY_MAP 'key 'val``: Build a new, empty map from keys of a + given type to values of another given type. + + The ``'key`` type must be comparable (the ``COMPARE`` primitive must + be defined over it). + +:: + + :: 'S -> map 'key 'val : 'S + + > EMPTY_MAP _ _ / S => {} : S + + +- ``GET``: Access an element in a map, returns an optional value to be + checked with ``IF_SOME``. + +:: + + :: 'key : map 'key 'val : 'S -> option 'val : 'S + + > GET / x : {} : S => None : S + > GET / x : { Elt k v ; } : S => opt_y : S + iff COMPARE / x : k : [] => 1 : [] + where GET / x : { } : S => opt_y : S + > GET / x : { Elt k v ; } : S => Some v : S + iff COMPARE / x : k : [] => 0 : [] + > GET / x : { Elt k v ; } : S => None : S + iff COMPARE / x : k : [] => -1 : [] + +- ``MEM``: Check for the presence of a binding for a key in a map. + +:: + + :: 'key : map 'key 'val : 'S -> bool : 'S + + > MEM / x : {} : S => false : S + > MEM / x : { Elt k v ; } : S => r : S + iff COMPARE / x : k : [] => 1 : [] + where MEM / x : { } : S => r : S + > MEM / x : { Elt k v ; } : S => true : S + iff COMPARE / x : k : [] => 0 : [] + > MEM / x : { Elt k v ; } : S => false : S + iff COMPARE / x : k : [] => -1 : [] + +- ``UPDATE``: Assign or remove an element in a map. + +:: + + :: 'key : option 'val : map 'key 'val : 'S -> map 'key 'val : 'S + + > UPDATE / x : None : {} : S => {} : S + > UPDATE / x : Some y : {} : S => { Elt x y } : S + > UPDATE / x : opt_y : { Elt k v ; } : S => { Elt k v ; } : S + iff COMPARE / x : k : [] => 1 : [] + where UPDATE / x : opt_y : { } : S => { } : S + > UPDATE / x : None : { Elt k v ; } : S => { } : S + iff COMPARE / x : k : [] => 0 : [] + > UPDATE / x : Some y : { Elt k v ; } : S => { Elt k y ; } : S + iff COMPARE / x : k : [] => 0 : [] + > UPDATE / x : None : { Elt k v ; } : S => { Elt k v ; } : S + iff COMPARE / x : k : [] => -1 : [] + > UPDATE / x : Some y : { Elt k v ; } : S => { Elt x y ; Elt k v ; } : S + iff COMPARE / x : k : [] => -1 : [] + +- ``GET_AND_UPDATE``: A combination of the ``GET`` and ``UPDATE`` instructions. + +:: + + :: 'key : option 'val : map 'key 'val : 'S -> option 'val : map 'key 'val : 'S + +This instruction is similar to ``UPDATE`` but it also returns the +value that was previously stored in the ``map`` at the same key as +``GET`` would. + +:: + + > GET_AND_UPDATE / x : None : {} : S => None : {} : S + > GET_AND_UPDATE / x : Some y : {} : S => None : { Elt x y } : S + > GET_AND_UPDATE / x : opt_y : { Elt k v ; } : S => opt_y' : { Elt k v ; } : S + iff COMPARE / x : k : [] => 1 : [] + where GET_AND_UPDATE / x : opt_y : { } : S => opt_y' : { } : S + > GET_AND_UPDATE / x : None : { Elt k v ; } : S => Some v : { } : S + iff COMPARE / x : k : [] => 0 : [] + > GET_AND_UPDATE / x : Some y : { Elt k v ; } : S => Some v : { Elt k y ; } : S + iff COMPARE / x : k : [] => 0 : [] + > GET_AND_UPDATE / x : None : { Elt k v ; } : S => None : { Elt k v ; } : S + iff COMPARE / x : k : [] => -1 : [] + > GET_AND_UPDATE / x : Some y : { Elt k v ; } : S => None : { Elt x y ; Elt k v ; } : S + iff COMPARE / x : k : [] => -1 : [] + +- ``MAP body``: Apply the body expression to each element of a map. The + body sequence has access to the stack. + +:: + + :: (map 'key 'val) : 'A -> (map 'key 'b) : 'A + iff body :: [ (pair 'key 'val) : 'A -> 'b : 'A ] + + > MAP body / {} : S => {} : S + > MAP body / { Elt k v ; } : S => { Elt k v' ; } : S'' + where body / Pair k v : S => v' : S' + and MAP body / { } : S' => { } : S'' + +- ``ITER body``: Apply the body expression to each element of a map. + The body sequence has access to the stack. + +:: + + :: (map 'elt 'val) : 'A -> 'A + iff body :: [ (pair 'elt 'val : 'A) -> 'A ] + + > ITER body / {} : S => S + > ITER body / { Elt k v ; } : S => ITER body / { } : S' + iff body / (Pair k v) : S => S' + +- ``SIZE``: Get the cardinality of the map. + +:: + + :: map 'key 'val : 'S -> nat : 'S + + > SIZE / {} : S => 0 : S + > SIZE / { _ ; } : S => 1 + s : S + where SIZE / { } : S => s : S + + +Operations on ``big_maps`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. _OperationsOnBigMaps_011: + +Big maps have three possible representations. A map literal is always +a valid representation for a big map. Big maps can also be represented +by integers called big-map identifiers. Finally, big maps can be +represented as pairs of a big-map identifier (an integer) and a +big-map diff (written in the same syntax as a map whose values are +options). + +So for example, ``{ Elt "bar" True ; Elt "foo" False }``, ``42``, and +``Pair 42 { Elt "foo" (Some False) }`` are all valid representations +of type ``big_map string bool``. + +The behavior of big-map operations is the same as if they were normal +maps, except that under the hood, the elements are loaded and +deserialized on demand. + +- ``EMPTY_BIG_MAP 'key 'val``: Build a new, empty big map from keys of a + given type to values of another given type. + + The ``'key`` type must be comparable (the ``COMPARE`` primitive must + be defined over it). + +:: + + :: 'S -> map 'key 'val : 'S + +- ``GET``: Access an element in a ``big_map``, returns an optional value to be + checked with ``IF_SOME``. + +:: + + :: 'key : big_map 'key 'val : 'S -> option 'val : 'S + +- ``MEM``: Check for the presence of an element in a ``big_map``. + +:: + + :: 'key : big_map 'key 'val : 'S -> bool : 'S + +- ``UPDATE``: Assign or remove an element in a ``big_map``. + +:: + + :: 'key : option 'val : big_map 'key 'val : 'S -> big_map 'key 'val : 'S + + +- ``GET_AND_UPDATE``: A combination of the ``GET`` and ``UPDATE`` instructions. + +:: + + :: 'key : option 'val : big_map 'key 'val : 'S -> option 'val : big_map 'key 'val : 'S + +This instruction is similar to ``UPDATE`` but it also returns the +value that was previously stored in the ``big_map`` at the same key as +``GET`` would. + + +Operations on optional values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- ``SOME``: Pack a value as an optional value. + +:: + + :: 'a : 'S -> option 'a : 'S + + > SOME / v : S => (Some v) : S + +- ``NONE 'a``: The absent optional value. + +:: + + :: 'S -> option 'a : 'S + + > NONE / S => None : S + +- ``IF_NONE bt bf``: Inspect an optional value. + +:: + + :: option 'a : 'A -> 'B + iff bt :: [ 'A -> 'B] + bf :: [ 'a : 'A -> 'B] + + > IF_NONE bt bf / (None) : S => bt / S + > IF_NONE bt bf / (Some a) : S => bf / a : S + +- ``COMPARE``: Optional values comparison + +:: + + :: option 'a : option 'a : 'S -> int : 'S + + > COMPARE / None : None : S => 0 : S + > COMPARE / None : (Some _) : S => -1 : S + > COMPARE / (Some _) : None : S => 1 : S + > COMPARE / (Some a) : (Some b) : S => COMPARE / a : b : S + +Operations on unions +~~~~~~~~~~~~~~~~~~~~ + +- ``LEFT 'b``: Pack a value in a union (left case). + +:: + + :: 'a : 'S -> or 'a 'b : 'S + + > LEFT / v : S => (Left v) : S + +- ``RIGHT 'a``: Pack a value in a union (right case). + +:: + + :: 'b : 'S -> or 'a 'b : 'S + + > RIGHT / v : S => (Right v) : S + +- ``IF_LEFT bt bf``: Inspect a value of a union. + +:: + + :: or 'a 'b : 'A -> 'B + iff bt :: [ 'a : 'A -> 'B] + bf :: [ 'b : 'A -> 'B] + + > IF_LEFT bt bf / (Left a) : S => bt / a : S + > IF_LEFT bt bf / (Right b) : S => bf / b : S + +- ``COMPARE``: Unions comparison + +:: + + :: or 'a 'b : or 'a 'b : 'S -> int : 'S + + > COMPARE / (Left a) : (Left b) : S => COMPARE / a : b : S + > COMPARE / (Left _) : (Right _) : S => -1 : S + > COMPARE / (Right _) : (Left _) : S => 1 : S + > COMPARE / (Right a) : (Right b) : S => COMPARE / a : b : S + +Operations on lists +~~~~~~~~~~~~~~~~~~~ + +- ``CONS``: Prepend an element to a list. + +:: + + :: 'a : list 'a : 'S -> list 'a : 'S + + > CONS / a : { } : S => { a ; } : S + +- ``NIL 'a``: The empty list. + +:: + + :: 'S -> list 'a : 'S + + > NIL / S => {} : S + +- ``IF_CONS bt bf``: Inspect a list. + +:: + + :: list 'a : 'A -> 'B + iff bt :: [ 'a : list 'a : 'A -> 'B] + bf :: [ 'A -> 'B] + + > IF_CONS bt bf / { a ; } : S => bt / a : { } : S + > IF_CONS bt bf / {} : S => bf / S + +- ``MAP body``: Apply the body expression to each element of the list. + The body sequence has access to the stack. + +:: + + :: (list 'elt) : 'A -> (list 'b) : 'A + iff body :: [ 'elt : 'A -> 'b : 'A ] + + > MAP body / {} : S => {} : S + > MAP body / { a ; } : S => { b ; } : S'' + where body / a : S => b : S' + and MAP body / { } : S' => { } : S'' + +- ``SIZE``: Get the number of elements in the list. + +:: + + :: list 'elt : 'S -> nat : 'S + + > SIZE / { _ ; } : S => 1 + s : S + where SIZE / { } : S => s : S + > SIZE / {} : S => 0 : S + + +- ``ITER body``: Apply the body expression to each element of a list. + The body sequence has access to the stack. + +:: + + :: (list 'elt) : 'A -> 'A + iff body :: [ 'elt : 'A -> 'A ] + > ITER body / {} : S => S + > ITER body / { a ; } : S => ITER body / { } : S' + iff body / a : S => S' + + +Domain specific data types +-------------------------- + +- ``timestamp``: Dates in the real world. + +- ``mutez``: A specific type for manipulating tokens. + +- ``address``: An untyped address (implicit account or smart contract). + +- ``contract 'param``: A contract, with the type of its code, + ``contract unit`` for implicit accounts. + +- ``operation``: An internal operation emitted by a contract. + +- ``key``: A public cryptographic key. + +- ``key_hash``: The hash of a public cryptographic key. + +- ``signature``: A cryptographic signature. + +- ``chain_id``: An identifier for a chain, used to distinguish the test and the main chains. + +- ``bls12_381_g1``, ``bls12_381_g2`` : Points on the BLS12-381 curves G\ :sub:`1`\ and G\ :sub:`2`\ , respectively. + +- ``bls12_381_fr`` : An element of the scalar field F\ :sub:`r`\ , used for scalar multiplication on the BLS12-381 curves G\ :sub:`1`\ and G\ :sub:`2`\ . + +- ``sapling_transaction ms``: A :doc:`Sapling ` transaction + +- ``sapling_state ms``: A :doc:`Sapling ` state + +- ``ticket (t)``: A ticket used to authenticate information of type ``(t)`` on-chain. + +- ``chest``: a timelocked chest containing bytes and information to open it. + see :doc:`Timelock ` . + +- ``chest_key``: used to open a chest, also contains a proof + to check the correctness of the opening. see :doc:`Timelock ` . + + +Domain specific operations +-------------------------- + +Operations on timestamps +~~~~~~~~~~~~~~~~~~~~~~~~ + +Timestamps can be obtained by the ``NOW`` operation, or retrieved from +script parameters or globals. + +- ``ADD`` Increment / decrement a timestamp of the given number of + seconds. + +:: + + :: timestamp : int : 'S -> timestamp : 'S + :: int : timestamp : 'S -> timestamp : 'S + + > ADD / seconds : nat (t) : S => (seconds + t) : S + > ADD / nat (t) : seconds : S => (t + seconds) : S + +- ``SUB`` Subtract a number of seconds from a timestamp. + +:: + + :: timestamp : int : 'S -> timestamp : 'S + + > SUB / seconds : nat (t) : S => (seconds - t) : S + +- ``SUB`` Subtract two timestamps. + +:: + + :: timestamp : timestamp : 'S -> int : 'S + + > SUB / seconds(t1) : seconds(t2) : S => (t1 - t2) : S + +- ``COMPARE``: Timestamp comparison. + +:: + + :: timestamp : timestamp : 'S -> int : 'S + + > COMPARE / seconds(t1) : seconds(t2) : S => -1 : S + iff t1 < t2 + > COMPARE / seconds(t1) : seconds(t2) : S => 0 : S + iff t1 = t2 + > COMPARE / seconds(t1) : seconds(t2) : S => 1 : S + iff t1 > t2 + + +Operations on Mutez +~~~~~~~~~~~~~~~~~~~ + +Mutez (micro-Tez) are internally represented by a 64 bit signed +integers. There are restrictions to prevent creating a negative amount +of mutez. Operations are limited to prevent overflow and mixing them +with other numerical types by mistake. They are also mandatory checked +for under/overflows. + +- ``ADD`` + +:: + + :: mutez : mutez : 'S -> mutez : 'S + + > ADD / x : y : S => [FAILED] on overflow + > ADD / x : y : S => (x + y) : S + +- ``SUB`` + +:: + + :: mutez : mutez : 'S -> mutez : 'S + + > SUB / x : y : S => [FAILED] + iff x < y + > SUB / x : y : S => (x - y) : S + +- ``MUL`` + +:: + + :: mutez : nat : 'S -> mutez : 'S + :: nat : mutez : 'S -> mutez : 'S + + > MUL / x : y : S => [FAILED] on overflow + > MUL / x : y : S => (x * y) : S + +- ``EDIV`` + +:: + + :: mutez : nat : 'S -> option (pair mutez mutez) : 'S + :: mutez : mutez : 'S -> option (pair nat mutez) : 'S + + > EDIV / x : 0 : S => None + > EDIV / x : y : S => Some (Pair (x / y) (x % y)) : S + iff y <> 0 + +- ``COMPARE``: Mutez comparison + +:: + + :: mutez : mutez : 'S -> int : 'S + + > COMPARE / x : y : S => -1 : S + iff x < y + > COMPARE / x : y : S => 0 : S + iff x = y + > COMPARE / x : y : S => 1 : S + iff x > y + +Operations on contracts +~~~~~~~~~~~~~~~~~~~~~~~ + +- ``CREATE_CONTRACT { storage 'g ; parameter 'p ; code ... }``: + Forge a new contract from a literal. + +:: + + :: option key_hash : mutez : 'g : 'S + -> operation : address : 'S + +Originate a contract based on a literal. The parameters are the +optional delegate, the initial amount taken from the current +contract, and the initial storage of the originated contract. +The contract is returned as a first class value (to be dropped, passed +as parameter or stored). The ``CONTRACT 'p`` instruction will fail +until it is actually originated. + +- ``TRANSFER_TOKENS``: Forge a transaction. + +:: + + :: 'p : mutez : contract 'p : 'S -> operation : 'S + +The parameter must be consistent with the one expected by the +contract, unit for an account. + +.. _MichelsonSetDelegate_011: + +- ``SET_DELEGATE``: Set or withdraw the contract's delegation. + +:: + + :: option key_hash : 'S -> operation : 'S + +Using this instruction is the only way to modify the delegation of a +smart contract. If the parameter is ``None`` then the delegation of the +current contract is withdrawn; if it is ``Some kh`` where ``kh`` is the +key hash of a registered delegate that is not the current delegate of +the contract, then this operation sets the delegate of the contract to +this registered delegate. The operation fails if ``kh`` is the current +delegate of the contract or if ``kh`` is not a registered delegate. + +- ``BALANCE``: Push the current amount of mutez held by the executing + contract, including any mutez added by the calling transaction. + +:: + + :: 'S -> mutez : 'S + +- ``ADDRESS``: Cast the contract to its address. + +:: + + :: contract _ : 'S -> address : 'S + + > ADDRESS / addr : S => addr : S + +- ``CONTRACT 'p``: Cast the address to the given contract type if possible. + +:: + + :: address : 'S -> option (contract 'p) : 'S + + > CONTRACT / addr : S => Some addr : S + iff addr exists and is a contract of parameter type 'p + > CONTRACT / addr : S => Some addr : S + iff 'p = unit and addr is an implicit contract + > CONTRACT / addr : S => None : S + otherwise + +- ``SOURCE``: Push the contract that initiated the current + transaction, i.e. the contract that paid the fees and + storage cost, and whose manager signed the operation + that was sent on the blockchain. Note that since + ``TRANSFER_TOKENS`` instructions can be chained, + ``SOURCE`` and ``SENDER`` are not necessarily the same. + +:: + + :: 'S -> address : 'S + +- ``SENDER``: Push the contract that initiated the current + internal transaction. It may be the ``SOURCE``, but may + also be different if the source sent an order to an intermediate + smart contract, which then called the current contract. + +:: + + :: 'S -> address : 'S + +- ``SELF``: Push the current contract. + +:: + + :: 'S -> contract 'p : 'S + where contract 'p is the type of the current contract + +Note that ``SELF`` is forbidden in lambdas because it cannot be +type-checked; the type of the contract executing the lambda cannot be +known at the point of type-checking the lambda's body. + +- ``SELF_ADDRESS``: Push the address of the current contract. This is + equivalent to ``SELF; ADDRESS`` except that it is allowed in + lambdas. + +:: + + :: 'S -> address : 'S + +Note that ``SELF_ADDRESS`` inside a lambda returns the address of the +contract executing the lambda, which can be different from the address +of the contract in which the ``SELF_ADDRESS`` instruction is written. + +- ``AMOUNT``: Push the amount of the current transaction. + +:: + + :: 'S -> mutez : 'S + +- ``IMPLICIT_ACCOUNT``: Return a default contract with the given + public/private key pair. Any funds deposited in this contract can + immediately be spent by the holder of the private key. This contract + cannot execute Michelson code and will always exist on the + blockchain. + +:: + + :: key_hash : 'S -> contract unit : 'S + +- ``VOTING_POWER``: Return the voting power of a given contract. This voting power + coincides with the weight of the contract in the voting listings (i.e., the rolls + count) which is calculated at the beginning of every voting period. + +:: + + :: key_hash : 'S -> nat : 'S + +Special operations +~~~~~~~~~~~~~~~~~~ + +- ``NOW``: Push the minimal injection time for the current block, + namely the block whose validation triggered this execution. The + minimal injection time is 60 seconds after the timestamp of the + predecessor block. This value does not change during the execution + of the contract. + +:: + + :: 'S -> timestamp : 'S + +- ``CHAIN_ID``: Push the chain identifier. + +:: + + :: 'S -> chain_id : 'S + +- ``COMPARE``: Chain identifier comparison + +:: + + :: chain_id : chain_id : 'S -> int : 'S + + > COMPARE / x : y : S => -1 : S + iff x < y + > COMPARE / x : y : S => 0 : S + iff x = y + > COMPARE / x : y : S => 1 : S + iff x > y + +- ``LEVEL``: Push the level of the current transaction's block. + +:: + + :: 'S -> nat : 'S + +- ``TOTAL_VOTING_POWER``: Return the total voting power of all contracts. The total + voting power coincides with the sum of the rolls count of every contract in the voting + listings. The voting listings is calculated at the beginning of every voting period. + +:: + + :: 'S -> nat : 'S + +Operations on bytes +~~~~~~~~~~~~~~~~~~~ + +Bytes are used for serializing data, in order to check signatures and +compute hashes on them. They can also be used to incorporate data from +the wild and untyped outside world. + +- ``PACK``: Serializes a piece of data to its optimized + binary representation. + +:: + + :: 'a : 'S -> bytes : 'S + +- ``UNPACK 'a``: Deserializes a piece of data, if valid. + +:: + + :: bytes : 'S -> option 'a : 'S + +- ``CONCAT``: Byte sequence concatenation. + +:: + + :: bytes : bytes : 'S -> bytes : 'S + + > CONCAT / s : t : S => (s ^ t) : S + + :: bytes list : 'S -> bytes : 'S + + > CONCAT / {} : S => 0x : S + > CONCAT / { s ; } : S => (s ^ r) : S + where CONCAT / { } : S => r : S + +- ``SIZE``: size of a sequence of bytes. + +:: + + :: bytes : 'S -> nat : 'S + +- ``SLICE``: Bytes access. + +:: + + :: nat : nat : bytes : 'S -> option bytes : 'S + + > SLICE / offset : length : s : S => Some ss : S + where ss is the substring of s at the given offset and of the given length + iff offset and (offset + length) are in bounds + > SLICE / offset : length : s : S => None : S + iff offset or (offset + length) are out of bounds + +- ``COMPARE``: Lexicographic comparison. + +:: + + :: bytes : bytes : 'S -> int : 'S + + > COMPARE / s : t : S => -1 : S + iff s < t + > COMPARE / s : t : S => 0 : S + iff s = t + > COMPARE / s : t : S => 1 : S + iff s > t + + +Cryptographic primitives +~~~~~~~~~~~~~~~~~~~~~~~~ + +- ``HASH_KEY``: Compute the b58check of a public key. + +:: + + :: key : 'S -> key_hash : 'S + +- ``BLAKE2B``: Compute a cryptographic hash of the value contents using the + Blake2b-256 cryptographic hash function. + +:: + + :: bytes : 'S -> bytes : 'S + +- ``KECCAK``: Compute a cryptographic hash of the value contents using the + Keccak-256 cryptographic hash function. + +:: + + :: bytes : 'S -> bytes : 'S + +- ``SHA256``: Compute a cryptographic hash of the value contents using the + Sha256 cryptographic hash function. + +:: + + :: bytes : 'S -> bytes : 'S + +- ``SHA512``: Compute a cryptographic hash of the value contents using the + Sha512 cryptographic hash function. + +:: + + :: bytes : 'S -> bytes : 'S + +- ``SHA3``: Compute a cryptographic hash of the value contents using the + SHA3-256 cryptographic hash function. + +:: + + :: bytes : 'S -> bytes : 'S + +- ``CHECK_SIGNATURE``: Check that a sequence of bytes has been signed + with a given key. + +:: + + :: key : signature : bytes : 'S -> bool : 'S + +- ``COMPARE``: Key hash, key and signature comparison + +:: + + :: key_hash : key_hash : 'S -> int : 'S + :: key : key : 'S -> int : 'S + :: signature : signature : 'S -> int : 'S + + > COMPARE / x : y : S => -1 : S + iff x < y + > COMPARE / x : y : S => 0 : S + iff x = y + > COMPARE / x : y : S => 1 : S + iff x > y + +BLS12-381 primitives +~~~~~~~~~~~~~~~~~~~~~~~~ + +- ``NEG``: Negate a curve point or field element. + +:: + + :: bls12_381_g1 : 'S -> bls12_381_g1 : 'S + :: bls12_381_g2 : 'S -> bls12_381_g2 : 'S + :: bls12_381_fr : 'S -> bls12_381_fr : 'S + +- ``ADD``: Add two curve points or field elements. + +:: + + :: bls12_381_g1 : bls12_381_g1 : 'S -> bls12_381_g1 : 'S + :: bls12_381_g2 : bls12_381_g2 : 'S -> bls12_381_g2 : 'S + :: bls12_381_fr : bls12_381_fr : 'S -> bls12_381_fr : 'S + +- ``MUL``: Multiply a curve point or field element by a scalar field element. Fr + elements can be built from naturals by multiplying by the unit of Fr using ``PUSH bls12_381_fr 1; MUL``. Note + that the multiplication will be computed using the natural modulo the order + of Fr. + +:: + + :: bls12_381_g1 : bls12_381_fr : 'S -> bls12_381_g1 : 'S + :: bls12_381_g2 : bls12_381_fr : 'S -> bls12_381_g2 : 'S + :: bls12_381_fr : bls12_381_fr : 'S -> bls12_381_fr : 'S + :: nat : bls12_381_fr : 'S -> bls12_381_fr : 'S + :: int : bls12_381_fr : 'S -> bls12_381_fr : 'S + :: bls12_381_fr : nat : 'S -> bls12_381_fr : 'S + :: bls12_381_fr : int : 'S -> bls12_381_fr : 'S + +- ``INT``: Convert a field element to type ``int``. The returned value is always between ``0`` (inclusive) and the order of Fr (exclusive). + +:: + + :: bls12_381_fr : 'S -> int : 'S + +- ``PAIRING_CHECK``: + Verify that the product of pairings of the given list of points is equal to 1 in Fq12. Returns ``true`` if the list is empty. + Can be used to verify if two pairings P1 and P2 are equal by verifying P1 * P2^(-1) = 1. + +:: + + :: list (pair bls12_381_g1 bls12_381_g2) : 'S -> bool : 'S + + +Sapling operations +~~~~~~~~~~~~~~~~~~ + +Please see the :doc:`Sapling integration` page for a more +comprehensive description of the Sapling protocol. + +- ``SAPLING_VERIFY_UPDATE``: verify and apply a transaction on a Sapling state. + +:: + + :: sapling_transaction ms : sapling_state ms : 'S -> option (pair int (sapling_state ms)): 'S + + > SAPLING_VERIFY_UPDATE / t : s : S => Some (Pair b s') : S + iff the transaction t successfully applied on state s resulting + in balance b and an updated state s' + > SAPLING_VERIFY_UPDATE / t : s : S => None : S + iff the transaction t is invalid with respect to the state + +- ``SAPLING_EMPTY_STATE ms``: Pushes an empty state on the stack. + + :: + + :: 'S -> sapling_state ms: 'S + + > SAPLING_EMPTY_STATE ms / S => sapling_state ms : S + with `sapling_state ms` being the empty state (ie. no one can spend tokens from it) + with memo_size `ms` + + +.. _MichelsonTickets_011: + +Operations on tickets +~~~~~~~~~~~~~~~~~~~~~ + +The following operations deal with tickets. Tickets are a way for smart-contracts +to authenticate data with respect to a Tezos address. This authentication can +then be used to build composable permission systems. + +A contract can create a ticket from a value and an amount. The ticket, when +inspected reveals the value, the amount, and the address of the ticketer (the contract that created the ticket). It is +impossible for a contract to “forge” a ticket that appears to have been created +by another ticketer. + +The amount is a meta-data that can be used to implement UTXOs. + +Tickets cannot be duplicated using the ``DUP`` instruction. + +For example, a ticket could represent a Non Fungible Token (NFT) or a Unspent +Transaction Output (UTXO) which can then be passed around and behave like a value. +This process can happen without the need to interact with a centralized NFT contract, +simplifying the code. + +- ``TICKET``: Create a ticket with the given content and amount. The ticketer is the address + of `SELF`. + +:: + + :: 'a : nat : 'S -> ticket 'a : 'S + +Type ``'a`` must be comparable (the ``COMPARE`` primitive must be defined over it). + +- ``READ_TICKET``: Retrieve the information stored in a ticket. Also return the ticket. + +:: + + :: ticket 'a : 'S -> pair address 'a nat : ticket 'a : 'S + +- ``SPLIT_TICKET``: Delete the given ticket and create two tickets with the + same content and ticketer as the original, but with the new provided amounts. + (This can be used to easily implement UTXOs.) + Return None iff the ticket's original amount is not equal to the sum of the + provided amounts. + +:: + + :: ticket 'a : (pair nat nat) : 'S -> + option (pair (ticket 'a) (ticket 'a)) : 'S + +- ``JOIN_TICKETS``: The inverse of ``SPLIT_TICKET``. Delete the given tickets and create a ticket with an amount equal to the + sum of the amounts of the input tickets. + (This can be used to consolidate UTXOs.) + Return None iff the input tickets have a different ticketer or content. + +:: + + :: (pair (ticket 'a) (ticket 'a)) : 'S -> + option (ticket 'a) : 'S + +Operations on timelock +~~~~~~~~~~~~~~~~~~~~~~ + +- ``OPEN_CHEST``: opens a timelocked chest given its key and the time. The results can be bytes + if the opening is correct, or a boolean indicating whether the chest was incorrect, + or its opening was. See :doc:`Timelock ` for more information. + +:: + + :: chest_key : chest : nat : 'S -> or bytes bool : 'S + + + +Removed instructions +~~~~~~~~~~~~~~~~~~~~ + +:doc:`../protocols/005_babylon` deprecated the following instructions. Because no smart +contract used these on Mainnet before they got deprecated, they have been +removed. The Michelson type-checker will reject any contract using them. + +- ``CREATE_CONTRACT { storage 'g ; parameter 'p ; code ... }``: + Forge a new contract from a literal. + +:: + + :: key_hash : option key_hash : bool : bool : mutez : 'g : 'S + -> operation : address : 'S + +See the documentation of the new ``CREATE_CONTRACT`` instruction. The +first, third, and fourth parameters are ignored. + +- ``CREATE_ACCOUNT``: Forge an account creation operation. + +:: + + :: key_hash : option key_hash : bool : mutez : 'S + -> operation : address : 'S + +Takes as argument the manager, optional delegate, the delegatable flag +and finally the initial amount taken from the currently executed +contract. This instruction originates a contract with two entrypoints; +``%default`` of type ``unit`` that does nothing and ``%do`` of type +``lambda unit (list operation)`` that executes and returns the +parameter if the sender is the contract's manager. + +- ``STEPS_TO_QUOTA``: Push the remaining steps before the contract + execution must terminate. + +:: + + :: 'S -> nat : 'S + +.. _MichelsonViews_011: + +Operations on views +~~~~~~~~~~~~~~~~~~~~ + +Views are a mechanism for contract calls that: + +- are read-only: they may depend on the storage of the contract declaring the view but cannot modify it nor emit operations (but they can call other views), +- take arguments as input in addition to the contract storage, +- return results as output, +- are synchronous: the result is immediately available on the stack of the caller contract. + +In other words, the execution of a view is included in the operation of caller's contract, but accesses the storage of the declarer's contract, in read-only mode. +Thus, in terms of execution, views are more like lambda functions rather than contract entrypoints, +Here is an example: + +:: + + code { + ...; + TRANSFER_TOKENS; + ...; + VIEW "view_ex" unit; + ...; + }; + +This contract calls a contract ``TRANSFER_TOKENS``, and, later on, a view called "view_ex". +No matter if the callee "view_ex" is defined in the same contract with this caller contract or not, +this view will be executed immediately in the current operation, +while the operations emitted by ``TRANSFER_TOKENS`` will be executed later on. +As a result, although it may seem that "view_ex" receives the storage modified by ``TRANSFER_TOKENS``, +this is not the case. +In other words, the storage of the view is the same as when the current contract was called. +In particular, in case of re-entrance, i.e., if a contract A calls a contract B that calls a view on A, the storage of the view will be the same as when B started, not when A started. + +Views are **declared** at the toplevel of the script of the contract on which they operate, +alongside the contract parameter type, storage type, and code. +To declare a view, the ``view`` keyword is used; its syntax is +``view name 'arg 'return { instr; ... }`` where: + +- ``name`` is a string of at most 31 characters matching the regular expression ``[a-zA-Z0-9_.%@]*``; it is used to identify the view, hence it must be different from the names of the other views declared in the same script; +- ``'arg`` is the type of the argument of the view; +- ``'return`` is the type of the result returned by the view; +- ``{ instr; ... }`` is a sequence of instructions of type ``lambda (pair 'arg 'storage_ty) 'return`` where ``'storage_ty`` is the type of the storage of the current contract. Certain specific instructions have different semantics in ``view``: ``BALANCE`` represents the current amount of mutez held by the contract where ``view`` is; ``SENDER`` represents the contract which is the caller of ``view``; ``SELF_ADDRESS`` represents the contract where ``view`` is; ``AMOUNT`` is always 0 mutez. + +Note that in both view input (type ``'arg``) and view output (type ``'return``), the following types are forbidden: ``ticket``, ``operation``, ``big_map`` and ``sapling_state``. + +Views are **called** using the following Michelson instruction: + +- ``VIEW name 'return``: Call the view named ``name`` from the contract whose address is the second element of the stack, sending it as input the top element of the stack. + +:: + + :: 'arg : address : 'S -> option 'return : 'S + + > VIEW name 'return / x : addr : S => Some y : S + iff addr is the address of a smart contract c with storage s + where c has a toplevel declaration of the form "view name 'arg 'return { code }" + and code / Pair x s : [] => y : [] + + > VIEW name 'return / _ : _ : S => None : S + otherwise + + + +If the given address is nonexistent or if the contract at that address does not have a view of the expected name and type, +``None`` will be returned. +Otherwise, ``Some a`` will be returned where ``a`` is the result of the view call. +Note that if a contract address containing an entrypoint ``address%entrypoint`` is provided, +only the ``address`` part will be taken. +``operation``, ``big_map`` and ``sapling_state`` and ``ticket`` types are forbidden for the ``'return`` type. + + +Here is an example using views, consisting of two contracts. +The first contract defines two views at toplevel that are named ``add_v`` and ``mul_v``. + +:: + + { parameter nat; + storage nat; + code { CAR; NIL operation ; PAIR }; + view "add_v" nat nat { UNPAIR; ADD }; + view "mul_v" nat nat { UNPAIR; MUL }; + } + + +The second contract calls the ``add_v`` view of the above contract and obtains a result immediately. + +:: + + { parameter (pair nat address) ; + storage nat ; + code { CAR ; UNPAIR; VIEW "add_v" nat ; + IF_SOME { } { FAIL }; NIL operation; PAIR }; } + +Macros +------ + +In addition to the operations above, several extensions have been added +to the language's concrete syntax. If you are interacting with the node +via RPC, bypassing the client, which expands away these macros, you will +need to desugar them yourself. + +These macros are designed to be unambiguous and reversible, meaning that +errors are reported in terms of desugared syntax. Below you'll see +these macros defined in terms of other syntactic forms. That is how +these macros are seen by the node. + +Compare +~~~~~~~ + +Syntactic sugar exists for merging ``COMPARE`` and comparison +combinators, and also for branching. + +- ``CMP{EQ|NEQ|LT|GT|LE|GE}`` + +:: + + > CMP(\op) / S => COMPARE ; (\op) / S + +- ``IF{EQ|NEQ|LT|GT|LE|GE} bt bf`` + +:: + + > IF(\op) bt bf / S => (\op) ; IF bt bf / S + +- ``IFCMP{EQ|NEQ|LT|GT|LE|GE} bt bf`` + +:: + + > IFCMP(\op) / S => COMPARE ; (\op) ; IF bt bf / S + +Fail +~~~~ + +The ``FAIL`` macros is equivalent to ``UNIT; FAILWITH`` and is callable +in any context since it does not use its input stack. + +- ``FAIL`` + +:: + + > FAIL / S => UNIT; FAILWITH / S + +Assertion macros +~~~~~~~~~~~~~~~~ + +All assertion operations are syntactic sugar for conditionals with a +``FAIL`` instruction in the appropriate branch. When possible, use them +to increase clarity about illegal states. + +- ``ASSERT`` + +:: + + > ASSERT => IF {} {FAIL} + +- ``ASSERT_{EQ|NEQ|LT|LE|GT|GE}`` + +:: + + > ASSERT_(\op) => IF(\op) {} {FAIL} + +- ``ASSERT_CMP{EQ|NEQ|LT|LE|GT|GE}`` + +:: + + > ASSERT_CMP(\op) => IFCMP(\op) {} {FAIL} + +- ``ASSERT_NONE`` + +:: + + > ASSERT_NONE => IF_NONE {} {FAIL} + +- ``ASSERT_SOME`` + +:: + + > ASSERT_SOME @x => IF_NONE {FAIL} {RENAME @x} + +- ``ASSERT_LEFT`` + +:: + + > ASSERT_LEFT @x => IF_LEFT {RENAME @x} {FAIL} + +- ``ASSERT_RIGHT`` + +:: + + > ASSERT_RIGHT @x => IF_LEFT {FAIL} {RENAME @x} + +Syntactic Conveniences +~~~~~~~~~~~~~~~~~~~~~~ + +These macros are simply more convenient syntax for various common +operations. + +- ``P(\left=A|P(\left)(\right))(\right=I|P(\left)(\right))R``: A syntactic sugar + for building nested pairs. In the case of right combs, `PAIR n` is more efficient. + +:: + + > PA(\right)R / S => DIP ((\right)R) ; PAIR / S + > P(\left)IR / S => (\left)R ; PAIR / S + > P(\left)(\right)R => (\left)R ; DIP ((\right)R) ; PAIR / S + +A good way to quickly figure which macro to use is to mentally parse the +macro as ``P`` for pair constructor, ``A`` for left leaf and ``I`` for +right leaf. The macro takes as many elements on the stack as there are +leaves and constructs a nested pair with the shape given by its name. + +Take the macro ``PAPPAIIR`` for instance: + +:: + + P A P P A I I R + ( l, ( ( l, r ), r )) + +A typing rule can be inferred: + +:: + + PAPPAIIR + :: 'a : 'b : 'c : 'd : 'S -> (pair 'a (pair (pair 'b 'c) 'd)) + +- ``UNP(\left=A|P(\left)(\right))(\right=I|P(\left)(\right))R``: A syntactic sugar + for destructing nested pairs. These macros follow the same convention + as the previous one. + +:: + + > UNPA(\right)R / S => UNPAIR ; DIP (UN(\right)R) / S + > UNP(\left)IR / S => UNPAIR ; UN(\left)R / S + > UNP(\left)(\right)R => UNPAIR ; DIP (UN(\right)R) ; UN(\left)R / S + +- ``C[AD]+R``: A syntactic sugar for accessing fields in nested pairs. In the case of right combs, ``CAR k`` and ``CDR k`` are more efficient. + +:: + + > CA(\rest=[AD]+)R / S => CAR ; C(\rest)R / S + > CD(\rest=[AD]+)R / S => CDR ; C(\rest)R / S + +- ``CAR k``: Access the ``k`` -th part of a right comb of size ``n > k + 1``. ``CAR 0`` is equivalent to ``CAR`` and in general ``CAR k`` is equivalent to ``k`` times the ``CDR`` instruction followed by once the ``CAR`` instruction. Note that this instruction cannot access the last element of a right comb; ``CDR k`` should be used for that. + +:: + + > CAR n / S => GET (2n+1) / S + +- ``CDR k``: Access the rightmost element of a right comb of size ``k``. ``CDR 0`` is a no-op, ``CDR 1`` is equivalent to ``CDR`` and in general ``CDR k`` is equivalent to ``k`` times the ``CDR`` instruction. Note that on a right comb of size ``n > k >= 2``, ``CDR k`` will return the right comb composed of the same elements but the ``k`` leftmost ones. + +:: + + > CDR n / S => GET (2n) / S + +- ``IF_SOME bt bf``: Inspect an optional value. + +:: + + > IF_SOME bt bf / S => IF_NONE bf bt / S + +- ``IF_RIGHT bt bf``: Inspect a value of a union. + +:: + + > IF_RIGHT bt bf / S => IF_LEFT bf bt / S + +- ``SET_CAR``: Set the left field of a pair. This is equivalent to ``SWAP; UPDATE 1``. + +:: + + > SET_CAR => CDR ; SWAP ; PAIR + +- ``SET_CDR``: Set the right field of a pair. This is equivalent to ``SWAP; UPDATE 2``. + +:: + + > SET_CDR => CAR ; PAIR + +- ``SET_C[AD]+R``: A syntactic sugar for setting fields in nested + pairs. In the case of right combs, `UPDATE n` is more efficient. + +:: + + > SET_CA(\rest=[AD]+)R / S => + { DUP ; DIP { CAR ; SET_C(\rest)R } ; CDR ; SWAP ; PAIR } / S + > SET_CD(\rest=[AD]+)R / S => + { DUP ; DIP { CDR ; SET_C(\rest)R } ; CAR ; PAIR } / S + +- ``MAP_CAR`` code: Transform the left field of a pair. + +:: + + > MAP_CAR code => DUP ; CDR ; DIP { CAR ; code } ; SWAP ; PAIR + +- ``MAP_CDR`` code: Transform the right field of a pair. + +:: + + > MAP_CDR code => DUP ; CDR ; code ; SWAP ; CAR ; PAIR + +- ``MAP_C[AD]+R`` code: A syntactic sugar for transforming fields in + nested pairs. + +:: + + > MAP_CA(\rest=[AD]+)R code / S => + { DUP ; DIP { CAR ; MAP_C(\rest)R code } ; CDR ; SWAP ; PAIR } / S + > MAP_CD(\rest=[AD]+)R code / S => + { DUP ; DIP { CDR ; MAP_C(\rest)R code } ; CAR ; PAIR } / S + +Concrete syntax +--------------- +.. _ConcreteSyntax_011: + +The concrete language is very close to the formal notation of the +specification. Its structure is extremely simple: an expression in the +language can only be one of the five following constructs. + +1. An integer in decimal notation. +2. A character string. +3. A byte sequence in hexadecimal notation prefixed by ``0x``. +4. The application of a primitive to a sequence of expressions. +5. A sequence of expressions. + +This simple five cases notation is called :doc:`../shell/micheline`. + +Constants +~~~~~~~~~ + +There are three kinds of constants: + +1. Integers or naturals in decimal notation. +2. Strings, with some usual escape sequences: ``\n``, ``\\``, + ``\"``. Unescaped line-breaks (both ``\n`` and ``\r``) cannot + appear in a Michelson string. Moreover, the current version of + Michelson restricts strings to be the printable subset of 7-bit + ASCII, namely characters with codes from within `[32, 126]` range, + plus the escaped characters mentioned above. +3. Byte sequences in hexadecimal notation, prefixed with ``0x``. + +Differences with the formal notation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The concrete syntax follows the same lexical conventions as the +specification: instructions are represented by uppercase identifiers, +type constructors by lowercase identifiers, and constant constructors +are capitalized. + +All domain specific constants are Micheline constants with specific +formats. Some have two variants accepted by the data type checker: a +readable one in a string and an optimized. + +- ``mutez`` amounts are written as naturals. +- ``timestamp``\ s are written either using ``RFC3339`` notation + in a string (readable), or as the number of seconds since Epoch + in a natural (optimized). +- ``contract``\ s, ``address``\ es, ``key``\ s and ``signature``\ s + are written as strings, in their usual Base58 encoded versions + (readable), or as their raw bytes (optimized). +- ``bls12_381_g1``\ s and ``bls12_381_g2``\ s are written as their raw bytes, using a big-endian point encoding, `as specified here `__. +- ``bls12_381_fr``\ s are written as their raw bytes, using a little-endian encoding. + +The optimized versions should not reach the RPCs, the protocol code +will convert to optimized by itself when forging operations, storing +to the database, and before hashing to get a canonical representation +of a datum for a given type. + +To prevent errors, control flow primitives that take instructions as +parameters require sequences in the concrete syntax. + +:: + + IF { instr1_true ; instr2_true ; ... } + { instr1_false ; instr2_false ; ... } + +Main program structure +~~~~~~~~~~~~~~~~~~~~~~ + +The toplevel of a smart contract file must be an un-delimited sequence +of three primitive applications (in no particular order) that provide its +``code``, ``parameter`` and ``storage`` fields. + +See the next section for a concrete example. + +Annotations +----------- + +The annotation mechanism of Michelson provides ways to better track +data on the stack and to give additional type constraints. Except for +a single exception specified just after, annotations are only here to +add constraints, *i.e.* they cannot turn an otherwise rejected program +into an accepted one. The notable exception to this rule is for +entrypoints: the semantics of the `CONTRACT` and `SELF` instructions vary depending on +their constructor annotations, and some contract origination may fail due +to invalid entrypoint constructor annotations. + +Stack visualization tools like the Michelson's Emacs mode print +annotations associated with each type in the program, as propagated by +the typechecker as well as variable annotations on the types of elements +in the stack. This is useful as a debugging aid. + +We distinguish three kinds of annotations: + +- type annotations, written ``:type_annot``, +- variable annotations, written ``@var_annot``, +- and field or constructors annotations, written ``%field_annot``. + +Type annotations +~~~~~~~~~~~~~~~~ + +Each type can be annotated with at most one type annotation. They are +used to give names to types. For types to be equal, their unnamed +version must be equal and their names must be the same or at least one +type must be unnamed. + +For instance, the following Michelson program which put its integer +parameter in the storage is not well typed: + +.. code-block:: michelson + + parameter (int :p) ; + storage (int :s) ; + code { UNPAIR ; SWAP ; DROP ; NIL operation ; PAIR } + +Whereas this one is: + +.. code-block:: michelson + + parameter (int :p) ; + storage int ; + code { UNPAIR ; SWAP ; DROP ; NIL operation ; PAIR } + +Inner components of composed typed can also be named. + +:: + + (pair :point (int :x_pos) (int :y_pos)) + +Push-like instructions, that act as constructors, can also be given a +type annotation. The stack type will then have on top a type with a corresponding name. + +:: + + UNIT :t + :: 'A -> (unit :t) : 'A + + PAIR :t + :: 'a : 'b : 'S -> (pair :t 'a 'b) : 'S + + SOME :t + :: 'a : 'S -> (option :t 'a) : 'S + + NONE :t 'a + :: 'S -> (option :t 'a) : 'S + + LEFT :t 'b + :: 'a : 'S -> (or :t 'a 'b) : 'S + + RIGHT :t 'a + :: 'b : 'S -> (or :t 'a 'b) : 'S + + NIL :t 'a + :: 'S -> (list :t 'a) : 'S + + EMPTY_SET :t 'elt + :: 'S -> (set :t 'elt) : 'S + + EMPTY_MAP :t 'key 'val + :: 'S -> (map :t 'key 'val) : 'S + + EMPTY_BIG_MAP :t 'key 'val + :: 'S -> (big_map :t 'key 'val) : 'S + + +A no-op instruction ``CAST`` ensures the top of the stack has the +specified type, and change its type if it is compatible. In particular, +this allows to change or remove type names explicitly. + +:: + + CAST 'b + :: 'a : 'S -> 'b : 'S + iff 'a = 'b + + > CAST t / a : S => a : S + + +Variable annotations +~~~~~~~~~~~~~~~~~~~~ + +Variable annotations can only be used on instructions that produce +elements on the stack. An instruction that produces ``n`` elements on +the stack can be given at most ``n`` variable annotations. + +The stack type contains both the types of each element in the stack, as +well as an optional variable annotation for each element. In this +sub-section we note: + +- ``[]`` for the empty stack, +- ``@annot (top) : (rest)`` for the stack whose first value has type ``(top)`` and is annotated with variable annotation ``@annot`` and whose queue has stack type ``(rest)``. + +The instructions which do not accept any variable annotations are: + +:: + + DROP + SWAP + DIG + DUG + IF_NONE + IF_LEFT + IF_CONS + ITER + IF + LOOP + LOOP_LEFT + DIP + FAILWITH + +The instructions which accept at most one variable annotation are: + +:: + + DUP + PUSH + UNIT + SOME + NONE + PAIR + CAR + CDR + LEFT + RIGHT + NIL + CONS + SIZE + MAP + MEM + EMPTY_SET + EMPTY_MAP + EMPTY_BIG_MAP + UPDATE + GET + LAMBDA + EXEC + ADD + SUB + CONCAT + MUL + OR + AND + XOR + NOT + ABS + ISNAT + INT + NEG + EDIV + LSL + LSR + COMPARE + EQ + NEQ + LT + GT + LE + GE + ADDRESS + CONTRACT + SET_DELEGATE + IMPLICIT_ACCOUNT + NOW + LEVEL + AMOUNT + BALANCE + HASH_KEY + CHECK_SIGNATURE + BLAKE2B + SOURCE + SENDER + SELF + SELF_ADDRESS + CAST + RENAME + CHAIN_ID + +The instructions which accept at most two variable annotations are: + +:: + + UNPAIR + CREATE_CONTRACT + +Annotations on instructions that produce multiple elements on the stack +will be used in order, where the first variable annotation is given to +the top-most element on the resulting stack. Instructions that produce +``n`` elements on the stack but are given less than ``n`` variable +annotations will see only their top-most stack type elements annotated. + +:: + + UNPAIR @fist @second + :: pair 'a 'b : 'S + -> @first 'a : @second 'b : 'S + + UNPAIR @first + :: pair 'a 'b : 'S + -> @first 'a : 'b : 'S + +A no-op instruction ``RENAME`` allows to rename variables in the stack +or to erase variable annotations in the stack. + +:: + + RENAME @new + :: @old 'a ; 'S -> @new 'a : 'S + + RENAME + :: @old 'a ; 'S -> 'a : 'S + + +Field and constructor annotations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Components of pair types, option types and or types can be annotated +with a field or constructor annotation. This feature is useful to encode +records fields and constructors of sum types. + +:: + + (pair :point + (int %x) + (int %y)) + +The previous Michelson type can be used as visual aid to represent the +record type (given in OCaml-like syntax): + +:: + + type point = { x : int ; y : int } + +Similarly, + +:: + + (or :t + (int %A) + (or + (bool %B) + (pair %C + (nat %n1) + (nat %n2)))) + +can be used to represent the algebraic data type (in OCaml-like syntax): + +:: + + type t = + | A of int + | B of bool + | C of { n1 : nat ; n2 : nat } + + +Field annotations are part of the type (at the same level as type name +annotations), and so types with differing field names (if present) are +not considered equal. + +Instructions that construct elements of composed types can also be +annotated with one or multiple field annotations (in addition to type +and variable annotations). + +:: + + PAIR %fst %snd + :: 'a : 'b : 'S -> (pair ('a %fst) ('b %snd)) : 'S + + LEFT %left %right 'b + :: 'a : 'S -> (or ('a %left) ('b %right)) : 'S + + RIGHT %left %right 'a + :: 'b : 'S -> (or ('a %left) ('b %right)) : 'S + +To improve readability and robustness, instructions ``CAR`` and ``CDR`` +accept one field annotation. For the contract to type check, the name of +the accessed field in the destructed pair must match the one given here. + +:: + + CAR %fst + :: (pair ('a %fst) 'b) : S -> 'a : 'S + + CDR %snd + :: (pair 'a ('b %snd)) : S -> 'b : 'S + + +Syntax +~~~~~~ + +Primitive applications can receive one or many annotations. + +An annotation is a sequence of characters that matches the regular +expression ``@%|@%%|%@|[@:%][_0-9a-zA-Z][_0-9a-zA-Z\.%@]*``. +Note however that ``@%``, ``@%%`` and ``%@`` are +:ref:`special annotations ` and are not allowed everywhere. + +Annotations come after the primitive name and before its potential arguments. + +:: + + (prim @v :t %x arg1 arg2 ...) + + +Ordering between different kinds of annotations is not significant, but +ordering among annotations of the same kind is. Annotations of the same +kind must be grouped together. + +For instance these two annotated instructions are equivalent: + +:: + + PAIR :t @my_pair %x %y + + PAIR %x %y :t @my_pair + +An annotation can be empty, in this case it will mean *no annotation* +and can be used as a wildcard. For instance, it is useful to annotate +only the right field of a pair instruction ``PAIR % %right`` or to +ignore field access constraints, *e.g.* in the macro ``UNPPAIPAIR %x1 % +%x3 %x4``. + +Annotations and macros +~~~~~~~~~~~~~~~~~~~~~~ + +Macros also support annotations, which are propagated on their expanded +forms. As with instructions, macros that produce ``n`` values on the +stack accept ``n`` variable annotations. + +:: + + DUU+P @annot + > DUU(\rest=U*)P @annot / S => DIP (DU(\rest)P @annot) ; SWAP / S + + C[AD]+R @annot %field_name + > CA(\rest=[AD]+)R @annot %field_name / S => CAR ; C(\rest)R @annot %field_name / S + > CD(\rest=[AD]+)R @annot %field_name / S => CDR ; C(\rest)R @annot %field_name / S + + CMP{EQ|NEQ|LT|GT|LE|GE} @annot + > CMP(\op) @annot / S => COMPARE ; (\op) @annot / S + +The variable annotation on ``SET_C[AD]+R`` and ``MAP_C[AD]+R`` annotates +the resulting toplevel pair while its field annotation is used to check +that the modified field is the expected one. + +:: + + SET_C[AD]+R @var %field + > SET_CAR @var %field => CDR %field ; SWAP ; PAIR @var + > SET_CDR @var %field => CAR %field ; PAIR @var + > SET_CA(\rest=[AD]+)R @var %field / S => + { DUP ; DIP { CAR ; SET_C(\rest)R %field } ; CDR ; SWAP ; PAIR @var } / S + > SET_CD(\rest=[AD]+)R @var %field/ S => + { DUP ; DIP { CDR ; SET_C(\rest)R %field } ; CAR ; PAIR @var } / S + + MAP_C[AD]+R @var %field code + > MAP_CAR code => DUP ; CDR ; DIP { CAR %field ; code } ; SWAP ; PAIR @var + > MAP_CDR code => DUP ; CDR %field ; code ; SWAP ; CAR ; PAIR @var + > MAP_CA(\rest=[AD]+)R @var %field code / S => + { DUP ; DIP { CAR ; MAP_C(\rest)R %field code } ; CDR ; SWAP ; PAIR @var} / S + > MAP_CD(\rest=[AD]+)R @var %field code / S => + { DUP ; DIP { CDR ; MAP_C(\rest)R %field code } ; CAR ; PAIR @var} / S + +Macros for nested ``PAIR`` accept multiple annotations. Field +annotations for ``PAIR`` give names to leaves of the constructed +nested pair, in order. This next snippet gives examples instead of +generic rewrite rules for readability purposes. + +:: + + PAPPAIIR @p %x1 %x2 %x3 %x4 + :: 'a : 'b : 'c : 'd : 'S + -> @p (pair ('a %x1) (pair (pair ('b %x) ('c %x3)) ('d %x4))) : 'S + + PAPAIR @p %x1 %x2 %x3 + :: 'a : 'b : 'c : 'S -> @p (pair ('a %x1) (pair ('b %x) ('c %x3))) : 'S + +Annotations for nested ``UNPAIR`` are deprecated. + +Automatic variable and field annotations inferring +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When no annotation is provided by the Michelson programmer, the +typechecker infers some annotations in specific cases. This greatly +helps users track information in the stack for bare contracts. + +For unannotated accesses with ``CAR`` and ``CDR`` to fields that are +named will be appended (with an additional ``.`` character) to the pair +variable annotation. + +:: + + CDAR + :: @p (pair ('a %foo) (pair %bar ('b %x) ('c %y))) : 'S -> @p.bar.x 'b : 'S + +If fields are not named but the pair is still named in the stack then +``.car`` or ``.cdr`` will be appended. + +:: + + CDAR + :: @p (pair 'a (pair 'b 'c)) : 'S -> @p.cdr.car 'b : 'S + +If the original pair is not named in the stack, but a field annotation +is present in the pair type the accessed value will be annotated with a +variable annotation corresponding to the field annotation alone. + +:: + + CDAR + :: (pair ('a %foo) (pair %bar ('b %x) ('c %y))) : 'S -> @bar.x 'b : 'S + +A similar mechanism is used for context dependent instructions: + +:: + + ADDRESS :: @c contract _ : 'S -> @c.address address : 'S + + CONTRACT 'p :: @a address : 'S -> @a.contract contract 'p : 'S + + BALANCE :: 'S -> @balance mutez : 'S + + SOURCE :: 'S -> @source address : 'S + + SENDER :: 'S -> @sender address : 'S + + SELF :: 'S -> @self contract 'p : 'S + + SELF_ADDRESS :: 'S -> @self address : 'S + + AMOUNT :: 'S -> @amount mutez : 'S + + NOW :: 'S -> @now timestamp : 'S + + LEVEL :: 'S -> @level nat : 'S + +Inside nested code blocks, bound items on the stack will be given a +default variable name annotation depending on the instruction and stack +type (which can be changed). For instance the annotated typing rule for +``ITER`` on lists is: + +:: + + ITER body + :: @l (list 'e) : 'A -> 'A + iff body :: [ @l.elt e' : 'A -> 'A ] + +Special annotations +~~~~~~~~~~~~~~~~~~~ +.. _SpecialAnnotations_011: + +The special variable annotations ``@%`` and ``@%%`` can be used on instructions +``CAR``, ``CDR``, and ``UNPAIR``. It means to use the accessed field name (if any) as +a name for the value on the stack. The following typing rule +demonstrates their use for instruction ``CAR``. + +:: + + CAR @% + :: @p (pair ('a %fst) ('b %snd)) : 'S -> @fst 'a : 'S + + CAR @%% + :: @p (pair ('a %fst) ('b %snd)) : 'S -> @p.fst 'a : 'S + +The special field annotation ``%@`` can be used on instructions +``PAIR``, ``LEFT`` and ``RIGHT``. It means to use the variable +name annotation in the stack as a field name for the constructed +element. Two examples with ``PAIR`` follows, notice the special +treatment of annotations with ``.``. + +:: + + PAIR %@ %@ + :: @x 'a : @y 'b : 'S -> (pair ('a %x) ('b %y)) : 'S + + PAIR %@ %@ + :: @p.x 'a : @p.y 'b : 'S -> @p (pair ('a %x) ('b %y)) : 'S + :: @p.x 'a : @q.y 'b : 'S -> (pair ('a %x) ('b %y)) : 'S + +Entrypoints +----------- + +The specification up to this point has been mostly ignoring existence +of entrypoints: a mechanism of contract level polymorphism. This +mechanism is optional, non intrusive, and transparent to smart +contracts that don't use them. This section is to be read as a patch +over the rest of the specification, introducing rules that apply only +in presence of contracts that make use of entrypoints. + +Defining and calling entrypoints +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Entrypoints piggyback on the constructor annotations. A contract with +entrypoints is basically a contract that takes a disjunctive type (a +nesting of ``or`` types) as the root of its input parameter, decorated +with constructor annotations. An extra check is performed on these +constructor annotations: a contract cannot define two entrypoints with +the same name. + +An external transaction can include an entrypoint name alongside the +parameter value. In that case, if there is a constructor annotation +with this name at any position in the nesting of ``or`` types, the +value is automatically wrapped into the according constructors. If the +transaction specifies an entrypoint, but there is no such constructor +annotation, the transaction fails. + +For instance, suppose the following input type. + +``parameter (or (or (nat %A) (bool %B)) (or %maybe_C (unit %Z) (string %C)))`` + +The input values will be wrapped as in the following examples. + +:: + + +------------+-----------+---------------------------------+ + | entrypoint | input | wrapped input | + +------------+-----------+---------------------------------+ + | %A | 3 | Left (Left 3) | + | %B | False | Left (Right False) | + | %C | "bob" | Right (Right "bob") | + | %Z | Unit | Right (Left Unit) | + | %maybe_C | Right "x" | Right (Right "x") | + | %maybe_C | Left Unit | Right (Left Unit) | + +------------+-----------+---------------------------------+ + | not given | value | value (untouched) | + | %BAD | _ | failure, contract not called | + +------------+-----------+---------------------------------+ + +The ``default`` entrypoint +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A special semantics is assigned to the ``default`` entrypoint. If the +contract does not explicitly declare a ``default`` entrypoint, then it +is automatically assigned to the root of the parameter +type. Conversely, if the contract is called without specifying an +entrypoint, then it is assumed to be called with the ``default`` +entrypoint. This behaviour makes the entrypoint system completely +transparent to contracts that do not use it. + +This is the case for the previous example, for instance. If a value is +passed to such a contract specifying entrypoint ``default``, then the +value is fed to the contract untouched, exactly as if no entrypoint +was given. + +A non enforced convention is to make the entrypoint ``default`` of +type unit, and to implement the crediting operation (just receive the +transferred tokens). + +A consequence of this semantics is that if the contract uses the +entrypoint system and defines a ``default`` entrypoint somewhere else +than at the root of the parameter type, then it must provide an +entrypoint for all the paths in the toplevel disjunction. Otherwise, +some parts of the contracts would be dead code. + +Another consequence of setting the entrypoint somewhere else than at +the root is that it makes it impossible to send the raw values of the +full parameter type to a contract. A trivial solution for that is to +name the root of the type. The conventional name for that is ``root``. + +Let us recapitulate this by tweaking the names of the previous example. + +``parameter %root (or (or (nat %A) (bool %B)) (or (unit %default) string))`` + +The input values will be wrapped as in the following examples. + +:: + + +------------+---------------------+-----------------------+ + | entrypoint | input | wrapped input | + +------------+---------------------+-----------------------+ + | %A | 3 | Left (Left 3) | + | %B | False | Left (Right False) | + | %default | Unit | Right (Left Unit) | + | %root | Right (Right "bob") | Right (Right "bob") | + +------------+---------------------+-----------------------+ + | not given | Unit | Right (Left Unit) | + | %BAD | _ | failure, contract not | + +------------+---------------------+-----------------------+ + +Calling entrypoints from Michelson +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Michelson code can also produce transactions to a specific entrypoint. + +For this, both types ``address`` and ``contract`` have the ability to +denote not just an address, but a pair of an address and an +entrypoint. The concrete notation is ``"address%entrypoint"``. +Note that ``"address"`` is strictly equivalent to ``"address%default"``, +and for clarity, the second variant is forbidden in the concrete syntax. + +When the ``TRANSFER_TOKENS`` instruction is called, it places the +entrypoint provided in the contract handle in the transaction. + +The ``CONTRACT t`` instruction has a variant ``CONTRACT %entrypoint +t``, that works as follows. Note that ``CONTRACT t`` is strictly +equivalent to ``CONTRACT %default t``, and for clarity, the second +variant is forbidden in the concrete syntax. + +:: + + +---------------+---------------------+------------------------------------------+ + | input address | instruction | output contract | + +---------------+---------------------+------------------------------------------+ + | "addr" | CONTRACT t | (Some "addr") if contract exists, has a | + | | | default entrypoint of type t, or has no | + | | | default entrypoint and parameter type t | + +---------------+---------------------+------------------------------------------+ + | "addr%name" | CONTRACT t | (Some "addr%name") if addr exists and | + +---------------+---------------------+ has an entrypoint %name of type t | + | "addr" | CONTRACT %name t | | + +---------------+---------------------+------------------------------------------+ + | "addr%_" | CONTRACT %_ t | None | + +---------------+---------------------+------------------------------------------+ + +Similarly, the ``SELF`` instruction has a variant ``SELF %entrypoint``, +that is only well-typed if the current contract has an entrypoint named ``%entrypoint``. + +- ``SELF %entrypoint`` + +:: + + :: 'S -> contract 'p : 'S + where contract 'p is the type of the entrypoint %entrypoint of the current contract + +Implicit accounts are considered to have a single ``default`` +entrypoint of type ``Unit``. + +JSON syntax +----------- + +Micheline expressions are encoded in JSON like this: + +- An integer ``N`` is an object with a single field ``"int"`` whose + value is the decimal representation as a string. + + ``{ "int": "N" }`` + +- A string ``"contents"`` is an object with a single field ``"string"`` + whose value is the decimal representation as a string. + + ``{ "string": "contents" }`` + +- A sequence is a JSON array. + + ``[ expr, ... ]`` + +- A primitive application is an object with two fields ``"prim"`` for + the primitive name and ``"args"`` for the arguments (that must + contain an array). A third optional field ``"annots"`` contains a + list of annotations, including their leading ``@``, ``%`` or ``:`` + sign. + + ``{ "prim": "pair", "args": [ { "prim": "nat", "args": [] }, { "prim": "nat", "args": [] } ], "annots": [":t"] }`` + +As in the concrete syntax, all domain specific constants are encoded as +strings. + +Examples +--------- + +Contracts in the system are stored as a piece of code and a global data +storage. The type of the global data of the storage is fixed for each +contract at origination time. This is ensured statically by checking on +origination that the code preserves the type of the global data. For +this, the code of the contract is checked to be of type +``lambda (pair 'arg 'global) -> (pair (list operation) 'global)`` where +``'global`` is the type of the original global store given on origination. +The contract also takes a parameter and returns a list of internal operations, +hence the complete calling convention above. The internal operations are +queued for execution when the contract returns. + +Empty contract +~~~~~~~~~~~~~~ + +The simplest contract is the contract for which the ``parameter`` and +``storage`` are all of type ``unit``. This contract is as follows: + +.. code-block:: michelson + + code { CDR ; # keep the storage + NIL operation ; # return no internal operation + PAIR }; # respect the calling convention + storage unit; + parameter unit; + + +Example contract with entrypoints +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following contract maintains a number in its storage. It has two +entrypoints ``add`` and ``sub`` to modify it, and the default +entrypoint, of type ``unit`` will reset it to ``0``. + +:: + + { parameter (or (or (nat %add) (nat %sub)) (unit %default)) ; + storage int ; + code { AMOUNT ; PUSH mutez 0 ; ASSERT_CMPEQ ; UNPAIR ; + IF_LEFT + { IF_LEFT { ADD } { SWAP ; SUB } } + { DROP ; DROP ; PUSH int 0 } ; + NIL operation ; PAIR } } + +Multisig contract +~~~~~~~~~~~~~~~~~ + +The multisig is a typical access control contract. The ownership of +the multisig contract is shared between ``N`` participants represented +by their public keys in the contract's storage. Any action on the +multisig contract needs to be signed by ``K`` participants where the +threshold ``K`` is also stored in the storage. + +To avoid replay of the signatures sent to the contract, the signed +data include not only a description of the action to perform but also +the address of the multisig contract and a counter that gets +incremented at each successful call to the contract. + +The multisig commands of :ref:`Tezos command line client ` +use this +smart contract. Moreover, `functional correctness of this contract has +been verified +`__ +using the Coq proof assistant. + + +.. code-block:: michelson + + parameter (pair + (pair :payload + (nat %counter) # counter, used to prevent replay attacks + (or :action # payload to sign, represents the requested action + (pair :transfer # transfer tokens + (mutez %amount) # amount to transfer + (contract %dest unit)) # destination to transfer to + (or + (option %delegate key_hash) # change the delegate to this address + (pair %change_keys # change the keys controlling the multisig + (nat %threshold) # new threshold + (list %keys key))))) # new list of keys + (list %sigs (option signature))); # signatures + + storage (pair (nat %stored_counter) (pair (nat %threshold) (list %keys key))) ; + + code + { + UNPAIR ; SWAP ; DUP ; DIP { SWAP } ; + DIP + { + UNPAIR ; + # pair the payload with the current contract address, to ensure signatures + # can't be replayed across different contracts if a key is reused. + DUP ; SELF ; ADDRESS ; CHAIN_ID ; PAIR ; PAIR ; + PACK ; # form the binary payload that we expect to be signed + DIP { UNPAIR @counter ; DIP { SWAP } } ; SWAP + } ; + + # Check that the counters match + UNPAIR @stored_counter; DIP { SWAP }; + ASSERT_CMPEQ ; + + # Compute the number of valid signatures + DIP { SWAP } ; UNPAIR @threshold @keys; + DIP + { + # Running count of valid signatures + PUSH @valid nat 0; SWAP ; + ITER + { + DIP { SWAP } ; SWAP ; + IF_CONS + { + IF_SOME + { SWAP ; + DIP + { + SWAP ; DIIP { DIP { DUP } ; SWAP } ; + # Checks signatures, fails if invalid + CHECK_SIGNATURE ; ASSERT ; + PUSH nat 1 ; ADD @valid } } + { SWAP ; DROP } + } + { + # There were fewer signatures in the list + # than keys. Not all signatures must be present, but + # they should be marked as absent using the option type. + FAIL + } ; + SWAP + } + } ; + # Assert that the threshold is less than or equal to the + # number of valid signatures. + ASSERT_CMPLE ; + DROP ; DROP ; + + # Increment counter and place in storage + DIP { UNPAIR ; PUSH nat 1 ; ADD @new_counter ; PAIR} ; + + # We have now handled the signature verification part, + # produce the operation requested by the signers. + NIL operation ; SWAP ; + IF_LEFT + { # Transfer tokens + UNPAIR ; UNIT ; TRANSFER_TOKENS ; CONS } + { IF_LEFT { + # Change delegate + SET_DELEGATE ; CONS } + { + # Change set of signatures + DIP { SWAP ; CAR } ; SWAP ; PAIR ; SWAP }} ; + PAIR } + + + +Full grammar +------------ + +:: + + ::= + | + | + | + | Unit + | True + | False + | Pair ... + | Left + | Right + | Some + | None + | { ; ... } + | { Elt ; ... } + | instruction + ::= + | [0-9]+ + ::= + | + | - + ::= + | "*" + ::= + | \" + | \r + | \n + | \t + | \b + | \\ + | [^"\] + ::= + | 0x[0-9a-fA-F]+ + ::= + | { ... } + | DROP + | DROP + | DUP + | DUP + | SWAP + | DIG + | DUG + | PUSH + | SOME + | NONE + | UNIT + | NEVER + | IF_NONE { ... } { ... } + | PAIR + | PAIR + | CAR + | CDR + | UNPAIR + | UNPAIR + | LEFT + | RIGHT + | IF_LEFT { ... } { ... } + | NIL + | CONS + | IF_CONS { ... } { ... } + | SIZE + | EMPTY_SET + | EMPTY_MAP + | EMPTY_BIG_MAP + | MAP { ... } + | ITER { ... } + | MEM + | GET + | GET + | UPDATE + | UPDATE + | IF { ... } { ... } + | LOOP { ... } + | LOOP_LEFT { ... } + | LAMBDA { ... } + | EXEC + | APPLY + | DIP { ... } + | DIP { ... } + | FAILWITH + | CAST + | RENAME + | CONCAT + | SLICE + | PACK + | UNPACK + | ADD + | SUB + | MUL + | EDIV + | ABS + | ISNAT + | INT + | NEG + | LSL + | LSR + | OR + | AND + | XOR + | NOT + | COMPARE + | EQ + | NEQ + | LT + | GT + | LE + | GE + | SELF + | SELF_ADDRESS + | CONTRACT + | TRANSFER_TOKENS + | SET_DELEGATE + | CREATE_CONTRACT { ... } + | IMPLICIT_ACCOUNT + | VOTING_POWER + | NOW + | LEVEL + | AMOUNT + | BALANCE + | CHECK_SIGNATURE + | BLAKE2B + | KECCAK + | SHA3 + | SHA256 + | SHA512 + | HASH_KEY + | SOURCE + | SENDER + | ADDRESS + | CHAIN_ID + | TOTAL_VOTING_POWER + | PAIRING_CHECK + | SAPLING_EMPTY_STATE + | SAPLING_VERIFY_UPDATE + | TICKET + | READ_TICKET + | SPLIT_TICKET + | JOIN_TICKETS + | OPEN_CHEST + ::= + | + | option + | list + | set + | operation + | contract + | ticket + | pair ... + | or + | lambda + | map + | big_map + | bls12_381_g1 + | bls12_381_g2 + | bls12_381_fr + | sapling_transaction + | sapling_state + | chest + | chest_key + ::= + | unit + | never + | bool + | int + | nat + | string + | chain_id + | bytes + | mutez + | key_hash + | key + | signature + | timestamp + | address + | option + | or + | pair ... + + +Reference implementation +------------------------ + +The language is implemented in OCaml as follows: + +- The lower internal representation is written as a GADT whose type + parameters encode exactly the typing rules given in this + specification. In other words, if a program written in this + representation is accepted by OCaml's typechecker, it is guaranteed + type-safe. This is of course also valid for programs not + handwritten but generated by OCaml code, so we are sure that any + manipulated code is type-safe. + + In the end, what remains to be checked is the encoding of the typing + rules as OCaml types, which boils down to half a line of code for + each instruction. Everything else is left to the venerable and well + trusted OCaml. + +- The interpreter is basically the direct transcription of the + rewriting rules presented above. It takes an instruction, a stack and + transforms it. OCaml's typechecker ensures that the transformation + respects the pre and post stack types declared by the GADT case for + each instruction. + + The only things that remain to be reviewed are value dependent + choices, such as we did not swap true and false when + interpreting the IF instruction. + +- The input, untyped internal representation is an OCaml ADT with + only 5 grammar constructions: ``String``, ``Int``, ``Bytes``, ``Seq`` and + ``Prim``. It is the target language for the parser, since not all + parsable programs are well typed, and thus could simply not be + constructed using the GADT. + +- The typechecker is a simple function that recognizes the abstract + grammar described in section X by pattern matching, producing the + well-typed, corresponding GADT expressions. It is mostly a checker, + not a full inferrer, and thus takes some annotations (basically the + input and output of the program, of lambdas and of uninitialized maps + and sets). It works by performing a symbolic evaluation of the + program, transforming a symbolic stack. It only needs one pass over + the whole program. + + Here again, OCaml does most of the checking, the structure of the + function is very simple, what we have to check is that we transform a + ``Prim ("If", ...)`` into an ``If``, a ``Prim ("Dup", ...)`` into a + ``Dup``, etc. diff --git a/docs/011/proof_of_stake.rst b/docs/011/proof_of_stake.rst new file mode 100644 index 000000000000..b7ef4fdb4956 --- /dev/null +++ b/docs/011/proof_of_stake.rst @@ -0,0 +1,203 @@ +Proof-of-stake +============== + +Overview +-------- + +:doc:`The consensus algorithm ` in Tezos is based on the +*proof-of-stake* mechanism. Proof-of-stake means that participants +in the consensus algorithm are chosen in function of their stake (the +amount of tokens a participant has). The same mechanism is used in the +Tezos :doc:`governance `. + +If one does not have enough stake to participate on its own or does not want to +set up the needed infrastructure, (s)he can use :ref:`delegation +`. Therefore, in Tezos, it is the :ref:`delegates` +that may participate in consensus. Delegates' rights to participate are +determined by a `follow-the-coin strategy +`_. This +procedure is random, in that its result cannot be predicted too much in advance. +The :ref:`randomness` is obtained from information already found on the +blockchain. Thus, the procedure is also deterministic: delegates' rights are +uniquely determined from the random element. + +Delegation +---------- + +A *delegate* is any :ref:`implicit account ` registered as +such by emitting a delegate registration operation. + +Any :ref:`accounts ` (implicit or originated) can specify a delegate +through a delegation operation. + + +Any account can change or revoke its delegate at any time. However, the change +only becomes effective after ``PRESERVED_CYCLES + 2`` :ref:`cycles `. +The value ``PRESERVED_CYCLES`` is a +:ref:`protocol constant `. + +A delegate participates in consensus and in governance with a weight +proportional with their delegated stake, which includes the balances of +all the accounts that delegate to it, and also the balance of the +delegate itself. + +Delegates place security deposits that may be forfeited in case they do not +follow (some particular rules of) the protocol. Security deposits are deduced +from the delegates' own balance. Therefore delegates may be subject to +:ref:`over-delegation`. + + +Active and passive delegates +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. _active_delegate_011: + +A delegate can be marked as either active or passive. A passive +delegate cannot participate in the consensus algorithm. + +A delegate is marked as active at its registration. + +A delegate becomes passive for cycle ``n`` when they +fail to participate in the consensus algorithm in +the past ``PRESERVED_CYCLES`` cycles, that is, in cycles ``n-1``, +``n-2``, ..., ``n - PRESERVED_CYCLES``. + +Delegates' rights selection +--------------------------- + +Tezos being proof-of-stake, the delegates' rights are selected at random based on their +stake. In theory, it would be possible to give each token a serial number and +track the specific tokens assigned to specific delegates. However, it would be +too demanding of nodes to track assignments at such a granular level. Instead, +Tezos works with *sets of tokens* which are called *rolls*. + +.. _roll_pos_011: + +Rolls +^^^^^ + +A roll holds ``TOKENS_PER_ROLL`` tokens. When tokens are moved, or a delegate for an +account is changed, the rolls change delegate according to the following +algorithm. + +Each delegate has a stack of roll identifiers plus some "change" which is always +an amount smaller than ``TOKENS_PER_ROLL``. When tokens are moved from one +delegate to the other, first, the change is used. If it is not enough, rolls +need to be "broken" which means that they move from the delegate stack to a +global, unallocated, roll stack. This is done until the amount is covered, and +some change possibly remains. + +Then, the other delegate is credited. First, the amount is added to the +"change". If it becomes greater than ``TOKENS_PER_ROLL``, then rolls are +unstacked from the global unallocated roll stack onto the delegate stack. If the +global stack is empty, a fresh roll is created. + +This preserves the property that if the delegate is changed through several +transactions, the roll assignment is preserved, even if each operation moves +less than a full roll. + +The advantage of tracking tokens in this way is that a delegate creating a +malicious fork cannot easily change the specific rolls assigned to them, even if +they control the underlying tokens and shuffle them around. + +.. _random_seed_011: + +Random seed +^^^^^^^^^^^ + +Each cycle ``n`` is associated with a random seed. The random seed for cycle +``n`` is a 256-bit number generated at the very end of cycle ``n-1`` from +*nonces* to which delegates commit during cycle ``n-2``. One block out of every +``BLOCKS_PER_COMMITMENT`` can contain a commitment. A commitment is the hash of +a nonce. The commitment is generated by the block proposer and is included in +the block header. + +The committed nonce must be revealed by the original block proposer during cycle +``n-1`` under penalty of forfeiting the rewards and fees of the block that +included the commitment. The associated security deposit is not forfeited. + +A *nonce revelation* is an operation, and multiple nonce revelations can thus be +included in a block. A reward ``SEED_NONCE_REVELATION_TIP`` is given for +including a revelation. Revelations are free operations which do not compete +with transactions for block space. Up to ``MAX_ANON_OPS_PER_BLOCK`` revelations, +wallet activations and denunciations can be contained in any given block. + +The seed for cycle ``n`` is obtained as follows: the seed of cycle ``n-1`` is +hashed with a constant and then with each nonce revealed in cycle ``n-1``. + +.. _rights_011: + +Slot selection +^^^^^^^^^^^^^^ + +To return to the rights selection mechanism, we first introduce a new +terminology, *roll snapshot*, to denote the stored (in the +:ref:`context `) distribution of rolls for a given block. Roll +snapshots are taken (and stored) every ``BLOCKS_PER_ROLL_SNAPSHOT`` +blocks. + +The delegates' rights at a given level and for a particular role in +the protocol are expressed in terms of *slots* that the delegate +receives for that role. The slot owner is obtained by running a PRNG +(pseudo-random number generator) with the following input: + +- the level +- the role (a string) +- the slot (a non-negative integer) + +Let `n` be the cycle the level belongs to. +The seed of the PRNG is the :ref:`random seed ` associated with cycle ``n-PRESERVED_CYCLES``. +The PRNG first selects a snapshot from cycle ``n-PRESERVED_CYCLES-2`` and then it selects a roll in the selected snapshot. +The slot owner is then the roll owner. + +.. _protocol_constants_011: + +Protocol constants +------------------ + +Protocols are parameterized by several parameters called *protocol constants*, which may vary from one protocol to another or from one network to another (for instance, test networks move faster). +An example of a parameter is the number of tez constituting a roll. This number is given by the constant named ``TOKENS_PER_ROLL``. + +The list of protocol constants can be found in the API of the `Constants module `__. + +The values of protocol constants can be found using a :ref:`specific RPC call `, as shown in :ref:`this example `. + +In particular, the protocol constants related to the proof-of-stake mechanism are detailed below. + +.. _ps_constants_011: + +Proof-of-stake parameters +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. list-table:: + :widths: 55 25 + :header-rows: 1 + + * - Parameter name + - Parameter value + * - ``BLOCKS_PER_CYCLE`` + - 8192 blocks + * - ``PRESERVED_CYCLES`` + - 5 cycles + * - ``BLOCKS_PER_COMMITMENT`` + - 64 blocks + * - ``MAX_ANON_OPS_PER_BLOCK`` + - 132 revelations + * - ``SEED_NONCE_REVELATION_TIP`` + - 1/8 ꜩ + * - ``TOKENS_PER_ROLL`` + - 8,000 ꜩ + * - ``BLOCKS_PER_ROLL_SNAPSHOT`` + - 512 blocks + + +Further External Resources +-------------------------- + +The original design of the proof-of-stake mechanism in Tezos can be +found in the `whitepaper +`_. + +Another presentation of the Tezos' proof-of-stake mechanism can be +found in the `Tezos agora wiki entry +`_. diff --git a/docs/011/sapling.rst b/docs/011/sapling.rst new file mode 100644 index 000000000000..e31087bbcc81 --- /dev/null +++ b/docs/011/sapling.rst @@ -0,0 +1,496 @@ +**The features described in this page are experimental and have not undergone any security review.** + +Sapling integration +=================== + +Sapling is a protocol enabling privacy-preserving transactions of fungible +tokens in a decentralised +environment. It was designed and implemented by the Electric Coin +Company as the last iteration over a series of previous protocols and +academic works starting with the `Zerocoin seminal +paper `_. + +The reference implementation of Sapling, +`librustzcash `_, was +integrated in the Tezos codebase during 2019. It will be proposed as +part of a protocol amendment during 2020. + +Librustzcash and the Tezos integration implement the protocol +described in this `specification +`_, version 2020.1.0. + + +Sapling +------- + +Keys +~~~~ + +Sapling offers a rich set of keys, each allowing different operations. +A `spending key` allows to spend tokens so if it is lost or +compromised the tokens could remain locked or be stolen. +From a spending key it is possible to derive a corresponding `viewing +key` which allows to view all incoming and outgoing transactions. +The viewing key allows the owner of the tokens to check their balance +and transaction history so if compromised there is a complete loss of +privacy. +On the other hand a viewing key can willingly be shared with a third +party, for example with an auditor for regulatory compliance purposes. + +A viewing key can also derive several diversified `addresses`. +An address can be used to receive funds, much like the address of an +implicit account. + +Additionally `proving keys` can be used to allow the creation of proofs, +thus revealing private information, without being able to spend funds. +They are useful for example in case the spending key is stored in a +hardware wallet but we'd like to use our laptop to craft the +transaction and produce the zero-knowledge proofs, which are +computationally too intensive for an embedded device. + +More details can be found in the `specification document +`_. + +Shielded transactions +~~~~~~~~~~~~~~~~~~~~~ + +Transactions use Bitcoin's UTXO model with the important difference that each +input and output, instead of containing an amount and an address, +are just cryptographic `commitments`. +In order to avoid double spends, it's important to be able to check +that a commitment has not already been spent. In Bitcoin we just need to +check if an output is also later used as an input to verify if it's +already spent. In Sapling however we can't know because inputs are not +linked to outputs. +For this reason for each input of a transaction, the owner must also +publish a `nullifier`, which invalidates it. The nullifier can only be +produced by the owner of a commitment and it's deterministic so that +everybody can check that it hasn't been already published. +Note however that it is not possible to infer which commitment has +been nullified. +Transactions of this form are privacy preserving and are referred to +as `shielded`, because they reveal neither the amount, the sender nor +the receiver. + +The existing set of transactions is referred to as the `shielded pool`. +Unlike Bitcoin, where everybody can compute the set of unspent +outputs of every user, in Sapling only the owner of a viewing key can +find their outputs and verify that they are not already spent. +For this reason, to an external +observer, the shielded pool is always increasing in size and the more +transactions are added the harder it is to pinpoint the commitments +belonging to a user. + +When we spend a commitment there is some additional information that +we need to transmit to the recipient in order for them to spend the +corresponding output. +This data is encrypted under a symmetric key resulting from a +Diffie-Hellman key exchange using the recipient address and an +ephemeral key. +In principle this `ciphertext` can be transmitted off-chain as it's +not needed to verify the integrity of the pool. For convenience, in +Tezos, it is stored together with the commitment and the nullifier on +chain. + +For reasons of efficiency the commitments are stored in an incremental +`Merkle tree `_ which +allows for compact proofs of membership. The root of the tree is all +that is needed to refer to a certain state of the shielded pool. + +In order to ensure the correctness of a transaction, given that there +is information that we wish to remain secret, the spender must also +generate proofs that various good properties are true. +Thanks to the use of `SNARKs `_ +these proofs are very succinct in size, fast to verify and they don't +reveal any private information. + +This model of transaction adapts elegantly to the case when we need to +mint or burn tokens, which is needed to shield or unshield from a +transparent token. +It suffices to add more values in the outputs than in the inputs +to mint and to have more in inputs than outputs to burn. + +Privacy guarantees +~~~~~~~~~~~~~~~~~~ + +We explained that the shielded pool contains one commitment for each +input (spent or not), and one nullifier for each spent input. +These cryptographic commitments hide the amount and the owner of the +tokens they represent. +Additionally commitments are unlinkable meaning that we can not deduce +which input is spent to create an output. + +It should be noted that the number of inputs and outputs of a +transaction is public, which could help link a class of +transactions. This problem can be mitigated by adding any number of +dummy inputs or outputs at the cost of wasting some space. + +The shielded pool communicates with the public ledger by minting and +burning shielded tokens in exchange for public coins. +Therefore going in and out of the shielded pool is public: we know +which address shielded or unshielded and how much. +We can among other things infer the total number of shielded coins. + +Timing and network information can also help to deduce some private +information. +For example by observing the gossip network we might learn the IP +address of somebody that is submitting a shielded transaction. +This can be mitigated by using `TOR +`_. + +Good practices +~~~~~~~~~~~~~~ + +When blending in a group of people, one should always pay attention to +the size and the variety of the group. + +We recommend two good practices. First, do not originate a second +contract if another one has the same functionalities, it will split +the anonymity set. + +Second, remember that shielding and unshielding are public operations. +A typical anti-pattern is to shield from tz1-alice 15.3 tez, and then +unshield 15.3 tez to tz1-bob. It's fairly clear from timing and +amounts that Alice transferred 15.3 tez to Bob. +To decorrelate the two transfers it is important to change the +amounts, let some time pass between the two and perform the +transactions when there is traffic in the pool. +Similar problems exist in ZCash and they are illustrated in this +introductory `blog post +`_. + +There are a number of more sophisticated techniques to deanonymise +users using timing of operations, network monitoring, side-channels on +clients and analysis of number of inputs/outputs just to mention a few +(`A fistful of Bitcoins +`_ is a good +first read). +We advice users to be familiar with the use of the TOR network and to +use clients developed specifically to protect their privacy. + + +Tezos integration +----------------- + +Michelson: verify update +~~~~~~~~~~~~~~~~~~~~~~~~ + +We introduce two new Michelson types `sapling_state` and +`sapling_transaction`, and two instructions called +`SAPLING_VERIFY_UPDATE` and `SAPLING_EMPTY_STATE` +(see the :doc:`Michelson reference` +for more details). +`SAPLING_EMPTY_STATE` pushes an empty `sapling_state` on the stack. +`SAPLING_VERIFY_UPDATE` takes a transaction and a state and returns an +option type which is Some (updated +state and a balance) if the transaction is correct, None otherwise. +A transaction has a list of inputs, outputs, a signature, a balance, +and the root of the Merkle tree containing its inputs. +The verification part checks the zero-knowledge proofs of all inputs +and outputs of the transaction, which guarantee several properties of +correctness. +It also checks a (randomised) signature associated with each input +(which guarantees that the owner forged the transaction), and the +signature that binds the whole transaction together and guarantees the +correctness of the balance. +All the signatures are over the hash of the data that we wish to sign +and the hash function used is Blake2-b, prefixed with the anti-replay string. +The anti-replay string is the the concatenation of the chain id and +the smart contract address. The same string has to be used by the client for +signing. + +Verify_update also checks that the root of the Merkle tree appears in +one of the past states and that the nullifiers are not already +present (i.e. no double spending is happening). +If one of the checks fails the instruction returns None. + +Otherwise the function adds to the new state the nullifiers given with each inputs +and adds the outputs to the Merkle tree, which will produce a new root. +It should be noted that it is possible to generate transactions +referring to an old root, as long as the inputs used were present in +the Merkle tree with that root and were not spent after. +In particular the protocol keeps 120 previous roots and guarantees +that roots are updated only once per block. +Considering 1 block per minute and that each block contains at least +one call to the same contract, a client has 2 hours to have its +transaction accepted before it is considered invalid. + +The nullifiers are stored in a set. The ciphertexts and other relevant +information linked to the commitment of the Merkle tree are +stored in a map indexed by the position of the commitment in the +Merkle tree. + +Lastly the instruction pushes the updated state and the balance as an option +on the stack. + +Example contracts +~~~~~~~~~~~~~~~~~ + +Shielded tez +^^^^^^^^^^^^ + +An example contract to have a shielded tez with a 1 to 1 conversion to +tez is available in the tests of `lib_sapling`. + +Simple Vote Contract +^^^^^^^^^^^^^^^^^^^^ + +One might think to use Sapling to do private voting. +It is possible to adapt shielded transactions to express preferences. +**Note that this is not what Sapling is designed for and it doesn't provide the same properties as an actual private voting protocol.** +A natural naive idea is the following. +Suppose we want a set of users to express a preference for option A or +B, we can generate two Sapling keys with two addresses that are +published and represent the two options. +The contract lets each user create a token which represents one vote +that can then be transferred to address A or B. +Using the published viewing keys everyone can check the outcome of the +vote. +**However note that a transaction can be replayed and we can see the balance of A or B going up. +This system does not offer ballot privacy. +Therefore one should ensure that the vote he is casting cannot be linked to him. +It is possible that the practical situation makes this usable but we recommend in general not to use +it for any important vote.** +Note that using a random elliptic curve element as incoming viewing key allows to generate a +dummy address that cannot be spent. This eases the counting of the votes. +To ensure that the ivk does not correspond to a normal address with spending key, one +can use the Fiat-Shamir heuristic. + + +Fees issue +~~~~~~~~~~ + +We have an additional privacy issue that Z-cash doesn't have. When +interacting with a shielded pool we interact with a smart contract +with a normal transaction and therefore have to pay fees from an +implicit account. +One could guess that private transactions whose fees are paid by the +same implicit account are from the same user. +This can be mitigated by making a service that act as a proxy by +forwarding the user transactions and paying it fees. The user would +then include in the transaction a shielded output for the service that +covers the fees plus a small bonus to pay the service. +This output can be open by the service before sending the transaction +to check that there is enough money to cover its fees. As for Z-cash, +users interacting with the proxy should use TOR or mitigate network +analysis as they wish. + +Gas, storage and costs +~~~~~~~~~~~~~~~~~~~~~~ + +Gas evaluation is not yet done. + +RPCs +~~~~ + +There are two Sapling RPCs under the prefix `context/sapling`. +`get_size` returns a pair with the size of the set of commitments +and the size of the set of nullifiers. +`get_diff` takes two optional starting offsets `cm_from` and `nf_from` +and returns the sapling state that was added from the offsets to the +current size. In particular it returns three lists, commitments, +ciphertexts from position `cm_from` up to the last one added and +nullifiers, from `nf_from` to the last one added. +Additionally it returns the last computed root of the merkle tree so +that a client updating its tree using the diff can verify the +correctness of the result. + +Client +~~~~~~ + +Wallet +^^^^^^ + +tezos-client supports Sapling keys and can send +shielded transactions to smart contracts. + +The client supports two ways to generate a new Sapling spending key. +It can be generated from a mnemonic using `BIP39 +`_, so +that it can be recovered in case of loss using the mnemonic. +Alternatively it is possible to derive new keys from existing ones +using `ZIP32 +`_, a Sapling +variant of `BIP32 +`_ for +hierarchical deterministic wallets. As usual, in this case it is +important to note the derivation path of the key to be able to recover +it in case of loss. +At the moment there is no hardware wallet support, keys are stored in +`~/.tezos-client/sapling_keys` by default encrypted with a password. +**Users should take care to backup this file.** + +The client can also derive addresses from viewing keys. +By default addresses are generated using an increasing counter called +the address index. Not all indexes corresponds to valid addresses for +each key so it is normal to see an increasing counter that +occasionally skips a few position. + +Because for now the only support for Sapling keys is to interact with +smart contracts, the client binds each newly generated key to a +specific smart contract address. + +Operations +^^^^^^^^^^ + +The client also facilitates the creation of shielded transactions and +their transfer as arguments of smart contracts. +For now there is seamless integration to send transactions to the +reference shielded-tez contract and we are planning to support a +larger class of contracts. + +For the shielded-tez smart contract, the client supports shielding, +unshielding and shielded transactions. +In the case of shielded transactions there are two commands, one to +forge a transaction and save it to file and one to submit it to the +smart contract. +The idea is that a user should not use their own transparent tz{1,2,3} +address to submit a shielded address but rather have a third party +inject it. + +Message argument +^^^^^^^^^^^^^^^^ +Sapling also allows to send an arbitrary encrypted message attached +to an output. +The message size has to be fixed by pool for privacy reasons. +For now it is fixed overall at eight bytes. An incorrect message length +will raise a failure in our client and the protocol will reject the +transaction. Our client adds a default zero's filled message of the +right length. If a message is provided with the --message option, +the client will pad it or truncate it if necessary. A warning message +is printed only if the user's message is truncated. + + +Code base +~~~~~~~~~ + +The current code-base is organized in three main components. +There is a core library called `lib_sapling` which binds `librustzcash`, +adds all the data structures necessary to run the sapling +protocol and includes a simple client and baker. +Under the protocol directory there is a `lib_client_sapling` library +which implements a full client capable of handling Sapling keys and +forging transactions. +Lastly in the protocol there is a efficient implementation of the +Sapling storage, in the spirit of `big_map`s, and the integration of +`SAPLING_VERIFY_UPDATE` in the Michelson interpreter. + +Protocol +^^^^^^^^ + +In order to export the Sapling library to the protocol we first need +to expose it through the environment that sandboxes the protocol. +The changes under `src/lib_protocol_environment` are simple but very +relevant as any change of the environment requires a manual update of the +Tezos node. This changes are part of version V1 of the environment +while protocols 000 to 006 depends on version V0. + +There are two main changes to Tezos' economic protocol, the storage +for Sapling and the addition of `SAPLING_VERIFY_UPDATE` to the Michelson +interpreter. + +Given that the storage of a Sapling contract can be substantially +large, it is important to provide an efficient implementation. +Similarly to what it's done for big_maps, the storage of Sapling can't +be entirely deserialized and modified in memory but only a diff of the +changes is kept by the interpreter and applied at the end of each +smart contract call. + +In the Michelson interpreter two new types are added, `sapling_state` and +`sapling_transaction`, and the instruction `SAPLING_VERIFY_UPDATE`. + +Client +^^^^^^ + +Under `lib_client_sapling` there is the client integration +with the support for Sapling keys and forging of transactions. +The main difference from the existing Tezos client is the need for the +Sapling client to keep an additional state, for each contract. +Because Sapling uses a UTXO model it is necessary for a client to +compute the set of unspent outputs in order to forge new transactions. +Computing this set requires scanning all the state of a contract which +can be expensive. +For this reason the client keeps a local state of the unspent outputs +after the last synchronization and updates it before performing any +Sapling command. +The update is done using the RPCs to recover the new updates since the +last known position. + +The state of all sapling contracts is stored in +`~/.tezos-client/sapling_states`. This file can be regenerated from +the chain in case of loss. However disclosure of this file will reveal +the balance and the unspent outputs of all viewing keys. + +Memo +^^^^^^ + +Sapling offers the possibility to add an arbitrary memo to any +created output. The memo is encrypted and available to anyone +owning the outgoing viewing key or the spending key. +For privacy reasons the size of the memo is fixed per contract +and it is chosen at origination time. +A transaction containing an output with a different memo-size +will be rejected. + +Sandbox tutorial +~~~~~~~~~~~~~~~~ + +As usual it's possible to test the system end-to-end using the +:doc:`../user/sandbox`. +After having set up the sandbox and originated the contract, a good +way to get familiar with the system is to generate keys and then +perform the full cycle of shielding, shielded transfer and +unshielding. + +:: + + # set up the sandbox + ./src/bin_node/tezos-sandboxed-node.sh 1 --connections 0 & + eval `./src/bin_client/tezos-init-sandboxed-client.sh 1` + tezos-activate-alpha + + # originate the contract with its initial empty sapling storage, + # bake a block to include it. + # { } represents an empty Sapling state. + tezos-client originate contract shielded-tez transferring 0 from bootstrap1 \ + running src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract.tz \ + --init '{ }' --burn-cap 3 & + tezos-client bake for bootstrap1 + + # as usual you can check the tezos-client manual + tezos-client sapling man + + # generate two shielded keys for Alice and Bob and use them for the shielded-tez contract + # the memo size has to be indicated + tezos-client sapling gen key alice + tezos-client sapling use key alice for contract shielded-tez --memo-size 8 + tezos-client sapling gen key bob + tezos-client sapling use key bob for contract shielded-tez --memo-size 8 + + # generate an address for Alice to receive shielded tokens. + tezos-client sapling gen address alice + zet1AliceXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # Alice's address + + + # shield 10 tez from bootstrap1 to alice + tezos-client sapling shield 10 from bootstrap1 to zet1AliceXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX using shielded-tez --burn-cap 2 & + tezos-client bake for bootstrap1 + tezos-client sapling get balance for alice in contract shielded-tez + + # generate an address for Bob to receive shielded tokens. + tezos-client sapling gen address bob + zet1BobXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # Bob's address + + # forge a shielded transaction from alice to bob that is saved to a file + tezos-client sapling forge transaction 10 from alice to zet1BobXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX using shielded-tez + + # submit the shielded transaction from any transparent account + tezos-client sapling submit sapling_transaction from bootstrap2 using shielded-tez --burn-cap 1 & + tezos-client bake for bootstrap1 + tezos-client sapling get balance for bob in contract shielded-tez + + # unshield from bob to any transparent account + tezos-client sapling unshield 10 from bob to bootstrap1 using shielded-tez --burn-cap 1 + ctrl+z # to put the process in background + tezos-client bake for bootstrap1 + fg # to put resume the transfer diff --git a/docs/011/timelock.rst b/docs/011/timelock.rst new file mode 100644 index 000000000000..7724081f02e2 --- /dev/null +++ b/docs/011/timelock.rst @@ -0,0 +1,129 @@ +Time locked Michelson against Block Producer Extractable Value +============================================================== + + +Block Producer Extractable Value +-------------------------------- + +We aim at tackling the issue known through +the unfortunate misnomer of "generalized front running", described +for instance in `here `__. + +Observing a transaction before it is actually included in the chain +can give an advantage to a trader against another one. Ultimately, +this means block producers can extract a rent from the system +as they have the ability to choose and order transactions in a block. +This is sometimes referred to, in proof-of-work networks like Ethereum as +`Miner Extractable Value `_ or MEV for shorts. +We refer to it as BPEV, for "Block producer extractable value" +or "Baker pecuniary extractable value", at the reader's preference. +We also note that the term "front-running" is regrettable as it can mislead people +into thinking there is a fiduciary relationship between block producers +and transaction emitters where, in fact, none exists unless explicitly contracted into. + +For example, upon receiving a transaction, a baker could craft a block including +this transaction and one of his such that the sequential execution of these +two transactions guarantees a gain to the baker. + +Timelock +-------- + +We propose a solution to alleviate this issue which is relatively easy to implement +and is based on time lock encryption +(see +`Timelock puzzles and timed release Crypto `_ +for more details). + +Time lock encryption allows to encrypt a message such that it can be +decrypted in two ways. +Either the author of the ciphertext produces a plaintext +(and a proof of correct decryption) +by providing a secret trapdoor (the factorization of an RSA modulus in our case). +Otherwise a sequential computation can decrypt the ciphertext after a computation +requiring $T$ sequential operations (modular squaring in our case), +for some pre-determined constant :math:`T`. + +In addition, a proof of the correctness of the decryption can also be produced and checked in sub linear time ($\log T$ in our case). + +By experimentally measuring the time the sequential operation takes +on available hardware using optimized implementation, we can estimate +a rough conversion (or a bound in our case) between the constant $T$ and +wall clock time. +We also note that the `VDF alliance `_ has been working on producing an ASIC for squaring in an RSA group to +ensure a level playing field in terms of computational speed. + +An implementation of the timelock puzzle +and proof scheme is available in :src:`src/lib_crypto/timelock.mli` inspired from +a proof of concept available +`here `__. + +General principle +----------------- + +To limit BPEV, we introduce in Michelson an opcode (``OPEN_CHEST``) and two types (``chest`` and ``chest_key``) allowing +timelock-encrypted values to be used inside a Michelson contract. + +The typical usage pattern would be as follows: + +1. In a first period, a contract collects user-submitted and timelock encrypted Michelson values along with some valuable deposit, such as tez. +2. In a second period, after the values are collected, the contract collects from users a decryption of the value they submitted alongside with a proof that the decryption is correct. +3. In a third period, if any value remains undecrypted, anyone can claim part of the deposit by submitting a decryption of they value, with the other part of the deposit being burnt. Different penalties can be assessed depending on whether the user merely failed to submit a decryption for their value, or if they also intentionally encrypted invalid data. Different rewards can be distributed for submitting a correct decryption. The third period needs to be long enough so that people have enough time to perform the timelock decryption. +4. Finally, the contract can compute some function of all the decrypted data. + +There is generally no incentive for users not to provide +the decryption of their data and thus the third period generally does not need +to take place. However, the second period needs to be long enough so that bakers +cannot easily censor submission of the decryption in a bid to later claim the reward. +Burning a part of the deposit also limits grieving attacks where a user gets back +their whole deposit by providing the decryption, but in a way that delays everyone else. + +Cryptographic principles +------------------------ + +Users first generate a RSA modulus and a symmetric encryption key. +They use authenticated encryption to encrypt a packed Michelson value (an array of bytes computed with ``PACK``) +and encrypt that encryption key using a timelock puzzle. +They then combine the RSA modulus, the timelocked symmetric key, the constant T +and the encrypted value as a single value as well (called chest in our library in :src:`src/lib_crypto`). + +A proof of decryption can be the symmetric key itself. +However, a malicious user could propose an authenticated ciphertext that does yield a valid value +even when decrypted with the symmetric key that was indeed time locked. +To avoid this threat, an opening (called +the chest_key in our library) includes the symmetric key and +a proof that the symmetric key proposed is indeed the one hidden in the timelock puzzle. +In this way we can differentiate whether the chest or the chest key was proposed by a +malicious user. + +Finally, our library exposes an ``open_chest`` function taking a chest, a chest key and +produces either the underlying plaintext or indicates that the chest or the chest key is +malicious. + +Proposed opcode and types +--------------------------- + +To expose the features added by our library, we introduce the following Michelson types: + +- ``chest``, which represents timelocked arbitrary bytes with the + necessary public parameters to open it. +- ``chest_key``, which represents the decryption key, + alongside with a proof that the key is correct. + +and the following opcode: + +``unlock :: chest_key → chest → time →or (bytes, bool)`` + +If everything is correct it pushes +``Left bytes`` on top of the stack where bytes are +cryptographically guaranteed to be the bytes the chest provider timelocked. +If the ciphertext does not decrypt under the symmetric key that was timelocked, it pushes on the stack +``Right False`` +If the provided symmetric key was not the one timelocked +(which we detect thanks to the timelock proof), +it pushes on the stack ``Right True``. +Note that we are using an authenticated encryption scheme, +so we can detect if someone provides a wrong key while fooling the time lock proof. +This is doable only by someone knowing the factorisation of the RSA modulus. +However, this cannot prevent someone from encrypting a wrong key, or putting +a wrong message authentication code, +so this is why we still need the proof of correctness. diff --git a/docs/011/voting.rst b/docs/011/voting.rst new file mode 100644 index 000000000000..2bf6f6fa4dd1 --- /dev/null +++ b/docs/011/voting.rst @@ -0,0 +1,328 @@ +The Amendment (and Voting) Process +================================== + +In the Tezos blockchain, the *economic protocol* can be amended. Specifically, +there is an on-chain mechanism to propose changes to the economic protocol, to +vote for-or-against these proposed changes, and, depending on the result of the +vote, to activate these changes or not. + +Note that the proposal, voting and activation processes are part of the economic +protocol itself. Consequently the amendment rules themselves are subject to +amendments. + +The rest of this page gives more details about the amendment and voting process. +Other than this page, there is an excellent overview from `Jacob +Arluck on medium `__. + +Periods +------- + +The amendment process consists of five *periods*. Each period lasts for 40960 +blocks (5 cycles) (or approximately two weeks). The periods (listed below) +typically succeed one another for a total duration of approximately 2 months and +a half, after which the whole amendment process starts again. + +The five periods are as follows: + +- *Proposal period*: During this period, delegates can + + - submit *protocol amendment proposals* (or, simply, *proposals*) using the + ``Proposals`` operation (see below), + - support a proposal using the ``Ballot`` operation (see below). + + Each delegate can submit a maximum of 20 proposals. Duplicates count towards + this total. + + At the end of a **proposal period**, the proposal with most support is + selected and we move to an **exploration period**. Note that support is + measured in the cumulated number of rolls that delegates supporting the + proposal have. E.g., a proposal supported by a single delegate with 100 rolls + has more support than a proposal supported by two delegates with 20 rolls + each. + + If there are no proposals, or a tie between two or more proposals, the process + moves back to a new **proposal period**. + +- *Exploration period*: During this period delegates can cast one + Yay, Nay, or Pass ballot on the selected proposal. They do so using the + ``Ballot`` operation. + + If the voting participation reaches *quorum* and there is a *super-majority* + of Yay, the process moves to the **cooldown period**. (See below for details + on participation, quorum, and super-majority.) + + Otherwise the process moves back to the **proposal period**. + +- *Cooldown period*: On-chain nothing specific happens during this period. + Off-chain the delegates can read the proposal with more scrutiny, the + community can discuss finer points of the proposal, the developers can + perform additional tests, etc. + + At the end of this period, the process moves to the **promotion period**. + +- *Promotion period*: During this period, delegates can cast a Yay, Nay, or Pass + ballots using the ``Ballot`` operation. + + If the voting participation reaches *quorum* and there is a super-majority of + Yay, the process moves to the **adoption period**. + + Otherwise the process moves back to the **proposal period**. + +- *Adoption period*: On-chain nothing specific happens during this period except + on the very last block (see below). + + Off-chain the developers release tools that include support for the + soon-to-be activated protocol, other actors (bakers, indexers, etc.) update + their infrastructure to support the newly released tools, smart-contract + developers start working with soon-to-be-available features, etc. + + At the very end of the period, the proposal is *activated*. This means that + the last block of the period is still interpreted by the current economic + protocol, but the first block after the period is interpreted by the new + economic protocol (the one that was voted in). + + And a new **proposal period** starts. + + +Activation +---------- + +After the activation step, the blocks added to the chain are interpreted in the +newly activated protocol. As a result gas costs may differ, new operations may +be available, contracts using new opcodes may be injected, etc. + +Because the amendment process is also part of the economic protocol, the +amendment process now unfolds according to the rules of the newly activated +protocol. As a result the periods may be lengthened or shortened, a new period +might be introduced, a different selection mechanism may be used, the quorum +requirement might differ, etc. + + +Voting Power +------------ + +When supporting a proposal or casting a Yay, Nay, or Pass ballot, each delegate +has voting power equal to its *stake*. The stake is always measured in +**number of rolls**. + +Note that the stake of each delegate is computed at the beginning of each +period. + + +Super-majority and Quorum +------------------------- + +As mentioned above, during either of the **proposal** or **promotion** periods, +delegates can cast ballots using the ``Ballot`` operation (see below). +In both cases, delegates can cast a single Yay, Nay, or Pass ballot. A ballot +has a weight equal to the delegate's stake as detailed above. + +For either of these two periods, the process continues to the next period if the +*vote participation* reaches *quorum* and there is a *super-majority* of +Yay. + +The *vote participation* is the ratio of all the cumulated stake of cast ballots +(including Pass ballots) to the total stake. + +For the first voting period, the *quorum* started at 80% of stake. The quorum is +adjusted after each vote as detailed below. This adjustment is necessary to +ensure that the amendment process can continue even if some delegates stop +participating. After each vote the new quorum is updated based on the old quorum +and the **vote participation** with the following coefficients:: + + new-quorum = 0.8 × old-quorum + 0.2 × participation + +The *super-majority* is reached if the cumulated stake of Yay ballots is +greater than 8/10 of the cumulated stake of Yay and Nay ballots. + +Note that Pass ballots do not count towards or against the super-majority; +they still counts towards participation and quorum. + +More details can be found in the file +:src:`src/proto_011_PtHangzH/lib_protocol/amendment.ml`. + + +The Hash and the Protocol +------------------------- + +On the one hand, the voting part of the process revolves around the +**hash of a protocol**. Specifically, a delegate submits a hash of a +protocol, and all the delegates cast ballots on the proposed hash. +The *hash of a protocol* is the hash of the files that constitute the source +code of the protocol. + +On the other hand, the **protocol activation** (at the end of the +**adoption period**) revolves around the compiled sources of the protocol. + +Basically, the voting process works on an identifier of the protocol whilst the +activation step works on the protocol itself. Consequently, if a protocol hash +is voted in and the protocol it identifies is invalid, the activation step +fails. + +.. sidebar:: Checking a hash is of a valid protocol + + When a hash is proposed by a delegate, it is usually accompanied by some + blogposts and forum threads on :ref:`community websites `. + These should include directions for testing the proposed protocols. If you + cannot find such directions, do not hesitate to ask. + +.. sidebar:: Localised failures + + It is possible that the activation step fails on a single node or a few nodes + of the network, but succeed on the others. In this case the nodes with the + failure are stuck, but the network as a whole continues. + + The most likely cause for this is nodes that have not been updated and do not + include a new protocol environment version. + + If your node becomes stuck, you should start a fresh up-to-date node. + +A protocol is *invalid* if its code cannot be compiled (e.g., if the code is not +valid source code), if its code uses functions not present in the +:ref:`protocol environment `, or if it downgrades the +:ref:`protocol environment ` version. + +If an invalid protocol is voted in, then the activation fails for all the nodes, +and then the chain becomes stuck. This is why it is important to vote for hashes +that designate valid protocols: ones with sources that are available and that +can be compiled. + +Operations +---------- + +There are two operations used by the delegates: **proposals** and **ballot**. + +A *proposals* operation can only be injected during a proposal period. + +:: + + Proposals : { + source: Signature.Public_key_hash.t ; + period: Voting_period_repr.t ; + proposals: Protocol_hash.t list ; } + +The ``source`` is the public key hash of the delegate, ``period`` is the unique +identifier of each voting period and ``proposals`` is a non-empty list of +maximum 20 protocol hashes. +The operation can be submitted more than once but only as long as the +cumulative length of the proposals lists is less than 20. +Duplicate proposals from the same delegate are accounted for in the +maximum number of proposals for that delegate. +However duplicates from the same delegate are not tallied at the end +of the proposal period. + +For example, a delegate submits a *proposals* operation for protocols A +and B early in the proposal period, later a new protocol C is revealed +and the delegate submits another *proposals* operation for protocols B +and C. +The list of submissions that will be tallied is [A,B,C]. + +A *ballot* operation can only be submitted during one of the voting +periods, and only once per period. + +:: + + Ballot : { + source: Signature.Public_key_hash.t ; + period: Voting_period_repr.t ; + proposal: Protocol_hash.t ; + ballot: Vote_repr.ballot ; } + +The fields ``source`` and ``period`` are the same as above, while ``proposal`` +is the currently selected proposal and ``ballot`` is one of ``Yay``, ``Nay`` or +``Pass``. +The ``Pass`` vote allows a delegate to contribute towards the quorum without +contributing towards the super-majority. This is important because, as detailed +above, the quorum is adaptive and that low participation would lower the +quorum of the next vote. + +More details on the operations can be found in +:src:`src/proto_011_PtHangzH/lib_protocol/operation_repr.ml`. +The binary format is described by +``tezos-client describe unsigned operation``. + +Client Commands +--------------- + +The Octez client, ``tezos-client``, provides commands for basic exploration and +interaction with the amendment and voting process. + + +Show +~~~~ + +Tezos' client provides a command to show the status of a voting period. +It displays different informations for different kind of periods, as +in the following samples:: + + $ tezos-client show voting period + Current period: "proposal" + Blocks remaining until end of period: 59 + Current proposals: + PsNa6jTtsRfbGaNSoYXNTNM5A7c3Lji22Yf2ZhpFUjQFC17iZVp 400 + + $ tezos-client show voting period + Current period: "exploration" + Blocks remaining until end of period: 63 + Current proposal: PsNa6jTtsRfbGaNSoYXNTNM5A7c3Lji22Yf2ZhpFUjQFC17iZVp + Ballots: { "yay": 400, "nay": 0, "pass": 0 } + Current participation 20.00%, necessary quorum 80.00% + Current in favor 400, needed supermajority 320 + + $ tezos-client show voting period + Current period: "cooldown" + Blocks remaining until end of period: 64 + Current proposal: PsNa6jTtsRfbGaNSoYXNTNM5A7c3Lji22Yf2ZhpFUjQFC17iZVp + +It should be noted that the ballot number 400 above is the stake counted in +number of rolls. +The proposal has a total stake of 400 rolls, which may come from a single ballot +from a delegate having 400 rolls, or it may come from multiple ballots from +delegates with a combined stake of 400 rolls. + + +Submit proposals +~~~~~~~~~~~~~~~~ + +During a proposal period, a list of proposals can be submitted with:: + + tezos-client submit proposals for ... + +Remember that each delegate can submit a maximum of 20 protocol +hashes and that duplicates count towards this total. +Moreover each proposal is accepted only if it meets one of the +following two conditions: + +- the protocol hash was already proposed on the network. In this case + we can submit an additional proposal that "upvotes" an existing one + and our rolls are added to the ones already supporting the proposal. +- the protocol is known by the node. In particular the first proposer + of a protocol should be able to successfully inject the protocol in + its node which performs some checks, compiles and loads the + protocol. + +These are protection measures that the Octez client takes to prevent the +accidental injection of invalid protocols. As mentioned above, it is still +important to check the validity of the protocols that you vote for as they may +have been injected via different means. + + +Submit ballots +~~~~~~~~~~~~~~ + +During either of the **exploration** or **promotion** periods, +ballots can be submitted once with:: + + tezos-client submit ballot for + +Other resources +~~~~~~~~~~~~~~~ + +For more details on the client commands refer to the manual at +:ref:`client_manual_011`. + +For vote related RPCs check the :doc:`rpc` under the prefix +``votes/``. + +For Ledger support refer to Obsidian Systems' `documentation +`__. diff --git a/docs/index.rst b/docs/index.rst index 33b4535decf3..4f004e3b1f29 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -154,6 +154,21 @@ in the :ref:`introduction `. active/rpc active/liquidity_baking +.. toctree:: + :maxdepth: 2 + :caption: 011 Hangzhou Protocol doc: + + 011/michelson + 011/proof_of_stake + 011/consensus + 011/sapling + 011/voting + 011/glossary + 011/cli-commands + 011/rpc + 011/liquidity_baking + 011/timelock + .. toctree:: :maxdepth: 2 :caption: Alpha Development Protocol doc: @@ -203,6 +218,7 @@ in the :ref:`introduction `. protocols/008_edo protocols/009_florence protocols/010_granada + protocols/011_hangzhou protocols/alpha .. toctree:: diff --git a/docs/protocols/011_hangzhou.rst b/docs/protocols/011_hangzhou.rst new file mode 100644 index 000000000000..6cbc0af5b3a9 --- /dev/null +++ b/docs/protocols/011_hangzhou.rst @@ -0,0 +1,179 @@ +Protocol Alpha +============== + +This page contains all the relevant information for protocol Alpha +(see :ref:`naming_convention`). + +The code can be found in the :src:`src/proto_011_PtHangzH` directory of the +``master`` branch of Tezos. + +This page documents the changes brought by protocol Alpha with respect +to Granada. + +.. contents:: + +New Environment Version (V3) +---------------------------- + +This protocol requires a different protocol environment than Granada. +It requires protocol environment V3, compared to V2 for Granada. +(MR :gl:`!3040`) + +Receipts, Balance Updates +------------------------- + +- **Breaking change:** Rewards balance updates for nonce revelations + or endorsements now mention the cycle at which the rewards were + granted instead of the cycle of the level carried by the operation. + Likewise for deposits balance updates related to endorsement + operations, they now mention the cycle at which the funds have been + deposited. (MR :gl:`!3270`) + +RPC Changes +----------- + +- Deprecated RPC ``POST ../endorsing_power`` has been removed. Clients + already used ``GET ../helpers/endorsing_rights`` which is clearer, as + powerful and equally costly in terms of computation for the + node. (MR :gl:`!3395`) + +- The RPCs ``GET ../context/delegates/[PUBLIC_KEY_HASH]/..`` now fail + gracefully with a specific error ``delegate.not_registered`` when + ``PUBLIC_KEY_HASH`` is not a delegate instead of the generic + ``context.storage_error``. (MR :gl:`!3258`, issues :gl:`#450`, + :gl:`#451`, and :gl:`#1276`) + +Timelock +-------- + +- Added timelock-related types and opcodes to Michelson. + They allow a smart contract to include a countermeasure against + Block Producer Extractable Value. + More info in :doc:`Timelock <../alpha/timelock>`. + (MRs :gl:`!3160` :gl:`!2940` :gl:`!2950` :gl:`!3304` :gl:`!3384`) + +Michelson On-Chain Views +------------------------ + +:ref:`Views ` are a new mechanism for contract calls that: + +- are read-only: they may depend on the contract storage but cannot + modify it nor emit operations (but they can call other views); + +- take arguments as input in addition to the contract storage; + +- return results as output; + +- are synchronous: the result is immediately available on the stack of + the caller contract. + +There are two added Michelson primitives: ``VIEW`` (instruction) and +``view`` (top-level keyword). + +- `TZIP `__ +- MRs :gl:`!2359` and :gl:`!3431` + +Global Constants +---------------- + +- A new manager operation and corresponding CLI command have been added + allowing users to register Micheline expressions in a global table of + constants, returning an index to the expression. A new primitive + ``constant `` has been added that allows contracts to reference + these constants by their index. When a contract is called, any + constants are expanded into their registered values. The result is + that users can use constants to originate larger contracts, as well as + share code between contracts. + +- `TZIP `__ + +- MRs: :gl:`!2962`, :gl:`!3467`, :gl:`!3473`, :gl:`!3492` + +Cache +----- + +- A chain-sensitive cache is now available to the protocol developers. + This cache can be seen as an in-memory context providing fast access + to the most recently used values. + +- The protocol now keeps contracts' source code and storage in the + cache. This reduces the gas consumption for the most recently used + contracts. + +- The new RPC ``context/cache/contracts/all`` returns the list of contracts + in the cache. + +- The new RPC ``context/cache/contracts/size`` returns an overapproximation + of the cache size (in bytes). + +- The new RPC ``context/cache/contracts/size_limit`` returns the maximal + cache size (in bytes). When this size is reached, the cache removes + the least recently used entries. + +- The new RPC ``context/cache/contract_rank`` gives the number of contracts + that are less recently used than the one provided as argument. + +- The new RPC ``scripts/script_size`` gives the size of the script + and its storage when stored in the cache. + +- MRs: :gl:`!3234` :gl:`!3419` + +- Gas instrumentation implemented in MR :gl:`!3430` + +Context Storage Flattening +-------------------------- + +Hex-nested directories like ``/12/af/83/3d/`` are removed from the +context. This results in better context access performance. (MR :gl:`!2771`) + +Gas computation has been adapted to this new flattened context layout. (MR :gl:`!2771`) + +Bug Fixes +--------- + +- A bug in Michelson comparison function has been fixed (MR :gl:`!3237`) + +- Fix balance updates that indicate inaccurate burned amounts in some + scenarios (MR :gl:`!3407`) + +Minor Changes +------------- + +- Gas improvements for typechecking instruction ``CONTRACT`` (MR :gl:`!3241`) + +- Other internal refactorings or documentation. (MRs :gl:`!2021` :gl:`!2984` + :gl:`!3042` :gl:`!3049` :gl:`!3088` :gl:`!3075` :gl:`!3266` :gl:`!3270` + :gl:`!3285` :gl:`!3375` :gl:`!3247`) + +- Set the predecessor version of the protocol to Granada (MR :gl:`!3347`) + +- Check order in the validation of endorsements has changed to not + compute all endorsement slots of a level if the endorsement is + invalid. (MR :gl:`!3395`) + +- Fix handling of potential negative integer in ``Raw_level_repr`` + encoding. (MR :gl:`!3273`) + +- RPCs ``GET ../helpers/endorsing_rights`` and ``GET ../helpers/baking_rewards`` + have been moved into the RPC plugin. Nothing has changed from the + end-user perspective for now but further improvements to their + performance will become easier now that they are decoupled from the + protocol development cycle. (MR :gl:`!3368`) + +- Gives an increase to the liquidity baking sunset level of + 211,681 blocks, or five voting periods plus 6,881 blocks to + sync with the following voting period, roughly an additional two + months and a half. Without this, the subsidy would halt during the lifespan of + this protocol. With this change the subsidy can continue until the + protocol after this one is activated, even accounting for some + delays in proposal injection and/or a restarted voting process, + while still making sure it won't extend to two protocols after this + one without a more significant increase. This follows the spirit of + `the liquidity baking TZIP `_ in that it is still roughly six months + from Granada activation and requires a referendum on the subsidy in + the protocol after this one. (MR :gl:`!3425` :gl:`!3464`) + +- Reimplemented ``Logging``. It now has Lwt-less APIs and the messages are handled + by the shell. (MR :gl:`!3225`) + +- The size limit on Michelson types has been roughly doubled (from 1000 to 2001). (MR :gl:`!3434`) diff --git a/sandbox.Makefile b/sandbox.Makefile index 831c8291d6cf..3fd63bb05202 100644 --- a/sandbox.Makefile +++ b/sandbox.Makefile @@ -3,10 +3,10 @@ TMP=/tmp CURRENT_PROTO=010-PtGRANAD CURRENT_PROTO_HASH=PtGRANADsDU8R9daYKAgWnQYAJ64omN1o3KMGVCykShA97vQbvV CURRENT_PROTO_NAME=Granada -## To be uncommented when protocol H is completed -# NEXT_PROTO=010-PtGRANAD # -# NEXT_PROTO_HASH=PtGRANADsDU8R9daYKAgWnQYAJ64omN1o3KMGVCykShA97vQbvV # -# NEXT_PROTO_NAME=Granada # +## To be recommented when protocol G is over +NEXT_PROTO=011-PtHangzH +NEXT_PROTO_HASH=PtHangzHogokSuiMHemCuowEavgYTP8J5qQ9fQS793MHYFpCY3r +NEXT_PROTO_NAME=Hangzhou ALPHA_PROTO=alpha ALPHA_PROTO_HASH=ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK @@ -17,14 +17,14 @@ all: accusations_simple_double_baking \ user_activated_upgrade_alpha \ daemons_upgrade_alpha \ node_synchronization -# all: accusations_simple_double_baking \ -# accusations_simple_double_endorsing \ -# voting_demo_noops \ -# user_activated_upgrade_next \ -# user_activated_upgrade_alpha \ -# daemons_upgrade_next \ -# daemons_upgrade_alpha \ -# node_synchronization +all: accusations_simple_double_baking \ + accusations_simple_double_endorsing \ + voting_demo_noops \ + user_activated_upgrade_next \ + user_activated_upgrade_alpha \ + daemons_upgrade_next \ + daemons_upgrade_alpha \ + node_synchronization # The following rules define how to build Tezos binaries if they are # missing. diff --git a/src/bin_client/dune b/src/bin_client/dune index d84faa2ed214..4e78fcebbce4 100644 --- a/src/bin_client/dune +++ b/src/bin_client/dune @@ -62,6 +62,9 @@ (select void_for_linking-010-PtGRANAD from (tezos-client-010-PtGRANAD-commands-registration -> void_for_linking-010-PtGRANAD.empty) (-> void_for_linking-010-PtGRANAD.empty)) + (select void_for_linking-011-PtHangzH from + (tezos-client-011-PtHangzH-commands-registration -> void_for_linking-011-PtHangzH.empty) + (-> void_for_linking-011-PtHangzH.empty)) (select void_for_linking-alpha from (tezos-client-alpha-commands-registration -> void_for_linking-alpha.empty) @@ -82,6 +85,9 @@ (select void_for_linking-baking-010-PtGRANAD from (tezos-baking-010-PtGRANAD-commands.registration -> void_for_linking-baking-010-PtGRANAD.empty) (-> void_for_linking-baking-010-PtGRANAD.empty)) + (select void_for_linking-baking-011-PtHangzH from + (tezos-baking-011-PtHangzH-commands.registration -> void_for_linking-baking-011-PtHangzH.empty) + (-> void_for_linking-baking-011-PtHangzH.empty)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; If you modify this file around here, modify src/bin_proxy_server/dune too! ; @@ -99,6 +105,9 @@ (select void_for_linking-010-PtGRANAD-protocol-plugin from (tezos-protocol-plugin-010-PtGRANAD -> void_for_linking-010-PtGRANAD-protocol-plugin.empty) (-> void_for_linking-010-PtGRANAD-protocol-plugin.empty)) + (select void_for_linking-011-PtHangzH-protocol-plugin from + (tezos-protocol-plugin-011-PtHangzH -> void_for_linking-011-PtHangzH-protocol-plugin.empty) + (-> void_for_linking-011-PtHangzH-protocol-plugin.empty)) (select void_for_linking-alpha-protocol-plugin from (tezos-protocol-plugin-alpha -> void_for_linking-alpha-protocol-plugin.empty) (-> void_for_linking-alpha-protocol-plugin.empty)) @@ -133,16 +142,19 @@ (write-file void_for_linking-008-PtEdo2Zk.empty "") (write-file void_for_linking-009-PsFLoren.empty "") (write-file void_for_linking-010-PtGRANAD.empty "") + (write-file void_for_linking-011-PtHangzH.empty "") (write-file void_for_linking-alpha.empty "") (write-file void_for_linking-demo-counter.empty "") (write-file void_for_linking-baking-alpha.empty "") (write-file void_for_linking-baking-008-PtEdo2Zk.empty "") (write-file void_for_linking-baking-009-PsFLoren.empty "") (write-file void_for_linking-baking-010-PtGRANAD.empty "") + (write-file void_for_linking-baking-011-PtHangzH.empty "") (write-file void_for_linking-007-PsDELPH1-protocol-plugin.empty "") (write-file void_for_linking-008-PtEdo2Zk-protocol-plugin.empty "") (write-file void_for_linking-009-PsFLoren-protocol-plugin.empty "") (write-file void_for_linking-010-PtGRANAD-protocol-plugin.empty "") + (write-file void_for_linking-011-PtHangzH-protocol-plugin.empty "") (write-file void_for_linking-alpha-protocol-plugin.empty "") ))) diff --git a/src/bin_client/tezos-client.opam b/src/bin_client/tezos-client.opam index 72a928fcae72..4bb1d0f8162c 100644 --- a/src/bin_client/tezos-client.opam +++ b/src/bin_client/tezos-client.opam @@ -25,6 +25,7 @@ depends: [ "tezos-client-008-PtEdo2Zk" "tezos-client-009-PsFLoren" "tezos-client-010-PtGRANAD" + "tezos-client-011-PtHangzH" "tezos-client-demo-counter" "tezos-client-alpha-commands" @@ -38,11 +39,13 @@ depends: [ "tezos-client-008-PtEdo2Zk-commands-registration" "tezos-client-009-PsFLoren-commands-registration" "tezos-client-010-PtGRANAD-commands-registration" + "tezos-client-011-PtHangzH-commands-registration" "tezos-baking-alpha-commands" "tezos-baking-008-PtEdo2Zk-commands" "tezos-baking-009-PsFLoren-commands" "tezos-baking-010-PtGRANAD-commands" + "tezos-baking-011-PtHangzH-commands" "tezos-client-base-unix" "tezos-mockup-commands" diff --git a/src/bin_codec/dune b/src/bin_codec/dune index 08455cd2bf42..19959613e7d5 100644 --- a/src/bin_codec/dune +++ b/src/bin_codec/dune @@ -38,6 +38,9 @@ (select void_for_linking-010-PtGRANAD from (tezos-client-010-PtGRANAD -> void_for_linking-010-PtGRANAD.empty) (-> void_for_linking-010-PtGRANAD.empty)) + (select void_for_linking-011-PtHangzH from + (tezos-client-011-PtHangzH -> void_for_linking-011-PtHangzH.empty) + (-> void_for_linking-011-PtHangzH.empty)) ) (flags (:standard -open Data_encoding -open Tezos_base__TzPervasives @@ -58,4 +61,5 @@ (write-file void_for_linking-008-PtEdo2Zk.empty "") (write-file void_for_linking-009-PsFLoren.empty "") (write-file void_for_linking-010-PtGRANAD.empty "") + (write-file void_for_linking-011-PtHangzH.empty "") ))) diff --git a/src/bin_codec/tezos-codec.opam b/src/bin_codec/tezos-codec.opam index 0532234e8efb..6e6c84d22ee1 100644 --- a/src/bin_codec/tezos-codec.opam +++ b/src/bin_codec/tezos-codec.opam @@ -24,6 +24,7 @@ depopts: [ "tezos-client-008-PtEdo2Zk" "tezos-client-009-PsFLoren" "tezos-client-010-PtGRANAD" + "tezos-client-011-PtHangzH" ] build: [ ["dune" "build" "-p" name "-j" jobs] diff --git a/src/bin_node/dune b/src/bin_node/dune index eac8dfeb358d..44cac4869ce8 100644 --- a/src/bin_node/dune +++ b/src/bin_node/dune @@ -84,6 +84,9 @@ (select void_for_linking-010-PtGRANAD from (tezos-embedded-protocol-010-PtGRANAD -> void_for_linking-010-PtGRANAD.empty) (-> void_for_linking-010-PtGRANAD.empty)) + (select void_for_linking-011-PtHangzH from + (tezos-embedded-protocol-011-PtHangzH -> void_for_linking-011-PtHangzH.empty) + (-> void_for_linking-011-PtHangzH.empty)) (select void_for_linking-008-PtEdo2Zk-protocol-plugin-registerer from (tezos-protocol-plugin-008-PtEdo2Zk-registerer -> void_for_linking-008-PtEdo2Zk-protocol-plugin-registerer.empty) (-> void_for_linking-008-PtEdo2Zk-protocol-plugin-registerer.empty)) @@ -93,6 +96,9 @@ (select void_for_linking-010-PtGRANAD-protocol-plugin-registerer from (tezos-protocol-plugin-010-PtGRANAD-registerer -> void_for_linking-010-PtGRANAD-protocol-plugin-registerer.empty) (-> void_for_linking-010-PtGRANAD-protocol-plugin-registerer.empty)) + (select void_for_linking-011-PtHangzH-protocol-plugin-registerer from + (tezos-protocol-plugin-011-PtHangzH-registerer -> void_for_linking-011-PtHangzH-protocol-plugin-registerer.empty) + (-> void_for_linking-011-PtHangzH-protocol-plugin-registerer.empty)) (select void_for_linking-alpha-protocol-plugin-registerer from (tezos-protocol-plugin-alpha-registerer -> void_for_linking-alpha-protocol-plugin-registerer.empty) (-> void_for_linking-alpha-protocol-plugin-registerer.empty)) @@ -136,10 +142,12 @@ (write-file void_for_linking-008-PtEdo2Zk.empty "") (write-file void_for_linking-009-PsFLoren.empty "") (write-file void_for_linking-010-PtGRANAD.empty "") + (write-file void_for_linking-011-PtHangzH.empty "") (write-file void_for_linking-alpha-protocol-plugin-registerer.empty "") (write-file void_for_linking-008-PtEdo2Zk-protocol-plugin-registerer.empty "") (write-file void_for_linking-009-PsFLoren-protocol-plugin-registerer.empty "") (write-file void_for_linking-010-PtGRANAD-protocol-plugin-registerer.empty "") + (write-file void_for_linking-011-PtHangzH-protocol-plugin-registerer.empty "") ))) (install diff --git a/src/bin_node/tezos-node.opam b/src/bin_node/tezos-node.opam index 96a27c8154e2..92febdd823cd 100644 --- a/src/bin_node/tezos-node.opam +++ b/src/bin_node/tezos-node.opam @@ -33,9 +33,11 @@ depends: [ "tezos-embedded-protocol-008-PtEdo2Zk" "tezos-embedded-protocol-009-PsFLoren" "tezos-embedded-protocol-010-PtGRANAD" + "tezos-embedded-protocol-011-PtHangzH" "tezos-protocol-plugin-008-PtEdo2Zk-registerer" "tezos-protocol-plugin-009-PsFLoren-registerer" "tezos-protocol-plugin-010-PtGRANAD-registerer" + "tezos-protocol-plugin-011-PtHangzH-registerer" "tezos-protocol-plugin-alpha-registerer" "cmdliner" "lwt-exit" diff --git a/src/bin_proxy_server/dune b/src/bin_proxy_server/dune index 6167b3fb59a8..bf99b9b1e32c 100644 --- a/src/bin_proxy_server/dune +++ b/src/bin_proxy_server/dune @@ -58,6 +58,9 @@ (select void_for_linking-010-PtGRANAD from (tezos-client-010-PtGRANAD -> void_for_linking-010-PtGRANAD.empty) (-> void_for_linking-010-PtGRANAD.empty)) + (select void_for_linking-011-PtHangzH from + (tezos-client-011-PtHangzH -> void_for_linking-011-PtHangzH.empty) + (-> void_for_linking-011-PtHangzH.empty)) (select void_for_linking-alpha from (tezos-client-alpha -> void_for_linking-alpha.empty) @@ -78,6 +81,9 @@ (select void_for_linking-010-PtGRANAD-protocol-plugin from (tezos-protocol-plugin-010-PtGRANAD -> void_for_linking-010-PtGRANAD-protocol-plugin.empty) (-> void_for_linking-010-PtGRANAD-protocol-plugin.empty)) + (select void_for_linking-011-PtHangzH-protocol-plugin from + (tezos-protocol-plugin-011-PtHangzH -> void_for_linking-011-PtHangzH-protocol-plugin.empty) + (-> void_for_linking-011-PtHangzH-protocol-plugin.empty)) (select void_for_linking-alpha-protocol-plugin from (tezos-protocol-plugin-alpha -> void_for_linking-alpha-protocol-plugin.empty) (-> void_for_linking-alpha-protocol-plugin.empty))) @@ -103,11 +109,13 @@ (write-file void_for_linking-008-PtEdo2Zk.empty "") (write-file void_for_linking-009-PsFLoren.empty "") (write-file void_for_linking-010-PtGRANAD.empty "") + (write-file void_for_linking-011-PtHangzH.empty "") (write-file void_for_linking-alpha.empty "") (write-file void_for_linking-demo-counter.empty "") (write-file void_for_linking-007-PsDELPH1-protocol-plugin.empty "") (write-file void_for_linking-008-PtEdo2Zk-protocol-plugin.empty "") (write-file void_for_linking-009-PsFLoren-protocol-plugin.empty "") (write-file void_for_linking-010-PtGRANAD-protocol-plugin.empty "") + (write-file void_for_linking-011-PtHangzH-protocol-plugin.empty "") (write-file void_for_linking-alpha-protocol-plugin.empty "") ))) diff --git a/src/lib_protocol_compiler/final_protocol_versions b/src/lib_protocol_compiler/final_protocol_versions index 06357eeea1f7..9040474695ae 100644 --- a/src/lib_protocol_compiler/final_protocol_versions +++ b/src/lib_protocol_compiler/final_protocol_versions @@ -10,4 +10,5 @@ PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo PtEdoTezd3RHSC31mpxxo1npxFjoWWcFgQtxapi51Z8TLu6v6Uq PtEdo2ZkT9oKpimTah6x2embF25oss54njMuPzkJTEi5RqfdZFA PsFLorenaUUuikDWvMDr6fGBRG8kt3e3D3fHoXK1j1BFRxeSH4i -PtGRANADsDU8R9daYKAgWnQYAJ64omN1o3KMGVCykShA97vQbvV \ No newline at end of file +PtGRANADsDU8R9daYKAgWnQYAJ64omN1o3KMGVCykShA97vQbvV +PtHangzHogokSuiMHemCuowEavgYTP8J5qQ9fQS793MHYFpCY3r \ No newline at end of file diff --git a/src/proto_011_PtHangzH/bin_accuser/.ocamlformat b/src/proto_011_PtHangzH/bin_accuser/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/bin_accuser/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/bin_accuser/dune b/src/proto_011_PtHangzH/bin_accuser/dune new file mode 100644 index 000000000000..f6739c2f1975 --- /dev/null +++ b/src/proto_011_PtHangzH/bin_accuser/dune @@ -0,0 +1,20 @@ +; build static executable with --profile static +(env + (static (flags (:standard + -ccopt -static + -cclib "-lusb-1.0 -lhidapi-libusb -ludev")))) + +(executable + (name main_accuser_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-accuser-011-PtHangzH) + (libraries tezos-client-base-unix + tezos-client-commands + tezos-baking-011-PtHangzH-commands) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_protocol_011_PtHangzH + -open Tezos_client_011_PtHangzH + -open Tezos_client_commands + -open Tezos_baking_011_PtHangzH_commands + -open Tezos_stdlib_unix + -open Tezos_client_base_unix))) diff --git a/src/proto_011_PtHangzH/bin_accuser/dune-project b/src/proto_011_PtHangzH/bin_accuser/dune-project new file mode 100644 index 000000000000..6b744fcbb48b --- /dev/null +++ b/src/proto_011_PtHangzH/bin_accuser/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(formatting (enabled_for ocaml)) +(name tezos-accuser-alpha) diff --git a/src/proto_011_PtHangzH/bin_accuser/main_accuser_011_PtHangzH.ml b/src/proto_011_PtHangzH/bin_accuser/main_accuser_011_PtHangzH.ml new file mode 100644 index 000000000000..7fb66dc3147f --- /dev/null +++ b/src/proto_011_PtHangzH/bin_accuser/main_accuser_011_PtHangzH.ml @@ -0,0 +1,38 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let () = + Client_commands.register Protocol.hash @@ fun _network -> + List.map (Clic.map_command (new Protocol_client_context.wrap_full)) + @@ Delegate_commands.accuser_commands () + +let select_commands _ _ = + return + (List.map + (Clic.map_command (new Protocol_client_context.wrap_full)) + (Delegate_commands.accuser_commands ())) + +let () = Client_main_run.run (module Client_config) ~select_commands diff --git a/src/proto_011_PtHangzH/bin_accuser/tezos-accuser-011-PtHangzH.opam b/src/proto_011_PtHangzH/bin_accuser/tezos-accuser-011-PtHangzH.opam new file mode 100644 index 000000000000..76d4be553c28 --- /dev/null +++ b/src/proto_011_PtHangzH/bin_accuser/tezos-accuser-011-PtHangzH.opam @@ -0,0 +1,20 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-base" + "tezos-client-011-PtHangzH" + "tezos-client-commands" + "tezos-baking-011-PtHangzH-commands" + "tezos-client-base-unix" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: accuser binary" diff --git a/src/proto_011_PtHangzH/bin_baker/.ocamlformat b/src/proto_011_PtHangzH/bin_baker/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/bin_baker/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/bin_baker/dune b/src/proto_011_PtHangzH/bin_baker/dune new file mode 100644 index 000000000000..f4916546c5d1 --- /dev/null +++ b/src/proto_011_PtHangzH/bin_baker/dune @@ -0,0 +1,20 @@ +; build static executable with --profile static +(env + (static (flags (:standard + -ccopt -static + -cclib "-lusb-1.0 -lhidapi-libusb -ludev")))) + +(executable + (name main_baker_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-baker-011-PtHangzH) + (libraries tezos-client-base-unix + tezos-client-commands + tezos-baking-011-PtHangzH-commands) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_protocol_011_PtHangzH + -open Tezos_client_011_PtHangzH + -open Tezos_client_commands + -open Tezos_baking_011_PtHangzH_commands + -open Tezos_stdlib_unix + -open Tezos_client_base_unix))) diff --git a/src/proto_011_PtHangzH/bin_baker/dune-project b/src/proto_011_PtHangzH/bin_baker/dune-project new file mode 100644 index 000000000000..ab21dd8b82f3 --- /dev/null +++ b/src/proto_011_PtHangzH/bin_baker/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(formatting (enabled_for ocaml)) +(name tezos-baker-alpha) diff --git a/src/proto_011_PtHangzH/bin_baker/main_baker_011_PtHangzH.ml b/src/proto_011_PtHangzH/bin_baker/main_baker_011_PtHangzH.ml new file mode 100644 index 000000000000..eb9f3ccd55c3 --- /dev/null +++ b/src/proto_011_PtHangzH/bin_baker/main_baker_011_PtHangzH.ml @@ -0,0 +1,47 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let () = + Client_commands.register Protocol.hash @@ fun _network -> + List.map (Clic.map_command (new Protocol_client_context.wrap_full)) + @@ Delegate_commands.delegate_commands () + +let select_commands _ _ = + return + (List.map + (Clic.map_command (new Protocol_client_context.wrap_full)) + (Delegate_commands.baker_commands ())) + +(* This call is not strictly necessary as the parameters are initialized + lazily the first time a Sapling operation (validation or forging) is + done. This is what the client does. + For a long running binary however it is important to make sure that the + parameters files are there at the start and avoid failing much later while + validating an operation. Plus paying this cost upfront means that the first + validation will not be more expensive. *) +let () = Tezos_sapling.Core.Validator.init_params () + +let () = Client_main_run.run (module Client_config) ~select_commands diff --git a/src/proto_011_PtHangzH/bin_baker/tezos-baker-011-PtHangzH.opam b/src/proto_011_PtHangzH/bin_baker/tezos-baker-011-PtHangzH.opam new file mode 100644 index 000000000000..b9fc1212c1ce --- /dev/null +++ b/src/proto_011_PtHangzH/bin_baker/tezos-baker-011-PtHangzH.opam @@ -0,0 +1,20 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-base" + "tezos-client-011-PtHangzH" + "tezos-client-commands" + "tezos-baking-011-PtHangzH-commands" + "tezos-client-base-unix" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: baker binary" diff --git a/src/proto_011_PtHangzH/bin_endorser/.ocamlformat b/src/proto_011_PtHangzH/bin_endorser/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/bin_endorser/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/bin_endorser/dune b/src/proto_011_PtHangzH/bin_endorser/dune new file mode 100644 index 000000000000..12d16a84de0c --- /dev/null +++ b/src/proto_011_PtHangzH/bin_endorser/dune @@ -0,0 +1,20 @@ +; build static executable with --profile static +(env + (static (flags (:standard + -ccopt -static + -cclib "-lusb-1.0 -lhidapi-libusb -ludev")))) + +(executable + (name main_endorser_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-endorser-011-PtHangzH) + (libraries tezos-client-base-unix + tezos-client-commands + tezos-baking-011-PtHangzH-commands) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_protocol_011_PtHangzH + -open Tezos_client_011_PtHangzH + -open Tezos_client_commands + -open Tezos_baking_011_PtHangzH_commands + -open Tezos_stdlib_unix + -open Tezos_client_base_unix))) diff --git a/src/proto_011_PtHangzH/bin_endorser/dune-project b/src/proto_011_PtHangzH/bin_endorser/dune-project new file mode 100644 index 000000000000..590a29e3f53b --- /dev/null +++ b/src/proto_011_PtHangzH/bin_endorser/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(formatting (enabled_for ocaml)) +(name tezos-endorser-alpha) diff --git a/src/proto_011_PtHangzH/bin_endorser/main_endorser_011_PtHangzH.ml b/src/proto_011_PtHangzH/bin_endorser/main_endorser_011_PtHangzH.ml new file mode 100644 index 000000000000..627a43b8e4cc --- /dev/null +++ b/src/proto_011_PtHangzH/bin_endorser/main_endorser_011_PtHangzH.ml @@ -0,0 +1,38 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let () = + Client_commands.register Protocol.hash @@ fun _network -> + List.map (Clic.map_command (new Protocol_client_context.wrap_full)) + @@ Delegate_commands.delegate_commands () + +let select_commands _ _ = + return + (List.map + (Clic.map_command (new Protocol_client_context.wrap_full)) + (Delegate_commands.endorser_commands ())) + +let () = Client_main_run.run (module Client_config) ~select_commands diff --git a/src/proto_011_PtHangzH/bin_endorser/tezos-endorser-011-PtHangzH.opam b/src/proto_011_PtHangzH/bin_endorser/tezos-endorser-011-PtHangzH.opam new file mode 100644 index 000000000000..6547605a34f3 --- /dev/null +++ b/src/proto_011_PtHangzH/bin_endorser/tezos-endorser-011-PtHangzH.opam @@ -0,0 +1,20 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-base" + "tezos-client-011-PtHangzH" + "tezos-client-commands" + "tezos-baking-011-PtHangzH-commands" + "tezos-client-base-unix" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: endorser binary" diff --git a/src/proto_011_PtHangzH/lib_benchmark/.ocamlformat b/src/proto_011_PtHangzH/lib_benchmark/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_benchmark/README.md b/src/proto_011_PtHangzH/lib_benchmark/README.md new file mode 100644 index 000000000000..8adba76cbf90 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/README.md @@ -0,0 +1,42 @@ +# `Tezos_benchmark_alpha` + +This library is dedicated to sampling Michelson values and in particular +Michelson programs. + +## Architecture + +This library provides a sampling-based interface for well-typed +Michelson generation. Internally, this library is built on a sampler for an +intermediate language called Mikhailsky post-composed with a function to +map Mikhailsky terms to Michelson ones. + +### Layer 1: Mikhailsky + Mikhailsky corresponds to "Michelson with typed holes". Mikhailsky terms + are encoded inside Micheline. The library `lib_benchmark_type_inference` + provides the language definition as well as a type inference engine. + +### Layer 2: Sampling Mikhailsky terms + We sample Mikhailsky terms using a Markov chain where transitions correspond + to local rewriting rules. The state space of the Markov chain is defined + in `State_space` module. The rewriting infrastructure is provided in the + `Kernel` module by instantiating `lib_micheline_rewriting`. + Rewrites are checked to preserved well-typedness in the Mikhailsky sense + using the type inference engine provided with Mikhailsky. The `Rules` + module defines all rewriting rules, for both Mikhailsky _programs_ + (submodule `Rules.Instruction`) and _data_ + (submodule `Rules.Data_rewrite_leaves`). The function `Rules.rewriting` + performs the enumeration of possible rewritings. + + The Markov chain is biased to sample terms of a specified + size using the Metropolis-Hasting functors provided by `StaTz`. + The instantiation of this Markov chain is defined in the `Sampler` + module. + +### Layer 3: + Once we can sample Mikhaislky terms of a specified size, we need + to convert them to Michelson ones. This is performed in two steps. + - In the first step, we use the `Autocomplete` module to fill holes + in Mikhailsky terms (resp. data) with well-typed code (resp. data). + This is a relatively ad-hoc process. + - The last step is to convert Mikhaislky to Michelson using the + `Michelson` module. diff --git a/src/proto_011_PtHangzH/lib_benchmark/autocomp.ml b/src/proto_011_PtHangzH/lib_benchmark/autocomp.ml new file mode 100644 index 000000000000..3d6397f2b18b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/autocomp.ml @@ -0,0 +1,380 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Michelson_samplers_parameters +open Sampling_helpers + +(* Autocompletion functions (removing holes from Mikhailsky terms). *) + +(* ------------------------------------------------------------------------- *) +(* Helpers *) + +let rec stack_length (stack : Type.Stack.t) acc = + match stack.node with + | Empty_t -> acc + | Stack_var_t _ -> acc + 1 + | Item_t (_, tl) -> stack_length tl (acc + 1) + +(* We need to sort and remove duplicate elements + of sets and maps to make them Michelson-compatible. *) +let sort_set_elements elements = + List.sort_uniq + (Structural_compare.compare + ~prim_compare:Mikhailsky.Mikhailsky_signature.compare) + elements + +let sort_map_elements elements = + let open Micheline in + List.sort_uniq + (fun node1 node2 -> + match (node1, node2) with + | ( Prim (_, Mikhailsky_prim.D_Elt, [k1; _v1], _), + Prim (_, Mikhailsky_prim.D_Elt, [k2; _v2], _) ) -> + Structural_compare.compare + ~prim_compare:Mikhailsky.Mikhailsky_signature.compare + k1 + k2 + | _ -> Stdlib.failwith "Autocomp.sort_map_elements: invalid Michelson map") + elements + +(* ------------------------------------------------------------------------- *) +(* Error handling *) + +type error_case = + | Cannot_complete_data of Mikhailsky.node * Kernel.Path.t + | Cannot_complete_code of Mikhailsky.node * Kernel.Path.t + +exception Autocompletion_error of error_case + +let cannot_complete_data node path = + raise (Autocompletion_error (Cannot_complete_data (node, path))) + +let cannot_complete_code node path = + raise (Autocompletion_error (Cannot_complete_code (node, path))) + +(* ------------------------------------------------------------------------- *) +(* Code & data autocompletion *) + +(* By default, comparable values are unit. *) +let default_comparable_type = Type.unit + +let generate_comparable _sp = Mikhailsky.Data.unit + +(* Instantiates variables in a base type, remaining variables + are mapped to some consistent choice of ground type + (this is made complicated by comparability constraints) *) +let rec instantiate_and_set ty = + let open Inference.M in + Inference.instantiate_base ty >>= fun ty -> replace_vars ty + +and replace_vars (ty : Type.Base.t) = + let open Inference.M in + let node = ty.node in + match node with + | Type.Base.Unit_t | Type.Base.Int_t | Type.Base.Nat_t | Type.Base.Bool_t + | Type.Base.String_t | Type.Base.Bytes_t | Type.Base.Key_hash_t + | Type.Base.Timestamp_t | Type.Base.Mutez_t | Type.Base.Key_t -> + return ty + | Type.Base.Var_t v -> ( + get_repr_exn v >>= fun repr -> + match repr with + | Inference.Stack_type _ -> assert false + | Inference.Base_type {comparable = _; repr = Some _} -> assert false + | Inference.Base_type {comparable; repr = None} -> ( + match comparable with + | Inference.Comparable -> return default_comparable_type + | Inference.Unconstrained | Inference.Not_comparable -> + return Type.unit)) + | Type.Base.Option_t ty -> + replace_vars ty >>= fun ty -> return (Type.option ty) + | Type.Base.Pair_t (lt, rt) -> + replace_vars lt >>= fun lt -> + replace_vars rt >>= fun rt -> return (Type.pair lt rt) + | Type.Base.Union_t (lt, rt) -> + replace_vars lt >>= fun lt -> + replace_vars rt >>= fun rt -> return (Type.union lt rt) + | Type.Base.List_t ty -> replace_vars ty >>= fun ty -> return (Type.list ty) + | Type.Base.Set_t ty -> replace_vars ty >>= fun ty -> return (Type.set ty) + | Type.Base.Map_t (k, v) -> + replace_vars k >>= fun k -> + replace_vars v >>= fun v -> return (Type.map k v) + | Type.Base.Lambda_t (dom, range) -> + replace_vars dom >>= fun dom -> + replace_vars range >>= fun range -> return (Type.lambda dom range) + +let rec instantiate_and_set_stack (stack_ty : Type.Stack.t) = + let open Inference.M in + let node = stack_ty.node in + match node with + | Type.Stack.Empty_t -> return Type.empty + | Type.Stack.Stack_var_t _ -> return Type.empty + | Type.Stack.Item_t (hd, tl) -> + instantiate_and_set hd >>= fun hd -> + instantiate_and_set_stack tl >>= fun tl -> return (Type.item hd tl) + +(* In the following we perform computations in the composite monad + (sampler o Inference.M.t), it is convenient to define the bind and return + explicitly. *) +module SM = struct + type 'a t = 'a Inference.M.t sampler + + let ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t = + fun m f rng_state s -> + let (x, s) = m rng_state s in + f x rng_state s + [@@inline] + + let sample : 'a sampler -> 'a Inference.M.t sampler = + fun x rng_state st -> (x rng_state, st) + [@@inline] + + let deterministic : 'a Inference.M.t -> 'a t = fun x _rng_state -> x + + let return x _ s = (x, s) [@@inline] +end + +module Make (P : Michelson_samplers_base.Full_S) = struct + (* Generates minimally sized random data of specified type. + Used in autocompletion. *) + (* /!\ Always call [instantiate_and_set] on the type argument of + [generate_data]. /!\ *) + let rec generate_data : Type.Base.t -> Mikhailsky.node SM.t = + fun ty -> + let open SM in + let open Type.Base in + let desc = ty.node in + match desc with + | Var_t _v -> assert false + | Unit_t -> return Mikhailsky.Data.unit + | Int_t -> + sample @@ Base_samplers.int ~size:P.sampling_parameters.int_size + >>= fun i -> return (Mikhailsky.Data.big_integer i) + | Nat_t -> + sample @@ Base_samplers.nat ~size:P.sampling_parameters.int_size + >>= fun n -> return (Mikhailsky.Data.big_natural n) + | Bool_t -> + sample Base_samplers.uniform_bool >>= fun b -> + if b then return Mikhailsky.Data.true_ + else return Mikhailsky.Data.false_ + | String_t -> + sample + (Base_samplers.readable_ascii_string + ~size:P.sampling_parameters.string_size) + >>= fun str -> return (Mikhailsky.Data.string str) + | Bytes_t -> + sample (Base_samplers.bytes ~size:P.sampling_parameters.bytes_size) + >>= fun bytes -> return (Mikhailsky.Data.bytes bytes) + | Key_hash_t -> + sample P.Crypto_samplers.pkh >>= fun pkh -> + return (Mikhailsky.Data.key_hash pkh) + | Timestamp_t -> + sample P.Michelson_base.timestamp >>= fun tstamp -> + return (Mikhailsky.Data.timestamp tstamp) + | Mutez_t -> + sample P.Michelson_base.tez >>= fun tz -> + return (Mikhailsky.Data.mutez tz) + | Key_t -> + sample P.Crypto_samplers.pk >>= fun pk -> + return (Mikhailsky.Data.key pk) + | Option_t ty -> + sample Base_samplers.uniform_bool >>= fun b -> + if b then return Mikhailsky.Data.none + else generate_data ty >>= fun res -> return (Mikhailsky.Data.some res) + | Pair_t (lty, rty) -> + generate_data lty >>= fun lv -> + generate_data rty >>= fun rv -> return (Mikhailsky.Data.pair lv rv) + | Union_t (lty, rty) -> + sample P.Michelson_base.bool >>= fun b -> + if b then generate_data lty >>= fun v -> return (Mikhailsky.Data.left v) + else generate_data rty >>= fun v -> return (Mikhailsky.Data.right v) + | List_t _ty -> return (Mikhailsky.Data.list []) + | Set_t _ty -> return (Mikhailsky.Data.set []) + | Map_t (_kty, _vty) -> return (Mikhailsky.Data.map []) + | Lambda_t (dom, range) -> + invent_term Type.(item dom empty) Type.(item range empty) + >>= fun code -> return (Mikhailsky.Data.lambda code) + + and invent_term (bef : Type.Stack.t) (aft : Type.Stack.t) : + Mikhailsky.node list SM.t = + let open SM in + install_dummy_stack aft [] >>= fun code -> + let terms = drop_stack bef code in + return terms + + and drop_stack (stack : Type.Stack.t) code = + Mikhailsky.Instructions.dropn (stack_length stack 0) :: code + + and install_dummy_stack (stack : Type.Stack.t) (acc : Mikhailsky.node list) = + let open SM in + match stack.node with + | Empty_t -> return acc + | Stack_var_t _ -> + let acc = Mikhailsky.(Instructions.push unit_ty Data.unit) :: acc in + return acc + | Item_t (hd, tl) -> + deterministic @@ instantiate_and_set hd >>= fun hd -> + (match hd.node with + | Lambda_t (dom, range) -> + invent_term Type.(item dom empty) Type.(item range empty) + >>= fun code -> + let instr = Mikhailsky.(prim I_LAMBDA [seq code] []) in + return instr + | _ -> + generate_data hd >>= fun term -> + let ty = Mikhailsky.unparse_ty_exn hd in + return (Mikhailsky.Instructions.push ty term)) + >>= fun instr -> install_dummy_stack tl (instr :: acc) + + (* Autocomplete Mikhailsky data. + When encountering a hole, we lookup its type and instantiate + some random data of the specified type. *) + let rec complete_data : + Mikhailsky.node -> Kernel.Path.t -> Mikhailsky.node SM.t = + let open SM in + fun node path -> + match node with + | Micheline.Int (_, _) | Micheline.String (_, _) | Micheline.Bytes (_, _) + -> + return node + | Micheline.Prim (_, D_Hole, _, _) -> ( + deterministic @@ Inference.M.get_data_annot path >>= fun ty_opt -> + match ty_opt with + | None -> cannot_complete_data node path + | Some ty -> + deterministic @@ instantiate_and_set ty >>= fun ty -> + generate_data ty) + | Micheline.Prim (_, A_Set, [Micheline.Seq (_, elements)], _) -> + complete_data_list (Kernel.Path.at_index 0 path) 0 elements [] + >>= fun elements -> + let elements = sort_set_elements elements in + return (Mikhailsky.Data.set elements) + | Micheline.Prim (_, A_Map, [Micheline.Seq (_, elements)], _) -> + complete_data_list (Kernel.Path.at_index 0 path) 0 elements [] + >>= fun elements -> + let elements = sort_map_elements elements in + return (Mikhailsky.Data.map elements) + | Micheline.Prim (_, prim, subterms, _) -> + complete_data_list path 0 subterms [] >>= fun subterms -> + return (Mikhailsky.prim prim subterms []) + | Micheline.Seq (_, subterms) -> + complete_data_list path 0 subterms [] >>= fun subterms -> + return (Mikhailsky.seq subterms) + + and complete_data_list path i subterms acc = + let open SM in + match subterms with + | [] -> return (List.rev acc) + | subterm :: tl -> + let path' = Kernel.Path.at_index i path in + complete_data subterm path' >>= fun term -> + complete_data_list path (i + 1) tl (term :: acc) + + let complete_data typing node rng_state = + let (root_type_opt, _) = + Inference.M.get_data_annot Kernel.Path.root typing + in + match root_type_opt with + | None -> Stdlib.failwith "Autocomp.complete_data: cannot get type of expr" + | Some ty -> + let (_, typing) = Inference.instantiate_base ty typing in + let (result, _) = + try complete_data node Kernel.Path.root rng_state typing + with Autocompletion_error (Cannot_complete_data (subterm, path)) -> + Format.eprintf "Cannot complete data@." ; + Format.eprintf "at path %s@." (Kernel.Path.to_string path) ; + Format.eprintf "%a@." Mikhailsky.pp subterm ; + Stdlib.failwith "in autocomp.ml: unrecoverable failure" + in + let (typ, _typing) = + try Inference.infer_data_with_state result + with Inference.Ill_typed_script error -> + Format.eprintf "%a@." Inference.pp_inference_error error ; + Format.eprintf "%a@." Mikhailsky.pp result ; + assert false + in + (result, typ) + + (* Autocomplete Mikhailsky code. *) + + let rec complete_code : + Mikhailsky.node -> Kernel.Path.t -> Mikhailsky.node SM.t = + let open SM in + fun node path -> + match node with + | Micheline.Int (_, _) | Micheline.String (_, _) | Micheline.Bytes (_, _) + -> + return node + | Micheline.Prim (_, I_Hole, _, _) -> ( + deterministic @@ Inference.M.get_instr_annot path >>= function + | None -> cannot_complete_code node path + | Some {bef; aft} -> + deterministic @@ Inference.instantiate bef >>= fun bef -> + deterministic @@ Inference.instantiate aft >>= fun aft -> + invent_term bef aft >>= fun code -> return (Mikhailsky.seq code)) + | Micheline.Prim (_, prim, subterms, _) -> + complete_code_list path 0 subterms [] >>= fun subterms -> + return (Mikhailsky.prim prim subterms []) + | Micheline.Seq (_, subterms) -> + complete_code_list path 0 subterms [] >>= fun subterms -> + return (Mikhailsky.seq subterms) + + and complete_code_list path i subterms acc = + let open SM in + match subterms with + | [] -> return (List.rev acc) + | subterm :: tl -> + let path' = Kernel.Path.at_index i path in + complete_code subterm path' >>= fun term -> + complete_code_list path (i + 1) tl (term :: acc) + + let complete_code typing node rng_state = + let (root_type_opt, _) = + Inference.M.get_instr_annot Kernel.Path.root typing + in + match root_type_opt with + | None -> Stdlib.failwith "Autocomp.complete_code: cannot get type of expr" + | Some {bef; aft} -> + let (_, typing) = Inference.instantiate bef typing in + let (_, typing) = Inference.instantiate aft typing in + let (result, _) = + try complete_code node Kernel.Path.root rng_state typing with + | Autocompletion_error (Cannot_complete_code (subterm, path)) -> + Format.eprintf "Cannot complete code@." ; + Format.eprintf "at path %s@." (Kernel.Path.to_string path) ; + Format.eprintf "%a@." Mikhailsky.pp subterm ; + Stdlib.failwith "in autocomp.ml: unrecoverable failure" + | _ -> assert false + in + let ((bef, aft), typing) = + try Inference.infer_with_state result + with Inference.Ill_typed_script error -> + Format.eprintf "%a@." Inference.pp_inference_error error ; + Format.eprintf "%a@." Mikhailsky.pp result ; + assert false + in + let (bef, typing) = instantiate_and_set_stack bef typing in + let (aft, typing) = instantiate_and_set_stack aft typing in + (result, (bef, aft), typing) +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/dune b/src/proto_011_PtHangzH/lib_benchmark/dune new file mode 100644 index 000000000000..4abc969bf9ec --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/dune @@ -0,0 +1,26 @@ +(library + (name tezos_benchmark_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-benchmark-011-PtHangzH) + (libraries + tezos-base + tezos-protocol-011-PtHangzH + tezos-protocol-011-PtHangzH-parameters + tezos-micheline-rewriting + tezos-benchmark + tezos-benchmark-type-inference-011-PtHangzH + hashcons + benchmark-utils + tezos-011-PtHangzH-test-helpers + staTz) + (library_flags (:standard -linkall)) + (flags (:standard -open Tezos_stdlib + -open Tezos_base + -open Tezos_error_monad + -open Tezos_micheline + -open Tezos_micheline_rewriting + -open Tezos_benchmark + -open Tezos_benchmark_type_inference_011_PtHangzH + -open Tezos_protocol_011_PtHangzH + -open Tezos_crypto + -open Tezos_011_PtHangzH_test_helpers))) diff --git a/src/proto_011_PtHangzH/lib_benchmark/dune-project b/src/proto_011_PtHangzH/lib_benchmark/dune-project new file mode 100644 index 000000000000..ceb4ae87901c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(formatting (enabled_for ocaml)) +(name tezos-benchmark-alpha) diff --git a/src/proto_011_PtHangzH/lib_benchmark/execution_context.ml b/src/proto_011_PtHangzH/lib_benchmark/execution_context.ml new file mode 100644 index 000000000000..6e5251a9c539 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/execution_context.ml @@ -0,0 +1,93 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Error_monad + +type context = Alpha_context.context * Script_interpreter.step_constants + +let context_init_memory ~rng_state = + Context.init + ~rng_state + ~initial_balances: + [ + 4_000_000_000_000L; + 4_000_000_000_000L; + 4_000_000_000_000L; + 4_000_000_000_000L; + 4_000_000_000_000L; + ] + 5 + >>=? fun (block, accounts) -> + match accounts with + | [bs1; bs2; bs3; bs4; bs5] -> + return (`Mem_block (block, (bs1, bs2, bs3, bs4, bs5))) + | _ -> assert false + +let context_init ~rng_state = context_init_memory ~rng_state + +let make ~rng_state = + context_init_memory ~rng_state >>=? fun context -> + let open Script_interpreter in + (match context with + | `Mem_block (block, (bs1, bs2, bs3, _, _)) -> + let source = bs1 in + let payer = bs2 in + let self = bs3 in + let step_constants = + { + source; + payer; + self; + amount = Alpha_context.Tez.one; + chain_id = Chain_id.zero; + } + in + return (block, step_constants) + | `Disk_block (block, source) -> + let step_constants = + { + source; + payer = source; + self = source; + amount = Alpha_context.Tez.one; + chain_id = Chain_id.zero; + } + in + return (block, step_constants)) + >>=? fun (block, step_constants) -> + Incremental.begin_construction + ~priority:0 + ~timestamp:(Time.Protocol.add block.header.shell.timestamp 30L) + block + >>=? fun vs -> + let ctxt = Incremental.alpha_ctxt vs in + let ctxt = + (* Required for eg Create_contract *) + Protocol.Alpha_context.Contract.init_origination_nonce + ctxt + Operation_hash.zero + in + return (ctxt, step_constants) diff --git a/src/proto_011_PtHangzH/lib_benchmark/generators.ml b/src/proto_011_PtHangzH/lib_benchmark/generators.ml new file mode 100644 index 000000000000..ee5f53b3c943 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/generators.ml @@ -0,0 +1,146 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module Code (X : sig + module Samplers : Michelson_samplers_base.Full_S + + val rng_state : Random.State.t + + val target_size : int + + val verbosity : [`Silent | `Progress | `Trace] +end) = +struct + module Autocomp = Autocomp.Make (X.Samplers) + + module MCMC = Sampler.Make (struct + let initial = + let term = Mikhailsky.Instructions.hole in + let typing = Lazy.from_val @@ snd (Inference.infer_with_state term) in + {State_space.term; typing} + + let energy state = + let stats = State_space.statistics state in + let size_deficit = + abs_float + (float_of_int X.target_size -. float_of_int stats.State_space.size) + in + let holes_proportion = float stats.holes /. float stats.size in + let holes_deficit = + (* we want at least 1% of holes, above is ok *) + if holes_proportion < 0.01 then + (0.01 -. holes_proportion) *. size_deficit + else 0.0 + in + size_deficit +. holes_deficit + + let rules = Rules.Instruction.rules + + let infer term = snd (Inference.infer_with_state term) + + let verbosity = X.verbosity + end) + + let to_michelson ({typing; term} : State_space.t) = + let typing = Lazy.force typing in + let (node, typ, state) = Autocomp.complete_code typing term X.rng_state in + let node = + Micheline.strip_locations @@ Michelson.of_mikhailsky node state + in + (node, typ) + + let generator ~burn_in = + let open StaTz in + Stats.map_gen to_michelson (MCMC.generator ~burn_in) +end + +module Data (X : sig + module Samplers : Michelson_samplers_base.Full_S + + val rng_state : Random.State.t + + val target_size : int + + val verbosity : [`Silent | `Progress | `Trace] +end) = +struct + module Autocomp = Autocomp.Make (X.Samplers) + module Rewrite_rules = Rules.Data_rewrite_leaves (X.Samplers) + + module MCMC = Sampler.Make (struct + let initial = + let term = Mikhailsky.Data.hole in + let typing = + Lazy.from_val @@ snd (Inference.infer_data_with_state term) + in + {State_space.term; typing} + + let energy state = + let stats = State_space.statistics state in + let size_deficit = + abs_float + (float_of_int X.target_size -. float_of_int stats.State_space.size) + in + let holes_proportion = + float_of_int stats.holes /. float_of_int stats.size + in + let holes_deficit = + (* we want at least 10% of holes, above is ok *) + if holes_proportion < 0.5 then (0.5 -. holes_proportion) *. size_deficit + else 0.0 + in + let depth_deficit = + abs_float + ((0.1 *. float_of_int X.target_size) -. float_of_int stats.depth) + in + size_deficit +. holes_deficit +. depth_deficit + + let rules = Rewrite_rules.rules X.rng_state + + let infer term = snd (Inference.infer_data_with_state term) + + let verbosity = X.verbosity + end) + + let to_michelson ({typing; term} : State_space.t) = + let typing = Lazy.force typing in + let (node, _) = Autocomp.complete_data typing term X.rng_state in + let (typ, state) = + try Inference.infer_data_with_state node + with _ -> + Format.eprintf "Bug found!@." ; + Format.eprintf "Ill-typed autocompletion. Resulting term:@." ; + Format.eprintf "%a@." Mikhailsky.pp node ; + Stdlib.failwith "in generators.ml: unrecoverable failure" + in + let node = + Micheline.strip_locations @@ Michelson.of_mikhailsky node state + in + (node, typ) + + let generator ~burn_in = + let open StaTz in + Stats.map_gen to_michelson (MCMC.generator ~burn_in) +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/kernel.ml b/src/proto_011_PtHangzH/lib_benchmark/kernel.ml new file mode 100644 index 000000000000..0932302aa20b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/kernel.ml @@ -0,0 +1,39 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* ------------------------------------------------------------------------- *) +(* Instantiate rewriting subsystem *) + +module Lang = + Micheline_with_hash_consing.Make + (Mikhailsky.Mikhailsky_signature) + (struct + let initial_size = None + end) + +module Path = Mikhailsky.Path +module Patt = Pattern.Make (Mikhailsky.Mikhailsky_signature) (Lang) (Path) +module Rewriter = + Rewrite.Make (Mikhailsky.Mikhailsky_signature) (Lang) (Path) (Patt) diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/.ocamlformat b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/dune b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/dune new file mode 100644 index 000000000000..983527aad510 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/dune @@ -0,0 +1,17 @@ +(library + (name tezos_benchmark_type_inference_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-benchmark-type-inference-011-PtHangzH) + (libraries + tezos-stdlib + tezos-error-monad + tezos-crypto + tezos-micheline + tezos-protocol-011-PtHangzH + tezos-micheline-rewriting + hashcons) + (flags (:standard -open Tezos_stdlib + -open Tezos_error_monad + -open Tezos_micheline + -open Tezos_micheline_rewriting + -open Tezos_protocol_011_PtHangzH))) diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/dune-project b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/dune-project new file mode 100644 index 000000000000..7eba7cc6ede3 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(name tezos-benchmark-type-inference-alpha) +(formatting (enabled_for ocaml)) diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/inference.ml b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/inference.ml new file mode 100644 index 000000000000..72dc6c1ef4be --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/inference.ml @@ -0,0 +1,1150 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Micheline +module UF = Uf.UF + +(* The domain of comparability: + * + * Comparable Not_comparable + * ^ ^ + * \ / + * \ / + * Unconstrained + * + * The higher we go, the more information we have. + * This domain admits all glbs but not all lubs. + *) + +type comparability = Comparable | Not_comparable | Unconstrained + +let pp_comparability fmtr (cmp : comparability) = + match cmp with + | Comparable -> Format.fprintf fmtr "Comparable" + | Not_comparable -> Format.fprintf fmtr "Not_comparable" + | Unconstrained -> Format.fprintf fmtr "Unconstrained" + +let sup_comparability (c1 : comparability) (c2 : comparability) = + match (c1, c2) with + | (Unconstrained, c) | (c, Unconstrained) -> Some c + | (Comparable, Comparable) -> Some Comparable + | (Not_comparable, Not_comparable) -> Some Not_comparable + | (Comparable, Not_comparable) | (Not_comparable, Comparable) -> None + +type michelson_type = + | Base_type of {repr : Type.Base.t option; comparable : comparability} + | Stack_type of Type.Stack.t option + +type transformer = {bef : Type.Stack.t; aft : Type.Stack.t} + +let michelson_type_to_string (x : michelson_type) = + match x with + | Base_type {repr = None; comparable} -> + Format.asprintf "?::[%a]" pp_comparability comparable + | Base_type {repr = Some ty; comparable} -> + Format.asprintf "%a::[%a]" Type.Base.pp ty pp_comparability comparable + | Stack_type None -> "" + | Stack_type (Some sty) -> Format.asprintf "%a" Type.Stack.pp sty + +(* ------------------------------------------------------------------------- *) +(* Typechecking errors *) + +type inference_error = + (* | Expected_data_with_ground_type of Mikhailsky.Path.t * Mikhailsky.node *) + | Unhandled_micheline of Mikhailsky.Path.t * Mikhailsky.node + | Expected_micheline_prim + | Unsatisfiable_comparability_constraint of comparability_error_witness + | Base_types_incompatible of Type.Base.t * Type.Base.t + | Stack_types_incompatible of Type.Stack.t * Type.Stack.t + | Badly_typed_arithmetic of Mikhailsky_prim.prim * Type.Base.t * Type.Base.t + | Ill_formed_arithmetic of Mikhailsky.Path.t * Mikhailsky.node + | Cyclic_stack_type + | Cyclic_base_type + | Invalid_ast of string option * Mikhailsky.Path.t * Mikhailsky.node + +and comparability_error_witness = + | Comparability_error_types of michelson_type * michelson_type + | Comparability_error_tags of Type.Base.t * comparability * comparability + +let pp_inference_error fmtr (err : inference_error) = + match err with + (* | Expected_data_with_ground_type (path, node) -> + * let path = Mikhailsky.Path.to_string path in + * let node = Mikhailsky.to_string node in + * Format.fprintf fmtr "Expected data with ground type: %s at path %s" node path *) + | Unhandled_micheline (path, node) -> + let path = Mikhailsky.Path.to_string path in + let node = Mikhailsky.to_string node in + Format.fprintf fmtr "Unhandled micheline: %s at path %s" node path + | Expected_micheline_prim -> + Format.fprintf fmtr "%s" "Expected_micheline_prim" + | Unsatisfiable_comparability_constraint + (Comparability_error_types (ty1, ty2)) -> + let ty1 = michelson_type_to_string ty1 in + let ty2 = michelson_type_to_string ty2 in + Format.fprintf + fmtr + "Unsatisfiable comparability constraint: %s # %s" + ty1 + ty2 + | Unsatisfiable_comparability_constraint + (Comparability_error_tags (ty, cmp1, cmp2)) -> + Format.fprintf + fmtr + "Unsatisfiable comparability constraint: %a :: %a # %a" + Type.Base.pp + ty + pp_comparability + cmp1 + pp_comparability + cmp2 + | Base_types_incompatible (ty1, ty2) -> + Format.fprintf + fmtr + "Base types incompatible: %a %a" + Type.Base.pp + ty1 + Type.Base.pp + ty2 + | Stack_types_incompatible (sty1, sty2) -> + Format.fprintf + fmtr + "Stack types incompatible: %a %a" + Type.Stack.pp + sty1 + Type.Stack.pp + sty2 + | Badly_typed_arithmetic (prim, ty1, ty2) -> + Format.fprintf + fmtr + "Badly typed arithmetic: %a(%a, %a)" + Mikhailsky_prim.pp + prim + Type.Base.pp + ty1 + Type.Base.pp + ty2 + | Ill_formed_arithmetic (path, node) -> + let path = Mikhailsky.Path.to_string path in + let node = Mikhailsky.to_string node in + Format.fprintf fmtr "Ill formed arithmetic: %s at path %s" node path + | Cyclic_stack_type -> Format.fprintf fmtr "Cyclic stack type" + | Cyclic_base_type -> Format.fprintf fmtr "Cyclic base type" + | Invalid_ast (msg_opt, path, node) -> ( + let path = Mikhailsky.Path.to_string path in + let node = Mikhailsky.to_string node in + match msg_opt with + | None -> Format.fprintf fmtr "Invalid ast: %s at path %s" node path + | Some msg -> + Format.fprintf fmtr "Invalid ast: %s at path %s (%s)" node path msg) + +exception Ill_typed_script of inference_error + +let unsatisfiable_comparability ty cmp1 cmp2 = + raise + (Ill_typed_script + (Unsatisfiable_comparability_constraint + (Comparability_error_tags (ty, cmp1, cmp2)))) + +let invalid_ast ?msg path node = + raise (Ill_typed_script (Invalid_ast (msg, path, node))) + +let () = + Printexc.register_printer (fun exn -> + match exn with + | Ill_typed_script error -> + Some (Format.asprintf "%a" pp_inference_error error) + | _ -> None) + +(* ------------------------------------------------------------------------- *) + +module Repr_store = + Stores.Map + (Int_map) + (struct + type key = int + + type value = michelson_type + + let key_to_string = string_of_int + + let value_to_string = michelson_type_to_string + end) + +module Repr_sm = Monads.Make_state_monad (Repr_store) +module Path_map = Map.Make (Mikhailsky.Path) + +module Annot_instr_store = + Stores.Map + (Path_map) + (struct + type key = Mikhailsky.Path.t + + type value = transformer + + let key_to_string = Mikhailsky.Path.to_string + + let value_to_string {bef; aft} = + Format.asprintf "%a => %a" Type.Stack.pp bef Type.Stack.pp aft + end) + +module Annot_instr_sm = Monads.Make_state_monad (Annot_instr_store) + +module Annot_data_store = + Stores.Map + (Path_map) + (struct + type key = Mikhailsky.Path.t + + type value = Type.Base.t + + let key_to_string = Mikhailsky.Path.to_string + + let value_to_string ty = Format.asprintf "%a" Type.Base.pp ty + end) + +module Annot_data_sm = Monads.Make_state_monad (Annot_data_store) + +type state = { + uf : UF.M.state; + repr : Repr_sm.state; + annot_instr : Annot_instr_sm.state; + annot_data : Annot_data_sm.state; +} + +module M = struct + type 'a t = state -> 'a * state + + let empty : unit -> state = + fun () -> + { + uf = UF.M.empty (); + repr = Repr_sm.empty (); + annot_instr = Annot_instr_sm.empty (); + annot_data = Annot_data_sm.empty (); + } + + let ( >>= ) m f s = + let (x, s) = m s in + f x s + [@@inline] + + let return x s = (x, s) + + (* let run m = fst (m (empty ())) *) + + let uf_lift : 'a UF.M.t -> 'a t = + fun computation state -> + let (res, uf) = computation state.uf in + (res, {state with uf}) + [@@inline] + + let repr_lift : 'a Repr_sm.t -> 'a t = + fun computation state -> + let (res, repr) = computation state.repr in + (res, {state with repr}) + [@@inline] + + let annot_instr_lift : 'a Annot_instr_sm.t -> 'a t = + fun computation state -> + let (res, annot_instr) = computation state.annot_instr in + (res, {state with annot_instr}) + [@@inline] + + let annot_data_lift : 'a Annot_data_sm.t -> 'a t = + fun computation state -> + let (res, annot_data) = computation state.annot_data in + (res, {state with annot_data}) + [@@inline] + + let set_repr k v = repr_lift (Repr_sm.set k v) [@@inline] + + let get_repr_exn k = + repr_lift (Repr_sm.get k) >>= function + | None -> Stdlib.failwith "get_repr_exn" + | Some res -> return res + [@@inline] + + let set_instr_annot k v = annot_instr_lift (Annot_instr_sm.set k v) [@@inline] + + let get_instr_annot k = annot_instr_lift (Annot_instr_sm.get k) [@@inline] + + let set_data_annot k v = annot_data_lift (Annot_data_sm.set k v) [@@inline] + + let get_data_annot k = annot_data_lift (Annot_data_sm.get k) [@@inline] + + let get_state state = (state, state) +end + +module S = Set.Make (Int) + +let rec instantiate (encountered : S.t) (stack_ty : Type.Stack.t) : + Type.Stack.t M.t = + let open Type.Stack in + let open M in + if S.mem stack_ty.tag encountered then + raise (Ill_typed_script Cyclic_stack_type) + else + let encountered = S.add stack_ty.tag encountered in + match stack_ty.node with + | Empty_t -> return stack_ty + | Stack_var_t x -> ( + uf_lift (UF.find x) >>= fun root -> + get_repr_exn root >>= function + | Stack_type None -> return (Type.stack_var root) + | Stack_type (Some ty) -> instantiate encountered ty + | _ -> assert false) + | Item_t (head, tail) -> + instantiate_base S.empty head >>= fun head -> + instantiate encountered tail >>= fun tail -> + return (Type.item head tail) + +and instantiate_base (encountered : S.t) (ty : Type.Base.t) : Type.Base.t M.t = + let open Type.Base in + let open M in + if S.mem ty.tag encountered then raise (Ill_typed_script Cyclic_base_type) + else + let encountered = S.add ty.tag encountered in + match ty.node with + | Unit_t | Int_t | Nat_t | Bool_t | String_t | Bytes_t | Key_hash_t | Key_t + | Timestamp_t | Mutez_t -> + return ty + | Option_t ty -> + instantiate_base encountered ty >>= fun ty -> return (Type.option ty) + | List_t ty -> + instantiate_base encountered ty >>= fun ty -> return (Type.list ty) + | Set_t ty -> + instantiate_base encountered ty >>= fun ty -> return (Type.set ty) + | Map_t (kty, vty) -> + instantiate_base encountered kty >>= fun kty -> + instantiate_base encountered vty >>= fun vty -> + return (Type.map kty vty) + | Pair_t (lty, rty) -> + instantiate_base encountered lty >>= fun lty -> + instantiate_base encountered rty >>= fun rty -> + return (Type.pair lty rty) + | Union_t (lty, rty) -> + instantiate_base encountered lty >>= fun lty -> + instantiate_base encountered rty >>= fun rty -> + return (Type.union lty rty) + | Lambda_t (dom, range) -> + instantiate_base encountered dom >>= fun dom -> + instantiate_base encountered range >>= fun range -> + return (Type.lambda dom range) + | Var_t x -> ( + uf_lift (UF.find x) >>= fun root -> + get_repr_exn root >>= function + | Base_type {repr = None; _} -> return (Type.var root) + | Base_type {repr = Some ty; _} -> instantiate_base encountered ty + | _ -> assert false) + +let instantiate_base base_ty = instantiate_base S.empty base_ty + +let instantiate stack_ty = instantiate S.empty stack_ty + +let rec unify (x : Type.Stack.t) (y : Type.Stack.t) : unit M.t = + let open Type.Stack in + let open M in + let unify_single_stack v x = + (match Type.Stack.vars x with + | None -> return () + | Some v' -> + if v = v' then raise (Ill_typed_script Cyclic_stack_type) else return ()) + >>= fun () -> + M.uf_lift (UF.find v) >>= fun root -> + get_repr_exn root >>= fun repr -> + merge_reprs (Stack_type (Some x)) repr >>= fun repr -> set_repr root repr + in + if x.tag = y.tag then return () + else + match (x.node, y.node) with + | (Empty_t, Empty_t) -> return () + | (Stack_var_t x, Stack_var_t y) -> + M.uf_lift (UF.find x) >>= fun root_x -> + M.uf_lift (UF.find y) >>= fun root_y -> + get_repr_exn root_x >>= fun repr_x -> + get_repr_exn root_y >>= fun repr_y -> + M.uf_lift (UF.union x y) >>= fun root -> + merge_reprs repr_x repr_y >>= fun repr -> set_repr root repr + | (Stack_var_t v, _) -> unify_single_stack v y + | (_, Stack_var_t v) -> unify_single_stack v x + | (Item_t (ty1, tail1), Item_t (ty2, tail2)) -> + unify_base ty1 ty2 >>= fun () -> + unify tail1 tail2 >>= fun () -> return () + | _ -> raise (Ill_typed_script (Stack_types_incompatible (x, y))) + +and unify_base (x : Type.Base.t) (y : Type.Base.t) : unit M.t = + let open Type.Base in + let open M in + let unify_single_var v x = + (if List.mem v (Type.Base.vars x) then + raise (Ill_typed_script Cyclic_base_type) + else return ()) + >>= fun () -> + M.uf_lift (UF.find v) >>= fun root -> + get_repr_exn root >>= fun repr -> + get_comparability x >>= fun comparable -> + merge_reprs (Base_type {repr = Some x; comparable}) repr >>= fun repr -> + set_repr root repr + in + if x.tag = y.tag then return () + else + match (x.node, y.node) with + | (Unit_t, Unit_t) + | (Int_t, Int_t) + | (Nat_t, Nat_t) + | (Bool_t, Bool_t) + | (String_t, String_t) + | (Bytes_t, Bytes_t) + | (Key_hash_t, Key_hash_t) + | (Timestamp_t, Timestamp_t) + | (Mutez_t, Mutez_t) + | (Key_t, Key_t) -> + return () + | (Option_t x, Option_t y) -> unify_base x y + | (List_t x, List_t y) -> unify_base x y + | (Set_t x, Set_t y) -> unify_base x y + | (Map_t (kx, vx), Map_t (ky, vy)) -> + unify_base kx ky >>= fun () -> unify_base vx vy + | (Pair_t (x, x'), Pair_t (y, y')) -> + unify_base x y >>= fun () -> unify_base x' y' + | (Union_t (x, x'), Union_t (y, y')) -> + unify_base x y >>= fun () -> unify_base x' y' + | (Lambda_t (x, x'), Lambda_t (y, y')) -> + unify_base x y >>= fun () -> unify_base x' y' + | (Var_t x, Var_t y) -> + M.uf_lift (UF.find x) >>= fun root_x -> + M.uf_lift (UF.find y) >>= fun root_y -> + get_repr_exn root_x >>= fun repr_x -> + get_repr_exn root_y >>= fun repr_y -> + M.uf_lift (UF.union x y) >>= fun root -> + merge_reprs repr_x repr_y >>= fun repr -> set_repr root repr + | (Var_t v, _) -> unify_single_var v y + | (_, Var_t v) -> unify_single_var v x + | _ -> + instantiate_base x >>= fun x -> + instantiate_base y >>= fun y -> + raise (Ill_typed_script (Base_types_incompatible (x, y))) + +and merge_reprs (repr1 : michelson_type) (repr2 : michelson_type) : + michelson_type M.t = + let open M in + match (repr1, repr2) with + | ((Stack_type None as repr), Stack_type None) + | ((Stack_type (Some _) as repr), Stack_type None) + | (Stack_type None, (Stack_type (Some _) as repr)) -> + return repr + | ((Stack_type (Some sty1) as repr), Stack_type (Some sty2)) -> + unify sty1 sty2 >>= fun () -> return repr + | ( Base_type {repr = opt1; comparable = cmp1}, + Base_type {repr = opt2; comparable = cmp2} ) -> ( + let comparable_opt = sup_comparability cmp1 cmp2 in + match comparable_opt with + | None -> + raise + (Ill_typed_script + (Unsatisfiable_comparability_constraint + (Comparability_error_types (repr1, repr2)))) + | Some comparable -> ( + match (opt1, opt2) with + | (None, None) -> return (Base_type {repr = None; comparable}) + | ((Some ty as repr), None) -> + assert_comparability comparable ty >>= fun () -> + return (Base_type {repr; comparable}) + | (None, (Some ty as repr)) -> + assert_comparability comparable ty >>= fun () -> + return (Base_type {repr; comparable}) + | (Some ty1, Some ty2) -> + unify_base ty1 ty2 >>= fun () -> + assert_comparability comparable ty1 >>= fun () -> + assert_comparability comparable ty2 >>= fun () -> + return (Base_type {repr = opt1; comparable}))) + | _ -> assert false + +and assert_comparability comparable ty = + assert_comparability_aux comparable ty [] + +and assert_comparability_aux lower_bound (ty : Type.Base.t) + (encountered : int list) : unit M.t = + let open M in + if List.mem ty.tag encountered then raise (Ill_typed_script Cyclic_base_type) + else + let encountered = ty.tag :: encountered in + match ty.node with + | Var_t v -> ( + uf_lift (UF.find v) >>= fun root -> + get_repr_exn root >>= fun repr -> + match repr with + | Base_type {repr = None; comparable} -> ( + match sup_comparability comparable lower_bound with + | None -> unsatisfiable_comparability ty comparable lower_bound + | Some comparable -> + set_repr root (Base_type {repr = None; comparable})) + | Base_type {repr = Some ty; comparable} -> ( + match sup_comparability comparable lower_bound with + | None -> unsatisfiable_comparability ty comparable lower_bound + | Some comparable -> + assert_comparability_aux lower_bound ty encountered + >>= fun () -> + set_repr root (Base_type {repr = Some ty; comparable})) + | Stack_type _ -> assert false) + | List_t _ | Set_t _ | Map_t _ | Lambda_t _ | Key_t -> ( + match lower_bound with + | Unconstrained | Not_comparable -> return () + | Comparable -> unsatisfiable_comparability ty Unconstrained lower_bound + ) + | Unit_t | Int_t | Nat_t | Bool_t | String_t | Bytes_t | Key_hash_t + | Timestamp_t | Mutez_t -> + (* if not (le_comparability lower_bound Comparable) then + * unsatisfiable_comparability ty Comparable lower_bound + * else *) + return () + | Option_t ty -> ( + match lower_bound with + | Comparable -> assert_comparability_aux Comparable ty encountered + | Not_comparable | Unconstrained -> return ()) + | Pair_t (l, r) -> ( + match lower_bound with + | Comparable -> + assert_comparability_aux Comparable l encountered >>= fun () -> + assert_comparability_aux Comparable r encountered + | Unconstrained | Not_comparable -> return ()) + | Union_t (l, r) -> ( + match lower_bound with + | Comparable -> + assert_comparability_aux Comparable l encountered >>= fun () -> + assert_comparability_aux Comparable r encountered + | Unconstrained | Not_comparable -> return ()) + +and get_comparability (ty : Type.Base.t) : comparability M.t = + let open M in + match ty.node with + | Var_t v -> ( + get_repr_exn v >>= fun repr -> + match repr with + | Stack_type _ -> assert false + | Base_type {comparable; _} -> return comparable) + | Unit_t | Int_t | Nat_t | Bool_t | String_t | Bytes_t | Key_hash_t + | Timestamp_t | Mutez_t -> + return Comparable + | List_t _ | Set_t _ | Map_t _ | Lambda_t _ | Key_t -> return Not_comparable + | Option_t ty -> get_comparability ty + | Union_t (lt, rt) | Pair_t (lt, rt) -> ( + get_comparability lt >>= fun lc -> + get_comparability rt >>= fun rc -> + match (lc, rc) with + | (Comparable, Comparable) -> return Comparable + | _ -> return Unconstrained) + +let fresh = + let x = ref ~-1 in + fun () -> + incr x ; + !x + +let exists_stack : unit -> Type.Stack.t M.t = + let open M in + fun () -> + let fresh = fresh () in + uf_lift (UF.add fresh) >>= fun () -> + set_repr fresh (Stack_type None) >>= fun () -> return (Type.stack_var fresh) + +let exists : unit -> Type.Base.t M.t = + let open M in + fun () -> + let fresh = fresh () in + uf_lift (UF.add fresh) >>= fun () -> + set_repr fresh (Base_type {repr = None; comparable = Unconstrained}) + >>= fun () -> return (Type.var fresh) + +let exists_cmp : unit -> Type.Base.t M.t = + let open M in + fun () -> + let fresh = fresh () in + uf_lift (UF.add fresh) >>= fun () -> + set_repr fresh (Base_type {repr = None; comparable = Comparable}) + >>= fun () -> return (Type.var fresh) + +(* Adapted from [script_ir_translator] *) +let parse_uint30 n : int = + let max_uint30 = 0x3fffffff in + match n with + | Micheline.Int (_, n') + when Compare.Z.(Z.zero <= n') && Compare.Z.(n' <= Z.of_int max_uint30) -> + Z.to_int n' + | _ -> assert false + +(* encodes the per-instruction relationship between input and output types + of binary arithmetic operations. *) +let arith_type (instr : Mikhailsky_prim.prim) (ty1 : Type.Base.t) + (ty2 : Type.Base.t) : Type.Base.t option = + match (instr, ty1.node, ty2.node) with + | ((I_ADD | I_MUL), Int_t, Int_t) + | ((I_ADD | I_MUL), Int_t, Nat_t) + | ((I_ADD | I_MUL), Nat_t, Int_t) -> + Some Type.int + | ((I_ADD | I_MUL), Nat_t, Nat_t) -> Some Type.nat + | (I_SUB, Int_t, Int_t) + | (I_SUB, Int_t, Nat_t) + | (I_SUB, Nat_t, Int_t) + | (I_SUB, Nat_t, Nat_t) + | (I_SUB, Timestamp_t, Timestamp_t) -> + Some Type.int + | (I_EDIV, Int_t, Int_t) + | (I_EDIV, Int_t, Nat_t) + | (I_EDIV, Nat_t, Int_t) + | (I_EDIV, Nat_t, Nat_t) -> + Some Type.(option (pair nat nat)) + (* Timestamp *) + | (I_ADD, Timestamp_t, Int_t) + | (I_ADD, Int_t, Timestamp_t) + | (I_SUB, Timestamp_t, Int_t) -> + Some Type.timestamp + (* Mutez *) + | (I_ADD, Mutez_t, Mutez_t) + | (I_SUB, Mutez_t, Mutez_t) + | (I_MUL, Mutez_t, Nat_t) + | (I_MUL, Nat_t, Mutez_t) -> + Some Type.mutez + | (I_EDIV, Mutez_t, Nat_t) -> Some Type.(option (pair mutez mutez)) + | (I_EDIV, Mutez_t, Mutez_t) -> Some Type.(option (pair nat mutez)) + | _ -> None + +let rec generate_constraints (path : Mikhailsky.Path.t) (node : Mikhailsky.node) + (bef : Type.Stack.t) (aft : Type.Stack.t) : unit M.t = + let open M in + set_instr_annot path {bef; aft} >>= fun () -> + match node with + | Int (_, _) -> + assert false (* Ints should always be guarded by annotations *) + | String (_, _) | Bytes (_, _) -> + raise (Ill_typed_script Expected_micheline_prim) + (* Hole *) + | Prim (_, I_Hole, [], _) -> return () + (* Stack ops - simple cases *) + | Prim (_loc, I_DROP, [], _annot) -> + exists () >>= fun top -> unify bef (Type.item top aft) + | Prim (_loc, I_DROP, [n], _annot) -> + let n = parse_uint30 n in + generate_constraints_dropn n bef aft + | Prim (_loc, I_DUP, [], _annot) -> + exists () >>= fun top -> + exists_stack () >>= fun rest -> + unify bef Type.(item top rest) >>= fun () -> + unify aft Type.(item top (item top rest)) + | Prim (_loc, I_SWAP, [], _annot) -> + exists () >>= fun a -> + exists () >>= fun b -> + exists_stack () >>= fun rest -> + unify bef Type.(item a (item b rest)) >>= fun () -> + unify aft Type.(item b (item a rest)) + | Prim (_loc, I_PUSH, [t; d], _annot) -> + let ty = + Mikhailsky.parse_ty + ~allow_big_map:false + ~allow_operation:false + ~allow_contract:false + t + in + generate_constraints_data (Mikhailsky.Path.at_index 1 path) d ty + >>= fun () -> + (* assert_data_has_ground_type (Mikhailsky.Path.at_index 1 path) d ty >>= fun () -> *) + unify aft Type.(item ty bef) + | Prim (_loc, I_UNIT, [], _annot) -> unify aft Type.(item unit bef) + | Prim (_loc, I_DIP, [code], _annot) -> + exists () >>= fun top -> + exists_stack () >>= fun bef_rest -> + exists_stack () >>= fun aft_rest -> + unify bef Type.(item top bef_rest) >>= fun () -> + unify aft Type.(item top aft_rest) >>= fun () -> + generate_constraints + (Mikhailsky.Path.at_index 0 path) + code + bef_rest + aft_rest + (* TODO: DIGn, etc *) + (* Option-related instructions *) + | Prim (_, I_SOME, [], _) -> + exists () >>= fun top -> + exists_stack () >>= fun rest -> + unify bef Type.(item top rest) >>= fun () -> + unify aft Type.(item (option top) rest) + | Prim (_, I_NONE, [t], _) -> + let ty = + Mikhailsky.parse_ty + ~allow_big_map:true + ~allow_operation:true + ~allow_contract:true + t + in + unify aft Type.(item (option ty) bef) + | Prim (_, I_IF_NONE, [bt; bf], _) -> + exists () >>= fun a -> + exists_stack () >>= fun rest -> + unify bef Type.(item (option a) rest) >>= fun () -> + generate_constraints (Mikhailsky.Path.at_index 0 path) bt rest aft + >>= fun () -> + generate_constraints + (Mikhailsky.Path.at_index 1 path) + bf + Type.(item a rest) + aft + (* bool-based control flow *) + | Prim (_, I_IF, [bt; bf], _) -> + exists_stack () >>= fun rest -> + unify bef Type.(item bool rest) >>= fun () -> + generate_constraints (Mikhailsky.Path.at_index 0 path) bt rest aft + >>= fun () -> + generate_constraints (Mikhailsky.Path.at_index 1 path) bf rest aft + | Prim (_, I_LOOP, [body], _) -> + unify bef Type.(item bool aft) >>= fun () -> + generate_constraints (Mikhailsky.Path.at_index 0 path) body aft bef + (* Boolean binops *) + | Prim (_, I_AND, [], _) | Prim (_, I_OR, [], _) | Prim (_, I_XOR, [], _) -> + exists_stack () >>= fun rest -> + unify bef Type.(item bool (item bool rest)) >>= fun () -> + unify aft Type.(item bool rest) + (* Arithmetic *) + | Prim (_, ((I_ADD | I_SUB | I_MUL | I_EDIV) as instr), [ty1; ty2], _) -> ( + let ty1 = + Mikhailsky.parse_ty + ~allow_big_map:false + ~allow_operation:false + ~allow_contract:false + ty1 + in + let ty2 = + Mikhailsky.parse_ty + ~allow_big_map:false + ~allow_operation:false + ~allow_contract:false + ty2 + in + match arith_type instr ty1 ty2 with + | None -> + raise (Ill_typed_script (Badly_typed_arithmetic (instr, ty1, ty2))) + | Some ret -> + exists_stack () >>= fun rest -> + unify bef Type.(item ty1 (item ty2 rest)) >>= fun () -> + unify aft Type.(item ret rest)) + | Prim (_, (I_ADD | I_SUB | I_MUL | I_EDIV), _, _) -> + raise (Ill_typed_script (Ill_formed_arithmetic (path, node))) + | Prim (_, I_COMPARE, [], _) -> + exists_cmp () >>= fun a -> + exists_stack () >>= fun rest -> + unify bef Type.(item a (item a rest)) >>= fun () -> + unify aft Type.(item int rest) + | Prim (_, I_ABS, [], _) -> + exists_stack () >>= fun rest -> + unify bef Type.(item int rest) >>= fun () -> + unify aft Type.(item nat rest) + | Prim (_, I_GT, [], _) -> + exists_stack () >>= fun rest -> + unify bef Type.(item int rest) >>= fun () -> + unify aft Type.(item bool rest) + (* Strings/bytes *) + | Prim (_, I_CONCAT, [], _) -> + exists_stack () >>= fun rest -> + unify bef Type.(item string (item string rest)) >>= fun () -> + unify aft Type.(item string rest) + | Prim (_, I_SIZE_STRING, [], _) -> + exists_stack () >>= fun rest -> + unify bef Type.(item string rest) >>= fun () -> + unify aft Type.(item nat rest) + | Prim (_, I_SIZE_BYTES, [], _) -> + exists_stack () >>= fun rest -> + unify bef Type.(item bytes rest) >>= fun () -> + unify aft Type.(item nat rest) + (* Crypto *) + | Prim (_, I_SHA256, [], _) + | Prim (_, I_SHA512, [], _) + | Prim (_, I_BLAKE2B, [], _) -> + exists_stack () >>= fun rest -> + unify bef Type.(item bytes rest) >>= fun () -> + unify aft Type.(item bytes rest) + | Prim (_, I_HASH_KEY, [], _) -> + exists_stack () >>= fun rest -> + unify bef Type.(item key rest) >>= fun () -> + unify aft Type.(item key_hash rest) + (* sets *) + | Prim (_, I_EMPTY_SET, [], _) -> + exists_cmp () >>= fun cmpty -> unify aft Type.(item (set cmpty) bef) + | Prim (_, I_UPDATE_SET, [], _) -> + exists_cmp () >>= fun cty -> + exists_stack () >>= fun rest -> + unify bef Type.(item cty (item bool (item (set cty) rest))) >>= fun () -> + unify aft Type.(item (set cty) rest) + | Prim (_, I_SIZE_SET, [], _) -> + exists_cmp () >>= fun cmpty -> + exists_stack () >>= fun rest -> + unify bef Type.(item (set cmpty) rest) >>= fun () -> + unify aft Type.(item nat rest) + | Prim (_, I_ITER_SET, [code], _) -> + exists_cmp () >>= fun cmpty -> + unify bef Type.(item (set cmpty) aft) >>= fun () -> + generate_constraints + (Mikhailsky.Path.at_index 0 path) + code + Type.(item cmpty aft) + aft + | Prim (_, I_MEM_SET, [], _) -> + exists_cmp () >>= fun cmpty -> + exists_stack () >>= fun rest -> + unify bef Type.(item cmpty (item (set cmpty) rest)) >>= fun () -> + unify aft Type.(item bool rest) + (* maps *) + | Prim (_, I_EMPTY_MAP, [], _) -> + exists_cmp () >>= fun kty -> + exists () >>= fun vty -> unify aft Type.(item (map kty vty) bef) + | Prim (_, I_UPDATE_MAP, [], _) -> + exists_cmp () >>= fun kty -> + exists () >>= fun vty -> + exists_stack () >>= fun rest -> + unify bef Type.(item kty (item (option vty) (item (map kty vty) rest))) + >>= fun () -> unify aft Type.(item (map kty vty) rest) + | Prim (_, I_SIZE_MAP, [], _) -> + exists_cmp () >>= fun kty -> + exists () >>= fun vty -> + exists_stack () >>= fun rest -> + unify bef Type.(item (map kty vty) rest) >>= fun () -> + unify aft Type.(item nat rest) + | Prim (_, I_ITER_MAP, [code], _) -> + exists_cmp () >>= fun kty -> + exists () >>= fun vty -> + unify bef Type.(item (map kty vty) aft) >>= fun () -> + generate_constraints + (Mikhailsky.Path.at_index 0 path) + code + Type.(item (pair kty vty) aft) + aft + | Prim (_, I_MAP_MAP, [code], _) -> + exists_cmp () >>= fun kty -> + exists () >>= fun vty1 -> + exists () >>= fun vty2 -> + exists_stack () >>= fun rest -> + unify bef Type.(item (map kty vty1) rest) >>= fun () -> + unify aft Type.(item (map kty vty2) rest) >>= fun () -> + generate_constraints + (Mikhailsky.Path.at_index 0 path) + code + Type.(item (pair kty vty1) rest) + Type.(item vty2 rest) + | Prim (_, I_MEM_MAP, [], _) -> + exists_cmp () >>= fun kty -> + exists () >>= fun vty -> + exists_stack () >>= fun rest -> + unify bef Type.(item kty (item (map kty vty) rest)) >>= fun () -> + unify aft Type.(item bool rest) + | Prim (_, I_GET_MAP, [], _) -> + exists_cmp () >>= fun kty -> + exists () >>= fun vty -> + exists_stack () >>= fun rest -> + unify bef Type.(item kty (item (map kty vty) rest)) >>= fun () -> + unify aft Type.(item (option vty) rest) + (* Pairs *) + | Prim (_, I_PAIR, [], _) -> + exists () >>= fun a -> + exists () >>= fun b -> + exists_stack () >>= fun rest -> + unify bef Type.(item a (item b rest)) >>= fun () -> + unify aft Type.(item (pair a b) rest) + | Prim (_, I_CAR, [], _) -> + exists () >>= fun a -> + exists () >>= fun b -> + exists_stack () >>= fun rest -> + unify bef Type.(item (pair a b) rest) >>= fun () -> + unify aft Type.(item a rest) + | Prim (_, I_CDR, [], _) -> + exists () >>= fun a -> + exists () >>= fun b -> + exists_stack () >>= fun rest -> + unify bef Type.(item (pair a b) rest) >>= fun () -> + unify aft Type.(item b rest) + (* Unions *) + | Prim (_, I_LEFT, [], _) -> + exists () >>= fun lt -> + exists () >>= fun rt -> + exists_stack () >>= fun rest -> + unify bef (Type.item lt rest) >>= fun () -> + unify aft Type.(item (union lt rt) rest) >>= fun res -> return res + | Prim (_, I_RIGHT, [], _) -> + exists () >>= fun lt -> + exists () >>= fun rt -> + exists_stack () >>= fun rest -> + unify bef Type.(item rt rest) >>= fun () -> + unify aft Type.(item (union lt rt) rest) + | Prim (_, (I_LEFT | I_RIGHT), _ :: _, _) -> + invalid_ast ~msg:__LOC__ path node + | Prim (_, I_LOOP_LEFT, [body], _) -> + exists () >>= fun l -> + exists () >>= fun r -> + exists_stack () >>= fun rest -> + unify bef Type.(item (union l r) rest) >>= fun () -> + unify aft Type.(item r rest) >>= fun () -> + generate_constraints + (Mikhailsky.Path.at_index 0 path) + body + Type.(item l rest) + bef + | Prim (_, I_IF_LEFT, [bt; bf], _) -> + exists () >>= fun a -> + exists () >>= fun b -> + exists_stack () >>= fun rest -> + unify bef Type.(item (union a b) rest) >>= fun () -> + generate_constraints + (Mikhailsky.Path.at_index 0 path) + bt + (Type.item a rest) + aft + >>= fun () -> + generate_constraints + (Mikhailsky.Path.at_index 1 path) + bf + (Type.item b rest) + aft + (* lambdas *) + | Prim (_, I_LAMBDA, [code], _) -> + exists () >>= fun dom -> + exists () >>= fun range -> + unify aft Type.(item (lambda dom range) bef) >>= fun () -> + generate_constraints + (Mikhailsky.Path.at_index 0 path) + code + Type.(item dom empty) + Type.(item range empty) + | Prim (_, I_LAMBDA, _, _) -> invalid_ast ~msg:__LOC__ path node + | Prim (_, I_APPLY, [], _) -> + exists () >>= fun a -> + exists () >>= fun b -> + exists () >>= fun ret -> + exists_stack () >>= fun rest -> + unify bef Type.(item a (item (lambda (pair a b) ret) rest)) >>= fun () -> + unify aft Type.(item (lambda b ret) rest) + | Prim (_, I_EXEC, [], _) -> + exists () >>= fun a -> + exists () >>= fun ret -> + exists_stack () >>= fun rest -> + unify bef Type.(item a (item (lambda a ret) rest)) >>= fun () -> + unify aft Type.(item ret rest) + (* lists *) + | Prim (_, I_NIL, [], _) -> + exists () >>= fun a -> unify aft Type.(item (list a) bef) + | Prim (_, I_CONS, [], _) -> + exists () >>= fun a -> + exists_stack () >>= fun rest -> + unify bef Type.(item a (item (list a) rest)) >>= fun () -> + unify aft Type.(item (list a) rest) + | Prim (_, I_SIZE_LIST, [], _) -> + exists () >>= fun ty -> + exists_stack () >>= fun rest -> + unify bef Type.(item (list ty) rest) >>= fun () -> + unify aft Type.(item nat rest) + | Prim (_, I_ITER_LIST, [code], _) -> + exists () >>= fun ty -> + unify bef Type.(item (list ty) aft) >>= fun () -> + generate_constraints + (Mikhailsky.Path.at_index 0 path) + code + Type.(item ty aft) + aft + | Prim (_, I_MAP_LIST, [code], _) -> + exists () >>= fun ty1 -> + exists () >>= fun ty2 -> + exists_stack () >>= fun rest -> + unify bef Type.(item (list ty1) rest) >>= fun () -> + unify aft Type.(item (list ty2) rest) >>= fun () -> + generate_constraints + (Mikhailsky.Path.at_index 0 path) + code + Type.(item ty1 rest) + Type.(item ty2 rest) + (* pack/unpack*) + | Prim (_, I_PACK, [], _) -> + exists () >>= fun ty -> + exists_stack () >>= fun rest -> + unify bef Type.(item ty rest) >>= fun () -> + unify aft Type.(item bytes rest) + | Prim (_, I_UNPACK, [], _) -> + exists () >>= fun ty -> + exists_stack () >>= fun rest -> + unify bef Type.(item bytes rest) >>= fun () -> + unify aft Type.(item (option ty) rest) + (* Others *) + | Seq (_, []) -> unify bef aft + | Seq (_, [single]) -> + generate_constraints (Mikhailsky.Path.at_index 0 path) single bef aft + | Seq (_, instrs) -> generate_constraints_seq path 0 instrs bef aft + | _ -> raise (Ill_typed_script (Unhandled_micheline (path, node))) + +and generate_constraints_seq path index instrs bef aft = + let open M in + match instrs with + | [] -> assert false + | [single] -> + generate_constraints (Mikhailsky.Path.at_index index path) single bef aft + | hd :: tl -> + exists_stack () >>= fun stack_ty -> + generate_constraints (Mikhailsky.Path.at_index index path) hd bef stack_ty + >>= fun () -> generate_constraints_seq path (index + 1) tl stack_ty aft + +and generate_constraints_data (path : Mikhailsky.Path.t) + (node : Mikhailsky.node) (ty : Type.Base.t) : unit M.t = + let open M in + set_data_annot path ty >>= fun () -> + match node with + | Prim (_, D_Hole, [], _) -> return () + | Prim (_, D_Unit, [], _) -> unify_base ty Type.unit + | Prim (_, D_True, [], _) | Prim (_, D_False, [], _) -> + unify_base ty Type.bool + | String _ -> unify_base ty Type.string + | Bytes _ -> unify_base ty Type.bytes + | Prim (_, D_Pair, [vl; vr], _) -> + exists () >>= fun lty -> + exists () >>= fun rty -> + generate_constraints_data (Mikhailsky.Path.at_index 0 path) vl lty + >>= fun () -> + generate_constraints_data (Mikhailsky.Path.at_index 1 path) vr rty + >>= fun () -> unify_base ty (Type.pair lty rty) + | Prim (_, D_Left, [term], _) -> + exists () >>= fun lty -> + exists () >>= fun rty -> + generate_constraints_data (Mikhailsky.Path.at_index 0 path) term lty + >>= fun () -> unify_base ty (Type.union lty rty) + | Prim (_, D_Right, [term], _) -> + exists () >>= fun lty -> + exists () >>= fun rty -> + generate_constraints_data (Mikhailsky.Path.at_index 0 path) term rty + >>= fun () -> unify_base ty (Type.union lty rty) + | Prim (_, D_None, [], _) -> + exists () >>= fun elt_ty -> unify_base ty (Type.option elt_ty) + | Prim (_, D_Some, [v], _) -> + exists () >>= fun elt_ty -> + generate_constraints_data (Mikhailsky.Path.at_index 0 path) v elt_ty + >>= fun () -> unify_base ty (Type.option elt_ty) + | Prim (_, A_Int, [Int (_, _)], _) -> unify_base ty Type.int + | Prim (_, A_Nat, [Int (_, _)], _) -> unify_base ty Type.nat + | Prim (_, A_Timestamp, [Int (_, _)], _) -> unify_base ty Type.timestamp + | Prim (_, A_Mutez, [Int (_, _)], _) -> unify_base ty Type.mutez + | Prim (_, A_Key_hash, [Bytes (_, _)], _) -> unify_base ty Type.key_hash + | Prim (_, A_Key, [Bytes (_, _)], _) -> unify_base ty Type.key + | Prim (_, A_List, [Seq (_, subterms)], _) -> + exists () >>= fun elt_ty -> + unify_base ty Type.(list elt_ty) >>= fun () -> + (* path' accounts for the fact that the Seq is hidden under an annot. *) + let path' = Mikhailsky.Path.at_index 0 path in + generate_constraints_data_list path' 0 subterms elt_ty + | Prim (_, A_Set, [Seq (_, subterms)], _) -> + exists_cmp () >>= fun elt_ty -> + unify_base ty Type.(set elt_ty) >>= fun () -> + (* path' accounts for the fact that the Seq is hidden under an annot. *) + let path' = Mikhailsky.Path.at_index 0 path in + generate_constraints_data_set path' 0 subterms elt_ty + | Prim (_, A_Map, [Seq (_, subterms)], _) -> + exists_cmp () >>= fun k_ty -> + exists () >>= fun v_ty -> + unify_base ty Type.(map k_ty v_ty) >>= fun () -> + (* path' accounts for the fact that the Seq is hidden under an annot. *) + let path' = Mikhailsky.Path.at_index 0 path in + generate_constraints_data_map path' 0 subterms k_ty v_ty + | Prim (_, A_Lambda, [(Seq (_, _) as node)], _) -> + exists () >>= fun dom -> + exists () >>= fun range -> + unify_base ty Type.(lambda dom range) >>= fun () -> + let path' = Mikhailsky.Path.at_index 0 path in + let bef = Type.(item dom empty) in + let aft = Type.(item range empty) in + generate_constraints path' node bef aft + | Prim (_, (A_Int | A_Nat | A_List), _, _) -> + invalid_ast ~msg:__LOC__ path node + | Int _ + (* Ints should always be guarded by annotations *) + | Seq (_, _) + (* Lists, sets, maps, lambdas, should always be guarded by annotations *) + | _ -> + invalid_ast ~msg:__LOC__ path node + +(* raise (Ill_typed_script (Invalid_ast (path, node))) *) +and generate_constraints_data_list path index data ty = + let open M in + match data with + | [] -> return () + | hd :: tl -> + let hd_path = Mikhailsky.Path.at_index index path in + generate_constraints_data hd_path hd ty >>= fun () -> + generate_constraints_data_list path (index + 1) tl ty + +and generate_constraints_data_set path index data ty = + let open M in + match data with + | [] -> return () + | hd :: tl -> + let hd_path = Mikhailsky.Path.at_index index path in + generate_constraints_data hd_path hd ty >>= fun () -> + generate_constraints_data_list path (index + 1) tl ty + +and generate_constraints_data_map path index data k_ty v_ty = + let open M in + match data with + | [] -> return () + | elt :: tl -> ( + let elt_path = Mikhailsky.Path.at_index index path in + match elt with + | Prim (_, D_Elt, [k; v], _) -> + let k_path = Mikhailsky.Path.at_index 0 elt_path in + generate_constraints_data k_path k k_ty >>= fun () -> + let v_path = Mikhailsky.Path.at_index 1 elt_path in + generate_constraints_data v_path v v_ty >>= fun () -> + generate_constraints_data_map path (index + 1) tl k_ty v_ty + | _ -> invalid_ast ~msg:__LOC__ elt_path elt) + +and generate_constraints_dropn n bef aft = + let open M in + if n = 0 then unify bef aft + else + exists () >>= fun top -> + generate_constraints_dropn (n - 1) bef (Type.item top aft) + +let infer_with_state (node : Mikhailsky.node) : + (Type.Stack.t * Type.Stack.t) * state = + let open M in + ( exists_stack () >>= fun bef -> + exists_stack () >>= fun aft -> + generate_constraints Mikhailsky.Path.root node bef aft >>= fun () -> + instantiate bef >>= fun bef -> + instantiate aft >>= fun aft -> return (bef, aft) ) + (M.empty ()) + +let infer (node : Mikhailsky.node) : Type.Stack.t * Type.Stack.t = + fst (infer_with_state node) + +let infer_data_with_state (node : Mikhailsky.node) : Type.Base.t * state = + let open M in + ( exists () >>= fun ty -> + generate_constraints_data Mikhailsky.Path.root node ty >>= fun () -> + instantiate_base ty >>= fun ty -> return ty ) + (M.empty ()) + +let infer_data (node : Mikhailsky.node) : Type.Base.t = + fst (infer_data_with_state node) diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/inference.mli b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/inference.mli new file mode 100644 index 000000000000..e44d83fab069 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/inference.mli @@ -0,0 +1,145 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Errors and their pretty-printing function *) +type inference_error + +exception Ill_typed_script of inference_error + +val pp_inference_error : Format.formatter -> inference_error -> unit + +(** Comparability tag. *) +type comparability = Comparable | Not_comparable | Unconstrained + +(** Michelson types. *) +type michelson_type = + | Base_type of {repr : Type.Base.t option; comparable : comparability} + | Stack_type of Type.Stack.t option + +type transformer = {bef : Type.Stack.t; aft : Type.Stack.t} + +(** State of the type inference module *) + +(** Store implementation for type representatives *) +module Repr_store : Stores.S with type key = int and type value = michelson_type + +(** State monad built on [Repr_store] *) +module Repr_sm : + Monads.State_sig + with type state = Repr_store.state + and type key = int + and type value = michelson_type + +(** Store implementation for instruction type representatives *) +module Annot_instr_store : + Stores.S with type key = Mikhailsky.Path.t and type value = transformer + +(** State monad handling annotations on instructions *) +module Annot_instr_sm : + Monads.State_sig + with type state = Annot_instr_store.state + and type value = transformer + and type key = Mikhailsky.Path.t + +(** Store implementation for data type representatives *) +module Annot_data_store : + Stores.S with type key = Mikhailsky.Path.t and type value = Type.Base.t + +(** State monad handling annotations on data *) +module Annot_data_sm : + Monads.State_sig + with type state = Annot_data_store.state + and type value = Type.Base.t + and type key = Mikhailsky.Path.t + +(** State of the inference module *) +type state = { + uf : Uf.UF.M.state; + repr : Repr_sm.state; + annot_instr : Annot_instr_sm.state; + annot_data : Annot_data_sm.state; +} + +(** State monad of the inference module. *) +module M : sig + type 'a t = state -> 'a * state + + val ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t + + val empty : unit -> state + + val return : 'a -> 'a t + + val set_repr : int -> michelson_type -> unit t + + val get_repr_exn : int -> michelson_type t + + val get_instr_annot : Annot_data_sm.key -> transformer option t + + val get_data_annot : Annot_data_sm.key -> Type.Base.t option t + + val uf_lift : 'a Uf.UF.M.t -> 'a t + + val repr_lift : 'a Repr_sm.t -> 'a t + + val annot_instr_lift : 'a Annot_instr_sm.t -> 'a t + + val annot_data_lift : 'a Annot_data_sm.t -> 'a t + + val get_state : state t +end + +(** Unifies two stack types. *) +val unify : Type.Stack.t -> Type.Stack.t -> unit M.t + +(** Unifies two base types. *) +val unify_base : Type.Base.t -> Type.Base.t -> unit M.t + +(** Instantiate type variables with the associated terms in a base type. *) +val instantiate_base : Type.Base.t -> Type.Base.t M.t + +(** Instantiate type variables with the associated terms in a stack type. *) +val instantiate : Type.Stack.t -> Type.Stack.t M.t + +(** Get comparability flag for a base type. *) +val get_comparability : Type.Base.t -> comparability M.t + +(** Performs inference on the given Mikhailsky term and returns + its type (as a pair of [before] and [after] stack) as well as the + inference engine state. *) +val infer_with_state : Mikhailsky.node -> (Type.Stack.t * Type.Stack.t) * state + +(** Performs inference on the given Mikhailsky term and throws + the inference engine state away. *) +val infer : Mikhailsky.node -> Type.Stack.t * Type.Stack.t + +(** Performs inference on a piece of Mikhailsky [data] and + returns the inference engine state along the inferred type. *) +val infer_data_with_state : Mikhailsky.node -> Type.Base.t * state + +(** Performs inference on a piece of Mikhailsky [data] and + returns the inferred type, throwing the inference engine + state away. *) +val infer_data : Mikhailsky.node -> Type.Base.t diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/int_map.ml b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/int_map.ml new file mode 100644 index 000000000000..e9b05fe91caa --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/int_map.ml @@ -0,0 +1,26 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +include Map.Make (Compare.Int) diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/mikhailsky.ml b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/mikhailsky.ml new file mode 100644 index 000000000000..a015381180a0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/mikhailsky.ml @@ -0,0 +1,422 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +exception Term_contains_holes + +module Mikhailsky_signature : Signature.S with type t = Mikhailsky_prim.prim = +struct + type t = Mikhailsky_prim.prim + + let compare (x : t) (y : t) = Stdlib.compare x y + + let hash (x : t) = Hashtbl.hash x + + let pp = Mikhailsky_prim.pp +end + +include + Micheline_with_hash_consing.Make + (Mikhailsky_signature) + (struct + let initial_size = None + end) + +module Path = Path.With_hash_consing (struct + let initial_size = None +end) + +(* Prints a Mikhailsky term. *) +let pp fmt node = + let canonical = Micheline.strip_locations node in + let printable = + Micheline_printer.printable Mikhailsky_prim.string_of_prim canonical + in + Micheline_printer.print_expr fmt printable + +let to_string node = + pp Format.str_formatter node ; + Format.flush_str_formatter () + +(* Adapted from Script_ir_translator.parse_ty *) +let rec parse_ty : + allow_big_map:bool -> + allow_operation:bool -> + allow_contract:bool -> + node -> + Type.Base.t = + fun ~allow_big_map ~allow_operation ~allow_contract node -> + match node with + | Prim (_loc, T_unit, [], _annot) -> Type.unit + | Prim (_loc, T_int, [], _annot) -> Type.int + | Prim (_loc, T_nat, [], _annot) -> Type.nat + | Prim (_loc, T_string, [], _annot) -> Type.string + | Prim (_loc, T_bytes, [], _annot) -> Type.bytes + | Prim (_loc, T_bool, [], _annot) -> Type.bool + | Prim (_loc, T_key_hash, [], _annot) -> Type.key_hash + | Prim (_loc, T_timestamp, [], _annot) -> Type.timestamp + | Prim (_loc, T_mutez, [], _annot) -> Type.mutez + | Prim (_loc, T_option, [ut], _annot) -> + let ty = parse_ty ~allow_big_map ~allow_operation ~allow_contract ut in + Type.option ty + | Prim (_loc, T_pair, [utl; utr], _annot) -> + let lty = parse_ty ~allow_big_map ~allow_operation ~allow_contract utl in + let rty = parse_ty ~allow_big_map ~allow_operation ~allow_contract utr in + Type.pair lty rty + | Prim (_loc, T_or, [utl; utr], _annot) -> + let lty = parse_ty ~allow_big_map ~allow_operation ~allow_contract utl in + let rty = parse_ty ~allow_big_map ~allow_operation ~allow_contract utr in + Type.union lty rty + | Prim (_loc, T_set, [ut], _annot) -> + let ut = parse_ty ~allow_big_map ~allow_operation ~allow_contract ut in + Type.set ut + | Prim (_loc, T_map, [uta; utb], _annot) -> + let uta = parse_ty ~allow_big_map ~allow_operation ~allow_contract uta in + let utb = parse_ty ~allow_big_map ~allow_operation ~allow_contract utb in + Type.map uta utb + | Prim (_loc, T_lambda, [dom; range], _annot) -> + let dom = parse_ty ~allow_big_map ~allow_operation ~allow_contract dom in + let range = + parse_ty ~allow_big_map ~allow_operation ~allow_contract range + in + Type.lambda dom range + | Prim (_loc, T_list, [elt], _annot) -> + let elt = parse_ty ~allow_big_map ~allow_operation ~allow_contract elt in + Type.list elt + | _ -> + let s = to_string node in + Stdlib.failwith ("Mikhailsky.parse_ty: could not parse " ^ s) + +exception Term_has_variables + +exception Ill_formed_mikhailsky + +let rec map_var f (x : Type.Base.t) = + match x.node with + | Unit_t -> prim T_unit [] [] + | Var_t v -> f v + | Int_t -> prim T_int [] [] + | Nat_t -> prim T_nat [] [] + | Bool_t -> prim T_bool [] [] + | String_t -> prim T_string [] [] + | Bytes_t -> prim T_bytes [] [] + | Key_hash_t -> prim T_key_hash [] [] + | Timestamp_t -> prim T_timestamp [] [] + | Mutez_t -> prim T_mutez [] [] + | Key_t -> prim T_key [] [] + | Option_t ty -> + let mty = map_var f ty in + prim T_option [mty] [] + | Pair_t (lty, rty) -> + let lty = map_var f lty in + let rty = map_var f rty in + prim T_pair [lty; rty] [] + | Union_t (lty, rty) -> + let lty = map_var f lty in + let rty = map_var f rty in + prim T_or [lty; rty] [] + | List_t ty -> + let mty = map_var f ty in + prim T_list [mty] [] + | Set_t ty -> + let mty = map_var f ty in + prim T_set [mty] [] + | Map_t (kty, vty) -> + let mkty = map_var f kty in + let mvty = map_var f vty in + prim T_map [mkty; mvty] [] + | Lambda_t (dom, range) -> + let dom = map_var f dom in + let range = map_var f range in + prim T_lambda [dom; range] [] + +let unparse_ty_exn (x : Type.Base.t) = + map_var (fun _ -> raise Term_has_variables) x + +let unparse_ty (x : Type.Base.t) = + try Some (unparse_ty_exn x) with Term_has_variables -> None + +(* Exports a Mikhailsky term to Michelson. Fails if term contains holes. + Erases annotations, introduces types where missing. *) +let rec to_michelson (n : node) = + match n with + | Micheline.Int (_, i) -> Micheline.Int (0, i) + | Micheline.Prim (_, head, [term], _) + when Mikhailsky_prim.kind head = Annot_kind && head <> A_Lambda -> + to_michelson term + | Micheline.Prim (_, I_Hole, _, _) -> raise Term_contains_holes + | Micheline.Prim (_, D_Hole, _, _) -> raise Term_contains_holes + | Micheline.Prim (_, head, subterms, annots) -> + let head = Mikhailsky_prim.to_michelson head in + Micheline.Prim (0, head, List.map to_michelson subterms, annots) + | Micheline.String (_, s) -> Micheline.String (0, s) + | Micheline.Bytes (_, b) -> Micheline.Bytes (0, b) + | Micheline.Seq (_, subterms) -> + Micheline.Seq (0, List.map to_michelson subterms) + +let to_michelson (n : node) : Script_repr.expr = + Micheline.strip_locations (to_michelson n) + +let rec size : node -> int = + fun node -> + match node with + | Micheline.Int (_, _) -> 1 + | Micheline.String (_, _) -> 1 + | Micheline.Bytes (_, _) -> 1 + | Micheline.Prim (_, _, subterms, _) -> + List.fold_left (fun acc n -> acc + size n) 1 subterms + | Micheline.Seq (_, subterms) -> + List.fold_left (fun acc n -> acc + size n) 1 subterms + +let instr_hole = prim I_Hole [] [] + +let data_hole = prim D_Hole [] [] + +(* types *) +let unit_ty = prim T_unit [] [] + +let bool_ty = prim T_bool [] [] + +let int_ty = prim T_int [] [] + +let nat_ty = prim T_nat [] [] + +let string_ty = prim T_string [] [] + +let bytes_ty = prim T_bytes [] [] + +let key_hash_ty = prim T_key_hash [] [] + +let option_ty x = prim T_option [x] [] + +let list_ty x = prim T_list [x] [] + +(* Unique identifier provided by hash-consing Micheline terms. *) +let tag node = + let l = label node in + l.tag + +(* hash of term *) +let hash node = + let l = label node in + l.hash + +module Instructions = struct + (* arithmetic *) + + let add ty1 ty2 = prim I_ADD [ty1; ty2] [] + + let sub ty1 ty2 = prim I_SUB [ty1; ty2] [] + + let mul ty1 ty2 = prim I_MUL [ty1; ty2] [] + + let ediv ty1 ty2 = prim I_EDIV [ty1; ty2] [] + + let abs = prim I_ABS [] [] + + let gt = prim I_GT [] [] + + (* stack ops *) + let push ty v = prim I_PUSH [ty; v] [] + + let dip code = prim I_DIP [seq [code]] [] + + let dup = prim I_DUP [] [] + + let drop = prim I_DROP [] [] + + let dropn n = prim I_DROP [int (Z.of_int n)] [] + + let swap = prim I_SWAP [] [] + + (* crypto *) + let blake2b = prim I_BLAKE2B [] [] + + let sha256 = prim I_SHA256 [] [] + + let sha512 = prim I_SHA512 [] [] + + let hash_key = prim I_HASH_KEY [] [] + + (* control *) + let if_ bt bf = prim I_IF [seq [bt]; seq [bf]] [] + + let if_left bt bf = prim I_IF_LEFT [seq [bt]; seq [bf]] [] + + let if_none bt bf = prim I_IF_NONE [seq [bt]; seq [bf]] [] + + let loop b = prim I_LOOP [seq [b]] [] + + let loop_left b = prim I_LOOP_LEFT [seq [b]] [] + + (* pairs *) + let car = prim I_CAR [] [] + + let cdr = prim I_CDR [] [] + + let pair = prim I_PAIR [] [] + + (* unions *) + + let left = prim I_LEFT [] [] + + let right = prim I_RIGHT [] [] + + (* boolean *) + let and_ = prim I_AND [] [] + + (* compare *) + let compare = prim I_COMPARE [] [] + + (* map/set *) + let empty_set = prim I_EMPTY_SET [] [] + + let update_set = prim I_UPDATE_SET [] [] + + let size_set = prim I_SIZE_SET [] [] + + let iter_set code = prim I_ITER_SET [seq code] [] + + let mem_set = prim I_MEM_SET [] [] + + let empty_map = prim I_EMPTY_MAP [] [] + + let update_map = prim I_UPDATE_MAP [] [] + + let size_map = prim I_SIZE_MAP [] [] + + let iter_map code = prim I_ITER_MAP [seq code] [] + + let map_map code = prim I_MAP_MAP [seq code] [] + + let get_map = prim I_GET_MAP [] [] + + let mem_map = prim I_MEM_MAP [] [] + + (* lists*) + let nil = prim I_NIL [] [] + + let cons = prim I_CONS [] [] + + let size_list = prim I_SIZE_LIST [] [] + + let iter_list code = prim I_ITER_LIST [seq code] [] + + let map_list code = prim I_MAP_LIST [seq code] [] + + (* strings *) + let concat = prim I_CONCAT [] [] + + let size_string = prim I_SIZE_STRING [] [] + + let size_bytes = prim I_SIZE_BYTES [] [] + + (* Lambdas *) + let lambda code = prim I_LAMBDA [seq code] [] + + let exec = prim I_EXEC [] [] + + let apply = prim I_APPLY [] [] + + (* pack/unpack *) + let pack = prim I_PACK [] [] + + let unpack = prim I_UNPACK [] [] + + (* hole *) + let hole = instr_hole +end + +(* value constructors *) +module Data = struct + let unit = prim D_Unit [] [] + + let false_ = prim D_False [] [] + + let true_ = prim D_True [] [] + + let none = prim D_None [] [] + + let some x = prim D_Some [x] [] + + let pair x y = prim D_Pair [x; y] [] + + let left x = prim D_Left [x] [] + + let right x = prim D_Right [x] [] + + let list elts = prim A_List [seq elts] [] + + let set elts = prim A_Set [seq elts] [] + + let map_elt k v = prim D_Elt [k; v] [] + + let map elts = prim A_Map [seq elts] [] + + let timestamp ts = + let z = Protocol.Alpha_context.Script_timestamp.to_zint ts in + prim A_Timestamp [int z] [] + + let mutez (tz : Protocol.Alpha_context.Tez.tez) = + let i = Protocol.Alpha_context.Tez.to_mutez tz in + prim A_Mutez [int (Z.of_int64 i)] [] + + let key_hash kh = + let b = + Data_encoding.Binary.to_bytes_exn + Tezos_crypto.Signature.Public_key_hash.encoding + kh + in + prim A_Key_hash [bytes b] [] + + let key k = + let b = + Data_encoding.Binary.to_bytes_exn + Tezos_crypto.Signature.Public_key.encoding + k + in + prim A_Key [bytes b] [] + + let integer (i : int) = prim A_Int [int (Z.of_int i)] [] + + let natural (i : int) = + assert (i >= 0) ; + prim A_Nat [int (Z.of_int i)] [] + + let big_integer (i : Z.t) = prim A_Int [int i] [] + + let big_natural (i : Z.t) = + assert (Z.geq i Z.zero) ; + prim A_Nat [int i] [] + + let string = string + + let bytes = bytes + + let lambda code = prim A_Lambda [seq code] [] + + let hole = data_hole +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/mikhailsky.mli b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/mikhailsky.mli new file mode 100644 index 000000000000..6285f6a39555 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/mikhailsky.mli @@ -0,0 +1,330 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(** Mikhailsky: Michelson in Micheline form, with typed holes and annotations. + Mikhailsky terms are hash-consed. *) + +(** + Michelson code is a hard to type-check and generate incrementally due to + the presence of ambiguous constructs, such as literals + like [{ 1 ; 2 ; 3 }]. Is it a list of ints? of nats? of tez? Or a set? + + Thus, we will work with Mikhailsky, a better behaved version of Michelson + allowing local reconstruction of types. + + Differences wrt Michelson: + + 1. non string/byte literals are explicitly annotated with their head type constructor. + Here is an int i: Prim (_, D_int, [Int i], _) + Here is an nat n: Prim (_, D_nat, [Int i], _) + Here is an list of something: Prim (_, D_list, michelson_list, _) + Here is a set: Prim (_, D_set, michelson_set, _) + Here is a map: Prim (_, D_map, michelson_map, _) + etc. + Projecting back from this language to Michelson is trivial. + + 2. Instructions `LEFT/RIGHT` do not need to carry the type of the other + component of the disjunction. These has to be filled in back when + generating Michelson from Mikhailsky. + + 4. The same holds for the input/output type of a lambda as specified in the + `LAMBDA` instruction. + + 3. Some instructions are annotated with the type on which they operate. + Eg if Prim (_, I_ADD, [], []) is the (ad-hoc polymorphic) addition in Michelson, + we will have the following variants in Mikhailsky: + - Prim (_, I_ADD, [ Prim (_, T_mutez, [], []), + Prim (_, T_mutez, [], []) ], []) for mutez addition + - Prim (_, I_ADD, [ Prim (_, T_int, [], []), + Prim (_, T_nat, [], []) ], []) for int+nat addition + etc. +*) + +(** The signature of Mikhailsky terms. *) +module Mikhailsky_signature : Signature.S with type t = Mikhailsky_prim.prim + +(** Elements of type [Path.t] allow to index subterms of Mikhailsky terms. *) +module Path : Path.S + +(** The following types correspond to those provided when instantiating the + functor [Micheline_with_hash_consing.Make] on [Mikhailsky_signature]. *) +type label = Micheline_with_hash_consing.hcons_info + +type head = Mikhailsky_signature.t + +type node = (label, head) Micheline.node + +exception Term_contains_holes + +exception Ill_formed_mikhailsky + +(** [parse_ty] returns a type from a Mikhailsky term. *) +val parse_ty : + allow_big_map:bool -> + allow_operation:bool -> + allow_contract:bool -> + node -> + Type.Base.t + +(** [map_var f x] maps the function f on all variables contained + in the type [x]. *) +val map_var : (int -> node) -> Type.Base.t -> node + +(** [unparse_ty] returns a Mikhailsky term representing a type. *) +val unparse_ty_exn : Type.Base.t -> node + +val unparse_ty : Type.Base.t -> node option + +(** Extracts a Michelson term from a Mikhailsky one. Raises + [Term_contains_holes] if it cannot be done. *) +val to_michelson : node -> Script_repr.expr + +(** Pretty printer. *) +val pp : Format.formatter -> node -> unit + +val to_string : node -> string + +(** Returns the number of nodes of a Mikhailsky term. *) +val size : node -> int + +(** Micheline generic constructors *) +val prim : Mikhailsky_prim.prim -> node list -> string list -> node + +val seq : node list -> node + +val string : string -> node + +val bytes : Bytes.t -> node + +(** Mikhailsky smart constructors*) + +(** Holes *) +val instr_hole : node + +val data_hole : node + +(** Types *) +val unit_ty : node + +val int_ty : node + +val nat_ty : node + +val bool_ty : node + +val string_ty : node + +val bytes_ty : node + +val key_hash_ty : node + +val option_ty : node -> node + +val list_ty : node -> node + +(** Project unique tag out of Mikhailsky node *) +val tag : node -> int + +(** Project hash out of Mikhailsky node *) +val hash : node -> int + +(** Instructions *) +module Instructions : sig + (** Arithmetic. Binary operations take the input types as extra arguments. *) + val add : node -> node -> node + + val sub : node -> node -> node + + val mul : node -> node -> node + + val ediv : node -> node -> node + + val abs : node + + val gt : node + + (** Stack *) + val push : node -> node -> node + + val dip : node -> node + + val dup : node + + val drop : node + + val dropn : int -> node + + val swap : node + + (** Crypto *) + val blake2b : node + + val sha256 : node + + val sha512 : node + + val hash_key : node + + (** Control *) + val if_ : node -> node -> node + + val if_left : node -> node -> node + + val if_none : node -> node -> node + + val loop : node -> node + + val loop_left : node -> node + + (** Pairs *) + val car : node + + val cdr : node + + val pair : node + + (** Unions *) + val left : node + + val right : node + + (** Booleans *) + val and_ : node + + (** Compare *) + val compare : node + + (** Set/Map *) + val empty_set : node + + val update_set : node + + val size_set : node + + val iter_set : node list -> node + + val mem_set : node + + val empty_map : node + + val update_map : node + + val size_map : node + + val iter_map : node list -> node + + val map_map : node list -> node + + val get_map : node + + val mem_map : node + + (** Lists *) + val nil : node + + val cons : node + + val size_list : node + + val iter_list : node list -> node + + val map_list : node list -> node + + (** Strings/bytes *) + val concat : node + + val size_string : node + + val size_bytes : node + + (** Lambdas *) + val lambda : node list -> node + + val exec : node + + val apply : node + + (** pack/unpack *) + + val pack : node + + val unpack : node + + (** Hole *) + val hole : node +end + +(** data *) +module Data : sig + val unit : node + + val false_ : node + + val true_ : node + + val none : node + + val some : node -> node + + val pair : node -> node -> node + + val left : node -> node + + val right : node -> node + + val list : node list -> node + + val set : node list -> node + + val map_elt : node -> node -> node + + val map : node list -> node + + val timestamp : Alpha_context.Script_timestamp.t -> node + + val mutez : Alpha_context.Tez.t -> node + + val key_hash : Tezos_crypto.Signature.Public_key_hash.t -> node + + val key : Tezos_crypto.Signature.Public_key.t -> node + + val integer : int -> node + + val natural : int -> node + + val big_integer : Z.t -> node + + val big_natural : Z.t -> node + + val string : string -> node + + val bytes : Bytes.t -> node + + val lambda : node list -> node + + val hole : node +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/mikhailsky_prim.ml b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/mikhailsky_prim.ml new file mode 100644 index 000000000000..b1b2fb140616 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/mikhailsky_prim.ml @@ -0,0 +1,570 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(** Mikhailsky primitives correspond to Michelson primitives plus special + "holes" for instructions and data. *) + +type prim = + | K_parameter + | K_storage + | K_code + | D_False + | D_Elt + | D_Left + | D_None + | D_Pair + | D_Right + | D_Some + | D_True + | D_Unit + | I_PACK + | I_UNPACK + | I_BLAKE2B + | I_SHA256 + | I_SHA512 + | I_ABS + | I_ADD + | I_AMOUNT + | I_AND + | I_BALANCE + | I_CAR + | I_CDR + | I_CHAIN_ID + | I_CHECK_SIGNATURE + | I_COMPARE + | I_CONCAT + | I_CONS + | I_CREATE_ACCOUNT + | I_CREATE_CONTRACT + | I_IMPLICIT_ACCOUNT + | I_DIP + | I_DROP + | I_DUP + | I_EDIV + | I_EMPTY_BIG_MAP + | I_EMPTY_MAP + | I_EMPTY_SET + | I_EQ + | I_EXEC + | I_APPLY + | I_FAILWITH + | I_GE + | I_GET_MAP + | I_GET_AND_UPDATE_MAP + | I_GT + | I_HASH_KEY + | I_IF + | I_IF_CONS + | I_IF_LEFT + | I_IF_NONE + | I_INT + | I_LAMBDA + | I_LE + | I_LEFT + | I_LOOP + | I_LSL + | I_LSR + | I_LT + | I_MAP_MAP + | I_MAP_LIST + | I_MEM_SET + | I_MEM_MAP + | I_MUL + | I_NEG + | I_NEQ + | I_NIL + | I_NONE + | I_NOT + | I_NOW + | I_OR + | I_PAIR + | I_UNPAIR + | I_PUSH + | I_RIGHT + | I_SIZE_SET + | I_SIZE_MAP + | I_SIZE_LIST + | I_SIZE_STRING + | I_SIZE_BYTES + | I_SOME + | I_SOURCE + | I_SENDER + | I_SELF + | I_SLICE + | I_STEPS_TO_QUOTA + | I_SUB + | I_SWAP + | I_TRANSFER_TOKENS + | I_SET_DELEGATE + | I_UNIT + | I_UPDATE_SET + | I_UPDATE_MAP + | I_XOR + | I_ITER_MAP + | I_ITER_LIST + | I_ITER_SET + | I_LOOP_LEFT + | I_ADDRESS + | I_CONTRACT + | I_ISNAT + | I_CAST + | I_RENAME + | I_DIG + | I_DUG + | I_LEVEL + | I_SELF_ADDRESS + | I_NEVER + | I_SAPLING_EMPTY_STATE + | I_SAPLING_VERIFY_UPDATE + | I_VOTING_POWER + | I_TOTAL_VOTING_POWER + | I_KECCAK + | I_SHA3 + | I_PAIRING_CHECK + | I_TICKET + | I_READ_TICKET + | I_SPLIT_TICKET + | I_JOIN_TICKETS + | T_bool + | T_contract + | T_int + | T_key + | T_key_hash + | T_lambda + | T_list + | T_map + | T_big_map + | T_nat + | T_option + | T_or + | T_pair + | T_set + | T_signature + | T_string + | T_bytes + | T_mutez + | T_timestamp + | T_unit + | T_operation + | T_address + | T_chain_id + | T_never + | T_sapling_state + | T_sapling_transaction + | T_bls12_381_g1 + | T_bls12_381_g2 + | T_bls12_381_fr + | T_ticket + (* Holes in programs and data. *) + | I_Hole + | D_Hole + (* Annotations. *) + | A_Int + | A_Nat + | A_Timestamp + | A_Mutez + | A_Key_hash + | A_Key + | A_List + | A_Set + | A_Map + | A_Lambda + +let relation = + [ + (K_parameter, Michelson_v1_primitives.K_parameter); + (K_storage, Michelson_v1_primitives.K_storage); + (K_code, Michelson_v1_primitives.K_code); + (D_False, Michelson_v1_primitives.D_False); + (D_Elt, Michelson_v1_primitives.D_Elt); + (D_Left, Michelson_v1_primitives.D_Left); + (D_None, Michelson_v1_primitives.D_None); + (D_Pair, Michelson_v1_primitives.D_Pair); + (D_Right, Michelson_v1_primitives.D_Right); + (D_Some, Michelson_v1_primitives.D_Some); + (D_True, Michelson_v1_primitives.D_True); + (D_Unit, Michelson_v1_primitives.D_Unit); + (I_PACK, Michelson_v1_primitives.I_PACK); + (I_UNPACK, Michelson_v1_primitives.I_UNPACK); + (I_BLAKE2B, Michelson_v1_primitives.I_BLAKE2B); + (I_SHA256, Michelson_v1_primitives.I_SHA256); + (I_SHA512, Michelson_v1_primitives.I_SHA512); + (I_ABS, Michelson_v1_primitives.I_ABS); + (I_ADD, Michelson_v1_primitives.I_ADD); + (I_AMOUNT, Michelson_v1_primitives.I_AMOUNT); + (I_AND, Michelson_v1_primitives.I_AND); + (I_BALANCE, Michelson_v1_primitives.I_BALANCE); + (I_CAR, Michelson_v1_primitives.I_CAR); + (I_CDR, Michelson_v1_primitives.I_CDR); + (I_CHAIN_ID, Michelson_v1_primitives.I_CHAIN_ID); + (I_CHECK_SIGNATURE, Michelson_v1_primitives.I_CHECK_SIGNATURE); + (I_COMPARE, Michelson_v1_primitives.I_COMPARE); + (I_CONCAT, Michelson_v1_primitives.I_CONCAT); + (I_CONS, Michelson_v1_primitives.I_CONS); + (I_CREATE_ACCOUNT, Michelson_v1_primitives.I_CREATE_ACCOUNT); + (I_CREATE_CONTRACT, Michelson_v1_primitives.I_CREATE_CONTRACT); + (I_IMPLICIT_ACCOUNT, Michelson_v1_primitives.I_IMPLICIT_ACCOUNT); + (I_DIP, Michelson_v1_primitives.I_DIP); + (I_DROP, Michelson_v1_primitives.I_DROP); + (I_DUP, Michelson_v1_primitives.I_DUP); + (I_EDIV, Michelson_v1_primitives.I_EDIV); + (I_EMPTY_BIG_MAP, Michelson_v1_primitives.I_EMPTY_BIG_MAP); + (I_EMPTY_MAP, Michelson_v1_primitives.I_EMPTY_MAP); + (I_EMPTY_SET, Michelson_v1_primitives.I_EMPTY_SET); + (I_EQ, Michelson_v1_primitives.I_EQ); + (I_EXEC, Michelson_v1_primitives.I_EXEC); + (I_APPLY, Michelson_v1_primitives.I_APPLY); + (I_FAILWITH, Michelson_v1_primitives.I_FAILWITH); + (I_GE, Michelson_v1_primitives.I_GE); + (I_GET_MAP, Michelson_v1_primitives.I_GET); + (I_GET_AND_UPDATE_MAP, Michelson_v1_primitives.I_GET_AND_UPDATE); + (I_GT, Michelson_v1_primitives.I_GT); + (I_HASH_KEY, Michelson_v1_primitives.I_HASH_KEY); + (I_IF, Michelson_v1_primitives.I_IF); + (I_IF_CONS, Michelson_v1_primitives.I_IF_CONS); + (I_IF_LEFT, Michelson_v1_primitives.I_IF_LEFT); + (I_IF_NONE, Michelson_v1_primitives.I_IF_NONE); + (I_INT, Michelson_v1_primitives.I_INT); + (I_LAMBDA, Michelson_v1_primitives.I_LAMBDA); + (I_LE, Michelson_v1_primitives.I_LE); + (I_LEFT, Michelson_v1_primitives.I_LEFT); + (I_LEVEL, Michelson_v1_primitives.I_LEVEL); + (I_LOOP, Michelson_v1_primitives.I_LOOP); + (I_LSL, Michelson_v1_primitives.I_LSL); + (I_LSR, Michelson_v1_primitives.I_LSR); + (I_LT, Michelson_v1_primitives.I_LT); + (I_MAP_MAP, Michelson_v1_primitives.I_MAP); + (I_MAP_LIST, Michelson_v1_primitives.I_MAP); + (I_MEM_SET, Michelson_v1_primitives.I_MEM); + (I_MEM_MAP, Michelson_v1_primitives.I_MEM); + (I_MUL, Michelson_v1_primitives.I_MUL); + (I_NEG, Michelson_v1_primitives.I_NEG); + (I_NEQ, Michelson_v1_primitives.I_NEQ); + (I_NIL, Michelson_v1_primitives.I_NIL); + (I_NONE, Michelson_v1_primitives.I_NONE); + (I_NOT, Michelson_v1_primitives.I_NOT); + (I_NOW, Michelson_v1_primitives.I_NOW); + (I_OR, Michelson_v1_primitives.I_OR); + (I_PAIR, Michelson_v1_primitives.I_PAIR); + (I_UNPAIR, Michelson_v1_primitives.I_UNPAIR); + (I_PUSH, Michelson_v1_primitives.I_PUSH); + (I_RIGHT, Michelson_v1_primitives.I_RIGHT); + (I_SIZE_SET, Michelson_v1_primitives.I_SIZE); + (I_SIZE_MAP, Michelson_v1_primitives.I_SIZE); + (I_SIZE_LIST, Michelson_v1_primitives.I_SIZE); + (I_SIZE_STRING, Michelson_v1_primitives.I_SIZE); + (I_SIZE_BYTES, Michelson_v1_primitives.I_SIZE); + (I_SOME, Michelson_v1_primitives.I_SOME); + (I_SOURCE, Michelson_v1_primitives.I_SOURCE); + (I_SENDER, Michelson_v1_primitives.I_SENDER); + (I_SELF, Michelson_v1_primitives.I_SELF); + (I_SELF_ADDRESS, Michelson_v1_primitives.I_SELF_ADDRESS); + (I_SLICE, Michelson_v1_primitives.I_SLICE); + (I_STEPS_TO_QUOTA, Michelson_v1_primitives.I_STEPS_TO_QUOTA); + (I_SUB, Michelson_v1_primitives.I_SUB); + (I_SWAP, Michelson_v1_primitives.I_SWAP); + (I_TRANSFER_TOKENS, Michelson_v1_primitives.I_TRANSFER_TOKENS); + (I_SET_DELEGATE, Michelson_v1_primitives.I_SET_DELEGATE); + (I_UNIT, Michelson_v1_primitives.I_UNIT); + (I_UPDATE_SET, Michelson_v1_primitives.I_UPDATE); + (I_UPDATE_MAP, Michelson_v1_primitives.I_UPDATE); + (I_XOR, Michelson_v1_primitives.I_XOR); + (I_ITER_MAP, Michelson_v1_primitives.I_ITER); + (I_ITER_LIST, Michelson_v1_primitives.I_ITER); + (I_ITER_SET, Michelson_v1_primitives.I_ITER); + (I_LOOP_LEFT, Michelson_v1_primitives.I_LOOP_LEFT); + (I_ADDRESS, Michelson_v1_primitives.I_ADDRESS); + (I_CONTRACT, Michelson_v1_primitives.I_CONTRACT); + (I_ISNAT, Michelson_v1_primitives.I_ISNAT); + (I_CAST, Michelson_v1_primitives.I_CAST); + (I_RENAME, Michelson_v1_primitives.I_RENAME); + (I_SAPLING_EMPTY_STATE, Michelson_v1_primitives.I_SAPLING_EMPTY_STATE); + (I_SAPLING_VERIFY_UPDATE, Michelson_v1_primitives.I_SAPLING_VERIFY_UPDATE); + (I_DIG, Michelson_v1_primitives.I_DIG); + (I_DUG, Michelson_v1_primitives.I_DUG); + (I_NEVER, Michelson_v1_primitives.I_NEVER); + (I_VOTING_POWER, Michelson_v1_primitives.I_VOTING_POWER); + (I_TOTAL_VOTING_POWER, Michelson_v1_primitives.I_TOTAL_VOTING_POWER); + (I_KECCAK, Michelson_v1_primitives.I_KECCAK); + (I_SHA3, Michelson_v1_primitives.I_SHA3); + (I_PAIRING_CHECK, Michelson_v1_primitives.I_PAIRING_CHECK); + (I_TICKET, Michelson_v1_primitives.I_TICKET); + (I_READ_TICKET, Michelson_v1_primitives.I_READ_TICKET); + (I_SPLIT_TICKET, Michelson_v1_primitives.I_SPLIT_TICKET); + (I_JOIN_TICKETS, Michelson_v1_primitives.I_JOIN_TICKETS); + (T_bool, Michelson_v1_primitives.T_bool); + (T_contract, Michelson_v1_primitives.T_contract); + (T_int, Michelson_v1_primitives.T_int); + (T_key, Michelson_v1_primitives.T_key); + (T_key_hash, Michelson_v1_primitives.T_key_hash); + (T_lambda, Michelson_v1_primitives.T_lambda); + (T_list, Michelson_v1_primitives.T_list); + (T_map, Michelson_v1_primitives.T_map); + (T_big_map, Michelson_v1_primitives.T_big_map); + (T_nat, Michelson_v1_primitives.T_nat); + (T_option, Michelson_v1_primitives.T_option); + (T_or, Michelson_v1_primitives.T_or); + (T_pair, Michelson_v1_primitives.T_pair); + (T_set, Michelson_v1_primitives.T_set); + (T_signature, Michelson_v1_primitives.T_signature); + (T_string, Michelson_v1_primitives.T_string); + (T_bytes, Michelson_v1_primitives.T_bytes); + (T_mutez, Michelson_v1_primitives.T_mutez); + (T_timestamp, Michelson_v1_primitives.T_timestamp); + (T_unit, Michelson_v1_primitives.T_unit); + (T_operation, Michelson_v1_primitives.T_operation); + (T_address, Michelson_v1_primitives.T_address); + (T_sapling_transaction, Michelson_v1_primitives.T_sapling_transaction); + (T_sapling_state, Michelson_v1_primitives.T_sapling_state); + (T_chain_id, Michelson_v1_primitives.T_chain_id); + (T_never, Michelson_v1_primitives.T_never); + (T_bls12_381_g1, Michelson_v1_primitives.T_bls12_381_g1); + (T_bls12_381_g2, Michelson_v1_primitives.T_bls12_381_g2); + (T_bls12_381_fr, Michelson_v1_primitives.T_bls12_381_fr); + (T_ticket, Michelson_v1_primitives.T_ticket); + ] + +let relation_table = + let table = Hashtbl.create 269 in + List.iter + (fun (mikhailsky, michelson) -> Hashtbl.add table mikhailsky michelson) + relation ; + table + +exception Primitive_cannot_be_cast_back_to_Michelson of prim + +let to_michelson prim = + match Hashtbl.find relation_table prim with + | exception Not_found -> + raise (Primitive_cannot_be_cast_back_to_Michelson prim) + | res -> res + +let string_of_prim prim = + match prim with + | K_parameter -> "K_parameter" + | K_storage -> "K_storage" + | K_code -> "K_code" + | D_False -> "D_False" + | D_Elt -> "D_Elt" + | D_Left -> "D_Left" + | D_None -> "D_None" + | D_Pair -> "D_Pair" + | D_Right -> "D_Right" + | D_Some -> "D_Some" + | D_True -> "D_True" + | D_Unit -> "D_Unit" + | I_PACK -> "I_PACK" + | I_UNPACK -> "I_UNPACK" + | I_BLAKE2B -> "I_BLAKE2B" + | I_SHA256 -> "I_SHA256" + | I_SHA512 -> "I_SHA512" + | I_ABS -> "I_ABS" + | I_ADD -> "I_ADD" + | I_AMOUNT -> "I_AMOUNT" + | I_AND -> "I_AND" + | I_BALANCE -> "I_BALANCE" + | I_CAR -> "I_CAR" + | I_CDR -> "I_CDR" + | I_CHAIN_ID -> "I_CHAIN_ID" + | I_CHECK_SIGNATURE -> "I_CHECK_SIGNATURE" + | I_COMPARE -> "I_COMPARE" + | I_CONCAT -> "I_CONCAT" + | I_CONS -> "I_CONS" + | I_CREATE_ACCOUNT -> "I_CREATE_ACCOUNT" + | I_CREATE_CONTRACT -> "I_CREATE_CONTRACT" + | I_IMPLICIT_ACCOUNT -> "I_IMPLICIT_ACCOUNT" + | I_DIP -> "I_DIP" + | I_DROP -> "I_DROP" + | I_DUP -> "I_DUP" + | I_EDIV -> "I_EDIV" + | I_EMPTY_BIG_MAP -> "I_EMPTY_BIG_MAP" + | I_EMPTY_MAP -> "I_EMPTY_MAP" + | I_EMPTY_SET -> "I_EMPTY_SET" + | I_EQ -> "I_EQ" + | I_EXEC -> "I_EXEC" + | I_APPLY -> "I_APPLY" + | I_FAILWITH -> "I_FAILWITH" + | I_GE -> "I_GE" + | I_GET_MAP -> "I_GET_MAP" + | I_GET_AND_UPDATE_MAP -> "I_GET_AND_UPDATE_MAP" + | I_GT -> "I_GT" + | I_HASH_KEY -> "I_HASH_KEY" + | I_IF -> "I_IF" + | I_IF_CONS -> "I_IF_CONS" + | I_IF_LEFT -> "I_IF_LEFT" + | I_IF_NONE -> "I_IF_NONE" + | I_INT -> "I_INT" + | I_LAMBDA -> "I_LAMBDA" + | I_LE -> "I_LE" + | I_LEFT -> "I_LEFT" + | I_LOOP -> "I_LOOP" + | I_LSL -> "I_LSL" + | I_LSR -> "I_LSR" + | I_LT -> "I_LT" + | I_MAP_MAP -> "I_MAP_MAP" + | I_MAP_LIST -> "I_MAP_LIST" + | I_MEM_SET -> "I_MEM_SET" + | I_MEM_MAP -> "I_MEM_MAP" + | I_MUL -> "I_MUL" + | I_NEG -> "I_NEG" + | I_NEQ -> "I_NEQ" + | I_NIL -> "I_NIL" + | I_NONE -> "I_NONE" + | I_NOT -> "I_NOT" + | I_NOW -> "I_NOW" + | I_OR -> "I_OR" + | I_PAIR -> "I_PAIR" + | I_UNPAIR -> "I_UNPAIR" + | I_PUSH -> "I_PUSH" + | I_RIGHT -> "I_RIGHT" + | I_SIZE_SET -> "I_SIZE_SET" + | I_SIZE_MAP -> "I_SIZE_MAP" + | I_SIZE_LIST -> "I_SIZE_LIST" + | I_SIZE_STRING -> "I_SIZE_STRING" + | I_SIZE_BYTES -> "I_SIZE_BYTES" + | I_SOME -> "I_SOME" + | I_SOURCE -> "I_SOURCE" + | I_SENDER -> "I_SENDER" + | I_SELF -> "I_SELF" + | I_SLICE -> "I_SLICE" + | I_STEPS_TO_QUOTA -> "I_STEPS_TO_QUOTA" + | I_SUB -> "I_SUB" + | I_SWAP -> "I_SWAP" + | I_TRANSFER_TOKENS -> "I_TRANSFER_TOKENS" + | I_SET_DELEGATE -> "I_SET_DELEGATE" + | I_UNIT -> "I_UNIT" + | I_UPDATE_SET -> "I_UPDATE_SET" + | I_UPDATE_MAP -> "I_UPDATE_MAP" + | I_XOR -> "I_XOR" + | I_ITER_MAP -> "I_ITER_MAP" + | I_ITER_LIST -> "I_ITER_LIST" + | I_ITER_SET -> "I_ITER_SET" + | I_LOOP_LEFT -> "I_LOOP_LEFT" + | I_ADDRESS -> "I_ADDRESS" + | I_CONTRACT -> "I_CONTRACT" + | I_ISNAT -> "I_ISNAT" + | I_CAST -> "I_CAST" + | I_RENAME -> "I_RENAME" + | I_DIG -> "I_DIG" + | I_DUG -> "I_DUG" + | I_LEVEL -> "I_LEVEL" + | I_SELF_ADDRESS -> "I_SELF_ADDRESS" + | I_NEVER -> "I_NEVER" + | I_SAPLING_EMPTY_STATE -> "I_SAPLING_EMPTY_STATE" + | I_SAPLING_VERIFY_UPDATE -> "I_SAPLING_VERIFY_UPDATE" + | I_VOTING_POWER -> "I_VOTING_POWER" + | I_TOTAL_VOTING_POWER -> "I_TOTAL_VOTING_POWER" + | I_KECCAK -> "I_KECCAK" + | I_SHA3 -> "I_SHA3" + | I_PAIRING_CHECK -> "I_PAIRING_CHECK" + | I_TICKET -> "I_TICKET" + | I_READ_TICKET -> "I_READ_TICKET" + | I_SPLIT_TICKET -> "I_SPLIT_TICKET" + | I_JOIN_TICKETS -> "I_JOIN_TICKETS" + | T_bool -> "T_bool" + | T_contract -> "T_contract" + | T_int -> "T_int" + | T_key -> "T_key" + | T_key_hash -> "T_key_hash" + | T_lambda -> "T_lambda" + | T_list -> "T_list" + | T_map -> "T_map" + | T_big_map -> "T_big_map" + | T_nat -> "T_nat" + | T_option -> "T_option" + | T_or -> "T_or" + | T_pair -> "T_pair" + | T_set -> "T_set" + | T_signature -> "T_signature" + | T_string -> "T_string" + | T_bytes -> "T_bytes" + | T_mutez -> "T_mutez" + | T_timestamp -> "T_timestamp" + | T_unit -> "T_unit" + | T_operation -> "T_operation" + | T_address -> "T_address" + | T_chain_id -> "T_chain_id" + | T_never -> "T_never" + | T_sapling_state -> "T_sapling_state" + | T_sapling_transaction -> "T_sapling_transaction" + | T_bls12_381_g1 -> "T_bls12_381_g1" + | T_bls12_381_g2 -> "T_bls12_381_g2" + | T_bls12_381_fr -> "T_bls12_381_fr" + | T_ticket -> "T_ticket" + | I_Hole -> "I_Hole" + | D_Hole -> "D_Hole" + | A_Int -> "A_Int" + | A_Nat -> "A_Nat" + | A_Timestamp -> "A_Timestamp" + | A_Mutez -> "A_Mutez" + | A_Key_hash -> "A_Key_hash" + | A_Key -> "A_Key" + | A_List -> "A_List" + | A_Set -> "A_Set" + | A_Map -> "A_Map" + | A_Lambda -> "A_Lambda" + +let pp fmtr prim = Format.fprintf fmtr "%s" (string_of_prim prim) + +type kind = Data_kind | Instr_kind | Type_kind | Keyword_kind | Annot_kind + +let kind (x : prim) = + match x with + | K_parameter | K_storage | K_code -> Keyword_kind + | D_Hole | D_False | D_Elt | D_Left | D_None | D_Pair | D_Right | D_Some + | D_True | D_Unit -> + Data_kind + | I_PACK | I_UNPACK | I_BLAKE2B | I_SHA256 | I_SHA512 | I_ABS | I_ADD + | I_AMOUNT | I_AND | I_BALANCE | I_CAR | I_CDR | I_CHAIN_ID + | I_CHECK_SIGNATURE | I_COMPARE | I_CONCAT | I_CONS | I_CREATE_ACCOUNT + | I_CREATE_CONTRACT | I_IMPLICIT_ACCOUNT | I_DIP | I_DROP | I_DUP | I_EDIV + | I_EMPTY_BIG_MAP | I_EMPTY_MAP | I_EMPTY_SET | I_EQ | I_EXEC | I_APPLY + | I_FAILWITH | I_GE | I_GET_MAP | I_GET_AND_UPDATE_MAP | I_GT | I_HASH_KEY + | I_IF | I_IF_CONS | I_IF_LEFT | I_IF_NONE | I_INT | I_LAMBDA | I_LE | I_LEFT + | I_LOOP | I_LSL | I_LSR | I_LT | I_MAP_MAP | I_MAP_LIST | I_MEM_SET + | I_MEM_MAP | I_MUL | I_NEG | I_NEQ | I_NIL | I_NONE | I_NOT | I_NOW | I_OR + | I_PAIR | I_UNPAIR | I_PUSH | I_RIGHT | I_SIZE_SET | I_SIZE_MAP | I_SIZE_LIST + | I_SIZE_STRING | I_SIZE_BYTES | I_SOME | I_SOURCE | I_SENDER | I_SELF + | I_SLICE | I_STEPS_TO_QUOTA | I_SUB | I_SWAP | I_TRANSFER_TOKENS + | I_SET_DELEGATE | I_UNIT | I_UPDATE_SET | I_UPDATE_MAP | I_XOR | I_ITER_MAP + | I_ITER_LIST | I_ITER_SET | I_LOOP_LEFT | I_ADDRESS | I_CONTRACT | I_ISNAT + | I_CAST | I_RENAME | I_DIG | I_DUG | I_LEVEL | I_SELF_ADDRESS | I_NEVER + | I_SAPLING_EMPTY_STATE | I_SAPLING_VERIFY_UPDATE | I_VOTING_POWER + | I_TOTAL_VOTING_POWER | I_KECCAK | I_SHA3 | I_PAIRING_CHECK | I_TICKET + | I_READ_TICKET | I_SPLIT_TICKET | I_JOIN_TICKETS | I_Hole -> + Instr_kind + | T_bool | T_contract | T_int | T_key | T_key_hash | T_lambda | T_list | T_map + | T_big_map | T_nat | T_option | T_or | T_pair | T_set | T_signature + | T_string | T_bytes | T_mutez | T_timestamp | T_unit | T_operation + | T_address | T_chain_id | T_never | T_sapling_state | T_sapling_transaction + | T_bls12_381_g1 | T_bls12_381_g2 | T_bls12_381_fr | T_ticket -> + Type_kind + (* Holes in programs and data. *) + (* Annotations. *) + | A_Int | A_Nat | A_Timestamp | A_Mutez | A_Key_hash | A_Key | A_List | A_Set + | A_Map | A_Lambda -> + Annot_kind diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/monads.ml b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/monads.ml new file mode 100644 index 000000000000..d0939011cb5e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/monads.ml @@ -0,0 +1,83 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Widely used module types. *) + +module type S = sig + type 'a t + + val ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t + + val return : 'a -> 'a t + + val run : 'a t -> 'a +end + +(* Signature of a state monad. *) +module type State_sig = sig + type state + + type key + + type value + + include S with type 'a t = state -> 'a * state + + val empty : unit -> state + + val set : key -> value -> unit t + + val get : key -> value option t + + val iter_list : ('a -> unit t) -> 'a list -> unit t +end + +module Make_state_monad (X : Stores.S) : + State_sig + with type state = X.state + and type key = X.key + and type value = X.value + and type 'a t = X.state -> 'a * X.state = struct + include X + + type 'a t = state -> 'a * state + + let ( >>= ) m f s = + let (x, s) = m s in + f x s + + let return x s = (x, s) + + let run m = fst (m (empty ())) + + let set k v s = ((), set k v s) + + let get k s = (get k s, s) + + let rec iter_list (f : 'a -> unit t) (l : 'a list) = + match l with + | [] -> return () + | elt :: tl -> f elt >>= fun () -> iter_list f tl +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/stores.ml b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/stores.ml new file mode 100644 index 000000000000..dff87824d1b4 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/stores.ml @@ -0,0 +1,85 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Various implementations of Monads.Store_sig *) + +(* Signature of a persistent store. *) +module type S = sig + type state + + type key + + type value + + val empty : unit -> state + + val set : key -> value -> state -> state + + val get : key -> state -> value option + + val map : (value -> value) -> state -> state + + val to_string : state -> string +end + +module type Map_store_param_sig = sig + type key + + type value + + val key_to_string : key -> string + + val value_to_string : value -> string +end + +(* An implemention of [S] using maps. *) +module Map (M : Map.S) (V : Map_store_param_sig with type key = M.key) : + S with type state = V.value M.t and type key = M.key and type value = V.value = +struct + type state = V.value M.t + + type key = M.key + + type value = V.value + + let empty () = M.empty + + let set = M.add + + let get = M.find_opt + + let map = M.map + + let to_string s = + M.fold + (fun key node acc -> + Printf.sprintf + "%s\n%s |-> %s" + acc + (V.key_to_string key) + (V.value_to_string node)) + s + "" +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/.ocamlformat b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/dune b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/dune new file mode 100644 index 000000000000..2b987b8e3e93 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/dune @@ -0,0 +1,10 @@ +(tests + (names test_uf + test_inference) + (package tezos-benchmark-type-inference-011-PtHangzH) + (libraries tezos-micheline tezos-micheline-rewriting + tezos-benchmark-type-inference-011-PtHangzH tezos-protocol-011-PtHangzH + tezos-error-monad tezos-client-011-PtHangzH) + (flags + (:standard -open Tezos_micheline + -open Tezos_benchmark_type_inference_011_PtHangzH))) diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/test_inference.ml b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/test_inference.ml new file mode 100644 index 000000000000..463a30657f96 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/test_inference.ml @@ -0,0 +1,637 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* open Tezos_rewriting *) +open Mikhailsky + +let unopt x = match x with Some x -> x | None -> assert false + +let time f = + let now = Unix.gettimeofday () in + let res = f () in + let later = Unix.gettimeofday () in + (later -. now, res) + +let add_ii = Instructions.(add Mikhailsky.int_ty Mikhailsky.int_ty) + +let add_in = Instructions.(add Mikhailsky.int_ty Mikhailsky.nat_ty) + +let mul_ii = Instructions.(mul Mikhailsky.int_ty Mikhailsky.int_ty) + +let push_int = Instructions.push int_ty (Data.big_integer (Z.of_int 100)) + +let push_nat = Instructions.push nat_ty (Data.big_natural (Z.of_int 100)) + +module Test1 = struct + open Data + open Instructions + + let program = seq [add_ii; push bool_ty false_; dip instr_hole; dip swap] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test2 = struct + open Instructions + + let program = seq [loop swap; and_] + + let () = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING FAILURE\n" ; + Format.printf "Program: %a\n" Mikhailsky.pp program ; + let exception Test_failed in + try + ignore + ( time @@ fun () -> + ignore @@ Inference.infer program ; + raise Test_failed ) + with + | Inference.Ill_typed_script error -> + Format.printf "Error:\n" ; + Format.printf "%a\n" Inference.pp_inference_error error + | Test_failed -> Format.printf "No type error: Test failed!" + + let _ = print_newline () +end + +module Test3 = struct + open Instructions + + let program = + seq + [ + dip (seq [swap; dup]); + swap; + dip cdr; + loop (seq [dip instr_hole; cdr; loop instr_hole]); + car; + car; + push int_ty (Data.integer 10); + compare; + ] + + let _ = + Format.printf "Testing rewriting and type inference\n" ; + Format.printf "Source program: %a\n" Mikhailsky.pp program + + open Tezos_micheline_rewriting + + module Lang = + Micheline_with_hash_consing.Make + (Mikhailsky.Mikhailsky_signature) + (struct + let initial_size = None + end) + + module Path = Mikhailsky.Path + module Patt = Pattern.Make (Mikhailsky.Mikhailsky_signature) (Lang) (Path) + module Rewriter = + Rewrite.Make (Mikhailsky.Mikhailsky_signature) (Lang) (Path) (Patt) + + let (timing, ((bef, aft), state)) = + try time @@ fun () -> Inference.infer_with_state program + with Inference.Ill_typed_script error -> + let s = Mikhailsky.to_string program in + Format.printf + "Ill-typed script:%a\n%s\n" + Inference.pp_inference_error + error + s ; + Format.printf "Test failed\n" ; + exit 1 + + let () = + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft + + let () = + try + ignore + ((let open Inference in + let open M in + M.uf_lift Uf.UF.show >>= fun uf_state -> + Inference.M.repr_lift (fun s -> (Inference.Repr_store.to_string s, s)) + >>= fun repr_state -> + Printf.printf "uf_state:\n%s\n" uf_state ; + Printf.printf "repr_state:\n%s\n" repr_state ; + let path = + Path.(at_index 2 (at_index 0 (at_index 0 (at_index 3 root)))) + in + let subterm = Rewriter.get_subterm ~term:program ~path in + Format.printf + "subterm at path %s:\n%a\n" + (Path.to_string path) + Mikhailsky.pp + subterm ; + Inference.M.annot_instr_lift (Inference.Annot_instr_sm.get path) + >>= fun typ -> + (match typ with + | None -> assert false + | Some {bef; aft} -> + Inference.instantiate bef >>= fun bef -> + Inference.instantiate aft >>= fun aft -> + Format.printf "Type of subterm:\n" ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + return ()) + >>= fun () -> return ()) + state) + with Inference.Ill_typed_script error -> + let s = Mikhailsky.to_string program in + Format.printf + "Ill-typed script:\n%a\n%s\n" + Inference.pp_inference_error + error + s + + let _ = print_newline () +end + +module Test4 = struct + open Instructions + + let program = + seq + [ + empty_set; + push Type.(unopt (unparse_ty bool)) Data.true_; + push + Type.(unopt (unparse_ty (pair int int))) + Data.(pair (integer 0) (integer 0)); + update_set; + ] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test5 = struct + open Instructions + + let unopt x = match x with Some x -> x | None -> assert false + + let program = + seq + [ + empty_map; + push Type.(unopt (unparse_ty (option (set int)))) Data.none; + push + Type.(unopt (unparse_ty (pair int int))) + Data.(pair (integer 0) (integer 0)); + update_map; + ] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () + + let program = + seq + [ + push + Type.(unopt (unparse_ty (map (pair int int) (set int)))) + Data.( + map + [ + map_elt + (pair (integer 0) (integer 1)) + (set [integer 42; integer 44]); + map_elt + (pair (integer 1) (integer 2)) + (set [integer 42; integer 48]); + ]); + ] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test6 = struct + open Instructions + + let program_str = + "parameter unit ;\n\ + storage unit ;\n\ + code { PUSH int 0 ;\n\ + \ PUSH int 100 ;\n\ + \ SWAP ;\n\ + \ DROP ;\n\ + \ DROP ;\n\ + \ DROP ;\n\ + \ PUSH unit Unit ;\n\ + \ PUSH bool False ;\n\ + \ PUSH unit Unit ;\n\ + \ PUSH int 4073851221413541140 ;\n\ + \ PUSH string \"n\" ;\n\ + \ PUSH string \"k\" ;\n\ + \ PUSH int 13919897678870462893 ;\n\ + \ PUSH int 100 ;\n\ + \ ABS ;\n\ + \ DROP ;\n\ + \ DIP { CONCAT } ;\n\ + \ COMPARE }" + + (* We remove a chunk from a well-typed program to make it ill-typed, and + expect the type inference to fail *) + let program = + seq + [ + push int_ty (Data.integer 0); + push int_ty (Data.integer 100); + swap; + drop; + drop; + drop; + push unit_ty Data.unit; + push bool_ty Data.false_; + push unit_ty Data.unit; + push int_ty (Data.integer 4073851221413541140); + push string_ty (string "n"); + push string_ty (string "k"); + push int_ty (Data.integer 1391989767887046289); + (* push int_ty (integer 100); + * abs; + * drop; *) + dip (prim I_CONCAT [] []); + compare; + ] + + let () = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING FAILURE\n" ; + Format.printf "Program: %a\n" Mikhailsky.pp program ; + let exception Test_failed in + try + ignore (Inference.infer program) ; + raise Test_failed + with + | Inference.Ill_typed_script error -> + Format.printf "Got error, as expected:\n" ; + Format.printf "%a@." Inference.pp_inference_error error + | Test_failed -> + Format.printf "No type error: Test failed!" ; + exit 1 +end + +module Test7 = struct + open Instructions + + let program = + seq + [ + push int_ty (Data.integer 42); + left; + push string_ty (Data.string "forty-two"); + right; + pair; + left; + ] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test8 = struct + open Instructions + + let program = + seq + [ + hole; + add_ii; + push int_ty (Data.big_integer (Z.of_int 100)); + abs; + right; + dup; + push int_ty (Data.big_integer (Z.of_int 100)); + dip (loop_left hole); + push_int; + hole; + mul_ii; + hole; + loop_left left; + sha512; + push_int; + dup; + add_ii; + right; + swap; + hole; + drop; + compare; + mul_ii; + push_int; + ] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test9 = struct + open Instructions + + let program = seq [car; if_none hole hole] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test10 = struct + open Instructions + + let program = seq [hash_key] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test11 = struct + open Instructions + + let program = + seq [lambda [dup; car; dip cdr; add_in]; push_int; apply; push_nat; exec] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test12 = struct + open Instructions + + let program = seq [dup; dup; if_none hole (seq [drop]); dup; compare] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test13 = struct + open Instructions + + let program = + seq [push Type.(unparse_ty_exn (lambda int int)) (Data.lambda [])] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test14 = struct + open Instructions + + let program = seq [nil; push_int; cons] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test15 = struct + open Instructions + + let program = seq [empty_set; size_set; empty_map; size_map; nil; size_list] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test16 = struct + open Instructions + + let program = + seq + [ + empty_set; + push bool_ty Data.true_; + push_int; + update_set; + iter_set [dup; add_ii; add_ii]; + ] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test17 = struct + open Instructions + + let program = + seq + [ + empty_map; + push (option_ty (list_ty bool_ty)) Data.(some (list [false_; true_])); + push_int; + update_map; + map_map + [ + cdr; + map_list + [ + if_ + (seq [push bool_ty Data.false_]) + (seq [push bool_ty Data.true_]); + ]; + ]; + ] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end + +module Test18 = struct + open Instructions + + let program = + seq + [ + empty_map; + push (option_ty (list_ty bool_ty)) Data.(some (list [false_; true_])); + push_int; + update_map; + map_map + [ + cdr; + map_list + [ + if_ + (seq [push bool_ty Data.false_]) + (seq [push bool_ty Data.true_]); + ]; + ]; + dup; + dip push_int; + push_int; + mem_map; + if_ + (seq [get_map]) + (seq [drop; drop; push (option_ty (list_ty bool_ty)) Data.none]); + ] + + let (timing, (bef, aft)) = time @@ fun () -> Inference.infer program + + let _ = + Format.printf "Testing type inference\n" ; + Format.printf "EXPECTING SUCCESS\n" ; + Format.printf "Program\n" ; + Format.printf "%a\n" Mikhailsky.pp program ; + Format.printf "In %f seconds:\n" timing ; + Format.printf "bef: %a@." Type.Stack.pp bef ; + Format.printf "aft: %a@." Type.Stack.pp aft ; + print_newline () +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/test_uf.ml b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/test_uf.ml new file mode 100644 index 000000000000..84fdd856e9ba --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/test/test_uf.ml @@ -0,0 +1,63 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let _ = + print_newline () ; + Printf.printf "Testing union-find algorithm\n" + +module UF = Uf.UF + +let test = + let open UF.M in + UF.add 0 >>= fun () -> + UF.add 1 >>= fun () -> + UF.add 2 >>= fun () -> + UF.add 3 >>= fun () -> + UF.add 4 >>= fun () -> + UF.find 0 >>= fun v0_repr -> + UF.find 1 >>= fun v1_repr -> + assert (v0_repr <> v1_repr) ; + UF.union 0 1 >>= fun _ -> + UF.find 0 >>= fun v0_repr -> + UF.find 1 >>= fun v1_repr -> + UF.find 2 >>= fun v2_repr -> + assert (v0_repr = v1_repr) ; + assert (v0_repr <> v2_repr) ; + UF.union 2 3 >>= fun _ -> + UF.union 0 3 >>= fun _ -> + UF.find 1 >>= fun v1_repr -> + UF.find 2 >>= fun v2_repr -> + UF.find 3 >>= fun v3_repr -> + UF.find 4 >>= fun v4_repr -> + assert (v1_repr = v2_repr) ; + UF.union 4 4 >>= fun _ -> + assert (v3_repr <> v4_repr) ; + UF.show >>= fun s -> + Printf.printf "UF state:%s\n" s ; + return () + +let () = UF.M.run test + +let _ = Printf.printf "Success.\n" diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/tezos-benchmark-type-inference-011-PtHangzH.opam b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/tezos-benchmark-type-inference-011-PtHangzH.opam new file mode 100644 index 000000000000..44bc65dbb336 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/tezos-benchmark-type-inference-011-PtHangzH.opam @@ -0,0 +1,24 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "tezos-tooling" { with-test } + "tezos-client-011-PtHangzH" { with-test } + "dune" { >= "1.11" } + "tezos-stdlib" + "tezos-error-monad" + "tezos-crypto" + "tezos-protocol-011-PtHangzH" + "tezos-micheline" + "tezos-micheline-rewriting" + "hashcons" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos: type inference for partial Michelson expressions" diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/type.ml b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/type.ml new file mode 100644 index 000000000000..dacd2ac7f8fd --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/type.ml @@ -0,0 +1,201 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Michelson types. *) + +module Base = struct + type comparable_tag = Comparable | Maybe_not_comparable + + type t = t_node Hashcons.hash_consed + + and t_node = + | Unit_t + | Var_t of int + | Int_t + | Nat_t + | Bool_t + | String_t + | Bytes_t + | Key_hash_t + | Timestamp_t + | Mutez_t + | Key_t + | Option_t of t + | Pair_t of t * t + | Union_t of t * t + | List_t of t + | Set_t of t + | Map_t of t * t + | Lambda_t of t * t + + module Hashed = struct + type t = t_node + + let equal (t1 : t) (t2 : t) = + match (t1, t2) with + | (Var_t v1, Var_t v2) -> v1 = v2 + | (Unit_t, Unit_t) + | (Int_t, Int_t) + | (Nat_t, Nat_t) + | (Bool_t, Bool_t) + | (String_t, String_t) + | (Bytes_t, Bytes_t) + | (Key_hash_t, Key_hash_t) + | (Timestamp_t, Timestamp_t) + | (Mutez_t, Mutez_t) + | (Key_t, Key_t) -> + true + | (Option_t ty1, Option_t ty2) -> ty1.tag = ty2.tag + | (Pair_t (l1, r1), Pair_t (l2, r2)) -> l1.tag = l2.tag && r1.tag = r2.tag + | (Union_t (l1, r1), Union_t (l2, r2)) -> + l1.tag = l2.tag && r1.tag = r2.tag + | (List_t ty1, List_t ty2) -> ty1.tag = ty2.tag + | (Set_t ty1, Set_t ty2) -> ty1.tag = ty2.tag + | (Map_t (kty1, vty1), Map_t (kty2, vty2)) -> + kty1.tag = kty2.tag && vty1.tag = vty2.tag + | (Lambda_t (dom1, range1), Lambda_t (dom2, range2)) -> + dom1.tag = dom2.tag && range1.tag = range2.tag + | _ -> false + + let hash (t : t) = Hashtbl.hash t + end + + module Table = Hashcons.Make (Hashed) + + let table = Table.create 101 + + let rec pp fmtr x = + match x.Hashcons.node with + | Unit_t -> Format.pp_print_string fmtr "unit" + | Var_t v -> Format.fprintf fmtr "%d" v + | Int_t -> Format.pp_print_string fmtr "int" + | Nat_t -> Format.pp_print_string fmtr "nat" + | Bool_t -> Format.pp_print_string fmtr "bool" + | String_t -> Format.pp_print_string fmtr "string" + | Bytes_t -> Format.pp_print_string fmtr "bytes" + | Key_hash_t -> Format.pp_print_string fmtr "key_hash" + | Timestamp_t -> Format.pp_print_string fmtr "timestamp" + | Mutez_t -> Format.pp_print_string fmtr "mutez" + | Key_t -> Format.pp_print_string fmtr "key" + | Option_t ty -> Format.fprintf fmtr "(option %a)" pp ty + | List_t ty -> Format.fprintf fmtr "(list %a)" pp ty + | Pair_t (lty, rty) -> Format.fprintf fmtr "(pair %a %a)" pp lty pp rty + | Union_t (lty, rty) -> Format.fprintf fmtr "(union %a %a)" pp lty pp rty + | Set_t ty -> Format.fprintf fmtr "(set %a)" pp ty + | Map_t (kty, vty) -> Format.fprintf fmtr "(map %a %a)" pp kty pp vty + | Lambda_t (dom, range) -> + Format.fprintf fmtr "(lambda %a %a)" pp dom pp range + + let rec vars x acc = + match x.Hashcons.node with + | Unit_t | Int_t | Nat_t | Bool_t | String_t | Bytes_t | Key_hash_t + | Timestamp_t | Mutez_t | Key_t -> + acc + | Var_t v -> v :: acc + | Option_t ty | List_t ty | Set_t ty -> vars ty acc + | Pair_t (lty, rty) | Union_t (lty, rty) -> vars lty (vars rty acc) + | Map_t (kty, vty) -> vars kty (vars vty acc) + | Lambda_t (dom, range) -> vars dom (vars range acc) + + let vars x = vars x [] +end + +module Stack = struct + type t = t_node Hashcons.hash_consed + + and t_node = Empty_t | Stack_var_t of int | Item_t of Base.t * t + + module Hashed = struct + type t = t_node + + let equal (t1 : t) (t2 : t) = + match (t1, t2) with + | (Empty_t, Empty_t) -> true + | (Stack_var_t v1, Stack_var_t v2) -> v1 = v2 + | (Item_t (h1, tl1), Item_t (h2, tl2)) -> h1 == h2 && tl1 == tl2 + | _ -> false + + let hash (t : t) = Hashtbl.hash t + end + + module Table = Hashcons.Make (Hashed) + + let table = Table.create 101 + + let rec pp fmtr x = + match x.Hashcons.node with + | Empty_t -> Format.pp_print_string fmtr "[]" + | Stack_var_t v -> Format.fprintf fmtr "<%d>" v + | Item_t (head, tail) -> Format.fprintf fmtr "%a :: %a" Base.pp head pp tail + + let rec vars x = + match x.Hashcons.node with + | Empty_t -> None + | Stack_var_t v -> Some v + | Item_t (_head, tail) -> vars tail +end + +let unit = Base.Table.hashcons Base.table Unit_t + +let var x = Base.Table.hashcons Base.table (Var_t x) + +let int = Base.Table.hashcons Base.table Int_t + +let nat = Base.Table.hashcons Base.table Nat_t + +let bool = Base.Table.hashcons Base.table Bool_t + +let string = Base.Table.hashcons Base.table String_t + +let bytes = Base.Table.hashcons Base.table Bytes_t + +let key_hash = Base.Table.hashcons Base.table Key_hash_t + +let timestamp = Base.Table.hashcons Base.table Timestamp_t + +let mutez = Base.Table.hashcons Base.table Mutez_t + +let key = Base.Table.hashcons Base.table Key_t + +let option ty = Base.Table.hashcons Base.table (Option_t ty) + +let pair lty rty = Base.Table.hashcons Base.table (Pair_t (lty, rty)) + +let union lty rty = Base.Table.hashcons Base.table (Union_t (lty, rty)) + +let list ty = Base.Table.hashcons Base.table (List_t ty) + +let set ty = Base.Table.hashcons Base.table (Set_t ty) + +let map kty vty = Base.Table.hashcons Base.table (Map_t (kty, vty)) + +let lambda dom range = Base.Table.hashcons Base.table (Lambda_t (dom, range)) + +(* Stack smart constructors *) +let empty = Stack.Table.hashcons Stack.table Empty_t + +let stack_var x = Stack.Table.hashcons Stack.table (Stack_var_t x) + +let item head tail = Stack.Table.hashcons Stack.table (Item_t (head, tail)) diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/type.mli b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/type.mli new file mode 100644 index 000000000000..168ba97e4d21 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/type.mli @@ -0,0 +1,111 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Michelson types, hash-consed. *) + +(** Base types *) +module Base : sig + type comparable_tag = Comparable | Maybe_not_comparable + + type t = t_node Hashcons.hash_consed + + and t_node = private + | Unit_t + | Var_t of int + | Int_t + | Nat_t + | Bool_t + | String_t + | Bytes_t + | Key_hash_t + | Timestamp_t + | Mutez_t + | Key_t + | Option_t of t + | Pair_t of t * t + | Union_t of t * t + | List_t of t + | Set_t of t + | Map_t of t * t + | Lambda_t of t * t + + val pp : Format.formatter -> t -> unit + + val vars : t -> int list +end + +(** Stack types *) +module Stack : sig + type t = t_node Hashcons.hash_consed + + and t_node = private Empty_t | Stack_var_t of int | Item_t of Base.t * t + + val pp : Format.formatter -> t -> unit + + val vars : t -> int option +end + +(** Smart constructors *) +val unit : Base.t + +val var : int -> Base.t + +val int : Base.t + +val nat : Base.t + +val bool : Base.t + +val string : Base.t + +val bytes : Base.t + +val key_hash : Base.t + +val timestamp : Base.t + +val mutez : Base.t + +val key : Base.t + +val option : Base.t -> Base.t + +val pair : Base.t -> Base.t -> Base.t + +val union : Base.t -> Base.t -> Base.t + +val list : Base.t -> Base.t + +val set : Base.t -> Base.t + +val map : Base.t -> Base.t -> Base.t + +val lambda : Base.t -> Base.t -> Base.t + +val empty : Stack.t + +val stack_var : int -> Stack.t + +val item : Base.t -> Stack.t -> Stack.t diff --git a/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/uf.ml b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/uf.ml new file mode 100644 index 000000000000..f14a166939a7 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/lib_benchmark_type_inference/uf.ml @@ -0,0 +1,99 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* ------------------------------------------------------------------------- *) +(* Union find parameterized over a persistent store. *) + +module type S = sig + module M : Monads.State_sig + + type key = int + + val add : key -> unit M.t + + val find : key -> key M.t + + val union : key -> key -> key M.t + + val show : string M.t +end + +module UF : S = struct + type node = T of {rank : int} | Ptr of key + + and key = int + + module S = + Stores.Map + (Int_map) + (struct + type key = int + + type value = node + + let key_to_string = string_of_int + + let value_to_string (x : value) = + match x with + | T {rank} -> Printf.sprintf "[%d]" rank + | Ptr k -> Printf.sprintf "ptr(%d)" k + end) + + module M = Monads.Make_state_monad (S) + + let add (k : key) = + let open M in + set k (T {rank = 1}) + + let rec get_root (k : key) (acc : key list) = + let open M in + get k >>= function + | None -> + let msg = Printf.sprintf "UF.get_root: invalid key %d" k in + Stdlib.failwith msg + | Some (T {rank}) -> + let ptr_to_root = Ptr k in + iter_list (fun key -> set key ptr_to_root) acc >>= fun () -> + return (k, rank) + | Some (Ptr k') -> get_root k' (k :: acc) + + let find (k : key) = + let open M in + get_root k [] >>= fun (res, _) -> return res + + let union k1 k2 = + let open M in + get_root k1 [] >>= fun (k1, rank1) -> + get_root k2 [] >>= fun (k2, rank2) -> + if k1 = k2 then return k1 + else if rank1 < rank2 then set k1 (Ptr k2) >>= fun () -> return k2 + else if rank1 > rank2 then set k2 (Ptr k1) >>= fun () -> return k1 + else + let new_root = T {rank = rank1 + 1} in + set k2 (Ptr k1) >>= fun () -> + set k1 new_root >>= fun () -> return k1 + + let show s = (S.to_string s, s) +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/micheline_sampler.ml b/src/proto_011_PtHangzH/lib_benchmark/micheline_sampler.ml new file mode 100644 index 000000000000..1e4778f856f0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/micheline_sampler.ml @@ -0,0 +1,110 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Micheline sampling. *) + +type width_function = depth:int -> int Base_samplers.sampler + +(** [Base_samplers] specifies samplers for leaves, primitives and annotations. *) +module type Base_samplers = sig + (** The type of primitives. *) + type prim + + val sample_prim : prim Base_samplers.sampler + + val sample_annots : string list Base_samplers.sampler + + val sample_string : string Base_samplers.sampler + + val sample_bytes : Bytes.t Base_samplers.sampler + + val sample_z : Z.t Base_samplers.sampler + + val width_function : width_function +end + +module type S = sig + type prim + + val sample : (int, prim) Micheline.node Base_samplers.sampler +end + +type node_kind = Int_node | String_node | Bytes_node | Seq_node | Prim_node + +(* The distribution can be skewed towards non-leaf nodes by repeating their + relevant kind in the array below. *) +let all_kinds = [|Int_node; String_node; Bytes_node; Seq_node; Prim_node|] + +let sample_kind : node_kind Base_samplers.sampler = + fun rng_state -> + let i = Random.State.int rng_state (Array.length all_kinds) in + all_kinds.(i) + +let reasonable_width_function ~depth rng_state = + (* Entirely ad-hoc *) + Base_samplers.( + sample_in_interval + ~range:{min = 0; max = 20 / (Bits.numbits depth + 1)} + rng_state) + +module Make (P : Base_samplers) : S with type prim = P.prim = struct + type prim = P.prim + + let sample (w : width_function) rng_state = + let rec sample depth rng_state k = + match sample_kind rng_state with + | Int_node -> k (Micheline.Int (0, P.sample_z rng_state)) + | String_node -> k (Micheline.String (0, P.sample_string rng_state)) + | Bytes_node -> k (Micheline.Bytes (0, P.sample_bytes rng_state)) + | Seq_node -> + let width = w ~depth rng_state in + sample_list + depth + width + [] + (fun terms -> k (Micheline.Seq (0, terms))) + rng_state + | Prim_node -> + let prim = P.sample_prim rng_state in + let annots = P.sample_annots rng_state in + let width = w ~depth rng_state in + sample_list + depth + width + [] + (fun terms -> k (Micheline.Prim (0, prim, terms, annots))) + rng_state + and sample_list depth width acc k rng_state = + if width < 0 then invalid_arg "sample_list: negative width" + else if width = 0 then k (List.rev acc) + else + sample (depth + 1) rng_state (fun x -> + sample_list depth (width - 1) (x :: acc) k rng_state) + in + sample 0 rng_state (fun x -> x) + + let sample rng_state = sample P.width_function rng_state +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/micheline_sampler.mli b/src/proto_011_PtHangzH/lib_benchmark/micheline_sampler.mli new file mode 100644 index 000000000000..97e3d4ec1e12 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/micheline_sampler.mli @@ -0,0 +1,70 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Micheline sampling. *) + +(** A [width_function] specifies the distribution of node degree as a function + of [depth]. A [width_function] {e must} be supported by the nonnegative + integers. + + Note that picking a [width_function] which doesn't converge fast enough to + the singular distribution on 0 could yield very large terms. *) +type width_function = depth:int -> int Base_samplers.sampler + +(** [reasonable_width_function] is a width function which works well + empirically. *) +val reasonable_width_function : width_function + +(** [Base_samplers] specifies samplers for leaves, primitives and annotations. *) +module type Base_samplers = sig + (** The type of primitives. *) + type prim + + val sample_prim : prim Base_samplers.sampler + + val sample_annots : string list Base_samplers.sampler + + val sample_string : string Base_samplers.sampler + + val sample_bytes : Bytes.t Base_samplers.sampler + + val sample_z : Z.t Base_samplers.sampler + + val width_function : width_function +end + +(** Applying the [Make] functor below yields a module with the following + type. *) +module type S = sig + type prim + + (** [sample w] is a Micheline sampler for the prescribed primitive + type. The sampler uses the provided width function [w]. *) + val sample : (int, prim) Micheline.node Base_samplers.sampler +end + +(** [Make] instantiates a micheline sampler. *) +module Make (P : Base_samplers) : S with type prim = P.prim diff --git a/src/proto_011_PtHangzH/lib_benchmark/michelson.ml b/src/proto_011_PtHangzH/lib_benchmark/michelson.ml new file mode 100644 index 000000000000..9c9ef9ebbfd0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/michelson.ml @@ -0,0 +1,232 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +exception Cannot_get_type of Mikhailsky.node * Kernel.Path.t + +exception Unexpected_stack_type of string + +exception Unexpected_base_type + +let unparse_type = Mikhailsky.map_var (fun _ -> Mikhailsky.prim T_unit [] []) + +let project_top (aft : Type.Stack.t) = + match aft.node with + | Type.Stack.Empty_t -> raise (Unexpected_stack_type "empty") + | Type.Stack.Stack_var_t _ -> raise (Unexpected_stack_type "var") + | Type.Stack.Item_t (top, _) -> top + +let project_union (aft : Type.Stack.t) = + let top = project_top aft in + match top.node with + | Type.Base.Union_t (l, r) -> (l, r) + | _ -> raise Unexpected_base_type + +let project_lambda (aft : Type.Stack.t) = + let top = project_top aft in + match top.node with + | Type.Base.Lambda_t (dom, range) -> (dom, range) + | _ -> raise Unexpected_base_type + +let project_list (aft : Type.Stack.t) = + let top = project_top aft in + match top.node with + | Type.Base.List_t t -> t + | _ -> raise Unexpected_base_type + +let project_set (aft : Type.Stack.t) = + let top = project_top aft in + match top.node with Type.Base.Set_t t -> t | _ -> raise Unexpected_base_type + +let project_map (aft : Type.Stack.t) = + let top = project_top aft in + match top.node with + | Type.Base.Map_t (k, v) -> (k, v) + | _ -> raise Unexpected_base_type + +let project_option (aft : Type.Stack.t) = + let top = project_top aft in + match top.node with + | Type.Base.Option_t t -> t + | _ -> raise Unexpected_base_type + +let rec of_mikhailsky_raw : Mikhailsky.node -> (int, 'a) Micheline.node = + fun node -> + match node with + | Micheline.Int (_, i) -> Micheline.Int (0, i) + | Micheline.Prim (_, head, subterms, annots) -> + let head = Mikhailsky_prim.to_michelson head in + Micheline.Prim (0, head, List.map of_mikhailsky_raw subterms, annots) + | Micheline.String (_, s) -> Micheline.String (0, s) + | Micheline.Bytes (_, b) -> Micheline.Bytes (0, b) + | Micheline.Seq (_, subterms) -> + Micheline.Seq (0, List.map of_mikhailsky_raw subterms) + +(* We assume that the term has been completed. *) +let rec of_mikhailsky : + Mikhailsky.node -> Kernel.Path.t -> (int, 'a) Micheline.node Inference.M.t = + fun node path -> + let open Inference.M in + match node with + | Micheline.Int (_, i) -> return (Micheline.Int (0, i)) + | Micheline.String (_, s) -> return (Micheline.String (0, s)) + | Micheline.Bytes (_, b) -> return (Micheline.Bytes (0, b)) + (* Remove annotations *) + | Micheline.Prim (_, prim, [term], _) + when Mikhailsky_prim.kind prim = Annot_kind -> + let path = Kernel.Path.at_index 0 path in + of_mikhailsky term path + (* Fail on holes *) + | Micheline.Prim (_, I_Hole, _, _) | Micheline.Prim (_, D_Hole, _, _) -> + raise Mikhailsky.Term_contains_holes + (* Add type information to union injections *) + | Micheline.Prim (_, I_LEFT, [], annots) -> ( + get_instr_annot path >>= fun ty_opt -> + match ty_opt with + | None -> raise (Cannot_get_type (node, path)) + | Some {aft; _} -> + Inference.instantiate aft >>= fun aft -> + let (_, r) = project_union aft in + Inference.instantiate_base r >>= fun r -> + Autocomp.replace_vars r >>= fun r -> + let r = unparse_type r in + let head = Mikhailsky_prim.to_michelson I_LEFT in + return (Micheline.Prim (0, head, [of_mikhailsky_raw r], annots))) + | Micheline.Prim (_, I_RIGHT, [], annots) -> ( + get_instr_annot path >>= fun ty_opt -> + match ty_opt with + | None -> raise (Cannot_get_type (node, path)) + | Some {aft; _} -> + Inference.instantiate aft >>= fun aft -> + let (l, _) = project_union aft in + Inference.instantiate_base l >>= fun l -> + Autocomp.replace_vars l >>= fun l -> + let l = unparse_type l in + let head = Mikhailsky_prim.to_michelson I_RIGHT in + return (Micheline.Prim (0, head, [of_mikhailsky_raw l], annots))) + | Micheline.Prim (_, (I_LEFT | I_RIGHT), _, _) -> + raise Mikhailsky.Ill_formed_mikhailsky + (* Add type information for lambdas *) + | Micheline.Prim (_, I_LAMBDA, [code], annots) -> ( + of_mikhailsky code (Kernel.Path.at_index 0 path) >>= fun code -> + get_instr_annot path >>= fun ty_opt -> + match ty_opt with + | None -> raise (Cannot_get_type (node, path)) + | Some {aft; _} -> + Inference.instantiate aft >>= fun aft -> + let (dom, range) = project_lambda aft in + Inference.instantiate_base dom >>= fun dom -> + Autocomp.replace_vars dom >>= fun dom -> + Inference.instantiate_base range >>= fun range -> + Autocomp.replace_vars range >>= fun range -> + let dom = unparse_type dom in + let range = unparse_type range in + let head = Mikhailsky_prim.to_michelson I_LAMBDA in + return + (Micheline.Prim + ( 0, + head, + [of_mikhailsky_raw dom; of_mikhailsky_raw range; code], + annots ))) + (* Add type information for empty_set, empty_map *) + | Micheline.Prim (_, I_EMPTY_SET, [], annots) -> ( + get_instr_annot path >>= fun ty_opt -> + match ty_opt with + | None -> raise (Cannot_get_type (node, path)) + | Some {aft; _} -> + Inference.instantiate aft >>= fun aft -> + let elt = project_set aft in + Inference.instantiate_base elt >>= fun elt -> + Autocomp.replace_vars elt >>= fun elt -> + let elt = unparse_type elt in + let head = Mikhailsky_prim.to_michelson I_EMPTY_SET in + return (Micheline.Prim (0, head, [of_mikhailsky_raw elt], annots))) + | Micheline.Prim (_, I_EMPTY_MAP, [], annots) -> ( + get_instr_annot path >>= fun ty_opt -> + match ty_opt with + | None -> raise (Cannot_get_type (node, path)) + | Some {aft; _} -> + Inference.instantiate aft >>= fun aft -> + let (k, v) = project_map aft in + Inference.instantiate_base k >>= fun k -> + Autocomp.replace_vars k >>= fun k -> + Inference.instantiate_base v >>= fun v -> + Autocomp.replace_vars v >>= fun v -> + let k = of_mikhailsky_raw (unparse_type k) in + let v = of_mikhailsky_raw (unparse_type v) in + let head = Mikhailsky_prim.to_michelson I_EMPTY_MAP in + return (Micheline.Prim (0, head, [k; v], annots))) + (* Add type information for UNPACK *) + | Micheline.Prim (_, I_UNPACK, [], annots) -> ( + get_instr_annot path >>= fun ty_opt -> + match ty_opt with + | None -> raise (Cannot_get_type (node, path)) + | Some {aft; _} -> + Inference.instantiate aft >>= fun aft -> + let elt = project_option aft in + Inference.instantiate_base elt >>= fun elt -> + Autocomp.replace_vars elt >>= fun elt -> + let elt = unparse_type elt in + let head = Mikhailsky_prim.to_michelson I_UNPACK in + return (Micheline.Prim (0, head, [of_mikhailsky_raw elt], annots))) + (* Add type information for NIL *) + | Micheline.Prim (_, I_NIL, [], annots) -> ( + get_instr_annot path >>= fun ty_opt -> + match ty_opt with + | None -> raise (Cannot_get_type (node, path)) + | Some {aft; _} -> + Inference.instantiate aft >>= fun aft -> + let elt = project_list aft in + Inference.instantiate_base elt >>= fun elt -> + Autocomp.replace_vars elt >>= fun elt -> + let elt = unparse_type elt in + let head = Mikhailsky_prim.to_michelson I_NIL in + return (Micheline.Prim (0, head, [of_mikhailsky_raw elt], annots))) + | Micheline.Prim (_, I_NIL, _, _) -> raise Mikhailsky.Ill_formed_mikhailsky + (* Project out type information from arithmetic ops *) + | Prim (_, ((I_ADD | I_SUB | I_MUL | I_EDIV) as instr), [_ty1; _ty2], annots) + -> + let head = Mikhailsky_prim.to_michelson instr in + return (Micheline.Prim (0, head, [], annots)) + | Prim (_, (I_ADD | I_SUB | I_MUL | I_EDIV), _, _) -> + raise Mikhailsky.Ill_formed_mikhailsky + (* Base case *) + | Micheline.Prim (_, head, subterms, annots) -> + let head = Mikhailsky_prim.to_michelson head in + of_mikhailsky_list path 0 subterms [] >>= fun subterms -> + return (Micheline.Prim (0, head, subterms, annots)) + | Micheline.Seq (_, subterms) -> + of_mikhailsky_list path 0 subterms [] >>= fun subterms -> + return (Micheline.Seq (0, subterms)) + +and of_mikhailsky_list path i subterms acc = + let open Inference.M in + match subterms with + | [] -> return (List.rev acc) + | subterm :: tl -> + let path' = Kernel.Path.at_index i path in + of_mikhailsky subterm path' >>= fun term -> + of_mikhailsky_list path (i + 1) tl (term :: acc) + +let of_mikhailsky node state = fst (of_mikhailsky node Kernel.Path.root state) diff --git a/src/proto_011_PtHangzH/lib_benchmark/michelson_samplers.ml b/src/proto_011_PtHangzH/lib_benchmark/michelson_samplers.ml new file mode 100644 index 000000000000..481d2306fd35 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/michelson_samplers.ml @@ -0,0 +1,795 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Script_typed_ir + +(* ------------------------------------------------------------------------- *) +(* Helpers. *) + +let comparable_downcast = Script_ir_translator.ty_of_comparable_ty + +(* ------------------------------------------------------------------------- *) +(* Type names. *) + +(* We only want to generated inhabited types, hence Never is not included. *) + +type type_name = + [ `TUnit + | `TInt + | `TNat + | `TSignature + | `TString + | `TBytes + | `TMutez + | `TKey_hash + | `TKey + | `TTimestamp + | `TAddress + | `TBool + | `TPair + | `TUnion + | `TLambda + | `TOption + | `TList + | `TSet + | `TMap + | `TBig_map + | `TContract + | `TSapling_transaction + | `TSapling_state + | `TOperation + | `TChain_id + | `TBls12_381_g1 + | `TBls12_381_g2 + | `TBls12_381_fr + | `TTicket ] + +let all_type_names : type_name array = + [| + `TUnit; + `TInt; + `TNat; + `TSignature; + `TString; + `TBytes; + `TMutez; + `TKey_hash; + `TKey; + `TTimestamp; + `TAddress; + `TBool; + `TPair; + `TUnion; + `TLambda; + `TOption; + `TList; + `TSet; + `TMap; + `TBig_map; + `TContract; + `TSapling_transaction; + `TSapling_state; + `TOperation; + `TChain_id; + `TBls12_381_g1; + `TBls12_381_g2; + `TBls12_381_fr; + `TTicket; + |] + +type atomic_type_name = + [ `TUnit + | `TInt + | `TNat + | `TSignature + | `TString + | `TBytes + | `TMutez + | `TKey_hash + | `TKey + | `TTimestamp + | `TAddress + | `TBool + | `TSapling_transaction + | `TSapling_state + | `TChain_id + | `TBls12_381_g1 + | `TBls12_381_g2 + | `TBls12_381_fr ] + +type non_atomic_type_name = + [ `TPair + | `TUnion + | `TLambda + | `TOption + | `TList + | `TSet + | `TMap + | `TBig_map + | `TContract + | `TTicket ] + +(* Ensure inclusion of atomic_type_name in type_name *) +let (_ : atomic_type_name -> type_name) = fun x -> (x :> type_name) + +(* Ensure inclusion of non_atomic_type_name in type_name *) +let (_ : non_atomic_type_name -> type_name) = fun x -> (x :> type_name) + +let all_atomic_type_names : atomic_type_name array = + [| + `TUnit; + `TInt; + `TNat; + `TSignature; + `TString; + `TBytes; + `TMutez; + `TKey_hash; + `TKey; + `TTimestamp; + `TAddress; + `TBool; + `TSapling_transaction; + `TSapling_state; + `TChain_id; + `TBls12_381_g1; + `TBls12_381_g2; + `TBls12_381_fr; + |] + +let all_non_atomic_type_names : non_atomic_type_name array = + [| + `TPair; + `TUnion; + `TLambda; + `TOption; + `TList; + `TSet; + `TMap; + `TBig_map; + `TContract; + `TTicket; + |] + +type comparable_type_name = + [ `TUnit + | `TInt + | `TNat + | `TSignature + | `TString + | `TBytes + | `TMutez + | `TBool + | `TKey_hash + | `TKey + | `TTimestamp + | `TChain_id + | `TAddress + | `TPair + | `TUnion + | `TOption ] + +(* Ensure inclusion of comparable_type_name in type_name *) +let (_ : comparable_type_name -> type_name) = fun x -> (x :> type_name) + +let all_comparable_type_names : comparable_type_name array = + [| + `TUnit; + `TInt; + `TNat; + `TSignature; + `TString; + `TBytes; + `TMutez; + `TBool; + `TKey_hash; + `TKey; + `TTimestamp; + `TChain_id; + `TAddress; + `TPair; + `TUnion; + `TOption; + |] + +type 'a comparable_and_atomic = 'a + constraint 'a = [< comparable_type_name] constraint 'a = [< atomic_type_name] + +let all_comparable_atomic_type_names : 'a comparable_and_atomic array = + [| + `TUnit; + `TInt; + `TNat; + `TSignature; + `TString; + `TBytes; + `TMutez; + `TBool; + `TKey_hash; + `TKey; + `TTimestamp; + `TChain_id; + `TAddress; + |] + +type 'a comparable_and_non_atomic = 'a + constraint 'a = [< comparable_type_name] + constraint 'a = [< non_atomic_type_name] + +let all_comparable_non_atomic_type_names : 'a comparable_and_non_atomic array = + [|`TPair; `TUnion; `TOption|] + +(* Ensure inclusion of comparable_and_atomic in type_name *) +let (_ : 'a comparable_and_atomic -> type_name) = fun x -> (x :> type_name) + +let type_names_count = Array.length all_type_names + +let atomic_type_names_count = Array.length all_atomic_type_names + +let non_atomic_type_names_count = Array.length all_non_atomic_type_names + +let comparable_type_names_count = Array.length all_comparable_type_names + +let comparable_atomic_type_names_count = + Array.length all_comparable_atomic_type_names + +let comparable_non_atomic_type_names_count = + Array.length all_comparable_non_atomic_type_names + +(* ------------------------------------------------------------------------- *) +(* Uniform type name generators *) + +open Sampling_helpers + +let uniform : 'a array -> 'a sampler = + fun arr rng_state -> + let i = Random.State.int rng_state (Array.length arr) in + arr.(i) + +let uniform_type_name : type_name sampler = uniform all_type_names + +let uniform_atomic_type_name : atomic_type_name sampler = + uniform all_atomic_type_names + +let uniform_non_atomic_type_name : non_atomic_type_name sampler = + uniform all_non_atomic_type_names + +let uniform_comparable_type_name : comparable_type_name sampler = + uniform all_comparable_type_names + +let uniform_comparable_atomic_type_name : 'a comparable_and_atomic sampler = + uniform all_comparable_atomic_type_names + +let uniform_comparable_non_atomic_type_name : + 'a comparable_and_non_atomic sampler = + uniform all_comparable_non_atomic_type_names + +(* ------------------------------------------------------------------------- *) +(* Existentially packed typed value. *) + +type ex_value = Ex_value : {typ : 'a Script_typed_ir.ty; v : 'a} -> ex_value + +(* ------------------------------------------------------------------------- *) +(* Random generation functor. *) + +let sample_list state ~range ~sampler = + let length = Base_samplers.sample_in_interval state ~range in + let list = List.init length (fun _i -> sampler ()) in + (length, list) + +module type S = sig + val sampling_parameters : Michelson_samplers_parameters.t + + module Crypto_samplers : Crypto_samplers.Finite_key_pool_S + + module Michelson_base : sig + val int : Alpha_context.Script_int.z Alpha_context.Script_int.num sampler + + val nat : Alpha_context.Script_int.n Alpha_context.Script_int.num sampler + + val signature : Tezos_crypto.Signature.t sampler + + val string : Alpha_context.Script_string.t sampler + + val bytes : bytes sampler + + val tez : Alpha_context.Tez.tez sampler + + val timestamp : Alpha_context.Script_timestamp.t sampler + + val bool : bool sampler + end + + module Random_type : sig + val m_type : size:int -> Script_ir_translator.ex_ty sampler + + val m_comparable_type : + size:int -> Script_ir_translator.ex_comparable_ty sampler + end + + module rec Random_value : sig + val value : 'a Script_typed_ir.ty -> 'a sampler + + val comparable : 'a Script_typed_ir.comparable_ty -> 'a sampler + + val stack : ('a, 'b) Script_typed_ir.stack_ty -> ('a * 'b) sampler + end +end + +exception SamplingError of string + +let fail_sampling error = raise (SamplingError error) + +module Make (P : Michelson_samplers_parameters.S) : S = struct + include Michelson_samplers_base.Make_full (P) + + let memo_size = + Alpha_context.Sapling.Memo_size.parse_z Z.zero |> Result.get_ok + + (* [pick_split x] randomly splits the integer [x] into two integers [left] + and [right] such that [1 <= left], [1 <= right], and [left + right = x]. + Expects [x >= 2]. *) + let pick_split : int -> (int * int) sampler = + fun x rng_state -> + if x < 2 then invalid_arg "pick_split" + else + (* x >= 2 *) + let left = 1 + Random.State.int rng_state (x - 1) in + let right = x - left in + assert (left + right = x) ; + (left, right) + + (* Random generation of Michelson types. *) + module Random_type = struct + let type_of_atomic_type_name (at_tn : atomic_type_name) : + Script_ir_translator.ex_ty = + match at_tn with + | `TString -> Ex_ty (string_t ~annot:None) + | `TNat -> Ex_ty (nat_t ~annot:None) + | `TKey -> Ex_ty (key_t ~annot:None) + | `TBytes -> Ex_ty (bytes_t ~annot:None) + | `TBool -> Ex_ty (bool_t ~annot:None) + | `TAddress -> Ex_ty (address_t ~annot:None) + | `TTimestamp -> Ex_ty (timestamp_t ~annot:None) + | `TKey_hash -> Ex_ty (key_hash_t ~annot:None) + | `TMutez -> Ex_ty (mutez_t ~annot:None) + | `TSignature -> Ex_ty (signature_t ~annot:None) + | `TUnit -> Ex_ty (unit_t ~annot:None) + | `TInt -> Ex_ty (int_t ~annot:None) + | `TSapling_state -> Ex_ty (sapling_state_t ~memo_size ~annot:None) + | `TSapling_transaction -> + Ex_ty (sapling_transaction_t ~memo_size ~annot:None) + | `TChain_id -> Ex_ty (chain_id_t ~annot:None) + | `TBls12_381_g1 -> Ex_ty (bls12_381_g1_t ~annot:None) + | `TBls12_381_g2 -> Ex_ty (bls12_381_g2_t ~annot:None) + | `TBls12_381_fr -> Ex_ty (bls12_381_fr_t ~annot:None) + + let comparable_type_of_comparable_atomic_type_name + (cmp_tn : 'a comparable_and_atomic) : + Script_ir_translator.ex_comparable_ty = + match cmp_tn with + | `TString -> Ex_comparable_ty (string_key ~annot:None) + | `TNat -> Ex_comparable_ty (nat_key ~annot:None) + | `TBytes -> Ex_comparable_ty (bytes_key ~annot:None) + | `TBool -> Ex_comparable_ty (bool_key ~annot:None) + | `TAddress -> Ex_comparable_ty (address_key ~annot:None) + | `TTimestamp -> Ex_comparable_ty (timestamp_key ~annot:None) + | `TKey_hash -> Ex_comparable_ty (key_hash_key ~annot:None) + | `TMutez -> Ex_comparable_ty (mutez_key ~annot:None) + | `TInt -> Ex_comparable_ty (int_key ~annot:None) + | `TUnit -> Ex_comparable_ty (unit_key ~annot:None) + | `TSignature -> Ex_comparable_ty (signature_key ~annot:None) + | `TKey -> Ex_comparable_ty (key_key ~annot:None) + | `TChain_id -> Ex_comparable_ty (chain_id_key ~annot:None) + + let rec m_type ~size : Script_ir_translator.ex_ty sampler = + let open Script_ir_translator in + let open M in + if size <= 0 then Stdlib.failwith "m_type: size <= 0" + else if size = 1 then + (* only atomic types can have size 1 *) + let* at_tn = uniform_atomic_type_name in + return (type_of_atomic_type_name at_tn) + else if size = 2 then + bind (uniform [|`TOption; `TList; `TSet; `TTicket; `TContract|]) + @@ function + | `TOption -> ( + let* (Ex_ty t) = m_type ~size:1 in + match option_t (-1) t ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + | `TList -> ( + let* (Ex_ty t) = m_type ~size:1 in + match list_t (-1) t ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + | `TSet -> ( + let* (Ex_comparable_ty t) = m_comparable_type ~size:1 in + match set_t (-1) t ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + | `TTicket -> ( + let* (Ex_comparable_ty contents) = m_comparable_type ~size:1 in + match ticket_t (-1) contents ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + | `TContract -> ( + let* (Ex_ty t) = m_type ~size:1 in + match contract_t (-1) t ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + else + bind (uniform all_non_atomic_type_names) @@ function + | `TPair -> ( + let* (lsize, rsize) = pick_split (size - 1) in + let* (Ex_ty left) = m_type ~size:lsize in + let* (Ex_ty right) = m_type ~size:rsize in + match + pair_t (-1) (left, None, None) (right, None, None) ~annot:None + with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + | `TLambda -> ( + let* (lsize, rsize) = pick_split (size - 1) in + let* (Ex_ty domain) = m_type ~size:lsize in + let* (Ex_ty range) = m_type ~size:rsize in + match lambda_t (-1) domain range ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + | `TUnion -> ( + let* (lsize, rsize) = pick_split (size - 1) in + let* (Ex_ty left) = m_type ~size:lsize in + let* (Ex_ty right) = m_type ~size:rsize in + match union_t (-1) (left, None) (right, None) ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + | `TOption -> ( + let* (Ex_ty t) = m_type ~size:(size - 1) in + match option_t (-1) t ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + | `TMap -> ( + let* (lsize, rsize) = pick_split (size - 1) in + let* (Ex_comparable_ty key) = m_comparable_type ~size:lsize in + let* (Ex_ty elt) = m_type ~size:rsize in + match map_t (-1) key elt ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + | `TSet -> ( + let* (Ex_comparable_ty key_ty) = + m_comparable_type ~size:(size - 1) + in + match set_t (-1) key_ty ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + | `TList -> ( + let* (Ex_ty elt) = m_type ~size:(size - 1) in + match list_t (-1) elt ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + | `TTicket -> ( + let* (Ex_comparable_ty contents) = + m_comparable_type ~size:(size - 1) + in + match ticket_t (-1) contents ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + | `TContract -> ( + let* (Ex_ty t) = m_type ~size:(size - 1) in + match contract_t (-1) t ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_ty res_ty) + | `TBig_map -> + (* Don't know what to do with theses. Redraw. *) + m_type ~size + + and m_comparable_type ~size : Script_ir_translator.ex_comparable_ty sampler + = + let open M in + let open Script_ir_translator in + let atomic_case () = + let* at_tn = uniform_comparable_atomic_type_name in + return (comparable_type_of_comparable_atomic_type_name at_tn) + in + let option_case size = + let size = size - 1 in + let* (Ex_comparable_ty t) = m_comparable_type ~size in + match option_key (-1) t ~annot:None with + | Error _ -> (* what should be done here? *) assert false + | Ok res_ty -> return @@ Ex_comparable_ty res_ty + in + let pair_case size = + let size = size - 1 in + let* size_left = + Base_samplers.sample_in_interval ~range:{min = 1; max = size - 1} + in + let size_right = size - size_left in + let* (Ex_comparable_ty l) = m_comparable_type ~size:size_left in + let* (Ex_comparable_ty r) = m_comparable_type ~size:size_right in + match pair_key (-1) (l, None) (r, None) ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_comparable_ty res_ty + in + let union_case size = + let size = size - 1 in + let* size_left = + Base_samplers.sample_in_interval ~range:{min = 1; max = size - 1} + in + let size_right = size - size_left in + let* (Ex_comparable_ty l) = m_comparable_type ~size:size_left in + let* (Ex_comparable_ty r) = m_comparable_type ~size:size_right in + match union_key (-1) (l, None) (r, None) ~annot:None with + | Error _ -> assert false + | Ok res_ty -> return @@ Ex_comparable_ty res_ty + in + + if size <= 1 then atomic_case () + else if size = 2 then option_case size + else + let* cmp_tn = uniform_comparable_non_atomic_type_name in + match cmp_tn with + | `TPair -> pair_case size + | `TUnion -> union_case size + | `TOption -> option_case size + end + + (* Type-directed generation of random values. *) + module rec Random_value : sig + val value : 'a Script_typed_ir.ty -> 'a sampler + + val comparable : 'a Script_typed_ir.comparable_ty -> 'a sampler + + val stack : ('a, 'b) Script_typed_ir.stack_ty -> ('a * 'b) sampler + end = struct + let address rng_state = + if Michelson_base.bool rng_state then + ( Alpha_context.Contract.implicit_contract + (Crypto_samplers.pkh rng_state), + "default" ) + else + (* For a description of the format, see + tezos-codec describe alpha.contract binary encoding *) + let string = + "\001" ^ Base_samplers.uniform_string ~nbytes:20 rng_state ^ "\000" + in + let contract = + Data_encoding.Binary.of_string_exn + Alpha_context.Contract.encoding + string + in + let ep = Base_samplers.string ~size:{min = 1; max = 31} rng_state in + (contract, ep) + + let chain_id rng_state = + let string = Base_samplers.uniform_string ~nbytes:4 rng_state in + Data_encoding.Binary.of_string_exn Chain_id.encoding string + + let rec value : type a. a Script_typed_ir.ty -> a sampler = + let open Script_typed_ir in + fun typ -> + match typ with + | Never_t _ -> assert false + | Unit_t _ -> M.return () + | Int_t _ -> Michelson_base.int + | Nat_t _ -> Michelson_base.nat + | Signature_t _ -> Michelson_base.signature + | String_t _ -> Michelson_base.string + | Bytes_t _ -> Michelson_base.bytes + | Mutez_t _ -> Michelson_base.tez + | Key_hash_t _ -> Crypto_samplers.pkh + | Key_t _ -> Crypto_samplers.pk + | Timestamp_t _ -> Michelson_base.timestamp + | Bool_t _ -> Michelson_base.bool + | Address_t _ -> address + | Pair_t ((left_t, _, _), (right_t, _, _), _) -> + M.( + let* left_v = value left_t in + let* right_v = value right_t in + return (left_v, right_v)) + | Union_t ((left_t, _), (right_t, _), _) -> + fun rng_state -> + if Michelson_base.bool rng_state then L (value left_t rng_state) + else R (value right_t rng_state) + | Lambda_t (arg_ty, ret_ty, _) -> generate_lambda arg_ty ret_ty + | Option_t (ty, _) -> + fun rng_state -> + if Michelson_base.bool rng_state then None + else Some (value ty rng_state) + | List_t (elt_ty, _) -> generate_list elt_ty + | Set_t (elt_ty, _) -> generate_set elt_ty + | Map_t (key_ty, val_ty, _) -> generate_map key_ty val_ty + | Contract_t (arg_ty, _) -> generate_contract arg_ty + | Operation_t _ -> generate_operation + | Big_map_t (key_ty, val_ty, _) -> generate_big_map key_ty val_ty + | Chain_id_t _ -> chain_id + | Bls12_381_g1_t _ -> generate_bls12_381_g1 + | Bls12_381_g2_t _ -> generate_bls12_381_g2 + | Bls12_381_fr_t _ -> generate_bls12_381_fr + | Ticket_t (contents_ty, _) -> + let ty = comparable_downcast contents_ty in + generate_ticket ty + | Sapling_transaction_t _ -> + fail_sampling + "Michelson_samplers: sapling transactions not handled yet" + | Sapling_state_t _ -> + fail_sampling "Michelson_samplers: sapling state not handled yet" + | Chest_key_t _ -> + fail_sampling "Michelson_samplers: chest key not handled yet" + | Chest_t _ -> fail_sampling "Michelson_samplers: chest not handled yet" + + and generate_lambda : + type arg ret. + arg Script_typed_ir.ty -> + ret Script_typed_ir.ty -> + (arg, ret) Script_typed_ir.lambda sampler = + fun _arg_ty _ret_ty _rng_state -> + fail_sampling "Michelson_samplers: lambda not handled yet" + + and generate_list : + type elt. + elt Script_typed_ir.ty -> elt Script_typed_ir.boxed_list sampler = + fun elt_type rng_state -> + let (length, elements) = + (* TODO: fix interface of list sampler *) + sample_list rng_state ~range:P.parameters.list_size ~sampler:(fun () -> + value elt_type rng_state) + in + Script_typed_ir.{elements; length} + + and generate_set : + type elt. + elt Script_typed_ir.comparable_ty -> elt Script_typed_ir.set sampler = + fun elt_ty rng_state -> + let ety = comparable_downcast elt_ty in + let {Script_typed_ir.elements; length = _} = + generate_list ety rng_state + in + List.fold_left + (fun set x -> Script_set.update x true set) + (Script_set.empty elt_ty) + elements + + and generate_map : + type key elt. + key Script_typed_ir.comparable_ty -> + elt Script_typed_ir.ty -> + (key, elt) Script_typed_ir.map sampler = + fun key_ty elt_ty rng_state -> + let size = + Base_samplers.sample_in_interval rng_state ~range:P.parameters.map_size + in + let kty = comparable_downcast key_ty in + let keys = List.init size (fun _ -> value kty rng_state) in + let elts = List.init size (fun _ -> value elt_ty rng_state) in + List.fold_left2 + (fun map key elt -> Script_map.update key (Some elt) map) + (Script_map.empty key_ty) + keys + elts + + and generate_big_map : + type key elt. + key Script_typed_ir.comparable_ty -> + elt Script_typed_ir.ty -> + (key, elt) Script_typed_ir.big_map sampler = + let open Script_typed_ir in + fun key_ty elt_ty rng_state -> + let open TzPervasives in + let result = + Lwt_main.run + ( Execution_context.make ~rng_state >>=? fun (ctxt, _) -> + let big_map = Script_ir_translator.empty_big_map key_ty elt_ty in + (* Cannot have big maps under big maps *) + option_t (-1) elt_ty ~annot:None |> Environment.wrap_tzresult + >>?= fun opt_elt_ty -> + let map = generate_map key_ty opt_elt_ty rng_state in + Script_map.fold + (fun k v acc -> + acc >>=? fun (bm, ctxt_acc) -> + Script_ir_translator.big_map_update ctxt_acc k v bm) + map + (return (big_map, ctxt)) + >|= Environment.wrap_tzresult + >>=? fun (big_map, _) -> return big_map ) + in + match result with + | Ok x -> x + | Error e -> + Format.eprintf + "%a@." + (Error_monad.TzTrace.pp_print Error_monad.pp) + e ; + fail_sampling "raise_if_error" + + and generate_contract : + type arg. + arg Script_typed_ir.ty -> arg Script_typed_ir.typed_contract sampler = + fun arg_ty -> + let open M in + let* addr = value (address_t ~annot:None) in + return (arg_ty, addr) + + and generate_operation : + (Alpha_context.packed_internal_operation + * Alpha_context.Lazy_storage.diffs option) + sampler = + fun rng_state -> + let transfer = generate_transfer_tokens rng_state in + (transfer, None) + + and generate_transfer_tokens : + Alpha_context.packed_internal_operation sampler = + fun _rng_state -> fail_sampling "generate_transfer_tokens: unimplemented" + + and generate_bls12_381_g1 : Environment.Bls12_381.G1.t sampler = + fun rng_state -> + let b = Bls12_381.G1.(to_bytes (random ~state:rng_state ())) in + match Environment.Bls12_381.G1.of_bytes_opt b with + | Some x -> x + | None -> assert false + + and generate_bls12_381_g2 : Environment.Bls12_381.G2.t sampler = + fun rng_state -> + let b = Bls12_381.G2.(to_bytes (random ~state:rng_state ())) in + match Environment.Bls12_381.G2.of_bytes_opt b with + | Some x -> x + | None -> assert false + + and generate_bls12_381_fr : Environment.Bls12_381.Fr.t sampler = + fun rng_state -> + let b = Bls12_381.Fr.(to_bytes (random ~state:rng_state ())) in + match Environment.Bls12_381.Fr.of_bytes_opt b with + | Some x -> x + | None -> assert false + + and generate_ticket : + type a. a Script_typed_ir.ty -> a Script_typed_ir.ticket sampler = + fun ty rng_state -> + let contents = value ty rng_state in + let ticketer = + ( Alpha_context.Contract.implicit_contract + (Crypto_samplers.pkh rng_state), + "default" ) + in + let amount = Michelson_base.nat rng_state in + Script_typed_ir.{ticketer; contents; amount} + + let comparable ty = value (comparable_downcast ty) + + (* Random stack generation. *) + let rec stack : type a b. (a, b) Script_typed_ir.stack_ty -> (a * b) sampler + = + let open M in + let open Script_typed_ir in + fun stack_ty -> + match stack_ty with + | Item_t (ty, tl, _) -> + let* elt = value ty in + let* tl = stack tl in + return ((elt, tl) : a * b) + | Bot_t -> return (EmptyCell, EmptyCell) + end +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/michelson_samplers_base.ml b/src/proto_011_PtHangzH/lib_benchmark/michelson_samplers_base.ml new file mode 100644 index 000000000000..cfa508c590f3 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/michelson_samplers_base.ml @@ -0,0 +1,122 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Sampling_helpers + +(* Samplers for basic Michelson types. *) + +module type Base_S = sig + val int : Alpha_context.Script_int.z Alpha_context.Script_int.num sampler + + val nat : Alpha_context.Script_int.n Alpha_context.Script_int.num sampler + + val signature : Tezos_crypto.Signature.t sampler + + val string : Alpha_context.Script_string.t sampler + + val bytes : bytes sampler + + val tez : Alpha_context.Tez.tez sampler + + val timestamp : Alpha_context.Script_timestamp.t sampler + + val bool : bool sampler +end + +module type Full_S = sig + val sampling_parameters : Michelson_samplers_parameters.t + + module Crypto_samplers : Crypto_samplers.Finite_key_pool_S + + module Michelson_base : Base_S +end + +module Make_base (P : Michelson_samplers_parameters.S) : Base_S = struct + let int rng_state = + let i = Base_samplers.int ~size:P.parameters.int_size rng_state in + Alpha_context.Script_int.of_zint i + + let nat rng_state = + let i = Base_samplers.nat ~size:P.parameters.int_size rng_state in + Alpha_context.Script_int.abs (Alpha_context.Script_int.of_zint i) + + let signature rng_state = + let i = Random.State.int rng_state 4 in + match i with + | 0 -> ( + let open Ed25519 in + let bytes = Base_samplers.uniform_bytes ~nbytes:size rng_state in + match of_bytes_opt bytes with + | None -> assert false + | Some s -> Signature.of_ed25519 s) + | 1 -> ( + let open Secp256k1 in + let bytes = Base_samplers.uniform_bytes ~nbytes:size rng_state in + match of_bytes_opt bytes with + | None -> assert false + | Some s -> Signature.of_secp256k1 s) + | 2 -> ( + let open P256 in + let bytes = Base_samplers.uniform_bytes ~nbytes:size rng_state in + match of_bytes_opt bytes with + | None -> assert false + | Some s -> Signature.of_p256 s) + | _ -> ( + let open Signature in + let bytes = Base_samplers.uniform_bytes ~nbytes:size rng_state in + match of_bytes_opt bytes with None -> assert false | Some s -> s) + + let string rng_state = + let s = + Base_samplers.readable_ascii_string + ~size:P.parameters.string_size + rng_state + in + match Protocol.Alpha_context.Script_string.of_string s with + | Ok s -> s + | Error _ -> assert false + + let bytes = Base_samplers.bytes ~size:P.parameters.bytes_size + + let tez rng_state = + let i = Random.State.int64 rng_state (Int64.of_int max_int) in + match Protocol.Alpha_context.Tez.of_mutez i with + | Some res -> res + | None -> assert false + + let timestamp rng_state = + let i = Base_samplers.int ~size:P.parameters.int_size rng_state in + Protocol.Alpha_context.Script_timestamp.of_zint i + + let bool rng_state = Base_samplers.uniform_bool rng_state +end + +module Make_full (P : Michelson_samplers_parameters.S) : Full_S = struct + let sampling_parameters = P.parameters + + module Crypto_samplers = Crypto_samplers.Make_finite_key_pool (P) + module Michelson_base = Make_base (P) +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/michelson_samplers_parameters.ml b/src/proto_011_PtHangzH/lib_benchmark/michelson_samplers_parameters.ml new file mode 100644 index 000000000000..665e57beee91 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/michelson_samplers_parameters.ml @@ -0,0 +1,96 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* ------------------------------------------------------------------------- *) + +type t = { + int_size : Base_samplers.range; + string_size : Base_samplers.range; + bytes_size : Base_samplers.range; + stack_size : Base_samplers.range; + type_size : Base_samplers.range; + list_size : Base_samplers.range; + set_size : Base_samplers.range; + map_size : Base_samplers.range; +} + +let encoding = + let open Data_encoding in + let range = Base_samplers.range_encoding in + conv + (fun { + int_size; + string_size; + bytes_size; + stack_size; + type_size; + list_size; + set_size; + map_size; + } -> + ( int_size, + string_size, + bytes_size, + stack_size, + type_size, + list_size, + set_size, + map_size )) + (fun ( int_size, + string_size, + bytes_size, + stack_size, + type_size, + list_size, + set_size, + map_size ) -> + { + int_size; + string_size; + bytes_size; + stack_size; + type_size; + list_size; + set_size; + map_size; + }) + (obj8 + (req "int_size" range) + (req "string_size" range) + (req "bytes_size" range) + (req "stack_size" range) + (req "michelson_type_size" range) + (req "list_size" range) + (req "set_size" range) + (req "map_size" range)) + +module type S = sig + val parameters : t + + val size : int + + (* By default, the algo is chosen randomly (uniformly) *) + val algo : [`Algo of Signature.algo | `Default] +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/rules.ml b/src/proto_011_PtHangzH/lib_benchmark/rules.ml new file mode 100644 index 000000000000..ca0e22389f9d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/rules.ml @@ -0,0 +1,968 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Kernel + +type rule_set = {rule_patt : pattern; replacements : guarded_replacement list} + +and guarded_replacement = { + type_constraint : type_constraint; + replacement : replacement list; +} + +and type_constraint = + | No_cnstrnt + | Data_cnstrnt of {cnstrnt : Type.Base.t; fresh : int list} + | Instr_cnstrnt of { + cnstrnt : Inference.transformer; + fresh : var list; + fresh_stack : int list; + } + +and replacement = + | Context_aware of (Mikhailsky.node -> Mikhailsky.node) + | Context_blind of (unit -> Mikhailsky.node) + +and pattern = Pattern of Patt.t | Root + +and var = Plain of int | Cmp of int + +let stack_repr = Inference.Stack_type None + +let base_repr = + Inference.Base_type {repr = None; comparable = Inference.Unconstrained} + +let cmp_repr = + Inference.Base_type {repr = None; comparable = Inference.Comparable} + +let rec add_fresh_stack_variables vars = + let open Inference.M in + match vars with + | [] -> return () + | fresh :: tl -> + uf_lift (Uf.UF.add fresh) >>= fun () -> + set_repr fresh stack_repr >>= fun () -> add_fresh_stack_variables tl + +let rec add_fresh_data_variables vars = + let open Inference.M in + match vars with + | [] -> return () + | fresh :: tl -> + uf_lift (Uf.UF.add fresh) >>= fun () -> + set_repr fresh base_repr >>= fun () -> add_fresh_data_variables tl + +let rec add_fresh_variables vars plain_repr cmp_repr = + let open Inference.M in + match vars with + | [] -> return () + | Plain fresh :: tl -> + uf_lift (Uf.UF.add fresh) >>= fun () -> + set_repr fresh plain_repr >>= fun () -> + add_fresh_variables tl plain_repr cmp_repr + | Cmp fresh :: tl -> + uf_lift (Uf.UF.add fresh) >>= fun () -> + set_repr fresh cmp_repr >>= fun () -> + add_fresh_variables tl plain_repr cmp_repr + +let evaluate_guard_monadic guard path = + let open Inference.M in + match guard with + | No_cnstrnt -> return () + | Data_cnstrnt {cnstrnt = base_type_constraint; fresh} -> ( + add_fresh_data_variables fresh >>= fun () -> + get_data_annot path >>= fun res_opt -> + match res_opt with + | None -> assert false + | Some type_of_expr -> + Inference.unify_base type_of_expr base_type_constraint >>= fun () -> + Inference.instantiate_base type_of_expr >>= fun _ -> return ()) + | Instr_cnstrnt {cnstrnt = {bef = pre; aft = post}; fresh; fresh_stack} -> ( + (* Add base fresh type variables *) + add_fresh_variables fresh base_repr cmp_repr + >>= fun () -> + add_fresh_stack_variables fresh_stack >>= fun () -> + get_instr_annot path >>= fun res_opt -> + match res_opt with + | None -> assert false + | Some {bef; aft} -> + Inference.unify pre bef >>= fun () -> + Inference.unify post aft >>= fun () -> + Inference.instantiate bef >>= fun _bef -> + Inference.instantiate aft >>= fun _aft -> return ()) + +let evaluate_guard typing guard path = + try + let _ = evaluate_guard_monadic guard path typing in + true + with Inference.Ill_typed_script _ -> false + +let filter_matches typing guard matches = + List.filter (evaluate_guard typing guard) matches + +(* Provides a speedup but should better be done in the + rewriting module (so that not only top matches are hash-consed). *) +let matches_with_hash_consing = + let match_table : (int * int, Kernel.Path.t list) Hashtbl.t = + Hashtbl.create 97 + in + fun pattern term -> + match pattern with + | Root -> [Path.root] + | Pattern patt -> ( + let key = (Kernel.Patt.uid patt, Mikhailsky.tag term) in + match Hashtbl.find_opt match_table key with + | None -> + let res = Rewriter.all_matches patt term in + Hashtbl.add match_table key res ; + res + | Some res -> res) + +let matches_without_consing pattern term = + match pattern with + | Root -> [Path.root] + | Pattern patt -> Rewriter.all_matches patt term + +let rewriting (state : State_space.t) (rules : rule_set list) = + List.fold_left + (fun acc rule -> + let matches = matches_without_consing rule.rule_patt state.term in + List.fold_left + (fun acc guarded_replacement -> + let matches = + filter_matches + (Lazy.force state.typing) + guarded_replacement.type_constraint + matches + in + List.fold_left + (fun acc replacement -> + match replacement with + | Context_blind term -> + List.fold_left + (fun acc path -> (path, term ()) :: acc) + acc + matches + | Context_aware f -> + List.fold_left + (fun acc path -> + let term = Rewriter.get_subterm ~term:state.term ~path in + (path, f term) :: acc) + acc + matches) + acc + guarded_replacement.replacement) + acc + rule.replacements) + [] + rules + +module Instruction = struct + (* ----------------------------------------------------------------------- *) + (* Rule: replace instruction by hole. *) + + (* Matches instructions *) + let match_any_instr = + let open Patt in + Pattern + (focus + (prim_pred + (fun prim -> Mikhailsky_prim.kind prim = Mikhailsky_prim.Instr_kind) + list_any)) + + let replace_any_instr_by_hole = + let replace_by_hole = + { + type_constraint = No_cnstrnt; + replacement = [Context_blind (fun () -> Mikhailsky.instr_hole)]; + } + in + {rule_patt = match_any_instr; replacements = [replace_by_hole]} + + (* ----------------------------------------------------------------------- *) + (* Rule: replace instruction hole by instruction satisfying typing + constraints. *) + + (* Matches instruction holes *) + let match_instr_hole = + let open Patt in + Pattern (focus (prim I_Hole list_any)) + + let replacement ?(fresh = []) ?(fresh_stack = []) ~bef ~aft ~replacement () : + guarded_replacement = + { + type_constraint = Instr_cnstrnt {cnstrnt = {bef; aft}; fresh; fresh_stack}; + replacement; + } + + let instructions = + let open Type in + let module M = Mikhailsky in + let module I = Inference in + let alpha = ~-1 in + let beta = ~-2 in + let gamma = ~-3 in + let delta = ~-4 in + [ + replacement + ~fresh_stack:[alpha] + ~bef:(item bytes (stack_var alpha)) + ~aft:(item bytes (stack_var alpha)) + ~replacement: + [ + Context_blind (fun () -> M.Instructions.blake2b); + Context_blind (fun () -> M.Instructions.sha256); + Context_blind (fun () -> M.Instructions.sha512); + ] + (); + replacement + ~fresh_stack:[alpha] + ~bef:(item int (stack_var alpha)) + ~aft:(item bool (stack_var alpha)) + ~replacement:[Context_blind (fun () -> M.Instructions.gt)] + (); + replacement + ~fresh_stack:[alpha] + ~bef:(item int (stack_var alpha)) + ~aft:(item nat (stack_var alpha)) + ~replacement:[Context_blind (fun () -> M.Instructions.abs)] + (); + replacement + ~fresh_stack:[alpha] + ~bef:(item int (item int (stack_var alpha))) + ~aft:(item int (stack_var alpha)) + ~replacement: + [ + Context_blind (fun () -> M.Instructions.add M.int_ty M.int_ty); + Context_blind (fun () -> M.Instructions.mul M.int_ty M.int_ty); + ] + (); + replacement + ~fresh:[Plain alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef:(item (pair (var alpha) (var beta)) (stack_var gamma)) + ~aft:(item (var alpha) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.car)] + (); + replacement + ~fresh:[Plain alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef:(item (pair (var alpha) (var beta)) (stack_var gamma)) + ~aft:(item (var beta) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.cdr)] + (); + replacement + ~fresh:[Cmp alpha] + ~fresh_stack:[gamma] + ~bef:(item (var alpha) (item (var alpha) (stack_var gamma))) + ~aft:(item int (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.compare)] + (); + replacement + ~fresh_stack:[gamma] + ~bef:(item string (item string (stack_var gamma))) + ~aft:(item string (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.concat)] + (); + replacement + ~fresh:[Plain alpha] + ~fresh_stack:[beta; gamma] + ~bef:(item (var alpha) (stack_var beta)) + ~aft:(item (var alpha) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.(dip hole))] + (); + replacement + ~fresh:[Plain alpha] + ~fresh_stack:[beta] + ~bef:(item (var alpha) (stack_var beta)) + ~aft:(stack_var beta) + ~replacement:[Context_blind (fun () -> M.Instructions.drop)] + (); + replacement + ~fresh:[Plain alpha] + ~fresh_stack:[beta] + ~bef:(item (var alpha) (stack_var beta)) + ~aft:(item (var alpha) (item (var alpha) (stack_var beta))) + ~replacement:[Context_blind (fun () -> M.Instructions.dup)] + (); + replacement + ~fresh:[] + ~fresh_stack:[alpha] + ~bef:(stack_var alpha) + ~aft:(item int (stack_var alpha)) + ~replacement: + [ + (* TODO : push random integer? *) + Context_blind + (fun () -> M.Instructions.push M.int_ty (M.Data.integer 100)); + ] + (); + replacement + ~fresh:[Plain alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef:(item (var alpha) (item (var beta) (stack_var gamma))) + ~aft:(item (var beta) (item (var alpha) (stack_var gamma))) + ~replacement:[Context_blind (fun () -> M.Instructions.swap)] + (); + (* control *) + replacement + ~fresh_stack:[alpha] + ~bef:(item bool (stack_var alpha)) + ~aft:(stack_var alpha) + ~replacement:[Context_blind (fun () -> M.Instructions.(loop hole))] + (); + replacement + ~fresh:[Plain alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef:(item (union (var alpha) (var beta)) (stack_var gamma)) + ~aft:(item (var beta) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.(loop_left hole))] + (); + replacement + ~fresh:[Plain alpha] + ~fresh_stack:[beta; gamma] + ~bef:(item (option (var alpha)) (stack_var beta)) + ~aft:(stack_var gamma) + ~replacement: + [Context_blind (fun () -> M.Instructions.(if_none hole hole))] + (); + replacement + ~fresh:[Plain alpha; Plain beta] + ~fresh_stack:[gamma; delta] + ~bef:(item (union (var alpha) (var beta)) (stack_var gamma)) + ~aft:(stack_var delta) + ~replacement: + [Context_blind (fun () -> M.Instructions.(if_left hole hole))] + (); + replacement + ~fresh:[] + ~fresh_stack:[alpha; beta] + ~bef:(item bool (stack_var alpha)) + ~aft:(stack_var beta) + ~replacement:[Context_blind (fun () -> M.Instructions.(if_ hole hole))] + (); + replacement + ~fresh_stack:[alpha; beta] + ~bef:(stack_var alpha) + ~aft:(stack_var beta) + ~replacement: + [ + Context_blind + (fun () -> M.seq [M.Instructions.hole; M.Instructions.hole]); + ] + (); + replacement + ~fresh:[Plain alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef:(item (var alpha) (stack_var gamma)) + ~aft:(item (union (var alpha) (var beta)) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.left)] + (); + replacement + ~fresh:[Plain alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef:(item (var beta) (stack_var gamma)) + ~aft:(item (union (var alpha) (var beta)) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.right)] + (); + replacement + ~fresh:[Plain alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef:(stack_var gamma) + ~aft:(item (lambda (var alpha) (var beta)) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.(lambda [hole]))] + (); + replacement + ~fresh:[Plain alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef:(stack_var gamma) + ~aft:(item (lambda (var alpha) (var beta)) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.(lambda [hole]))] + (); + (* set/map/list*) + replacement + ~fresh:[Cmp alpha] + ~fresh_stack:[gamma] + ~bef: + (item + (var alpha) + (item bool (item (set (var alpha)) (stack_var gamma)))) + ~aft:(item (set (var alpha)) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.update_set)] + (); + replacement + ~fresh:[Cmp alpha] + ~fresh_stack:[gamma] + ~bef:(stack_var gamma) + ~aft:(item (set (var alpha)) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.empty_set)] + (); + replacement + ~fresh:[Cmp alpha] + ~fresh_stack:[gamma] + ~bef:(item (set (var alpha)) (stack_var gamma)) + ~aft:(stack_var gamma) + ~replacement: + [Context_blind (fun () -> M.Instructions.(iter_set [hole]))] + (); + replacement + ~fresh:[Cmp alpha] + ~fresh_stack:[gamma] + ~bef:(item (var alpha) (item (set (var alpha)) (stack_var gamma))) + ~aft:(item bool (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.mem_set)] + (); + replacement + ~fresh:[Cmp alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef: + (item + (var alpha) + (item + (option (var beta)) + (item (map (var alpha) (var beta)) (stack_var gamma)))) + ~aft:(item (map (var alpha) (var beta)) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.update_map)] + (); + replacement + ~fresh:[Cmp alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef:(stack_var gamma) + ~aft:(item (map (var alpha) (var beta)) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.empty_map)] + (); + replacement + ~fresh:[Cmp alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef:(item (map (var alpha) (var beta)) (stack_var gamma)) + ~aft:(stack_var gamma) + ~replacement: + [Context_blind (fun () -> M.Instructions.(iter_map [hole]))] + (); + replacement + ~fresh:[Cmp alpha; Plain beta; Plain delta] + ~fresh_stack:[gamma] + ~bef:(item (map (var alpha) (var beta)) (stack_var gamma)) + ~aft:(item (map (var alpha) (var delta)) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.(map_map [hole]))] + (); + replacement + ~fresh:[Cmp alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef: + (item + (var alpha) + (item (map (var alpha) (var beta)) (stack_var gamma))) + ~aft:(item bool (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.mem_map)] + (); + replacement + ~fresh:[Cmp alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef: + (item + (var alpha) + (item (map (var alpha) (var beta)) (stack_var gamma))) + ~aft:(item (option (var beta)) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.get_map)] + (); + (* lists *) + replacement + ~fresh:[Plain alpha] + ~fresh_stack:[gamma] + ~bef:(stack_var gamma) + ~aft:(item (list (var alpha)) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.nil)] + (); + replacement + ~fresh:[Plain alpha] + ~fresh_stack:[gamma] + ~bef:(item (var alpha) (item (list (var alpha)) (stack_var gamma))) + ~aft:(item (list (var alpha)) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.cons)] + (); + replacement + ~fresh:[Plain alpha] + ~fresh_stack:[gamma] + ~bef:(item (list (var alpha)) (stack_var gamma)) + ~aft:(stack_var gamma) + ~replacement: + [Context_blind (fun () -> M.Instructions.(iter_list [hole]))] + (); + replacement + ~fresh:[Plain alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef:(item (list (var alpha)) (stack_var gamma)) + ~aft:(item (list (var beta)) (stack_var gamma)) + ~replacement: + [Context_blind (fun () -> M.Instructions.(map_list [hole]))] + (); + (* sizes *) + replacement + ~fresh:[Cmp alpha] + ~fresh_stack:[gamma] + ~bef:(item (set (var alpha)) (stack_var gamma)) + ~aft:(item nat (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.size_set)] + (); + replacement + ~fresh:[Cmp alpha; Plain beta] + ~fresh_stack:[gamma] + ~bef:(item (map (var alpha) (var beta)) (stack_var gamma)) + ~aft:(item nat (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.size_map)] + (); + replacement + ~fresh:[Plain alpha] + ~fresh_stack:[gamma] + ~bef:(item (list (var alpha)) (stack_var gamma)) + ~aft:(item nat (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.size_list)] + (); + replacement + ~fresh:[] + ~fresh_stack:[gamma] + ~bef:(item string (stack_var gamma)) + ~aft:(item nat (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.size_string)] + (); + replacement + ~fresh:[] + ~fresh_stack:[gamma] + ~bef:(item bytes (stack_var gamma)) + ~aft:(item nat (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.size_bytes)] + (); + (* pack/unpack *) + replacement + ~fresh:[Plain alpha] + ~fresh_stack:[gamma] + ~bef:(item (var alpha) (stack_var gamma)) + ~aft:(item bytes (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.pack)] + (); + replacement + ~fresh:[Plain alpha] + ~fresh_stack:[gamma] + ~bef:(item bytes (stack_var gamma)) + ~aft:(item (option (var alpha)) (stack_var gamma)) + ~replacement:[Context_blind (fun () -> M.Instructions.unpack)] + (); + ] + + let rules = + [ + replace_any_instr_by_hole; + {rule_patt = match_instr_hole; replacements = instructions}; + ] +end + +module Data_rewrite_leaves (P : Michelson_samplers_base.Full_S) = struct + let hole_patt = + let open Patt in + prim_pred (fun prim -> prim = D_Hole) list_empty + + (* Matches a data hole *) + let match_hole = + let open Patt in + Pattern (focus hole_patt) + + (* Matches an integer literal *) + let match_int = + let open Patt in + Pattern (focus (prim_pred (fun prim -> prim = A_Int) list_any)) + + (* Matches a list literal *) + let match_list = + let open Patt in + Pattern (focus (prim_pred (fun prim -> prim = A_List) list_any)) + + (* Matches a set literal *) + let match_set = + let open Patt in + Pattern (focus (prim_pred (fun prim -> prim = A_Set) list_any)) + + (* Matches a map literal *) + let match_map = + let open Patt in + Pattern (focus (prim_pred (fun prim -> prim = A_Map) list_any)) + + (* Matches a timestamp literal *) + let match_timestamp = + let open Patt in + Pattern (focus (prim_pred (fun prim -> prim = A_Timestamp) list_any)) + + (* Matches a mutez literal *) + let match_mutez = + let open Patt in + Pattern (focus (prim_pred (fun prim -> prim = A_Mutez) list_any)) + + (* Matches a key_hash literal *) + let match_key_hash = + let open Patt in + Pattern (focus (prim_pred (fun prim -> prim = A_Key_hash) list_any)) + + let match_int_mutez_timestamp_key_hash_key_or_none = + let open Patt in + Pattern + (focus + (prim_pred + (function + | A_Int | A_Nat | A_Mutez | A_Timestamp | A_Key_hash | A_Key + | D_None -> + true + | _ -> false) + list_any)) + + (* Matches an empty list, set or map literal *) + let match_empty_list_set_or_map = + let open Patt in + Pattern + (focus + (prim_pred + (function A_List | A_Set | A_Map -> true | _ -> false) + (list_cons (seq list_empty) list_empty))) + + (* Matches a pair containing two holes*) + let match_empty_pair = + let open Patt in + Pattern + (focus + (prim_pred + (fun prim -> prim = D_Pair) + (list_cons hole_patt (list_cons hole_patt list_empty)))) + + (* Match a Some, Left or Right containing a hole *) + let match_empty_some_left_or_right = + let open Patt in + Pattern + (focus + (prim_pred + (function D_Left | D_Right | D_Some -> true | _ -> false) + (list_cons hole_patt list_empty))) + + (* Match a None constructor *) + let match_none = + let open Patt in + Pattern (focus (prim_pred (fun prim -> prim = D_None) list_empty)) + + (* rules *) + + (* fresh type variables *) + let (alpha, beta) = (-1, -2) + + let replacement ~fresh ~typ ~replacement = + { + type_constraint = Data_cnstrnt {cnstrnt = typ; fresh}; + replacement = [Context_blind (fun () -> replacement)]; + } + + let replacement_gen ~fresh ~typ ~replacement = + { + type_constraint = Data_cnstrnt {cnstrnt = typ; fresh}; + replacement = [Context_blind replacement]; + } + + let fill_in_hole rng_state = + let replace_by_singleton_list = + replacement + ~fresh:[alpha] + ~typ:Type.(list (var alpha)) + ~replacement:Mikhailsky.Data.(list [hole]) + in + let replace_by_empty_pair = + replacement + ~fresh:[alpha; beta] + ~typ:Type.(pair (var alpha) (var beta)) + ~replacement:Mikhailsky.Data.(pair hole hole) + in + let replace_by_singleton_set = + replacement + ~fresh:[alpha] + ~typ:Type.(set (var alpha)) + ~replacement:Mikhailsky.Data.(set [hole]) + in + let replace_by_singleton_map = + replacement + ~fresh:[alpha; beta] + ~typ:Type.(map (var alpha) (var beta)) + ~replacement:Mikhailsky.Data.(map [map_elt hole hole]) + in + let replace_by_random_int rng_state = + let type_constraint = Data_cnstrnt {cnstrnt = Type.int; fresh = []} in + let replacement = + Context_blind + (fun () -> + Mikhailsky.Data.big_integer + (Base_samplers.int ~size:P.sampling_parameters.int_size rng_state)) + in + {type_constraint; replacement = [replacement]} + in + let replace_by_left = + replacement + ~fresh:[alpha; beta] + ~typ:Type.(union (var alpha) (var beta)) + ~replacement:Mikhailsky.Data.(left hole) + in + let replace_by_right = + replacement + ~fresh:[alpha; beta] + ~typ:Type.(union (var alpha) (var beta)) + ~replacement:Mikhailsky.Data.(right hole) + in + let replace_by_some = + replacement + ~fresh:[alpha] + ~typ:Type.(option (var alpha)) + ~replacement:Mikhailsky.Data.(some hole) + in + let replace_by_none = + replacement + ~fresh:[alpha] + ~typ:Type.(option (var alpha)) + ~replacement:Mikhailsky.Data.none + in + let replace_by_mutez rng_state = + replacement_gen ~fresh:[] ~typ:Type.mutez ~replacement:(fun () -> + Mikhailsky.Data.mutez (P.Michelson_base.tez rng_state)) + in + let replace_by_key_hash rng_state = + replacement_gen ~fresh:[] ~typ:Type.key_hash ~replacement:(fun () -> + Mikhailsky.Data.key_hash (P.Crypto_samplers.pkh rng_state)) + in + let replace_by_key rng_state = + replacement_gen ~fresh:[] ~typ:Type.key ~replacement:(fun () -> + Mikhailsky.Data.key (P.Crypto_samplers.pk rng_state)) + in + { + rule_patt = match_hole; + replacements = + [ + replace_by_singleton_list; + replace_by_empty_pair; + replace_by_singleton_set; + replace_by_singleton_map; + replace_by_random_int rng_state; + replace_by_left; + replace_by_right; + replace_by_some; + replace_by_none; + replace_by_mutez rng_state; + replace_by_key_hash rng_state; + replace_by_key rng_state; + ]; + } + + let kill_empty_pair = + { + rule_patt = match_empty_pair; + replacements = + [ + { + type_constraint = No_cnstrnt; + replacement = [Context_blind (fun () -> Mikhailsky.Data.hole)]; + }; + ]; + } + + let kill_int_mutez_timestamp_key_hash_none = + { + rule_patt = match_int_mutez_timestamp_key_hash_key_or_none; + replacements = + [ + { + type_constraint = No_cnstrnt; + replacement = [Context_blind (fun () -> Mikhailsky.Data.hole)]; + }; + ]; + } + + let kill_empty_list_set_or_map = + { + rule_patt = match_empty_list_set_or_map; + replacements = + [ + { + type_constraint = No_cnstrnt; + replacement = [Context_blind (fun () -> Mikhailsky.Data.hole)]; + }; + ]; + } + + let kill_empty_some_left_or_right = + { + rule_patt = match_empty_some_left_or_right; + replacements = + [ + { + type_constraint = No_cnstrnt; + replacement = [Context_blind (fun () -> Mikhailsky.Data.hole)]; + }; + ]; + } + + let modify_set = + let grow_ungrow_set = + { + type_constraint = No_cnstrnt; + replacement = + [ + Context_aware + (fun set -> + match set with + | Micheline.Prim (_, A_Set, [Micheline.Seq (_, elements)], _) -> + Mikhailsky.Data.(set (hole :: elements)) + | _ -> assert false); + Context_aware + (fun set -> + match set with + | Micheline.Prim (_, A_Set, [Micheline.Seq (_, elements)], _) + -> ( + match elements with + | [] -> Mikhailsky.Data.hole + | _ :: tl -> Mikhailsky.Data.set tl) + | _ -> assert false); + ]; + } + in + {rule_patt = match_set; replacements = [grow_ungrow_set]} + + let modify_map = + let grow_ungrow_map = + { + type_constraint = No_cnstrnt; + replacement = + [ + Context_aware + (fun set -> + match set with + | Micheline.Prim (_, A_Map, [Micheline.Seq (_, elements)], _) -> + Mikhailsky.Data.(map (map_elt hole hole :: elements)) + | _ -> assert false); + Context_aware + (fun set -> + match set with + | Micheline.Prim (_, A_Map, [Micheline.Seq (_, elements)], _) + -> ( + match elements with + | [] -> Mikhailsky.Data.hole + | _ :: tl -> Mikhailsky.Data.map tl) + | _ -> assert false); + ]; + } + in + {rule_patt = match_map; replacements = [grow_ungrow_map]} + + let modify_list = + let grow_ungrow_list = + { + type_constraint = No_cnstrnt; + replacement = + [ + Context_aware + (fun list -> + match list with + | Micheline.Prim (_, A_List, [Micheline.Seq (_, terms)], _) -> + Mikhailsky.Data.(list (hole :: terms)) + | _ -> assert false); + Context_aware + (fun list -> + match list with + | Micheline.Prim (_, A_List, [Micheline.Seq (_, terms)], _) -> ( + match terms with + | [] -> Mikhailsky.Data.hole + | _ :: tl -> Mikhailsky.Data.list tl) + | _ -> assert false); + ]; + } + in + {rule_patt = match_list; replacements = [grow_ungrow_list]} + + let rules rng_state = + [ + fill_in_hole rng_state; + kill_empty_pair; + kill_empty_list_set_or_map; + kill_empty_some_left_or_right; + kill_int_mutez_timestamp_key_hash_none; + modify_list; + modify_set; + modify_map; + ] +end + +module Data (P : Michelson_samplers_base.Full_S) = struct + let match_data_node = + let open Patt in + Pattern + (focus + (prim_pred + (function + | Mikhailsky_prim.D_Elt | D_Hole -> false + | D_False | D_Left | D_None | D_Pair | D_Right | D_Some | D_True + | D_Unit | A_Int | A_Nat | A_Set | A_List | A_Map | A_Key_hash + | A_Mutez | A_Timestamp | A_Key -> + true + | _ -> false) + list_any)) + + let match_list = + let open Patt in + Pattern (focus (prim_pred (fun prim -> prim = A_List) list_any)) + + let match_data_hole = + let open Patt in + Pattern (focus (prim_pred (fun prim -> prim = D_Hole) list_any)) + + let replace_by_hole = + let replace_by_hole = + { + type_constraint = No_cnstrnt; + replacement = [Context_blind (fun () -> Mikhailsky.Data.hole)]; + } + in + {rule_patt = match_data_node; replacements = [replace_by_hole]} + + let pack_root = + let replacement = + [ + Context_aware (fun node -> Mikhailsky.Data.list [node]); + Context_aware (fun node -> Mikhailsky.Data.(pair node hole)); + Context_aware (fun node -> Mikhailsky.Data.(pair hole node)); + ] + in + let guarded_replacements = [{type_constraint = No_cnstrnt; replacement}] in + {rule_patt = Root; replacements = guarded_replacements} + + module Data_rewrite_leaves_rules = Data_rewrite_leaves (P) + + let rules rng_state = + [ + Data_rewrite_leaves_rules.fill_in_hole rng_state; + replace_by_hole; + Data_rewrite_leaves_rules.modify_list; + Data_rewrite_leaves_rules.modify_map; + Data_rewrite_leaves_rules.modify_set; + ] +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/sampler.ml b/src/proto_011_PtHangzH/lib_benchmark/sampler.ml new file mode 100644 index 000000000000..c3874893544b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/sampler.ml @@ -0,0 +1,101 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open StaTz + +let print_m (term : Mikhailsky.node) = + Mikhailsky.pp Format.str_formatter term ; + Format.flush_str_formatter () + +module type Sampler_parameters_sig = sig + val initial : State_space.t + + val energy : State_space.t -> float + + val rules : Rules.rule_set list + + val infer : Mikhailsky.node -> Inference.state + + val verbosity : [`Silent | `Progress | `Trace] +end + +module T = Benchmark_utils.Stubs.Time + +(* Generic MCMC michelson sampler (can be used for code and data) *) +module Make (P : Sampler_parameters_sig) = struct + module MH_params : MH.MH_parameters with type t = State_space.t = struct + let uniform (l : State_space.t list) : State_space.t Stats.fin_prb = + match l with + | [] -> assert false + | _ -> + let arr = Array.of_list l in + let emp = Stats.empirical_of_raw_data arr in + Stats.fin_prb_of_empirical (module State_space) emp + + let trace state = + match P.verbosity with + | `Silent | `Progress -> () + | `Trace -> + Format.eprintf "@." ; + Format.eprintf "%a" State_space.pp state ; + Format.eprintf "energy:@." ; + Format.eprintf "%f:@." (P.energy state) + + let unrecoverable_failure err current result = + Format.eprintf "Error when typechecking term:@." ; + Format.eprintf "%a@." Inference.pp_inference_error err ; + Format.eprintf "Original state: @[%a@]@." State_space.pp current ; + Format.eprintf "Erroneous term: %a@." Mikhailsky.pp result ; + Stdlib.failwith "in sampler.ml: unrecoverable failure." + + let rec proposal ({State_space.term; _} as current) = + trace current ; + let rewriting_options = Rules.rewriting current P.rules in + let rewritings = + List.fold_left + (fun rewritings (path, replacement) -> + let result = Kernel.Rewriter.subst ~term ~path ~replacement in + let typing = + Lazy.from_fun (fun () -> + try P.infer result + with Inference.Ill_typed_script err -> + unrecoverable_failure err current result) + in + {State_space.typing; term = result} :: rewritings) + [] + rewriting_options + in + match rewritings with [] -> proposal current | _ -> uniform rewritings + + let log_weight state = -.P.energy state + + include State_space + end + + module Sampler = MH.Make (MH_params) + + let generator ~burn_in = + Sampler.mcmc ~verbosity:P.verbosity ~initial:P.initial ~burn_in +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/sampling_helpers.ml b/src/proto_011_PtHangzH/lib_benchmark/sampling_helpers.ml new file mode 100644 index 000000000000..8b36fc09e0bf --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/sampling_helpers.ml @@ -0,0 +1,41 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* ------------------------------------------------------------------------- *) + +(* TODO: use Statz's def. of sampler once upstreamed. *) +type 'a sampler = Random.State.t -> 'a + +module M = struct + let ( let* ) : 'a sampler -> ('a -> 'b sampler) -> 'b sampler = + fun sampler f rng_state -> + let x = sampler rng_state in + f x rng_state + [@@inline] + + let bind = ( let* ) + + let return x _ = x +end diff --git a/src/proto_011_PtHangzH/lib_benchmark/state_space.ml b/src/proto_011_PtHangzH/lib_benchmark/state_space.ml new file mode 100644 index 000000000000..8da388263593 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/state_space.ml @@ -0,0 +1,71 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* The state of rewriting is a typed term *) +type t = {typing : Inference.state lazy_t; term : Mikhailsky.node} + +let compare (term1 : t) (term2 : t) = + let tag1 = Mikhailsky.tag term1.term in + let tag2 = Mikhailsky.tag term2.term in + if tag1 < tag2 then -1 else if tag1 > tag2 then 1 else 0 + +type node_statistics = { + mutable size : int; + mutable bytes : int; + mutable holes : int; + mutable depth : int; +} + +let pp_statistics fmtr stats = + Format.fprintf + fmtr + "{ size = %d ; bytes = %d ; holes = %d }" + stats.size + stats.bytes + stats.holes + +let rec statistics stats depth (n : Mikhailsky.node) = + stats.size <- stats.size + 1 ; + stats.depth <- max depth stats.depth ; + match n with + | Micheline.Int (_, z) -> stats.bytes <- stats.bytes + (Z.numbits z / 8) + | Micheline.String (_, s) -> stats.bytes <- stats.bytes + String.length s + | Micheline.Bytes (_, b) -> stats.bytes <- stats.bytes + Bytes.length b + | Micheline.Prim (_, Mikhailsky_prim.I_Hole, _, _) + | Micheline.Prim (_, Mikhailsky_prim.D_Hole, _, _) -> + stats.holes <- stats.holes + 1 + | Micheline.Prim (_, _, subterms, _) | Micheline.Seq (_, subterms) -> + List.iter (statistics stats (depth + 1)) subterms + +let statistics {term; _} = + let stats = {size = 0; bytes = 0; holes = 0; depth = 0} in + statistics stats 0 term ; + stats + +let pp fmtr (state : t) = + Format.fprintf fmtr "current term:@." ; + Format.fprintf fmtr "%a@." Mikhailsky.pp state.term ; + Format.fprintf fmtr "stats:@." ; + Format.fprintf fmtr "%a:@." pp_statistics (statistics state) diff --git a/src/proto_011_PtHangzH/lib_benchmark/test/.ocamlformat b/src/proto_011_PtHangzH/lib_benchmark/test/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/test/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_benchmark/test/dune b/src/proto_011_PtHangzH/lib_benchmark/test/dune new file mode 100644 index 000000000000..67baef30b92c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/test/dune @@ -0,0 +1,40 @@ +(executables + (names test_sampling_data test_sampling_code test_autocompletion test_distribution) + (libraries tezos-micheline + tezos-micheline-rewriting + tezos-benchmark-type-inference-011-PtHangzH + tezos-benchmark + tezos-benchmark-011-PtHangzH + tezos-protocol-011-PtHangzH + tezos-011-PtHangzH-test-helpers + tezos-error-monad + alcotest-lwt + staTz) +;; uncomment to enable gprof profiling +;; (ocamlopt_flags (:standard -p -ccopt -no-pie)) + (flags (:standard + -open Tezos_micheline + -open Tezos_protocol_011_PtHangzH + -open Tezos_benchmark_type_inference_011_PtHangzH + -open Tezos_benchmark_011_PtHangzH + -open Tezos_011_PtHangzH_test_helpers))) + +(alias + (name buildtest) + (deps test_sampling_data.exe test_sampling_code.exe)) + +(rule + (alias runtest_micheline_rewriting_data) + (action (run %{exe:test_sampling_data.exe} 1234))) + +(rule + (alias runtest_micheline_rewriting_code) + (action (run %{exe:test_sampling_code.exe} 1234))) + + +(alias + (name runtest) + (package tezos-benchmark-011-PtHangzH) + (deps (alias runtest_micheline_rewriting_data) + (alias runtest_micheline_rewriting_code) + )) diff --git a/src/proto_011_PtHangzH/lib_benchmark/test/test_autocompletion.ml b/src/proto_011_PtHangzH/lib_benchmark/test/test_autocompletion.ml new file mode 100644 index 000000000000..f67ce5ae0559 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/test/test_autocompletion.ml @@ -0,0 +1,123 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let rng_state = Random.State.make [|42; 987897; 54120|] + +let sampling_parameters = + let open Michelson_samplers_parameters in + let size = {Tezos_benchmark.Base_samplers.min = 4; max = 32} in + { + int_size = size; + string_size = size; + bytes_size = size; + stack_size = size; + type_size = size; + list_size = size; + set_size = size; + map_size = size; + } + +module Full = Michelson_samplers_base.Make_full (struct + let parameters = sampling_parameters + + let algo = `Default + + let size = 16 +end) + +module Autocomp = Autocomp.Make (Full) + +let () = Format.eprintf "===============================@.%!" + +let () = Format.eprintf "Testing dummy program generator@.%!" + +let run x = x rng_state (Inference.M.empty ()) + +let invent_term bef aft = + let (term, _state) = run (Autocomp.invent_term bef aft) in + Mikhailsky.seq term + +let invent_term bef aft = + Format.eprintf + "requested type: %a => %a@." + Type.Stack.pp + bef + Type.Stack.pp + aft ; + let term = invent_term bef aft in + let (bef', aft') = Inference.infer term in + Format.eprintf + "generated type: %a => %a@." + Type.Stack.pp + bef' + Type.Stack.pp + aft' ; + Format.eprintf "%a@." Mikhailsky.pp term + +module T = Type + +let bef = T.(item unit (item unit (item unit empty))) + +let aft = T.(item int (item unit (item (pair nat nat) empty))) + +let () = invent_term bef aft + +let () = Format.eprintf "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@.%!" + +let () = invent_term bef aft + +let () = Format.eprintf "===============================@.%!" + +let () = Format.eprintf "Testing completion@.%!" + +let complete term = + Format.eprintf "term: %a@." Mikhailsky.pp term ; + let ((bef, aft), state) = Inference.infer_with_state term in + Format.eprintf "Inferred type: %a => %a@." Type.Stack.pp bef Type.Stack.pp aft ; + let (term, (bef', aft'), _state) = + Autocomp.complete_code state term rng_state + in + Format.eprintf "completed: %a@." Mikhailsky.pp term ; + Format.eprintf + "Inferred type after generation: %a => %a@." + Type.Stack.pp + bef' + Type.Stack.pp + aft' ; + let node = Micheline.strip_locations @@ Michelson.of_mikhailsky term state in + Test_helpers.typecheck_by_tezos bef' node + +open Mikhailsky +open Instructions + +let push_int = Instructions.push int_ty (Data.big_integer (Z.of_int 100)) + +let add_ii = Instructions.(add Mikhailsky.int_ty Mikhailsky.int_ty) + +let () = complete (lambda [if_left right (dip (seq [push_int; hole]))]) + +let () = Format.eprintf "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@.%!" + +let () = complete (seq [push_int; add_ii; lambda [dip (seq [dup; dip hole])]]) diff --git a/src/proto_011_PtHangzH/lib_benchmark/test/test_distribution.ml b/src/proto_011_PtHangzH/lib_benchmark/test/test_distribution.ml new file mode 100644 index 000000000000..229a72e54c8b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/test/test_distribution.ml @@ -0,0 +1,170 @@ +open StaTz +open Tezos_benchmark +open Michelson_samplers +open Protocol + +module Comparable_type_name = struct + type t = type_name + + let compare (x : t) (y : t) = Stdlib.compare x y +end + +let pp_type_name fmtr (t : type_name) = + Format.pp_print_string fmtr + @@ + match t with + | `TString -> "string" + | `TNat -> "nat" + | `TPair -> "pair" + | `TKey -> "key" + | `TLambda -> "lambda" + | `TUnion -> "union" + | `TOperation -> "operation" + | `TOption -> "option" + | `TSapling_state -> "sapling_state" + | `TBytes -> "bytes" + | `TChain_id -> "chain_id" + | `TBool -> "bool" + | `TBls12_381_g2 -> "bls12_381_g2" + | `TTicket -> "ticket" + | `TMap -> "map" + | `TAddress -> "address" + | `TContract -> "contract" + | `TBls12_381_fr -> "bls12_381_fr" + | `TSapling_transaction -> "sapling_transaction" + | `TTimestamp -> "timestamp" + | `TKey_hash -> "key_hash" + | `TBig_map -> "big_map" + | `TSet -> "set" + | `TBls12_381_g1 -> "bls12_381_g1" + | `TList -> "list" + | `TMutez -> "mutez" + | `TSignature -> "signature" + | `TUnit -> "unit" + | `TInt -> "int" + +let rec tnames_of_type : + type a. a Script_typed_ir.ty -> type_name list -> type_name list = + fun t acc -> + match t with + | Script_typed_ir.Unit_t _ -> `TUnit :: acc + | Script_typed_ir.Int_t _ -> `TInt :: acc + | Script_typed_ir.Nat_t _ -> `TNat :: acc + | Script_typed_ir.Signature_t _ -> `TSignature :: acc + | Script_typed_ir.String_t _ -> `TString :: acc + | Script_typed_ir.Bytes_t _ -> `TBytes :: acc + | Script_typed_ir.Mutez_t _ -> `TMutez :: acc + | Script_typed_ir.Key_hash_t _ -> `TKey_hash :: acc + | Script_typed_ir.Key_t _ -> `TKey :: acc + | Script_typed_ir.Timestamp_t _ -> `TTimestamp :: acc + | Script_typed_ir.Address_t _ -> `TAddress :: acc + | Script_typed_ir.Bool_t _ -> `TBool :: acc + | Script_typed_ir.Pair_t ((lty, _, _), (rty, _, _), _) -> + tnames_of_type lty (tnames_of_type rty (`TPair :: acc)) + | Script_typed_ir.Union_t ((lty, _), (rty, _), _) -> + tnames_of_type lty (tnames_of_type rty (`TUnion :: acc)) + | Script_typed_ir.Lambda_t (dom, range, _) -> + tnames_of_type dom (tnames_of_type range (`TLambda :: acc)) + | Script_typed_ir.Option_t (ty, _) -> tnames_of_type ty (`TOption :: acc) + | Script_typed_ir.List_t (ty, _) -> tnames_of_type ty (`TList :: acc) + | Script_typed_ir.Set_t (ty, _) -> tnames_of_comparable_type ty (`TSet :: acc) + | Script_typed_ir.Map_t (kty, vty, _) -> + tnames_of_comparable_type kty (tnames_of_type vty (`TMap :: acc)) + | Script_typed_ir.Big_map_t (kty, vty, _) -> + tnames_of_comparable_type kty (tnames_of_type vty (`TBig_map :: acc)) + | Script_typed_ir.Contract_t (ty, _) -> tnames_of_type ty (`TContract :: acc) + | Script_typed_ir.Sapling_transaction_t (_, _) -> `TSapling_transaction :: acc + | Script_typed_ir.Sapling_state_t (_, _) -> `TSapling_state :: acc + | Script_typed_ir.Operation_t _ -> `TOperation :: acc + | Script_typed_ir.Chain_id_t _ -> `TChain_id :: acc + | Script_typed_ir.Never_t _ -> assert false + | Script_typed_ir.Bls12_381_g1_t _ -> `TBls12_381_g1 :: acc + | Script_typed_ir.Bls12_381_g2_t _ -> `TBls12_381_g2 :: acc + | Script_typed_ir.Bls12_381_fr_t _ -> `TBls12_381_fr :: acc + | Script_typed_ir.Ticket_t (ty, _) -> + tnames_of_comparable_type ty (`TTicket :: acc) + | Script_typed_ir.Chest_key_t _ -> assert false + | Script_typed_ir.Chest_t _ -> assert false + +and tnames_of_comparable_type : + type a. a Script_typed_ir.comparable_ty -> type_name list -> type_name list + = + fun t acc -> + match t with + | Script_typed_ir.Unit_key _ -> `TUnit :: acc + | Script_typed_ir.Never_key _ -> assert false + | Script_typed_ir.Int_key _ -> `TInt :: acc + | Script_typed_ir.Nat_key _ -> `TNat :: acc + | Script_typed_ir.Signature_key _ -> `TSignature :: acc + | Script_typed_ir.String_key _ -> `TString :: acc + | Script_typed_ir.Bytes_key _ -> `TBytes :: acc + | Script_typed_ir.Mutez_key _ -> `TMutez :: acc + | Script_typed_ir.Bool_key _ -> `TBool :: acc + | Script_typed_ir.Key_hash_key _ -> `TKey_hash :: acc + | Script_typed_ir.Key_key _ -> `TKey :: acc + | Script_typed_ir.Timestamp_key _ -> `TTimestamp :: acc + | Script_typed_ir.Chain_id_key _ -> `TChain_id :: acc + | Script_typed_ir.Address_key _ -> `TAddress :: acc + | Script_typed_ir.Pair_key ((lty, _), (rty, _), _) -> + tnames_of_comparable_type + lty + (tnames_of_comparable_type rty (`TPair :: acc)) + | Script_typed_ir.Union_key ((lty, _), (rty, _), _) -> + tnames_of_comparable_type + lty + (tnames_of_comparable_type rty (`TUnion :: acc)) + | Script_typed_ir.Option_key (ty, _) -> + tnames_of_comparable_type ty (`TOption :: acc) + +module Config = struct + open Michelson_samplers_parameters + + let parameters = + { + int_size = {min = 8; max = 32}; + string_size = {min = 8; max = 128}; + bytes_size = {min = 8; max = 128}; + stack_size = {min = 3; max = 8}; + type_size = {min = 1; max = 15}; + list_size = {min = 0; max = 1000}; + set_size = {min = 0; max = 1000}; + map_size = {min = 0; max = 1000}; + } + + let size = 16 + + let algo = `Default +end + +module Sampler = Michelson_samplers.Make (Config) + +let pp_stats = Stats.pp_fin_fun pp_type_name + +let tnames_dist : type_name list -> type_name Stats.fin_prb = + fun tnames -> + Stats.empirical_of_raw_data (Array.of_list tnames) + |> Stats.fin_prb_of_empirical (module Comparable_type_name) + +let rec sample nsamples acc = + let open Sampling_helpers.M in + if nsamples = 0 then return acc + else + let* size = + Base_samplers.(sample_in_interval ~range:{min = 1; max = 1000}) + in + let* (Ex_ty ty) = Sampler.Random_type.m_type ~size in + let* acc = sample (nsamples - 1) acc in + return (tnames_of_type ty acc) + +let sample nsamples = sample nsamples [] + +let dist nsamples = + let open Sampling_helpers.M in + let* samples = sample nsamples in + return (tnames_dist samples) + +let () = + Format.printf + "stats:@.%a@." + pp_stats + (Obj.magic (dist 500 (Random.State.make [|0x1337; 0x533D|]))) diff --git a/src/proto_011_PtHangzH/lib_benchmark/test/test_helpers.ml b/src/proto_011_PtHangzH/lib_benchmark/test/test_helpers.ml new file mode 100644 index 000000000000..da0a44c81fec --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/test/test_helpers.ml @@ -0,0 +1,123 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Tezos_error_monad.Error_monad + +let rng_state = Random.State.make [|42; 987897; 54120|] + +let base_type_to_michelson_type (typ : Type.Base.t) = + let typ = Mikhailsky.map_var (fun _ -> Mikhailsky.unit_ty) typ in + Mikhailsky.to_michelson typ + +(* Convert a Mikhailsky stack to a list of Micheline-encoded types *) +let rec stack_type_to_michelson_type_list (typ : Type.Stack.t) = + let node = typ.node in + match node with + | Type.Stack.Stack_var_t _ -> + Stdlib.failwith "stack_type_to_michelson_type_list: bug found" + | Type.Stack.Empty_t -> [] + | Type.Stack.Item_t (ty, tl) -> + base_type_to_michelson_type ty :: stack_type_to_michelson_type_list tl + +(* Convert a Micheline-encoded type to its internal GADT format. *) +let michelson_type_to_ex_ty (typ : Protocol.Alpha_context.Script.expr) + (ctxt : Protocol.Alpha_context.t) = + Protocol.Script_ir_translator.parse_ty + ctxt + ~legacy:false + ~allow_lazy_storage:false + ~allow_operation:false + ~allow_contract:false + ~allow_ticket:false + (Micheline.root typ) + |> Protocol.Environment.wrap_tzresult + |> function + | Ok t -> t + | Error errs -> + Format.eprintf "%a@." pp_print_error errs ; + raise (Failure "Test_helpers.michelson_type_to_ex_ty: error") + +let base_type_to_ex_ty ty = + michelson_type_to_ex_ty (base_type_to_michelson_type ty) + +(* Convert a list of Micheline-encoded Michelson types to the + internal GADT format. *) +let rec michelson_type_list_to_ex_stack_ty + (stack_ty : Protocol.Alpha_context.Script.expr list) ctxt = + let open Protocol.Script_ir_translator in + let open Protocol.Script_typed_ir in + match stack_ty with + | [] -> (Ex_stack_ty Bot_t, ctxt) + | hd :: tl -> ( + let (ex_ty, ctxt) = michelson_type_to_ex_ty hd ctxt in + match ex_ty with + | Ex_ty ty -> ( + let (ex_stack_ty, ctxt) = + michelson_type_list_to_ex_stack_ty tl ctxt + in + match ex_stack_ty with + | Ex_stack_ty tl -> (Ex_stack_ty (Item_t (ty, tl, None)), ctxt))) + +let typecheck_by_tezos = + let context_init_memory ~rng_state = + Context.init + ~rng_state + ~initial_balances: + [ + 4_000_000_000_000L; + 4_000_000_000_000L; + 4_000_000_000_000L; + 4_000_000_000_000L; + 4_000_000_000_000L; + ] + 5 + >>=? fun (block, _accounts) -> + Incremental.begin_construction + ~priority:0 + ~timestamp:(Tezos_base.Time.Protocol.add block.header.shell.timestamp 30L) + block + >>=? fun vs -> + let ctxt = Incremental.alpha_ctxt vs in + (* Required for eg Create_contract *) + return + @@ Protocol.Alpha_context.Contract.init_origination_nonce + ctxt + Tezos_crypto.Operation_hash.zero + in + fun bef node -> + Stdlib.Result.get_ok + (Lwt_main.run + ( context_init_memory ~rng_state >>=? fun ctxt -> + let stack = stack_type_to_michelson_type_list bef in + let (bef, ctxt) = michelson_type_list_to_ex_stack_ty stack ctxt in + let (Protocol.Script_ir_translator.Ex_stack_ty bef) = bef in + Protocol.Script_ir_translator.parse_instr + Protocol.Script_ir_translator.Lambda + ctxt + ~legacy:false + (Micheline.root node) + bef + >|= Protocol.Environment.wrap_tzresult + >>=? fun _ -> return_unit )) diff --git a/src/proto_011_PtHangzH/lib_benchmark/test/test_sampling_code.ml b/src/proto_011_PtHangzH/lib_benchmark/test/test_sampling_code.ml new file mode 100644 index 000000000000..2e653d85ba05 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/test/test_sampling_code.ml @@ -0,0 +1,98 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Input parameter parsing *) + +let verbose = + if Array.length Sys.argv < 2 then ( + Format.eprintf "Executable expects random seed on input\n%!" ; + exit 1) + else + (Random.init (int_of_string Sys.argv.(1)) ; + List.exists (( = ) "-v")) + (Array.to_list Sys.argv) + +(* ------------------------------------------------------------------------- *) +(* Base sampler parameters *) + +let sampling_parameters = + let open Michelson_samplers_parameters in + let size = {Tezos_benchmark.Base_samplers.min = 4; max = 32} in + { + int_size = size; + string_size = size; + bytes_size = size; + stack_size = size; + type_size = size; + list_size = size; + set_size = size; + map_size = size; + } + +let state = Random.State.make [|42; 987897; 54120|] + +module Full = Michelson_samplers_base.Make_full (struct + let parameters = sampling_parameters + + let algo = `Default + + let size = 16 +end) + +(* ------------------------------------------------------------------------- *) +(* MCMC instantiation *) + +module Gen = Generators.Code (struct + module Samplers = Full + + let rng_state = state + + let target_size = 500 + + let verbosity = if verbose then `Trace else `Silent +end) + +let start = Unix.gettimeofday () + +let generator = Gen.generator ~burn_in:(500 * 7) + +let stop = Unix.gettimeofday () + +let () = Format.printf "Burn in time: %f seconds@." (stop -. start) + +let _ = + for i = 1 to 1000 do + let (michelson, (bef, aft)) = StaTz.Stats.sample_gen generator in + Test_helpers.typecheck_by_tezos bef michelson ; + let printable = + Micheline_printer.printable + Protocol.Michelson_v1_primitives.string_of_prim + michelson + in + if verbose then ( + Format.eprintf "result %d/1000:@." i ; + Format.eprintf "type: %a => %a@." Type.Stack.pp bef Type.Stack.pp aft ; + Format.eprintf "%a@." Micheline_printer.print_expr printable) + done diff --git a/src/proto_011_PtHangzH/lib_benchmark/test/test_sampling_data.ml b/src/proto_011_PtHangzH/lib_benchmark/test/test_sampling_data.ml new file mode 100644 index 000000000000..43fe373bfc61 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/test/test_sampling_data.ml @@ -0,0 +1,94 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Input parameter parsing *) + +let verbose = + if Array.length Sys.argv < 2 then ( + Format.eprintf "Executable expects random seed on input\n%!" ; + exit 1) + else + (Random.init (int_of_string Sys.argv.(1)) ; + List.exists (( = ) "-v")) + (Array.to_list Sys.argv) + +(* ------------------------------------------------------------------------- *) +(* MCMC instantiation *) + +let sampling_parameters = + let open Michelson_samplers_parameters in + let size = {Tezos_benchmark.Base_samplers.min = 4; max = 32} in + { + int_size = size; + string_size = size; + bytes_size = size; + stack_size = size; + type_size = size; + list_size = size; + set_size = size; + map_size = size; + } + +let state = Random.State.make [|42; 987897; 54120|] + +module Full = Michelson_samplers_base.Make_full (struct + let parameters = sampling_parameters + + let algo = `Default + + let size = 16 +end) + +module Gen = Generators.Data (struct + module Samplers = Full + + let rng_state = state + + let target_size = 500 + + let verbosity = if verbose then `Trace else `Silent +end) + +let start = Unix.gettimeofday () + +let generator = Gen.generator ~burn_in:(200 * 7) + +let stop = Unix.gettimeofday () + +let () = Format.printf "Burn in time: %f seconds@." (stop -. start) + +let _ = + for _i = 0 to 1000 do + let (michelson, typ) = StaTz.Stats.sample_gen generator in + let printable = + Micheline_printer.printable + Protocol.Michelson_v1_primitives.string_of_prim + michelson + in + if verbose then ( + Format.eprintf "result:@." ; + Format.eprintf "type: %a@." Type.Base.pp typ ; + Format.eprintf "%a@." Micheline_printer.print_expr printable) + done diff --git a/src/proto_011_PtHangzH/lib_benchmark/tezos-benchmark-011-PtHangzH.opam b/src/proto_011_PtHangzH/lib_benchmark/tezos-benchmark-011-PtHangzH.opam new file mode 100644 index 000000000000..2e0b9e0eebe5 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmark/tezos-benchmark-011-PtHangzH.opam @@ -0,0 +1,32 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "tezos-tooling" { with-test } + "dune" { >= "2.0" } + "tezos-base" + "tezos-benchmark" + "tezos-protocol-environment" + "tezos-protocol-011-PtHangzH" + "tezos-011-PtHangzH-test-helpers" + "tezos-protocol-011-PtHangzH-parameters" + "tezos-micheline-rewriting" + "tezos-benchmark-type-inference-011-PtHangzH" + "hashcons" + "benchmark-utils" + "tezos-011-PtHangzH-test-helpers" + "staTz" + "tezos-micheline" { with-test } + "tezos-error-monad" { with-test } + "alcotest-lwt" { with-test } + +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: library for writing benchmarks (protocol-specific part)" diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/.ocamlformat b/src/proto_011_PtHangzH/lib_benchmarks_proto/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/cache_benchmarks.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/cache_benchmarks.ml new file mode 100644 index 000000000000..3d96c3976834 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/cache_benchmarks.ml @@ -0,0 +1,195 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(** {2 [Alpha_context.Cache]-related benchmarks} *) + +let assert_ok_lwt x = + match Lwt_main.run x with Ok x -> x | Error _ -> assert false + +let assert_ok = function Ok x -> x | Error _ -> assert false + +module Admin = Alpha_context.Cache.Admin + +(** We can't construct a dummy cache client from outside the protocol. + We'll have to benchmark the {!Environment_cache} through the interface + exposed by {!Script_cache}. *) +module Cache = Script_cache + +(** { 2 Constructing a dummy cached value. } *) + +let make_context ~rng_state = + Execution_context.make ~rng_state |> assert_ok_lwt |> fst + +let throwaway_context = + let rng_state = Random.State.make [|0x1337; 0x533D|] in + make_context ~rng_state + +let dummy_script : Cache.cached_contract = + let str = "{ parameter unit; storage unit; code FAILWITH }" in + let storage = + let (parsed, _) = Michelson_v1_parser.parse_expression "Unit" in + Alpha_context.Script.lazy_expr parsed.expanded + in + let code = + let (parsed, _) = Michelson_v1_parser.parse_expression ~check:false str in + Alpha_context.Script.lazy_expr parsed.expanded + in + let script = Alpha_context.Script.{code; storage} in + let (ex_script, _) = + Script_ir_translator.parse_script + throwaway_context + ~legacy:true + ~allow_forged_in_storage:false + script + |> assert_ok_lwt + in + (script, ex_script) + +(** {2 Creating dummy cache value identifiers.} *) + +(** Configuration shared among all cache benchmarks. *) +module Cache_shared_config = struct + type config = unit + + let config_encoding = Data_encoding.unit + + let default_config = () + + type workload = {cache_cardinal : int} + + let workload_encoding = + let open Data_encoding in + conv + (fun {cache_cardinal} -> cache_cardinal) + (fun cache_cardinal -> {cache_cardinal}) + (obj1 (req "cache_cardinal" int31)) + + let tags = [Tags.cache] + + let workload_to_vector {cache_cardinal} = + Sparse_vec.String.of_list [("cache_cardinal", float_of_int cache_cardinal)] +end + +(* We can't produce a Script_cache.identifier without calling [Script_cache.find]. *) +let identifier_of_contract (c : Alpha_context.Contract.t) : Cache.identifier = + let (_, id, _) = Cache.find throwaway_context c |> assert_ok_lwt in + id + +let contract_of_int i : Alpha_context.Contract.t = + Alpha_context.Contract.of_b58check + Contract_hash.(to_b58check (hash_string [string_of_int i])) + |> assert_ok + +let identifier_of_int i = identifier_of_contract @@ contract_of_int i + +(** Prepare a context with a cache of the prescribed cardinality. A key in the domain of + the cache is returned along the context: this key is used to benchmark + (successful) cache accesses. *) +let prepare_context rng_state cache_cardinal = + assert (cache_cardinal > 0) ; + let ctxt = make_context ~rng_state in + let some_key_in_domain = identifier_of_int 0 in + let rec loop i ctxt = + if Compare.Int.(i = cache_cardinal) then ctxt + else + let key = identifier_of_int i in + loop (i + 1) (Cache.update ctxt key dummy_script 1 |> assert_ok) + in + (loop 0 ctxt, some_key_in_domain) + +(** Benchmark {!Script_cache.update}. This almost directly calls {!Environment_cache.update}. + We also use the result of this benchmark to assign a cost to {!Environment_cache.find}, + which alas can't be directly benchmarked from the interface provided by {!Script_cache}. *) +module Cache_update_benchmark : Benchmark.S = struct + include Cache_shared_config + + let name = "CACHE_UPDATE" + + let info = "Benchmarking the time it takes to update a key in the cache" + + (** It is expected that cache keys are non-adversarial, + ie do not share a long common prefix. This is the case for [Script_cache], + for which the keys are B58-encoded contract hashes. + + To rephrase: with high probability, comparing two keys in the domain of the cache is + a constant-time operation (two keys will differ after the first few characters). + We therefore do not take into account the length of the key in the model. *) + let model = + let affine_logn ~intercept ~coeff = + let open Model in + let module M = struct + type arg_type = int * unit + + module Def (X : Costlang.S) = struct + open X + + type model_type = size -> size + + let arity = arity_1 + + let model = + lam ~name:"size" @@ fun size -> + free ~name:intercept + (free ~name:coeff * log2 (int 1 + size)) + end + end in + (module M : Model_impl with type arg_type = int * unit) + in + (* Looking at the plots, it looks like this benchmark underestimates the constant term. + In the interpreter, this would warrant a dedicated benchmark for the intercept. *) + let intercept_variable = + Free_variable.of_string (Format.asprintf "%s_const" name) + in + let coeff_variable = + Free_variable.of_string (Format.asprintf "%s_coeff" name) + in + Model.make + ~conv:(function {cache_cardinal} -> (cache_cardinal, ())) + ~model:(affine_logn ~intercept:intercept_variable ~coeff:coeff_variable) + + let models = [("cache_model", model)] + + let cache_update_benchmark ctxt some_key_in_domain cache_cardinal = + let workload = {cache_cardinal} in + let closure () = + ignore (Cache.update ctxt some_key_in_domain dummy_script 1) + in + Generator.Plain {workload; closure} + + (** At the time of writing (Protocol H) the worst case execution path for + [Cache.update] is to update a key which is already present. *) + let make_bench rng_state _cfg () = + let cache_cardinal = + Base_samplers.sample_in_interval ~range:{min = 1; max = 100_000} rng_state + in + let (ctxt, some_key_in_domain) = prepare_context rng_state cache_cardinal in + cache_update_benchmark ctxt some_key_in_domain cache_cardinal + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Cache_update_benchmark) diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/dune b/src/proto_011_PtHangzH/lib_benchmarks_proto/dune new file mode 100644 index 000000000000..40e8d663d1d0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/dune @@ -0,0 +1,31 @@ +(library + (name tezos_benchmarks_proto_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-benchmarks-proto-011-PtHangzH) + (libraries + tezos-base + tezos-protocol-011-PtHangzH + tezos-protocol-011-PtHangzH-parameters + tezos-benchmark + tezos-benchmark-011-PtHangzH + tezos-shell-benchmarks + tezos-micheline + tezos-011-PtHangzH-test-helpers + tezos-sapling + tezos-client-011-PtHangzH +) + (library_flags (:standard -linkall)) + (flags (:standard -open Tezos_stdlib + -open Tezos_base + -open Tezos_base__TzPervasives + -open Tezos_error_monad + -open Tezos_benchmark + -open Tezos_benchmark_011_PtHangzH + -open Tezos_benchmark_type_inference_011_PtHangzH + -open Tezos_protocol_011_PtHangzH + -open Tezos_raw_protocol_011_PtHangzH + -open Tezos_client_011_PtHangzH + -open Tezos_crypto + -open Tezos_micheline + -open Tezos_011_PtHangzH_test_helpers + -open Tezos_client_011_PtHangzH))) diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/dune-project b/src/proto_011_PtHangzH/lib_benchmarks_proto/dune-project new file mode 100644 index 000000000000..57161287b4b3 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(name tezos-benchmarks-proto-alpha) +(formatting (enabled_for ocaml)) diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/encodings_benchmarks.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/encodings_benchmarks.ml new file mode 100644 index 000000000000..b18ecee6b3c7 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/encodings_benchmarks.ml @@ -0,0 +1,439 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +module Micheline_common = struct + let make_printable node = + Micheline_printer.printable + Michelson_v1_primitives.string_of_prim + (Micheline.strip_locations node) + + type phase = Trace_production | In_protocol | Global + + type error = + | Bad_micheline of { + benchmark_name : string; + micheline : Alpha_context.Script.node; + phase : phase; + } + + exception Micheline_benchmark of error + + let pp_phase fmtr (phase : phase) = + match phase with + | Trace_production -> Format.fprintf fmtr "trace production" + | In_protocol -> Format.fprintf fmtr "in protocol" + | Global -> Format.fprintf fmtr "global" + + let pp_error fmtr = function + | Bad_micheline {benchmark_name; micheline; phase} -> + Format.open_vbox 1 ; + Format.fprintf fmtr "Bad micheline:@," ; + Format.fprintf fmtr "benchmark = %s@," benchmark_name ; + Format.fprintf + fmtr + "expression = @[%a@]@," + Micheline_printer.print_expr + (make_printable micheline) ; + Format.fprintf fmtr "phase = %a@," pp_phase phase ; + Format.close_box () + + let bad_micheline benchmark_name micheline phase = + raise + (Micheline_benchmark (Bad_micheline {benchmark_name; micheline; phase})) + + type workload = {size : Size.micheline_size; bytes : int} + + let workload_encoding = + let open Data_encoding in + def "encoding_micheline_trace" + @@ conv + (fun {size; bytes} -> (size, bytes)) + (fun (size, bytes) -> {size; bytes}) + (obj2 + (req "micheline_size" Size.micheline_size_encoding) + (req "micheline_bytes" Size.encoding)) + + let workload_to_vector (workload : workload) = + let keys = + [ + ("encoding_micheline_traversal", Size.to_float workload.size.traversal); + ("encoding_micheline_int_bytes", Size.to_float workload.size.int_bytes); + ( "encoding_micheline_string_bytes", + Size.to_float workload.size.string_bytes ); + ("encoding_micheline_bytes", Size.to_float workload.bytes); + ] + in + Sparse_vec.String.of_list keys + + let tags = [Tags.encoding] + + let model_size name = + Model.make + ~conv:(fun {size = {Size.traversal; int_bytes; string_bytes}; _} -> + (traversal, (int_bytes, (string_bytes, ())))) + ~model: + (Model.trilinear + ~coeff1: + (Free_variable.of_string + (Format.asprintf "%s_micheline_traversal" name)) + ~coeff2: + (Free_variable.of_string + (Format.asprintf "%s_micheline_int_bytes" name)) + ~coeff3: + (Free_variable.of_string + (Format.asprintf "%s_micheline_string_bytes" name))) + + let model_bytes name = + Model.make + ~conv:(fun {bytes; _} -> (bytes, ())) + ~model: + (Model.linear + ~coeff: + (Free_variable.of_string + (Format.asprintf "%s_micheline_bytes" name))) + + let models name = + [("micheline", model_size name); ("micheline_bytes", model_bytes name)] +end + +module Encoding_micheline : Benchmark.S = struct + include Translator_benchmarks.Config + include Micheline_common + + let name = "ENCODING_MICHELINE" + + let info = "Benchmarking strip_location + encoding of Micheline to bytes" + + let micheline_serialization_trace (micheline_node : Alpha_context.Script.node) + = + match + Data_encoding.Binary.to_bytes + Protocol.Script_repr.expr_encoding + (Micheline.strip_locations micheline_node) + with + | Error err -> + Format.eprintf + "micheline_serialization_trace: %a@." + Data_encoding.Binary.pp_write_error + err ; + None + | Ok bytes -> + let micheline_size = Size.of_micheline micheline_node in + Some {size = micheline_size; bytes = Size.bytes bytes} + + let encoding_micheline_benchmark (node : Protocol.Script_repr.expr) = + let node = Micheline.root node in + let workload = + match micheline_serialization_trace node with + | None -> Micheline_common.bad_micheline name node Trace_production + | Some trace -> trace + in + let closure () = + try + ignore + (Data_encoding.Binary.to_bytes_exn + Protocol.Script_repr.expr_encoding + (Micheline.strip_locations node)) + with _ -> Micheline_common.bad_micheline name node In_protocol + in + Generator.Plain {workload; closure} + + let make_bench rng_state cfg () = + match + Michelson_generation.make_data_sampler rng_state cfg.generator_config + with + | Data {term; typ = _} -> encoding_micheline_benchmark term + | _ -> assert false + + let create_benchmarks ~rng_state ~bench_num config = + match config.michelson_terms_file with + | Some file -> + Format.eprintf "Loading terms from %s@." file ; + let terms = Michelson_generation.load ~filename:file in + List.map + (function + | Michelson_generation.Data {term; typ = _} + | Michelson_generation.Code {term; bef = _} -> + fun () -> encoding_micheline_benchmark term) + terms + | None -> List.repeat bench_num (make_bench rng_state config) + + let models = models name +end + +let () = Registration_helpers.register (module Encoding_micheline) + +module Decoding_micheline : Benchmark.S = struct + include Translator_benchmarks.Config + include Micheline_common + + let name = "DECODING_MICHELINE" + + let info = "Decoding of bytes to Micheline" + + let micheline_deserialization_trace (micheline_bytes : Bytes.t) = + match + Data_encoding.Binary.of_bytes + Protocol.Script_repr.expr_encoding + micheline_bytes + with + | Error err -> + Format.eprintf + "micheline_deserialization_trace: %a@." + Data_encoding.Binary.pp_read_error + err ; + None + | Ok micheline_node -> + let micheline_size = + Size.of_micheline (Micheline.root micheline_node) + in + Some {size = micheline_size; bytes = Size.bytes micheline_bytes} + + let decoding_micheline_benchmark (node : Protocol.Script_repr.expr) = + let encoded = + Data_encoding.Binary.to_bytes_exn Protocol.Script_repr.expr_encoding node + in + let node = Micheline.root node in + let workload = + match micheline_deserialization_trace encoded with + | None -> bad_micheline name node Trace_production + | Some trace -> trace + in + let closure () = + try + ignore + (Data_encoding.Binary.of_bytes_exn + Protocol.Script_repr.expr_encoding + encoded) + with _ -> bad_micheline name node In_protocol + in + Generator.Plain {workload; closure} + + let make_bench rng_state cfg () = + match + Michelson_generation.make_data_sampler rng_state cfg.generator_config + with + | Data {term; typ = _} -> decoding_micheline_benchmark term + | _ -> assert false + + let create_benchmarks ~rng_state ~bench_num config = + match config.michelson_terms_file with + | Some file -> + Format.eprintf "Loading terms from %s@." file ; + let terms = Michelson_generation.load ~filename:file in + List.map + (function + | Michelson_generation.Data {term; typ = _} + | Michelson_generation.Code {term; bef = _} -> + fun () -> decoding_micheline_benchmark term) + terms + | None -> List.repeat bench_num (make_bench rng_state config) + + let models = models name +end + +let () = Registration_helpers.register (module Decoding_micheline) + +(* TODO: benchmark timestamps with big values (>64 bits) *) +module Timestamp = struct + let () = + Registration_helpers.register + @@ + let open Tezos_shell_benchmarks.Encoding_benchmarks_helpers in + fixed_size_shared + ~name:"TIMESTAMP_READABLE_ENCODING" + ~generator:(fun rng_state -> + let seconds_in_year = 30_000_000 in + let offset = Random.State.int rng_state seconds_in_year in + Alpha_context.Script_timestamp.of_zint (Z.of_int (1597764116 + offset))) + ~make_bench:(fun generator () -> + let tstamp_string = generator () in + let closure () = + ignore (Alpha_context.Script_timestamp.to_string tstamp_string) + in + Generator.Plain {workload = (); closure}) + + let () = + Registration_helpers.register + @@ + let open Tezos_shell_benchmarks.Encoding_benchmarks_helpers in + fixed_size_shared + ~name:"TIMESTAMP_READABLE_DECODING" + ~generator:(fun rng_state -> + let seconds_in_year = 30_000_000 in + let offset = Random.State.int rng_state seconds_in_year in + let tstamp = + Alpha_context.Script_timestamp.of_zint + (Z.of_int (1597764116 + offset)) + in + Alpha_context.Script_timestamp.to_string tstamp) + ~make_bench:(fun generator () -> + let tstamp_string = generator () in + let closure () = + ignore (Alpha_context.Script_timestamp.of_string tstamp_string) + in + Generator.Plain {workload = (); closure}) +end + +module BLS = struct + open Tezos_shell_benchmarks.Encoding_benchmarks_helpers + + let () = + Registration_helpers.register + @@ make_encode_fixed_size_to_bytes + ~name:"ENCODING_BLS_FR" + ~to_bytes:Bls12_381_legacy.Fr.to_bytes + ~generator:(fun rng_state -> + Bls12_381_legacy.Fr.random ~state:rng_state ()) + + let () = + Registration_helpers.register + @@ make_encode_fixed_size_to_bytes + ~name:"ENCODING_BLS_G1" + ~to_bytes:Bls12_381_legacy.G1.Uncompressed.to_bytes + ~generator:(fun rng_state -> + Bls12_381_legacy.G1.Uncompressed.random ~state:rng_state ()) + + let () = + Registration_helpers.register + @@ make_encode_fixed_size_to_bytes + ~name:"ENCODING_BLS_G2" + ~to_bytes:Bls12_381_legacy.G2.Uncompressed.to_bytes + ~generator:(fun rng_state -> + Bls12_381_legacy.G2.Uncompressed.random ~state:rng_state ()) + + let () = + Registration_helpers.register + @@ make_decode_fixed_size_from_bytes + ~name:"DECODING_BLS_FR" + ~to_bytes:Bls12_381_legacy.Fr.to_bytes + ~from_bytes:Bls12_381_legacy.Fr.of_bytes_exn + ~generator:(fun rng_state -> + Bls12_381_legacy.Fr.random ~state:rng_state ()) + + let () = + Registration_helpers.register + @@ make_decode_fixed_size_from_bytes + ~name:"DECODING_BLS_G1" + ~to_bytes:Bls12_381_legacy.G1.Uncompressed.to_bytes + ~from_bytes:Bls12_381_legacy.G1.Uncompressed.of_bytes_exn + ~generator:(fun rng_state -> + Bls12_381_legacy.G1.Uncompressed.random ~state:rng_state ()) + + let () = + Registration_helpers.register + @@ make_decode_fixed_size_from_bytes + ~name:"DECODING_BLS_G2" + ~to_bytes:Bls12_381_legacy.G2.Uncompressed.to_bytes + ~from_bytes:Bls12_381_legacy.G2.Uncompressed.of_bytes_exn + ~generator:(fun rng_state -> + Bls12_381_legacy.G2.Uncompressed.random ~state:rng_state ()) + + let () = + Registration_helpers.register + @@ fixed_size_shared + ~name:"BLS_FR_FROM_Z" + ~generator:(fun rng_state -> + Bls12_381_legacy.Fr.random ~state:rng_state ()) + ~make_bench:(fun generator () -> + let generated = generator () in + let z = Bls12_381_legacy.Fr.to_z generated in + let closure () = ignore (Bls12_381_legacy.Fr.of_z z) in + Generator.Plain {workload = (); closure}) + + let () = + Registration_helpers.register + @@ fixed_size_shared + ~name:"BLS_FR_TO_Z" + ~generator:(fun rng_state -> + Bls12_381_legacy.Fr.random ~state:rng_state ()) + ~make_bench:(fun generator () -> + let generated = generator () in + let closure () = ignore (Bls12_381_legacy.Fr.to_z generated) in + Generator.Plain {workload = (); closure}) +end + +module Timelock = struct + open Tezos_shell_benchmarks.Encoding_benchmarks_helpers + + let generator rng_state = + let log_time = + Base_samplers.sample_in_interval ~range:{min = 0; max = 29} rng_state + in + let time = Random.State.int rng_state (Int.shift_left 1 log_time) in + let plaintext_size = + Base_samplers.sample_in_interval ~range:{min = 1; max = 10000} rng_state + in + let (chest, chest_key) = + Timelock.chest_sampler ~plaintext_size ~time ~rng_state + in + ((chest, chest_key), plaintext_size) + + let () = + Registration_helpers.register + @@ make_encode_variable_size_to_bytes + ~name:"ENCODING_Chest" + ~to_bytes:(Data_encoding.Binary.to_bytes_exn Timelock.chest_encoding) + ~generator:(fun rng_state -> + let ((chest, _), plaintext_size) = generator rng_state in + (chest, {bytes = plaintext_size})) + + let () = + Registration_helpers.register + @@ make_encode_fixed_size_to_bytes + ~name:"ENCODING_Chest_key" + ~to_bytes: + (Data_encoding.Binary.to_bytes_exn Timelock.chest_key_encoding) + ~generator:(fun rng_state -> + let ((_, chest_key), _w) = generator rng_state in + chest_key) + + let () = + Registration_helpers.register + @@ make_decode_variable_size_from_bytes + ~name:"DECODING_Chest" + ~to_bytes:(Data_encoding.Binary.to_bytes_exn Timelock.chest_encoding) + ~from_bytes:(Data_encoding.Binary.of_bytes_exn Timelock.chest_encoding) + ~generator:(fun rng_state -> + let ((chest, _), _) = generator rng_state in + let b = + Data_encoding.Binary.to_bytes_exn Timelock.chest_encoding chest + in + (chest, {bytes = Bytes.length b})) + + let () = + Registration_helpers.register + @@ make_decode_fixed_size_from_bytes + ~name:"DECODING_Chest_key" + ~to_bytes: + (Data_encoding.Binary.to_bytes_exn Timelock.chest_key_encoding) + ~from_bytes: + (Data_encoding.Binary.of_bytes_exn Timelock.chest_key_encoding) + ~generator:(fun rng_state -> + let ((_, chest_key), _w) = generator rng_state in + chest_key) +end diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/gas_helpers.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/gas_helpers.ml new file mode 100644 index 000000000000..bf8bcde60256 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/gas_helpers.ml @@ -0,0 +1,36 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +let set_limit ctxt = + Alpha_context.Gas.set_limit + ctxt + (Alpha_context.Gas.Arith.integral_of_int_exn 999_999_999_999) + +let fp_to_z (fp : Alpha_context.Gas.Arith.fp) = + let open Data_encoding in + Binary.to_bytes_exn Alpha_context.Gas.Arith.z_fp_encoding fp + |> Binary.of_bytes_exn z diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/global_constants_storage_benchmarks.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/global_constants_storage_benchmarks.ml new file mode 100644 index 000000000000..4906dae28183 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/global_constants_storage_benchmarks.ml @@ -0,0 +1,727 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* *) +(* 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 includes benchmarks for [Global_constants_storage.expand] + and [Global_constants_storage.Internal_for_tests.expr_to_address_in_context]. + The other main function exported by [Global_constants_storage] is [register]; + however, [register] calls [expand] and does little else, and thus does + not need to be further carbonated. + + In the process of creating these benchmarks, we benchmarked several OCaml + stdlib functions and [Script_expr_hash.of_b58check_opt]. While these cost + models are not used in the protocol, they are kept here to ensure the + assumptions underlying [register] and [expand] don't change out + from under us.*) + +open Tezos_benchmark +open Tezos_micheline +open Protocol + +let assert_ok_lwt x = + match Lwt_main.run x with + | Ok x -> x + | Error errs -> + Format.eprintf "%a" pp_print_error errs ; + exit 1 + +let assert_ok = function + | Ok x -> x + | Error errs -> + Format.eprintf "%a" pp_print_error errs ; + exit 1 + +(** [seq_of_n_constants n hash] generates a Seq filled + with [n] constant primitives containing [hash] *) +let seq_of_n_constants n hash = + let open Micheline in + Seq + ( -1, + Stdlib.List.init n (fun _ -> + Prim (-1, Michelson_v1_primitives.H_constant, [String (-1, hash)], [])) + ) + +(** Computes the b58check hash of a Micheline node as a string. *) +let node_to_hash node = + let expr_bytes = + Micheline.strip_locations node + |> Script_repr.lazy_expr |> Script_repr.force_bytes |> Stdlib.Result.get_ok + in + Script_expr_hash.hash_bytes [expr_bytes] |> Script_expr_hash.to_b58check + +(* An ad-hoc sampler for Micheline values. Boltzmann sampling would do well + here. + + Copied from lib_micheline and modified to use [Michelson_v1_primitives.prim]. *) +module Micheline_sampler = struct + type node = Alpha_context.Script.node + + let prims = + let open Protocol.Michelson_v1_primitives in + [| + K_parameter; + K_storage; + K_code; + D_False; + D_Elt; + D_Left; + D_None; + D_Pair; + D_Right; + D_Some; + D_True; + D_Unit; + I_PACK; + I_UNPACK; + I_BLAKE2B; + I_SHA256; + I_SHA512; + I_ABS; + I_ADD; + I_AMOUNT; + I_AND; + I_BALANCE; + I_CAR; + I_CDR; + I_CHAIN_ID; + I_CHECK_SIGNATURE; + I_COMPARE; + I_CONCAT; + I_CONS; + I_CREATE_ACCOUNT; + I_CREATE_CONTRACT; + I_IMPLICIT_ACCOUNT; + I_DIP; + I_DROP; + I_DUP; + I_EDIV; + I_EMPTY_BIG_MAP; + I_EMPTY_MAP; + I_EMPTY_SET; + I_EQ; + I_EXEC; + I_APPLY; + I_FAILWITH; + I_GE; + I_GET; + I_GET_AND_UPDATE; + I_GT; + I_HASH_KEY; + I_IF; + I_IF_CONS; + I_IF_LEFT; + I_IF_NONE; + I_INT; + I_LAMBDA; + I_LE; + I_LEFT; + I_LEVEL; + I_LOOP; + I_LSL; + I_LSR; + I_LT; + I_MAP; + I_MEM; + I_MUL; + I_NEG; + I_NEQ; + I_NIL; + I_NONE; + I_NOT; + I_NOW; + I_OR; + I_PAIR; + I_UNPAIR; + I_PUSH; + I_RIGHT; + I_SIZE; + I_SOME; + I_SOURCE; + I_SENDER; + I_SELF; + I_SELF_ADDRESS; + I_SLICE; + I_STEPS_TO_QUOTA; + I_SUB; + I_SWAP; + I_TRANSFER_TOKENS; + I_SET_DELEGATE; + I_UNIT; + I_UPDATE; + I_XOR; + I_ITER; + I_LOOP_LEFT; + I_ADDRESS; + I_CONTRACT; + I_ISNAT; + I_CAST; + I_RENAME; + I_SAPLING_EMPTY_STATE; + I_SAPLING_VERIFY_UPDATE; + I_DIG; + I_DUG; + I_NEVER; + I_VOTING_POWER; + I_TOTAL_VOTING_POWER; + I_KECCAK; + I_SHA3; + I_PAIRING_CHECK; + I_TICKET; + I_READ_TICKET; + I_SPLIT_TICKET; + I_JOIN_TICKETS; + T_bool; + T_contract; + T_int; + T_key; + T_key_hash; + T_lambda; + T_list; + T_map; + T_big_map; + T_nat; + T_option; + T_or; + T_pair; + T_set; + T_signature; + T_string; + T_bytes; + T_mutez; + T_timestamp; + T_unit; + T_operation; + T_address; + T_sapling_transaction; + T_sapling_state; + T_chain_id; + T_never; + T_bls12_381_g1; + T_bls12_381_g2; + T_bls12_381_fr; + T_ticket + (* We don't want constants in our generator, else the constants + functions might fail because it's ill-formed. *) + (* H_constant; *); + |] + + module Sampler = Micheline_sampler.Make (struct + type prim = Michelson_v1_primitives.prim + + let sample_prim : Michelson_v1_primitives.prim Base_samplers.sampler = + fun rng_state -> + let i = Random.State.int rng_state (Array.length prims) in + prims.(i) + + let sample_annots : string list Base_samplers.sampler = fun _rng_state -> [] + + let sample_string _ = "" + + let sample_bytes _ = Bytes.empty + + let sample_z _ = Z.zero + + let width_function = Micheline_sampler.reasonable_width_function + end) + + let sample = Sampler.sample + + type size = {nodes : int; bytes : int} + + let int z = {nodes = 1; bytes = (Z.numbits z + 7) / 8} + + let string s = {nodes = 1; bytes = String.length s} + + let bytes b = {nodes = 1; bytes = Bytes.length b} + + let node = {nodes = 1; bytes = 0} + + let ( @+ ) x y = {nodes = x.nodes + y.nodes; bytes = x.bytes + y.bytes} + + let micheline_size (n : node) = + let rec micheline_size n acc = + let open Micheline in + match n with + | Int (_, i) -> acc @+ int i + | String (_, s) -> acc @+ string s + | Bytes (_, b) -> acc @+ bytes b + | Seq (_, terms) -> + List.fold_left + (fun acc term -> micheline_size term acc) + (acc @+ node) + terms + | Prim (_, _, terms, _) -> + List.fold_left + (fun acc term -> micheline_size term acc) + (acc @+ node) + terms + in + micheline_size n {nodes = 0; bytes = 0} +end + +(** Cost model and benchmarks for set element addition from the + OCaml stdlib. + + The cost model is not currently used + in the protocol, but we include the benchmarks to validate our + assumptions about functions that use this. *) +module Set_add : Benchmark.S = struct + let name = "Set_add" + + let info = + "Benchmarks and cost model for set element addition from OCaml stdlib." + + let tags = ["global_constants"] + + type config = unit + + let config_encoding = Data_encoding.unit + + let default_config = () + + type workload = int + + let workload_encoding = Data_encoding.int31 + + let workload_to_vector : workload -> Sparse_vec.String.t = + fun size -> Sparse_vec.String.of_list [("size", float_of_int size)] + + (* As an OCaml set is a balanced binary tree, complexity is O(log n). *) + let models = + [ + ( "Set_add", + Model.( + make + ~conv:(fun size -> (size, ())) + ~model:(logn ~coeff:(Free_variable.of_string "size"))) ); + ] + + module Int_set = Set.Make (Int) + + let create_benchmark rng_state _config () = + let range : Base_samplers.range = {min = 0; max = 10_000} in + let size = Base_samplers.sample_in_interval ~range rng_state in + let set = Stdlib.List.init size Fun.id |> Int_set.of_list in + let closure () = ignore (Int_set.add (size + 1) set) in + Generator.Plain {workload = size; closure} + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (create_benchmark rng_state config) +end + +let () = + Registration.register (module Set_add) ; + Registration.register_for_codegen + "Set_add" + (Model.For_codegen + (WithExceptions.Option.get ~loc:__LOC__ + @@ List.assoc ~equal:String.equal "Set_add" Set_add.models)) + +(** Cost model and benchmarks for set elements from the + OCaml stdlib. + + The cost model is not currently used + in the protocol, but we include the benchmarks to validate our + assumptions about functions that use this. *) +module Set_elements : Benchmark.S = struct + let name = "Set_elements" + + let info = "Benchmarks and cost model for set elements from OCaml stdlib." + + let tags = ["global_constants"] + + type config = unit + + let config_encoding = Data_encoding.unit + + let default_config = () + + type workload = int + + let workload_encoding = Data_encoding.int31 + + let workload_to_vector : workload -> Sparse_vec.String.t = + fun size -> Sparse_vec.String.of_list [("size", float_of_int size)] + + (* Cost of retrieving all elements from the set is linear with the size + of the set.*) + let models = + [ + ( "Set_elements", + Model.( + make + ~conv:(fun size -> (size, ())) + ~model:(linear ~coeff:(Free_variable.of_string "size"))) ); + ] + + module Int_set = Set.Make (Int) + + let create_benchmark rng_state _config () = + let range : Base_samplers.range = {min = 0; max = 10_000} in + let size = Base_samplers.sample_in_interval ~range rng_state in + let set = Stdlib.List.init size (fun x -> x) |> Int_set.of_list in + let closure () = ignore (Int_set.elements set) in + Generator.Plain {workload = size; closure} + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (create_benchmark rng_state config) +end + +let () = + Registration.register (module Set_elements) ; + Registration.register_for_codegen + "Set_elements" + (Model.For_codegen + (WithExceptions.Option.get ~loc:__LOC__ + @@ List.assoc ~equal:String.equal "Set_elements" Set_elements.models)) + +(** Cost model and benchmarks for [Script_expr_hash.of_b58_check_opt]. + Under the hood this function uses the [Blake2b] functor, which uses + the HACL* crypto library. + + The cost model is not currently used + in the protocol, but we include the benchmarks to validate our + assumptions about functions that use this. *) +module Script_expr_hash_of_b58check_opt : Benchmark.S = struct + let name = "Script_expr_hash_of_b58check_opt" + + let info = "Benchmark for Script_expr_hash.of_b58check_opt" + + let tags = ["global_constants"] + + type config = unit + + let config_encoding = Data_encoding.unit + + let default_config = () + + type workload = Micheline_sampler.size + + let workload_encoding = + let open Data_encoding in + conv + (fun Micheline_sampler.{nodes; bytes} -> (nodes, bytes)) + (fun (nodes, bytes) -> {nodes; bytes}) + (obj2 (req "nodes" int31) (req "bytes" int31)) + + let workload_to_vector Micheline_sampler.{nodes; bytes} = + Sparse_vec.String.of_list + [("nodes", float_of_int nodes); ("bytes", float_of_int bytes)] + + (* On testing we found that this function is a constant + time operation. However, to test this, we use an affine model. If + our assumption holds, the coefficient should be near zero. *) + let models = + [ + ( "Script_expr_hash_of_b58check_opt", + Model.( + make + ~conv:(fun Micheline_sampler.{nodes; _} -> (nodes, ())) + ~model: + (Model.affine + ~intercept:(Free_variable.of_string "b58_check_cost") + ~coeff:(Free_variable.of_string "size"))) ); + ] + + (* To create realistic benchmarks, we generate a random Micheline expression, + hash it, then benchmark the cost of validating the hash. *) + let create_benchmark rng_state _config () = + let open Protocol in + let term = Micheline_sampler.sample rng_state in + let size = Micheline_sampler.micheline_size term in + let expr_encoding = Alpha_context.Script.expr_encoding in + let lazy_expr = + Data_encoding.make_lazy expr_encoding (Micheline.strip_locations term) + in + let expr_bytes = Data_encoding.force_bytes lazy_expr in + let hash = Script_expr_hash.hash_bytes [expr_bytes] in + let hash_str = Script_expr_hash.to_b58check hash in + let closure () = ignore (Script_expr_hash.of_b58check_opt hash_str) in + Generator.Plain {workload = size; closure} + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (create_benchmark rng_state config) +end + +let () = + Registration.register (module Script_expr_hash_of_b58check_opt) ; + Registration.register_for_codegen + "Script_expr_hash_of_b58check_opt" + (Model.For_codegen + (WithExceptions.Option.get ~loc:__LOC__ + @@ List.assoc + ~equal:String.equal + "Script_expr_hash_of_b58check_opt" + Script_expr_hash_of_b58check_opt.models)) + +module Global_constants_storage_expr_to_address_in_context : Benchmark.S = +struct + let name = "Global_constants_storage_expr_to_address_in_context" + + let info = + "Benchmark for the \ + Global_constants_storage.Internal_for_tests.expr_to_address_in_context \ + function" + + let tags = ["global_constants"] + + type config = unit + + let config_encoding = Data_encoding.unit + + let default_config = () + + type workload = int + + let workload_encoding = Data_encoding.int31 + + let workload_to_vector : workload -> Sparse_vec.String.t = + fun size -> Sparse_vec.String.of_list [("size", float_of_int size)] + + (** The cost of a Blake2b hashing function is linear with the size of the input *) + let models = + [ + ( "Global_constants_storage_expr_to_address_in_context", + Model.( + make + ~conv:(fun size -> (size, ())) + ~model:(linear ~coeff:(Free_variable.of_string "size"))) ); + ] + + let create_benchmark rng_state _config () = + let open Micheline in + let expr = Micheline_sampler.sample rng_state |> strip_locations in + let b = + Script_repr.lazy_expr expr |> Script_repr.force_bytes + |> Environment.wrap_tzresult |> assert_ok + in + let size = Bytes.length b in + + let closure () = ignore (Script_expr_hash.hash_bytes [b]) in + Generator.Plain {workload = size; closure} + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (create_benchmark rng_state config) +end + +let () = + Registration.register + (module Global_constants_storage_expr_to_address_in_context) ; + Registration.register_for_codegen + "Global_constants_storage_expr_to_address_in_context" + (Model.For_codegen + (WithExceptions.Option.get ~loc:__LOC__ + @@ List.assoc + ~equal:String.equal + "Global_constants_storage_expr_to_address_in_context" + Global_constants_storage_expr_to_address_in_context.models)) + +(** [Global_constants_storage.expand] traverses a Micheline node, + searching for constants and replacing them with their values + retrieved from storage. + + There are three branches in the iterations of [Global_constants_storage.expand] + can take, each with different costs: + - Branch 1: The first time a particular constant is found, the hash is parsed with + [Script_expr_hash.of_b58check_opt], and its value is retrieved + from storage. This storage call (implemented [Global_constants_storage.get]) + is already carbonated and dominates the cost in this case, so do not need to + benchmark Branch 1 - the benchmarks for storage access are sufficient. + - Branch 2: If the same constant is found a subsequent time, its value is looked up + in a map. On testing we determined that the cost of [Script_expr_hash.of_b58check_opt] + dominates the cost of this branch - the cost of an OCaml map lookup is O(log 2 n), and + n has to be unreasonably large to catch up to the constant time cost of validating the + hash. + - Branch 3: When no constant is found, the cost is merely that of pattern matching + and calling the continuation (similar to that of [Micheline.strip_locations]). + + Because we don't know the full size of node being traversed ahead of time (because they + are retrieved from storage), it is impossible to calculate the full gas cost upfront. + However, each time we find a new expression to traverse, we can calculate its size upfront + and charge the cost of all Branch 3 cases. We can then do an additional charge for Branch 2 + each time we find a constant, and let storage handle charging for Branch 1. + + Below are models for Branch 2 and 3 respectively. + *) +module Global_constants_storage_expand_models = struct + module Global_constants_storage_expand_constant_branch : Benchmark.S = struct + let name = "Global_constants_storage_expand_constant_branch" + + let info = + "Benchmark for the constant branch Global_constants_storage.expand \ + function" + + let tags = ["global_constants"] + + type config = unit + + let config_encoding = Data_encoding.unit + + let default_config = () + + type workload = int + + let workload_encoding = Data_encoding.int31 + + let workload_to_vector : workload -> Sparse_vec.String.t = + fun constants -> + Sparse_vec.String.of_list + [("number of constants", float_of_int constants)] + + (** The cost of Branch 2 is linear to the number of constants in the expression. As + discussed above, the constant time operation [Script_expr_hash.of_b58check_opt] + dominates the cost of each iteration. *) + let models = + [ + ( "Global_constants_storage_expand_constant_branch", + Model.( + make + ~conv:(fun size -> (size, ())) + ~model: + (linear ~coeff:(Free_variable.of_string "number of constants"))) + ); + ] + + (* To test Branch 2 as nearly as possible, we generate a Micheline Seq + consisting of the same constant repeated n times. As n increases, + the benchmark more closely approximates the true cost of Branch 2. *) + let create_benchmark rng_state _config () = + let open Micheline in + let node = Micheline_sampler.sample rng_state in + let size = (Micheline_sampler.micheline_size node).nodes in + let registered_constant = Int (-1, Z.of_int 1) in + let hash = registered_constant |> node_to_hash in + let (context, _) = Execution_context.make ~rng_state |> assert_ok_lwt in + let (context, _, _) = + Alpha_context.Global_constants_storage.register + context + (strip_locations registered_constant) + >|= Environment.wrap_tzresult |> assert_ok_lwt + in + let node = seq_of_n_constants size hash in + let closure () = + ignore + (Lwt_main.run + @@ Alpha_context.Global_constants_storage.expand + context + (strip_locations node)) + in + Generator.Plain {workload = size; closure} + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (create_benchmark rng_state config) + end + + let () = + Registration.register + (module Global_constants_storage_expand_constant_branch) ; + Registration.register_for_codegen + "Global_constants_storage_expand_constant_branch" + (Model.For_codegen + (WithExceptions.Option.get ~loc:__LOC__ + @@ List.assoc + ~equal:String.equal + "Global_constants_storage_expand_constant_branch" + Global_constants_storage_expand_constant_branch.models)) + + module Global_constants_storage_expand_no_constant_branch : Benchmark.S = + struct + let name = "Global_constants_storage_expand_no_constant_branch" + + let info = + "Benchmark for the Global_constants_storage.expand function on the case \ + without constants" + + let tags = ["global_constants"] + + type config = unit + + let config_encoding = Data_encoding.unit + + let default_config = () + + type workload = int + + let workload_encoding = Data_encoding.int31 + + let workload_to_vector : workload -> Sparse_vec.String.t = + fun size -> + Sparse_vec.String.of_list [("number of nodes", float_of_int size)] + + (* The cost of Branch 3 is the cost of traversing a single node. It + is therefore linear to the number of nodes being traversed. This is + very similar to [Micheline.strip_locations]. + + On testing I observed that while the linear model was accurate + for small numbers of nodes, after 1000 nodes the cost seems to increase more + than linearly. I think I would have to fine tune the sampler to better test + past this amount; however, I don't think it's necessary - to get large orders + of nodes, you need to use constants, in which case the cost of + [Script_expr_hash.of_b58check_opt] will dominate. A n*log(n) model seems + accurate enough for the range of values tested. + *) + let models = + [ + ( "Global_constants_storage_expand_no_constant_branch", + Model.( + make + ~conv:(fun size -> (size, ())) + ~model: + (nlogn + ~intercept:(Free_variable.of_string "cst") + ~coeff:(Free_variable.of_string "number of nodes"))) ); + ] + + (** We benchmark this by generating a random Micheline expression without constants + and calling [expand] on it. This causes the function to spend all its time in + Branch 3. *) + let create_benchmark rng_state _config () = + let open Micheline in + let node = Micheline_sampler.sample rng_state in + let size = (Micheline_sampler.micheline_size node).nodes in + let (context, _) = Execution_context.make ~rng_state |> assert_ok_lwt in + let expr = strip_locations node in + let closure () = + ignore + (Lwt_main.run + @@ Alpha_context.Global_constants_storage.expand context expr) + in + Generator.Plain {workload = size; closure} + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (create_benchmark rng_state config) + end + + let () = + Registration.register + (module Global_constants_storage_expand_no_constant_branch) ; + Registration.register_for_codegen + "Global_constants_storage_expand_no_constant_branch" + (Model.For_codegen + (WithExceptions.Option.get ~loc:__LOC__ + @@ List.assoc + ~equal:String.equal + "Global_constants_storage_expand_no_constant_branch" + Global_constants_storage_expand_no_constant_branch.models)) +end diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/interpreter_benchmarks.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/interpreter_benchmarks.ml new file mode 100644 index 000000000000..a97f1daee107 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/interpreter_benchmarks.ml @@ -0,0 +1,3079 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(* ------------------------------------------------------------------------- *) + +type ex_stack_and_kinstr = + | Ex_stack_and_kinstr : { + stack : 'a * 'b; + kinstr : ('a, 'b, 'c, 'd) Script_typed_ir.kinstr; + } + -> ex_stack_and_kinstr + +type ex_stack_and_continuation = + | Ex_stack_and_cont : { + stack : 'a * 'b; + cont : ('a, 'b, 'c, 'd) Script_typed_ir.continuation; + } + -> ex_stack_and_continuation + +type ex_value = + | Ex_value : {value : 'a; ty : 'a Script_typed_ir.ty} -> ex_value + +(* ------------------------------------------------------------------------- *) + +let sf = Printf.sprintf + +(* End of Stack *) +let eos = Script_typed_ir.(EmptyCell, EmptyCell) + +let info_and_name ~intercept ?(salt = "") s = + let s = s ^ salt in + if intercept then (sf "Benchmark %s (intercept case)" s, s ^ "_intercept") + else (sf "Benchmark %s" s, s) + +module Default_boilerplate = struct + type workload = Interpreter_workload.t + + let workload_encoding = Interpreter_workload.encoding + + let workload_to_vector = Interpreter_workload.trace_to_sparse_vec + + let tags = [Tags.interpreter] +end + +module Default_config = struct + (* Configuration specific to sapling benchmarks *) + type sapling_config = {sapling_txs_file : string; seed : int option} + + (* Configuration specific to benchmarking Dign/Dipn/Dupn/Dropn/Combs *) + type comb_config = {max_depth : int} + + type config = { + sampler : Michelson_samplers_parameters.t; + sapling : sapling_config; + comb : comb_config; + } + + let default_config = + let open Michelson_samplers_parameters in + { + sampler = + { + int_size = {min = 8; max = 100_000}; + string_size = {min = 1 lsl 10; max = 1 lsl 17}; + bytes_size = {min = 1 lsl 10; max = 1 lsl 17}; + stack_size = {min = 3; max = 3}; + type_size = {min = 1; max = 15}; + list_size = {min = 10; max = 1000}; + set_size = {min = 10; max = 1000}; + map_size = {min = 10; max = 1000}; + }; + sapling = {sapling_txs_file = {|/no/such/file|}; seed = None}; + comb = {max_depth = 1000}; + } + + let sapling_config_encoding = + let open Data_encoding in + conv + (fun {sapling_txs_file; seed} -> (sapling_txs_file, seed)) + (fun (sapling_txs_file, seed) -> {sapling_txs_file; seed}) + (obj2 (req "sapling_txs_file" string) (req "seed" (option int31))) + + let comb_config_encoding = + let open Data_encoding in + conv + (fun {max_depth} -> max_depth) + (fun max_depth -> {max_depth}) + (obj1 (req "max_depth" int31)) + + let config_encoding = + let open Data_encoding in + conv + (fun {sampler; sapling; comb} -> (sampler, sapling, comb)) + (fun (sampler, sapling, comb) -> {sampler; sapling; comb}) + (obj3 + (req "sampler" Michelson_samplers_parameters.encoding) + (req "sapling" sapling_config_encoding) + (req "comb" comb_config_encoding)) +end + +let make_default_samplers ?(algo = `Default) cfg : (module Michelson_samplers.S) + = + let module Samplers = Michelson_samplers.Make (struct + let size = 16 + + let algo = algo + + let parameters = cfg + end) in + (module Samplers) + +(* ------------------------------------------------------------------------- *) +(* Helpers for creating benchmarks for the interpreter *) + +let benchmark_from_kinstr_and_stack : + ?amplification:int -> + Alpha_context.context -> + Protocol.Script_interpreter.step_constants -> + ex_stack_and_kinstr -> + Interpreter_workload.ir_sized_step list Generator.benchmark = + fun ?amplification ctxt step_constants stack_kinstr -> + let ctxt = Gas_helpers.set_limit ctxt in + match stack_kinstr with + | Ex_stack_and_kinstr {stack = (bef_top, bef); kinstr} -> + let (workload, closure) = + match amplification with + | None -> + let workload = + Interpreter_workload.extract_deps + ctxt + step_constants + kinstr + (bef_top, bef) + in + let outdated_ctxt = + Script_interpreter.Internals.OutDatedContext ctxt + in + let closure () = + ignore + (* Lwt_main.run *) + (Script_interpreter.Internals.step + (outdated_ctxt, step_constants) + 9_999_999_999 + kinstr + bef_top + bef) + in + (workload, closure) + | Some amplification_factor -> + assert (amplification_factor > 0) ; + let workload = + Interpreter_workload.extract_deps + ctxt + step_constants + kinstr + (bef_top, bef) + in + let workload = + List.repeat amplification_factor workload |> List.flatten + in + let outdated_ctxt = + Script_interpreter.Internals.OutDatedContext ctxt + in + let closure () = + for _i = 1 to amplification_factor do + ignore + (* Lwt_main.run *) + (Script_interpreter.Internals.step + (outdated_ctxt, step_constants) + 9_999_999_999 + kinstr + bef_top + bef) + done + in + (workload, closure) + in + Generator.Plain {workload; closure} + +let make_benchmark : + ?amplification:int -> + ?intercept:bool -> + ?salt:string -> + ?more_tags:string list -> + name:Interpreter_workload.instruction_name -> + kinstr_and_stack_sampler: + (Default_config.config -> Random.State.t -> unit -> ex_stack_and_kinstr) -> + unit -> + Benchmark.t = + fun ?amplification + ?(intercept = false) + ?salt + ?(more_tags = []) + ~name + ~kinstr_and_stack_sampler + () -> + let module B : Benchmark.S = struct + include Default_config + include Default_boilerplate + + let tags = tags @ more_tags + + let models = + (* [intercept = true] implies there's a benchmark with [intercept = false]. + No need to register the model twice. *) + Interpreter_model.make_model + ?amplification + (if intercept then None else Some (Instr_name name)) + + let (info, name) = + info_and_name + ~intercept + ?salt + (Interpreter_workload.string_of_instruction_name name) + + let benchmark kinstr_and_stack_sampler ctxt step_constants () = + let stack_instr = kinstr_and_stack_sampler () in + benchmark_from_kinstr_and_stack + ?amplification + ctxt + step_constants + stack_instr + + let create_benchmarks ~rng_state ~bench_num (config : config) = + match Lwt_main.run (Execution_context.make ~rng_state) with + | Error _errs -> assert false + | Ok (ctxt, step_constants) -> + let kinstr_and_stack_sampler = + kinstr_and_stack_sampler config rng_state + in + List.repeat + bench_num + (benchmark kinstr_and_stack_sampler ctxt step_constants) + end in + (module B : Benchmark.S) + +let make_simple_benchmark : + type bef_top bef res_top res. + ?amplification:int -> + ?intercept:bool -> + ?more_tags:string list -> + name:Interpreter_workload.instruction_name -> + kinstr:(bef_top, bef, res_top, res) Script_typed_ir.kinstr -> + unit -> + Benchmark.t = + fun ?amplification ?intercept ?more_tags ~name ~kinstr () -> + let kinfo = Script_typed_ir.kinfo_of_kinstr kinstr in + let stack_ty = kinfo.kstack_ty in + let kinstr_and_stack_sampler config rng_state = + let (module Samplers) = + make_default_samplers config.Default_config.sampler + in + fun () -> + Ex_stack_and_kinstr + {stack = Samplers.Random_value.stack stack_ty rng_state; kinstr} + in + make_benchmark + ?amplification + ?intercept + ?more_tags + ~name + ~kinstr_and_stack_sampler + () + +let benchmark ?amplification ?intercept ?more_tags ~name + ~kinstr_and_stack_sampler () = + let bench = + make_benchmark + ?amplification + ?intercept + ?more_tags + ~name + ~kinstr_and_stack_sampler + () + in + Registration_helpers.register bench + +let benchmark_with_stack_sampler ?amplification ?intercept ?more_tags ~name + ~kinstr ~stack_sampler () = + let kinstr_and_stack_sampler config rng_state = + let stack_sampler = stack_sampler config rng_state in + fun () -> Ex_stack_and_kinstr {stack = stack_sampler (); kinstr} + in + let bench = + make_benchmark + ?amplification + ?intercept + ?more_tags + ~name + ~kinstr_and_stack_sampler + () + in + Registration_helpers.register bench + +let benchmark_with_fixed_stack ?amplification ?intercept ?more_tags ~name ~stack + ~kinstr () = + benchmark_with_stack_sampler + ?amplification + ?intercept + ?more_tags + ~name + ~kinstr + ~stack_sampler:(fun _cfg _rng_state () -> stack) + () + +let simple_benchmark_with_stack_sampler ?amplification ?intercept_stack + ?more_tags ~name ~kinstr ~stack_sampler () = + benchmark_with_stack_sampler + ?amplification + ~intercept:false + ?more_tags + ~name + ~kinstr + ~stack_sampler + () ; + Option.iter + (fun stack -> + benchmark_with_fixed_stack + ?amplification + ~intercept:true + ?more_tags + ~name + ~stack + ~kinstr + ()) + intercept_stack + +let simple_benchmark ?amplification ?intercept_stack ?more_tags ~name ~kinstr () + = + let bench = + make_simple_benchmark + ?amplification + ~intercept:false + ?more_tags + ~name + ~kinstr + () + in + Registration_helpers.register bench ; + Option.iter + (fun stack -> + benchmark_with_fixed_stack + ?amplification + ~intercept:true + ?more_tags + ~name + ~stack + ~kinstr + ()) + intercept_stack + +(* ------------------------------------------------------------------------- *) +(* Helpers for creating benchmarks for [Script_interpreter.next] *) + +let benchmark_from_continuation : + ?amplification:int -> + Alpha_context.context -> + Protocol.Script_interpreter.step_constants -> + ex_stack_and_continuation -> + Interpreter_workload.ir_sized_step list Generator.benchmark = + fun ?amplification ctxt step_constants stack_cont -> + let ctxt = Gas_helpers.set_limit ctxt in + match stack_cont with + | Ex_stack_and_cont {stack = (bef_top, bef); cont} -> + let (workload, closure) = + match amplification with + | None -> + let workload = + Interpreter_workload.extract_deps_continuation + ctxt + step_constants + cont + (bef_top, bef) + in + let outdated_ctxt = + Script_interpreter.Internals.OutDatedContext ctxt + in + let closure () = + ignore + (* Lwt_main.run *) + (Script_interpreter.Internals.next + None + (outdated_ctxt, step_constants) + 9_999_999_999 + cont + bef_top + bef) + in + (workload, closure) + | Some amplification_factor -> + assert (amplification_factor > 0) ; + let workload = + Interpreter_workload.extract_deps_continuation + ctxt + step_constants + cont + (bef_top, bef) + in + let workload = + List.repeat amplification_factor workload |> List.flatten + in + let outdated_ctxt = + Script_interpreter.Internals.OutDatedContext ctxt + in + let closure () = + for _i = 1 to amplification_factor do + ignore + (* Lwt_main.run *) + (Script_interpreter.Internals.next + None + (outdated_ctxt, step_constants) + 9_999_999_999 + cont + bef_top + bef) + done + in + (workload, closure) + in + Generator.Plain {workload; closure} + +let make_continuation_benchmark : + ?amplification:int -> + ?intercept:bool -> + ?salt:string -> + ?more_tags:string list -> + name:Interpreter_workload.continuation_name -> + cont_and_stack_sampler: + (Default_config.config -> + Random.State.t -> + unit -> + ex_stack_and_continuation) -> + unit -> + Benchmark.t = + fun ?amplification + ?(intercept = false) + ?salt + ?(more_tags = []) + ~name + ~cont_and_stack_sampler + () -> + let module B : Benchmark.S = struct + include Default_config + include Default_boilerplate + + let tags = tags @ more_tags + + let models = + Interpreter_model.make_model + ?amplification + (if intercept then None else Some (Cont_name name)) + + let (info, name) = + info_and_name + ~intercept + ?salt + (Interpreter_workload.string_of_continuation_name name) + + let benchmark cont_and_stack_sampler ctxt step_constants () = + let stack_instr = cont_and_stack_sampler () in + benchmark_from_continuation ?amplification ctxt step_constants stack_instr + + let create_benchmarks ~rng_state ~bench_num (config : config) = + match Lwt_main.run (Execution_context.make ~rng_state) with + | Error _errs -> assert false + | Ok (ctxt, step_constants) -> + let cont_and_stack_sampler = + cont_and_stack_sampler config rng_state + in + List.repeat + bench_num + (benchmark cont_and_stack_sampler ctxt step_constants) + end in + (module B : Benchmark.S) + +let continuation_benchmark ?amplification ?intercept ?salt ?more_tags ~name + ~cont_and_stack_sampler () = + let bench = + make_continuation_benchmark + ?amplification + ?intercept + ?salt + ?more_tags + ~name + ~cont_and_stack_sampler + () + in + Registration_helpers.register bench + +(* ------------------------------------------------------------------------- *) +(* Sampling helpers *) + +let nat_of_positive_int (i : int) = + let open Alpha_context.Script_int in + match is_nat (of_int i) with None -> assert false | Some x -> x + +let adversarial_ints rng_state (cfg : Default_config.config) n = + let (_common_prefix, ls) = + Base_samplers.Adversarial.integers + ~prefix_size:cfg.sampler.int_size + ~card:n + rng_state + in + List.map Script_int_repr.of_zint ls + +(* ------------------------------------------------------------------------- *) +(* Error helpers *) + +let raise_if_error = function + | Ok x -> x + | Error e -> + Format.eprintf "%a@." (Error_monad.TzTrace.pp_print Error_monad.pp) e ; + Stdlib.failwith "raise_if_error" + +(* ------------------------------------------------------------------------- *) + +(** [Registration_section] contains all interpreter benchmarks. The goal of + a benchmark is to gather enough data to reliably estimate the parameters + of the cost model associated to each instruction. In general, it can + take several distinct benchmarks to properly cover all the execution + paths. + + In particular, for affine cost model, it is often worth estimating the + intercept separately from the size-dependent coefficients. + *) + +module Registration_section = struct + open Script_typed_ir + open Michelson_types + + let sf = Printf.sprintf + + let kinfo kstack_ty = {iloc = 0; kstack_ty} + + let halt stack_ty = IHalt (kinfo stack_ty) + + let halt_unit = halt (unit @$ bot) + + let halt_unitunit = halt (unit @$ unit @$ bot) + + let kinfo_unit = kinfo (unit @$ bot) + + let kinfo_unitunit = kinfo (unit @$ unit @$ bot) + + let () = + (* KHalt *) + simple_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_IHalt + ~kinstr:halt_unit + () + + module Amplification = struct + module Loop : Benchmark.S = struct + let name = "amplification_loop" + + let info = "Benchmarking the cost of an empty loop" + + let tags = [Tags.interpreter] + + type config = {max_iterations : int} + + let config_encoding = + let open Data_encoding in + conv + (fun {max_iterations} -> max_iterations) + (fun max_iterations -> {max_iterations}) + (obj1 (req "max_iterations" int31)) + + let default_config = {max_iterations = 100000} + + type workload = int + + let workload_encoding = Data_encoding.int31 + + let workload_to_vector n = + Sparse_vec.String.of_list [("iterations", float_of_int n)] + + let models = [("interpreter", Interpreter_model.amplification_loop_model)] + + let benchmark rng_state config () = + let workload = Random.State.int rng_state config.max_iterations in + let closure () = + for _i = 1 to workload do + Sys.opaque_identity () + done + in + Generator.Plain {workload; closure} + + let create_benchmarks ~rng_state ~bench_num (config : config) = + List.repeat bench_num (benchmark rng_state config) + end + end + + let () = Registration_helpers.register (module Amplification.Loop) + + module Stack = struct + let () = + (* KDrop ; KHalt *) + simple_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_IDrop + ~kinstr:(IDrop (kinfo_unitunit, halt_unit)) + () + + let () = + (* IDup ; IHalt *) + simple_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_IDup + ~kinstr:(IDup (kinfo_unit, halt_unitunit)) + () + + let () = + simple_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_ISwap + ~kinstr:(ISwap (kinfo_unitunit, halt_unitunit)) + () + + let () = + simple_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_IConst + ~kinstr:(IConst (kinfo_unit, (), halt_unitunit)) + () + + (* deep stack manipulation *) + + (* Constructing these instructions is made especially painful by the + fact that they include "stack preservation witnesses", which are not + exposed in Script_ir_translator. + We must go through [Script_ir_translator.parse_instr] to construct + the corresponding terms. *) + type ex_stack = + | Ex_stack : ('a, 'b) Script_typed_ir.stack_ty * ('a * 'b) -> ex_stack + + let rec make_stack (depth : int) = + if depth = 0 then assert false + else if depth = 1 then Ex_stack (unit @$ Script_typed_ir.Bot_t, ((), eos)) + else + let stack = make_stack (depth - 1) in + match stack with + | Ex_stack (stack_ty, stack) -> Ex_stack (unit @$ stack_ty, ((), stack)) + + let parse_instr rng_state node stack = + match stack with + | Ex_stack (stack_ty, stack) -> + raise_if_error + (Lwt_main.run + ( Execution_context.make ~rng_state + >>=? fun (ctxt, _step_constants) -> + Script_ir_translator.parse_instr + Script_ir_translator.Lambda + ctxt + ~legacy:false + node + stack_ty + >|= Environment.wrap_tzresult + >>=? fun (judgement, _) -> + match judgement with + | Script_ir_translator.Typed descr -> + let kinfo = {iloc = 0; kstack_ty = descr.bef} in + let kinfo' = {iloc = 0; kstack_ty = descr.aft} in + let kinstr = descr.instr.apply kinfo (IHalt kinfo') in + return (Ex_stack_and_kinstr {stack; kinstr}) + | Script_ir_translator.Failed _ -> assert false )) + + open Protocol.Michelson_v1_primitives + + (* The size parameter of a deep stack instruction must fit on 10 bits. See + [Script_ir_translator.parse_uint10]. *) + let stack_size = 1023 + + let long_stack = make_stack stack_size + + let sample_depth rng_state = + Base_samplers.( + sample_in_interval rng_state ~range:{min = 0; max = stack_size - 2}) + + let () = + let dig = Micheline.(Prim (0, I_DIG, [Int (0, Z.of_int 0)], [])) in + benchmark + ~amplification:100 + ~intercept:true + ~name:Interpreter_workload.N_IDig + ~kinstr_and_stack_sampler:(fun _cfg rng_state () -> + let node = dig in + parse_instr rng_state node long_stack) + () + + let () = + let dig n = Micheline.(Prim (0, I_DIG, [Int (0, Z.of_int n)], [])) in + benchmark + ~name:Interpreter_workload.N_IDig + ~kinstr_and_stack_sampler:(fun _cfg rng_state () -> + let node = dig (sample_depth rng_state) in + parse_instr rng_state node long_stack) + () + + let () = + let dug = Micheline.(Prim (0, I_DUG, [Int (0, Z.of_int 0)], [])) in + benchmark + ~intercept:true + ~name:Interpreter_workload.N_IDug + ~kinstr_and_stack_sampler:(fun _cfg rng_state () -> + let node = dug in + parse_instr rng_state node long_stack) + () + + let () = + let dug n = Micheline.(Prim (0, I_DUG, [Int (0, Z.of_int n)], [])) in + benchmark + ~name:Interpreter_workload.N_IDug + ~kinstr_and_stack_sampler:(fun _cfg rng_state () -> + let node = dug (sample_depth rng_state) in + parse_instr rng_state node long_stack) + () + + let () = + let nop = Micheline.Seq (0, []) in + let dip = Micheline.(Prim (0, I_DIP, [Int (0, Z.of_int 0); nop], [])) in + benchmark + ~intercept:true + ~name:Interpreter_workload.N_IDipN + ~kinstr_and_stack_sampler:(fun _cfg rng_state () -> + let node = dip in + parse_instr rng_state node long_stack) + () + + let () = + let nop = Micheline.Seq (0, []) in + let dip n = Micheline.(Prim (0, I_DIP, [Int (0, Z.of_int n); nop], [])) in + benchmark + ~name:Interpreter_workload.N_IDipN + ~kinstr_and_stack_sampler:(fun _cfg rng_state () -> + let node = dip (sample_depth rng_state) in + parse_instr rng_state node long_stack) + () + + let () = + let drop = Micheline.(Prim (0, I_DROP, [Int (0, Z.of_int 0)], [])) in + benchmark + ~intercept:true + ~name:Interpreter_workload.N_IDropN + ~kinstr_and_stack_sampler:(fun _cfg rng_state () -> + let node = drop in + parse_instr rng_state node long_stack) + () + + let () = + let drop n = Micheline.(Prim (0, I_DROP, [Int (0, Z.of_int n)], [])) in + benchmark + ~name:Interpreter_workload.N_IDropN + ~kinstr_and_stack_sampler:(fun _cfg rng_state () -> + let node = drop (sample_depth rng_state) in + parse_instr rng_state node long_stack) + () + + let () = + let pair n = Micheline.(Prim (0, I_PAIR, [Int (0, Z.of_int n)], [])) in + benchmark + ~name:Interpreter_workload.N_IComb + ~kinstr_and_stack_sampler:(fun cfg rng_state () -> + let width = + Base_samplers.( + sample_in_interval + rng_state + ~range:{min = 2; max = cfg.comb.max_depth}) + in + let node = pair width in + parse_instr rng_state node long_stack) + () + + let rec make_comb_stack (comb_width : int) (depth : int) acc = + if depth = 0 then + match acc with + | Ex_stack (stack_ty, stack) -> ( + match make_comb comb_width (Ex_value {value = (); ty = unit}) with + | Ex_value {value; ty} -> Ex_stack (ty @$ stack_ty, (value, stack))) + else + match acc with + | Ex_stack (stack_ty, stack) -> + make_comb_stack + comb_width + (depth - 1) + (Ex_stack (unit @$ stack_ty, ((), stack))) + + and make_comb comb_width comb_acc = + if comb_width = 0 then assert false + else if comb_width = 1 then comb_acc + else + match comb_acc with + | Ex_value {value; ty} -> + make_comb + (comb_width - 1) + (Ex_value {value = ((), value); ty = pair unit ty}) + + let () = + let unpair n = + Micheline.(Prim (0, I_UNPAIR, [Int (0, Z.of_int n)], [])) + in + benchmark + ~name:Interpreter_workload.N_IUncomb + ~kinstr_and_stack_sampler:(fun _cfg rng_state () -> + let width = + Base_samplers.( + sample_in_interval + rng_state + ~range:{min = 2; max = stack_size - 2}) + in + let node = unpair width in + let stack = + make_comb_stack width 1 (Ex_stack (unit @$ bot, ((), eos))) + in + parse_instr rng_state node stack) + () + + let () = + let comb_get n = Micheline.(Prim (0, I_GET, [Int (0, Z.of_int n)], [])) in + benchmark + ~name:Interpreter_workload.N_IComb_get + ~kinstr_and_stack_sampler:(fun _cfg rng_state () -> + let width = + Base_samplers.( + sample_in_interval + rng_state + ~range:{min = 2; max = stack_size - 2}) + in + let index = + Base_samplers.( + sample_in_interval rng_state ~range:{min = 0; max = width}) + in + let node = comb_get index in + let stack = + make_comb_stack width 1 (Ex_stack (unit @$ bot, ((), eos))) + in + parse_instr rng_state node stack) + () + + let () = + let comb_set n = + Micheline.(Prim (0, I_UPDATE, [Int (0, Z.of_int n)], [])) + in + benchmark + ~name:Interpreter_workload.N_IComb_set + ~kinstr_and_stack_sampler:(fun _cfg rng_state () -> + let width = + Base_samplers.( + sample_in_interval + rng_state + ~range:{min = 2; max = stack_size - 2}) + in + let index = + Base_samplers.( + sample_in_interval rng_state ~range:{min = 0; max = width}) + in + let node = comb_set index in + let stack = + let (Ex_stack (stack_ty, stack)) = + make_comb_stack width 1 (Ex_stack (unit @$ bot, ((), eos))) + in + Ex_stack (unit @$ stack_ty, ((), stack)) + in + parse_instr rng_state node stack) + () + + let () = + let dup n = Micheline.(Prim (0, I_DUP, [Int (0, Z.of_int n)], [])) in + benchmark + ~name:Interpreter_workload.N_IDupN + ~kinstr_and_stack_sampler:(fun _cfg rng_state () -> + let node = dup (1 + sample_depth rng_state) in + parse_instr rng_state node long_stack) + () + end + + module Pairs = struct + let () = + simple_benchmark + ~name:Interpreter_workload.N_ICons_pair + ~kinstr:(ICons_pair (kinfo_unitunit, halt (pair unit unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ICar + ~kinstr:(ICar (kinfo (pair unit unit @$ bot), halt_unit)) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ICdr + ~kinstr:(ICdr (kinfo (pair unit unit @$ bot), halt_unit)) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IUnpair + ~kinstr:(IUnpair (kinfo (pair unit unit @$ bot), halt_unitunit)) + () + end + + module Options = struct + let () = + simple_benchmark + ~name:Interpreter_workload.N_ICons_some + ~kinstr:(ICons_some (kinfo_unit, halt (option unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ICons_none + ~kinstr:(ICons_none (kinfo_unit, halt (option unit @$ unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IIf_none + ~kinstr: + (IIf_none + { + kinfo = kinfo (option unit @$ unit @$ bot); + branch_if_none = halt_unit; + branch_if_some = IDrop (kinfo_unitunit, halt_unit); + k = halt_unit; + }) + () + end + + module Unions = struct + let () = + simple_benchmark + ~name:Interpreter_workload.N_ILeft + ~kinstr:(ICons_left (kinfo_unit, halt (union unit unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IRight + ~kinstr:(ICons_right (kinfo_unit, halt (union unit unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IIf_left + ~kinstr: + (IIf_left + { + kinfo = kinfo (union unit unit @$ bot); + branch_if_left = halt_unit; + branch_if_right = halt_unit; + k = halt_unit; + }) + () + end + + module Lists = struct + let () = + simple_benchmark + ~name:Interpreter_workload.N_ICons_list + ~kinstr: + (ICons_list (kinfo (unit @$ list unit @$ bot), halt (list unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_INil + ~kinstr:(INil (kinfo_unit, halt (list unit @$ unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IIf_cons + ~kinstr: + (IIf_cons + { + kinfo = kinfo (list unit @$ unit @$ bot); + branch_if_cons = + IDrop + ( kinfo (unit @$ list unit @$ unit @$ bot), + IDrop (kinfo (list unit @$ unit @$ bot), halt_unit) ); + branch_if_nil = halt_unit; + k = halt_unit; + }) + () + + module Mapping = struct + let kinfo_enter_body = kinfo_unit + + let kinfo_exit_body = kinfo_unitunit + + let () = + (* + IList_map -> + IList_enter_body (empty case) -> + IHalt + *) + benchmark_with_fixed_stack + ~name:Interpreter_workload.N_IList_map + ~stack:(Script_list.empty, ((), eos)) + ~kinstr: + (IList_map + ( kinfo (list unit @$ unit @$ bot), + halt_unitunit, + halt (list unit @$ unit @$ bot) )) + () + end + + let () = + let kinfo = kinfo (list unit @$ bot) in + simple_benchmark + ~name:Interpreter_workload.N_IList_size + ~kinstr:(IList_size (kinfo, halt (nat @$ bot))) + () + + let () = + (* + IList_iter -> + IIter (empty case) -> + IHalt + *) + let kinfo1 = kinfo (list unit @$ unit @$ bot) in + benchmark_with_fixed_stack + ~name:Interpreter_workload.N_IList_iter + ~stack:(Script_list.empty, ((), eos)) + ~kinstr: + (IList_iter (kinfo1, IDrop (kinfo_unitunit, halt_unit), halt_unit)) + () + end + + module Sets = struct + let () = + simple_benchmark + ~name:Interpreter_workload.N_IEmpty_set + ~kinstr: + (IEmpty_set (kinfo_unit, unit_cmp, halt (set unit_cmp @$ unit @$ bot))) + () + + let set_iter_code = + ISet_iter + ( kinfo (set int_cmp @$ unit @$ bot), + IDrop (kinfo (int @$ unit @$ bot), halt_unit), + halt_unit ) + + let () = + (* + ISet_iter -> + (List.rev (set_fold)) -> + { + IIter -> + IDrop -> + ICons -> + ... + } + *) + simple_benchmark + ~name:Interpreter_workload.N_ISet_iter + ~intercept_stack:(Script_set.empty int_cmp, ((), eos)) + ~kinstr:set_iter_code + () + + let () = + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_ISet_mem + ~kinstr: + (ISet_mem + ( kinfo (int @$ set int_cmp @$ unit @$ bot), + halt (bool @$ unit @$ bot) )) + ~intercept_stack: + (Alpha_context.Script_int.zero, (Script_set.empty int_cmp, ((), eos))) + ~stack_sampler:(fun cfg rng_state () -> + assert (cfg.sampler.set_size.min >= 1) ; + let n = + Base_samplers.sample_in_interval + rng_state + ~range:cfg.sampler.set_size + in + let elts = adversarial_ints rng_state cfg n in + let set = + List.fold_left + (fun set elt -> Script_set.update elt true set) + (Script_set.empty int_cmp) + elts + in + let elt = + List.nth_opt elts (Random.State.int rng_state n) + |> WithExceptions.Option.get ~loc:__LOC__ + in + (elt, (set, ((), eos)))) + () + + let () = + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_ISet_update + ~kinstr: + (ISet_update + ( kinfo (int @$ bool @$ set int_cmp @$ bot), + halt (set int_cmp @$ bot) )) + ~intercept_stack: + ( Alpha_context.Script_int.zero, + (false, (Script_set.empty int_cmp, eos)) ) + ~stack_sampler:(fun cfg rng_state () -> + assert (cfg.sampler.set_size.min >= 2) ; + let n = + Base_samplers.sample_in_interval + rng_state + ~range:cfg.sampler.set_size + in + let elts = adversarial_ints rng_state cfg (n + 1) in + let (out_of_set, in_set) = + match elts with [] -> assert false | hd :: tl -> (hd, tl) + in + let set = + List.fold_left + (fun set elt -> Script_set.update elt true set) + (Script_set.empty int_cmp) + in_set + in + let stack = + let flip = Random.State.bool rng_state in + if flip then + (* add an element not in the set *) + (out_of_set, (true, (set, eos))) + else + (* remove an element in the set *) + let elt = out_of_set in + let set = Script_set.update elt true set in + (elt, (flip, (set, eos))) + in + stack) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ISet_size + ~kinstr:(ISet_size (kinfo (set unit_cmp @$ bot), halt (nat @$ bot))) + () + end + + module Maps = struct + let generate_map_and_key_in_map (cfg : Default_config.config) rng_state = + let n = + Base_samplers.sample_in_interval rng_state ~range:cfg.sampler.set_size + in + let keys = adversarial_ints rng_state cfg n in + let map = + List.fold_left + (fun map i -> Script_map.update i (Some ()) map) + (Script_map.empty int_cmp) + keys + in + let (module M) = map in + let key = + M.OPS.fold + (fun k _ -> function None -> Some k | x -> x) + (fst M.boxed) + None + |> WithExceptions.Option.get ~loc:__LOC__ + in + (key, map) + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IEmpty_map + ~kinstr: + (IEmpty_map + (kinfo_unit, unit_cmp, halt (map unit_cmp unit @$ unit @$ bot))) + () + + (* + let map_map_code = + IMap_map + ( kinfo (map int_cmp unit @$ unit @$ bot), + ICdr (kinfo (pair int unit @$ unit @$ bot), halt_unitunit), + halt (map int_cmp unit @$ unit @$ bot) ) + *) + + let map_map_code = + IMap_map + ( kinfo (map int_cmp unit @$ unit @$ bot), + IFailwith (kinfo (pair int unit @$ unit @$ bot), 0, pair int unit), + halt (map int_cmp unit @$ unit @$ bot) ) + + let () = + (* + Map_map (nonempty case) -> + (List.rev (map_fold nonempty_map)) -> + KMap_enter_body (nonempty case) -> + fail (early interruption) + *) + simple_benchmark + ~name:Interpreter_workload.N_IMap_map + ~intercept_stack: + (let map = Script_map.empty int_cmp in + (map, ((), eos))) + ~kinstr:map_map_code + () + + let kmap_iter_code = + IMap_iter + ( kinfo (map int_cmp unit @$ unit @$ bot), + IDrop (kinfo (pair int unit @$ unit @$ bot), halt_unit), + halt_unit ) + + let () = + (* + IMap_iter (nonempty case) -> + (List.rev (map_fold (nonempty))) -> + IIter (nonempty case) -> + ... + *) + simple_benchmark + ~name:Interpreter_workload.N_IMap_iter + ~intercept_stack: + (let map = Script_map.empty int_cmp in + (map, ((), eos))) + ~kinstr:kmap_iter_code + () + + let () = + (* + IMap_mem -> + (map_mem) -> + IHalt + *) + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IMap_mem + ~kinstr: + (IMap_mem + ( kinfo (int @$ map int_cmp unit @$ unit @$ bot), + halt (bool @$ unit @$ bot) )) + ~intercept_stack: + (let map = Script_map.empty int_cmp in + (Alpha_context.Script_int.zero, (map, ((), eos)))) + ~stack_sampler:(fun cfg rng_state () -> + let (key, map) = generate_map_and_key_in_map cfg rng_state in + (key, (map, ((), eos)))) + () + + let () = + (* + IMap_get -> + (map_get) -> + IHalt + *) + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IMap_get + ~kinstr: + (IMap_get + ( kinfo (int @$ map int_cmp unit @$ unit @$ bot), + halt (option unit @$ unit @$ bot) )) + ~intercept_stack: + (let map = Script_map.empty int_cmp in + (Alpha_context.Script_int.zero, (map, ((), eos)))) + ~stack_sampler:(fun cfg rng_state () -> + let (key, map) = generate_map_and_key_in_map cfg rng_state in + (key, (map, ((), eos)))) + () + + let () = + (* + IMap_update -> + (map_update) -> + IHalt + *) + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IMap_update + ~kinstr: + (IMap_update + ( kinfo (int @$ option unit @$ map int_cmp unit @$ bot), + halt (map int_cmp unit @$ bot) )) + ~intercept_stack: + (let map = Script_map.empty int_cmp in + (Alpha_context.Script_int.zero, (None, (map, eos)))) + ~stack_sampler:(fun cfg rng_state () -> + let (key, map) = generate_map_and_key_in_map cfg rng_state in + (key, (Some (), (map, eos)))) + () + + let () = + (* + IMap_get_and_update -> + (map_update) -> + (map_get) -> + IHalt + *) + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IMap_get_and_update + ~kinstr: + (IMap_get_and_update + ( kinfo (int @$ option unit @$ map int_cmp unit @$ bot), + halt (option unit @$ map int_cmp unit @$ bot) )) + ~intercept_stack: + (let map = Script_map.empty int_cmp in + (Alpha_context.Script_int.zero, (None, (map, eos)))) + ~stack_sampler:(fun cfg rng_state () -> + let (key, map) = generate_map_and_key_in_map cfg rng_state in + (key, (Some (), (map, eos)))) + () + + let () = + (* + IMap_size -> + (map_update) -> + (map_get) -> + IHalt + *) + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IMap_size + ~kinstr:(IMap_size (kinfo (map int_cmp unit @$ bot), halt (nat @$ bot))) + ~stack_sampler:(fun _cfg _rng_state -> + let map = Script_map.empty int_cmp in + fun () -> (map, eos)) + () + end + + module Big_maps = struct + let generate_big_map_and_key_in_map (cfg : Default_config.config) rng_state + = + let n = + Base_samplers.sample_in_interval rng_state ~range:cfg.sampler.set_size + in + let keys = adversarial_ints rng_state cfg n in + let map = + List.fold_left + (fun map i -> Script_map.update i (Some (Some ())) map) + (Script_map.empty int_cmp) + keys + in + let (module M) = map in + let key = + M.OPS.fold + (fun k _ -> function None -> Some k | x -> x) + (fst M.boxed) + None + |> WithExceptions.Option.get ~loc:__LOC__ + in + let big_map = + raise_if_error + (Lwt_main.run + ( Execution_context.make ~rng_state >>=? fun (ctxt, _) -> + let big_map = + Script_ir_translator.empty_big_map int_cmp (unit_t ~annot:None) + in + Script_map.fold + (fun k v acc -> + acc >>=? fun (bm, ctxt_acc) -> + Script_ir_translator.big_map_update ctxt_acc k v bm) + map + (return (big_map, ctxt)) + >|= Environment.wrap_tzresult + >>=? fun (big_map, _) -> return big_map )) + in + (key, big_map) + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IEmpty_big_map + ~kinstr: + (IEmpty_big_map + ( kinfo_unit, + unit_cmp, + unit, + halt (big_map unit_cmp unit @$ unit @$ bot) )) + () + + let () = + (* + IBig_map_mem -> + (update context with gas) + (big_map_mem) -> + IHalt + *) + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IBig_map_mem + ~kinstr: + (IBig_map_mem + ( kinfo (int @$ big_map int_cmp unit @$ unit @$ bot), + halt (bool @$ unit @$ bot) )) + ~stack_sampler:(fun cfg rng_state () -> + let (key, map) = generate_big_map_and_key_in_map cfg rng_state in + (key, (map, ((), eos)))) + () + + let () = + (* + IBig_map_get -> + (big_map_get) -> + IHalt + *) + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IBig_map_get + ~kinstr: + (IBig_map_get + ( kinfo (int @$ big_map int_cmp unit @$ unit @$ bot), + halt (option unit @$ unit @$ bot) )) + ~intercept_stack: + (let map = Script_ir_translator.empty_big_map int_cmp unit in + (Alpha_context.Script_int.zero, (map, ((), eos)))) + ~stack_sampler:(fun cfg rng_state () -> + let (key, map) = generate_big_map_and_key_in_map cfg rng_state in + (key, (map, ((), eos)))) + () + + let () = + (* + IBig_map_update -> + (big_map_update) -> + IHalt + *) + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IBig_map_update + ~kinstr: + (IBig_map_update + ( kinfo (int @$ option unit @$ big_map int_cmp unit @$ bot), + halt (big_map int_cmp unit @$ bot) )) + ~intercept_stack: + (let map = Script_ir_translator.empty_big_map int_cmp unit in + (Alpha_context.Script_int.zero, (None, (map, eos)))) + ~stack_sampler:(fun cfg rng_state () -> + let (key, map) = generate_big_map_and_key_in_map cfg rng_state in + (key, (Some (), (map, eos)))) + () + + let () = + (* + IBig_map_get_and_update -> + (big_map_update) -> + (big_map_get) -> + IHalt + *) + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IBig_map_get_and_update + ~kinstr: + (IBig_map_get_and_update + ( kinfo (int @$ option unit @$ big_map int_cmp unit @$ bot), + halt (option unit @$ big_map int_cmp unit @$ bot) )) + ~intercept_stack: + (let map = Script_ir_translator.empty_big_map int_cmp unit in + (Alpha_context.Script_int.zero, (None, (map, eos)))) + ~stack_sampler:(fun cfg rng_state () -> + let (key, map) = generate_big_map_and_key_in_map cfg rng_state in + (key, (Some (), (map, eos)))) + () + end + + module Strings = struct + open Alpha_context.Script_string + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IConcat_string + ~intercept_stack:(Script_list.empty, eos) + ~kinstr: + (IConcat_string (kinfo (list string @$ bot), halt (string @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IConcat_string_pair + ~intercept_stack:(empty, (empty, eos)) + ~kinstr: + (IConcat_string_pair + (kinfo (string @$ string @$ bot), halt (string @$ bot))) + () + + let () = + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_ISlice_string + ~kinstr: + (ISlice_string + (kinfo (nat @$ nat @$ string @$ bot), halt (option string @$ bot))) + ~intercept_stack: + (let z = Alpha_context.Script_int.zero_n in + (z, (z, (empty, eos)))) + ~stack_sampler:(fun cfg rng_state -> + let (module Samplers) = make_default_samplers cfg.sampler in + fun () -> + let string = + Samplers.Random_value.value + Script_typed_ir.(string_t ~annot:None) + rng_state + in + let len = nat_of_positive_int (length string) in + (* worst case: offset = 0 *) + (nat_of_positive_int 0, (len, (string, eos)))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IString_size + ~kinstr:(IString_size (kinfo (string @$ bot), halt (nat @$ bot))) + () + end + + module Bytes = struct + (* Copy of [String] modulo renaming string to bytes. *) + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IConcat_bytes + ~intercept_stack:(Script_list.empty, eos) + ~kinstr:(IConcat_bytes (kinfo (list bytes @$ bot), halt (bytes @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IConcat_bytes_pair + ~intercept_stack:(Bytes.empty, (Bytes.empty, eos)) + ~kinstr: + (IConcat_bytes_pair + (kinfo (bytes @$ bytes @$ bot), halt (bytes @$ bot))) + () + + let () = + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_ISlice_bytes + ~kinstr: + (ISlice_bytes + (kinfo (nat @$ nat @$ bytes @$ bot), halt (option bytes @$ bot))) + ~intercept_stack: + (let z = Alpha_context.Script_int.zero_n in + (z, (z, (Bytes.empty, eos)))) + ~stack_sampler:(fun cfg rng_state -> + let (module Samplers) = make_default_samplers cfg.sampler in + fun () -> + let bytes = + Samplers.Random_value.value + Script_typed_ir.(bytes_t ~annot:None) + rng_state + in + let len = nat_of_positive_int (Bytes.length bytes) in + (* worst case: offset = 0 *) + (nat_of_positive_int 0, (len, (bytes, eos)))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IBytes_size + ~kinstr:(IBytes_size (kinfo (bytes @$ bot), halt (nat @$ bot))) + () + end + + module Timestamps = struct + let zero_timestamp = Alpha_context.Script_timestamp.of_zint Z.zero + + let zero_int = Alpha_context.Script_int.zero + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAdd_seconds_to_timestamp + ~intercept_stack:(zero_int, (zero_timestamp, eos)) + ~kinstr: + (IAdd_seconds_to_timestamp + (kinfo (int @$ timestamp @$ bot), halt (timestamp @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAdd_timestamp_to_seconds + ~intercept_stack:(zero_timestamp, (zero_int, eos)) + ~kinstr: + (IAdd_timestamp_to_seconds + (kinfo (timestamp @$ int @$ bot), halt (timestamp @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ISub_timestamp_seconds + ~intercept_stack:(zero_timestamp, (zero_int, eos)) + ~kinstr: + (ISub_timestamp_seconds + (kinfo (timestamp @$ int @$ bot), halt (timestamp @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IDiff_timestamps + ~intercept_stack:(zero_timestamp, (zero_timestamp, eos)) + ~kinstr: + (IDiff_timestamps + (kinfo (timestamp @$ timestamp @$ bot), halt (int @$ bot))) + () + end + + module Tez = struct + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAdd_tez + ~kinstr:(IAdd_tez (kinfo (mutez @$ mutez @$ bot), halt (mutez @$ bot))) + () + + let () = + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_ISub_tez + ~kinstr:(ISub_tez (kinfo (mutez @$ mutez @$ bot), halt (mutez @$ bot))) + ~stack_sampler:(fun cfg rng_state -> + let (module Samplers) = + make_default_samplers cfg.Default_config.sampler + in + fun () -> + let a = Samplers.Random_value.value mutez rng_state in + let b = + match Alpha_context.Tez.(a /? 2L) with + | Error _ -> assert false + | Ok x -> x + in + (a, (b, eos))) + () + + let sample_tez_nat (module Samplers : Michelson_samplers.S) rng_state = + let mutez = Samplers.Random_value.value mutez rng_state in + let mutez_int64 = Alpha_context.Tez.to_mutez mutez in + let int64 = Int64.(div max_int (mul mutez_int64 2L)) in + let nat = + match Alpha_context.Script_int.(is_nat (of_int64 int64)) with + | None -> assert false + | Some nat -> nat + in + (mutez, nat) + + let () = + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IMul_teznat + ~kinstr:(IMul_teznat (kinfo (mutez @$ nat @$ bot), halt (mutez @$ bot))) + ~stack_sampler:(fun cfg rng_state -> + let samplers = make_default_samplers cfg.sampler in + fun () -> + let (mutez, nat) = sample_tez_nat samplers rng_state in + (mutez, (nat, eos))) + () + + let () = + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IMul_nattez + ~kinstr:(IMul_nattez (kinfo (nat @$ mutez @$ bot), halt (mutez @$ bot))) + ~stack_sampler:(fun cfg rng_state -> + let samplers = make_default_samplers cfg.sampler in + fun () -> + let (mutez, nat) = sample_tez_nat samplers rng_state in + (nat, (mutez, eos))) + () + + let () = + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IEdiv_teznat + ~kinstr: + (IEdiv_teznat + ( kinfo (mutez @$ nat @$ bot), + halt (option (pair mutez mutez) @$ bot) )) + ~stack_sampler:(fun cfg rng_state -> + let samplers = make_default_samplers cfg.sampler in + fun () -> + let (mutez, nat) = sample_tez_nat samplers rng_state in + (mutez, (nat, eos))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IEdiv_tez + ~kinstr: + (IEdiv_tez + ( kinfo (mutez @$ mutez @$ bot), + halt (option (pair nat mutez) @$ bot) )) + () + end + + module Booleans = struct + let () = + simple_benchmark + ~name:Interpreter_workload.N_IOr + ~kinstr:(IOr (kinfo (bool @$ bool @$ bot), halt (bool @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAnd + ~kinstr:(IAnd (kinfo (bool @$ bool @$ bot), halt (bool @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IXor + ~kinstr:(IXor (kinfo (bool @$ bool @$ bot), halt (bool @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_INot + ~kinstr:(INot (kinfo (bool @$ bot), halt (bool @$ bot))) + () + end + + module Integers = struct + let zero = Alpha_context.Script_int.zero + + let zero_n = Alpha_context.Script_int.zero_n + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IIs_nat + ~intercept_stack:(zero, eos) + ~kinstr:(IIs_nat (kinfo (int @$ bot), halt (option nat @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_INeg_nat + ~intercept_stack:(zero_n, eos) + ~kinstr:(INeg_nat (kinfo (nat @$ bot), halt (int @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_INeg_int + ~intercept_stack:(zero, eos) + ~kinstr:(INeg_int (kinfo (int @$ bot), halt (int @$ bot))) + () + + let () = + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IAbs_int + ~kinstr:(IAbs_int (kinfo (int @$ bot), halt (nat @$ bot))) + ~intercept_stack:(zero, eos) + ~stack_sampler:(fun cfg rng_state -> + let (module Samplers) = make_default_samplers cfg.sampler in + fun () -> + let x = Samplers.Michelson_base.nat rng_state in + let neg_x = Alpha_context.Script_int.neg x in + (neg_x, eos)) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IInt_nat + ~intercept_stack:(zero_n, eos) + ~kinstr:(IInt_nat (kinfo (nat @$ bot), halt (int @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAdd_intint + ~intercept_stack:(zero, (zero, eos)) + ~kinstr:(IAdd_intint (kinfo (int @$ int @$ bot), halt (int @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAdd_natint + ~intercept_stack:(zero_n, (zero, eos)) + ~kinstr:(IAdd_natint (kinfo (nat @$ int @$ bot), halt (int @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAdd_intnat + ~intercept_stack:(zero, (zero_n, eos)) + ~kinstr:(IAdd_intnat (kinfo (int @$ nat @$ bot), halt (int @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAdd_natnat + ~intercept_stack:(zero_n, (zero_n, eos)) + ~kinstr:(IAdd_natnat (kinfo (nat @$ nat @$ bot), halt (nat @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ISub_int + ~intercept_stack:(zero, (zero, eos)) + ~kinstr:(ISub_int (kinfo (int @$ int @$ bot), halt (int @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IMul_intint + ~intercept_stack:(zero, (zero, eos)) + ~kinstr:(IMul_intint (kinfo (int @$ int @$ bot), halt (int @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IMul_intnat + ~intercept_stack:(zero, (zero_n, eos)) + ~kinstr:(IMul_intnat (kinfo (int @$ nat @$ bot), halt (int @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IMul_natint + ~intercept_stack:(zero_n, (zero, eos)) + ~kinstr:(IMul_natint (kinfo (nat @$ int @$ bot), halt (int @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IMul_natnat + ~intercept_stack:(zero_n, (zero_n, eos)) + ~kinstr:(IMul_natnat (kinfo (nat @$ nat @$ bot), halt (nat @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IEdiv_intint + ~intercept_stack:(zero, (zero, eos)) + ~kinstr: + (IEdiv_intint + (kinfo (int @$ int @$ bot), halt (option (pair int nat) @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IEdiv_intnat + ~intercept_stack:(zero, (zero_n, eos)) + ~kinstr: + (IEdiv_intnat + (kinfo (int @$ nat @$ bot), halt (option (pair int nat) @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IEdiv_natint + ~intercept_stack:(zero_n, (zero, eos)) + ~kinstr: + (IEdiv_natint + (kinfo (nat @$ int @$ bot), halt (option (pair int nat) @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IEdiv_natnat + ~intercept_stack:(zero_n, (zero_n, eos)) + ~kinstr: + (IEdiv_natnat + (kinfo (nat @$ nat @$ bot), halt (option (pair nat nat) @$ bot))) + () + + let () = + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_ILsl_nat + ~intercept_stack:(zero_n, (zero_n, eos)) + ~kinstr:(ILsl_nat (kinfo (nat @$ nat @$ bot), halt (nat @$ bot))) + ~stack_sampler:(fun cfg rng_state -> + let (module Samplers) = make_default_samplers cfg.sampler in + fun () -> + let x = Samplers.Michelson_base.nat rng_state in + (* shift must be in [0;256]: 1 byte max *) + let shift = + Script_int_repr.(abs (of_int (Random.State.int rng_state 256))) + in + (x, (shift, eos))) + () + + let () = + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_ILsr_nat + ~intercept_stack:(zero_n, (zero_n, eos)) + ~kinstr:(ILsr_nat (kinfo (nat @$ nat @$ bot), halt (nat @$ bot))) + ~stack_sampler:(fun cfg rng_state -> + let (module Samplers) = make_default_samplers cfg.sampler in + fun () -> + let x = Samplers.Michelson_base.nat rng_state in + (* shift must be in [0;256]: 1 byte max *) + let shift = + Script_int_repr.(abs (of_int (Random.State.int rng_state 256))) + in + (x, (shift, eos))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IOr_nat + ~intercept_stack:(zero_n, (zero_n, eos)) + ~kinstr:(IOr_nat (kinfo (nat @$ nat @$ bot), halt (nat @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAnd_nat + ~intercept_stack:(zero_n, (zero_n, eos)) + ~kinstr:(IAnd_nat (kinfo (nat @$ nat @$ bot), halt (nat @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAnd_int_nat + ~intercept_stack:(zero, (zero_n, eos)) + ~kinstr:(IAnd_int_nat (kinfo (int @$ nat @$ bot), halt (nat @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IXor_nat + ~intercept_stack:(zero_n, (zero_n, eos)) + ~kinstr:(IXor_nat (kinfo (nat @$ nat @$ bot), halt (nat @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_INot_nat + ~intercept_stack:(zero_n, eos) + ~kinstr:(INot_nat (kinfo (nat @$ bot), halt (int @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_INot_int + ~intercept_stack:(zero, eos) + ~kinstr:(INot_int (kinfo (int @$ bot), halt (int @$ bot))) + () + end + + module Control = struct + let () = + simple_benchmark + ~name:Interpreter_workload.N_IIf + ~kinstr: + (IIf + { + kinfo = kinfo (bool @$ unit @$ bot); + branch_if_true = halt_unit; + branch_if_false = halt_unit; + k = halt_unit; + }) + () + + let () = + (* + ILoop -> + either + - IHalt (false on top of stack) + - IConst false ; IHalt (true on top of stack) + *) + let push_false = IConst (kinfo_unit, false, halt (bool @$ unit @$ bot)) in + simple_benchmark + ~name:Interpreter_workload.N_ILoop + ~kinstr:(ILoop (kinfo (bool @$ unit @$ bot), push_false, halt_unit)) + () + + let () = + (* + ILoop_left -> + ICons_right -> + IHalt + *) + let cons_r = ICons_right (kinfo_unit, halt (union unit unit @$ bot)) in + simple_benchmark + ~name:Interpreter_workload.N_ILoop_left + ~kinstr:(ILoop_left (kinfo (union unit unit @$ bot), cons_r, halt_unit)) + () + + let () = + (* + IDip -> + IHalt -> + IConst -> + IHalt + *) + simple_benchmark + ~name:Interpreter_workload.N_IDip + ~kinstr:(IDip (kinfo (unit @$ unit @$ bot), halt_unit, halt_unitunit)) + () + + let dummy_lambda = + let open Script_typed_ir in + let descr = + {kloc = 0; kbef = unit @$ bot; kaft = unit @$ bot; kinstr = halt_unit} + in + Lam (descr, Micheline.Int (0, Z.zero)) + + let () = + (* + IExec -> + (switch to in-context gas-counting) -> + interp lambda code -> + IHalt + *) + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IExec + ~kinstr:(IExec (kinfo (unit @$ lambda unit unit @$ bot), halt_unit)) + ~stack_sampler:(fun _cfg _rng_state () -> ((), (dummy_lambda, eos))) + () + + let () = + (* + IApply -> + unparse unit -> + unparse unit_ty -> + construct term -> + IHalt + *) + let code = + let open Script_typed_ir in + let descr = + { + kloc = 0; + kbef = pair unit unit @$ bot; + kaft = unit @$ bot; + kinstr = ICdr (kinfo (pair unit unit @$ bot), halt_unit); + } + in + Lam (descr, Micheline.Int (0, Z.zero)) + in + simple_benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IApply + ~kinstr: + (IApply + ( kinfo (unit @$ lambda (pair unit unit) unit @$ bot), + unit, + halt (lambda unit unit @$ bot) )) + ~stack_sampler:(fun _cfg _rng_state () -> ((), (code, eos))) + () + + let () = + (* + ILambda -> + IHalt + *) + simple_benchmark + ~name:Interpreter_workload.N_ILambda + ~kinstr: + (ILambda + (kinfo_unit, dummy_lambda, halt (lambda unit unit @$ unit @$ bot))) + () + + let () = + (* + IFailwith -> + (unparse_data Unit) -> + (strip_locations) -> + fail + *) + simple_benchmark + ~name:Interpreter_workload.N_IFailwith + ~amplification:100 + ~kinstr:(IFailwith (kinfo_unit, 0, unit)) + () + end + + module Comparison = struct + let () = + benchmark + ~name:Interpreter_workload.N_ICompare + ~kinstr_and_stack_sampler:(fun cfg rng_state -> + let (module Samplers) = make_default_samplers cfg.sampler in + fun () -> + let size = + Base_samplers.sample_in_interval + rng_state + ~range:cfg.sampler.type_size + in + let (Script_ir_translator.Ex_comparable_ty cmp_ty) = + Samplers.Random_type.m_comparable_type ~size rng_state + in + let ty = Michelson_samplers.comparable_downcast cmp_ty in + let value = Samplers.Random_value.comparable cmp_ty rng_state in + let kinstr = + ICompare (kinfo (ty @$ ty @$ bot), cmp_ty, halt (int @$ bot)) + in + Ex_stack_and_kinstr {stack = (value, (value, eos)); kinstr}) + () + end + + module Comparators = struct + let () = + simple_benchmark + ~name:Interpreter_workload.N_IEq + ~kinstr:(IEq (kinfo (int @$ bot), halt (bool @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_INeq + ~kinstr:(INeq (kinfo (int @$ bot), halt (bool @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ILt + ~kinstr:(ILt (kinfo (int @$ bot), halt (bool @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IGt + ~kinstr:(IGt (kinfo (int @$ bot), halt (bool @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ILe + ~kinstr:(ILe (kinfo (int @$ bot), halt (bool @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IGe + ~kinstr:(IGe (kinfo (int @$ bot), halt (bool @$ bot))) + () + end + + module Proto = struct + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAddress + ~kinstr:(IAddress (kinfo (contract unit @$ bot), halt (address @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IContract + ~kinstr: + (IContract + ( kinfo (address @$ bot), + unit, + "default", + halt (option (contract unit) @$ bot) )) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ITransfer_tokens + ~kinstr: + (ITransfer_tokens + ( kinfo (unit @$ mutez @$ contract unit @$ bot), + halt (operation @$ bot) )) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IImplicit_account + ~kinstr: + (IImplicit_account + (kinfo (key_hash @$ bot), halt (contract unit @$ bot))) + () + + let () = + let lambda = + let open Script_typed_ir in + let descr = + { + kloc = 0; + kbef = pair unit unit @$ bot; + kaft = pair (list operation) unit @$ bot; + kinstr = + ICdr + ( kinfo (pair unit unit @$ bot), + INil + ( kinfo (unit @$ bot), + ICons_pair + ( kinfo (list operation @$ unit @$ bot), + IHalt (kinfo (pair (list operation) unit @$ bot)) ) ) + ); + } + in + Lam (descr, Micheline.Int (0, Z.zero)) + in + simple_benchmark + ~name:Interpreter_workload.N_ICreate_contract + ~kinstr: + (ICreate_contract + { + kinfo = kinfo (option key_hash @$ mutez @$ unit @$ bot); + storage_type = unit; + arg_type = unit; + lambda; + views = SMap.empty; + root_name = None; + k = halt (operation @$ address @$ bot); + }) + () + + let () = + let name = + match Protocol.Alpha_context.Script_string.of_string "view" with + | Ok s -> s + | Error _ -> assert false + in + simple_benchmark + ~name:Interpreter_workload.N_IView + ~kinstr: + (IView + ( kinfo (unit @$ address @$ bot), + View_signature {name; input_ty = unit; output_ty = unit}, + halt (option unit @$ bot) )) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ISet_delegate + ~kinstr: + (ISet_delegate + (kinfo (option key_hash @$ bot), halt (operation @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_INow + ~kinstr:(INow (kinfo (unit @$ bot), halt (timestamp @$ unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IBalance + ~kinstr:(IBalance (kinfo (unit @$ bot), halt (mutez @$ unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ILevel + ~kinstr:(ILevel (kinfo (unit @$ bot), halt (nat @$ unit @$ bot))) + () + + let check_signature (algo : Signature.algo) ~for_intercept = + let name = + match algo with + | Signature.Ed25519 -> Interpreter_workload.N_ICheck_signature_ed25519 + | Signature.Secp256k1 -> + Interpreter_workload.N_ICheck_signature_secp256k1 + | Signature.P256 -> Interpreter_workload.N_ICheck_signature_p256 + in + benchmark_with_stack_sampler + ~intercept:for_intercept + ~name + ~kinstr: + (ICheck_signature + ( kinfo (public_key @$ signature @$ bytes @$ bot), + halt (bool @$ bot) )) + ~stack_sampler:(fun cfg rng_state -> + let (module Samplers) = + make_default_samplers ~algo:(`Algo algo) cfg.Default_config.sampler + in + fun () -> + let (_pkh, pk, sk) = Samplers.Crypto_samplers.all rng_state in + let unsigned_message = + if for_intercept then Environment.Bytes.empty + else + Samplers.Random_value.value + Script_typed_ir.(bytes_t ~annot:None) + rng_state + in + let signed_message = Signature.sign sk unsigned_message in + (pk, (signed_message, (unsigned_message, eos)))) + () + + let check_signature algo = + check_signature algo ~for_intercept:true ; + check_signature algo ~for_intercept:false + + let () = check_signature Signature.Ed25519 + + let () = check_signature Signature.Secp256k1 + + let () = check_signature Signature.P256 + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IHash_key + ~kinstr:(IHash_key (kinfo (public_key @$ bot), halt (key_hash @$ bot))) + () + + let () = + benchmark + ~name:Interpreter_workload.N_IPack + ~kinstr_and_stack_sampler:(fun _cfg _rng_state -> + let kinstr = IPack (kinfo (unit @$ bot), unit, halt (bytes @$ bot)) in + fun () -> Ex_stack_and_kinstr {stack = ((), eos); kinstr}) + () + + let () = + benchmark + ~name:Interpreter_workload.N_IUnpack + ~kinstr_and_stack_sampler:(fun _cfg rng_state -> + let b = + raise_if_error + (Lwt_main.run + ( Execution_context.make ~rng_state >>=? fun (ctxt, _) -> + Script_ir_translator.pack_data ctxt unit () + >|= Environment.wrap_tzresult + >>=? fun (bytes, _) -> return bytes )) + in + let kinstr = + IUnpack (kinfo (bytes @$ bot), unit, halt (option unit @$ bot)) + in + fun () -> Ex_stack_and_kinstr {stack = (b, eos); kinstr}) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IBlake2b + ~intercept_stack:(Environment.Bytes.empty, eos) + ~kinstr:(IBlake2b (kinfo (bytes @$ bot), halt (bytes @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ISha256 + ~intercept_stack:(Environment.Bytes.empty, eos) + ~kinstr:(ISha256 (kinfo (bytes @$ bot), halt (bytes @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ISha512 + ~intercept_stack:(Environment.Bytes.empty, eos) + ~kinstr:(ISha512 (kinfo (bytes @$ bot), halt (bytes @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IKeccak + ~intercept_stack:(Environment.Bytes.empty, eos) + ~kinstr:(IKeccak (kinfo (bytes @$ bot), halt (bytes @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ISha3 + ~intercept_stack:(Environment.Bytes.empty, eos) + ~kinstr:(ISha3 (kinfo (bytes @$ bot), halt (bytes @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ISource + ~kinstr:(ISource (kinfo (unit @$ bot), halt (address @$ unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ISender + ~kinstr:(ISender (kinfo (unit @$ bot), halt (address @$ unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ISelf + ~kinstr: + (ISelf + ( kinfo (unit @$ bot), + unit, + "default", + halt (contract unit @$ unit @$ bot) )) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ISelf_address + ~kinstr: + (ISelf_address (kinfo (unit @$ bot), halt (address @$ unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAmount + ~kinstr:(IAmount (kinfo (unit @$ bot), halt (mutez @$ unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IChainId + ~kinstr:(IChainId (kinfo (unit @$ bot), halt (chain_id @$ unit @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IVoting_power + ~kinstr:(IVoting_power (kinfo (key_hash @$ bot), halt (nat @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_ITotal_voting_power + ~kinstr: + (ITotal_voting_power (kinfo (unit @$ bot), halt (nat @$ unit @$ bot))) + () + end + + module Sapling = struct + let () = + let memo_size = + match Alpha_context.Sapling.Memo_size.parse_z Z.zero with + | Error _ -> assert false + | Ok sz -> sz + in + simple_benchmark + ~name:Interpreter_workload.N_ISapling_empty_state + ~kinstr: + (ISapling_empty_state + ( kinfo (unit @$ bot), + memo_size, + halt (sapling_state memo_size @$ unit @$ bot) )) + () + + let () = + (* Note that memo_size is hardcoded to 0 in module [Sapling_generation]. *) + let memo_size = + match Alpha_context.Sapling.Memo_size.parse_z Z.zero with + | Error _ -> assert false + | Ok sz -> sz + in + let (info, name) = + info_and_name ~intercept:false "ISapling_verify_update" + in + let module B : Benchmark.S = struct + let name = name + + let info = info + + include Default_config + include Default_boilerplate + + let models = + Interpreter_model.make_model + (Some (Instr_name Interpreter_workload.N_ISapling_verify_update)) + + let kinstr = + let spl_state = sapling_state memo_size in + let spl_tx = sapling_transaction memo_size in + ISapling_verify_update + ( kinfo (spl_tx @$ spl_state @$ bot), + halt (option (pair int spl_state) @$ bot) ) + + let prepare_sapling_execution_environment sapling_forge_rng_seed + sapling_transition = + let sapling_forge_rng_state = + Random.State.make + @@ Option.fold + ~none:Sapling_generation.shared_seed + ~some:(fun seed -> [|seed|]) + sapling_forge_rng_seed + in + (* Prepare context. We _must_ reuse the same seed as the one used for + the context when generating the transactions. This ensures that the + bootstrap account match and that the transactions can be replayed. *) + let result = + Lwt_main.run + ( Execution_context.make ~rng_state:sapling_forge_rng_state + >>=? fun (ctxt, step_constants) -> + (* Prepare a sapling state able to replay the transition. *) + Sapling_generation.prepare_seeded_state sapling_transition ctxt + >>=? fun (_, _, _, _, ctxt, state_id) -> + Alpha_context.Sapling.(state_from_id ctxt (Id.parse_z state_id)) + >|= Environment.wrap_tzresult + >>=? fun (state, ctxt) -> return (ctxt, state, step_constants) + ) + in + match result with + | Ok r -> r + | Error _ -> + Format.eprintf + "Error in prepare_sapling_execution_environment, aborting@." ; + Stdlib.failwith "prepare_sapling_execution_environment" + + let create_benchmarks ~rng_state ~bench_num (config : config) = + ignore rng_state ; + match config.sapling with + | {sapling_txs_file; seed} -> + let transitions = + Sapling_generation.load ~filename:sapling_txs_file + in + let length = List.length transitions in + if length < bench_num then + Format.eprintf + "ISapling_verify_update: warning, only %d available \ + transactions (requested %d)@." + length + bench_num ; + let transitions = + List.take_n (min bench_num length) transitions + in + List.map + (fun (_, transition) () -> + let (ctxt, state, step_constants) = + prepare_sapling_execution_environment seed transition + in + let stack_instr = + Ex_stack_and_kinstr + {stack = (transition.sapling_tx, (state, eos)); kinstr} + in + benchmark_from_kinstr_and_stack + ctxt + step_constants + stack_instr) + transitions + end in + Registration_helpers.register (module B) + end + + module Bls12_381 = struct + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAdd_bls12_381_g1 + ~kinstr: + (IAdd_bls12_381_g1 + ( kinfo (bls12_381_g1 @$ bls12_381_g1 @$ bot), + halt (bls12_381_g1 @$ bot) )) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAdd_bls12_381_g2 + ~kinstr: + (IAdd_bls12_381_g2 + ( kinfo (bls12_381_g2 @$ bls12_381_g2 @$ bot), + halt (bls12_381_g2 @$ bot) )) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IAdd_bls12_381_fr + ~kinstr: + (IAdd_bls12_381_fr + ( kinfo (bls12_381_fr @$ bls12_381_fr @$ bot), + halt (bls12_381_fr @$ bot) )) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IMul_bls12_381_g1 + ~kinstr: + (IMul_bls12_381_g1 + ( kinfo (bls12_381_g1 @$ bls12_381_fr @$ bot), + halt (bls12_381_g1 @$ bot) )) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IMul_bls12_381_g2 + ~kinstr: + (IMul_bls12_381_g2 + ( kinfo (bls12_381_g2 @$ bls12_381_fr @$ bot), + halt (bls12_381_g2 @$ bot) )) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IMul_bls12_381_fr + ~kinstr: + (IMul_bls12_381_fr + ( kinfo (bls12_381_fr @$ bls12_381_fr @$ bot), + halt (bls12_381_fr @$ bot) )) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IMul_bls12_381_z_fr + ~kinstr: + (IMul_bls12_381_z_fr + (kinfo (bls12_381_fr @$ int @$ bot), halt (bls12_381_fr @$ bot))) + () + + let () = + benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IMul_bls12_381_z_fr + ~intercept:true + ~kinstr: + (IMul_bls12_381_z_fr + (kinfo (bls12_381_fr @$ int @$ bot), halt (bls12_381_fr @$ bot))) + ~stack_sampler:(fun cfg rng_state -> + let (module Samplers) = make_default_samplers cfg.sampler in + let fr_sampler = Samplers.Random_value.value bls12_381_fr in + let zero = Alpha_context.Script_int.zero in + fun () -> (fr_sampler rng_state, (zero, eos))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IMul_bls12_381_fr_z + ~kinstr: + (IMul_bls12_381_fr_z + (kinfo (int @$ bls12_381_fr @$ bot), halt (bls12_381_fr @$ bot))) + () + + let () = + benchmark_with_stack_sampler + ~name:Interpreter_workload.N_IMul_bls12_381_fr_z + ~intercept:true + ~kinstr: + (IMul_bls12_381_fr_z + (kinfo (int @$ bls12_381_fr @$ bot), halt (bls12_381_fr @$ bot))) + ~stack_sampler:(fun cfg rng_state -> + let (module Samplers) = make_default_samplers cfg.sampler in + let fr_sampler = Samplers.Random_value.value bls12_381_fr in + let zero = Alpha_context.Script_int.zero in + fun () -> (zero, (fr_sampler rng_state, eos))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IInt_bls12_381_z_fr + ~kinstr: + (IInt_bls12_381_fr (kinfo (bls12_381_fr @$ bot), halt (int @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_INeg_bls12_381_g1 + ~kinstr: + (INeg_bls12_381_g1 + (kinfo (bls12_381_g1 @$ bot), halt (bls12_381_g1 @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_INeg_bls12_381_g2 + ~kinstr: + (INeg_bls12_381_g2 + (kinfo (bls12_381_g2 @$ bot), halt (bls12_381_g2 @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_INeg_bls12_381_fr + ~kinstr: + (INeg_bls12_381_fr + (kinfo (bls12_381_fr @$ bot), halt (bls12_381_fr @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IPairing_check_bls12_381 + ~kinstr: + (IPairing_check_bls12_381 + ( kinfo (list (pair bls12_381_g1 bls12_381_g2) @$ bot), + halt (bool @$ bot) )) + () + end + + module Tickets = struct + let () = + simple_benchmark + ~name:Interpreter_workload.N_ITicket + ~kinstr: + (ITicket (kinfo (unit @$ nat @$ bot), halt (ticket unit_cmp @$ bot))) + () + + let () = + simple_benchmark + ~name:Interpreter_workload.N_IRead_ticket + ~kinstr: + (IRead_ticket + ( kinfo (ticket unit_cmp @$ bot), + halt (pair address (pair unit nat) @$ ticket unit_cmp @$ bot) )) + () + + let split_ticket_instr = + ISplit_ticket + ( kinfo (ticket unit_cmp @$ pair nat nat @$ bot), + halt (option (pair (ticket unit_cmp) (ticket unit_cmp)) @$ bot) ) + + let () = + let zero = Alpha_context.Script_int.zero_n in + let ticket = + { + ticketer = + ( Alpha_context.Contract.implicit_contract + Environment.Signature.Public_key_hash.zero, + "" ); + contents = (); + amount = zero; + } + in + benchmark_with_fixed_stack + ~intercept:true + ~name:Interpreter_workload.N_ISplit_ticket + ~stack:(ticket, ((zero, zero), eos)) + ~kinstr:split_ticket_instr + () + + let () = + benchmark + ~name:Interpreter_workload.N_ISplit_ticket + ~kinstr_and_stack_sampler:(fun config rng_state -> + let (module Samplers) = + make_default_samplers config.Default_config.sampler + in + fun () -> + let half_amount = Samplers.Random_value.value nat rng_state in + let amount = + Alpha_context.Script_int.add_n half_amount half_amount + in + let ticket = + Samplers.Random_value.value (ticket unit_cmp) rng_state + in + let ticket = {ticket with amount} in + Ex_stack_and_kinstr + { + stack = (ticket, ((half_amount, half_amount), eos)); + kinstr = split_ticket_instr; + }) + () + + let join_tickets_instr = + IJoin_tickets + ( kinfo (pair (ticket string_cmp) (ticket string_cmp) @$ bot), + string_cmp, + halt (option (ticket string_cmp) @$ bot) ) + + let () = + benchmark + ~intercept:true + ~name:Interpreter_workload.N_IJoin_tickets + ~kinstr_and_stack_sampler:(fun config rng_state -> + let (module Samplers) = + make_default_samplers config.Default_config.sampler + in + fun () -> + let ticket = + Samplers.Random_value.value (ticket string_cmp) rng_state + in + let ticket = + { + ticket with + contents = Alpha_context.Script_string.empty; + amount = Script_int_repr.zero_n; + } + in + Ex_stack_and_kinstr + {stack = ((ticket, ticket), eos); kinstr = join_tickets_instr}) + () + + let () = + benchmark + ~name:Interpreter_workload.N_IJoin_tickets + ~kinstr_and_stack_sampler:(fun config rng_state -> + let (module Samplers) = + make_default_samplers config.Default_config.sampler + in + fun () -> + let ticket = + Samplers.Random_value.value (ticket string_cmp) rng_state + in + let alt_amount = Samplers.Random_value.value nat rng_state in + let ticket' = {ticket with amount = alt_amount} in + Ex_stack_and_kinstr + {stack = ((ticket, ticket'), eos); kinstr = join_tickets_instr}) + () + end + + module Timelock = struct + let name = Interpreter_workload.N_IOpen_chest + + let kinstr = + IOpen_chest + ( kinfo + (Michelson_types.chest_key @$ Michelson_types.chest @$ nat @$ bot), + halt (union bytes bool @$ bot) ) + + let resulting_stack chest chest_key time = + ( chest_key, + ( chest, + ( Script_int_repr.is_nat (Script_int_repr.of_int time) + |> WithExceptions.Option.get ~loc:"Timelock:gas benchmarks", + eos ) ) ) + + let () = + benchmark_with_stack_sampler + ~intercept:true + ~name + ~kinstr + ~stack_sampler:(fun _ rng_state () -> + let (chest, chest_key) = + Timelock.chest_sampler ~plaintext_size:1 ~time:0 ~rng_state + in + resulting_stack chest chest_key 0) + () + + let () = + benchmark_with_stack_sampler + ~name + ~kinstr + ~stack_sampler:(fun _ rng_state () -> + let log_time = + Base_samplers.sample_in_interval + ~range:{min = 0; max = 29} + rng_state + in + let time = Random.State.int rng_state (Int.shift_left 1 log_time) in + let plaintext_size = + Base_samplers.sample_in_interval + ~range:{min = 1; max = 10000} + rng_state + in + + let (chest, chest_key) = + Timelock.chest_sampler ~plaintext_size ~time ~rng_state + in + resulting_stack chest chest_key time) + () + end + + module Continuations = struct + let () = + (* + KNil + *) + continuation_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_KNil + ~cont_and_stack_sampler:(fun _cfg _rng_state -> + let cont = KNil in + let stack = eos in + fun () -> Ex_stack_and_cont {stack; cont}) + () + + let () = + (* + KCons -> step + KHalt -> next + KNil + *) + continuation_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_KCons + ~cont_and_stack_sampler:(fun _cfg _rng_state -> + let cont = KCons (halt_unit, KNil) in + let stack = ((), eos) in + fun () -> Ex_stack_and_cont {stack; cont}) + () + + let () = + (* + KReturn -> next + KNil + *) + continuation_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_KReturn + ~cont_and_stack_sampler:(fun _cfg _rng_state -> + let cont = KReturn (halt_unit, KNil) in + let stack = ((), eos) in + fun () -> Ex_stack_and_cont {stack; cont}) + () + + let () = + (* + KLoop_in -> next + KNil + *) + continuation_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_KLoop_in + ~cont_and_stack_sampler:(fun _cfg _rng_state -> + let cont = + KLoop_in + (IConst (kinfo_unit, false, halt (bool @$ unit @$ bot)), KNil) + in + let stack = (false, ((), eos)) in + fun () -> Ex_stack_and_cont {stack; cont}) + () + + let () = + (* + KLoop_in_left -> next + KNil + *) + continuation_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_KLoop_in_left + ~cont_and_stack_sampler:(fun _cfg _rng_state -> + let cont = + KLoop_in_left + (ICons_right (kinfo_unit, halt (union unit unit @$ bot)), KNil) + in + let stack = (R (), eos) in + fun () -> Ex_stack_and_cont {stack; cont}) + () + + let () = + (* + KUndip -> next + KNil + *) + continuation_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_KUndip + ~cont_and_stack_sampler:(fun _cfg _rng_state -> + let cont = KUndip ((), KNil) in + let stack = eos in + fun () -> Ex_stack_and_cont {stack; cont}) + () + + let () = + (* + KIter (empty case) -> next + KNil + *) + continuation_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_KIter + ~salt:"_empty" + ~cont_and_stack_sampler:(fun _cfg _rng_state -> + let cont = KIter (IDrop (kinfo_unitunit, halt_unit), [], KNil) in + let stack = ((), eos) in + fun () -> Ex_stack_and_cont {stack; cont}) + () + + let () = + (* + KIter (nonempty case) -> step + KDrop -> step + KHalt -> next + KIter (empty case) -> next + KNil + *) + continuation_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_KIter + ~salt:"_nonempty" + ~cont_and_stack_sampler:(fun _cfg _rng_state -> + let cont = KIter (IDrop (kinfo_unitunit, halt_unit), [()], KNil) in + let stack = ((), eos) in + fun () -> Ex_stack_and_cont {stack; cont}) + () + + let () = + (* + KList_enter_body ([()], bot accumulator case) -> step + KHalt -> next + KList_exit_body ([], []) -> + KList_enter_body ([], [()] -> + List.rev singleton + KNil + *) + continuation_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_KList_enter_body + ~salt:"_singleton_list" + ~cont_and_stack_sampler:(fun _cfg _rng_state -> + let kbody = halt_unitunit in + fun () -> + let cont = KList_enter_body (kbody, [()], [], 1, KNil) in + Ex_stack_and_cont {stack = ((), eos); cont}) + () + + let () = + (* + KList_enter_body (empty list, nonempty accumulator case) -> + {List.rev n elements} -> next + KNil + *) + continuation_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_KList_enter_body + ~salt:"_terminal" + ~cont_and_stack_sampler:(fun cfg rng_state -> + let (module Samplers) = make_default_samplers cfg.sampler in + let kbody = halt_unitunit in + fun () -> + let ys = Samplers.Random_value.value (list unit) rng_state in + let cont = + KList_enter_body (kbody, [], ys.elements, ys.length, KNil) + in + Ex_stack_and_cont {stack = ((), eos); cont}) + () + + let () = + (* + KList_enter_body (empty list, bot accumulator case) -> + {List.rev singleton} -> next + KNil + *) + continuation_benchmark + ~amplification:100 + ~intercept:true + ~name:Interpreter_workload.N_KList_enter_body + ~salt:"_terminal" + ~cont_and_stack_sampler:(fun _cfg _rng_state -> + let kbody = halt_unitunit in + fun () -> + let cont = KList_enter_body (kbody, [], [], 1, KNil) in + Ex_stack_and_cont {stack = ((), eos); cont}) + () + + let () = + (* + KList_exit_body (empty list) -> next + KList_enter_body -> + {List.rev 1 element} -> next + KNil + *) + continuation_benchmark + ~amplification:100 + ~intercept:true + ~name:Interpreter_workload.N_KList_exit_body + ~salt:"_terminal" + ~cont_and_stack_sampler:(fun _cfg _rng_state -> + let kbody = halt_unitunit in + let cont = KList_exit_body (kbody, [], [], 1, KNil) in + fun () -> Ex_stack_and_cont {stack = ((), ((), eos)); cont}) + () + + let map_enter_body_code = + let kbody = ICdr (kinfo (pair int unit @$ unit @$ bot), halt_unitunit) in + fun accu -> KMap_enter_body (kbody, accu, Script_map.empty int_cmp, KNil) + + let () = + (* + KMap_enter_body (empty case) -> next + KNil + *) + continuation_benchmark + ~amplification:100 + ~salt:"_empty" + ~name:Interpreter_workload.N_KMap_enter_body + ~cont_and_stack_sampler:(fun _cfg _rng_state () -> + Ex_stack_and_cont {stack = ((), eos); cont = map_enter_body_code []}) + () + + let () = + (* + KMap_enter_body (singleton case) -> step + KCdr -> step + KHalt -> next + KMap_exit_body -> next + (map_update) + KMap_enter_body (empty case) -> next + KNil + *) + continuation_benchmark + ~amplification:100 + ~salt:"_singleton" + ~name:Interpreter_workload.N_KMap_enter_body + ~cont_and_stack_sampler:(fun _cfg _rng_state () -> + Ex_stack_and_cont + { + stack = ((), eos); + cont = map_enter_body_code [(Script_int_repr.zero, ())]; + }) + () + + let () = + (* + KMap_exit_body -> + (map_update) -> next + KMap_enter_body (empty case) -> next + KNil + *) + continuation_benchmark + ~amplification:100 + ~name:Interpreter_workload.N_KMap_exit_body + ~cont_and_stack_sampler:(fun cfg rng_state -> + let kbody = + ICdr (kinfo (pair int unit @$ unit @$ bot), halt_unitunit) + in + fun () -> + let (key, map) = Maps.generate_map_and_key_in_map cfg rng_state in + let cont = KMap_exit_body (kbody, [], map, key, KNil) in + Ex_stack_and_cont {stack = ((), ((), eos)); cont}) + () + end +end diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/interpreter_model.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/interpreter_model.ml new file mode 100644 index 000000000000..25709755f527 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/interpreter_model.ml @@ -0,0 +1,543 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* ------------------------------------------------------------------------- *) + +let trace_error expected given = + let open Interpreter_workload in + let exp = string_of_instr_or_cont expected in + let given = string_of_instr_or_cont given in + let msg = + Format.asprintf + "Interpreter_model: trace error, expected %s, given %s" + exp + given + in + Stdlib.failwith msg + +let arity_error instr expected given = + let open Interpreter_workload in + let s = string_of_instr_or_cont instr in + let msg = + Format.asprintf + "Interpreter_model: arity error (%s), expected %d, given %a" + s + expected + Interpreter_workload.pp_args + given + in + Stdlib.failwith msg + +(* ------------------------------------------------------------------------- *) + +let model_0 instr model = + let open Interpreter_workload in + Model.make + ~conv:(function + | {name; args = []} -> if name = instr then () else trace_error instr name + | {args; _} -> arity_error instr 0 args) + ~model + +let model_1 instr model = + let open Interpreter_workload in + Model.make + ~conv:(function + | {name; args = [{name = _; arg}]} -> + if name = instr then (arg, ()) else trace_error instr name + | {args; _} -> arity_error instr 1 args) + ~model + +let model_2 instr model = + let open Interpreter_workload in + Model.make + ~conv:(function + | {name; args = [{name = _; arg = x}; {name = _; arg = y}]} -> + if name = instr then (x, (y, ())) else trace_error instr name + | {args; _} -> arity_error instr 2 args) + ~model + +let model_3 instr model = + let open Interpreter_workload in + Model.make + ~conv:(function + | { + name; + args = [{name = _; arg = x}; {name = _; arg = y}; {name = _; arg = z}]; + } -> + if name = instr then (x, (y, (z, ()))) else trace_error instr name + | {args; _} -> arity_error instr 3 args) + ~model + +let model_4 instr model = + let open Interpreter_workload in + Model.make + ~conv:(function + | { + name; + args = + [ + {name = _; arg = w}; + {name = _; arg = x}; + {name = _; arg = y}; + {name = _; arg = z}; + ]; + } -> + if name = instr then (w, (x, (y, (z, ())))) + else trace_error instr name + | {args; _} -> arity_error instr 4 args) + ~model + +let fv = Free_variable.of_string + +let sf = Format.asprintf + +let division_cost name = + let const = fv (sf "%s_const" name) in + let coeff = fv (sf "%s_coeff" name) in + let module M = struct + type arg_type = int * (int * unit) + + module Def (X : Costlang.S) = struct + open X + + type model_type = size -> size -> size + + let arity = Model.arity_2 + + let model = + lam ~name:"size1" @@ fun size1 -> + lam ~name:"size2" @@ fun size2 -> + let_ ~name:"q" (size1 - size2) @@ fun q -> + (free ~name:coeff * if_ (lt size2 size1) (q * size2) (int 0)) + + free ~name:const + end + end in + (module M : Model.Model_impl with type arg_type = int * (int * unit)) + +let addlogadd name = + let const = fv (sf "%s_const" name) in + let coeff = fv (sf "%s_coeff" name) in + let module M = struct + type arg_type = int * (int * unit) + + module Def (X : Costlang.S) = struct + open X + + type model_type = size -> size -> size + + let arity = Model.arity_2 + + let model = + lam ~name:"size1" @@ fun size1 -> + lam ~name:"size2" @@ fun size2 -> + let_ ~name:"a" (size1 + size2) @@ fun a -> + (free ~name:coeff * (a * log2 (int 1 + a))) + free ~name:const + end + end in + (module M : Model.Model_impl with type arg_type = int * (int * unit)) + +(* Some instructions are oveloaded (eg COMPARE). In order to generate distinct + models at different types, we must specialize these models. The [specialization] + parameter acts as a mangling scheme to produce distinct models. *) +let name_of_instr_or_cont ?specialization instr_or_cont = + let spec = Option.fold ~none:"" ~some:(fun s -> "_" ^ s) specialization in + Interpreter_workload.string_of_instr_or_cont instr_or_cont ^ spec + +module Models = struct + let const1_model name = + (* For constant-time instructions *) + Model.unknown_const1 ~const:(fv (sf "%s_const" name)) + + let affine_model name = + (* For instructions with cost function + [\lambda size. const + coeff * size] *) + Model.affine + ~intercept:(fv (sf "%s_const" name)) + ~coeff:(fv (sf "%s_coeff" name)) + + let break_model name break = + Model.breakdown + ~coeff1:(fv (sf "%s_coeff1" name)) + ~coeff2:(fv (sf "%s_coeff2" name)) + ~break + + let break_model_2 name break1 break2 = + Model.breakdown2 + ~coeff1:(fv (sf "%s_coeff1" name)) + ~coeff2:(fv (sf "%s_coeff2" name)) + ~coeff3:(fv (sf "%s_coeff3" name)) + ~break1 + ~break2 + + let break_model_2_const name break1 break2 = + Model.breakdown2_const + ~coeff1:(fv (sf "%s_coeff1" name)) + ~coeff2:(fv (sf "%s_coeff2" name)) + ~coeff3:(fv (sf "%s_coeff3" name)) + ~const:(fv (sf "%s_const" name)) + ~break1 + ~break2 + + let nlogm_model name = + (* For instructions with cost function + [\lambda size1. \lambda size2. const + coeff * size1 log2(size2)] *) + Model.nlogm + ~intercept:(fv (sf "%s_const" name)) + ~coeff:(fv (sf "%s_coeff" name)) + + let concat_model name = + Model.bilinear_affine + ~intercept:(fv (sf "%s_const" name)) + ~coeff1:(fv (sf "%s_total_bytes" name)) + ~coeff2:(fv (sf "%s_list_length" name)) + + let concat_pair_model name = + Model.linear_sum + ~intercept:(fv (sf "%s_const" name)) + ~coeff:(fv (sf "%s_coeff" name)) + + let linear_max_model name = + (* For instructions with cost function + [\lambda size1. \lambda size2. const + coeff * max(size1,size2)] *) + Model.linear_max + ~intercept:(fv (sf "%s_const" name)) + ~coeff:(fv (sf "%s_coeff" name)) + + let linear_min_model name = + (* For instructions with cost function + [\lambda size1. \lambda size2. const + coeff * min(size1,size2)] *) + Model.linear_min + ~intercept:(fv (sf "%s_const" name)) + ~coeff:(fv (sf "%s_coeff" name)) + + let pack_model name = + Model.trilinear + ~coeff1:(fv (sf "%s_micheline_nodes" name)) + ~coeff2:(fv (sf "%s_micheline_int_bytes" name)) + ~coeff3:(fv (sf "%s_micheline_string_bytes" name)) + + let split_ticket_model name = + let module M = struct + type arg_type = int * (int * unit) + + module Def (X : Costlang.S) = struct + open X + + type model_type = size -> size -> size + + let arity = Model.arity_2 + + let model = + lam ~name:"size1" @@ fun size1 -> + lam ~name:"size2" @@ fun size2 -> + free ~name:(fv (sf "%s_const" name)) + + (free ~name:(fv (sf "%s_add_coeff" name)) * max size1 size2) + + (free ~name:(fv (sf "%s_cmp_coeff" name)) * min size1 size2) + end + end in + (module M : Model.Model_impl with type arg_type = int * (int * unit)) + + let open_chest_model name = + let module M = struct + type arg_type = int * (int * unit) + + module Def (X : Costlang.S) = struct + open X + + type model_type = size -> size -> size + + let arity = Model.arity_2 + + let model = + lam ~name:"size1" @@ fun size1 -> + lam ~name:"size2" @@ fun size2 -> + free ~name:(fv (sf "%s_const" name)) + + (free ~name:(fv (sf "%s_log_time_coeff" name)) * size1) + + (free ~name:(fv (sf "%s_plaintext_coeff" name)) * size2) + end + end in + (module M : Model.Model_impl with type arg_type = int * (int * unit)) + + let verify_update_model name = + Model.bilinear_affine + ~intercept:(fv (sf "%s_const" name)) + ~coeff1:(fv (sf "%s_inputs" name)) + ~coeff2:(fv (sf "%s_ouputs" name)) + + let list_enter_body_model name = + let module M = struct + type arg_type = int * (int * unit) + + module Def (X : Costlang.S) = struct + open X + + type model_type = size -> size -> size + + let arity = Model.arity_2 + + let model = + lam ~name:"size_xs" @@ fun size_xs -> + lam ~name:"size_ys" @@ fun size_ys -> + if_ + (eq size_xs (int 0)) + (free ~name:(fv (sf "%s_const" name)) + + (free ~name:(fv (sf "%s_coeff" name)) * size_ys)) + (free ~name:(fv (sf "%s_iter" name))) + end + end in + (module M : Model.Model_impl with type arg_type = int * (int * unit)) + + let branching_model name = + let module M = struct + type arg_type = int * unit + + module Def (X : Costlang.S) = struct + open X + + type model_type = size -> size + + let arity = Model.arity_1 + + let model = + lam ~name:"size" @@ fun size -> + if_ + (eq size (int 0)) + (free ~name:(fv (sf "%s_empty" name))) + (free ~name:(fv (sf "%s_nonempty" name))) + end + end in + (module M : Model.Model_impl with type arg_type = int * unit) + + let join_tickets_model name = + let module M = struct + type arg_type = int * (int * (int * (int * unit))) + + module Def (X : Costlang.S) = struct + open X + + type model_type = size -> size -> size -> size -> size + + let arity = Model.Succ_arity Model.arity_3 + + let model = + lam ~name:"content_size_x" @@ fun content_size_x -> + lam ~name:"content_size_y" @@ fun content_size_y -> + lam ~name:"amount_size_x" @@ fun amount_size_x -> + lam ~name:"amount_size_y" @@ fun amount_size_y -> + free ~name:(fv (sf "%s_const" name)) + + free ~name:(fv (sf "%s_compare_coeff" name)) + * min content_size_x content_size_y + + free ~name:(fv (sf "%s_add_coeff" name)) + * max amount_size_x amount_size_y + end + end in + (module M : Model.Model_impl + with type arg_type = int * (int * (int * (int * unit)))) +end + +let ir_model ?specialization instr_or_cont = + let open Interpreter_workload in + let open Models in + let name = name_of_instr_or_cont ?specialization instr_or_cont in + match instr_or_cont with + | Instr_name instr -> ( + match instr with + | N_IDrop | N_IDup | N_ISwap | N_IConst | N_ICons_pair | N_ICar | N_ICdr + | N_ICons_some | N_ICons_none | N_IIf_none | N_ILeft | N_IRight + | N_IIf_left | N_ICons_list | N_INil | N_IIf_cons | N_IEmpty_set + | N_IEmpty_map | N_IEmpty_big_map | N_IOr | N_IAnd | N_IXor | N_INot + | N_IIf | N_ILoop | N_ILoop_left | N_IDip | N_IExec | N_IView | N_ILambda + | N_IFailwith | N_IAddress | N_ICreate_contract | N_ISet_delegate | N_INow + | N_IBalance | N_IHash_key | N_IUnpack | N_ISource | N_ISender | N_ISelf + | N_IAmount | N_IChainId | N_ILevel | N_ISelf_address | N_INever + | N_IUnpair | N_IVoting_power | N_ITotal_voting_power | N_IList_size + | N_ISet_size | N_IMap_size | N_ISapling_empty_state -> + model_0 instr_or_cont (const1_model name) + | N_ISet_mem | N_ISet_update | N_IMap_mem | N_IMap_get | N_IMap_update + | N_IBig_map_mem | N_IBig_map_get | N_IBig_map_update + | N_IMap_get_and_update | N_IBig_map_get_and_update -> + model_2 instr_or_cont (nlogm_model name) + | N_IConcat_string -> model_2 instr_or_cont (concat_model name) + | N_IConcat_string_pair -> model_2 instr_or_cont (concat_pair_model name) + | N_ISlice_string -> model_1 instr_or_cont (affine_model name) + | N_IString_size -> model_0 instr_or_cont (const1_model name) + | N_IConcat_bytes -> model_2 instr_or_cont (concat_model name) + | N_IConcat_bytes_pair -> model_2 instr_or_cont (concat_pair_model name) + | N_ISlice_bytes -> model_1 instr_or_cont (affine_model name) + | N_IBytes_size -> model_0 instr_or_cont (const1_model name) + | N_IAdd_seconds_to_timestamp | N_IAdd_timestamp_to_seconds + | N_ISub_timestamp_seconds | N_IDiff_timestamps -> + model_2 instr_or_cont (linear_max_model name) + | N_IAdd_tez | N_ISub_tez | N_IEdiv_tez -> + model_0 instr_or_cont (const1_model name) + | N_IMul_teznat | N_IMul_nattez -> + model_1 instr_or_cont (affine_model name) + | N_IEdiv_teznat -> model_2 instr_or_cont (division_cost name) + | N_IIs_nat -> model_0 instr_or_cont (const1_model name) + | N_INeg_nat -> model_1 instr_or_cont (affine_model name) + | N_INeg_int -> model_1 instr_or_cont (affine_model name) + | N_IAbs_int -> model_1 instr_or_cont (affine_model name) + | N_IInt_nat -> model_0 instr_or_cont (const1_model name) + | N_IAdd_intint -> model_2 instr_or_cont (linear_max_model name) + | N_IAdd_intnat -> model_2 instr_or_cont (linear_max_model name) + | N_IAdd_natint -> model_2 instr_or_cont (linear_max_model name) + | N_IAdd_natnat -> model_2 instr_or_cont (linear_max_model name) + | N_ISub_int -> model_2 instr_or_cont (linear_max_model name) + | N_IMul_intint -> model_2 instr_or_cont (addlogadd name) + | N_IMul_intnat -> model_2 instr_or_cont (addlogadd name) + | N_IMul_natint -> model_2 instr_or_cont (addlogadd name) + | N_IMul_natnat -> model_2 instr_or_cont (addlogadd name) + | N_IEdiv_intint -> model_2 instr_or_cont (division_cost name) + | N_IEdiv_intnat -> model_2 instr_or_cont (division_cost name) + | N_IEdiv_natint -> model_2 instr_or_cont (division_cost name) + | N_IEdiv_natnat -> model_2 instr_or_cont (division_cost name) + | N_ILsl_nat -> model_1 instr_or_cont (affine_model name) + | N_ILsr_nat -> model_1 instr_or_cont (affine_model name) + | N_IOr_nat -> model_2 instr_or_cont (linear_max_model name) + | N_IAnd_nat -> model_2 instr_or_cont (linear_min_model name) + | N_IAnd_int_nat -> model_2 instr_or_cont (linear_min_model name) + | N_IXor_nat -> model_2 instr_or_cont (linear_max_model name) + | N_INot_nat -> model_1 instr_or_cont (affine_model name) + | N_INot_int -> model_1 instr_or_cont (affine_model name) + | N_ICompare -> model_2 instr_or_cont (linear_min_model name) + | N_IEq | N_INeq | N_ILt | N_IGt | N_ILe | N_IGe -> + model_0 instr_or_cont (const1_model name) + | N_IPack -> model_3 instr_or_cont (pack_model name) + | N_IBlake2b | N_ISha256 | N_ISha512 | N_IKeccak | N_ISha3 -> + model_1 instr_or_cont (affine_model name) + | N_ICheck_signature_ed25519 | N_ICheck_signature_secp256k1 + | N_ICheck_signature_p256 -> + model_1 instr_or_cont (affine_model name) + | N_IContract | N_ITransfer_tokens | N_IImplicit_account -> + model_0 instr_or_cont (const1_model name) + (* The following two instructions are expected to have an affine model. However, + we observe 3 affine parts, on [0;300], [300;400] and [400;\inf[. *) + | N_IDupN -> model_1 instr_or_cont (break_model_2 name 300 400) + | N_IDropN -> model_1 instr_or_cont (break_model_2_const name 300 400) + | N_IDig | N_IDug | N_IDipN -> model_1 instr_or_cont (affine_model name) + | N_IAdd_bls12_381_g1 | N_IAdd_bls12_381_g2 | N_IAdd_bls12_381_fr + | N_IMul_bls12_381_g1 | N_IMul_bls12_381_g2 | N_IMul_bls12_381_fr + | N_INeg_bls12_381_g1 | N_INeg_bls12_381_g2 | N_INeg_bls12_381_fr + | N_IInt_bls12_381_z_fr -> + model_0 instr_or_cont (const1_model name) + | N_IMul_bls12_381_fr_z | N_IMul_bls12_381_z_fr + | N_IPairing_check_bls12_381 -> + model_1 instr_or_cont (affine_model name) + | N_IComb_get | N_IComb | N_IComb_set | N_IUncomb -> + model_1 instr_or_cont (affine_model name) + | N_ITicket | N_IRead_ticket -> model_0 instr_or_cont (const1_model name) + | N_ISplit_ticket -> model_2 instr_or_cont (split_ticket_model name) + | N_IJoin_tickets -> model_4 instr_or_cont (join_tickets_model name) + | N_ISapling_verify_update -> + model_2 instr_or_cont (verify_update_model name) + | N_IList_map -> model_0 instr_or_cont (const1_model name) + | N_IList_iter -> model_0 instr_or_cont (const1_model name) + | N_IIter -> model_0 instr_or_cont (const1_model name) + | N_IMap_map -> model_1 instr_or_cont (affine_model name) + | N_IMap_iter -> model_1 instr_or_cont (affine_model name) + | N_ISet_iter -> model_1 instr_or_cont (affine_model name) + | N_IHalt -> model_0 instr_or_cont (const1_model name) + | N_IApply -> model_0 instr_or_cont (const1_model name) + | N_ILog -> model_0 instr_or_cont (const1_model name) + | N_IOpen_chest -> model_2 instr_or_cont (open_chest_model name)) + | Cont_name cont -> ( + match cont with + | N_KNil -> model_0 instr_or_cont (const1_model name) + | N_KCons -> model_0 instr_or_cont (const1_model name) + | N_KReturn -> model_0 instr_or_cont (const1_model name) + | N_KUndip -> model_0 instr_or_cont (const1_model name) + | N_KLoop_in -> model_0 instr_or_cont (const1_model name) + | N_KLoop_in_left -> model_0 instr_or_cont (const1_model name) + | N_KIter -> model_1 instr_or_cont (branching_model name) + | N_KList_enter_body -> model_2 instr_or_cont (list_enter_body_model name) + | N_KList_exit_body -> model_0 instr_or_cont (const1_model name) + | N_KMap_enter_body -> model_1 instr_or_cont (branching_model name) + | N_KMap_exit_body -> model_2 instr_or_cont (nlogm_model name) + | N_KLog -> model_0 instr_or_cont (const1_model name)) + +let amplification_loop_iteration = fv "amplification_loop_iteration" + +let amplification_loop_model = + Model.make + ~conv:(fun iterations -> (iterations, ())) + ~model:(Model.linear ~coeff:amplification_loop_iteration) + +(* The following model stitches together the per-instruction models and + adds a term corresponding to the latency induced by the timer itself. *) +let interpreter_model ?amplification ?specialization () = + Model.make_preapplied ~model:(fun trace -> + let module Def (X : Costlang.S) = struct + let applied = + let (module Timer_applied) = + Model.apply Tezos_benchmark.Builtin_benchmarks.timer_model () + in + let module Timer_result = Timer_applied (X) in + let initial = + match amplification with + | None -> Timer_result.applied + | Some amplification_factor -> + let (module Amplification_applied) = + Model.apply amplification_loop_model amplification_factor + in + let module Amplification_result = Amplification_applied (X) in + X.(Timer_result.applied + Amplification_result.applied) + in + List.fold_left + (fun (acc : X.size X.repr) instr_trace -> + let (module Applied_instr) = + Model.apply + (ir_model + ?specialization + instr_trace.Interpreter_workload.name) + instr_trace + in + let module R = Applied_instr (X) in + X.(acc + R.applied)) + initial + trace + end in + ((module Def) : Model.applied)) + +let make_model ?amplification ?specialization instr_name_opt = + match instr_name_opt with + | None -> + [("interpreter", interpreter_model ?amplification ?specialization ())] + | Some name -> + (* When generating code, we don't want to consider the terms specific to + Lwt and to the timer latency. Also, we restrict to single instructions. *) + let ir_model = ir_model ?specialization name in + let name = name_of_instr_or_cont ?specialization name in + Registration_helpers.register_for_codegen + name + (Model.For_codegen ir_model) ; + let ir_model = + Model.precompose + (function [sized_step] -> sized_step | _ -> assert false) + ir_model + in + [ + ("interpreter", interpreter_model ?amplification ?specialization ()); + ("codegen", ir_model); + ] diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/interpreter_workload.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/interpreter_workload.ml new file mode 100644 index 000000000000..5f856a28a17f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/interpreter_workload.ml @@ -0,0 +1,1596 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(* ------------------------------------------------------------------------- *) + +type id = string + +let pp_id = Format.pp_print_string + +let equal_id = String.equal + +(* ------------------------------------------------------------------------- *) +(* Names of IR instructions together with sizes of their operands as + encountered during evaluation. *) + +type instruction_name = + (* stack ops *) + | N_IDrop + | N_IDup + | N_ISwap + | N_IConst + (* pairs *) + | N_ICons_pair + | N_ICar + | N_ICdr + | N_IUnpair + (* options *) + | N_ICons_some + | N_ICons_none + | N_IIf_none + (* unions *) + | N_ILeft + | N_IRight + | N_IIf_left + (* lists *) + | N_ICons_list + | N_INil + | N_IIf_cons + | N_IList_map + | N_IList_iter + | N_IIter + | N_IList_size + (* sets *) + | N_IEmpty_set + | N_ISet_iter + | N_ISet_mem + | N_ISet_update + | N_ISet_size + (* maps *) + | N_IEmpty_map + | N_IMap_map + | N_IMap_iter + | N_IMap_mem + | N_IMap_get + | N_IMap_update + | N_IMap_get_and_update + | N_IMap_size + (* big maps *) + | N_IEmpty_big_map + | N_IBig_map_mem + | N_IBig_map_get + | N_IBig_map_update + | N_IBig_map_get_and_update + (* string operations *) + | N_IConcat_string + | N_IConcat_string_pair + | N_ISlice_string + | N_IString_size + (* bytes operations *) + | N_IConcat_bytes + | N_IConcat_bytes_pair + | N_ISlice_bytes + | N_IBytes_size + (* timestamp operations *) + | N_IAdd_seconds_to_timestamp + | N_IAdd_timestamp_to_seconds + | N_ISub_timestamp_seconds + | N_IDiff_timestamps + (* currency operations *) + | N_IAdd_tez + | N_ISub_tez + | N_IMul_teznat + | N_IMul_nattez + | N_IEdiv_teznat + | N_IEdiv_tez + (* boolean operations - assumed O(1) *) + | N_IOr + | N_IAnd + | N_IXor + | N_INot + (* integer operations *) + | N_IIs_nat + | N_INeg_nat + | N_INeg_int + | N_IAbs_int + | N_IInt_nat + | N_IAdd_intint + | N_IAdd_intnat + | N_IAdd_natint + | N_IAdd_natnat + | N_ISub_int + | N_IMul_intint + | N_IMul_intnat + | N_IMul_natint + | N_IMul_natnat + | N_IEdiv_intint + | N_IEdiv_intnat + | N_IEdiv_natint + | N_IEdiv_natnat + | N_ILsl_nat + | N_ILsr_nat + | N_IOr_nat + | N_IAnd_nat + | N_IAnd_int_nat + | N_IXor_nat + | N_INot_nat + | N_INot_int + (* control *) + | N_IIf + | N_ILoop + | N_ILoop_left + | N_IDip + | N_IExec + | N_IApply + | N_ILambda + | N_IFailwith + (* comparison, warning: ad-hoc polymorphic instruction *) + | N_ICompare + (* comparators *) + | N_IEq + | N_INeq + | N_ILt + | N_IGt + | N_ILe + | N_IGe + (* protocol *) + | N_IAddress + | N_IContract + | N_ITransfer_tokens + | N_IImplicit_account + | N_ICreate_contract + | N_ISet_delegate + | N_INow + | N_IBalance + | N_ILevel + | N_IView + (* We specialize the check-signature instruction for each crypto scheme. *) + | N_ICheck_signature_ed25519 + | N_ICheck_signature_secp256k1 + | N_ICheck_signature_p256 + | N_IHash_key + | N_IPack + | N_IUnpack + | N_IBlake2b + | N_ISha256 + | N_ISha512 + | N_ISource + | N_ISender + | N_ISelf + | N_ISelf_address + | N_IAmount + | N_ISapling_empty_state + | N_ISapling_verify_update + | N_IDig + | N_IDug + | N_IDipN + | N_IDropN + | N_IChainId + | N_INever + | N_IVoting_power + | N_ITotal_voting_power + | N_IKeccak + | N_ISha3 + (* Elliptic curves *) + | N_IAdd_bls12_381_g1 + | N_IAdd_bls12_381_g2 + | N_IAdd_bls12_381_fr + | N_IMul_bls12_381_g1 + | N_IMul_bls12_381_g2 + | N_IMul_bls12_381_fr + | N_INeg_bls12_381_g1 + | N_INeg_bls12_381_g2 + | N_INeg_bls12_381_fr + | N_IMul_bls12_381_fr_z + | N_IMul_bls12_381_z_fr + | N_IInt_bls12_381_z_fr + | N_IPairing_check_bls12_381 + (* Combs *) + | N_IComb + | N_IUncomb + | N_IComb_get + | N_IComb_set + | N_IDupN + (* Tickets *) + | N_ITicket + | N_IRead_ticket + | N_ISplit_ticket + | N_IJoin_tickets + (* Misc *) + | N_IHalt + | N_ILog + (* Timelock*) + | N_IOpen_chest + +type continuation_name = + | N_KNil + | N_KCons + | N_KReturn + | N_KUndip + | N_KLoop_in + | N_KLoop_in_left + | N_KIter + | N_KList_enter_body + | N_KList_exit_body + | N_KMap_enter_body + | N_KMap_exit_body + | N_KLog + +and instr_or_cont_name = + | Instr_name of instruction_name + | Cont_name of continuation_name + +(* ------------------------------------------------------------------------- *) +(* Code that ought to be auto-generated *) + +let string_of_instruction_name : instruction_name -> string = + fun ir -> + match ir with + | N_IDrop -> "N_IDrop" + | N_IDup -> "N_IDup" + | N_ISwap -> "N_ISwap" + | N_IConst -> "N_IConst" + | N_ICons_pair -> "N_ICons_pair" + | N_ICar -> "N_ICar" + | N_ICdr -> "N_ICdr" + | N_ICons_some -> "N_ICons_some" + | N_ICons_none -> "N_ICons_none" + | N_IIf_none -> "N_IIf_none" + | N_ILeft -> "N_ILeft" + | N_IRight -> "N_IRight" + | N_IIf_left -> "N_IIf_left" + | N_ICons_list -> "N_ICons_list" + | N_INil -> "N_INil" + | N_IIf_cons -> "N_IIf_cons" + | N_IList_map -> "N_IList_map" + | N_IList_iter -> "N_IList_iter" + | N_IIter -> "N_IIter" + | N_IList_size -> "N_IList_size" + | N_IEmpty_set -> "N_IEmpty_set" + | N_ISet_iter -> "N_ISet_iter" + | N_ISet_mem -> "N_ISet_mem" + | N_ISet_update -> "N_ISet_update" + | N_ISet_size -> "N_ISet_size" + | N_IEmpty_map -> "N_IEmpty_map" + | N_IMap_map -> "N_IMap_map" + | N_IMap_iter -> "N_IMap_iter" + | N_IMap_mem -> "N_IMap_mem" + | N_IMap_get -> "N_IMap_get" + | N_IMap_update -> "N_IMap_update" + | N_IMap_size -> "N_IMap_size" + | N_IEmpty_big_map -> "N_IEmpty_big_map" + | N_IBig_map_mem -> "N_IBig_map_mem" + | N_IBig_map_get -> "N_IBig_map_get" + | N_IBig_map_update -> "N_IBig_map_update" + | N_IConcat_string -> "N_IConcat_string" + | N_IConcat_string_pair -> "N_IConcat_string_pair" + | N_ISlice_string -> "N_ISlice_string" + | N_IString_size -> "N_IString_size" + | N_IConcat_bytes -> "N_IConcat_bytes" + | N_IConcat_bytes_pair -> "N_IConcat_bytes_pair" + | N_ISlice_bytes -> "N_ISlice_bytes" + | N_IBytes_size -> "N_IBytes_size" + | N_IAdd_seconds_to_timestamp -> "N_IAdd_seconds_to_timestamp" + | N_IAdd_timestamp_to_seconds -> "N_IAdd_timestamp_to_seconds" + | N_ISub_timestamp_seconds -> "N_ISub_timestamp_seconds" + | N_IDiff_timestamps -> "N_IDiff_timestamps" + | N_IAdd_tez -> "N_IAdd_tez" + | N_ISub_tez -> "N_ISub_tez" + | N_IMul_teznat -> "N_IMul_teznat" + | N_IMul_nattez -> "N_IMul_nattez" + | N_IEdiv_teznat -> "N_IEdiv_teznat" + | N_IEdiv_tez -> "N_IEdiv_tez" + | N_IOr -> "N_IOr" + | N_IAnd -> "N_IAnd" + | N_IXor -> "N_IXor" + | N_INot -> "N_INot" + | N_IIs_nat -> "N_IIs_nat" + | N_INeg_nat -> "N_INeg_nat" + | N_INeg_int -> "N_INeg_int" + | N_IAbs_int -> "N_IAbs_int" + | N_IInt_nat -> "N_IInt_nat" + | N_IAdd_intint -> "N_IAdd_intint" + | N_IAdd_intnat -> "N_IAdd_intnat" + | N_IAdd_natint -> "N_IAdd_natint" + | N_IAdd_natnat -> "N_IAdd_natnat" + | N_ISub_int -> "N_ISub_int" + | N_IMul_intint -> "N_IMul_intint" + | N_IMul_intnat -> "N_IMul_intnat" + | N_IMul_natint -> "N_IMul_natint" + | N_IMul_natnat -> "N_IMul_natnat" + | N_IEdiv_intint -> "N_IEdiv_intint" + | N_IEdiv_intnat -> "N_IEdiv_intnat" + | N_IEdiv_natint -> "N_IEdiv_natint" + | N_IEdiv_natnat -> "N_IEdiv_natnat" + | N_ILsl_nat -> "N_ILsl_nat" + | N_ILsr_nat -> "N_ILsr_nat" + | N_IOr_nat -> "N_IOr_nat" + | N_IAnd_nat -> "N_IAnd_nat" + | N_IAnd_int_nat -> "N_IAnd_int_nat" + | N_IXor_nat -> "N_IXor_nat" + | N_INot_nat -> "N_INot_nat" + | N_INot_int -> "N_INot_int" + | N_IIf -> "N_IIf" + | N_ILoop -> "N_ILoop" + | N_ILoop_left -> "N_ILoop_left" + | N_IDip -> "N_IDip" + | N_IExec -> "N_IExec" + | N_IApply -> "N_IApply" + | N_ILambda -> "N_ILambda" + | N_IFailwith -> "N_IFailwith" + | N_ICompare -> "N_ICompare" + | N_IEq -> "N_IEq" + | N_INeq -> "N_INeq" + | N_ILt -> "N_ILt" + | N_IGt -> "N_IGt" + | N_ILe -> "N_ILe" + | N_IGe -> "N_IGe" + | N_IAddress -> "N_IAddress" + | N_IContract -> "N_IContract" + | N_ITransfer_tokens -> "N_ITransfer_tokens" + | N_IImplicit_account -> "N_IImplicit_account" + | N_ICreate_contract -> "N_ICreate_contract" + | N_ISet_delegate -> "N_ISet_delegate" + | N_INow -> "N_INow" + | N_IBalance -> "N_IBalance" + | N_ICheck_signature_ed25519 -> "N_ICheck_signature_ed25519" + | N_ICheck_signature_secp256k1 -> "N_ICheck_signature_secp256k1" + | N_ICheck_signature_p256 -> "N_ICheck_signature_p256" + | N_IHash_key -> "N_IHash_key" + | N_IPack -> "N_IPack" + | N_IUnpack -> "N_IUnpack" + | N_IBlake2b -> "N_IBlake2b" + | N_ISha256 -> "N_ISha256" + | N_ISha512 -> "N_ISha512" + | N_ISource -> "N_ISource" + | N_ISender -> "N_ISender" + | N_ISelf -> "N_ISelf" + | N_IAmount -> "N_IAmount" + | N_IDig -> "N_IDig" + | N_IDug -> "N_IDug" + | N_IDipN -> "N_IDipN" + | N_IDropN -> "N_IDropN" + | N_IDupN -> "N_IDupN" + | N_IChainId -> "N_IChainId" + | N_ILevel -> "N_ILevel" + | N_IView -> "N_IView" + | N_ISelf_address -> "N_ISelf_address" + | N_INever -> "N_INever" + | N_IUnpair -> "N_IUnpair" + | N_IVoting_power -> "N_IVoting_power" + | N_ITotal_voting_power -> "N_ITotal_voting_power" + | N_IKeccak -> "N_IKeccak" + | N_ISha3 -> "N_ISha3" + | N_IAdd_bls12_381_g1 -> "N_IAdd_bls12_381_g1" + | N_IAdd_bls12_381_g2 -> "N_IAdd_bls12_381_g2" + | N_IAdd_bls12_381_fr -> "N_IAdd_bls12_381_fr" + | N_IMul_bls12_381_g1 -> "N_IMul_bls12_381_g1" + | N_IMul_bls12_381_g2 -> "N_IMul_bls12_381_g2" + | N_IMul_bls12_381_fr -> "N_IMul_bls12_381_fr" + | N_INeg_bls12_381_g1 -> "N_INeg_bls12_381_g1" + | N_INeg_bls12_381_g2 -> "N_INeg_bls12_381_g2" + | N_INeg_bls12_381_fr -> "N_INeg_bls12_381_fr" + | N_IPairing_check_bls12_381 -> "N_IPairing_check_bls12_381" + | N_IMul_bls12_381_fr_z -> "N_IMul_bls12_381_fr_z" + | N_IMul_bls12_381_z_fr -> "N_IMul_bls12_381_z_fr" + | N_IInt_bls12_381_z_fr -> "N_IInt_bls12_381_z_fr" + | N_IComb -> "N_IComb" + | N_IUncomb -> "N_IUncomb" + | N_IComb_get -> "N_IComb_get" + | N_IComb_set -> "N_IComb_set" + | N_ITicket -> "N_ITicket" + | N_IRead_ticket -> "N_IRead_ticket" + | N_ISplit_ticket -> "N_ISplit_ticket" + | N_IJoin_tickets -> "N_IJoin_tickets" + | N_ISapling_empty_state -> "N_ISapling_empty_state" + | N_ISapling_verify_update -> "N_ISapling_verify_update" + | N_IMap_get_and_update -> "N_IMap_get_and_update" + | N_IBig_map_get_and_update -> "N_IBig_map_get_and_update" + | N_IHalt -> "N_IHalt" + | N_ILog -> "N_ILog" + | N_IOpen_chest -> "N_IOpen_chest" + +let string_of_continuation_name : continuation_name -> string = + fun c -> + match c with + | N_KNil -> "N_KNil" + | N_KCons -> "N_KCons" + | N_KReturn -> "N_KReturn" + | N_KUndip -> "N_KUndip" + | N_KLoop_in -> "N_KLoop_in" + | N_KLoop_in_left -> "N_KLoop_in_left" + | N_KIter -> "N_KIter" + | N_KList_enter_body -> "N_KList_enter_body" + | N_KList_exit_body -> "N_KList_exit_body" + | N_KMap_enter_body -> "N_KMap_enter_body" + | N_KMap_exit_body -> "N_KMap_exit_body" + | N_KLog -> "N_KLog" + +let string_of_instr_or_cont name = + match name with + | Instr_name instr_name -> string_of_instruction_name instr_name + | Cont_name cont_name -> string_of_continuation_name cont_name + +(* ------------------------------------------------------------------------- *) + +type args = arg list + +and arg = {name : id; arg : Size.t} + +let nullary : args = [] + +let unary xn x : args = [{name = xn; arg = x}] + +let binary xn x yn y : args = {name = xn; arg = x} :: unary yn y + +let ternary xn x yn y zn z : args = {name = xn; arg = x} :: binary yn y zn z + +let quaternary wn w xn x yn y zn z : args = + {name = wn; arg = w} :: ternary xn x yn y zn z + +let pp_arg fmtr {name; arg} = Format.fprintf fmtr "%s = %a" name Size.pp arg + +let pp_args fmtr args = + Format.pp_print_list + ~pp_sep:(fun fmtr () -> Format.fprintf fmtr ";") + pp_arg + fmtr + args + +type ir_sized_step = {name : instr_or_cont_name; args : args} + +type t = ir_sized_step list + +let ir_sized_step instr_name args = {name = Instr_name instr_name; args} + +let cont_sized_step cont_name args = {name = Cont_name cont_name; args} + +(* ------------------------------------------------------------------------- *) + +let all_instructions = + [ + N_IDrop; + N_IDup; + N_ISwap; + N_IConst; + N_ICons_pair; + N_ICar; + N_ICdr; + N_ICons_some; + N_ICons_none; + N_IIf_none; + N_ILeft; + N_IRight; + N_IIf_left; + N_ICons_list; + N_INil; + N_IIf_cons; + N_IList_map; + N_IList_iter; + N_IIter; + N_IList_size; + N_IEmpty_set; + N_ISet_iter; + N_ISet_mem; + N_ISet_update; + N_ISet_size; + N_IEmpty_map; + N_IMap_map; + N_IMap_iter; + N_IMap_mem; + N_IMap_get; + N_IMap_update; + N_IMap_size; + N_IEmpty_big_map; + N_IBig_map_mem; + N_IBig_map_get; + N_IBig_map_update; + N_IConcat_string; + N_IConcat_string_pair; + N_ISlice_string; + N_IString_size; + N_IConcat_bytes; + N_IConcat_bytes_pair; + N_ISlice_bytes; + N_IBytes_size; + N_IAdd_seconds_to_timestamp; + N_IAdd_timestamp_to_seconds; + N_ISub_timestamp_seconds; + N_IDiff_timestamps; + N_IAdd_tez; + N_ISub_tez; + N_IMul_teznat; + N_IMul_nattez; + N_IEdiv_teznat; + N_IEdiv_tez; + N_IOr; + N_IAnd; + N_IXor; + N_INot; + N_IIs_nat; + N_INeg_nat; + N_INeg_int; + N_IAbs_int; + N_IInt_nat; + N_IAdd_intint; + N_IAdd_intnat; + N_IAdd_natint; + N_IAdd_natnat; + N_ISub_int; + N_IMul_intint; + N_IMul_intnat; + N_IMul_natint; + N_IMul_natnat; + N_IEdiv_intint; + N_IEdiv_intnat; + N_IEdiv_natint; + N_IEdiv_natnat; + N_ILsl_nat; + N_ILsr_nat; + N_IOr_nat; + N_IAnd_nat; + N_IAnd_int_nat; + N_IXor_nat; + N_INot_nat; + N_INot_int; + N_IIf; + N_ILoop; + N_ILoop_left; + N_IDip; + N_IExec; + N_IApply; + N_ILambda; + N_IFailwith; + N_ICompare; + N_IEq; + N_INeq; + N_ILt; + N_IGt; + N_ILe; + N_IGe; + N_IAddress; + N_IContract; + N_ITransfer_tokens; + N_IImplicit_account; + N_ICreate_contract; + N_ISet_delegate; + N_INow; + N_IBalance; + N_ICheck_signature_ed25519; + N_ICheck_signature_secp256k1; + N_ICheck_signature_p256; + N_IHash_key; + N_IPack; + N_IUnpack; + N_IBlake2b; + N_ISha256; + N_ISha512; + N_ISource; + N_ISender; + N_ISelf; + N_IAmount; + N_IDig; + N_IDug; + N_IDipN; + N_IDropN; + N_IDupN; + N_IChainId; + N_ILevel; + N_IView; + N_ISelf_address; + N_INever; + N_IUnpair; + N_IVoting_power; + N_ITotal_voting_power; + N_IKeccak; + N_ISha3; + N_IAdd_bls12_381_g1; + N_IAdd_bls12_381_g2; + N_IAdd_bls12_381_fr; + N_IMul_bls12_381_g1; + N_IMul_bls12_381_g2; + N_IMul_bls12_381_fr; + N_INeg_bls12_381_g1; + N_INeg_bls12_381_g2; + N_INeg_bls12_381_fr; + N_IPairing_check_bls12_381; + N_IMul_bls12_381_fr_z; + N_IMul_bls12_381_z_fr; + N_IInt_bls12_381_z_fr; + N_IComb; + N_IUncomb; + N_IComb_get; + N_IComb_set; + N_ITicket; + N_IRead_ticket; + N_ISplit_ticket; + N_IJoin_tickets; + N_ISapling_empty_state; + N_ISapling_verify_update; + N_IMap_get_and_update; + N_IBig_map_get_and_update; + N_IHalt; + N_ILog; + N_IOpen_chest; + ] + +let all_continuations = + [ + N_KNil; + N_KCons; + N_KReturn; + N_KUndip; + N_KLoop_in; + N_KLoop_in_left; + N_KIter; + N_KList_enter_body; + N_KList_exit_body; + N_KMap_enter_body; + N_KMap_exit_body; + N_KLog; + ] + +let instruction_name_encoding = + let open Data_encoding in + def "instruction_name_encoding" + @@ string_enum + (List.map + (fun instr_name -> + (string_of_instruction_name instr_name, instr_name)) + all_instructions) + +let continuation_name_encoding = + let open Data_encoding in + def "continuation_name_encoding" + @@ string_enum + (List.map + (fun cont_name -> (string_of_continuation_name cont_name, cont_name)) + all_continuations) + +let args_encoding = + let open Data_encoding in + def "args_encoding" + @@ list + (conv + (fun {name; arg} -> (name, arg)) + (fun (name, arg) -> {name; arg}) + (tup2 string Size.encoding)) + +let instr_or_cont_name_encoding = + let open Data_encoding in + def "instr_or_cont_name" + @@ union + [ + case + ~title:"instr_name" + (Tag 0) + instruction_name_encoding + (function Instr_name name -> Some name | _ -> None) + (fun name -> Instr_name name); + case + ~title:"cont_name" + (Tag 1) + continuation_name_encoding + (function Cont_name name -> Some name | _ -> None) + (fun name -> Cont_name name); + ] + +let ir_sized_step_encoding = + let open Data_encoding in + def "ir_sized_step_encoding" + @@ conv + (fun {name; args} -> (name, args)) + (fun (name, args) -> {name; args}) + (tup2 instr_or_cont_name_encoding args_encoding) + +let encoding = + let open Data_encoding in + def "interpreter_trace_encoding" @@ list ir_sized_step_encoding + +(* ------------------------------------------------------------------------- *) + +module Instructions = struct + let drop = ir_sized_step N_IDrop nullary + + let dup = ir_sized_step N_IDup nullary + + let swap = ir_sized_step N_ISwap nullary + + let const = ir_sized_step N_IConst nullary + + let cons_pair = ir_sized_step N_ICons_pair nullary + + let car = ir_sized_step N_ICar nullary + + let cdr = ir_sized_step N_ICdr nullary + + let cons_some = ir_sized_step N_ICons_some nullary + + let cons_none = ir_sized_step N_ICons_none nullary + + let if_none = ir_sized_step N_IIf_none nullary + + let left = ir_sized_step N_ILeft nullary + + let right = ir_sized_step N_IRight nullary + + let if_left = ir_sized_step N_IIf_left nullary + + let cons_list = ir_sized_step N_ICons_list nullary + + let nil = ir_sized_step N_INil nullary + + let if_cons = ir_sized_step N_IIf_cons nullary + + let list_map = ir_sized_step N_IList_map nullary + + let list_iter = ir_sized_step N_IList_iter nullary + + let iter = ir_sized_step N_IIter nullary + + let list_size _list = ir_sized_step N_IList_size nullary + + let empty_set = ir_sized_step N_IEmpty_set nullary + + let set_iter set = ir_sized_step N_ISet_iter (unary "set" set) + + let set_mem elt set = ir_sized_step N_ISet_mem (binary "elt" elt "set" set) + + let set_update elt set = + ir_sized_step N_ISet_update (binary "elt" elt "set" set) + + let set_size _set = ir_sized_step N_ISet_size nullary + + let empty_map = ir_sized_step N_IEmpty_map nullary + + let map_map map = ir_sized_step N_IMap_map (unary "map" map) + + let map_iter map = ir_sized_step N_IMap_iter (unary "map" map) + + let map_mem key map = ir_sized_step N_IMap_mem (binary "key" key "map" map) + + let map_get key map = ir_sized_step N_IMap_get (binary "key" key "map" map) + + let map_update key map = + ir_sized_step N_IMap_update (binary "key" key "map" map) + + let map_size _map = ir_sized_step N_IMap_size nullary + + let empty_big_map = ir_sized_step N_IEmpty_big_map nullary + + let big_map_mem key big_map = + ir_sized_step N_IBig_map_mem (binary "key" key "big_map" big_map) + + let big_map_get key big_map = + ir_sized_step N_IBig_map_get (binary "key" key "big_map" big_map) + + let big_map_update key big_map = + ir_sized_step N_IBig_map_update (binary "key" key "big_map" big_map) + + let big_map_get_and_update key big_map = + ir_sized_step N_IBig_map_get_and_update (binary "key" key "big_map" big_map) + + let concat_string total_bytes list = + ir_sized_step + N_IConcat_string + (binary "total_bytes" total_bytes "list" list) + + let concat_string_pair str1 str2 = + ir_sized_step N_IConcat_string_pair (binary "str1" str1 "str2" str2) + + let slice_string string = + ir_sized_step N_ISlice_string (unary "string" string) + + let string_size _string = ir_sized_step N_IString_size nullary + + let concat_bytes total_bytes list = + ir_sized_step N_IConcat_bytes (binary "total_bytes" total_bytes "list" list) + + let concat_bytes_pair str1 str2 = + ir_sized_step N_IConcat_bytes_pair (binary "str1" str1 "str2" str2) + + let slice_bytes bytes = ir_sized_step N_ISlice_bytes (unary "bytes" bytes) + + let bytes_size = ir_sized_step N_IBytes_size nullary + + let add_seconds_to_timestamp seconds tstamp = + ir_sized_step + N_IAdd_seconds_to_timestamp + (binary "seconds" seconds "tstamp" tstamp) + + let add_timestamp_to_seconds tstamp seconds = + ir_sized_step + N_IAdd_timestamp_to_seconds + (binary "tstamp" tstamp "seconds" seconds) + + let sub_timestamp_seconds tstamp seconds = + ir_sized_step + N_ISub_timestamp_seconds + (binary "tstamp" tstamp "seconds" seconds) + + let diff_timestamps tstamp1 tstamp2 = + ir_sized_step + N_IDiff_timestamps + (binary "tstamp1" tstamp1 "tstamp2" tstamp2) + + let add_tez _tez1 _tez2 = ir_sized_step N_IAdd_tez nullary + + let sub_tez _tez1 _tez2 = ir_sized_step N_ISub_tez nullary + + let mul_teznat _tez nat = ir_sized_step N_IMul_teznat (unary "nat" nat) + + let mul_nattez nat _tez = ir_sized_step N_IMul_nattez (unary "nat" nat) + + let ediv_teznat tez nat = + ir_sized_step N_IEdiv_teznat (binary "tez" tez "nat" nat) + + let ediv_tez _tez1 _tez2 = ir_sized_step N_IEdiv_tez nullary + + let or_ = ir_sized_step N_IOr nullary + + let and_ = ir_sized_step N_IAnd nullary + + let xor_ = ir_sized_step N_IXor nullary + + let not_ = ir_sized_step N_INot nullary + + let is_nat _int = ir_sized_step N_IIs_nat nullary + + let neg_nat nat = ir_sized_step N_INeg_nat (unary "nat" nat) + + let neg_int int = ir_sized_step N_INeg_int (unary "int" int) + + let abs_int int = ir_sized_step N_IAbs_int (unary "int" int) + + let int_nat _nat = ir_sized_step N_IInt_nat nullary + + let add_intint int1 int2 = + ir_sized_step N_IAdd_intint (binary "int1" int1 "int2" int2) + + let add_intnat int nat = + ir_sized_step N_IAdd_intnat (binary "int" int "nat" nat) + + let add_natint nat int = + ir_sized_step N_IAdd_natint (binary "nat" nat "int" int) + + let add_natnat nat1 nat2 = + ir_sized_step N_IAdd_natnat (binary "nat1" nat1 "nat2" nat2) + + let sub_int int1 int2 = + ir_sized_step N_ISub_int (binary "int1" int1 "int2" int2) + + let mul_intint int1 int2 = + ir_sized_step N_IMul_intint (binary "int1" int1 "int2" int2) + + let mul_intnat int nat = + ir_sized_step N_IMul_intnat (binary "int" int "nat" nat) + + let mul_natint nat int = + ir_sized_step N_IMul_natint (binary "nat" nat "int" int) + + let mul_natnat nat1 nat2 = + ir_sized_step N_IMul_natnat (binary "nat1" nat1 "nat2" nat2) + + let ediv_intint int1 int2 = + ir_sized_step N_IEdiv_intint (binary "int1" int1 "int2" int2) + + let ediv_intnat int nat = + ir_sized_step N_IEdiv_intnat (binary "int" int "nat" nat) + + let ediv_natint nat int = + ir_sized_step N_IEdiv_natint (binary "nat" nat "int" int) + + let ediv_natnat nat1 nat2 = + ir_sized_step N_IEdiv_natnat (binary "nat1" nat1 "nat2" nat2) + + let lsl_nat nat1 _shift = ir_sized_step N_ILsl_nat (unary "nat" nat1) + + let lsr_nat nat1 _shift = ir_sized_step N_ILsr_nat (unary "nat" nat1) + + let or_nat nat1 nat2 = + ir_sized_step N_IOr_nat (binary "nat1" nat1 "nat2" nat2) + + let and_nat nat1 nat2 = + ir_sized_step N_IAnd_nat (binary "nat1" nat1 "nat2" nat2) + + let and_int_nat int nat = + ir_sized_step N_IAnd_int_nat (binary "int" int "nat" nat) + + let xor_nat nat1 nat2 = + ir_sized_step N_IXor_nat (binary "nat1" nat1 "nat2" nat2) + + let not_nat nat = ir_sized_step N_INot_nat (unary "nat" nat) + + let not_int int = ir_sized_step N_INot_int (unary "int" int) + + let if_ = ir_sized_step N_IIf nullary + + let loop = ir_sized_step N_ILoop nullary + + let loop_left = ir_sized_step N_ILoop_left nullary + + let dip = ir_sized_step N_IDip nullary + + let exec = ir_sized_step N_IExec nullary + + let apply = ir_sized_step N_IApply nullary + + let lambda = ir_sized_step N_ILambda nullary + + let failwith_ = ir_sized_step N_IFailwith nullary + + let compare arg1 arg2 = + ir_sized_step N_ICompare (binary "arg1" arg1 "arg2" arg2) + + let eq = ir_sized_step N_IEq nullary + + let neq = ir_sized_step N_INeq nullary + + let lt = ir_sized_step N_ILt nullary + + let gt = ir_sized_step N_IGt nullary + + let le = ir_sized_step N_ILe nullary + + let ge = ir_sized_step N_IGe nullary + + let address = ir_sized_step N_IAddress nullary + + let contract = ir_sized_step N_IContract nullary + + let transfer_tokens = ir_sized_step N_ITransfer_tokens nullary + + let implicit_account = ir_sized_step N_IImplicit_account nullary + + let create_contract = ir_sized_step N_ICreate_contract nullary + + let set_delegate = ir_sized_step N_ISet_delegate nullary + + let now = ir_sized_step N_INow nullary + + let balance = ir_sized_step N_IBalance nullary + + let check_signature_ed25519 _pk _signature message = + ir_sized_step N_ICheck_signature_ed25519 (unary "message" message) + + let check_signature_secp256k1 _pk _signature message = + ir_sized_step N_ICheck_signature_secp256k1 (unary "message" message) + + let check_signature_p256 _pk _signature message = + ir_sized_step N_ICheck_signature_p256 (unary "message" message) + + let hash_key = ir_sized_step N_IHash_key nullary + + let pack (micheline_size : Size.micheline_size) = + ir_sized_step + N_IPack + (ternary + "micheline_nodes" + micheline_size.traversal + "micheline_int_bytes" + micheline_size.int_bytes + "micheline_string_bytes" + micheline_size.string_bytes) + + let unpack = ir_sized_step N_IUnpack nullary + + let blake2b bytes = ir_sized_step N_IBlake2b (unary "bytes" bytes) + + let sha256 bytes = ir_sized_step N_ISha256 (unary "bytes" bytes) + + let sha512 bytes = ir_sized_step N_ISha512 (unary "bytes" bytes) + + let source = ir_sized_step N_ISource nullary + + let sender = ir_sized_step N_ISender nullary + + let self = ir_sized_step N_ISelf nullary + + let amount = ir_sized_step N_IAmount nullary + + let dig depth = ir_sized_step N_IDig (unary "depth" depth) + + let dug depth = ir_sized_step N_IDug (unary "depth" depth) + + let dipn depth = ir_sized_step N_IDipN (unary "depth" depth) + + let dropn depth = ir_sized_step N_IDropN (unary "depth" depth) + + let dupn depth = ir_sized_step N_IDupN (unary "depth" depth) + + let chain_id = ir_sized_step N_IChainId nullary + + let level = ir_sized_step N_ILevel nullary + + let view = ir_sized_step N_IView nullary + + let self_address = ir_sized_step N_ISelf_address nullary + + let never = ir_sized_step N_INever nullary + + let unpair = ir_sized_step N_IUnpair nullary + + let voting_power = ir_sized_step N_IVoting_power nullary + + let total_voting_power = ir_sized_step N_ITotal_voting_power nullary + + let keccak bytes = ir_sized_step N_IKeccak (unary "bytes" bytes) + + let sha3 bytes = ir_sized_step N_ISha3 (unary "bytes" bytes) + + let add_bls12_381_g1 = ir_sized_step N_IAdd_bls12_381_g1 nullary + + let add_bls12_381_g2 = ir_sized_step N_IAdd_bls12_381_g2 nullary + + let add_bls12_381_fr = ir_sized_step N_IAdd_bls12_381_fr nullary + + let mul_bls12_381_g1 = ir_sized_step N_IMul_bls12_381_g1 nullary + + let mul_bls12_381_g2 = ir_sized_step N_IMul_bls12_381_g2 nullary + + let mul_bls12_381_fr = ir_sized_step N_IMul_bls12_381_fr nullary + + let neg_bls12_381_g1 = ir_sized_step N_INeg_bls12_381_g1 nullary + + let neg_bls12_381_g2 = ir_sized_step N_INeg_bls12_381_g2 nullary + + let neg_bls12_381_fr = ir_sized_step N_INeg_bls12_381_fr nullary + + let pairing_check_bls12_381 length = + ir_sized_step N_IPairing_check_bls12_381 (unary "length" length) + + let mul_bls12_381_fr_z nat = + ir_sized_step N_IMul_bls12_381_fr_z (unary "nat" nat) + + let mul_bls12_381_z_fr nat = + ir_sized_step N_IMul_bls12_381_z_fr (unary "nat" nat) + + let int_bls12_381_z_fr = ir_sized_step N_IInt_bls12_381_z_fr nullary + + let comb depth = ir_sized_step N_IComb (unary "depth" depth) + + let uncomb depth = ir_sized_step N_IUncomb (unary "depth" depth) + + let comb_get key = ir_sized_step N_IComb_get (unary "key" key) + + let comb_set key = ir_sized_step N_IComb_set (unary "key" key) + + let ticket = ir_sized_step N_ITicket nullary + + let read_ticket = ir_sized_step N_IRead_ticket nullary + + let split_ticket nat1 nat2 = + ir_sized_step N_ISplit_ticket (binary "nat1" nat1 "nat2" nat2) + + let join_tickets size1 size2 size3 size4 = + ir_sized_step + N_IJoin_tickets + (quaternary + "contents1" + size1 + "contents2" + size2 + "amount1" + size3 + "amount2" + size4) + + let sapling_empty_state = ir_sized_step N_ISapling_empty_state nullary + + let sapling_verify_update inputs outputs _state = + ir_sized_step + N_ISapling_verify_update + (binary "inputs" inputs "outputs" outputs) + + let map_get_and_update key_size map_size = + ir_sized_step + N_IMap_get_and_update + (binary "key_size" key_size "map_size" map_size) + + let halt = ir_sized_step N_IHalt nullary + + let log = ir_sized_step N_ILog nullary + + let open_chest log_time size = + ir_sized_step N_IOpen_chest (binary "log_time" log_time "size" size) +end + +module Control = struct + let nil = cont_sized_step N_KNil nullary + + let cons = cont_sized_step N_KCons nullary + + let return = cont_sized_step N_KReturn nullary + + let undip = cont_sized_step N_KUndip nullary + + let loop_in = cont_sized_step N_KLoop_in nullary + + let loop_in_left = cont_sized_step N_KLoop_in_left nullary + + let iter size = cont_sized_step N_KIter (unary "size" size) + + let list_enter_body xs_size ys_size = + cont_sized_step + N_KList_enter_body + (binary "xs_size" xs_size "ys_size" ys_size) + + let list_exit_body = cont_sized_step N_KList_exit_body nullary + + let map_enter_body size = + cont_sized_step N_KMap_enter_body (unary "size" size) + + let map_exit_body key_size map_size = + cont_sized_step N_KMap_exit_body (binary "key" key_size "map" map_size) + + let log = cont_sized_step N_KLog nullary +end + +(* ------------------------------------------------------------------------- *) + +open Script_typed_ir + +let rec size_of_comparable_value : type a. a comparable_ty -> a -> Size.t = + fun (type a) (wit : a comparable_ty) (v : a) -> + match wit with + | Never_key _ -> Size.zero + | Unit_key _ -> Size.unit + | Int_key _ -> Size.integer v + | Nat_key _ -> Size.integer v + | String_key _ -> Size.string v + | Bytes_key _ -> Size.bytes v + | Mutez_key _ -> Size.mutez v + | Bool_key _ -> Size.bool v + | Key_hash_key _ -> Size.key_hash v + | Timestamp_key _ -> Size.timestamp v + | Address_key _ -> Size.address v + | Pair_key ((leaf, _), (node, _), _) -> + let (lv, rv) = v in + let size = + Size.add + (size_of_comparable_value leaf lv) + (size_of_comparable_value node rv) + in + Size.add size Size.one + | Union_key ((left, _), (right, _), _) -> + let size = + match v with + | L v -> size_of_comparable_value left v + | R v -> size_of_comparable_value right v + in + Size.add size Size.one + | Option_key (ty, _) -> ( + match v with + | None -> Size.one + | Some x -> Size.add (size_of_comparable_value ty x) Size.one) + | Signature_key _ -> Size.signature v + | Key_key _ -> Size.public_key v + | Chain_id_key _ -> Size.chain_id v + +let extract_compare_sized_step : + type a. a comparable_ty -> a -> a -> ir_sized_step = + fun comparable_ty x y -> + Instructions.compare + (size_of_comparable_value comparable_ty x) + (size_of_comparable_value comparable_ty y) + +let extract_ir_sized_step : + type bef_top bef res_top res. + Alpha_context.t -> + (bef_top, bef, res_top, res) Script_typed_ir.kinstr -> + bef_top * bef -> + ir_sized_step = + fun ctxt instr stack -> + let open Script_typed_ir in + match (instr, stack) with + | (IDrop (_, _), _) -> Instructions.drop + | (IDup (_, _), _) -> Instructions.dup + | (ISwap (_, _), _) -> Instructions.swap + | (IConst (_, _, _), _) -> Instructions.const + | (ICons_pair (_, _), _) -> Instructions.cons_pair + | (ICar (_, _), _) -> Instructions.car + | (ICdr (_, _), _) -> Instructions.cdr + | (IUnpair (_, _), _) -> Instructions.unpair + | (ICons_some (_, _), _) -> Instructions.cons_some + | (ICons_none (_, _), _) -> Instructions.cons_none + | (IIf_none _, _) -> Instructions.if_none + | (ICons_left (_, _), _) -> Instructions.left + | (ICons_right (_, _), _) -> Instructions.right + | (IIf_left _, _) -> Instructions.if_left + | (ICons_list (_, _), _) -> Instructions.cons_list + | (INil (_, _), _) -> Instructions.nil + | (IIf_cons _, _) -> Instructions.if_cons + | (IList_iter (_, _, _), _) -> Instructions.list_iter + | (IList_map (_, _, _), _) -> Instructions.list_map + | (IList_size (_, _), (list, _)) -> Instructions.list_size (Size.list list) + | (IEmpty_set (_, _, _), _) -> Instructions.empty_set + | (ISet_iter _, (set, _)) -> Instructions.set_iter (Size.set set) + | (ISet_mem (_, _), (v, (set, _))) -> + let (module S) = set in + let sz = size_of_comparable_value S.elt_ty v in + Instructions.set_mem sz (Size.set set) + | (ISet_update (_, _), (v, (_flag, (set, _)))) -> + let (module S) = set in + let sz = size_of_comparable_value S.elt_ty v in + Instructions.set_update sz (Size.set set) + | (ISet_size (_, _), (set, _)) -> Instructions.set_size (Size.set set) + | (IEmpty_map (_, _, _), _) -> Instructions.empty_map + | (IMap_map _, (map, _)) -> Instructions.map_map (Size.map map) + | (IMap_iter _, (map, _)) -> Instructions.map_iter (Size.map map) + | (IMap_mem (_, _), (v, (((module Map) as map), _))) -> + let key_size = size_of_comparable_value Map.key_ty v in + Instructions.map_mem key_size (Size.map map) + | (IMap_get (_, _), (v, (((module Map) as map), _))) -> + let key_size = size_of_comparable_value Map.key_ty v in + Instructions.map_get key_size (Size.map map) + | (IMap_update (_, _), (v, (_elt_opt, (((module Map) as map), _)))) -> + let key_size = size_of_comparable_value Map.key_ty v in + Instructions.map_update key_size (Size.map map) + | (IMap_get_and_update (_, _), (v, (_elt_opt, (((module Map) as map), _)))) -> + let key_size = size_of_comparable_value Map.key_ty v in + Instructions.map_get_and_update key_size (Size.map map) + | (IMap_size (_, _), (map, _)) -> Instructions.map_size (Size.map map) + | (IEmpty_big_map (_, _, _, _), _) -> Instructions.empty_big_map + | (IBig_map_mem (_, _), (v, ({diff = {size; _}; key_type; _}, _))) -> + let key_size = size_of_comparable_value key_type v in + Instructions.big_map_mem key_size size + | (IBig_map_get (_, _), (v, ({diff = {size; _}; key_type; _}, _))) -> + let key_size = size_of_comparable_value key_type v in + Instructions.big_map_get key_size size + | (IBig_map_update (_, _), (v, (_, ({diff = {size; _}; key_type; _}, _)))) -> + let key_size = size_of_comparable_value key_type v in + Instructions.big_map_update key_size size + | ( IBig_map_get_and_update (_, _), + (v, (_, ({diff = {size; _}; key_type; _}, _))) ) -> + let key_size = size_of_comparable_value key_type v in + Instructions.big_map_get_and_update key_size size + | (IConcat_string (_, _), (ss, _)) -> + let list_size = Size.list ss in + let total_bytes = + List.fold_left + (fun x s -> Size.(add x (string s))) + Size.zero + ss.elements + in + Instructions.concat_string list_size total_bytes + | (IConcat_string_pair (_, _), (s1, (s2, _))) -> + Instructions.concat_string_pair (Size.string s1) (Size.string s2) + | (ISlice_string (_, _), (_off, (_len, (s, _)))) -> + Instructions.slice_string (Size.string s) + | (IString_size (_, _), (s, _)) -> Instructions.string_size (Size.string s) + | (IConcat_bytes (_, _), (ss, _)) -> + let list_size = Size.list ss in + let total_bytes = + List.fold_left (fun x s -> Size.(add x (bytes s))) Size.zero ss.elements + in + Instructions.concat_bytes list_size total_bytes + | (IConcat_bytes_pair (_, _), (s1, (s2, _))) -> + Instructions.concat_bytes_pair (Size.bytes s1) (Size.bytes s2) + | (ISlice_bytes (_, _), (_off, (_len, (s, _)))) -> + Instructions.slice_bytes (Size.bytes s) + | (IBytes_size (_, _), _) -> Instructions.bytes_size + | (IAdd_seconds_to_timestamp (_, _), (s, (t, _))) -> + Instructions.add_seconds_to_timestamp (Size.timestamp t) (Size.integer s) + | (IAdd_timestamp_to_seconds (_, _), (t, (s, _))) -> + Instructions.add_timestamp_to_seconds (Size.timestamp t) (Size.integer s) + | (ISub_timestamp_seconds (_, _), (t, (s, _))) -> + Instructions.sub_timestamp_seconds (Size.timestamp t) (Size.integer s) + | (IDiff_timestamps (_, _), (t1, (t2, _))) -> + Instructions.diff_timestamps (Size.timestamp t1) (Size.timestamp t2) + | (IAdd_tez (_, _), (x, (y, _))) -> + Instructions.add_tez (Size.mutez x) (Size.mutez y) + | (ISub_tez (_, _), (x, (y, _))) -> + Instructions.sub_tez (Size.mutez x) (Size.mutez y) + | (IMul_teznat (_, _), (x, (y, _))) -> + Instructions.mul_teznat (Size.mutez x) (Size.integer y) + | (IMul_nattez (_, _), (x, (y, _))) -> + Instructions.mul_nattez (Size.integer x) (Size.mutez y) + | (IEdiv_teznat (_, _), (x, (y, _))) -> + Instructions.ediv_teznat (Size.mutez x) (Size.integer y) + | (IEdiv_tez (_, _), (x, (y, _))) -> + Instructions.ediv_tez (Size.mutez x) (Size.mutez y) + | (IOr (_, _), _) -> Instructions.or_ + | (IAnd (_, _), _) -> Instructions.and_ + | (IXor (_, _), _) -> Instructions.xor_ + | (INot (_, _), _) -> Instructions.not_ + | (IIs_nat (_, _), (x, _)) -> Instructions.is_nat (Size.integer x) + | (INeg_nat (_, _), (x, _)) -> Instructions.neg_nat (Size.integer x) + | (INeg_int (_, _), (x, _)) -> Instructions.neg_int (Size.integer x) + | (IAbs_int (_, _), (x, _)) -> Instructions.abs_int (Size.integer x) + | (IInt_nat (_, _), (x, _)) -> Instructions.int_nat (Size.integer x) + | (IAdd_intint (_, _), (x, (y, _))) -> + Instructions.add_intint (Size.integer x) (Size.integer y) + | (IAdd_intnat (_, _), (x, (y, _))) -> + Instructions.add_intnat (Size.integer x) (Size.integer y) + | (IAdd_natint (_, _), (x, (y, _))) -> + Instructions.add_natint (Size.integer x) (Size.integer y) + | (IAdd_natnat (_, _), (x, (y, _))) -> + Instructions.add_natnat (Size.integer x) (Size.integer y) + | (ISub_int (_, _), (x, (y, _))) -> + Instructions.sub_int (Size.integer x) (Size.integer y) + | (IMul_intint (_, _), (x, (y, _))) -> + Instructions.mul_intint (Size.integer x) (Size.integer y) + | (IMul_intnat (_, _), (x, (y, _))) -> + Instructions.mul_intnat (Size.integer x) (Size.integer y) + | (IMul_natint (_, _), (x, (y, _))) -> + Instructions.mul_natint (Size.integer x) (Size.integer y) + | (IMul_natnat (_, _), (x, (y, _))) -> + Instructions.mul_natnat (Size.integer x) (Size.integer y) + | (IEdiv_intint (_, _), (x, (y, _))) -> + Instructions.ediv_intint (Size.integer x) (Size.integer y) + | (IEdiv_intnat (_, _), (x, (y, _))) -> + Instructions.ediv_intnat (Size.integer x) (Size.integer y) + | (IEdiv_natint (_, _), (x, (y, _))) -> + Instructions.ediv_natint (Size.integer x) (Size.integer y) + | (IEdiv_natnat (_, _), (x, (y, _))) -> + Instructions.ediv_natnat (Size.integer x) (Size.integer y) + | (ILsl_nat (_, _), (x, (y, _))) -> + Instructions.lsl_nat (Size.integer x) (Size.integer y) + | (ILsr_nat (_, _), (x, (y, _))) -> + Instructions.lsr_nat (Size.integer x) (Size.integer y) + | (IOr_nat (_, _), (x, (y, _))) -> + Instructions.or_nat (Size.integer x) (Size.integer y) + | (IAnd_nat (_, _), (x, (y, _))) -> + Instructions.and_nat (Size.integer x) (Size.integer y) + | (IAnd_int_nat (_, _), (x, (y, _))) -> + Instructions.and_int_nat (Size.integer x) (Size.integer y) + | (IXor_nat (_, _), (x, (y, _))) -> + Instructions.xor_nat (Size.integer x) (Size.integer y) + | (INot_nat (_, _), (x, _)) -> Instructions.not_nat (Size.integer x) + | (INot_int (_, _), (x, _)) -> Instructions.not_int (Size.integer x) + | (IIf _, _) -> Instructions.if_ + | (ILoop (_, _, _), _) -> Instructions.loop + | (ILoop_left (_, _, _), _) -> Instructions.loop_left + | (IDip (_, _, _), _) -> Instructions.dip + | (IExec (_, _), _) -> Instructions.exec + | (IApply (_, _, _), _) -> Instructions.apply + | (ILambda (_, _, _), _) -> Instructions.lambda + | (IFailwith (_, _, _), _) -> Instructions.failwith_ + | (ICompare (_, cmp_ty, _), (a, (b, _))) -> + extract_compare_sized_step cmp_ty a b + | (IEq (_, _), _) -> Instructions.eq + | (INeq (_, _), _) -> Instructions.neq + | (ILt (_, _), _) -> Instructions.lt + | (IGt (_, _), _) -> Instructions.gt + | (ILe (_, _), _) -> Instructions.le + | (IGe (_, _), _) -> Instructions.ge + | (IAddress (_, _), _) -> Instructions.address + | (IContract (_, _, _, _), _) -> Instructions.contract + | (ITransfer_tokens (_, _), _) -> Instructions.transfer_tokens + | (IView (_, _, _), _) -> Instructions.view + | (IImplicit_account (_, _), _) -> Instructions.implicit_account + | (ICreate_contract _, _) -> Instructions.create_contract + | (ISet_delegate (_, _), _) -> Instructions.set_delegate + | (INow (_, _), _) -> Instructions.now + | (IBalance (_, _), _) -> Instructions.balance + | (ILevel (_, _), _) -> Instructions.level + | (ICheck_signature (_, _), (public_key, (_signature, (message, _)))) -> ( + match public_key with + | Signature.Ed25519 _pk -> + let pk = Size.of_int Ed25519.size in + let signature = Size.of_int Signature.size in + let message = Size.bytes message in + Instructions.check_signature_ed25519 pk signature message + | Signature.Secp256k1 _pk -> + let pk = Size.of_int Secp256k1.size in + let signature = Size.of_int Signature.size in + let message = Size.bytes message in + Instructions.check_signature_secp256k1 pk signature message + | Signature.P256 _pk -> + let pk = Size.of_int P256.size in + let signature = Size.of_int Signature.size in + let message = Size.bytes message in + Instructions.check_signature_p256 pk signature message) + | (IHash_key (_, _), _) -> Instructions.hash_key + | (IPack (_, ty, _), (v, _)) -> + let encoding_size = Size.of_encoded_value ctxt ty v in + Instructions.pack encoding_size + | (IUnpack (_, _, _), _) -> Instructions.unpack + | (IBlake2b (_, _), (bytes, _)) -> Instructions.blake2b (Size.bytes bytes) + | (ISha256 (_, _), (bytes, _)) -> Instructions.sha256 (Size.bytes bytes) + | (ISha512 (_, _), (bytes, _)) -> Instructions.sha512 (Size.bytes bytes) + | (ISource (_, _), _) -> Instructions.source + | (ISender (_, _), _) -> Instructions.sender + | (ISelf (_, _, _, _), _) -> Instructions.self + | (ISelf_address (_, _), _) -> Instructions.self_address + | (IAmount (_, _), _) -> Instructions.amount + | (ISapling_empty_state (_, _, _), _) -> Instructions.sapling_empty_state + | (ISapling_verify_update (_, _), (transaction, (_state, _))) -> + let inputs = Size.sapling_transaction_inputs transaction in + let outputs = Size.sapling_transaction_outputs transaction in + let state = Size.zero in + Instructions.sapling_verify_update inputs outputs state + | (IDig (_, n, _, _), _) -> Instructions.dig n + | (IDug (_, n, _, _), _) -> Instructions.dug n + | (IDipn (_, n, _, _, _), _) -> Instructions.dipn n + | (IDropn (_, n, _, _), _) -> Instructions.dropn n + | (IChainId (_, _), _) -> Instructions.chain_id + | (INever _, _) -> . + | (IVoting_power (_, _), _) -> Instructions.voting_power + | (ITotal_voting_power (_, _), _) -> Instructions.total_voting_power + | (IKeccak (_, _), (bytes, _)) -> Instructions.keccak (Size.bytes bytes) + | (ISha3 (_, _), (bytes, _)) -> Instructions.sha3 (Size.bytes bytes) + | (IAdd_bls12_381_g1 (_, _), _) -> Instructions.add_bls12_381_g1 + | (IAdd_bls12_381_g2 (_, _), _) -> Instructions.add_bls12_381_g2 + | (IAdd_bls12_381_fr (_, _), _) -> Instructions.add_bls12_381_fr + | (IMul_bls12_381_g1 (_, _), _) -> Instructions.mul_bls12_381_g1 + | (IMul_bls12_381_g2 (_, _), _) -> Instructions.mul_bls12_381_g2 + | (IMul_bls12_381_fr (_, _), _) -> Instructions.mul_bls12_381_fr + | (IMul_bls12_381_z_fr (_, _), (_fr, (z, _))) -> + Instructions.mul_bls12_381_z_fr (Size.integer z) + | (IMul_bls12_381_fr_z (_, _), (z, _)) -> + Instructions.mul_bls12_381_fr_z (Size.integer z) + | (IInt_bls12_381_fr (_, _), _) -> Instructions.int_bls12_381_z_fr + | (INeg_bls12_381_g1 (_, _), _) -> Instructions.neg_bls12_381_g1 + | (INeg_bls12_381_g2 (_, _), _) -> Instructions.neg_bls12_381_g2 + | (INeg_bls12_381_fr (_, _), _) -> Instructions.neg_bls12_381_fr + | (IPairing_check_bls12_381 (_, _), (list, _)) -> + Instructions.pairing_check_bls12_381 (Size.list list) + | (IComb (_, n, _, _), _) -> Instructions.comb (Size.of_int n) + | (IUncomb (_, n, _, _), _) -> Instructions.uncomb (Size.of_int n) + | (IComb_get (_, n, _, _), _) -> Instructions.comb_get (Size.of_int n) + | (IComb_set (_, n, _, _), _) -> Instructions.comb_set (Size.of_int n) + | (IDup_n (_, n, _, _), _) -> Instructions.dupn (Size.of_int n) + | (ITicket (_, _), _) -> Instructions.ticket + | (IRead_ticket (_, _), _) -> Instructions.read_ticket + | (ISplit_ticket (_, _), (_ticket, ((amount_a, amount_b), _))) -> + Instructions.split_ticket (Size.integer amount_a) (Size.integer amount_b) + | (IJoin_tickets (_, cmp_ty, _), ((ticket1, ticket2), _)) -> + let size1 = size_of_comparable_value cmp_ty ticket1.contents in + let size2 = size_of_comparable_value cmp_ty ticket2.contents in + let tez1 = Size.integer ticket1.amount in + let tez2 = Size.integer ticket2.amount in + Instructions.join_tickets size1 size2 tez1 tez2 + | (IHalt _, _) -> Instructions.halt + | (ILog _, _) -> Instructions.log + | (IOpen_chest (_, _), (_, (chest, (time, _)))) -> + let plaintext_size = Timelock.get_plaintext_size chest - 1 in + let log_time = Z.log2 Z.(one + Script_int_repr.to_zint time) in + Instructions.open_chest log_time plaintext_size + +let extract_control_trace (type bef_top bef aft_top aft) + (cont : (bef_top, bef, aft_top, aft) Script_typed_ir.continuation) = + match cont with + | KNil -> Control.nil + | KCons _ -> Control.cons + | KReturn _ -> Control.return + | KUndip _ -> Control.undip + | KLoop_in _ -> Control.loop_in + | KLoop_in_left _ -> Control.loop_in_left + | KIter (_, xs, _) -> Control.iter (Size.of_int (List.length xs)) + | KList_enter_body (_, xs, ys, _, _) -> + Control.list_enter_body + (Size.of_int (List.length xs)) + (Size.of_int (List.length ys)) + | KList_exit_body (_, _, _, _, _) -> Control.list_exit_body + | KMap_enter_body (_, xs, _, _) -> + Control.map_enter_body (Size.of_int (List.length xs)) + | KMap_exit_body (_, _, ((module Map) as map), k, _) -> + let key_size = size_of_comparable_value Map.key_ty k in + Control.map_exit_body key_size (Size.map map) + | KLog _ -> Control.log + +(** [Stop_bench] gets raised when a [IFailwith] would be the next instruction. + This allows us to recover the full execution trace, including the trace of + the [IFailwith]. + + The actual benchmark will follow the same execution branch, but instead will + raise an [error] which will be ignored. Thus it is safe to end a benchmark + with [IFailwith], but timings are expected to be different from ending with + [IHalt]. This means that, if we choose to include this behavior in any + benchmark, [IFailwith] must be benched. *) +exception Stop_bench + +let extract_deps (type bef_top bef aft_top aft) ctxt step_constants + (kinstr : (bef_top, bef, aft_top, aft) Script_typed_ir.kinstr) + (stack : bef_top * bef) = + let trace = ref [] in + (* Logger definition *) + let log_interp _instr _ctxt _log _stack_ty _stack = () in + let log_entry : + type a s b f. (a, s, b, f, a, s) Script_typed_ir.logging_function = + fun kinstr ctxt _loc _stack_ty stack -> + trace := extract_ir_sized_step ctxt kinstr stack :: !trace ; + match kinstr with IFailwith _ -> raise Stop_bench | _ -> () + in + let log_control kont = trace := extract_control_trace kont :: !trace in + let log_exit _instr _ctxt _log _stack_ty _stack = () in + let get_log () = Environment.Error_monad.return_none in + let logger = {log_interp; log_entry; log_control; log_exit; get_log} in + try + let res = + Lwt_main.run + (Script_interpreter.kstep + (Some logger) + ctxt + step_constants + kinstr + (fst stack) + (snd stack)) + in + match Environment.wrap_tzresult res with + | Error errs -> + Format.eprintf "%a@." Error_monad.pp_print_error errs ; + raise (Failure "Interpreter_workload.extract_deps: error in step") + | Ok (_aft_top, _aft, _ctxt) -> + (* ((aft_top, aft), List.rev !trace, ctxt) *) + List.rev !trace + with Stop_bench -> List.rev !trace + +let extract_deps_continuation (type bef_top bef aft_top aft) ctxt step_constants + (cont : (bef_top, bef, aft_top, aft) Script_typed_ir.continuation) + (stack : bef_top * bef) = + let trace = ref [] in + (* Logger definition *) + let log_interp _instr _ctxt _log _stack_ty _stack = () in + let log_entry : + type a s b f. (a, s, b, f, a, s) Script_typed_ir.logging_function = + fun kinstr ctxt _loc _stack_ty stack -> + trace := extract_ir_sized_step ctxt kinstr stack :: !trace ; + match kinstr with IFailwith _ -> raise Stop_bench | _ -> () + in + let log_control kont = trace := extract_control_trace kont :: !trace in + let log_exit _instr _ctxt _log _stack_ty _stack = () in + let get_log () = Environment.Error_monad.return_none in + let logger = {log_interp; log_entry; log_control; log_exit; get_log} in + try + let res = + Lwt_main.run + (Script_interpreter.Internals.next + (Some logger) + (Script_interpreter.Internals.OutDatedContext ctxt, step_constants) + 0xFF_FF_FF_FF + cont + (fst stack) + (snd stack)) + in + match Environment.wrap_tzresult res with + | Error errs -> + Format.eprintf "%a@." Error_monad.pp_print_error errs ; + raise (Failure "Interpreter_workload.extract_deps: error in step") + | Ok (_aft_top, _aft, _outdated_ctxt, _gas) -> + (* ((aft_top, aft), List.rev !trace, outdated_ctxt, gas) *) + List.rev !trace + with Stop_bench -> List.rev !trace + +let sized_step_to_sparse_vec {name; args} = + let s = string_of_instr_or_cont name in + match args with + | [] -> Sparse_vec.String.of_list [(s, float_of_int 1)] + | _ -> + List.fold_left + (fun acc {name; arg} -> + Sparse_vec.String.( + add acc (of_list [(s ^ "_" ^ name, float_of_int arg)]))) + Sparse_vec.String.zero + args + +let trace_to_sparse_vec trace = + List.fold_left + (fun acc step -> Sparse_vec.String.add acc (sized_step_to_sparse_vec step)) + Sparse_vec.String.zero + trace diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_commands.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_commands.ml new file mode 100644 index 000000000000..a7a68e0a82dd --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_commands.ml @@ -0,0 +1,200 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Michelson_generation + +let group = + { + Clic.name = "Michelson generation"; + title = "Command for generating random Michelson code and data"; + } + +module Michelson_concat_cmd = struct + let handler () file1 file2 file3 () = + let trace1 = Michelson_generation.load ~filename:file1 in + let trace2 = Michelson_generation.load ~filename:file2 in + let terms = trace1 @ trace2 in + let l1 = List.length trace1 in + let l2 = List.length trace2 in + Format.eprintf + "Loaded %d terms from %s, %d terms from %s, total %d@." + l1 + file1 + l2 + file2 + (l1 + l2) ; + Michelson_generation.save ~filename:file3 ~terms ; + return_unit + + let params = + Clic.( + prefixes [Protocol.name; "michelson"; "concat"; "files"] + @@ string ~name:"FILENAME" ~desc:"First file" + @@ prefixes ["and"] + @@ string ~name:"FILENAME" ~desc:"Second file" + @@ prefixes ["into"] + @@ string ~name:"FILENAME" ~desc:"Target file" + @@ stop) + + let command = + Clic.command + ~group + ~desc:"Michelson generation" + Clic.no_options + params + handler +end + +let () = Registration.add_command Michelson_concat_cmd.command + +module Michelson_gen_cmd = struct + let lift_opt f opt_arg state = + match opt_arg with None -> state | Some arg -> f arg state + + let handler (min_size, max_size, burn_in, seed) terms_count terms_kind + filename () = + let default = Michelson_generation.default_generator_config in + let min = Option.value ~default:default.target_size.min min_size in + let max = Option.value ~default:default.target_size.max max_size in + let burn_in_multiplier = + Option.value ~default:default.burn_in_multiplier burn_in + in + let rng_state = + match seed with + | None -> + Format.eprintf "Self-initialization of PRNG@." ; + let state = Random.State.make_self_init () in + Format.(eprintf "PRNG state hash: %d@." (Hashtbl.hash state)) ; + state + | Some seed -> + Format.eprintf "PRNG initialized with seed %d@." seed ; + Random.State.make [|seed|] + in + let cfg = + {Michelson_generation.target_size = {min; max}; burn_in_multiplier} + in + let terms_count = + match int_of_string terms_count with + | exception Failure _ -> + Format.eprintf "TERMS-COUNT must be an integer, exiting@." ; + exit 1 + | terms_count -> + if terms_count <= 0 then ( + Format.eprintf "TERMS-COUNT must be strictly positive, exiting@." ; + exit 1) + else terms_count + in + let progress = + Benchmark_helpers.make_progress_printer + Format.err_formatter + terms_count + "Generating term" + in + let terms = + match terms_kind with + | "data" -> + Stdlib.List.init terms_count (fun _i -> + progress () ; + Michelson_generation.make_data_sampler rng_state cfg) + | "code" -> + Stdlib.List.init terms_count (fun _i -> + progress () ; + Michelson_generation.make_code_sampler rng_state cfg) + | _ -> + Format.eprintf "Term kind must be either \"data\" or \"code\"@." ; + exit 1 + in + Michelson_generation.save ~filename ~terms ; + return_unit + + let min_size_arg = + let min_size = + Clic.parameter (fun (_ : unit) parsed -> + try return (int_of_string parsed) + with _ -> + Printf.eprintf "Error while parsing --min-size argument." ; + exit 1) + in + Clic.arg + ~doc:"Lower bound for target size of terms" + ~long:"min-size" + ~placeholder:"int" + min_size + + let max_size_arg = + let max_size = + Clic.parameter (fun (_ : unit) parsed -> + try return (int_of_string parsed) + with _ -> + Printf.eprintf "Error while parsing --max-size argument." ; + exit 1) + in + Clic.arg + ~doc:"Lower bound for target size of terms" + ~long:"max-size" + ~placeholder:"int" + max_size + + let burn_in_arg = + let target_size = + Clic.parameter (fun (_ : unit) parsed -> + try return (int_of_string parsed) + with _ -> + Printf.eprintf "Error while parsing --burn-in argument." ; + exit 1) + in + Clic.arg + ~doc:"Burn-in multiplier" + ~long:"burn-in" + ~placeholder:"int" + target_size + + let seed_arg = + let seed = + Clic.parameter (fun (_ : unit) parsed -> + try return (int_of_string parsed) + with _ -> + Printf.eprintf "Error while parsing --seed argument." ; + exit 1) + in + Clic.arg ~doc:"RNG seed" ~long:"seed" ~placeholder:"int" seed + + let options = Clic.args4 min_size_arg max_size_arg burn_in_arg seed_arg + + let params = + Clic.( + prefixes [Protocol.name; "michelson"; "generate"] + @@ string ~name:"TERMS-COUNT" ~desc:"Number of terms to generate" + @@ prefixes ["terms"; "of"; "kind"] + @@ string ~name:"{data|code}" ~desc:"Kind of term to generate" + @@ prefixes ["in"] + @@ string ~name:"FILENAME" ~desc:"File where to save Michelson terms" + @@ stop) + + let command = + Clic.command ~group ~desc:"Michelson generation" options params handler +end + +let () = Registration.add_command Michelson_gen_cmd.command diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_generation.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_generation.ml new file mode 100644 index 000000000000..8687a9b2a379 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_generation.ml @@ -0,0 +1,224 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +type generator_config = { + target_size : Base_samplers.range; + burn_in_multiplier : int; +} + +let default_generator_config = + {target_size = {Base_samplers.min = 100; max = 1000}; burn_in_multiplier = 5} + +let generator_config_encoding = + let open Data_encoding in + conv + (fun {target_size; burn_in_multiplier} -> (target_size, burn_in_multiplier)) + (fun (target_size, burn_in_multiplier) -> {target_size; burn_in_multiplier}) + (obj2 + (req "target_size" Base_samplers.range_encoding) + (req "burn_in_multiplier" int31)) + +(* ----------------------------------------------------------------------- *) + +type michelson_data = + | Code of {term : Script_repr.expr; bef : Script_repr.expr list} + | Data of {term : Script_repr.expr; typ : Script_repr.expr} + +let michelson_data_list_encoding = + let open Data_encoding in + let e = Script_repr.expr_encoding in + list + @@ union + [ + case + ~title:"Code" + (Tag 0) + (tup2 e (list e)) + (function Code {term; bef} -> Some (term, bef) | _ -> None) + (fun (term, bef) -> Code {term; bef}); + case + ~title:"Data" + (Tag 1) + (tup2 e e) + (function Data {term; typ} -> Some (term, typ) | _ -> None) + (fun (term, typ) -> Data {term; typ}); + ] + +let save ~filename ~terms = + let bytes = + match Data_encoding.Binary.to_bytes michelson_data_list_encoding terms with + | Error err -> + Format.eprintf + "Michelson_generation.save: encoding failed (%a); exiting" + Data_encoding.Binary.pp_write_error + err ; + exit 1 + | Ok res -> res + in + ignore (* TODO handle error *) + (Lwt_main.run + @@ Tezos_stdlib_unix.Lwt_utils_unix.create_file + filename + (Bytes.unsafe_to_string bytes)) + +let load ~filename = + Lwt_main.run + @@ ( Tezos_stdlib_unix.Lwt_utils_unix.read_file filename >>= fun str -> + Format.eprintf "Michelson_generation.load: loaded %s@." filename ; + let bytes = Bytes.unsafe_of_string str in + match + Data_encoding.Binary.of_bytes michelson_data_list_encoding bytes + with + | Ok result -> Lwt.return result + | Error err -> + Format.eprintf + "Michelson_generation.load: can't load file (%a); exiting" + Data_encoding.Binary.pp_read_error + err ; + exit 1 ) + +(* ----------------------------------------------------------------------- *) + +let michelson_samplers = + let module Config = struct + open Michelson_samplers_parameters + + let parameters = + { + int_size = {min = 8; max = 32}; + string_size = {min = 8; max = 128}; + bytes_size = {min = 8; max = 128}; + stack_size = {min = 3; max = 8}; + type_size = {min = 1; max = 15}; + list_size = {min = 0; max = 1000}; + set_size = {min = 0; max = 1000}; + map_size = {min = 0; max = 1000}; + } + + let size = 16 + + let algo = `Default + end in + let module Samplers = Michelson_samplers.Make (Config) in + (module Samplers : Michelson_samplers.S) + +module Samplers = (val michelson_samplers) + +(* ----------------------------------------------------------------------- *) + +let base_type_to_michelson_type (typ : Type.Base.t) = + let typ = Mikhailsky.map_var (fun _ -> Mikhailsky.unit_ty) typ in + Mikhailsky.to_michelson typ + +(* Convert a Micheline-encoded type to its internal GADT format. *) +let michelson_type_to_ex_ty (typ : Alpha_context.Script.expr) + (ctxt : Alpha_context.t) = + Script_ir_translator.parse_ty + ctxt + ~legacy:false + ~allow_lazy_storage:false + ~allow_operation:false + ~allow_contract:false + ~allow_ticket:false + (Micheline.root typ) + |> Environment.wrap_tzresult + |> function + | Ok t -> t + | Error errs -> + Format.eprintf "%a@." Error_monad.pp_print_error errs ; + Stdlib.failwith "Michelson_generation.michelson_type_to_ex_ty: error" + +let base_type_to_ex_ty ty = + michelson_type_to_ex_ty (base_type_to_michelson_type ty) + +(* Convert a Mikhailsky stack to a list of Micheline-encoded types *) +let rec stack_type_to_michelson_type_list (typ : Type.Stack.t) = + let node = typ.node in + match node with + | Type.Stack.Stack_var_t _ -> + Stdlib.failwith "stack_type_to_michelson_type_list: bug found" + | Type.Stack.Empty_t -> [] + | Type.Stack.Item_t (ty, tl) -> + base_type_to_michelson_type ty :: stack_type_to_michelson_type_list tl + +(* Convert a list of Micheline-encoded Michelson types to the + internal GADT format. *) +let rec michelson_type_list_to_ex_stack_ty + (stack_ty : Alpha_context.Script.expr list) ctxt = + let open Script_ir_translator in + let open Script_typed_ir in + match stack_ty with + | [] -> (Ex_stack_ty Bot_t, ctxt) + | hd :: tl -> ( + let (ex_ty, ctxt) = michelson_type_to_ex_ty hd ctxt in + match ex_ty with + | Ex_ty ty -> ( + let (ex_stack_ty, ctxt) = + michelson_type_list_to_ex_stack_ty tl ctxt + in + match ex_stack_ty with + | Ex_stack_ty tl -> (Ex_stack_ty (Item_t (ty, tl, None)), ctxt))) + +let stack_type_to_ex_stack_ty ty = + michelson_type_list_to_ex_stack_ty (stack_type_to_michelson_type_list ty) + +let make_data_sampler rng_state config = + let target_size = + Base_samplers.sample_in_interval rng_state ~range:config.target_size + in + let module Gen = Generators.Data (struct + module Samplers = Samplers + + let rng_state = rng_state + + let target_size = target_size + + let verbosity = `Silent + end) in + let burn_in = target_size * config.burn_in_multiplier in + let generator = Gen.generator ~burn_in in + let (term, typ) = StaTz.Stats.sample_gen generator in + Data {term; typ = base_type_to_michelson_type typ} + +let make_code_sampler rng_state config = + let target_size = + Base_samplers.sample_in_interval rng_state ~range:config.target_size + in + let module Gen = Generators.Code (struct + module Samplers = Samplers + + let rng_state = rng_state + + let target_size = target_size + + let verbosity = `Silent + end) in + let burn_in = target_size * config.burn_in_multiplier in + let generator = Gen.generator ~burn_in in + let (term, (bef, _aft)) = StaTz.Stats.sample_gen generator in + let bef = stack_type_to_michelson_type_list bef in + Code {term; bef} diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_generation.mli b/src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_generation.mli new file mode 100644 index 000000000000..3e444c15dbc1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_generation.mli @@ -0,0 +1,124 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** {2 Wrappers around some Michelson generators and related helpers} *) + +open Protocol + +(** [generator_config] specifies some parameters to the + {!Tezos_benchmark_alpha.Generators} Michelson code and data generators. *) +type generator_config = { + target_size : Base_samplers.range; + (** The target size of the terms, in number of nodes, is sampled uniformly + in [target_size]. *) + burn_in_multiplier : int; + (** The generators are based on a Markov chain, which must be + "heated-up" until it reaches its stationary state. A prefix of samples + are therefore thrown away: this is called the {e burn-in} phase. + The number of thrown away terms is proportional to [burn_in_multiplier] + and [target_size]. *) +} + +(** Default configuration for the generators. *) +val default_generator_config : generator_config + +val generator_config_encoding : generator_config Data_encoding.t + +(** [michelson_data] is the type of Michelson data, as produced by the + samplers. *) +type michelson_data = + | Code of { + term : Script_repr.expr; + (** [term] is a typeable Michelson program in Micheline form. *) + bef : Script_repr.expr list; + (** [bef] is the type of the initial stack of [term]. *) + } + | Data of { + term : Script_repr.expr; + (** [term] is a typeable Michelson data in Micheline form. *) + typ : Script_repr.expr; (** [typ] is the type of [term]. *) + } + +val michelson_data_list_encoding : michelson_data list Data_encoding.t + +(** Saving/loading michelson data to disk *) + +(** [save ~filename ~terms] saves the list [terms] to the file [filename]. *) +val save : filename:string -> terms:michelson_data list -> unit + +(** [load filename] loads the Michelson data in [filename]. *) +val load : filename:string -> michelson_data list + +(** Type conversion helpers *) + +(** [base_type_to_michelson_type] converts a type as produced by the + type inference engine in {!Tezos_benchmark_type_inference_alpha.Inference} + to a type in IR form. *) +val base_type_to_michelson_type : Type.Base.t -> Script_repr.expr + +(** [michelson_type_list_to_ex_stack_ty] converts a list of types in + Micheline form to a stack type in IR form. *) +val michelson_type_list_to_ex_stack_ty : + Alpha_context.Script.expr list -> + Alpha_context.t -> + Script_ir_translator.ex_stack_ty * Alpha_context.t + +(** [michelson_type_to_ex_ty ty ctxt] parses the type [ty]. + + @raise Failure if an error arises during parsing. *) +val michelson_type_to_ex_ty : + Alpha_context.Script.expr -> + Alpha_context.t -> + Script_ir_translator.ex_ty * Alpha_context.t + +(** [base_type_to_ex_ty] converts a type as produced by the + type inference engine in {!Tezos_benchmark_type_inference_alpha.Inference} + into a type in IR form. *) +val base_type_to_ex_ty : + Type.Base.t -> Alpha_context.t -> Script_ir_translator.ex_ty * Alpha_context.t + +(** [stack_type_to_ex_stack_ty] converts a stack type as produced by the + type inference engine in {!Tezos_benchmark_type_inference_alpha.Inference} + into a stack type in IR form. + + @raise Failure if a stack type variable occurs in the argument. *) +val stack_type_to_ex_stack_ty : + Type.Stack.t -> + Alpha_context.t -> + Script_ir_translator.ex_stack_ty * Alpha_context.t + +(** Samplers *) + +(** [make_data_sampler] constructs a Michelson data sampler based on the + infrastructure available in {!Tezos_benchmark_alpha.Generators}. *) +val make_data_sampler : Random.State.t -> generator_config -> michelson_data + +(** [make_code_sampler] constructs a Michelson code sampler based on the + infrastructure available in {!Tezos_benchmark_alpha.Generators}. *) +val make_code_sampler : Random.State.t -> generator_config -> michelson_data + +(** [Samplers] is an instance of the direct-style (non-MCMC based) samplers + implemented in {!Tezos_benchmark_alpha.Michelson_samplers}. *) +module Samplers : Michelson_samplers.S diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_types.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_types.ml new file mode 100644 index 000000000000..047097c932e2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/michelson_types.ml @@ -0,0 +1,138 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Script_typed_ir + +[@@@ocaml.warning "-32"] + +let ( @$ ) x y = Item_t (x, y, None) + +let bot = Bot_t + +let unit = unit_t ~annot:None + +let unit_cmp = unit_key ~annot:None + +let int_cmp = int_key ~annot:None + +let string_cmp = string_key ~annot:None + +(* the type of integers *) +let int = int_t ~annot:None + +(* the type of naturals *) +let nat = nat_t ~annot:None + +(* the type of strings *) +let string = string_t ~annot:None + +(* the type of bytes *) +let bytes = bytes_t ~annot:None + +(* the type of booleans *) +let bool = bool_t ~annot:None + +(* the type of mutez *) +let mutez = mutez_t ~annot:None + +(* the type of public key *) +let public_key = key_t ~annot:None + +(* the type of key hashes *) +let key_hash = key_hash_t ~annot:None + +(* the type of signatures *) +let signature = signature_t ~annot:None + +(* the type of addresses *) +let address = address_t ~annot:None + +(* the type of chain ids *) +let chain_id = chain_id_t ~annot:None + +(* the type of timestamps *) +let timestamp = timestamp_t ~annot:None + +(* list type constructor *) +let list x = + match list_t (-1) x ~annot:None with Error _ -> assert false | Ok t -> t + +(* option type constructor *) +let option x = + match option_t (-1) x ~annot:None with Error _ -> assert false | Ok t -> t + +(* map type constructor*) +let map k v = + match map_t (-1) k v ~annot:None with Error _ -> assert false | Ok t -> t + +(* map type constructor*) +let big_map k v = + match big_map_t (-1) k v ~annot:None with + | Error _ -> assert false + | Ok t -> t + +(* set type constructor*) +let set k = + match set_t (-1) k ~annot:None with Error _ -> assert false | Ok t -> t + +(* pair type constructor*) +let pair k1 k2 = + match pair_t (-1) (k1, None, None) (k2, None, None) ~annot:None with + | Error _ -> assert false + | Ok t -> t + +(* union type constructor*) +let union k1 k2 = + match union_t (-1) (k1, None) (k2, None) ~annot:None with + | Error _ -> assert false + | Ok t -> t + +let lambda x y = + match lambda_t (-1) x y ~annot:None with Error _ -> assert false | Ok t -> t + +let contract arg_ty = + match contract_t (-1) arg_ty ~annot:None with + | Error _ -> assert false + | Ok t -> t + +let operation = operation_t ~annot:None + +let sapling_state memo_size = sapling_state_t ~memo_size ~annot:None + +let sapling_transaction memo_size = sapling_transaction_t ~memo_size ~annot:None + +let bls12_381_g1 = bls12_381_g1_t ~annot:None + +let bls12_381_g2 = bls12_381_g2_t ~annot:None + +let bls12_381_fr = bls12_381_fr_t ~annot:None + +let ticket ty = + match ticket_t (-1) ty ~annot:None with Error _ -> assert false | Ok t -> t + +let chest_key = chest_key_t ~annot:None + +let chest = chest_t ~annot:None diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/registration_helpers.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/registration_helpers.ml new file mode 100644 index 000000000000..81a84d090420 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/registration_helpers.ml @@ -0,0 +1,37 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let register ((module Bench) : Benchmark.t) = + let module B : Benchmark.S = struct + include Bench + + let name = name ^ "_" ^ Protocol.name + + let tags = Protocol.name :: tags + end in + Registration.register (module B) + +let register_for_codegen name model = + Registration.register_for_codegen (name ^ "_" ^ Protocol.name) model diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/sapling_benchmarks.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/sapling_benchmarks.ml new file mode 100644 index 000000000000..24121b1c5af7 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/sapling_benchmarks.ml @@ -0,0 +1,152 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +module Apply_diff_bench : Benchmark.S = struct + include Interpreter_benchmarks.Default_config + include Interpreter_benchmarks.Default_boilerplate + + let name = "SAPLING_APPLY_DIFF" + + let info = "Benchmarking SAPLING_APPLY_DIFF" + + let tags = ["sapling"] + + let diff_from_tx (tx : Alpha_context.Sapling.transaction) = + let open Environment.Sapling.UTXO in + let commitments_and_ciphertexts = + List.map (fun x -> (x.cm, x.ciphertext)) tx.outputs + in + { + Protocol.Sapling_repr.commitments_and_ciphertexts; + nullifiers = List.map (fun (x : input) -> x.nf) tx.inputs; + } + + type workload = {nb_input : int; nb_output : int; nb_cm : int; nb_nf : int} + + let workload_encoding : workload Data_encoding.t = + let open Data_encoding in + def "diff_arg_encoding" + @@ conv + (fun {nb_input; nb_output; nb_cm; nb_nf} -> + (nb_input, nb_output, nb_cm, nb_nf)) + (fun (nb_input, nb_output, nb_cm, nb_nf) -> + {nb_input; nb_output; nb_cm; nb_nf}) + (tup4 Size.encoding Size.encoding Size.encoding Size.encoding) + + let workload_to_vector {nb_input; nb_output; nb_cm = _; nb_nf = _} = + let l = + [ + ("nb_input", float_of_int nb_input); + ("nb_output", float_of_int nb_output); + ] + in + Sparse_vec.String.of_list l + + let model = + Model.make + ~conv:(fun {nb_input; nb_output; _} -> (nb_input, (nb_output, ()))) + ~model: + (Model.bilinear_affine + ~intercept:(Free_variable.of_string "apply_diff_const") + ~coeff1:(Free_variable.of_string "apply_diff_inputs") + ~coeff2:(Free_variable.of_string "apply_diff_outputs")) + + let models = [("apply_diff", model)] + + let benchmark_apply_diff seed sapling_transition () = + let sapling_forge_rng_state = + Random.State.make + @@ Option.fold + ~none:Sapling_generation.shared_seed + ~some:(fun seed -> [|seed|]) + seed + in + Lwt_main.run + ( Execution_context.make ~rng_state:sapling_forge_rng_state + >>=? fun (ctxt, step_constants) -> + Sapling_generation.prepare_seeded_state sapling_transition ctxt + >>=? fun (_, _, _, _, ctxt, state_id) -> + let external_state_id = Alpha_context.Sapling.Id.parse_z state_id in + let internal_state_id = + Lazy_storage_kind.Sapling_state.Id.parse_z state_id + in + Alpha_context.Sapling.(state_from_id ctxt external_state_id) + >|= Protocol.Environment.wrap_tzresult + >>=? fun (state, ctxt) -> + Format.eprintf "state hash: %d@." (Hashtbl.hash state.diff) ; + Format.eprintf + "tx hash: %d@." + (Hashtbl.hash sapling_transition.sapling_tx) ; + let address = Alpha_context.Contract.to_b58check step_constants.self in + let chain_id = + Environment.Chain_id.to_b58check step_constants.chain_id + in + let anti_replay = address ^ chain_id in + Format.eprintf "anti-replay: %s@." anti_replay ; + let diff = diff_from_tx sapling_transition.sapling_tx in + let closure () = + ignore + (Lwt_main.run + (Sapling_generation.apply_diff ctxt internal_state_id diff)) + in + let workload = + { + nb_input = List.length sapling_transition.sapling_tx.inputs; + nb_output = List.length sapling_transition.sapling_tx.outputs; + nb_cm = Int64.to_int sapling_transition.commitment_count; + nb_nf = Int64.to_int sapling_transition.nullifier_count; + } + in + return (Generator.Plain {workload; closure}) ) + |> function + | Ok closure -> closure + | Error errs -> + Format.eprintf + "Runner.benchmarkable_from_instr_str:\n%a@." + (Format.pp_print_list Error_monad.pp) + errs ; + exit 1 + + let create_benchmarks ~rng_state ~bench_num config = + ignore rng_state ; + match config.sapling with + | {sapling_txs_file; seed} -> + let transitions = Sapling_generation.load ~filename:sapling_txs_file in + let length = List.length transitions in + if length < bench_num then + Format.eprintf + "KSapling_verify_update: warning, only %d available transactions \ + (requested %d)@." + length + bench_num ; + let transitions = List.take_n (min bench_num length) transitions in + List.map + (fun (_filename, tx) -> benchmark_apply_diff seed tx) + transitions +end + +let () = Registration.register (module Apply_diff_bench) diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/sapling_commands.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/sapling_commands.ml new file mode 100644 index 000000000000..77b42a0b848b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/sapling_commands.ml @@ -0,0 +1,134 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module Sapling_gen_cmd = struct + let lift_opt f opt_arg state = + match opt_arg with None -> state | Some arg -> f arg state + + (* ----------------------------------------------------------------------- *) + (* Handling options for the "generate sapling transactions" command *) + + (* Generic max-%s argument *) + let max name = + Clic.arg + ~doc:(Printf.sprintf "Maximum number of %s" name) + ~long:(Printf.sprintf "max-%s" name) + ~placeholder:"integer" + (Clic.parameter (fun (_ : unit) parsed -> + match int_of_string parsed with + | exception Failure _ -> + Format.eprintf + "Ill-formatted --max-%s option (expected integer), exiting" + name ; + exit 1 + | res when res <= 0 -> + Format.eprintf + "--max-%s should be a strictly positive integer, exiting" + name ; + exit 1 + | res -> return res)) + + (* Integer argument --seed *) + let seed_arg = + let seed = + Clic.parameter (fun (_ : unit) parsed -> + try return (int_of_string parsed) + with _ -> + Printf.eprintf "Error while parsing --seed argument." ; + exit 1) + in + Clic.arg ~doc:"RNG seed" ~long:"seed" ~placeholder:"int" seed + + let positive_param = + Clic.parameter (fun _ s -> + match int_of_string_opt s with + | Some i when i > 0 -> return i + | _ -> failwith "Parameter should be a positive integer literal") + + open Sapling_generation + + let set_max_inputs max_inputs options = {options with max_inputs} + + let set_max_outputs max_outputs options = {options with max_outputs} + + let set_max_nullifiers max_nullifiers options = {options with max_nullifiers} + + let set_max_additional_commitments max_additional_commitments options = + {options with max_additional_commitments} + + let set_seed seed (options : sapling_gen_options) = + {options with seed = Some seed} + + let sapling_handler + (max_inputs, max_outputs, max_nullifiers, max_additional_commitments, seed) + tx_count save_to () = + let sapling_gen_options = + default_sapling_gen_options + |> lift_opt set_max_inputs max_inputs + |> lift_opt set_max_outputs max_outputs + |> lift_opt set_max_nullifiers max_nullifiers + |> lift_opt set_max_additional_commitments max_additional_commitments + |> lift_opt set_seed seed + in + generate save_to tx_count sapling_gen_options ; + return () + + let options = + Clic.args5 + (max "inputs") + (max "outputs") + (max "nullifiers") + (max "additional-commitments") + seed_arg + + let params = + Clic.( + prefixes [Protocol.name; "sapling"; "generate"] + @@ param + ~name:"SAPLING-TX-COUNT" + ~desc:"Number of sapling transactions to generate" + positive_param + @@ prefixes ["transactions"; "in"] + @@ string + ~name:"SAPLING-TX-FILE" + ~desc:"File containing sapling transactions" + @@ stop) + + let group = + { + Clic.name = "Sapling tx generation"; + title = "Command for generating random sapling transactions"; + } + + let command = + Clic.command + ~group + ~desc:"Sapling transaction generation" + options + params + sapling_handler +end + +let () = Registration.add_command Sapling_gen_cmd.command diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/sapling_generation.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/sapling_generation.ml new file mode 100644 index 000000000000..0a7b6ee9f2fc --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/sapling_generation.ml @@ -0,0 +1,564 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(* ------------------------------------------------------------------------- *) +type sapling_gen_options = { + max_inputs : int; + max_outputs : int; + max_nullifiers : int; + max_additional_commitments : int; + seed : int option; +} + +let default_sapling_gen_options = + { + max_inputs = 100; + max_outputs = 100; + max_nullifiers = 100; + max_additional_commitments = 50; + seed = None; + } + +(* ------------------------------------------------------------------------- *) +(* Evil incantations *) + +(* We have to break the protocol abstraction boundary quite often in this + module. Props to whoever finds a way to avoid these calls. *) + +let alpha_to_raw (x : Alpha_context.t) : Raw_context.t = Obj.magic x + +let raw_to_alpha (x : Raw_context.t) : Alpha_context.t = Obj.magic x + +(* ------------------------------------------------------------------------- *) +(* Helpers *) + +(* sample a random permutation of [0 ; ... ; n-1] *) +let fisher_yates n state = + let a = Array.init n (fun i -> i) in + for i = 0 to Array.length a - 1 do + let j = Random.State.int state (i + 1) in + let tmp = a.(j) in + a.(j) <- a.(i) ; + a.(i) <- tmp + done ; + a + +(* sample a random injection of [0 ; ... ; m-1 ] in [0 ; ... ; n - 1] *) +let random_injection m n state = + if m > n then invalid_arg "random_injection" + else + let a = fisher_yates n state in + Array.sub a 0 m + +(* ------------------------------------------------------------------------- *) +(* Sapling generation *) + +(* Sapling state spec + sapling transaction valid for that state. *) +type sapling_transition = { + state_seed : int64; + nullifier_count : int64; + commitment_count : int64; + sapling_tx : Alpha_context.Sapling.transaction; +} + +type forge_info = { + rcm : Tezos_sapling.Core.Client.Rcm.t; + position : int64; + amount : int64; + address : Tezos_sapling.Core.Client.Viewing_key.address; + nf : Tezos_sapling.Core.Client.Nullifier.t; +} + +let random_amount sum = + Random.int64 (Int64.sub Tezos_sapling.Core.Validator.UTXO.max_amount sum) + +let reverse diff = + Protocol.Sapling_repr. + { + diff with + commitments_and_ciphertexts = List.rev diff.commitments_and_ciphertexts; + } + +let pp_rpc_diff fmtr (diff : Protocol.Sapling_repr.diff) = + let json = + Data_encoding.Json.construct Protocol.Sapling_repr.diff_encoding diff + in + Format.fprintf fmtr "%a" Data_encoding.Json.pp json + +let random_bytes state size = + Bytes.init size (fun _ -> Char.chr (Random.State.int state 256)) + +let rec gen_rcm state = + let rcm = + Data_encoding.Binary.of_bytes_exn + Tezos_sapling.Core.Client.Rcm.encoding + (random_bytes state 32) + in + try + Tezos_sapling.Core.Client.Rcm.assert_valid rcm ; + rcm + with _ -> gen_rcm state + +(* Adds a commitment, ciphertext, cv to an rpc_diff *) +let add_input diff vk index position sum state = + let rcm = gen_rcm state in + let amount = random_amount sum in + let (new_idx, address) = + Tezos_sapling.Core.Client.Viewing_key.new_address vk index + in + let cv = + Tezos_sapling.Core.Client.CV.of_bytes (random_bytes state 32) + |> WithExceptions.Option.get ~loc:__LOC__ + in + let (ciphertext, cm) = + Tezos_sapling.Core.Client.Forge.Output.to_ciphertext + Tezos_sapling.Core.Client.Forge.Output. + {address; amount; memo = Bytes.empty} + cv + vk + rcm + (Tezos_sapling.Core.Client.DH.esk_random ()) + in + let nf = + Tezos_sapling.Core.Client.Nullifier.compute address vk ~amount rcm ~position + in + let diff = + Protocol.Sapling_repr. + { + diff with + commitments_and_ciphertexts = + (cm, ciphertext) :: diff.commitments_and_ciphertexts; + } + in + return (diff, {rcm; position; amount; address; nf}, new_idx) + +let generate_commitments ~vk ~nb_input ~nb_cm ~nb_nf ~diff ~index state = + let inj = random_injection nb_input nb_cm state in + let use_for_input i = Array.exists (fun k -> k = i) inj in + let rec loop i cm_index nb_nf diff to_forge sum = + if i = nb_cm then return (reverse diff, to_forge) + else if use_for_input i then + (* create commitment for input *) + add_input diff vk cm_index (Int64.of_int i) sum state + >>=? fun (diff, forge_info, next_index) -> + let sum = Int64.add sum forge_info.amount in + loop (i + 1) next_index nb_nf diff (forge_info :: to_forge) sum + else + (* create commitment (not for input) *) + add_input diff vk cm_index (Int64.of_int i) sum state + >>=? fun (diff, {nf; _}, next_index) -> + (* can we use a nullifier? *) + if nb_nf = 0 then (* No. *) + loop (i + 1) next_index nb_nf diff to_forge sum + else + (* Yes! Grab it. *) + let diff = + Protocol.Sapling_repr.{diff with nullifiers = nf :: diff.nullifiers} + in + loop (i + 1) next_index (nb_nf - 1) diff to_forge sum + in + loop 0 index nb_nf diff [] 0L + +(* Add roots to the storage. One cm has to be added for every root. *) +let rec add_root nb_root ctxt id vk index size diff state = + if nb_root > 0 then + add_input Protocol.Sapling_storage.empty_diff vk index size 0L state + >>=? fun (diff_to_add, {position = size; _}, new_idx) -> + Protocol.Sapling_storage.apply_diff ctxt id diff_to_add + >|= Protocol.Environment.wrap_tzresult + >>=? fun (ctxt, _) -> + (* We call it nb_root -1 because one root is already present*) + add_root + (nb_root - 1) + ctxt + id + vk + new_idx + (Int64.succ size) + Protocol.Sapling_repr. + { + diff with + commitments_and_ciphertexts = + diff.commitments_and_ciphertexts + @ diff_to_add.commitments_and_ciphertexts; + } + state + else return (ctxt, diff) + +(* Compute a state as an OCaml object to compute the witness *) +let state_from_rpc_diff rpc_diff = + Tezos_sapling.Storage.add + (Tezos_sapling.Storage.empty ~memo_size:0) + rpc_diff.Protocol.Sapling_repr.commitments_and_ciphertexts + +(* Create an (unspendable) output from a proving context and a vk *) +let output proving_ctx vk sum = + let address = Tezos_sapling.Core.Client.Viewing_key.dummy_address () in + let amount = random_amount sum in + let rcm = Tezos_sapling.Core.Client.Rcm.random () in + let esk = Tezos_sapling.Core.Client.DH.esk_random () in + let (cv_o, proof_o) = + Tezos_sapling.Core.Client.Proving.output_proof + proving_ctx + esk + address + rcm + ~amount + in + let (ciphertext, cm) = + Tezos_sapling.Core.Client.Forge.Output.to_ciphertext + Tezos_sapling.Core.Client.Forge.Output. + {address; amount; memo = Bytes.empty} + cv_o + vk + rcm + esk + in + (Tezos_sapling.Core.Validator.UTXO.{cm; proof_o; ciphertext}, amount) + +(* Returns a list of outputs and the sum of their amount *) +let outputs nb_output proving_ctx vk = + let rec aux output_amount list_outputs nb_output sum = + match nb_output with + | 0 -> (output_amount, list_outputs) + | nb_output -> + let (output, amount) = output proving_ctx vk sum in + assert ( + Int64.compare + amount + (Int64.sub + Int64.max_int + Tezos_sapling.Core.Validator.UTXO.max_amount) + < 0) ; + aux + (Int64.add output_amount amount) + (output :: list_outputs) + (nb_output - 1) + (Int64.add sum amount) + in + aux 0L [] nb_output 0L + +(* Create the list of inputs. To use once the merkle tree is completed. *) +let make_inputs to_forge local_state proving_ctx sk vk root anti_replay = + List.map_ep + (fun {rcm; position; amount; address; nf} -> + let witness = Tezos_sapling.Storage.get_witness local_state position in + let ar = Tezos_sapling.Core.Client.Proving.ar_random () in + let (cv, rk, proof) = + Tezos_sapling.Core.Client.Proving.spend_proof + proving_ctx + vk + sk + address + rcm + ar + ~amount + ~root + ~witness + in + let signature = + Tezos_sapling.Core.Client.Proving.spend_sig + sk + ar + cv + nf + rk + proof + anti_replay + in + return + Tezos_sapling.Core.Validator.UTXO. + {cv; nf; rk; proof_i = proof; signature}) + to_forge + +let init_fresh_sapling_state ctxt = + let open Protocol.Environment.Error_monad in + Protocol.Lazy_storage_diff.fresh + Protocol.Lazy_storage_kind.Sapling_state + ~temporary:false + ctxt + >>=? fun (ctxt, id) -> + Protocol.Sapling_storage.init ctxt id ~memo_size:0 + (* TODO CHECK *) + >>=? fun ctxt -> return (ctxt, id) + +let generate_spending_and_viewing_keys state = + let sk = + Tezos_sapling.Core.Client.Spending_key.of_seed (random_bytes state 32) + in + let vk = Tezos_sapling.Core.Client.Viewing_key.of_sk sk in + (sk, vk) + +let prepare_seeded_state_internal ~(nb_input : int) ~(nb_nf : int) + ~(nb_cm : int) (ctxt : Raw_context.t) (state : Random.State.t) : + (Sapling_repr.diff + * forge_info list + * Tezos_sapling.Core.Client.Spending_key.t + * Tezos_sapling.Core.Client.Viewing_key.t + * Raw_context.t + * Protocol.Lazy_storage_kind.Sapling_state.Id.t) + tzresult + Lwt.t = + init_fresh_sapling_state ctxt >|= Protocol.Environment.wrap_tzresult + >>=? fun (ctxt, id) -> + let index_start = Tezos_sapling.Core.Client.Viewing_key.default_index in + let (sk, vk) = generate_spending_and_viewing_keys state in + generate_commitments + ~vk + ~nb_input + ~nb_cm + ~nb_nf + ~diff:Protocol.Sapling_storage.empty_diff + ~index:index_start + state + >>=? fun (diff, to_forge) -> + Protocol.Sapling_storage.apply_diff ctxt id diff + >|= Protocol.Environment.wrap_tzresult + >>=? fun (ctxt, _size) -> return (diff, to_forge, sk, vk, ctxt, id) + +let prepare_seeded_state + {state_seed; nullifier_count; commitment_count; sapling_tx} ctxt = + let rng_state = Random.State.make [|Int64.to_int state_seed|] in + prepare_seeded_state_internal + ~nb_input:(List.length sapling_tx.inputs) + ~nb_nf:(Int64.to_int nullifier_count) + ~nb_cm:(Int64.to_int commitment_count) + (alpha_to_raw ctxt) + rng_state + >>=? fun (diff, forge_info, spending_key, viewing_key, raw_ctxt, raw_id) -> + let id = Protocol.Lazy_storage_kind.Sapling_state.Id.unparse_to_z raw_id in + return (diff, forge_info, spending_key, viewing_key, raw_to_alpha raw_ctxt, id) + +let generate ~(nb_input : int) ~(nb_output : int) ~(nb_nf : int) ~(nb_cm : int) + ~(anti_replay : string) ~ctxt state = + assert (nb_input <= nb_cm) ; + assert (nb_nf <= nb_cm - nb_input) ; + prepare_seeded_state_internal ~nb_input ~nb_nf ~nb_cm ctxt state + >>=? fun (diff, to_forge, sk, vk, ctxt, id) -> + let local_state = state_from_rpc_diff diff in + let root = Tezos_sapling.Storage.get_root local_state in + Tezos_sapling.Core.Client.Proving.with_proving_ctx (fun proving_ctx -> + make_inputs to_forge local_state proving_ctx sk vk root anti_replay + >>=? fun inputs -> + let (output_amount, outputs) = outputs nb_output proving_ctx vk in + let input_amount = + List.fold_left + (fun sum {amount; _} -> + assert ( + Int64.compare + sum + (Int64.sub + Int64.max_int + Tezos_sapling.Core.Validator.UTXO.max_amount) + < 0) ; + Int64.add sum amount) + 0L + to_forge + in + let balance = Int64.sub input_amount output_amount in + let binding_sig = + Tezos_sapling.Core.Client.Proving.make_binding_sig + proving_ctx + inputs + outputs + ~balance + anti_replay + in + let transaction = + Tezos_sapling.Core.Validator.UTXO. + {inputs; outputs; binding_sig; balance; root} + in + return transaction) + >>=? fun transaction -> + assert (List.length transaction.inputs = nb_input) ; + assert (List.length transaction.outputs = nb_output) ; + return (transaction, (ctxt, id)) + +(* ------------------------------------------------------------------------- *) +(* Nicely packaging sapling generation for snoop *) + +let sapling_transition_encoding = + let open Data_encoding in + conv + (fun {state_seed; nullifier_count; commitment_count; sapling_tx} -> + (state_seed, nullifier_count, commitment_count, sapling_tx)) + (fun (state_seed, nullifier_count, commitment_count, sapling_tx) -> + {state_seed; nullifier_count; commitment_count; sapling_tx}) + (obj4 + (req "state_seed" int64) + (req "nullifier_count" int64) + (req "commitment_count" int64) + (req "sapling_tx" Alpha_context.Sapling.transaction_encoding)) + +let sapling_dataset_encoding = Data_encoding.list sapling_transition_encoding + +let save ~filename ~txs = + let bytes = + match Data_encoding.Binary.to_bytes sapling_dataset_encoding txs with + | Error err -> + Format.eprintf + "Sapling_generation.save: encoding failed (%a); exiting" + Data_encoding.Binary.pp_write_error + err ; + exit 1 + | Ok res -> res + in + ignore (* TODO handle error *) + (Lwt_main.run + @@ Tezos_stdlib_unix.Lwt_utils_unix.create_file + filename + (Bytes.unsafe_to_string bytes)) + +let load_file filename = + Lwt_main.run + @@ ( Tezos_stdlib_unix.Lwt_utils_unix.read_file filename >>= fun str -> + Format.eprintf "Sapling_generation.load: loaded %s@." filename ; + let bytes = Bytes.unsafe_of_string str in + match Data_encoding.Binary.of_bytes sapling_dataset_encoding bytes with + | Ok result -> + let result = List.map (fun tx -> (filename, tx)) result in + Lwt.return result + | Error err -> + Format.eprintf + "Sapling_generation.load: can't load file (%a); exiting" + Data_encoding.Binary.pp_read_error + err ; + exit 1 ) + +let get_all_sapling_data_files directory = + let is_sapling_data file = + let regexp = Str.regexp ".*\\.sapling" in + Str.string_match regexp file 0 + in + let lift file = directory ^ "/" ^ file in + let handle = Unix.opendir directory in + let rec loop acc = + match Unix.readdir handle with + | file -> if is_sapling_data file then loop (lift file :: acc) else loop acc + | exception End_of_file -> + Unix.closedir handle ; + acc + in + loop [] + +let load ~filename = + if not (Sys.file_exists filename) then ( + Format.eprintf "Sapling_generation.load: file does not exist@." ; + Stdlib.failwith "Sapling_generation.load") + else if Sys.is_directory filename then + let () = + Format.eprintf + "Sapling_generation.load: loading all .sapling files from directory \ + %s@." + filename + in + let files = get_all_sapling_data_files filename in + List.concat (List.map load_file files) + else load_file filename + +let shared_seed = [|9798798; 217861209; 876786|] + +let generate (save_to : string) (tx_count : int) + (sapling_gen_options : sapling_gen_options) = + let result = + Lwt_main.run + (let { + max_inputs; + max_outputs; + max_nullifiers; + max_additional_commitments; + seed; + } = + sapling_gen_options + in + let rng_state = + (* /!\ This must match the seed used at benchmark time, + defined in Runner.benchmark_sapling. /!\ *) + Random.State.make + @@ Option.fold ~none:shared_seed ~some:(fun seed -> [|seed|]) seed + in + Execution_context.make ~rng_state >>=? fun (ctxt, step_constants) -> + let address = Alpha_context.Contract.to_b58check step_constants.self in + let chain_id = + Environment.Chain_id.to_b58check step_constants.chain_id + in + let anti_replay = address ^ chain_id in + let ctxt = alpha_to_raw ctxt in + (match sapling_gen_options.seed with + | None -> Random.self_init () + | Some seed -> Random.init seed) ; + let seeds = + Stdlib.List.init tx_count (fun i -> (i, Random.int 0x3FFFFFFF)) + in + let rec loop seeds acc = + match seeds with + | [] -> return acc + | (i, seed) :: tl -> + let nb_input = 1 + Random.int max_inputs in + let nb_output = 1 + Random.int max_outputs in + let nb_nf = 1 + Random.int max_nullifiers in + let nb_cm = + nb_input + nb_nf + Random.int max_additional_commitments + in + let () = + Format.eprintf "@." ; + Format.eprintf "generating sapling tx %i/%d@." (i + 1) tx_count ; + Format.eprintf "saving to file %s@." save_to ; + Format.eprintf "nb_input = %d@." nb_input ; + Format.eprintf "nb_output = %d@." nb_output ; + Format.eprintf "nb_nf = %d@." nb_nf ; + Format.eprintf "nb_cm = %d@." nb_cm ; + Format.eprintf "anti_replay = %s@." anti_replay + in + let state = Random.State.make [|seed|] in + generate + ~nb_input + ~nb_output + ~nb_nf + ~nb_cm + ~anti_replay + ~ctxt + state + >>=? fun (tx, (_ctxt, _state_id)) -> + let result = + { + state_seed = Int64.of_int seed; + nullifier_count = Int64.of_int nb_nf; + commitment_count = Int64.of_int nb_cm; + sapling_tx = Obj.magic tx; + } + in + loop tl (result :: acc) + in + loop seeds []) + in + match result with Ok txs -> save ~filename:save_to ~txs | Error _ -> () + +let apply_diff ctxt id diff = + let open Protocol.Environment.Error_monad in + Sapling_storage.apply_diff (alpha_to_raw ctxt) id diff + >>=? fun (ctxt, size) -> return (raw_to_alpha ctxt, size) diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/script_repr_benchmarks.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/script_repr_benchmarks.ml new file mode 100644 index 000000000000..dbe9f16b0161 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/script_repr_benchmarks.ml @@ -0,0 +1,111 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(** {2 [Script_repr] benchmarks} *) + +module Script_repr_shared_config = struct + type config = unit + + let config_encoding = Data_encoding.unit + + let default_config = () + + type workload = {micheline_nodes : int} + + let workload_encoding = + let open Data_encoding in + conv + (fun {micheline_nodes} -> micheline_nodes) + (fun micheline_nodes -> {micheline_nodes}) + (obj1 (req "micheline_nodes" int31)) + + let tags = [Tags.translator] + + let workload_to_vector {micheline_nodes} = + Sparse_vec.String.of_list [("nodes", float_of_int micheline_nodes)] +end + +module Sampler = Micheline_sampler.Make (struct + type prim = Michelson_v1_primitives.prim + + (* The runtime of the functions in [Script_repr] do not depend on the primitives. *) + let sample_prim : Michelson_v1_primitives.prim Base_samplers.sampler = + fun _rng_state -> I_ADD + + let sample_annots : string list Base_samplers.sampler = fun _rng_state -> [] + + let sample_string = Base_samplers.uniform_string ~nbytes:4 + + let sample_bytes = Base_samplers.uniform_bytes ~nbytes:4 + + let sample_z = Base_samplers.int ~size:{min = 1; max = 8} + + let width_function = Micheline_sampler.reasonable_width_function +end) + +module Micheline_nodes_benchmark : Benchmark.S = struct + include Script_repr_shared_config + + let name = "MICHELINE_NODES" + + let info = + "Benchmarking the time it takes to compute the number of nodes of a \ + Micheline term" + + let size_based_model = + Model.make + ~conv:(function {micheline_nodes} -> (micheline_nodes, ())) + ~model: + (Model.affine + ~intercept: + (Free_variable.of_string (Format.asprintf "%s_const" name)) + ~coeff: + (Free_variable.of_string + (Format.asprintf "%s_ns_per_node_coeff" name))) + + let () = + Registration_helpers.register_for_codegen + name + (Model.For_codegen size_based_model) + + let models = [("size_translator_model", size_based_model)] + + let micheline_nodes_benchmark node = + let nodes = Script_repr.micheline_nodes node in + let workload = {micheline_nodes = nodes} in + let closure () = ignore (Script_repr.micheline_nodes node) in + Generator.Plain {workload; closure} + + let make_bench rng_state _cfg () = + let term = Sampler.sample rng_state in + micheline_nodes_benchmark term + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Micheline_nodes_benchmark) diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/script_typed_ir_size_benchmarks.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/script_typed_ir_size_benchmarks.ml new file mode 100644 index 000000000000..ed41588b36af --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/script_typed_ir_size_benchmarks.ml @@ -0,0 +1,342 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(** {2 {!Script_typed_ir_size}-related benchmarks} *) + +(** Benchmarking {!Script_typed_ir_size.value_size}. *) + +let model_name = "ir_size_model" + +module Size_benchmarks_shared_config = struct + include Translator_benchmarks.Config + + type workload = {size : int} + + let workload_encoding : workload Data_encoding.t = + let open Data_encoding in + def "size_encoding" + @@ conv (fun {size} -> size) (fun size -> {size}) (obj1 (req "size" int31)) + + let workload_to_vector {size} = + Sparse_vec.String.of_list [("size", float_of_int size)] + + let tags = [Tags.translator] + + let size_based_model name = + let intercept_variable = + Free_variable.of_string (Format.asprintf "%s_const" name) + in + let coeff_variable = + Free_variable.of_string (Format.asprintf "%s_size_coeff" name) + in + Model.make + ~conv:(function {size} -> (size, ())) + ~model:(Model.affine ~intercept:intercept_variable ~coeff:coeff_variable) +end + +module Value_size_benchmark : sig + include Tezos_benchmark.Benchmark.S + + val size_based_model : string -> workload Model.t +end = struct + include Size_benchmarks_shared_config + + let name = "VALUE_SIZE" + + let models = [(model_name, size_based_model name)] + + let info = "Benchmarking Script_typed_ir_size.value_size" + + let value_size_benchmark rng_state (node : Protocol.Script_repr.expr) + (michelson_type : Script_repr.expr) = + (* FIXME: cleanup and factorize this code between translator benches and these ones. *) + let open Translator_benchmarks in + Lwt_main.run + ( Execution_context.make ~rng_state >>=? fun (ctxt, _) -> + let (ex_ty, ctxt) = + Michelson_generation.michelson_type_to_ex_ty michelson_type ctxt + in + match ex_ty with + | Script_ir_translator.Ex_ty ty -> ( + match + Lwt_main.run + (Script_ir_translator.parse_data + ctxt + ~legacy:false + ~allow_forged:false + ty + (Micheline.root node)) + with + | Error _ | (exception _) -> + bad_data name node michelson_type In_protocol + | Ok (value, _) -> + let open Script_typed_ir_size in + let open Cache_memory_helpers in + let size = Nodes.(to_int (fst (value_size ty value))) in + let workload = {size} in + let closure () = ignore (value_size ty value) in + return (Generator.Plain {workload; closure})) ) + |> function + | Ok closure -> closure + | Error errs -> global_error name errs + + let make_bench rng_state cfg () = + match + Michelson_generation.make_data_sampler rng_state cfg.generator_config + with + | Data {term; typ} -> value_size_benchmark rng_state term typ + | _ -> assert false + + let create_benchmarks ~rng_state ~bench_num config = + match config.michelson_terms_file with + | Some file -> + Format.eprintf "Loading terms from %s@." file ; + let terms = Michelson_generation.load ~filename:file in + List.filter_map + (function + | Michelson_generation.Data {term; typ} -> + Some (fun () -> value_size_benchmark rng_state term typ) + | _ -> None) + terms + | None -> + Format.eprintf "No michelson_terms_file given, generating on-the-fly@." ; + List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Value_size_benchmark) + +(** Benchmarking {!Script_typed_ir_size.ty_size}. *) + +module Type_size_benchmark : Tezos_benchmark.Benchmark.S = struct + include Size_benchmarks_shared_config + + type config = unit + + let config_encoding = Data_encoding.unit + + let default_config = () + + let name = "TYPE_SIZE" + + let info = + "Benchmarking the time it takes to compute Script_typed_ir_size.ty_size" + + let models = [(model_name, size_based_model name)] + + let type_size_benchmark (Script_ir_translator.Ex_ty ty) = + let open Script_typed_ir_size in + let open Cache_memory_helpers in + let size = Nodes.(to_int (fst (ty_size ty))) in + let workload = {size} in + let closure () = ignore (ty_size ty) in + Generator.Plain {workload; closure} + + let make_bench rng_state _cfg () = + (* The [size] here is a parameter to the random sampler and does not + match the [size] returned by [type_size]. *) + let size = + Base_samplers.sample_in_interval ~range:{min = 1; max = 1000} rng_state + in + let ex_ty = + Michelson_generation.Samplers.Random_type.m_type ~size rng_state + in + type_size_benchmark ex_ty + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Type_size_benchmark) + +(** Benchmarking {!Script_typed_ir_size.comparable_ty_size}. *) + +module Comparable_type_size_benchmark : Tezos_benchmark.Benchmark.S = struct + include Size_benchmarks_shared_config + + let name = "COMPARABLE_TYPE_SIZE" + + let info = + "Benchmarking the time it takes to compute \ + Script_typed_ir_size.comparable_ty_size" + + let models = [(model_name, size_based_model name)] + + let type_size_benchmark (Script_ir_translator.Ex_comparable_ty ty) = + let workload = + let open Script_typed_ir_size in + let open Cache_memory_helpers in + {size = Nodes.to_int @@ fst @@ comparable_ty_size ty} + in + let closure () = ignore (Script_typed_ir_size.comparable_ty_size ty) in + Generator.Plain {workload; closure} + + let make_bench rng_state _cfg () = + (* The [size] here is a parameter to the random sampler and does not + match the [size] returned by [type_size]. *) + let size = + Base_samplers.sample_in_interval ~range:{min = 1; max = 1000} rng_state + in + let ex_ty = + Michelson_generation.Samplers.Random_type.m_comparable_type + ~size + rng_state + in + type_size_benchmark ex_ty + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Comparable_type_size_benchmark) + +(** Benchmarking {!Script_typed_ir_size.kinstr_size}. *) + +module Kinstr_size_benchmark : sig + include Tezos_benchmark.Benchmark.S + + val size_based_model : string -> workload Model.t +end = struct + include Size_benchmarks_shared_config + + let name = "KINSTR_SIZE" + + let models = [(model_name, size_based_model name)] + + let info = "Benchmarking Script_typed_ir_size.kinstr_size" + + let kinstr_size_benchmark rng_state (expr : Protocol.Script_repr.expr) + (stack : Script_repr.expr list) = + (* FIXME: cleanup and factorize this code between translator benches and these ones. *) + let open Translator_benchmarks in + Lwt_main.run + ( Execution_context.make ~rng_state >>=? fun (ctxt, _) -> + let (ex_stack_ty, ctxt) = + Michelson_generation.michelson_type_list_to_ex_stack_ty stack ctxt + in + let (Script_ir_translator.Ex_stack_ty bef) = ex_stack_ty in + let node = Micheline.root expr in + match + Lwt_main.run + (Script_ir_translator.parse_instr + Script_ir_translator.Lambda + ctxt + ~legacy:false + node + bef) + with + | Error _ | (exception _) -> bad_code name expr stack In_protocol + | Ok (Failed {descr}, _) -> + let kdescr = Script_ir_translator.close_descr (descr Bot_t) in + let kinstr = kdescr.kinstr in + let workload = + let open Script_typed_ir_size in + let open Cache_memory_helpers in + {size = Nodes.to_int @@ fst @@ kinstr_size kinstr} + in + let closure () = ignore (Script_typed_ir_size.kinstr_size kinstr) in + return (Generator.Plain {workload; closure}) + | Ok (Typed descr, _) -> + let kdescr = Script_ir_translator.close_descr descr in + let kinstr = kdescr.kinstr in + let workload = + let open Script_typed_ir_size in + let open Cache_memory_helpers in + {size = Nodes.to_int @@ fst @@ kinstr_size kinstr} + in + let closure () = ignore (Script_typed_ir_size.kinstr_size kinstr) in + return (Generator.Plain {workload; closure}) ) + |> function + | Ok closure -> closure + | Error errs -> global_error name errs + + let make_bench rng_state cfg () = + match + Michelson_generation.make_code_sampler rng_state cfg.generator_config + with + | Code {term; bef} -> kinstr_size_benchmark rng_state term bef + | _ -> assert false + + let create_benchmarks ~rng_state ~bench_num config = + match config.michelson_terms_file with + | Some file -> + Format.eprintf "Loading terms from %s@." file ; + let terms = Michelson_generation.load ~filename:file in + List.filter_map + (function + | Michelson_generation.Code {term; bef} -> + Some (fun () -> kinstr_size_benchmark rng_state term bef) + | _ -> None) + terms + | None -> + Format.eprintf "No michelson_terms_file given, generating on-the-fly@." ; + List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Kinstr_size_benchmark) + +module Node_size_benchmark : Benchmark.S = struct + include Script_repr_benchmarks.Script_repr_shared_config + + let name = "NODE_SIZE" + + let info = + "Benchmarking the time it takes to compute Script_typed_ir_size.node_size" + + let size_based_model = + Model.make + ~conv:(function {micheline_nodes} -> (micheline_nodes, ())) + ~model: + (Model.affine + ~intercept: + (Free_variable.of_string (Format.asprintf "%s_const" name)) + ~coeff: + (Free_variable.of_string + (Format.asprintf "%s_ns_per_node_coeff" name))) + + let () = + Registration_helpers.register_for_codegen + name + (Model.For_codegen size_based_model) + + let models = [(model_name, size_based_model)] + + let micheline_nodes_benchmark node = + let open Cache_memory_helpers in + let nodes = Nodes.to_int @@ fst @@ node_size node in + let workload = {micheline_nodes = nodes} in + let closure () = ignore (Script_typed_ir_size.node_size node) in + Generator.Plain {workload; closure} + + let make_bench rng_state _cfg () = + let term = Script_repr_benchmarks.Sampler.sample rng_state in + micheline_nodes_benchmark term + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Node_size_benchmark) diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/size.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/size.ml new file mode 100644 index 000000000000..7604a14f7509 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/size.ml @@ -0,0 +1,204 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +type t = int + +type micheline_size = {traversal : t; int_bytes : t; string_bytes : t} + +(* ------------------------------------------------------------------------- *) +(* encoding *) + +let encoding : t Data_encoding.encoding = + let open Data_encoding in + conv (fun i -> Int64.of_int i) (fun l -> Int64.to_int l) int64 + +let micheline_size_encoding : micheline_size Data_encoding.encoding = + let open Data_encoding in + conv + (fun {traversal; int_bytes; string_bytes} -> + (traversal, int_bytes, string_bytes)) + (fun (traversal, int_bytes, string_bytes) -> + {traversal; int_bytes; string_bytes}) + (tup3 encoding encoding encoding) + +(* ------------------------------------------------------------------------- *) + +let zero = 0 + +let one = 1 + +let add = ( + ) + +let sub = ( - ) + +let mul = ( * ) + +let div = ( / ) + +let max x y = if x < y then y else x + +let min x y = if x < y then x else y + +(* can't be bothered to do it well *) +let rec pow x i = if i = 0 then 1 else x * pow x (i - 1) + +module Ops = struct + let ( * ) = mul + + let ( / ) = div + + let ( + ) = add + + let ( - ) = sub + + let ( ** ) = pow +end + +let compare = Stdlib.compare + +let equal = ( = ) + +let lt = ( < ) + +let leq = ( <= ) + +let pp = Format.pp_print_int + +let pp_micheline_size fmtr {traversal; int_bytes; string_bytes} = + Format.fprintf + fmtr + "@[{ traversal = %a;@; int_bytes = %a;@; string_bytes = %a;@,}@]" + pp + traversal + pp + int_bytes + pp + string_bytes + +let show = string_of_int + +let to_float = float_of_int + +let of_float = int_of_float + +let to_int x = x + +let of_int x = x + +let log2 x = Z.log2 (Z.of_int x) + +let unit : t = 1 + +let integer (i : 'a Alpha_context.Script_int.num) : t = + Z.numbits (Alpha_context.Script_int.to_zint i) / 8 + +let string = Alpha_context.Script_string.length + +let bytes (b : Bytes.t) : t = Bytes.length b + +let mutez (_tez : Alpha_context.Tez.tez) : t = + (* Up to now, mutez are stored on 8 bytes (int64). *) + 8 + +let bool (_ : bool) : t = 1 + +let signature (_signature : Signature.t) : t = Signature.size + +let key_hash (_keyhash : Signature.public_key_hash) : t = + Signature.Public_key_hash.size + +let public_key (public_key : Signature.public_key) : t = + Signature.Public_key.size public_key + +let chain_id (_chain_id : Chain_id.t) : t = Chain_id.size + +let address (addr : Script_typed_ir.address) : t = + let (_contract, entrypoint) = addr in + Signature.Public_key_hash.size + String.length entrypoint + +let list (list : 'a Script_typed_ir.boxed_list) : t = + list.Script_typed_ir.length + +let set (set : 'a Script_typed_ir.set) : t = + let res = Alpha_context.Script_int.to_int (Script_set.size set) in + match res with None -> assert false | Some x -> x + +let map (map : ('a, 'b) Script_typed_ir.map) : t = + let res = Alpha_context.Script_int.to_int (Script_map.size map) in + match res with None -> assert false | Some x -> x + +let timestamp (tstamp : Alpha_context.Script_timestamp.t) : t = + Z.numbits (Alpha_context.Script_timestamp.to_zint tstamp) / 8 + +(* ------------------------------------------------------------------------- *) +(* Micheline/Michelson-related *) + +let micheline_zero = {traversal = 0; int_bytes = 0; string_bytes = 0} + +let ( ++ ) x y = + { + traversal = Ops.(x.traversal + y.traversal); + int_bytes = Ops.(x.int_bytes + y.int_bytes); + string_bytes = Ops.(x.string_bytes + y.string_bytes); + } + +let node leaves = + let r = List.fold_left ( ++ ) micheline_zero leaves in + {r with traversal = Ops.(r.traversal + 1)} + +let rec of_micheline (x : ('a, 'b) Micheline.node) = + match x with + | Micheline.Int (_loc, z) -> + let int_bytes = integer (Alpha_context.Script_int.of_zint z) in + {traversal = 1; int_bytes; string_bytes = 0} + | Micheline.String (_loc, s) -> + let string_bytes = String.length s in + {traversal = 1; int_bytes = 0; string_bytes} + | Micheline.Bytes (_loc, b) -> + let string_bytes = bytes b in + {traversal = 1; int_bytes = 0; string_bytes} + | Micheline.Prim (_loc, _prim, subterms, _annot) -> + node (List.map of_micheline subterms) + | Micheline.Seq (_loc, subterms) -> node (List.map of_micheline subterms) + +let of_encoded_value : + type a. Alpha_context.t -> a Script_typed_ir.ty -> a -> micheline_size = + fun (type a) ctxt (ty : a Script_typed_ir.ty) (v : a) -> + let open Script_ir_translator in + let script_res = Lwt_main.run (unparse_data ctxt Optimized ty v) in + match script_res with + | Ok (node, _ctxt) -> of_micheline node + | Error _ -> Stdlib.failwith "sizeof: could not unparse" + +(* ------------------------------------------------------------------------- *) +(* Sapling-related *) + +let sapling_transaction_inputs : Alpha_context.Sapling.transaction -> t = + fun tx -> List.length tx.Tezos_sapling.Core.Client.UTXO.inputs + +let sapling_transaction_outputs : Alpha_context.Sapling.transaction -> t = + fun tx -> List.length tx.Tezos_sapling.Core.Client.UTXO.outputs diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/tags.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/tags.ml new file mode 100644 index 000000000000..2748e3551ccd --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/tags.ml @@ -0,0 +1,32 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let interpreter = "interpreter" + +let translator = "translator" + +let encoding = "encoding" + +let cache = "cache" diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/tezos-benchmarks-proto-011-PtHangzH.opam b/src/proto_011_PtHangzH/lib_benchmarks_proto/tezos-benchmarks-proto-011-PtHangzH.opam new file mode 100644 index 000000000000..96a6e4ad967c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/tezos-benchmarks-proto-011-PtHangzH.opam @@ -0,0 +1,28 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "tezos-tooling" { with-test } + "dune" { >= "2.0" } + "tezos-base" + "tezos-benchmark" + "tezos-benchmark-011-PtHangzH" + "tezos-protocol-environment" + "tezos-protocol-011-PtHangzH" + "tezos-protocol-011-PtHangzH-parameters" + "tezos-shell-benchmarks" + "tezos-micheline" + "tezos-011-PtHangzH-test-helpers" + "tezos-sapling" + "tezos-client-011-PtHangzH" + +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: protocol benchmarks" diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/translator_benchmarks.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/translator_benchmarks.ml new file mode 100644 index 000000000000..7225ffbb3f55 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/translator_benchmarks.ml @@ -0,0 +1,775 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Script_typed_ir + +(** {2 [Script_ir_translator] benchmarks} *) + +module Config = struct + type config = { + generator_config : Michelson_generation.generator_config; + michelson_terms_file : string option; + } + + let default_config = + { + generator_config = Michelson_generation.default_generator_config; + michelson_terms_file = None; + } + + let config_encoding = + let open Data_encoding in + conv + (fun {generator_config; michelson_terms_file} -> + (generator_config, michelson_terms_file)) + (fun (generator_config, michelson_terms_file) -> + {generator_config; michelson_terms_file}) + (obj2 + (req "generator_config" Michelson_generation.generator_config_encoding) + (opt "michelson_terms_file" string)) +end + +module Default_boilerplate = struct + type workload = Translator_workload.t + + let workload_encoding = Translator_workload.encoding + + let workload_to_vector = Translator_workload.workload_to_sparse_vec + + let tags = [Tags.translator] + + let make_models t_kind code_or_data = + [ + ( "gas_translator_model", + Translator_model.gas_based_model t_kind code_or_data ); + ( "size_translator_model", + Translator_model.size_based_model t_kind code_or_data ); + ] +end + +(* ----------------------------------------------------------------------- *) +(* Error handling *) + +type phase = Workload_production | In_protocol | Global + +type error_kind = + | Global_error of { + benchmark_name : string; + workload : Tezos_base.TzPervasives.tztrace; + } + | Bad_data of { + benchmark_name : string; + micheline : Alpha_context.Script.expr; + expected_type : Alpha_context.Script.expr; + phase : phase; + } + | Bad_code of { + benchmark_name : string; + micheline : Alpha_context.Script.expr; + expected_stack_type : Alpha_context.Script.expr list; + phase : phase; + } + +let pp_phase fmtr (phase : phase) = + match phase with + | Workload_production -> Format.fprintf fmtr "workload production" + | In_protocol -> Format.fprintf fmtr "in protocol" + | Global -> Format.fprintf fmtr "global" + +let report_michelson_errors fmtr errs = + Michelson_v1_error_reporter.report_errors + ~details:true + ~show_source:true + fmtr + errs + +let make_printable node = + Micheline_printer.printable Michelson_v1_primitives.string_of_prim node + +let pp_error_kind fmtr (error_kind : error_kind) = + match error_kind with + | Global_error {benchmark_name; workload} -> + Format.open_vbox 1 ; + Format.fprintf fmtr "Global error:@," ; + Format.fprintf fmtr "benchmark = %s@," benchmark_name ; + Format.fprintf fmtr "workload:@," ; + report_michelson_errors fmtr workload ; + Format.close_box () + | Bad_data {benchmark_name; micheline; expected_type; phase} -> + Format.open_vbox 1 ; + Format.fprintf fmtr "Bad data:@," ; + Format.fprintf fmtr "benchmark = %s@," benchmark_name ; + Format.fprintf + fmtr + "expression = @[%a@]@," + Micheline_printer.print_expr + (make_printable micheline) ; + Format.fprintf + fmtr + "expected type = @[%a@]@," + Micheline_printer.print_expr + (make_printable expected_type) ; + Format.fprintf fmtr "phase = %a@," pp_phase phase ; + Format.close_box () + | Bad_code {benchmark_name; micheline; expected_stack_type; phase} -> + Format.open_vbox 1 ; + Format.fprintf fmtr "Bad code:@," ; + Format.fprintf fmtr "benchmark = %s@," benchmark_name ; + Format.fprintf + fmtr + "expression = @[%a@]@," + Micheline_printer.print_expr + (make_printable micheline) ; + Format.fprintf + fmtr + "expected stack = @[%a@]@," + (Format.pp_print_list + ~pp_sep:(fun fmtr () -> Format.fprintf fmtr "::") + (fun fmtr node -> + let printable = make_printable node in + Format.fprintf fmtr "%a" Micheline_printer.print_expr printable)) + expected_stack_type ; + Format.fprintf fmtr "phase = %a@," pp_phase phase ; + Format.close_box () + +exception Translator_benchmark_error of error_kind + +let () = + Printexc.register_printer (function + | Translator_benchmark_error err -> + Some (Format.asprintf "%a" pp_error_kind err) + | _ -> None) + +let global_error benchmark_name workload = + raise (Translator_benchmark_error (Global_error {benchmark_name; workload})) + +let bad_data benchmark_name micheline expected_type phase = + raise + (Translator_benchmark_error + (Bad_data {benchmark_name; micheline; expected_type; phase})) + +let bad_code benchmark_name micheline expected_stack_type phase = + raise + (Translator_benchmark_error + (Bad_code {benchmark_name; micheline; expected_stack_type; phase})) + +(* ----------------------------------------------------------------------- *) +(* Typechecking data (Micheline data -> typed data) *) + +module Typechecking_data : Benchmark.S = struct + include Config + include Default_boilerplate + + let models = make_models Translator_workload.Parsing Translator_workload.Data + + let name = "TYPECHECKING_DATA" + + let info = "Benchmarking typechecking of data" + + let typechecking_data_benchmark rng_state (node : Protocol.Script_repr.expr) + (michelson_type : Script_repr.expr) = + Lwt_main.run + ( Execution_context.make ~rng_state >>=? fun (ctxt, _) -> + let (ex_ty, ctxt) = + Michelson_generation.michelson_type_to_ex_ty michelson_type ctxt + in + let workload = + match + Translator_workload.data_typechecker_workload + ctxt + Translator_workload.Parsing + (Micheline.root node) + ex_ty + with + | None -> bad_data name node michelson_type Workload_production + | Some workload -> workload + in + match ex_ty with + | Script_ir_translator.Ex_ty ty -> + let closure () = + match + Lwt_main.run + (Script_ir_translator.parse_data + ctxt + ~legacy:false + ~allow_forged:false + ty + (Micheline.root node)) + with + | Error _ | (exception _) -> + bad_data name node michelson_type In_protocol + | Ok _ -> () + in + return (Generator.Plain {workload; closure}) ) + |> function + | Ok closure -> closure + | Error errs -> global_error name errs + + let make_bench rng_state cfg () = + match + Michelson_generation.make_data_sampler rng_state cfg.generator_config + with + | Data {term; typ} -> typechecking_data_benchmark rng_state term typ + | _ -> assert false + + let create_benchmarks ~rng_state ~bench_num config = + match config.michelson_terms_file with + | Some file -> + Format.eprintf "Loading terms from %s@." file ; + let terms = Michelson_generation.load ~filename:file in + List.filter_map + (function + | Michelson_generation.Data {term; typ} -> + Some (fun () -> typechecking_data_benchmark rng_state term typ) + | _ -> None) + terms + | None -> + Format.eprintf "No michelson_terms_file given, generating on-the-fly@." ; + List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Typechecking_data) + +module Unparsing_data : Benchmark.S = struct + include Config + include Default_boilerplate + + let models = + make_models Translator_workload.Unparsing Translator_workload.Data + + let name = "UNPARSING_DATA" + + let info = "Benchmarking unparsing of data" + + let unparsing_data_benchmark rng_state (node : Protocol.Script_repr.expr) + (michelson_type : Protocol.Script_repr.expr) = + Lwt_main.run + ( Execution_context.make ~rng_state >>=? fun (ctxt, _) -> + let (ex_ty, ctxt) = + Michelson_generation.michelson_type_to_ex_ty michelson_type ctxt + in + let workload = + match + Translator_workload.data_typechecker_workload + ctxt + Translator_workload.Unparsing + (Micheline.root node) + ex_ty + with + | None -> bad_data name node michelson_type Workload_production + | Some workload -> workload + in + match ex_ty with + | Script_ir_translator.Ex_ty ty -> + Script_ir_translator.parse_data + ctxt + ~legacy:false + ~allow_forged:false + ty + (Micheline.root node) + >|= Environment.wrap_tzresult + >>=? fun (typed, ctxt) -> + let closure () = + match + Lwt_main.run + (Script_ir_translator.unparse_data + ctxt + Script_ir_translator.Optimized + ty + typed) + with + | Error _ | (exception _) -> + bad_data name node michelson_type In_protocol + | Ok _ -> () + in + return (Generator.Plain {workload; closure}) ) + |> function + | Ok closure -> closure + | Error errs -> global_error name errs + + let make_bench rng_state cfg () = + match + Michelson_generation.make_data_sampler rng_state cfg.generator_config + with + | Data {term; typ} -> unparsing_data_benchmark rng_state term typ + | _ -> assert false + + let create_benchmarks ~rng_state ~bench_num config = + match config.michelson_terms_file with + | Some file -> + Format.eprintf "Loading terms from %s@." file ; + let terms = Michelson_generation.load ~filename:file in + List.filter_map + (function + | Michelson_generation.Data {term; typ} -> + Some (fun () -> unparsing_data_benchmark rng_state term typ) + | _ -> None) + terms + | None -> + Format.eprintf "No michelson_terms_file given, generating on-the-fly@." ; + List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Unparsing_data) + +(* The new elaborator expects one more element at the bottom of the stack. *) +let cushion_stack_type type_list = + type_list @ [Michelson_generation.base_type_to_michelson_type Type.unit] + +module Typechecking_code : Benchmark.S = struct + include Config + include Default_boilerplate + + let models = make_models Translator_workload.Parsing Translator_workload.Code + + let name = "TYPECHECKING_CODE" + + let info = "Benchmarking typechecking of code" + + let typechecking_code_benchmark rng_state (node : Protocol.Script_repr.expr) + (stack : Script_repr.expr list) = + Lwt_main.run + ( Execution_context.make ~rng_state >>=? fun (ctxt, _) -> + let (ex_stack_ty, ctxt) = + Michelson_generation.michelson_type_list_to_ex_stack_ty stack ctxt + in + let workload = + match + Translator_workload.code_typechecker_workload + ctxt + Translator_workload.Parsing + (Micheline.root node) + ex_stack_ty + with + | None -> bad_code name node stack Workload_production + | Some workload -> workload + in + let (Script_ir_translator.Ex_stack_ty bef) = ex_stack_ty in + let closure () = + let result = + Lwt_main.run + (Script_ir_translator.parse_instr + Script_ir_translator.Lambda + ctxt + ~legacy:false + (Micheline.root node) + bef) + in + match Environment.wrap_tzresult result with + | Error errs -> + Format.eprintf "%a@." Error_monad.pp_print_error errs ; + bad_code name node stack In_protocol + | Ok _ -> () + in + return (Generator.Plain {workload; closure}) ) + |> function + | Ok closure -> closure + | Error errs -> global_error name errs + + let make_bench rng_state (cfg : Config.config) () = + let open Michelson_generation in + match make_code_sampler rng_state cfg.generator_config with + | Code {term; bef} -> typechecking_code_benchmark rng_state term bef + | Data _ -> assert false + + let create_benchmarks ~rng_state ~bench_num config = + match config.michelson_terms_file with + | Some file -> + Format.eprintf "Loading terms from %s@." file ; + let terms = Michelson_generation.load ~filename:file in + List.filter_map + (function + | Michelson_generation.Code {term; bef} -> + Some (fun () -> typechecking_code_benchmark rng_state term bef) + | _ -> None) + terms + | None -> + Format.eprintf "No michelson_terms_file given, generating on-the-fly@." ; + List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Typechecking_code) + +module Unparsing_code : Benchmark.S = struct + include Config + include Default_boilerplate + + let models = + make_models Translator_workload.Unparsing Translator_workload.Code + + let name = "UNPARSING_CODE" + + let info = "Benchmarking unparsing of code" + + let unparsing_code_benchmark rng_state (node : Protocol.Script_repr.expr) + (stack : Script_repr.expr list) = + Lwt_main.run + ( Execution_context.make ~rng_state >>=? fun (ctxt, _) -> + let (ex_stack_ty, ctxt) = + Michelson_generation.michelson_type_list_to_ex_stack_ty stack ctxt + in + let workload = + match + Translator_workload.code_typechecker_workload + ctxt + Translator_workload.Unparsing + (Micheline.root node) + ex_stack_ty + with + | None -> bad_code name node stack Workload_production + | Some workload -> workload + in + let (Script_ir_translator.Ex_stack_ty bef) = ex_stack_ty in + (* We parse the code just to check it is well-typed. *) + Script_ir_translator.parse_instr + Script_ir_translator.Lambda + ctxt + ~legacy:false + (Micheline.root node) + bef + >|= Environment.wrap_tzresult + >>=? fun (_typed, ctxt) -> + let closure () = + let result = + Lwt_main.run + (Script_ir_translator.unparse_code + ctxt + Optimized + (Micheline.root node)) + in + match Environment.wrap_tzresult result with + | Error errs -> + Format.eprintf "%a@." Error_monad.pp_print_error errs ; + bad_code name node stack In_protocol + | Ok _ -> () + in + return (Generator.Plain {workload; closure}) ) + |> function + | Ok closure -> closure + | Error errs -> global_error name errs + + let make_bench rng_state (cfg : Config.config) () = + let open Michelson_generation in + match make_code_sampler rng_state cfg.generator_config with + | Code {term; bef} -> unparsing_code_benchmark rng_state term bef + | Data _ -> assert false + + let create_benchmarks ~rng_state ~bench_num config = + match config.michelson_terms_file with + | Some file -> + Format.eprintf "Loading terms from %s@." file ; + let terms = Michelson_generation.load ~filename:file in + List.filter_map + (function + | Michelson_generation.Code {term; bef} -> + Some (fun () -> unparsing_code_benchmark rng_state term bef) + | _ -> None) + terms + | None -> List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Unparsing_code) + +let rec check_printable_ascii v i = + if Compare.Int.(i < 0) then true + else + match v.[i] with + | '\n' | '\x20' .. '\x7E' -> check_printable_ascii v (i - 1) + | _ -> false + +let check_printable_benchmark = + let open Tezos_shell_benchmarks.Encoding_benchmarks_helpers in + linear_shared + ~name:"CHECK_PRINTABLE" + ~generator:(fun rng_state -> + let open Base_samplers in + let string = + readable_ascii_string rng_state ~size:{min = 1; max = 1024} + in + (string, {Shared_linear.bytes = String.length string})) + ~make_bench:(fun generator () -> + let (generated, workload) = generator () in + let closure () = + ignore (check_printable_ascii generated (String.length generated - 1)) + in + Generator.Plain {workload; closure}) + +let () = Registration_helpers.register check_printable_benchmark + +module Merge_types : Benchmark.S = struct + type config = {max_size : int} + + let config_encoding = + let open Data_encoding in + conv + (fun {max_size} -> max_size) + (fun max_size -> {max_size}) + (obj1 (req "max_size" int31)) + + let default_config = {max_size = 64} + + type workload = Merge_types_workload of {nodes : int; consumed : Size.t} + + let workload_encoding = + let open Data_encoding in + conv + (function Merge_types_workload {nodes; consumed} -> (nodes, consumed)) + (fun (nodes, consumed) -> Merge_types_workload {nodes; consumed}) + (obj2 (req "nodes" int31) (req "consumed" int31)) + + let workload_to_vector = function + | Merge_types_workload {nodes; consumed} -> + Sparse_vec.String.of_list + [("nodes", float_of_int nodes); ("consumed", float_of_int consumed)] + + let name = "MERGE_TYPES" + + let info = "Benchmarking merging of types" + + let tags = [Tags.translator] + + let intercept_var = Free_variable.of_string (Format.asprintf "%s_const" name) + + let coeff_var = Free_variable.of_string (Format.asprintf "%s_coeff" name) + + let size_model = + Model.make + ~conv:(function Merge_types_workload {nodes; _} -> (nodes, ())) + ~model: + (Model.affine_split_const + ~intercept1:Builtin_benchmarks.timer_variable + ~intercept2:intercept_var + ~coeff:coeff_var) + + let codegen_model = + Model.make + ~conv:(function Merge_types_workload {nodes; _} -> (nodes, ())) + ~model:(Model.affine ~intercept:intercept_var ~coeff:coeff_var) + + let () = + Registration_helpers.register_for_codegen + name + (Model.For_codegen codegen_model) + + let models = + [("size_translator_model", size_model); ("codegen", codegen_model)] + + let merge_type_benchmark rng_state nodes (ty : Script_ir_translator.ex_ty) = + let open Error_monad in + Lwt_main.run + ( Execution_context.make ~rng_state >>=? fun (ctxt, _) -> + let ctxt = Gas_helpers.set_limit ctxt in + match ty with + | Ex_ty ty -> + let dummy_loc = 0 in + Lwt.return (Script_ir_translator.ty_eq ctxt dummy_loc ty ty) + >|= Environment.wrap_tzresult + >>=? fun (_, ctxt') -> + let consumed = + Alpha_context.Gas.consumed ~since:ctxt ~until:ctxt' + in + let workload = + Merge_types_workload + {nodes; consumed = Z.to_int (Gas_helpers.fp_to_z consumed)} + in + let closure () = ignore (Script_ir_translator.ty_eq ctxt 0 ty ty) in + return (Generator.Plain {workload; closure}) ) + |> function + | Ok closure -> closure + | Error errs -> global_error name errs + + let make_bench rng_state (cfg : config) () = + let nodes = + Base_samplers.( + sample_in_interval ~range:{min = 1; max = cfg.max_size} rng_state) + in + let ty = + Michelson_generation.Samplers.Random_type.m_type ~size:nodes rng_state + in + merge_type_benchmark rng_state nodes ty + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Merge_types) + +(* A dummy type generator, sampling linear terms of a given size. *) +let rec dummy_type_generator depth = + let open Script_ir_translator in + if depth = 0 then Ex_ty (unit_t ~annot:None) + else + match dummy_type_generator (depth - 1) with + | Ex_ty something -> Ex_ty (Michelson_types.list something) + +(* Generate combs; the size of a comb of depth d should be + d * 2 + 1. *) +let rec dummy_comparable_type_generator depth = + let open Script_ir_translator in + let open Script_typed_ir in + if depth = 0 then Ex_comparable_ty (unit_key ~annot:None) + else + match dummy_comparable_type_generator (depth - 1) with + | Ex_comparable_ty r -> + let l = unit_key ~annot:None in + Ex_comparable_ty + (match pair_key (-1) (l, None) (r, None) ~annot:None with + | Error _ -> assert false + | Ok t -> t) + +module Parse_type_shared = struct + type config = {max_size : int} + + let default_config = {max_size = Constants_repr.michelson_maximum_type_size} + + let config_encoding = + let open Data_encoding in + conv + (fun {max_size} -> max_size) + (fun max_size -> {max_size}) + (obj1 (req "max_size" int31)) + + type workload = Type_workload of {nodes : int; consumed : Size.t} + + let workload_encoding = + let open Data_encoding in + conv + (function Type_workload {nodes; consumed} -> (nodes, consumed)) + (fun (nodes, consumed) -> Type_workload {nodes; consumed}) + (obj2 (req "nodes" int31) (req "consumed" int31)) + + let workload_to_vector = function + | Type_workload {nodes; consumed} -> + Sparse_vec.String.of_list + [("nodes", float_of_int nodes); ("consumed", float_of_int consumed)] + + let tags = [Tags.translator] +end + +let parse_ty ctxt node = + Script_ir_translator.parse_ty + ctxt + ~legacy:true + ~allow_lazy_storage:true + ~allow_operation:true + ~allow_contract:true + ~allow_ticket:true + node + +let unparse_ty ctxt ty = Script_ir_translator.unparse_ty ctxt ty + +module Parse_type_benchmark : Benchmark.S = struct + include Parse_type_shared + + let name = "PARSE_TYPE" + + let info = "Benchmarking parse_ty" + + let make_bench rng_state config () = + let open Error_monad in + ( Lwt_main.run (Execution_context.make ~rng_state) >>? fun (ctxt, _) -> + let ctxt = Gas_helpers.set_limit ctxt in + let depth = Random.State.int rng_state config.max_size in + let ty = dummy_type_generator depth in + match ty with + | Ex_ty ty -> + Environment.wrap_tzresult @@ unparse_ty ctxt ty + >>? fun (unparsed, _) -> + Environment.wrap_tzresult @@ parse_ty ctxt unparsed + >>? fun (_, ctxt') -> + let consumed = + Z.to_int + (Gas_helpers.fp_to_z + (Alpha_context.Gas.consumed ~since:ctxt ~until:ctxt')) + in + let workload = Type_workload {nodes = depth; consumed} in + let closure () = ignore (parse_ty ctxt unparsed) in + ok (Generator.Plain {workload; closure}) ) + |> function + | Ok closure -> closure + | Error errs -> global_error name errs + + let size_model = + Model.make + ~conv:(function Type_workload {nodes; consumed = _} -> (nodes, ())) + ~model: + (Model.affine + ~intercept: + (Free_variable.of_string (Format.asprintf "%s_const" name)) + ~coeff:(Free_variable.of_string (Format.asprintf "%s_coeff" name))) + + let models = [("size_translator_model", size_model)] + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Parse_type_benchmark) + +module Unparse_type_benchmark : Benchmark.S = struct + include Parse_type_shared + + let name = "UNPARSE_TYPE" + + let info = "Benchmarking unparse_ty" + + let make_bench rng_state config () = + let open Error_monad in + ( Lwt_main.run (Execution_context.make ~rng_state) >>? fun (ctxt, _) -> + let ctxt = Gas_helpers.set_limit ctxt in + let depth = Random.State.int rng_state config.max_size in + let ty = dummy_type_generator depth in + match ty with + | Ex_ty ty -> + Environment.wrap_tzresult @@ unparse_ty ctxt ty >>? fun (_, ctxt') -> + let consumed = + Z.to_int + (Gas_helpers.fp_to_z + (Alpha_context.Gas.consumed ~since:ctxt ~until:ctxt')) + in + let workload = Type_workload {nodes = depth; consumed} in + let closure () = ignore (unparse_ty ctxt ty) in + ok (Generator.Plain {workload; closure}) ) + |> function + | Ok closure -> closure + | Error errs -> global_error name errs + + let size_model = + Model.make + ~conv:(function Type_workload {nodes; consumed = _} -> (nodes, ())) + ~model: + (Model.affine + ~intercept: + (Free_variable.of_string (Format.asprintf "%s_const" name)) + ~coeff:(Free_variable.of_string (Format.asprintf "%s_coeff" name))) + + let models = [("size_translator_model", size_model)] + + let create_benchmarks ~rng_state ~bench_num config = + List.repeat bench_num (make_bench rng_state config) +end + +let () = Registration_helpers.register (module Unparse_type_benchmark) diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/translator_model.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/translator_model.ml new file mode 100644 index 000000000000..0bcf6c3b8a20 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/translator_model.ml @@ -0,0 +1,68 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let gas_full t_kind code_or_data = + let name = + Format.asprintf + "%a_%a" + Translator_workload.pp_kind + t_kind + Translator_workload.pp_code_or_data + code_or_data + in + let intercept = Free_variable.of_string (Format.asprintf "%s_const" name) in + let coeff = Free_variable.of_string (Format.asprintf "%s_coeff" name) in + Model.affine ~intercept ~coeff + +let size_full t_kind code_or_data = + let name = + Format.asprintf + "%a_%a" + Translator_workload.pp_kind + t_kind + Translator_workload.pp_code_or_data + code_or_data + in + let coeff1 = Free_variable.of_string (Format.asprintf "%s_traversal" name) in + let coeff2 = Free_variable.of_string (Format.asprintf "%s_int_bytes" name) in + let coeff3 = + Free_variable.of_string (Format.asprintf "%s_string_bytes" name) + in + Model.trilinear ~coeff1 ~coeff2 ~coeff3 + +let gas_based_model t_kind code_or_data = + Model.make + ~conv:(function + | Translator_workload.Typechecker_workload {consumed; _} -> (consumed, ())) + ~model:(gas_full t_kind code_or_data) + +let size_based_model t_kind code_or_data = + Model.make + ~conv:(function + | Translator_workload.Typechecker_workload {micheline_size; _} -> ( + match micheline_size with + | {traversal; int_bytes; string_bytes} -> + (traversal, (int_bytes, (string_bytes, ()))))) + ~model:(size_full t_kind code_or_data) diff --git a/src/proto_011_PtHangzH/lib_benchmarks_proto/translator_workload.ml b/src/proto_011_PtHangzH/lib_benchmarks_proto/translator_workload.ml new file mode 100644 index 000000000000..1ba338327374 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_benchmarks_proto/translator_workload.ml @@ -0,0 +1,186 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type kind = Parsing | Unparsing + +type code_or_data = Code | Data + +type t = + | Typechecker_workload of { + t_kind : kind; + code_or_data : code_or_data; + micheline_size : Size.micheline_size; + consumed : Size.t; + } + +let kind_encoding : kind Data_encoding.t = + let open Data_encoding in + def "kind_encoding" + @@ string_enum [("parsing", Parsing); ("unparsing", Unparsing)] + +let code_or_data_encoding : code_or_data Data_encoding.t = + let open Data_encoding in + def "code_or_data_encoding" @@ string_enum [("code", Code); ("data", Data)] + +let encoding : t Data_encoding.t = + let open Data_encoding in + def "translator_trace_encoding" + @@ conv + (function + | Typechecker_workload {t_kind; code_or_data; micheline_size; consumed} + -> + (t_kind, code_or_data, micheline_size, consumed)) + (fun (t_kind, code_or_data, micheline_size, consumed) -> + Typechecker_workload {t_kind; code_or_data; micheline_size; consumed}) + (tup4 + kind_encoding + code_or_data_encoding + Size.micheline_size_encoding + Size.encoding) + +let pp_kind fmtr (kind : kind) = + match kind with + | Parsing -> Format.pp_print_string fmtr "Parsing" + | Unparsing -> Format.pp_print_string fmtr "Unparsing" + +let pp_code_or_data fmtr (x : code_or_data) = + match x with + | Code -> Format.pp_print_string fmtr "Code" + | Data -> Format.pp_print_string fmtr "Data" + +let pp fmtr (trace : t) = + match trace with + | Typechecker_workload {t_kind; code_or_data; micheline_size; consumed} -> + Format.fprintf + fmtr + "typechecker_trace { %a; %a; %a; %a }" + pp_kind + t_kind + pp_code_or_data + code_or_data + Size.pp_micheline_size + micheline_size + Size.pp + consumed + +let workload_to_sparse_vec (trace : t) = + let (name, {Size.traversal; int_bytes; string_bytes}, consumed) = + match trace with + | Typechecker_workload {t_kind; code_or_data; micheline_size; consumed} -> + let name = + Format.asprintf "%a_%a" pp_kind t_kind pp_code_or_data code_or_data + in + (name, micheline_size, consumed) + in + let n s = name ^ "_" ^ s in + let vars = + [ + (n "traversal", Size.to_float traversal); + (n "int_bytes", Size.to_float int_bytes); + (n "string_bytes", Size.to_float string_bytes); + (n "gas", Size.to_float consumed); + ] + in + Sparse_vec.String.of_list vars + +let data_typechecker_workload ctxt t_kind micheline_node ex_ty = + let open Protocol in + match ex_ty with + | Script_ir_translator.Ex_ty ty -> + let ctxt = Gas_helpers.set_limit ctxt in + Lwt_main.run + ( Script_ir_translator.parse_data + ctxt + ~legacy:false + ~allow_forged:false + ty + micheline_node + |> Lwt.map Environment.wrap_tzresult + >>= fun res -> + match res with + | Ok (_res, ctxt_after) -> + let micheline_size = Size.of_micheline micheline_node in + let consumed = + Alpha_context.Gas.consumed ~since:ctxt ~until:ctxt_after + in + let trace = + Typechecker_workload + { + t_kind; + code_or_data = Data; + micheline_size; + consumed = + Size.of_int (Z.to_int (Gas_helpers.fp_to_z consumed)); + } + in + Lwt.return (Some trace) + | Error errors -> + Michelson_v1_error_reporter.report_errors + ~details:true + ~show_source:true + Format.err_formatter + errors ; + Format.eprintf "@." ; + Lwt.return None ) + +let code_typechecker_workload (ctxt : Protocol.Alpha_context.context) + (t_kind : kind) (code : Protocol.Alpha_context.Script.node) + (bef : Protocol.Script_ir_translator.ex_stack_ty) = + let open Protocol in + let ctxt = Gas_helpers.set_limit ctxt in + let (Script_ir_translator.Ex_stack_ty stack_ty) = bef in + Lwt_main.run + ( Script_ir_translator.parse_instr + Script_ir_translator.Lambda + ctxt + ~legacy:false + code + stack_ty + |> Lwt.map Environment.wrap_tzresult + >>= fun res -> + match res with + | Ok (_res, ctxt_after) -> + let micheline_size = Size.of_micheline code in + let consumed = + Alpha_context.Gas.consumed ~since:ctxt ~until:ctxt_after + in + let trace = + Typechecker_workload + { + t_kind; + code_or_data = Code; + micheline_size; + consumed = Size.of_int (Z.to_int (Gas_helpers.fp_to_z consumed)); + } + in + Lwt.return (Some trace) + | Error errs -> + Michelson_v1_error_reporter.report_errors + ~details:true + ~show_source:true + Format.err_formatter + errs ; + Format.eprintf "@." ; + Lwt.return None ) diff --git a/src/proto_011_PtHangzH/lib_client/.ocamlformat b/src/proto_011_PtHangzH/lib_client/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_client/annotated_manager_operation.ml b/src/proto_011_PtHangzH/lib_client/annotated_manager_operation.ml new file mode 100644 index 000000000000..5290d7bb7050 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/annotated_manager_operation.ml @@ -0,0 +1,123 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2018-2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +type _ t = + | Manager_info : { + source : Alpha_context.public_key_hash option; + fee : Tez.t Limit.t; + gas_limit : Gas.Arith.integral Limit.t; + storage_limit : Z.t Limit.t; + counter : Z.t option; + operation : 'kind manager_operation; + } + -> 'kind t + +type packed = Annotated_manager_operation : 'kind t -> packed + +type _ annotated_list = + | Single_manager : 'kind t -> 'kind annotated_list + | Cons_manager : + 'kind t * 'rest annotated_list + -> ('kind * 'rest) annotated_list + +type packed_annotated_list = + | Manager_list : 'kind annotated_list -> packed_annotated_list + +let rec manager_to_list = function + | Manager_list (Single_manager o) -> [Annotated_manager_operation o] + | Manager_list (Cons_manager (o, os)) -> + Annotated_manager_operation o :: manager_to_list (Manager_list os) + +let rec manager_of_list = function + | [] -> assert false + | [Annotated_manager_operation o] -> Manager_list (Single_manager o) + | Annotated_manager_operation o :: os -> + let (Manager_list os) = manager_of_list os in + Manager_list (Cons_manager (o, os)) + +let join_fee fee operation = + let (Manager_info c) = operation in + Limit.join ~where:__LOC__ Tez.equal fee c.fee >|? fun fee -> + Manager_info {c with fee} + +let set_fee fee (Manager_info c) = Manager_info {c with fee} + +let join_gas_limit gas_limit operation = + let (Manager_info c) = operation in + Limit.join ~where:__LOC__ Gas.Arith.equal gas_limit c.gas_limit + >|? fun gas_limit -> Manager_info {c with gas_limit} + +let set_gas_limit gas_limit (Manager_info c) = Manager_info {c with gas_limit} + +let join_storage_limit storage_limit (Manager_info c) = + Limit.join ~where:__LOC__ Z.equal storage_limit c.storage_limit + >|? fun storage_limit -> Manager_info {c with storage_limit} + +let set_storage_limit storage_limit (Manager_info c) = + Manager_info {c with storage_limit} + +let set_counter counter (Manager_info c) = + match c.counter with + | Some _ -> generic_error "set_counter_annot: already set" + | None -> ok (Manager_info {c with counter = Some counter}) + +let set_source source (Manager_info c) = + match c.source with + | Some _ -> generic_error "set_source_annot: already set" + | None -> ok (Manager_info {c with source = Some source}) + +let manager_from_annotated operation = + let (Manager_info {source; fee; gas_limit; storage_limit; counter; operation}) + = + operation + in + Limit.get ~when_unknown:"unknown fee" fee >>? fun fee -> + Limit.get ~when_unknown:"unknown gas limit" gas_limit >>? fun gas_limit -> + Limit.get ~when_unknown:"unknown storage limit" storage_limit + >>? fun storage_limit -> + Option.fold + ~some:ok + ~none:(generic_error "manager_from_annotated: source not set") + source + >>? fun source -> + Option.fold + ~some:ok + ~none:(generic_error "manager_from_annotated: counter not set") + counter + >|? fun counter -> + Manager_operation {source; fee; counter; gas_limit; storage_limit; operation} + +let rec manager_list_from_annotated : + type kind. kind annotated_list -> kind Kind.manager contents_list tzresult = + function + | Single_manager operation -> + manager_from_annotated operation >|? fun op -> Single op + | Cons_manager (operation, rest) -> + manager_list_from_annotated rest >>? fun rest -> + manager_from_annotated operation >|? fun op -> Cons (op, rest) diff --git a/src/proto_011_PtHangzH/lib_client/annotated_manager_operation.mli b/src/proto_011_PtHangzH/lib_client/annotated_manager_operation.mli new file mode 100644 index 000000000000..4eebe07b7a59 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/annotated_manager_operation.mli @@ -0,0 +1,98 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2018 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Annotated manager operations are wrappers used to accumulate information + (especially about limits) on the operation prior to the injection. *) + +open Protocol +open Alpha_context + +type _ t = + | Manager_info : { + source : Alpha_context.public_key_hash option; + fee : Tez.t Limit.t; + gas_limit : Gas.Arith.integral Limit.t; + storage_limit : Z.t Limit.t; + counter : Z.t option; + operation : 'kind manager_operation; + } + -> 'kind t + +type packed = Annotated_manager_operation : 'kind t -> packed + +(** The [annotated_list] type helps making + [contents_list] from a list of [manager_operation]s. + Its construction mimics [contents_list] in order to keep + consistent types when calling [inject_manager_operation] + and [inject_operation].*) +type _ annotated_list = + | Single_manager : 'kind t -> 'kind annotated_list + | Cons_manager : + 'kind t * 'rest annotated_list + -> ('kind * 'rest) annotated_list + +type packed_annotated_list = + | Manager_list : 'kind annotated_list -> packed_annotated_list + +(** Convert a list of annotated operations to a list of packed annotated + operations *) +val manager_to_list : packed_annotated_list -> packed list + +(** Converse of [manager_to_list] *) +val manager_of_list : packed list -> packed_annotated_list + +(** [join_fee fee op] updates [op.fee] to [Limit.join op.fee fee] and + fails if the join fails *) +val join_fee : Tez.t Limit.t -> 'a t -> 'a t tzresult + +(** [set_fee fee op] updates [op.fee] to [fee] *) +val set_fee : Tez.t Limit.t -> 'a t -> 'a t + +(** See [join_fee] *) +val join_gas_limit : Gas.Arith.integral Limit.t -> 'a t -> 'a t tzresult + +(** See [set_fee] *) +val set_gas_limit : Gas.Arith.integral Limit.t -> 'a t -> 'a t + +(** See [join_fee] *) +val join_storage_limit : Z.t Limit.t -> 'a t -> 'a t tzresult + +(** See [set_fee] *) +val set_storage_limit : Z.t Limit.t -> 'a t -> 'a t + +(** Set the counter of the annotated operation. Fail if the counter + is already set. *) +val set_counter : counter -> 'a t -> 'a t tzresult + +(** Set the source of the operation. Fail if the source is already set. *) +val set_source : public_key_hash -> 'a t -> 'a t tzresult + +(** Convert an annotated manager operation to a proper manager operation. + Fail if some fields in the annotated operation are not set. *) +val manager_from_annotated : 'a t -> 'a Kind.manager contents tzresult + +val manager_list_from_annotated : + 'kind annotated_list -> 'kind Kind.manager contents_list tzresult diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_args.ml b/src/proto_011_PtHangzH/lib_client/client_proto_args.ml new file mode 100644 index 000000000000..793b95cfd1b8 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_args.ml @@ -0,0 +1,533 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol_client_context +open Protocol +open Alpha_context +open Clic + +type error += Bad_tez_arg of string * string (* Arg_name * value *) + +type error += Bad_max_priority of string + +type error += Bad_minimal_fees of string + +type error += Bad_max_waiting_time of string + +type error += Bad_endorsement_delay of string + +type error += Bad_preserved_levels of string + +let () = + register_error_kind + `Permanent + ~id:"badTezArg" + ~title:"Bad Tez Arg" + ~description:"Invalid \xEA\x9C\xA9 notation in parameter." + ~pp:(fun ppf (arg_name, literal) -> + Format.fprintf + ppf + "Invalid \xEA\x9C\xA9 notation in parameter %s: '%s'" + arg_name + literal) + Data_encoding.(obj2 (req "parameter" string) (req "literal" string)) + (function + | Bad_tez_arg (parameter, literal) -> Some (parameter, literal) + | _ -> None) + (fun (parameter, literal) -> Bad_tez_arg (parameter, literal)) ; + register_error_kind + `Permanent + ~id:"badMaxPriorityArg" + ~title:"Bad -max-priority arg" + ~description:"invalid priority in -max-priority" + ~pp:(fun ppf literal -> + Format.fprintf ppf "invalid priority '%s' in -max-priority" literal) + Data_encoding.(obj1 (req "parameter" string)) + (function Bad_max_priority parameter -> Some parameter | _ -> None) + (fun parameter -> Bad_max_priority parameter) ; + register_error_kind + `Permanent + ~id:"badMinimalFeesArg" + ~title:"Bad -minimal-fees arg" + ~description:"invalid fee threshold in -fee-threshold" + ~pp:(fun ppf literal -> + Format.fprintf ppf "invalid minimal fees '%s'" literal) + Data_encoding.(obj1 (req "parameter" string)) + (function Bad_minimal_fees parameter -> Some parameter | _ -> None) + (fun parameter -> Bad_minimal_fees parameter) ; + register_error_kind + `Permanent + ~id:"badMaxWaitingTimeArg" + ~title:"Bad -max-waiting-time arg" + ~description:"invalid duration in -max-waiting-time" + ~pp:(fun ppf literal -> + Format.fprintf + ppf + "Bad argument value for -max-waiting-time. Expected an integer, but \ + given '%s'" + literal) + Data_encoding.(obj1 (req "parameter" string)) + (function Bad_max_waiting_time parameter -> Some parameter | _ -> None) + (fun parameter -> Bad_max_waiting_time parameter) ; + register_error_kind + `Permanent + ~id:"badEndorsementDelayArg" + ~title:"Bad -endorsement-delay arg" + ~description:"invalid duration in -endorsement-delay" + ~pp:(fun ppf literal -> + Format.fprintf + ppf + "Bad argument value for -endorsement-delay. Expected an integer, but \ + given '%s'" + literal) + Data_encoding.(obj1 (req "parameter" string)) + (function Bad_endorsement_delay parameter -> Some parameter | _ -> None) + (fun parameter -> Bad_endorsement_delay parameter) ; + register_error_kind + `Permanent + ~id:"badPreservedLevelsArg" + ~title:"Bad -preserved-levels arg" + ~description:"invalid number of levels in -preserved-levels" + ~pp:(fun ppf literal -> + Format.fprintf + ppf + "Bad argument value for -preserved_levels. Expected a positive \ + integer, but given '%s'" + literal) + Data_encoding.(obj1 (req "parameter" string)) + (function Bad_preserved_levels parameter -> Some parameter | _ -> None) + (fun parameter -> Bad_preserved_levels parameter) + +let tez_sym = "\xEA\x9C\xA9" + +let string_parameter = parameter (fun _ x -> return x) + +let int_parameter = + parameter (fun _ p -> + try return (int_of_string p) with _ -> failwith "Cannot read int") + +let bytes_of_prefixed_string s = + try + if String.length s < 2 || s.[0] <> '0' || s.[1] <> 'x' then raise Exit + else return (Hex.to_bytes (`Hex (String.sub s 2 (String.length s - 2)))) + with _ -> + failwith "Invalid bytes, expecting hexadecimal notation (e.g. 0x1234abcd)" + +let bytes_parameter = parameter (fun _ s -> bytes_of_prefixed_string s) + +let data_parameter = + parameter (fun _ data -> + Lwt.return @@ Tezos_micheline.Micheline_parser.no_parsing_error + @@ Michelson_v1_parser.parse_expression data) + +let init_arg = + default_arg + ~long:"init" + ~placeholder:"data" + ~doc:"initial value of the contract's storage" + ~default:"Unit" + string_parameter + +let global_constant_param ~name ~desc next = + Clic.param ~name ~desc string_parameter next + +let arg_arg = + arg + ~long:"arg" + ~placeholder:"data" + ~doc:"argument passed to the contract's script, if needed" + string_parameter + +let default_arg_arg = + arg + ~long:"default-arg" + ~placeholder:"data" + ~doc:"default argument passed to each contract's script, if needed" + string_parameter + +let delegate_arg = + Client_keys.Public_key_hash.source_arg + ~long:"delegate" + ~placeholder:"address" + ~doc:"delegate of the contract\nMust be a known address." + () + +let source_arg = + arg + ~long:"source" + ~placeholder:"address" + ~doc:"source of the deposits to be paid\nMust be a known address." + string_parameter + +let entrypoint_arg = + arg + ~long:"entrypoint" + ~placeholder:"name" + ~doc:"entrypoint of the smart contract" + string_parameter + +let default_entrypoint_arg = + arg + ~long:"default-entrypoint" + ~placeholder:"name" + ~doc:"default entrypoint of the smart contracts" + string_parameter + +let force_switch = + switch + ~long:"force" + ~short:'f' + ~doc: + "disables the node's injection checks\n\ + Force the injection of branch-invalid operation or force the injection \ + of block without a fitness greater than the current head." + () + +let minimal_timestamp_switch = + switch + ~long:"minimal-timestamp" + ~doc: + "Use the minimal timestamp instead of the current date as timestamp of \ + the baked block." + () + +let tez_format = + "Text format: `DDDDDDD.DDDDDD`.\n\ + Tez and mutez and separated by a period sign. Trailing and pending zeroes \ + are allowed." + +let tez_parameter param = + parameter (fun _ s -> + match Tez.of_string s with + | Some tez -> return tez + | None -> fail (Bad_tez_arg (param, s))) + +let tez_arg ~default ~parameter ~doc = + default_arg + ~long:parameter + ~placeholder:"amount" + ~doc + ~default + (tez_parameter ("--" ^ parameter)) + +let tez_param ~name ~desc next = + Clic.param + ~name + ~desc:(desc ^ " in \xEA\x9C\xA9\n" ^ tez_format) + (tez_parameter name) + next + +let fee_arg = + arg + ~long:"fee" + ~placeholder:"amount" + ~doc:"fee in \xEA\x9C\xA9 to pay to the baker" + (tez_parameter "--fee") + +let default_fee_arg = + arg + ~long:"default-fee" + ~placeholder:"amount" + ~doc:"default fee in \xEA\x9C\xA9 to pay to the baker for each transaction" + (tez_parameter "--default-fee") + +let gas_limit_kind = + parameter (fun _ s -> + try + let v = Z.of_string s in + return (Gas.Arith.integral_exn v) + with _ -> failwith "invalid gas limit (must be a positive number)") + +let gas_limit_arg = + arg + ~long:"gas-limit" + ~short:'G' + ~placeholder:"amount" + ~doc: + "Set the gas limit of the transaction instead of letting the client \ + decide based on a simulation" + gas_limit_kind + +let default_gas_limit_arg = + arg + ~long:"default-gas-limit" + ~short:'G' + ~placeholder:"amount" + ~doc: + "Set the default gas limit for each transaction instead of letting the \ + client decide based on a simulation" + gas_limit_kind + +let run_gas_limit_arg = + arg + ~long:"gas" + ~short:'G' + ~doc:"Initial quantity of gas for typechecking and execution" + ~placeholder:"gas" + gas_limit_kind + +let storage_limit_kind = + parameter (fun _ s -> + try + let v = Z.of_string s in + assert (Compare.Z.(v >= Z.zero)) ; + return v + with _ -> + failwith "invalid storage limit (must be a positive number of bytes)") + +let storage_limit_arg = + arg + ~long:"storage-limit" + ~short:'S' + ~placeholder:"amount" + ~doc: + "Set the storage limit of the transaction instead of letting the client \ + decide based on a simulation" + storage_limit_kind + +let default_storage_limit_arg = + arg + ~long:"default-storage-limit" + ~short:'S' + ~placeholder:"amount" + ~doc: + "Set the default storage limit for each transaction instead of letting \ + the client decide based on a simulation" + storage_limit_kind + +let counter_arg = + arg + ~long:"counter" + ~short:'C' + ~placeholder:"counter" + ~doc:"Set the counter to be used by the transaction" + (parameter (fun _ s -> + try + let v = Z.of_string s in + assert (Compare.Z.(v >= Z.zero)) ; + return v + with _ -> + failwith "invalid counter (must be a positive number of bytes)")) + +let max_priority_arg = + arg + ~long:"max-priority" + ~placeholder:"slot" + ~doc:"maximum allowed baking slot" + (parameter (fun _ s -> + try return (int_of_string s) with _ -> fail (Bad_max_priority s))) + +let default_minimal_fees = + match Tez.of_mutez 100L with None -> assert false | Some t -> t + +let default_minimal_nanotez_per_gas_unit = Q.of_int 100 + +let default_minimal_nanotez_per_byte = Q.of_int 1000 + +let minimal_fees_arg = + default_arg + ~long:"minimal-fees" + ~placeholder:"amount" + ~doc:"exclude operations with fees lower than this threshold (in tez)" + ~default:(Tez.to_string default_minimal_fees) + (parameter (fun _ s -> + match Tez.of_string s with + | Some t -> return t + | None -> fail (Bad_minimal_fees s))) + +let minimal_nanotez_per_gas_unit_arg = + default_arg + ~long:"minimal-nanotez-per-gas-unit" + ~placeholder:"amount" + ~doc: + "exclude operations with fees per gas lower than this threshold (in \ + nanotez)" + ~default:(Q.to_string default_minimal_nanotez_per_gas_unit) + (parameter (fun _ s -> + try return (Q.of_string s) with _ -> fail (Bad_minimal_fees s))) + +let minimal_nanotez_per_byte_arg = + default_arg + ~long:"minimal-nanotez-per-byte" + ~placeholder:"amount" + ~default:(Q.to_string default_minimal_nanotez_per_byte) + ~doc: + "exclude operations with fees per byte lower than this threshold (in \ + nanotez)" + (parameter (fun _ s -> + try return (Q.of_string s) with _ -> fail (Bad_minimal_fees s))) + +let force_low_fee_arg = + switch + ~long:"force-low-fee" + ~doc:"Don't check that the fee is lower than the estimated default value" + () + +let fee_cap_arg = + default_arg + ~long:"fee-cap" + ~placeholder:"amount" + ~default:"1.0" + ~doc:"Set the fee cap" + (parameter (fun _ s -> + match Tez.of_string s with + | Some t -> return t + | None -> failwith "Bad fee cap")) + +let burn_cap_arg = + default_arg + ~long:"burn-cap" + ~placeholder:"amount" + ~default:"0" + ~doc:"Set the burn cap" + (parameter (fun _ s -> + match Tez.of_string s with + | Some t -> return t + | None -> failwith "Bad burn cap")) + +let no_waiting_for_endorsements_arg = + switch + ~long:"no-waiting-for-late-endorsements" + ~doc:"Disable waiting for late endorsements" + () + +let await_endorsements_arg = + switch + ~long:"await-late-endorsements" + ~doc:"Await late endorsements when baking a block" + () + +let endorsement_delay_arg = + default_arg + ~long:"endorsement-delay" + ~placeholder:"seconds" + ~doc: + "delay before endorsing blocks\n\ + Delay between notifications of new blocks from the node and production \ + of endorsements for these blocks." + ~default:"0" + (parameter (fun _ s -> + try + let i = int_of_string s in + fail_when (i < 0) (Bad_endorsement_delay s) >>=? fun () -> + return (int_of_string s) + with _ -> fail (Bad_endorsement_delay s))) + +let preserved_levels_arg = + default_arg + ~long:"preserved-levels" + ~placeholder:"threshold" + ~doc:"Number of effective levels kept in the accuser's memory" + ~default:"4096" + (parameter (fun _ s -> + try + let preserved_cycles = int_of_string s in + if preserved_cycles < 0 then fail (Bad_preserved_levels s) + else return preserved_cycles + with _ -> fail (Bad_preserved_levels s))) + +let no_print_source_flag = + switch + ~long:"no-print-source" + ~short:'q' + ~doc: + "don't print the source code\n\ + If an error is encountered, the client will print the contract's source \ + code by default.\n\ + This option disables this behaviour." + () + +let no_confirmation = + switch + ~long:"no-confirmation" + ~doc:"don't print wait for the operation to be confirmed." + () + +let signature_parameter = + parameter (fun _cctxt s -> + match Signature.of_b58check_opt s with + | Some s -> return s + | None -> failwith "Not given a valid signature") + +let unparsing_mode_parameter = + parameter + ~autocomplete:(fun _cctxt -> + return ["Readable"; "Optimized"; "Optimized_legacy"]) + (fun _cctxt s -> + match s with + | "Readable" -> return Script_ir_translator.Readable + | "Optimized" -> return Script_ir_translator.Optimized + | "Optimized_legacy" -> return Script_ir_translator.Optimized_legacy + | _ -> failwith "Unknown unparsing mode %s" s) + +let unparsing_mode_arg ~default = + default_arg + ~long:"unparsing-mode" + ~placeholder:"mode" + ~doc: + "Unparsing mode to use\n\ + One of \"Readable\", \"Optimized\", or \"Optimized_legacy\".\n\ + This option affects the way the values of the following Michelson types \ + are represented:\n\ + - timestamp: the Readable representation is a RFC3339 string, the \ + Optimized and Optimized_legacy representations are the number of \ + seconds since Epoch\n\ + - key, signature, key_hash, address, contract, chain_id: the Readable \ + representation is a Base58Check string, the Optimized and \ + Optimized_legacy representations are byte sequences\n\ + - nested pairs: in Readable mode, the Pair constructor is used even \ + with arity bigger than 2 such as in Pair 0 1 2; in Optimized_legacy \ + mode, the Pair constructor is always use with arity 2 such as in Pair 0 \ + (Pair 1 2); in Optimized mode, a sequence is used if there are at least \ + 4 elements and the behavior is the same as in Optimized_legacy mode \ + otherwise.\n" + ~default + unparsing_mode_parameter + +let enforce_indentation_flag = + switch + ~long:"enforce-indentation" + ~doc: + "Check that the Micheline expression passed to this command is \ + well-indented." + () + +let display_names_flag = + switch + ~long:"display-names" + ~doc:"Print names of scripts passed to this command" + () + +module Daemon = struct + let baking_switch = + switch ~long:"baking" ~short:'B' ~doc:"run the baking daemon" () + + let endorsement_switch = + switch ~long:"endorsement" ~short:'E' ~doc:"run the endorsement daemon" () + + let denunciation_switch = + switch ~long:"denunciation" ~short:'D' ~doc:"run the denunciation daemon" () +end diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_args.mli b/src/proto_011_PtHangzH/lib_client/client_proto_args.mli new file mode 100644 index 000000000000..5ea6ce7f59f3 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_args.mli @@ -0,0 +1,133 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Protocol_client_context + +val tez_sym : string + +val init_arg : (string, full) Clic.arg + +val fee_arg : (Tez.t option, full) Clic.arg + +val default_fee_arg : (Tez.t option, full) Clic.arg + +val counter_arg : (Z.t option, full) Clic.arg + +val gas_limit_arg : (Gas.Arith.integral option, full) Clic.arg + +val default_gas_limit_arg : (Gas.Arith.integral option, full) Clic.arg + +val run_gas_limit_arg : (Gas.Arith.integral option, full) Clic.arg + +val storage_limit_arg : (Z.t option, full) Clic.arg + +val default_storage_limit_arg : (Z.t option, full) Clic.arg + +val arg_arg : (string option, full) Clic.arg + +val default_arg_arg : (string option, full) Clic.arg + +val source_arg : (string option, full) Clic.arg + +val entrypoint_arg : (string option, full) Clic.arg + +val default_entrypoint_arg : (string option, full) Clic.arg + +val delegate_arg : (Signature.Public_key_hash.t option, full) Clic.arg + +val max_priority_arg : (int option, full) Clic.arg + +val minimal_fees_arg : (Tez.tez, full) Clic.arg + +val minimal_nanotez_per_gas_unit_arg : (Q.t, full) Clic.arg + +val minimal_nanotez_per_byte_arg : (Q.t, full) Clic.arg + +val force_low_fee_arg : (bool, full) Clic.arg + +val fee_cap_arg : (Tez.t, full) Clic.arg + +val burn_cap_arg : (Tez.t, full) Clic.arg + +val no_waiting_for_endorsements_arg : (bool, full) Clic.arg + +val await_endorsements_arg : (bool, full) Clic.arg + +val force_switch : (bool, full) Clic.arg + +val minimal_timestamp_switch : (bool, full) Clic.arg + +val endorsement_delay_arg : (int, full) Clic.arg + +val preserved_levels_arg : (int, full) Clic.arg + +val no_print_source_flag : (bool, full) Clic.arg + +val no_confirmation : (bool, full) Clic.arg + +val tez_arg : + default:string -> parameter:string -> doc:string -> (Tez.t, full) Clic.arg + +val tez_param : + name:string -> + desc:string -> + ('a, full) Clic.params -> + (Tez.t -> 'a, full) Clic.params + +val global_constant_param : + name:string -> + desc:string -> + ('a, full) Clic.params -> + (string -> 'a, full) Clic.params + +val signature_parameter : (Signature.t, full) Clic.parameter + +module Daemon : sig + val baking_switch : (bool, full) Clic.arg + + val endorsement_switch : (bool, full) Clic.arg + + val denunciation_switch : (bool, full) Clic.arg +end + +val int_parameter : (int, full) Clic.parameter + +val string_parameter : (string, full) Clic.parameter + +val bytes_of_prefixed_string : string -> Bytes.t tzresult Lwt.t + +val bytes_parameter : (Bytes.t, full) Clic.parameter + +val data_parameter : (Michelson_v1_parser.parsed, full) Clic.parameter + +val unparsing_mode_arg : + default:string -> (Script_ir_translator.unparsing_mode, full) Clic.arg + +val enforce_indentation_flag : (bool, full) Clic.arg + +val display_names_flag : (bool, full) Clic.arg diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_context.ml b/src/proto_011_PtHangzH/lib_client/client_proto_context.ml new file mode 100644 index 000000000000..b082e742ad83 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_context.ml @@ -0,0 +1,711 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Protocol_client_context +open Tezos_micheline +open Client_proto_contracts +open Client_keys + +let get_balance (rpc : #rpc_context) ~chain ~block contract = + Alpha_services.Contract.balance rpc (chain, block) contract + +let get_storage (rpc : #rpc_context) ~chain ~block ~unparsing_mode contract = + Plugin.RPC.Contract.get_storage_normalized + rpc + (chain, block) + ~unparsing_mode + ~contract + +let get_big_map_value (rpc : #rpc_context) ~chain ~block ~unparsing_mode id key + = + Plugin.RPC.Big_map.big_map_get_normalized + rpc + (chain, block) + ~unparsing_mode + id + key + +let get_contract_big_map_value (rpc : #rpc_context) ~chain ~block contract key = + Alpha_services.Contract.contract_big_map_get_opt + rpc + (chain, block) + contract + key + +let get_script (rpc : #rpc_context) ~chain ~block ~unparsing_mode contract = + Plugin.RPC.Contract.get_script_normalized + rpc + (chain, block) + ~unparsing_mode + ~contract + +let get_script_hash (rpc : #rpc_context) ~chain ~block contract = + Alpha_services.Contract.script_opt rpc (chain, block) contract + >>=? fun script_opt -> + Lwt.return @@ Environment.wrap_tzresult + @@ Option.map_e + (fun {Script.code; storage = _} -> + Script_repr.force_decode code >>? fun code -> + let bytes = + Data_encoding.Binary.to_bytes_exn Script.expr_encoding code + in + let hash = Script_expr_hash.hash_bytes [bytes] in + ok hash) + script_opt + +let parse_expression arg = + Lwt.return + (Micheline_parser.no_parsing_error + (Michelson_v1_parser.parse_expression arg)) + +let parse_arg_transfer arg = + (match arg with + | Some arg -> + parse_expression arg >>=? fun {expanded = arg; _} -> return_some arg + | None -> return_none) + >>=? fun parameters -> + return + (Option.fold ~some:Script.lazy_expr ~none:Script.unit_parameter parameters) + +let build_transaction_operation ~amount ~parameters ?(entrypoint = "default") + ?fee ?gas_limit ?storage_limit destination = + let operation = Transaction {amount; parameters; destination; entrypoint} in + Injection.prepare_manager_operation + ~fee:(Limit.of_option fee) + ~gas_limit:(Limit.of_option gas_limit) + ~storage_limit:(Limit.of_option storage_limit) + operation + +let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run + ?verbose_signing ?simulation ?branch ~source ~src_pk ~src_sk ~destination + ?(entrypoint = "default") ?arg ~amount ?fee ?gas_limit ?storage_limit + ?counter ~fee_parameter () = + parse_arg_transfer arg >>=? fun parameters -> + let contents = + build_transaction_operation + ~amount + ~parameters + ~entrypoint + ?fee + ?gas_limit + ?storage_limit + destination + in + let contents = Annotated_manager_operation.Single_manager contents in + Injection.inject_manager_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ?simulation + ?branch + ~source + ~fee:(Limit.of_option fee) + ~gas_limit:(Limit.of_option gas_limit) + ~storage_limit:(Limit.of_option storage_limit) + ?counter + ~src_pk + ~src_sk + ~fee_parameter + contents + >>=? fun (oph, op, result) -> + Lwt.return (Injection.originated_contracts result) >>=? fun contracts -> + match Apply_results.pack_contents_list op result with + | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> + return ((oph, op, result), contracts) + +let build_reveal_operation ?fee ?gas_limit ?storage_limit pk = + let operation = Reveal pk in + Injection.prepare_manager_operation + ~fee:(Limit.of_option fee) + ~gas_limit:(Limit.of_option gas_limit) + ~storage_limit:(Limit.of_option storage_limit) + operation + +let reveal cctxt ~chain ~block ?confirmations ?dry_run ?verbose_signing ?branch + ~source ~src_pk ~src_sk ?fee ~fee_parameter () = + let contents = + Annotated_manager_operation.Single_manager + (build_reveal_operation ?fee ~storage_limit:Z.zero src_pk) + in + Injection.inject_manager_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ?branch + ~source + ~fee:(Limit.of_option fee) + ~gas_limit:Limit.unknown + ~storage_limit:Limit.unknown + ~src_pk + ~src_sk + ~fee_parameter + contents + >>=? fun (oph, op, result) -> + match Apply_results.pack_contents_list op result with + | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> + return (oph, op, result) + +let build_delegate_operation ?fee ?gas_limit ?storage_limit delegate_opt = + let operation = Delegation delegate_opt in + Injection.prepare_manager_operation + ~fee:(Limit.of_option fee) + ~gas_limit:(Limit.of_option gas_limit) + ~storage_limit:(Limit.of_option storage_limit) + operation + +let delegate_contract cctxt ~chain ~block ?branch ?confirmations ?dry_run + ?verbose_signing ?simulation ~source ~src_pk ~src_sk ?fee ~fee_parameter + delegate_opt = + let operation = + Annotated_manager_operation.Single_manager + (build_delegate_operation ?fee delegate_opt) + in + Injection.inject_manager_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ?simulation + ?branch + ~source + ~fee:(Limit.of_option fee) + ~gas_limit:Limit.unknown + ~storage_limit:Limit.unknown + ~src_pk + ~src_sk + ~fee_parameter + operation + >>=? fun (oph, op, result) -> + match Apply_results.pack_contents_list op result with + | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> + return (oph, op, result) + +let list_contract_labels cctxt ~chain ~block = + Alpha_services.Contract.list cctxt (chain, block) >>=? fun contracts -> + List.rev_map_es + (fun h -> + (match Contract.is_implicit h with + | Some m -> ( + Public_key_hash.rev_find cctxt m >>=? function + | None -> return "" + | Some nm -> ( + RawContractAlias.find_opt cctxt nm >>=? function + | None -> return (" (known as " ^ nm ^ ")") + | Some _ -> return (" (known as key:" ^ nm ^ ")"))) + | None -> ( + RawContractAlias.rev_find cctxt h >>=? function + | None -> return "" + | Some nm -> return (" (known as " ^ nm ^ ")"))) + >>=? fun nm -> + let kind = + match Contract.is_implicit h with Some _ -> " (implicit)" | None -> "" + in + let h_b58 = Contract.to_b58check h in + return (nm, h_b58, kind)) + contracts + >|=? List.rev + +let message_added_contract (cctxt : #full) name = + cctxt#message "Contract memorized as %s." name + +let set_delegate cctxt ~chain ~block ?confirmations ?dry_run ?verbose_signing + ?simulation ?fee contract ~src_pk ~manager_sk ~fee_parameter opt_delegate = + delegate_contract + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ?simulation + ~source:contract + ~src_pk + ~src_sk:manager_sk + ?fee + ~fee_parameter + opt_delegate + +let register_as_delegate cctxt ~chain ~block ?confirmations ?dry_run + ?verbose_signing ?fee ~manager_sk ~fee_parameter src_pk = + let source = Signature.Public_key.hash src_pk in + delegate_contract + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ~source + ~src_pk + ~src_sk:manager_sk + ?fee + ~fee_parameter + (Some source) + +let save_contract ~force cctxt alias_name contract = + RawContractAlias.add ~force cctxt alias_name contract >>=? fun () -> + message_added_contract cctxt alias_name >>= fun () -> return_unit + +let build_origination_operation ?fee ?gas_limit ?storage_limit ~initial_storage + ~code ~delegate ~balance () = + (* With the change of making implicit accounts delegatable, the following + 3 arguments are being defaulted before they can be safely removed. *) + Lwt.return (Michelson_v1_parser.parse_expression initial_storage) + >>= fun result -> + Lwt.return (Micheline_parser.no_parsing_error result) + >>=? fun {Michelson_v1_parser.expanded = storage; _} -> + let code = Script.lazy_expr code and storage = Script.lazy_expr storage in + let origination = + Origination + { + delegate; + script = {code; storage}; + credit = balance; + preorigination = None; + } + in + return + (Injection.prepare_manager_operation + ~fee:(Limit.of_option fee) + ~gas_limit:(Limit.of_option gas_limit) + ~storage_limit:(Limit.of_option storage_limit) + origination) + +let originate_contract (cctxt : #full) ~chain ~block ?confirmations ?dry_run + ?verbose_signing ?branch ?fee ?gas_limit ?storage_limit ~delegate + ~initial_storage ~balance ~source ~src_pk ~src_sk ~code ~fee_parameter () = + build_origination_operation + ?fee + ?gas_limit + ?storage_limit + ~initial_storage + ~code + ~delegate + ~balance + () + >>=? fun origination -> + let origination = Annotated_manager_operation.Single_manager origination in + Injection.inject_manager_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ?branch + ~source + ~fee:(Limit.of_option fee) + ~gas_limit:(Limit.of_option gas_limit) + ~storage_limit:(Limit.of_option storage_limit) + ~src_pk + ~src_sk + ~fee_parameter + origination + >>=? fun (oph, op, result) -> + (match Apply_results.pack_contents_list op result with + | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> + return (oph, op, result)) + >>=? fun res -> + Lwt.return (Injection.originated_contracts result) >>=? function + | [contract] -> return (res, contract) + | contracts -> + failwith + "The origination introduced %d contracts instead of one." + (List.length contracts) + +let michelson_expression_of_string str = + Michelson_v1_parser.parse_expression str |> Micheline_parser.no_parsing_error + >>? fun {Michelson_v1_parser.expanded = v; _} -> ok @@ Script.lazy_expr v + +let build_register_global_constant ?fee ?gas_limit ?storage_limit value = + michelson_expression_of_string value >>? fun value -> + let op = Register_global_constant {value} in + ok + (Injection.prepare_manager_operation + ~fee:(Limit.of_option fee) + ~gas_limit:(Limit.of_option gas_limit) + ~storage_limit:(Limit.of_option storage_limit) + op) + +let register_global_constant (cctxt : #full) ~chain ~block ?confirmations + ?dry_run ?verbose_signing ?simulation ?fee ?gas_limit ?storage_limit + ?counter ~source ~src_pk ~src_sk ~fee_parameter ~constant () = + build_register_global_constant ?fee ?storage_limit ?gas_limit constant + >>?= fun op -> + let op = Annotated_manager_operation.Single_manager op in + Injection.inject_manager_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ?simulation + ?counter + ~source + ~fee:(Limit.of_option fee) + ~storage_limit:(Limit.of_option storage_limit) + ~gas_limit:(Limit.of_option gas_limit) + ~src_pk + ~src_sk + ~fee_parameter + op + >>=? fun (oph, op, result) -> + match Apply_results.pack_contents_list op result with + | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> + return (oph, op, result) + +type activation_key = { + pkh : Ed25519.Public_key_hash.t; + amount : Tez.t; + activation_code : Blinded_public_key_hash.activation_code; + mnemonic : string list; + password : string; + email : string; +} + +let raw_activation_key_encoding = + let open Data_encoding in + obj6 + (req "pkh" Ed25519.Public_key_hash.encoding) + (req "amount" Tez.encoding) + (req "activation_code" Blinded_public_key_hash.activation_code_encoding) + (req "mnemonic" (list string)) + (req "password" string) + (req "email" string) + +let activation_key_encoding = + (* Hack: allow compatibility with older encoding *) + let open Data_encoding in + conv + (fun {pkh; amount; activation_code; mnemonic; password; email} -> + (pkh, amount, activation_code, mnemonic, password, email)) + (fun (pkh, amount, activation_code, mnemonic, password, email) -> + {pkh; amount; activation_code; mnemonic; password; email}) + @@ splitted + ~binary:raw_activation_key_encoding + ~json: + (union + [ + case + ~title:"Activation" + Json_only + raw_activation_key_encoding + (fun x -> Some x) + (fun x -> x); + case + ~title:"Deprecated_activation" + Json_only + (obj6 + (req "pkh" Ed25519.Public_key_hash.encoding) + (req "amount" Tez.encoding) + (req + "secret" + Blinded_public_key_hash.activation_code_encoding) + (req "mnemonic" (list string)) + (req "password" string) + (req "email" string)) + (fun _ -> None) + (fun x -> x); + ]) + +type batch_transfer_operation = { + destination : string; + fee : string option; + gas_limit : Gas.Arith.integral option; + storage_limit : Z.t option; + amount : string; + arg : string option; + entrypoint : string option; +} + +let batch_transfer_operation_encoding = + let open Data_encoding in + conv + (fun {destination; fee; gas_limit; storage_limit; amount; arg; entrypoint} -> + (destination, fee, gas_limit, storage_limit, amount, arg, entrypoint)) + (fun (destination, fee, gas_limit, storage_limit, amount, arg, entrypoint) -> + {destination; fee; gas_limit; storage_limit; amount; arg; entrypoint}) + (obj7 + (req "destination" string) + (opt "fee" string) + (opt "gas-limit" Gas.Arith.n_integral_encoding) + (opt "storage-limit" z) + (req "amount" string) + (opt "arg" string) + (opt "entrypoint" string)) + +let read_key key = + match Bip39.of_words key.mnemonic with + | None -> failwith "" + | Some t -> + (* TODO: unicode normalization (NFKD)... *) + let passphrase = + Bytes.(cat (of_string key.email) (of_string key.password)) + in + let sk = Bip39.to_seed ~passphrase t in + let sk = Bytes.sub sk 0 32 in + let sk : Signature.Secret_key.t = + Ed25519 + (Data_encoding.Binary.of_bytes_exn Ed25519.Secret_key.encoding sk) + in + let pk = Signature.Secret_key.to_public_key sk in + let pkh = Signature.Public_key.hash pk in + return (pkh, pk, sk) + +let inject_activate_operation cctxt ~chain ~block ?confirmations ?dry_run alias + pkh activation_code = + let contents = Single (Activate_account {id = pkh; activation_code}) in + Injection.inject_operation + cctxt + ?confirmations + ?dry_run + ~chain + ~block + ~fee_parameter:Injection.dummy_fee_parameter + contents + >>=? fun (oph, op, result) -> + (match confirmations with + | None -> return_unit + | Some _confirmations -> + Alpha_services.Contract.balance + cctxt + (chain, block) + (Contract.implicit_contract (Ed25519 pkh)) + >>=? fun balance -> + cctxt#message + "Account %s (%a) activated with %s%a." + alias + Ed25519.Public_key_hash.pp + pkh + Client_proto_args.tez_sym + Tez.pp + balance + >>= fun () -> return_unit) + >>=? fun () -> + match Apply_results.pack_contents_list op result with + | Apply_results.Single_and_result ((Activate_account _ as op), result) -> + return (oph, op, result) + +let activate_account (cctxt : #full) ~chain ~block ?confirmations ?dry_run + ?(encrypted = false) ?force key name = + read_key key >>=? fun (pkh, pk, sk) -> + fail_unless + (Signature.Public_key_hash.equal pkh (Ed25519 key.pkh)) + (failure + "@[Inconsistent activation key:@ Computed pkh: %a@ Embedded pkh: \ + %a @]" + Signature.Public_key_hash.pp + pkh + Ed25519.Public_key_hash.pp + key.pkh) + >>=? fun () -> + Tezos_signer_backends.Unencrypted.make_pk pk >>=? fun pk_uri -> + (if encrypted then + Tezos_signer_backends.Encrypted.prompt_twice_and_encrypt cctxt sk + else Tezos_signer_backends.Unencrypted.make_sk sk) + >>=? fun sk_uri -> + Client_keys.register_key cctxt ?force (pkh, pk_uri, sk_uri) name + >>=? fun () -> + inject_activate_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + name + key.pkh + key.activation_code + +let activate_existing_account (cctxt : #full) ~chain ~block ?confirmations + ?dry_run alias activation_code = + Client_keys.alias_keys cctxt alias >>=? function + | Some (Ed25519 pkh, _, _) -> + inject_activate_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + alias + pkh + activation_code + | Some _ -> failwith "Only Ed25519 accounts can be activated" + | None -> failwith "Unknown account" + +type period_info = { + current_period_kind : Voting_period.kind; + position : Int32.t; + remaining : Int32.t; + current_proposal : Protocol_hash.t option; +} + +type ballots_info = { + current_quorum : Int32.t; + participation : Int32.t; + supermajority : Int32.t; + ballots : Vote.ballots; +} + +let get_ballots_info (cctxt : #full) ~chain ~block = + (* Get the next level, not the current *) + let cb = (chain, block) in + Alpha_services.Voting.ballots cctxt cb >>=? fun ballots -> + Alpha_services.Voting.current_quorum cctxt cb >>=? fun current_quorum -> + Alpha_services.Voting.listings cctxt cb >>=? fun listings -> + let max_participation = + List.fold_left (fun acc (_, w) -> Int32.add w acc) 0l listings + in + let all_votes = Int32.(add (add ballots.yay ballots.nay) ballots.pass) in + let participation = Int32.(div (mul all_votes 100_00l) max_participation) in + let supermajority = Int32.(div (mul 8l (add ballots.yay ballots.nay)) 10l) in + return {current_quorum; participation; supermajority; ballots} + +let get_period_info ?(successor = false) (cctxt : #full) ~chain ~block = + let cb = (chain, block) in + (if successor then Alpha_services.Voting.successor_period + else Alpha_services.Voting.current_period) + cctxt + cb + >>=? fun voting_period -> + Alpha_services.Voting.current_proposal cctxt cb >>=? fun current_proposal -> + return + { + current_period_kind = voting_period.voting_period.kind; + position = voting_period.position; + remaining = voting_period.remaining; + current_proposal; + } + +let get_proposals (cctxt : #full) ~chain ~block = + let cb = (chain, block) in + Alpha_services.Voting.proposals cctxt cb + +let submit_proposals ?dry_run ?verbose_signing (cctxt : #full) ~chain ~block + ?confirmations ~src_sk source proposals = + Alpha_services.Voting.successor_period cctxt (chain, block) + >>=? fun {voting_period = {index; _}; _} -> + let contents = Single (Proposals {source; period = index; proposals}) in + Injection.inject_operation + cctxt + ~chain + ~block + ?confirmations + ~fee_parameter:Injection.dummy_fee_parameter + ?dry_run + ~src_sk + contents + ?verbose_signing + +let submit_ballot ?dry_run ?verbose_signing (cctxt : #full) ~chain ~block + ?confirmations ~src_sk source proposal ballot = + (* The user must provide the proposal explicitly to make himself sure + for what he is voting. *) + Alpha_services.Voting.successor_period cctxt (chain, block) + >>=? fun {voting_period = {index; _}; _} -> + let contents = Single (Ballot {source; period = index; proposal; ballot}) in + Injection.inject_operation + cctxt + ~chain + ~block + ?confirmations + ~fee_parameter:Injection.dummy_fee_parameter + ?dry_run + ~src_sk + contents + ?verbose_signing + +let pp_operation formatter (a : Alpha_block_services.operation) = + match (a.receipt, a.protocol_data) with + | (Some (Apply_results.Operation_metadata omd), Operation_data od) -> ( + match Apply_results.kind_equal_list od.contents omd.contents with + | Some Apply_results.Eq -> + Operation_result.pp_operation_result + formatter + (od.contents, omd.contents) + | None -> Stdlib.failwith "Unexpected result.") + | (None, _) -> + Stdlib.failwith + "Pruned metadata: the operation receipt was removed accordingly to the \ + node's history mode." + | _ -> Stdlib.failwith "Unexpected result." + +let get_operation_from_block (cctxt : #full) ~chain predecessors operation_hash + = + Client_confirmations.lookup_operation_in_previous_blocks + cctxt + ~chain + ~predecessors + operation_hash + >>=? function + | None -> return_none + | Some (block, i, j) -> + cctxt#message + "Operation found in block: %a (pass: %d, offset: %d)" + Block_hash.pp + block + i + j + >>= fun () -> + Protocol_client_context.Alpha_block_services.Operations.operation + cctxt + ~chain + ~block:(`Hash (block, 0)) + i + j + >>=? fun op' -> return_some op' + +let display_receipt_for_operation (cctxt : #full) ~chain ?(predecessors = 10) + operation_hash = + get_operation_from_block cctxt ~chain predecessors operation_hash + >>=? function + | None -> failwith "Couldn't find operation" + | Some op -> cctxt#message "%a" pp_operation op >>= fun () -> return_unit + +let cached_contracts cctxt ~chain ~block = + let cb = (chain, block) in + Alpha_services.Cache.cached_contracts cctxt cb + +let contract_rank cctxt ~chain ~block contract = + let cb = (chain, block) in + Alpha_services.Cache.contract_rank cctxt cb contract + +let contract_cache_size cctxt ~chain ~block = + let cb = (chain, block) in + Alpha_services.Cache.contract_cache_size cctxt cb + +let contract_cache_size_limit cctxt ~chain ~block = + let cb = (chain, block) in + Alpha_services.Cache.contract_cache_size_limit cctxt cb diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_context.mli b/src/proto_011_PtHangzH/lib_client/client_proto_context.mli new file mode 100644 index 000000000000..c5dc30b57e24 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_context.mli @@ -0,0 +1,363 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +val list_contract_labels : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + (string * string * string) list tzresult Lwt.t + +val get_storage : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + unparsing_mode:Script_ir_translator.unparsing_mode -> + Contract.t -> + Script.expr option tzresult Lwt.t + +val get_contract_big_map_value : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + Contract.t -> + Script.expr * Script.expr -> + Script.expr option tzresult Lwt.t + +val register_global_constant : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?simulation:bool -> + ?fee:Tez.tez -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + ?counter:Z.t -> + source:Signature.public_key_hash -> + src_pk:Signature.public_key -> + src_sk:Client_keys.sk_uri -> + fee_parameter:Injection.fee_parameter -> + constant:string -> + unit -> + (Kind.register_global_constant Kind.manager Injection.result, tztrace) result + Lwt.t + +val get_big_map_value : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + unparsing_mode:Script_ir_translator.unparsing_mode -> + Big_map.Id.t -> + Script_expr_hash.t -> + Script.expr tzresult Lwt.t + +val get_script : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + unparsing_mode:Script_ir_translator.unparsing_mode -> + Contract.t -> + Script.t option tzresult Lwt.t + +val get_script_hash : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + Contract.t -> + Script_expr_hash.t option tzresult Lwt.t + +val get_balance : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + Contract.t -> + Tez.t tzresult Lwt.t + +val build_delegate_operation : + ?fee:Tez.t -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + public_key_hash option -> + Kind.delegation Annotated_manager_operation.t + +val set_delegate : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?simulation:bool -> + ?fee:Tez.tez -> + public_key_hash -> + src_pk:public_key -> + manager_sk:Client_keys.sk_uri -> + fee_parameter:Injection.fee_parameter -> + public_key_hash option -> + Kind.delegation Kind.manager Injection.result tzresult Lwt.t + +val register_as_delegate : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?fee:Tez.tez -> + manager_sk:Client_keys.sk_uri -> + fee_parameter:Injection.fee_parameter -> + public_key -> + Kind.delegation Kind.manager Injection.result tzresult Lwt.t + +val save_contract : + force:bool -> + #Protocol_client_context.full -> + string -> + Contract.t -> + unit tzresult Lwt.t + +val originate_contract : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?branch:int -> + ?fee:Tez.t -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + delegate:public_key_hash option -> + initial_storage:string -> + balance:Tez.t -> + source:public_key_hash -> + src_pk:public_key -> + src_sk:Client_keys.sk_uri -> + code:Script.expr -> + fee_parameter:Injection.fee_parameter -> + unit -> + (Kind.origination Kind.manager Injection.result * Contract.t) tzresult Lwt.t + +val parse_arg_transfer : string option -> Script.lazy_expr tzresult Lwt.t + +val build_transaction_operation : + amount:Tez.t -> + parameters:Script.lazy_expr -> + ?entrypoint:string -> + ?fee:Tez.t -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + Contract.t -> + Kind.transaction Annotated_manager_operation.t + +val transfer : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?simulation:bool -> + ?branch:int -> + source:public_key_hash -> + src_pk:public_key -> + src_sk:Client_keys.sk_uri -> + destination:Contract.t -> + ?entrypoint:string -> + ?arg:string -> + amount:Tez.t -> + ?fee:Tez.t -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + ?counter:Z.t -> + fee_parameter:Injection.fee_parameter -> + unit -> + (Kind.transaction Kind.manager Injection.result * Contract.t list) tzresult + Lwt.t + +val build_reveal_operation : + ?fee:Tez.t -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + public_key -> + Kind.reveal Annotated_manager_operation.t + +val reveal : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?branch:int -> + source:public_key_hash -> + src_pk:public_key -> + src_sk:Client_keys.sk_uri -> + ?fee:Tez.t -> + fee_parameter:Injection.fee_parameter -> + unit -> + Kind.reveal Kind.manager Injection.result tzresult Lwt.t + +type activation_key = { + pkh : Ed25519.Public_key_hash.t; + amount : Tez.t; + activation_code : Blinded_public_key_hash.activation_code; + mnemonic : string list; + password : string; + email : string; +} + +val activation_key_encoding : activation_key Data_encoding.t + +type batch_transfer_operation = { + destination : string; + fee : string option; + gas_limit : Gas.Arith.integral option; + storage_limit : Z.t option; + amount : string; + arg : string option; + entrypoint : string option; +} + +val batch_transfer_operation_encoding : batch_transfer_operation Data_encoding.t + +val activate_account : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?encrypted:bool -> + ?force:bool -> + activation_key -> + string -> + Kind.activate_account Injection.result tzresult Lwt.t + +val activate_existing_account : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + string -> + Blinded_public_key_hash.activation_code -> + Kind.activate_account Injection.result tzresult Lwt.t + +type period_info = { + current_period_kind : Voting_period.kind; + position : Int32.t; + remaining : Int32.t; + current_proposal : Protocol_hash.t option; +} + +type ballots_info = { + current_quorum : Int32.t; + participation : Int32.t; + supermajority : Int32.t; + ballots : Vote.ballots; +} + +val get_period_info : + ?successor:bool -> + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + period_info tzresult Lwt.t + +val get_ballots_info : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ballots_info tzresult Lwt.t + +val get_proposals : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + Int32.t Environment.Protocol_hash.Map.t tzresult Lwt.t + +val submit_proposals : + ?dry_run:bool -> + ?verbose_signing:bool -> + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + src_sk:Client_keys.sk_uri -> + public_key_hash -> + Protocol_hash.t list -> + Kind.proposals Injection.result_list tzresult Lwt.t + +val submit_ballot : + ?dry_run:bool -> + ?verbose_signing:bool -> + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + src_sk:Client_keys.sk_uri -> + public_key_hash -> + Protocol_hash.t -> + Vote.ballot -> + Kind.ballot Injection.result_list tzresult Lwt.t + +(** lookup an operation in [predecessors] previous blocks, and print the + receipt if found *) +val display_receipt_for_operation : + #Protocol_client_context.full -> + chain:Block_services.chain -> + ?predecessors:int -> + Operation_list_hash.elt -> + unit tzresult Lwt.t + +val cached_contracts : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + (Contract.t * int) list tzresult Lwt.t + +val contract_rank : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + Contract.t -> + int option tzresult Lwt.t + +val contract_cache_size : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + int tzresult Lwt.t + +val contract_cache_size_limit : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + int tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_contracts.ml b/src/proto_011_PtHangzH/lib_client/client_proto_contracts.ml new file mode 100644 index 000000000000..12d154d7d6dd --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_contracts.ml @@ -0,0 +1,156 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +module ContractEntity = struct + include Contract (* t, Compare, encoding *) + + let of_source s = + Contract.of_b58check s |> Environment.wrap_tzresult + |> record_trace (failure "bad contract notation") + |> Lwt.return + + let to_source s = return (Contract.to_b58check s) + + let name = "contract" +end + +module RawContractAlias = Client_aliases.Alias (ContractEntity) + +module ContractAlias = struct + let find cctxt s = + RawContractAlias.find_opt cctxt s >>=? function + | Some v -> return (s, v) + | None -> ( + Client_keys.Public_key_hash.find_opt cctxt s >>=? function + | Some v -> return (s, Contract.implicit_contract v) + | None -> failwith "no contract or key named %s" s) + + let find_key cctxt name = + Client_keys.Public_key_hash.find cctxt name >>=? fun v -> + return (name, Contract.implicit_contract v) + + let rev_find cctxt c = + match Contract.is_implicit c with + | Some hash -> ( + Client_keys.Public_key_hash.rev_find cctxt hash >>=? function + | Some name -> return_some ("key:" ^ name) + | None -> return_none) + | None -> RawContractAlias.rev_find cctxt c + + let get_contract cctxt s = + match String.split ~limit:1 ':' s with + | ["key"; key] -> find_key cctxt key + | _ -> find cctxt s + + let autocomplete cctxt = + Client_keys.Public_key_hash.autocomplete cctxt >>=? fun keys -> + RawContractAlias.autocomplete cctxt >>=? fun contracts -> + return (List.map (( ^ ) "key:") keys @ contracts) + + let alias_param ?(name = "name") ?(desc = "existing contract alias") next = + let desc = + desc ^ "\n" + ^ "Can be a contract alias or a key alias (autodetected in order).\n\ + Use 'key:name' to force the later." + in + Clic.( + param + ~name + ~desc + (parameter ~autocomplete (fun cctxt p -> get_contract cctxt p)) + next) + + let find_destination cctxt s = + match String.split ~limit:1 ':' s with + | ["alias"; alias] -> find cctxt alias + | ["key"; text] -> + Client_keys.Public_key_hash.find cctxt text >>=? fun v -> + return (s, Contract.implicit_contract v) + | _ -> ( + find cctxt s >>= function + | Ok v -> return v + | Error k_errs -> ( + ContractEntity.of_source s >>= function + | Ok v -> return (s, v) + | Error c_errs -> Lwt.return_error (k_errs @ c_errs))) + + let destination_parameter () = + Clic.parameter + ~autocomplete:(fun cctxt -> + autocomplete cctxt >>=? fun list1 -> + Client_keys.Public_key_hash.autocomplete cctxt >>=? fun list2 -> + return (list1 @ list2)) + find_destination + + let destination_param ?(name = "dst") ?(desc = "destination contract") next = + let desc = + String.concat + "\n" + [ + desc; + "Can be an alias, a key, or a literal (autodetected in order).\n\ + Use 'text:literal', 'alias:name', 'key:name' to force."; + ] + in + Clic.param ~name ~desc (destination_parameter ()) next + + let destination_arg ?(name = "dst") ?(doc = "destination contract") () = + let doc = + String.concat + "\n" + [ + doc; + "Can be an alias, a key, or a literal (autodetected in order).\n\ + Use 'text:literal', 'alias:name', 'key:name' to force."; + ] + in + Clic.arg ~long:name ~doc ~placeholder:name (destination_parameter ()) + + let name cctxt contract = + rev_find cctxt contract >>=? function + | None -> return (Contract.to_b58check contract) + | Some name -> return name +end + +let list_contracts cctxt = + RawContractAlias.load cctxt >>=? fun raw_contracts -> + List.map_s (fun (n, v) -> Lwt.return ("", n, v)) raw_contracts + >>= fun contracts -> + Client_keys.Public_key_hash.load cctxt >>=? fun keys -> + (* List accounts (implicit contracts of identities) *) + List.map_es + (fun (n, v) -> + RawContractAlias.mem cctxt n >>=? fun mem -> + let p = if mem then "key:" else "" in + let v' = Contract.implicit_contract v in + return (p, n, v')) + keys + >>=? fun accounts -> return (contracts @ accounts) + +let get_delegate cctxt ~chain ~block source = + Alpha_services.Contract.delegate_opt cctxt (chain, block) source diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_contracts.mli b/src/proto_011_PtHangzH/lib_client/client_proto_contracts.mli new file mode 100644 index 000000000000..fcef44b21f11 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_contracts.mli @@ -0,0 +1,74 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Clic + +module RawContractAlias : Client_aliases.Alias with type t = Contract.t + +module ContractAlias : sig + val get_contract : + #Client_context.wallet -> string -> (string * Contract.t) tzresult Lwt.t + + val alias_param : + ?name:string -> + ?desc:string -> + ('a, (#Client_context.wallet as 'wallet)) params -> + (string * Contract.t -> 'a, 'wallet) params + + val find_destination : + #Client_context.wallet -> string -> (string * Contract.t) tzresult Lwt.t + + val destination_param : + ?name:string -> + ?desc:string -> + ('a, (#Client_context.wallet as 'wallet)) params -> + (string * Contract.t -> 'a, 'wallet) params + + val destination_arg : + ?name:string -> + ?doc:string -> + unit -> + ((string * Contract.t) option, #Client_context.wallet) Clic.arg + + val rev_find : + #Client_context.wallet -> Contract.t -> string option tzresult Lwt.t + + val name : #Client_context.wallet -> Contract.t -> string tzresult Lwt.t + + val autocomplete : #Client_context.wallet -> string list tzresult Lwt.t +end + +val list_contracts : + #Client_context.wallet -> + (string * string * RawContractAlias.t) list tzresult Lwt.t + +val get_delegate : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + Contract.t -> + public_key_hash option tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_fa12.ml b/src/proto_011_PtHangzH/lib_client/client_proto_fa12.ml new file mode 100644 index 000000000000..34ea9f86c17d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_fa12.ml @@ -0,0 +1,974 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol_client_context +open Protocol +open Alpha_context +open Tezos_micheline + +type error += Contract_has_no_script of Contract.t + +type error += Contract_has_no_storage of Contract.t + +type error += Entrypoint_mismatch of string * (Script.expr * Script.expr) option + +type error += Action_unwrapping_error of string * Script.expr + +type error += Not_a_viewable_entrypoint of string + +type error += Not_an_entrypoint of Script.expr + +type error += Not_enough_balance of Z.t * Z.t + +type error += Not_enough_allowance of Z.t * Z.t + +type error += Unsafe_allowance_change of Z.t + +type error += Unexpected_error of Script.location * Script.expr + +let entrypoint_mismatch_explanation ppf (name, ty) = + match ty with + | None -> Format.fprintf ppf "Entrypoint %s is missing" name + | Some (ty, expected) -> + Format.fprintf + ppf + "Entrypoint \"%s\" has type @[%a@], but should have type @[%a@]" + name + Michelson_v1_printer.print_expr + ty + Michelson_v1_printer.print_expr + expected + +let () = + register_error_kind + `Permanent + ~id:"fa12ContractHasNoScript" + ~title:"The given contract is not a smart contract" + ~description:"An FA1.2 command has referenced a scriptless contract." + ~pp:(fun ppf contract -> + Format.fprintf + ppf + "Contract %a is not a smart contract, it has no script." + Contract.pp + contract) + Data_encoding.(obj1 (req "contract" Contract.encoding)) + (function Contract_has_no_script c -> Some c | _ -> None) + (fun c -> Contract_has_no_script c) ; + register_error_kind + `Permanent + ~id:"fa12ContractHasNoStorage" + ~title:"The given contract has no storage" + ~description: + "An FA1.2 command made a call on a contract that has no storage." + ~pp:(fun ppf contract -> + Format.fprintf ppf "Contract %a has no storage." Contract.pp contract) + Data_encoding.(obj1 (req "contract" Contract.encoding)) + (function Contract_has_no_storage c -> Some c | _ -> None) + (fun c -> Contract_has_no_storage c) ; + register_error_kind + `Permanent + ~id:"entrypointMismatch" + ~title:"The given contract does not implement the FA1.2 interface" + ~description: + "An FA1.2 command has referenced a smart contract whose script does not \ + implement at least one FA1.2 entrypoint, or with an incompatible type. \ + See TZIP-7 \ + (https://gitlab.com/tzip/tzip/-/blob/master/proposals/tzip-7/tzip-7.md) \ + for documentation on FA1.2." + ~pp:(fun ppf (name, ty) -> + Format.fprintf + ppf + "Not a supported FA1.2 contract.@\n%a." + entrypoint_mismatch_explanation + (name, ty)) + Data_encoding.( + obj2 + (req "name" string) + (req "type" (option (tup2 Script.expr_encoding Script.expr_encoding)))) + (function Entrypoint_mismatch (n, t) -> Some (n, t) | _ -> None) + (fun (n, t) -> Entrypoint_mismatch (n, t)) ; + register_error_kind + `Permanent + ~id:"actionUnwrappingError" + ~title:"The argument is not for an FA1.2 parameter" + ~description: + "The argument's type does not correspond to that of the corresponding \ + FA1.2 entrypoint." + ~pp:(fun ppf (entrypoint, expr) -> + Format.fprintf + ppf + "Not a supported FA1.2 entrypoint argument.@\nEntrypoint: %s@\n%a." + entrypoint + Michelson_v1_printer.print_expr + expr) + Data_encoding.( + obj2 (req "entrypoint" string) (req "expr" Script.expr_encoding)) + (function Action_unwrapping_error (s, e) -> Some (s, e) | _ -> None) + (fun (s, e) -> Action_unwrapping_error (s, e)) ; + register_error_kind + `Permanent + ~id:"notAViewableEntrypoint" + ~title:"The entrypoint is not viewable" + ~description: + "A transaction made a call on an entrypoint expecting it to implement \ + the 'view' type." + ~pp:(fun ppf entrypoint -> + Format.fprintf ppf "Entrypoint %s is not viewable." entrypoint) + Data_encoding.(obj1 (req "entrypoint" string)) + (function Not_a_viewable_entrypoint e -> Some e | _ -> None) + (fun e -> Not_a_viewable_entrypoint e) ; + register_error_kind + `Permanent + ~id:"notAnEntrypoint" + ~title:"The expression is not for an entrypoint" + ~description: + "The parameter value of the contract call refers to a non-existing \ + entrypoint." + ~pp:(fun ppf param -> + Format.fprintf + ppf + "Not a parameter for an entrypoint.@\n%a." + Michelson_v1_printer.print_expr + param) + Data_encoding.(obj1 (req "param" Script.expr_encoding)) + (function Not_an_entrypoint e -> Some e | _ -> None) + (fun e -> Not_an_entrypoint e) ; + register_error_kind + `Permanent + ~id:"notEnoughBalance" + ~title:"The sender does not have enough balance" + ~description: + "An FA1.2 transfer failed because the sender does not have enough \ + balance." + ~pp:(fun ppf (required, present) -> + Format.fprintf + ppf + "Not enough balance.@\nRequired: %a.@\nPresent: %a." + Z.pp_print + required + Z.pp_print + present) + Data_encoding.(obj2 (req "present" n) (req "required" n)) + (function Not_enough_balance (p, r) -> Some (p, r) | _ -> None) + (fun (p, r) -> Not_enough_balance (p, r)) ; + register_error_kind + `Permanent + ~id:"notEnoughAllowance" + ~title:"The sender does not have enough allowance" + ~description: + "An FA1.2 transfer failed because the receiver does not have enough \ + allowance to ask for a transfer from the sender." + ~pp:(fun ppf (required, present) -> + Format.fprintf + ppf + "Not enough allowance.@\nRequired: %a.@\nPresent: %a." + Z.pp_print + required + Z.pp_print + present) + Data_encoding.(obj2 (req "present" n) (req "required" n)) + (function Not_enough_allowance (p, r) -> Some (p, r) | _ -> None) + (fun (p, r) -> Not_enough_allowance (p, r)) ; + register_error_kind + `Permanent + ~id:"unsafeAllowanceChange" + ~title:"The allowance change is unsafe" + ~description: + "An FA1.2 non-zero allowance change failed because the current allowance \ + is non-zero. For more explanation on why such allowance change is \ + unsafe, please look at TZIP-7 \ + (https://gitlab.com/tzip/tzip/-/blob/master/proposals/tzip-7/tzip-7.md#approve)." + ~pp:(fun ppf previous -> + Format.fprintf + ppf + "Unsafe allowance change@\nPrevious: %a." + Z.pp_print + previous) + Data_encoding.(obj1 (req "previous" n)) + (function Unsafe_allowance_change p -> Some p | _ -> None) + (fun p -> Unsafe_allowance_change p) ; + register_error_kind + `Permanent + ~id:"fa12UnexpectedError" + ~title:"Unexpected error during FA1.2 contract interpretation" + ~description: + "An unexpected Michelson error was reached during the interpretation of \ + an FA1.2 contract." + ~pp:(fun ppf (loc, expr) -> + Format.fprintf + ppf + "An unexpected error was reached at location %d with: %a." + loc + Michelson_v1_printer.print_expr + expr) + Data_encoding.( + obj2 + (req "location" Tezos_micheline.Micheline.canonical_location_encoding) + (req "value" Script.expr_encoding)) + (function Unexpected_error (loc, expr) -> Some (loc, expr) | _ -> None) + (fun (loc, expr) -> Unexpected_error (loc, expr)) + +let callback_encoding = + Data_encoding.( + conv + (fun (c, e) -> (c, Option.value ~default:"" e)) + (fun (c, e) -> (c, if String.equal e "" then None else Some e)) + (tup2 Contract.encoding Variable.string)) + +(** Michelson combinators *) + +let pair ~loc a b = Micheline.Prim (loc, Script.D_Pair, [a; b], []) + +let nat ~loc i = Micheline.Int (loc, i) + +let unit ~loc () = Micheline.Prim (loc, Script.D_Unit, [], []) + +let bytes ~loc b = Micheline.Bytes (loc, b) + +let address ~loc addr = + bytes ~loc (Data_encoding.Binary.to_bytes_exn Contract.encoding addr) + +let callback ~loc ?entrypoint addr = + bytes + ~loc + (Data_encoding.Binary.to_bytes_exn callback_encoding (addr, entrypoint)) + +(** Types *) + +(** Michelson type combinators: produce a Michelson node of the + expected type, and a function to check another node is + syntactically equivalent. *) + +type node = + (Micheline.canonical_location, Michelson_v1_primitives.prim) Micheline.node + +type type_eq_combinator = node * (node -> bool) + +(** [t_pair ~loc l] takes a list of types and respective equivalence + check functions, and returns a type of n-ary pair of such types and + a function checking syntactical equivalence with another node. *) +let t_pair ?(loc = 0) l : type_eq_combinator = + let (values, are_ty) = List.split l in + let is_pair p = + match p with + | Micheline.Prim (_, Script.T_pair, l, _) -> ( + let res = + List.for_all2 + ~when_different_lengths:() + (fun is_ty v -> is_ty v) + are_ty + l + in + match res with Ok b -> b | Error () -> false) + | _ -> false + in + (Micheline.Prim (loc, Script.T_pair, values, []), is_pair) + +(** [t_unit ~loc ()] returns a Micheline node for the `unit` type, and + a function checking another node is syntactically equivalent. *) +let t_unit ?(loc = 0) () : type_eq_combinator = + let is_unit p = + match p with Micheline.Prim (_, Script.T_unit, [], _) -> true | _ -> false + in + (Micheline.Prim (loc, Script.T_unit, [], []), is_unit) + +(** [t_nat ~loc ()] returns a Micheline node for the `nat` type, and + a function checking another node is syntactically equivalent. *) +let t_nat ?(loc = 0) () : type_eq_combinator = + let is_nat p = + match p with Micheline.Prim (_, Script.T_nat, [], _) -> true | _ -> false + in + (Micheline.Prim (loc, Script.T_nat, [], []), is_nat) + +(** [t_address ~loc ()] returns a Micheline node for the `address` + type, and a function checking another node is syntactically + equivalent. *) +let t_address ?(loc = 0) () : type_eq_combinator = + let is_address p = + match p with + | Micheline.Prim (_, Script.T_address, [], _) -> true + | _ -> false + in + (Micheline.Prim (loc, Script.T_address, [], []), is_address) + +(** [t_contract ~loc (c, is_c)] takes a node representing a Michelson + type and its own syntactical equivalence checker, and returns a + Micheline node for the type `contract c`, and a function checking + another node is syntactically equivalent. *) +let t_contract ?(loc = 0) (a, is_a) : type_eq_combinator = + let is_contract c = + match c with + | Micheline.Prim (_, Script.T_contract, [a], _) -> is_a a + | _ -> false + in + (Micheline.Prim (loc, Script.T_contract, [a], []), is_contract) + +(** [t_view ~loc a b] takes two node [a] and [b] and their syntactical + equivalence checking functions, and returns a Micheline node for + the `view a b` type, and a function checking another node is + syntactically equivalent. The view type is defined by + [TZIP4](https://gitlab.com/tzip/tzip/-/blob/master/proposals/tzip-4/tzip-4.md). + *) +let t_view ?loc a b : type_eq_combinator = t_pair ?loc [a; t_contract ?loc b] + +(** * Actions *) + +(** Corresponds to + [TZIP7](https://gitlab.com/tzip/tzip/-/blob/master/proposals/tzip-7/tzip-7.md) + entrypoints. *) + +(** A callback from a view can be on a specific entrypoint of the + contract, or the default one if not specified. *) +type callback_contract = Contract.t * string option + +type action = + | Transfer of Contract.t * Contract.t * Z.t + | Approve of Contract.t * Z.t + | Get_allowance of Contract.t * Contract.t * callback_contract + | Get_balance of Contract.t * callback_contract + | Get_total_supply of callback_contract + +let print_callback_contract ppf (c, etp) = + Format.fprintf + ppf + "%a%s" + Contract.pp + c + (match etp with None | Some "" -> "" | Some etp -> "%" ^ etp) + +let print_action ppf = function + | Transfer (src, dst, amount) -> + Format.fprintf + ppf + "Transfer (%a, %a, %a)" + Contract.pp + src + Contract.pp + dst + Z.pp_print + amount + | Approve (addr, amount) -> + Format.fprintf ppf "Approve (%a, %a)" Contract.pp addr Z.pp_print amount + | Get_allowance (src, dst, callback) -> + Format.fprintf + ppf + "Get_allowance (%a, %a, %a)" + Contract.pp + src + Contract.pp + dst + print_callback_contract + callback + | Get_balance (addr, callback) -> + Format.fprintf + ppf + "Get_balance (%a, %a)" + Contract.pp + addr + print_callback_contract + callback + | Get_total_supply callback -> + Format.fprintf + ppf + "Get_total_supply (%a)" + print_callback_contract + callback + +let transfer_encoding = + Data_encoding.( + case + ~title:"transfer" + (Tag 0) + (obj3 + (req "transfer_source" Contract.encoding) + (req "transfer_destination" Contract.encoding) + (req "transfer_amount" n)) + (function + | Transfer (src, dst, amount) -> Some (src, dst, amount) | _ -> None) + (fun (src, dst, amount) -> Transfer (src, dst, amount))) + +let approve_encoding = + Data_encoding.( + case + ~title:"approve" + (Tag 1) + (obj2 (req "approve_address" Contract.encoding) (req "approve_amount" n)) + (function Approve (addr, amount) -> Some (addr, amount) | _ -> None) + (fun (addr, amount) -> Approve (addr, amount))) + +let getBalance_encoding = + Data_encoding.( + case + ~title:"getBalance" + (Tag 2) + (obj2 + (req "getBalance_address" Contract.encoding) + (req "getBalance_callback" callback_encoding)) + (function + | Get_balance (addr, callback) -> Some (addr, callback) | _ -> None) + (fun (addr, callback) -> Get_balance (addr, callback))) + +let getAllowance_encoding = + Data_encoding.( + case + ~title:"getAllowance" + (Tag 3) + (obj3 + (req "getAllowance_source" Contract.encoding) + (req "getAllowance_destination" Contract.encoding) + (req "getAllowance_callback" callback_encoding)) + (function + | Get_allowance (src, dst, callback) -> Some (src, dst, callback) + | _ -> None) + (fun (src, dst, callback) -> Get_allowance (src, dst, callback))) + +let getTotalSupply_encoding = + Data_encoding.( + case + ~title:"getTotalSupply" + (Tag 4) + (obj1 (req "getTotalSupply_callback" callback_encoding)) + (function Get_total_supply callback -> Some callback | _ -> None) + (fun callback -> Get_total_supply callback)) + +let action_encoding = + Data_encoding.union + [ + transfer_encoding; + approve_encoding; + getBalance_encoding; + getAllowance_encoding; + getTotalSupply_encoding; + ] + +let transfer_type = t_pair [t_address (); t_address (); t_nat ()] + +let approve_type = t_pair [t_address (); t_nat ()] + +let getAllowance_type = t_view (t_pair [t_address (); t_address ()]) (t_nat ()) + +let getBalance_type = t_view (t_address ()) (t_nat ()) + +let getTotalSupply_type = t_view (t_unit ()) (t_nat ()) + +let standard_entrypoints = + [ + ("transfer", transfer_type); + ("approve", approve_type); + ("getAllowance", getAllowance_type); + ("getBalance", getBalance_type); + ("getTotalSupply", getTotalSupply_type); + ] + +let view_input ?(loc = 0) action = + match action with + | Get_allowance (source, destination, _) -> + pair ~loc (address ~loc source) (address ~loc destination) + | Get_balance (addr, _) -> address ~loc addr + | Get_total_supply _ -> unit ~loc () + | _ -> unit ~loc () + +let action_to_expr ?(loc = 0) action = + match action with + | Transfer (source, destination, amount) -> + pair + ~loc + (address ~loc source) + (pair ~loc (address ~loc destination) (nat ~loc amount)) + | Approve (addr, amount) -> pair ~loc (address ~loc addr) (nat ~loc amount) + | Get_allowance (_, _, (cb, entrypoint)) -> + let input = view_input action in + pair ~loc input (callback ~loc ?entrypoint cb) + | Get_balance (_, (cb, entrypoint)) -> + let input = view_input action in + pair ~loc input (callback ~loc ?entrypoint cb) + | Get_total_supply (cb, entrypoint) -> + let input = view_input action in + pair ~loc input (callback ~loc ?entrypoint cb) + +let parse_address error = function + | Micheline.Bytes (_, b) -> + ok @@ Data_encoding.Binary.of_bytes_exn Contract.encoding b + | String (_, s) -> ( + match Contract.of_b58check s with Ok c -> ok c | Error _ -> error ()) + | _ -> error () + +let parse_callback error expr = + let of_b58_check (c, entrypoint) = + match Contract.of_b58check c with + | Ok c -> ok (c, entrypoint) + | Error _ -> error () + in + match expr with + | Micheline.Bytes (_, b) -> ( + match Data_encoding.Binary.of_bytes callback_encoding b with + | Ok (c, entrypoint) -> ok (c, entrypoint) + | Error _ -> error ()) + | String (_, s) -> ( + match String.index_opt s '%' with + | None -> of_b58_check (s, None) + | Some pos -> ( + let len = String.length s - pos - 1 in + let name = String.sub s (pos + 1) len in + match (String.sub s 0 pos, name) with + | (addr, "default") -> of_b58_check (addr, None) + | (addr, name) -> of_b58_check (addr, Some name))) + | _ -> error () + +let action_of_expr ~entrypoint expr = + let open Micheline in + let error () = + error (Action_unwrapping_error (entrypoint, Micheline.strip_locations expr)) + in + match (entrypoint, expr) with + (* Transfer operation before comb pairs. *) + | ( "transfer", + Prim + ( _, + Script.D_Pair, + [ + ((Bytes (_, _) | String (_, _)) as source); + Prim + ( _, + Script.D_Pair, + [ + ((Bytes (_, _) | String (_, _)) as destination); + Int (_, amount); + ], + _ ); + ], + _ ) ) + (* Transfer operation since Edo comb pairs are now directly interpreted as a + tuple of 3 elements instead of a pair inside a pair. *) + | ( "transfer", + Prim + ( _, + Script.D_Pair, + [ + ((Bytes (_, _) | String (_, _)) as source); + ((Bytes (_, _) | String (_, _)) as destination); + Int (_, amount); + ], + _ ) ) -> + parse_address error source >>? fun source -> + parse_address error destination >>? fun destination -> + ok (Transfer (source, destination, amount)) + | ( "approve", + Prim + ( _, + Script.D_Pair, + [((Bytes (_, _) | String (_, _)) as addr); Int (_, amount)], + _ ) ) -> + parse_address error addr >>? fun addr -> ok (Approve (addr, amount)) + | ( "getBalance", + Prim + ( _, + Script.D_Pair, + [ + ((Bytes (_, _) | String (_, _)) as addr); + ((Bytes (_, _) | String (_, _)) as cb); + ], + _ ) ) -> + parse_address error addr >>? fun addr -> + parse_callback error cb >>? fun callback -> + ok (Get_balance (addr, callback)) + | ( "getAllowance", + Prim + ( _, + Script.D_Pair, + [ + Prim + ( _, + Script.D_Pair, + [ + ((Bytes (_, _) | String (_, _)) as source); + ((Bytes (_, _) | String (_, _)) as destination); + ], + _ ); + ((Bytes (_, _) | String (_, _)) as contract); + ], + _ ) ) -> + parse_address error source >>? fun source -> + parse_address error destination >>? fun destination -> + parse_callback error contract >>? fun callback -> + ok (Get_allowance (source, destination, callback)) + | ( "getTotalSupply", + Prim + ( _, + Script.D_Pair, + [ + Prim (_, Script.D_Unit, [], _); + ((Bytes (_, _) | String (_, _)) as contract); + ], + _ ) ) -> + parse_callback error contract >>? fun callback -> + ok (Get_total_supply callback) + | _ -> error () + +let find_entrypoint_in_annot error annots expr = + match List.find_opt (fun annot -> annot.[0] = '%') annots with + | Some entrypoint -> + action_of_expr + ~entrypoint:(String.sub entrypoint 1 (String.length entrypoint - 1)) + expr + | None -> error () + +let derive_action expr t_param = + let error () = error (Not_an_entrypoint (Micheline.strip_locations expr)) in + let rec derive expr t_param = + match (expr, t_param) with + | ( Micheline.Prim (_, Script.D_Left, [left], _), + Micheline.Prim (_, Script.T_or, [t_left; _], _) ) -> + derive left t_left + | ( Micheline.Prim (_, Script.D_Right, [right], _), + Micheline.Prim (_, Script.T_or, [_; t_right], _) ) -> + derive right t_right + | (_, Micheline.Prim (_, _, _, annots)) -> + find_entrypoint_in_annot error annots expr + | _ -> error () + in + derive expr t_param + +let extract_parameter contract = function + | Micheline.Seq (_, l) -> ( + List.filter_map + (function + | Micheline.Prim (_, Script.K_parameter, [param], _) -> Some param + | _ -> None) + l + |> function + | param :: _ -> ok param + | _ -> error (Contract_has_no_script contract)) + | _ -> error (Contract_has_no_script contract) + +let get_contract_parameter cctxt ~chain ~block contract = + Client_proto_context.get_script + cctxt + ~chain + ~block + contract + ~unparsing_mode:Optimized + >>=? function + | None -> fail (Contract_has_no_script contract) + | Some {code; _} -> ( + match Script_repr.force_decode code with + | Error _ -> fail (Contract_has_no_script contract) + | Ok code -> Lwt.return (extract_parameter contract (Micheline.root code)) + ) + +let convert_wrapped_parameter_into_action cctxt ~chain ~block contract param = + get_contract_parameter cctxt ~chain ~block contract >>=? fun parameter -> + Lwt.return (derive_action param parameter) + +let check_entrypoint entrypoints (name, (expected_ty, check)) = + match List.assoc_opt ~equal:String.equal name entrypoints with + | None -> error (Entrypoint_mismatch (name, None)) + | Some ty -> + if not (check (Micheline.root ty)) then + error + (Entrypoint_mismatch + (name, Some (ty, Micheline.strip_locations expected_ty))) + else Ok () + +let action_to_entrypoint = function + | Transfer (_, _, _) -> "transfer" + | Approve (_, _) -> "approve" + | Get_allowance (_, _, _) -> "getAllowance" + | Get_balance (_, _) -> "getBalance" + | Get_total_supply _ -> "getTotalSupply" + +let contract_has_fa12_interface : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + contract:Alpha_context.Contract.t -> + unit -> + unit tzresult Lwt.t = + fun cctxt ~chain ~block ~contract () -> + match Contract.is_implicit contract with + | Some _ -> fail (Contract_has_no_script contract) + | None -> + Michelson_v1_entrypoints.list_contract_entrypoints + cctxt + ~chain + ~block + ~contract + >>=? fun entrypoints -> + List.iter_e (check_entrypoint entrypoints) standard_entrypoints + |> Lwt.return + +let translate_action_to_argument action = + let entrypoint = action_to_entrypoint action in + let expr = Micheline.strip_locations (action_to_expr action) in + (entrypoint, Format.asprintf "%a" Michelson_v1_printer.print_expr expr) + +let parse_error = + let open Micheline in + function + | ( "NotEnoughBalance", + Prim (_, Script.D_Pair, [Int (_, required); Int (_, present)], _) ) -> + Some (Not_enough_balance (required, present)) + | ( "NotEnoughAllowance", + Prim (_, Script.D_Pair, [Int (_, required); Int (_, present)], _) ) -> + Some (Not_enough_allowance (required, present)) + | ("UnsafeAllowanceChange", Int (_, previous)) -> + Some (Unsafe_allowance_change previous) + | _ -> None + +let extract_error trace = + let open Micheline in + TzTrace.fold + (fun _ error -> + match error with + | Environment.Ecoproto_error (Script_interpreter.Reject (loc, param, _)) + -> ( + match root param with + | Prim (_, Script.D_Pair, [String (_, error); res], _) -> + parse_error (error, res) + | _ -> Some (Unexpected_error (loc, param))) + | _ -> None) + None + trace + +let call_contract (cctxt : #Protocol_client_context.full) ~chain ~block + ?confirmations ?dry_run ?verbose_signing ?branch ~source ~src_pk ~src_sk + ~contract ~action ~tez_amount ?fee ?gas_limit ?storage_limit ?counter + ~fee_parameter () = + contract_has_fa12_interface cctxt ~chain ~block ~contract () >>=? fun () -> + let (entrypoint, arg) = translate_action_to_argument action in + Client_proto_context.transfer + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?branch + ~source + ~src_pk + ~src_sk + ~destination:contract + ~arg + ~amount:tez_amount + ~entrypoint + ?fee + ?gas_limit + ?storage_limit + ?counter + ~fee_parameter + ?verbose_signing + () + >>= function + | Ok res -> return res + | Error trace -> ( + match extract_error trace with + | None -> Lwt.return (Error trace) + | Some error -> fail error) + +type token_transfer = { + token_contract : string; + destination : string; + amount : Z.t; + tez_amount : string option; + fee : string option; + gas_limit : Gas.Arith.integral option; + storage_limit : Z.t option; +} + +let token_transfer_encoding = + let open Data_encoding in + conv + (fun { + token_contract; + destination; + amount; + tez_amount; + fee; + gas_limit; + storage_limit; + } -> + ( token_contract, + destination, + amount, + tez_amount, + fee, + gas_limit, + storage_limit )) + (fun ( token_contract, + destination, + amount, + tez_amount, + fee, + gas_limit, + storage_limit ) -> + { + token_contract; + destination; + amount; + tez_amount; + fee; + gas_limit; + storage_limit; + }) + (obj7 + (req "token_contract" string) + (req "destination" string) + (req "amount" z) + (opt "tez-amount" string) + (opt "fee" string) + (opt "gas-limit" Gas.Arith.n_integral_encoding) + (opt "storage-limit" z)) + +let tez_of_string_exn index field s = + match Tez.of_string s with + | Some t -> ok t + | None -> + generic_error + "Invalid %s notation at entry %i, field \"%s\": %s" + Client_proto_args.tez_sym + index + field + s + +let tez_of_opt_string_exn index field s = + Option.map_e (tez_of_string_exn index field) s + +let build_transaction_operation ?(tez_amount = Tez.zero) ?fee ?gas_limit + ?storage_limit token action = + let entrypoint = action_to_entrypoint action in + let parameters = + Script.lazy_expr (Micheline.strip_locations (action_to_expr action)) + in + let operation = + Transaction + {amount = tez_amount; parameters; destination = token; entrypoint} + in + Injection.prepare_manager_operation + ~fee:(Limit.of_option fee) + ~gas_limit:(Limit.of_option gas_limit) + ~storage_limit:(Limit.of_option storage_limit) + operation + +let prepare_single_token_transfer cctxt ?default_fee ?default_gas_limit + ?default_storage_limit ~chain ~block src index transfer = + Client_proto_contracts.ContractAlias.find_destination + cctxt + transfer.token_contract + >>=? fun (_, token) -> + contract_has_fa12_interface cctxt ~chain ~block ~contract:token () + >>=? fun () -> + Client_proto_contracts.ContractAlias.find_destination + cctxt + transfer.destination + >>=? fun (_, dest) -> + tez_of_opt_string_exn index "tez_amount" transfer.tez_amount + >>?= fun tez_amount -> + tez_of_opt_string_exn index "fee" transfer.fee >>?= fun transfer_fee -> + let fee = Option.either transfer_fee default_fee in + let gas_limit = Option.either transfer.gas_limit default_gas_limit in + let storage_limit = + Option.either transfer.storage_limit default_storage_limit + in + let action = Transfer (src, dest, transfer.amount) in + let operation = + build_transaction_operation + ?tez_amount + ?fee + ?gas_limit + ?storage_limit + token + action + in + return (Annotated_manager_operation.Annotated_manager_operation operation) + +let inject_token_transfer_batch (cctxt : #Protocol_client_context.full) ~chain + ~block ?confirmations ?dry_run ?verbose_signing ~sender ~source ~src_pk + ~src_sk ~token_transfers ~fee_parameter ?counter ?default_fee + ?default_gas_limit ?default_storage_limit () = + List.mapi_ep + (prepare_single_token_transfer + cctxt + ?default_fee + ?default_gas_limit + ?default_storage_limit + ~chain + ~block + sender) + token_transfers + >>=? fun contents -> + let (Manager_list contents) = + Annotated_manager_operation.manager_of_list contents + in + Injection.inject_manager_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ~source + ~fee:(Limit.of_option default_fee) + ~gas_limit:(Limit.of_option default_gas_limit) + ~storage_limit:(Limit.of_option default_storage_limit) + ?counter + ~src_pk + ~src_sk + ~fee_parameter + contents + >>= function + | Ok _ -> return () + | Error trace -> ( + match extract_error trace with + | None -> Lwt.return (Error trace) + | Some error -> fail error) + +let is_viewable_action action = + match action with + | Get_balance (_, _) | Get_allowance (_, _, _) | Get_total_supply _ -> + return () + | _ -> fail (Not_a_viewable_entrypoint (action_to_entrypoint action)) + +let run_view_action (cctxt : #Protocol_client_context.full) ~chain ~block + ?source ~contract ~action ?payer ?gas ~unparsing_mode () = + is_viewable_action action >>=? fun () -> + contract_has_fa12_interface cctxt ~chain ~block ~contract () >>=? fun () -> + let entrypoint = action_to_entrypoint action in + let input = Micheline.strip_locations (view_input action) in + Chain_services.chain_id cctxt ~chain () >>=? fun chain_id -> + Plugin.RPC.Scripts.run_view + cctxt + (chain, block) + ~contract + ~input + ~chain_id + ?source + ?payer + ?gas + ~entrypoint + ~unparsing_mode + +let () = + Data_encoding.( + Registration.register + @@ def (Protocol.name ^ ".fa1.2.token_transfer") token_transfer_encoding) diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_fa12.mli b/src/proto_011_PtHangzH/lib_client/client_proto_fa12.mli new file mode 100644 index 000000000000..c712af89a2dd --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_fa12.mli @@ -0,0 +1,157 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** [Client_proto_fa12] implements built-in support for the + {{:https://gitlab.com/tzip/tzip/-/blob/master/proposals/tzip-7/tzip-7.md} + FA1.2} standard. This module features functions to check whether a + contract implements the standard interface and to interact with + such contracts using high-level [actions] that model the entrypoint + calls. + + This module also provides functions to unwrap [Micheline] values + into [actions], which can be useful for indexers or applications + using this module to interpret transactions on FA1.2 contracts as + FA1.2 operations. *) + +open Protocol +open Alpha_context +open Protocol_client_context + +(** A callback contract is represented by an address and a possible + entrypoint on which the transaction is done. *) +type callback_contract = Contract.t * string option + +type action = + | Transfer of Contract.t * Contract.t * Z.t + | Approve of Contract.t * Z.t + | Get_allowance of Contract.t * Contract.t * callback_contract + | Get_balance of Contract.t * callback_contract + | Get_total_supply of callback_contract + +val print_action : Format.formatter -> action -> unit + +val action_encoding : action Data_encoding.encoding + +val action_to_expr : ?loc:Script.location -> action -> Script.node + +val action_of_expr : entrypoint:string -> Script.node -> action tzresult + +(** [convert_wrapped_parameter_into_action ccctx ~chain ~block + ~contract parameter] converts a wrapped FA1.2 contract [parameter] + into the corresponding FA1.2 [action]. + + That is, it takes a contract parameter on the form [C_1 .. (C_n + ... ))] where [C_1 ... C_n] is a sequence of + [Left]/[Right] constructors. It finds the entrypoint corresponding + to that path in [contract]'s interface. The result of the function + is the [] applied to the [action] + corresponding to that entrypoint. *) +val convert_wrapped_parameter_into_action : + full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + Contract.t -> + Script.node -> + action tzresult Lwt.t + +(** Check whether a contract has an FA1.2 interface. *) +val contract_has_fa12_interface : + full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + contract:Alpha_context.Contract.t -> + unit -> + unit tzresult Lwt.t + +val call_contract : + full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?branch:int -> + source:public_key_hash -> + src_pk:public_key -> + src_sk:Client_keys.sk_uri -> + contract:Contract.t -> + action:action -> + tez_amount:Tez.t -> + ?fee:Tez.t -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + ?counter:Z.t -> + fee_parameter:Injection.fee_parameter -> + unit -> + (Kind.transaction Kind.manager Injection.result * Contract.t list) tzresult + Lwt.t + +(** Single transfer operation. *) +type token_transfer = { + token_contract : string; + destination : string; + amount : Z.t; + tez_amount : string option; + fee : string option; + gas_limit : Gas.Arith.integral option; + storage_limit : Z.t option; +} + +val token_transfer_encoding : token_transfer Data_encoding.t + +(** Inject a batch of token transfers. *) +val inject_token_transfer_batch : + full -> + chain:Chain_services.chain -> + block:Block_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + sender:Contract.t -> + source:public_key_hash -> + src_pk:public_key -> + src_sk:Client_keys.sk_uri -> + token_transfers:token_transfer list -> + fee_parameter:Injection.fee_parameter -> + ?counter:counter -> + ?default_fee:Tez.t -> + ?default_gas_limit:Gas.Arith.integral -> + ?default_storage_limit:counter -> + unit -> + unit tzresult Lwt.t + +(** Run the action without injecting it. Only for views. *) +val run_view_action : + full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?source:Contract.t -> + contract:Contract.t -> + action:action -> + ?payer:Contract.t -> + ?gas:Gas.Arith.integral -> + unparsing_mode:Script_ir_translator.unparsing_mode -> + unit -> + Script.expr tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_multisig.ml b/src/proto_011_PtHangzH/lib_client/client_proto_multisig.ml new file mode 100644 index 000000000000..8a9dd286262b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_multisig.ml @@ -0,0 +1,1211 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol_client_context +open Protocol +open Alpha_context +open Michelson_v1_helpers + +type error += Contract_has_no_script of Contract.t + +type error += Not_a_supported_multisig_contract of Script_expr_hash.t + +type error += Contract_has_no_storage of Contract.t + +type error += Contract_has_unexpected_storage of Contract.t + +type error += Invalid_signature of signature + +type error += Not_enough_signatures of int * int + +type error += Action_deserialisation_error of Script.expr + +type error += Bytes_deserialisation_error of Bytes.t + +type error += Bad_deserialized_contract of (Contract.t * Contract.t) + +type error += Bad_deserialized_counter of (counter * counter) + +type error += Non_positive_threshold of int + +type error += Threshold_too_high of int * int + +type error += Unsupported_feature_generic_call of Script.expr + +type error += Unsupported_feature_generic_call_ty of Script.expr + +type error += Unsupported_feature_lambda of string + +type error += + | Ill_typed_argument of Contract.t * string * Script.expr * Script.expr + +type error += Ill_typed_lambda of Script.expr * Script.expr + +let () = + register_error_kind + `Permanent + ~id:"contractHasNoScript" + ~title: + "The given contract is not a multisig contract because it has no script" + ~description: + "A multisig command has referenced a scriptless smart contract instead \ + of a multisig smart contract." + ~pp:(fun ppf contract -> + Format.fprintf ppf "Contract has no script %a." Contract.pp contract) + Data_encoding.(obj1 (req "contract" Contract.encoding)) + (function Contract_has_no_script c -> Some c | _ -> None) + (fun c -> Contract_has_no_script c) ; + register_error_kind + `Permanent + ~id:"notASupportedMultisigContract" + ~title:"The given contract is not one of the supported contracts" + ~description: + "A multisig command has referenced a smart contract whose script is not \ + one of the known multisig contract scripts." + ~pp:(fun ppf hash -> + Format.fprintf + ppf + "Not a supported multisig contract.@\n\ + The hash of this script is %a, it was not found among in the list of \ + known multisig script hashes." + Script_expr_hash.pp + hash) + Data_encoding.(obj1 (req "hash" Script_expr_hash.encoding)) + (function Not_a_supported_multisig_contract h -> Some h | _ -> None) + (fun h -> Not_a_supported_multisig_contract h) ; + register_error_kind + `Permanent + ~id:"contractHasNoStorage" + ~title: + "The given contract is not a multisig contract because it has no storage" + ~description: + "A multisig command has referenced a smart contract without storage \ + instead of a multisig smart contract." + ~pp:(fun ppf contract -> + Format.fprintf ppf "Contract has no storage %a." Contract.pp contract) + Data_encoding.(obj1 (req "contract" Contract.encoding)) + (function Contract_has_no_storage c -> Some c | _ -> None) + (fun c -> Contract_has_no_storage c) ; + register_error_kind + `Permanent + ~id:"contractHasUnexpectedStorage" + ~title: + "The storage of the given contract is not of the shape expected for a \ + multisig contract" + ~description: + "A multisig command has referenced a smart contract whose storage is of \ + a different shape than the expected one." + ~pp:(fun ppf contract -> + Format.fprintf + ppf + "Contract has unexpected storage %a." + Contract.pp + contract) + Data_encoding.(obj1 (req "contract" Contract.encoding)) + (function Contract_has_unexpected_storage c -> Some c | _ -> None) + (fun c -> Contract_has_unexpected_storage c) ; + register_error_kind + `Permanent + ~id:"invalidSignature" + ~title: + "The following signature did not match a public key in the given \ + multisig contract" + ~description: + "A signature was given for a multisig contract that matched none of the \ + public keys of the contract signers" + ~pp:(fun ppf s -> + Format.fprintf ppf "Invalid signature %s." (Signature.to_b58check s)) + Data_encoding.(obj1 (req "invalid_signature" Signature.encoding)) + (function Invalid_signature s -> Some s | _ -> None) + (fun s -> Invalid_signature s) ; + register_error_kind + `Permanent + ~id:"notEnoughSignatures" + ~title:"Not enough signatures were provided for this multisig action" + ~description: + "To run an action on a multisig contract, you should provide at least as \ + many signatures as indicated by the threshold stored in the multisig \ + contract." + ~pp:(fun ppf (threshold, nsigs) -> + Format.fprintf + ppf + "Not enough signatures: only %d signatures were given but the \ + threshold is currently %d" + nsigs + threshold) + Data_encoding.(obj1 (req "threshold_nsigs" (tup2 int31 int31))) + (function + | Not_enough_signatures (threshold, nsigs) -> Some (threshold, nsigs) + | _ -> None) + (fun (threshold, nsigs) -> Not_enough_signatures (threshold, nsigs)) ; + register_error_kind + `Permanent + ~id:"actionDeserialisation" + ~title:"The expression is not a valid multisig action" + ~description: + "When trying to deserialise an action from a sequence of bytes, we got \ + an expression that does not correspond to a known multisig action" + ~pp:(fun ppf e -> + Format.fprintf + ppf + "Action deserialisation error %a." + Michelson_v1_printer.print_expr + e) + Data_encoding.(obj1 (req "expr" Script.expr_encoding)) + (function Action_deserialisation_error e -> Some e | _ -> None) + (fun e -> Action_deserialisation_error e) ; + register_error_kind + `Permanent + ~id:"bytesDeserialisation" + ~title:"The byte sequence is not a valid multisig action" + ~description: + "When trying to deserialise an action from a sequence of bytes, we got \ + an error" + ~pp:(fun ppf b -> + Format.fprintf ppf "Bytes deserialisation error %s." (Bytes.to_string b)) + Data_encoding.(obj1 (req "expr" bytes)) + (function Bytes_deserialisation_error b -> Some b | _ -> None) + (fun b -> Bytes_deserialisation_error b) ; + register_error_kind + `Permanent + ~id:"badDeserializedContract" + ~title:"The byte sequence is not for the given multisig contract" + ~description: + "When trying to deserialise an action from a sequence of bytes, we got \ + an action for another multisig contract" + ~pp:(fun ppf (received, expected) -> + Format.fprintf + ppf + "Bad deserialized contract, received %a expected %a." + Contract.pp + received + Contract.pp + expected) + Data_encoding.( + obj1 (req "received_expected" (tup2 Contract.encoding Contract.encoding))) + (function Bad_deserialized_contract b -> Some b | _ -> None) + (fun b -> Bad_deserialized_contract b) ; + register_error_kind + `Permanent + ~id:"Bad deserialized counter" + ~title:"Deserialized counter does not match the stored one" + ~description: + "The byte sequence references a multisig counter that does not match the \ + one currently stored in the given multisig contract" + ~pp:(fun ppf (received, expected) -> + Format.fprintf + ppf + "Bad deserialized counter, received %d expected %d." + received + expected) + Data_encoding.(obj1 (req "received_expected" (tup2 int31 int31))) + (function + | Bad_deserialized_counter (c1, c2) -> Some (Z.to_int c1, Z.to_int c2) + | _ -> None) + (fun (c1, c2) -> Bad_deserialized_counter (Z.of_int c1, Z.of_int c2)) ; + register_error_kind + `Permanent + ~id:"thresholdTooHigh" + ~title:"Given threshold is too high" + ~description: + "The given threshold is higher than the number of keys, this would lead \ + to a frozen multisig contract" + ~pp:(fun ppf (threshold, nkeys) -> + Format.fprintf + ppf + "Threshold too high: %d expected at most %d." + threshold + nkeys) + Data_encoding.(obj1 (req "received_expected" (tup2 int31 int31))) + (function Threshold_too_high (c1, c2) -> Some (c1, c2) | _ -> None) + (fun (c1, c2) -> Threshold_too_high (c1, c2)) ; + register_error_kind + `Permanent + ~id:"nonPositiveThreshold" + ~title:"Given threshold is not positive" + ~description:"A multisig threshold should be a positive number" + ~pp:(fun ppf threshold -> + Format.fprintf ppf "Multisig threshold %d should be positive." threshold) + Data_encoding.(obj1 (req "threshold" int31)) + (function Non_positive_threshold t -> Some t | _ -> None) + (fun t -> Non_positive_threshold t) ; + register_error_kind + `Permanent + ~id:"unsupportedGenericMultisigFeature" + ~title:"Unsupported multisig feature: generic call" + ~description: + "This multisig contract does not feature calling contracts with arguments" + ~pp:(fun ppf arg -> + Format.fprintf + ppf + "This multisig contract can only transfer tokens to contracts of type \ + unit; calling a contract with argument %a is not supported." + Michelson_v1_printer.print_expr + arg) + Data_encoding.(obj1 (req "arg" Script.expr_encoding)) + (function Unsupported_feature_generic_call arg -> Some arg | _ -> None) + (fun arg -> Unsupported_feature_generic_call arg) ; + register_error_kind + `Permanent + ~id:"unsupportedGenericMultisigFeatureTy" + ~title:"Unsupported multisig feature: generic call to non-unit entrypoint" + ~description: + "This multisig contract does not feature calling contracts with arguments" + ~pp:(fun ppf ty -> + Format.fprintf + ppf + "This multisig contract can only transfer tokens to contracts of type \ + unit; calling a contract of type %a is not supported." + Michelson_v1_printer.print_expr + ty) + Data_encoding.(obj1 (req "ty" Script.expr_encoding)) + (function Unsupported_feature_generic_call_ty ty -> Some ty | _ -> None) + (fun ty -> Unsupported_feature_generic_call_ty ty) ; + register_error_kind + `Permanent + ~id:"unsupportedGenericMultisigLambda" + ~title:"Unsupported multisig feature: running lambda" + ~description:"This multisig contract does not feature running lambdas" + ~pp:(fun ppf lam -> + Format.fprintf + ppf + "This multisig contract has a fixed set of actions, it cannot run the \ + following lambda: %s." + lam) + Data_encoding.(obj1 (req "lam" string)) + (function Unsupported_feature_lambda lam -> Some lam | _ -> None) + (fun lam -> Unsupported_feature_lambda lam) ; + register_error_kind + `Permanent + ~id:"illTypedArgumentForMultisig" + ~title:"Ill-typed argument in multi-signed transfer" + ~description: + "The provided argument for a transfer from a multisig contract is \ + ill-typed" + ~pp:(fun ppf (destination, entrypoint, parameter_ty, parameter) -> + Format.fprintf + ppf + "The entrypoint %s of contract %a called from a multisig contract is \ + of type %a; the provided parameter %a is ill-typed." + entrypoint + Contract.pp + destination + Michelson_v1_printer.print_expr + parameter_ty + Michelson_v1_printer.print_expr + parameter) + Data_encoding.( + obj4 + (req "destination" Contract.encoding) + (req "entrypoint" string) + (req "parameter_ty" Script.expr_encoding) + (req "parameter" Script.expr_encoding)) + (function + | Ill_typed_argument (destination, entrypoint, parameter_ty, parameter) -> + Some (destination, entrypoint, parameter_ty, parameter) + | _ -> None) + (fun (destination, entrypoint, parameter_ty, parameter) -> + Ill_typed_argument (destination, entrypoint, parameter_ty, parameter)) ; + register_error_kind + `Permanent + ~id:"illTypedLambdaForMultisig" + ~title:"Ill-typed lambda for multi-signed transfer" + ~description: + "The provided lambda for a transfer from a multisig contract is ill-typed" + ~pp:(fun ppf (lam, exp) -> + Format.fprintf + ppf + "The provided lambda %a for multisig contract is ill-typed; %a is \ + expected." + Michelson_v1_printer.print_expr + lam + Michelson_v1_printer.print_expr + exp) + Data_encoding.( + obj2 (req "lam" Script.expr_encoding) (req "exp" Script.expr_encoding)) + (function Ill_typed_lambda (lam, exp) -> Some (lam, exp) | _ -> None) + (fun (lam, exp) -> Ill_typed_lambda (lam, exp)) + +(* The multisig contract script written by Arthur Breitman + https://github.com/murbard/smart-contracts/blob/abdb582d8f1fe7ba7eb15975867d8862cb70acfe/multisig/michelson/generic.tz *) +let multisig_script_string = + {| +parameter (or (unit %default) + (pair %main + (pair :payload + (nat %counter) # counter, used to prevent replay attacks + (or :action # payload to sign, represents the requested action + (lambda %operation unit (list operation)) + (pair %change_keys # change the keys controlling the multisig + (nat %threshold) # new threshold + (list %keys key)))) # new list of keys + (list %sigs (option signature)))); # signatures + +storage (pair (nat %stored_counter) (pair (nat %threshold) (list %keys key))) ; + +code + { + UNPAIR ; + IF_LEFT + { # Default entry point: do nothing + # This entry point can be used to send tokens to this contract + DROP ; NIL operation ; PAIR } + { # Main entry point + # Assert no token was sent: + # to send tokens, the default entry point should be used + PUSH mutez 0 ; AMOUNT ; ASSERT_CMPEQ ; + SWAP ; DUP ; DIP { SWAP } ; + DIP + { + UNPAIR ; + # pair the payload with the current contract address, to ensure signatures + # can't be replayed accross different contracts if a key is reused. + DUP ; SELF ; ADDRESS ; CHAIN_ID ; PAIR ; PAIR ; + PACK ; # form the binary payload that we expect to be signed + DIP { UNPAIR @counter ; DIP { SWAP } } ; SWAP + } ; + + # Check that the counters match + UNPAIR @stored_counter; DIP { SWAP }; + ASSERT_CMPEQ ; + + # Compute the number of valid signatures + DIP { SWAP } ; UNPAIR @threshold @keys; + DIP + { + # Running count of valid signatures + PUSH @valid nat 0; SWAP ; + ITER + { + DIP { SWAP } ; SWAP ; + IF_CONS + { + IF_SOME + { SWAP ; + DIP + { + SWAP ; DIIP { DUUP } ; + # Checks signatures, fails if invalid + { DUUUP; DIP {CHECK_SIGNATURE}; SWAP; IF {DROP} {FAILWITH} }; + PUSH nat 1 ; ADD @valid } } + { SWAP ; DROP } + } + { + # There were fewer signatures in the list + # than keys. Not all signatures must be present, but + # they should be marked as absent using the option type. + FAIL + } ; + SWAP + } + } ; + # Assert that the threshold is less than or equal to the + # number of valid signatures. + ASSERT_CMPLE ; + # Assert no unchecked signature remains + IF_CONS {FAIL} {} ; + DROP ; + + # Increment counter and place in storage + DIP { UNPAIR ; PUSH nat 1 ; ADD @new_counter ; PAIR} ; + + # We have now handled the signature verification part, + # produce the operation requested by the signers. + IF_LEFT + { # Get operation + UNIT ; EXEC + } + { + # Change set of signatures + DIP { CAR } ; SWAP ; PAIR ; NIL operation + }; + PAIR } + } +|} + +(* Client_proto_context.originate expects the contract script as a Script.expr *) +let multisig_script : Script.expr = + Michelson_v1_parser.parse_toplevel ?check:(Some true) multisig_script_string + |> Tezos_micheline.Micheline_parser.no_parsing_error + |> function + | Error _ -> + assert false + (* This is a top level assertion, it is asserted when the client's process runs. *) + | Ok parsing_result -> parsing_result.Michelson_v1_parser.expanded + +let multisig_script_hash = + let bytes = + Data_encoding.Binary.to_bytes_exn Script.expr_encoding multisig_script + in + Script_expr_hash.hash_bytes [bytes] + +(* The previous multisig script is the only one that the client can + originate but the client knows how to interact with several + versions of the multisig contract. For each version, the description + indicates which features are available and how to interact with + the contract. *) + +type multisig_contract_description = { + hash : Script_expr_hash.t; + (* The hash of the contract script *) + requires_chain_id : bool; + (* The signatures should contain the chain identifier *) + main_entrypoint : string option; + (* name of the main entrypoint of the multisig contract, None means use the default entrypoint *) + generic : bool; + (* False means that the contract uses a custom action type, true + means that the contract expects the action as a (lambda unit + (list operation)). *) +} + +(* List of known multisig contracts hashes with their kinds *) +let known_multisig_contracts : multisig_contract_description list = + [ + { + (* First supported version of the generic multisig contract. Supports incoming + transfers from unauthenticated senders and outgoing transfers of + arbitrary operation lists. + + See docs/user/multisig.rst for more details. *) + hash = multisig_script_hash; + requires_chain_id = true; + main_entrypoint = Some "main"; + generic = true; + }; + { + (* Fourth supported version of the legacy multisig contract. This script is + functionally equivalent to the third version but uses the [DUP 2] + instruction introduced in Edo instead of the macro for [DIG 2; DUP; DUG 3]. *) + hash = + Script_expr_hash.of_b58check_exn + "exprutz4BVGJ3Qms6qjmqvUF8sEk27H1cfqhRT17qpTdhEs5hEjbWm"; + requires_chain_id = true; + main_entrypoint = None; + generic = false; + }; + { + (* Third supported version of the legacy multisig contract. This script is + functionally equivalent to the second version but uses the [DIP 2] + instruction introduced in Babylon instead of the [DIIP] macro. *) + hash = + Script_expr_hash.of_b58check_exn + "exprumpS39YZd26Cn4kyKUK5ezTR3at838iGWg7i6uETv8enDeAnfb"; + requires_chain_id = true; + main_entrypoint = None; + generic = false; + }; + { + (* Second supported version of the legacy multisig contract. This script + is the one resulting from the stitching of the Babylon protocol, the + only difference with the first version is that the chain id is part of + the data to sign. *) + hash = + Script_expr_hash.of_b58check_exn + "exprtw1v4KvQN414oEXdGuA1U3eQizuCdS8cipx8QGK8TbNLRwc3qL"; + requires_chain_id = true; + main_entrypoint = None; + generic = false; + }; + { + (* First supported version of the legacy multisig contract. This script should not + be used anymore because it is subject to a small replay attack: when + the test chain is forked both instances have the same address and + counter so whatever happens on the test chain can be replayed on the + main chain. The script has been fixed during the activation of the + Babylon protocol. *) + hash = + Script_expr_hash.of_b58check_exn + "expru4Ju9kf6MQ216FxUEsb9P6j8UhkPtsFcYP8r9XhQSRb47FZGfM"; + requires_chain_id = false; + main_entrypoint = None; + generic = false; + }; + ] + +let known_multisig_hashes = + List.map (fun descr -> descr.hash) known_multisig_contracts + +let check_multisig_script_hash hash : + multisig_contract_description tzresult Lwt.t = + match + List.find_opt + (fun d -> Script_expr_hash.(d.hash = hash)) + known_multisig_contracts + with + | None -> fail (Not_a_supported_multisig_contract hash) + | Some d -> return d + +(* Returns [Ok ()] if [~contract] is an originated contract whose code + is [multisig_script] *) +let check_multisig_contract (cctxt : #Protocol_client_context.full) ~chain + ~block contract = + Client_proto_context.get_script_hash cctxt ~chain ~block contract + >>=? function + | None -> fail (Contract_has_no_script contract) + | Some hash -> check_multisig_script_hash hash + +(* Some Michelson building functions, specific to the needs of the multisig + interface.*) + +(* The type of the lambdas consumed by the generic script *) +let lambda_action_t ~loc = lambda_t ~loc (unit_t ~loc) (operations_t ~loc) + +(* Conversion functions from common types to Script_expr using the optimized representation *) +let mutez ~loc (amount : Tez.t) = int ~loc (Z.of_int64 (Tez.to_mutez amount)) + +let optimized_key_hash ~loc (key_hash : Signature.Public_key_hash.t) = + bytes + ~loc + (Data_encoding.Binary.to_bytes_exn + Signature.Public_key_hash.encoding + key_hash) + +let optimized_address ~loc ~(address : Contract.t) ~(entrypoint : string) = + let entrypoint = match entrypoint with "default" -> "" | name -> name in + bytes + ~loc + (Data_encoding.Binary.to_bytes_exn + Data_encoding.(tup2 Contract.encoding Variable.string) + (address, entrypoint)) + +let optimized_key ~loc (key : Signature.Public_key.t) = + bytes + ~loc + (Data_encoding.Binary.to_bytes_exn Signature.Public_key.encoding key) + +(** * Actions *) + +type multisig_action = + | Transfer of { + amount : Tez.t; + destination : Contract.t; + entrypoint : string; + parameter_type : Script.expr; + parameter : Script.expr; + } + | Change_delegate of public_key_hash option + | Lambda of Script.expr + | Change_keys of Z.t * public_key list + +let action_to_expr_generic ~loc = function + | Transfer {amount; destination; entrypoint; parameter_type; parameter} -> ( + match Contract.is_implicit destination with + | Some destination -> + lambda_from_string + @@ Managed_contract.build_lambda_for_transfer_to_implicit + ~destination + ~amount + >|? left ~loc + | None -> + lambda_from_string + @@ Managed_contract.build_lambda_for_transfer_to_originated + ~destination + ~entrypoint + ~parameter_type + ~parameter + ~amount + >|? left ~loc) + | Lambda code -> + Error_monad.ok Tezos_micheline.Micheline.(left ~loc (root code)) + | Change_delegate delegate -> + lambda_from_string + @@ Managed_contract.build_lambda_for_set_delegate ~delegate + >|? left ~loc + | Change_keys (threshold, keys) -> + let optimized_keys = seq ~loc (List.map (optimized_key ~loc) keys) in + let expr = right ~loc (pair ~loc (int ~loc threshold) optimized_keys) in + Error_monad.ok expr + +let action_to_expr_legacy ~loc = function + | Transfer {amount; destination; entrypoint; parameter_type; parameter} -> + if parameter <> Tezos_micheline.Micheline.strip_locations (unit ~loc:0) + then Error_monad.error @@ Unsupported_feature_generic_call parameter + else if + parameter_type + <> Tezos_micheline.Micheline.strip_locations (unit_t ~loc:0) + then + Error_monad.error @@ Unsupported_feature_generic_call_ty parameter_type + else + Error_monad.ok + @@ left + ~loc + (pair + ~loc + (mutez ~loc amount) + (optimized_address ~loc ~address:destination ~entrypoint)) + | Lambda _ -> Error_monad.error @@ Unsupported_feature_lambda "" + | Change_delegate delegate -> + let delegate_opt = + match delegate with + | None -> none ~loc () + | Some delegate -> some ~loc (optimized_key_hash ~loc delegate) + in + Error_monad.ok @@ right ~loc (left ~loc delegate_opt) + | Change_keys (threshold, keys) -> + let optimized_keys = seq ~loc (List.map (optimized_key ~loc) keys) in + let expr = right ~loc (pair ~loc (int ~loc threshold) optimized_keys) in + Error_monad.ok (right ~loc expr) + +let action_to_expr ~loc ~generic action = + if generic then action_to_expr_generic ~loc action + else action_to_expr_legacy ~loc action + +let action_of_expr_generic e = + let fail () = + Error_monad.fail + (Action_deserialisation_error + (Tezos_micheline.Micheline.strip_locations e)) + in + match e with + | Tezos_micheline.Micheline.Prim (_, Script.D_Left, [lam], []) -> + return @@ Lambda (Tezos_micheline.Micheline.strip_locations lam) + | Tezos_micheline.Micheline.Prim + ( _, + Script.D_Right, + [ + Tezos_micheline.Micheline.Prim + ( _, + Script.D_Pair, + [ + Tezos_micheline.Micheline.Int (_, threshold); + Tezos_micheline.Micheline.Seq (_, key_bytes); + ], + [] ); + ], + [] ) -> + List.map_es + (function + | Tezos_micheline.Micheline.Bytes (_, s) -> + return + @@ Data_encoding.Binary.of_bytes_exn + Signature.Public_key.encoding + s + | _ -> fail ()) + key_bytes + >>=? fun keys -> return @@ Change_keys (threshold, keys) + | _ -> fail () + +let action_of_expr_not_generic e = + let fail () = + Error_monad.fail + (Action_deserialisation_error + (Tezos_micheline.Micheline.strip_locations e)) + in + match e with + | Tezos_micheline.Micheline.Prim + ( _, + Script.D_Left, + [ + Tezos_micheline.Micheline.Prim + ( _, + Script.D_Pair, + [ + Tezos_micheline.Micheline.Int (_, i); + Tezos_micheline.Micheline.Bytes (_, s); + ], + [] ); + ], + [] ) -> ( + match Tez.of_mutez (Z.to_int64 i) with + | None -> fail () + | Some amount -> + return + @@ Transfer + { + amount; + destination = + Data_encoding.Binary.of_bytes_exn Contract.encoding s; + entrypoint = "default"; + parameter_type = + Tezos_micheline.Micheline.strip_locations @@ unit_t ~loc:0; + parameter = + Tezos_micheline.Micheline.strip_locations @@ unit ~loc:0; + }) + | Tezos_micheline.Micheline.Prim + ( _, + Script.D_Right, + [ + Tezos_micheline.Micheline.Prim + ( _, + Script.D_Left, + [Tezos_micheline.Micheline.Prim (_, Script.D_None, [], [])], + [] ); + ], + [] ) -> + return @@ Change_delegate None + | Tezos_micheline.Micheline.Prim + ( _, + Script.D_Right, + [ + Tezos_micheline.Micheline.Prim + ( _, + Script.D_Left, + [ + Tezos_micheline.Micheline.Prim + ( _, + Script.D_Some, + [Tezos_micheline.Micheline.Bytes (_, s)], + [] ); + ], + [] ); + ], + [] ) -> + return + @@ Change_delegate + (Some + (Data_encoding.Binary.of_bytes_exn + Signature.Public_key_hash.encoding + s)) + | Tezos_micheline.Micheline.Prim + ( _, + Script.D_Right, + [ + Tezos_micheline.Micheline.Prim + ( _, + Script.D_Right, + [ + Tezos_micheline.Micheline.Prim + ( _, + Script.D_Pair, + [ + Tezos_micheline.Micheline.Int (_, threshold); + Tezos_micheline.Micheline.Seq (_, key_bytes); + ], + [] ); + ], + [] ); + ], + [] ) -> + List.map_es + (function + | Tezos_micheline.Micheline.Bytes (_, s) -> + return + @@ Data_encoding.Binary.of_bytes_exn + Signature.Public_key.encoding + s + | _ -> fail ()) + key_bytes + >>=? fun keys -> return @@ Change_keys (threshold, keys) + | _ -> fail () + +let action_of_expr ~generic = + if generic then action_of_expr_generic else action_of_expr_not_generic + +type key_list = Signature.Public_key.t list + +(* The relevant information that we can get about a multisig smart contract *) +type multisig_contract_information = { + counter : Z.t; + threshold : Z.t; + keys : key_list; +} + +let multisig_get_information (cctxt : #Protocol_client_context.full) ~chain + ~block contract = + let open Client_proto_context in + let open Tezos_micheline.Micheline in + get_storage cctxt ~chain ~block ~unparsing_mode:Readable contract + >>=? fun storage_opt -> + match storage_opt with + | None -> fail (Contract_has_no_storage contract) + | Some storage -> ( + match root storage with + | Prim + ( _, + D_Pair, + [Int (_, counter); Int (_, threshold); Seq (_, key_nodes)], + _ ) -> + List.map_es + (function + | String (_, key_str) -> + return @@ Signature.Public_key.of_b58check_exn key_str + | _ -> fail (Contract_has_unexpected_storage contract)) + key_nodes + >>=? fun keys -> return {counter; threshold; keys} + | _ -> fail (Contract_has_unexpected_storage contract)) + +let multisig_create_storage ~counter ~threshold ~keys () : + Script.expr tzresult Lwt.t = + let loc = Tezos_micheline.Micheline_parser.location_zero in + let open Tezos_micheline.Micheline in + List.map_es + (fun key -> + let key_str = Signature.Public_key.to_b58check key in + return (String (loc, key_str))) + keys + >>=? fun l -> + return @@ strip_locations + @@ pair ~loc (int ~loc counter) (pair ~loc (int ~loc threshold) (seq ~loc l)) + +(* Client_proto_context.originate expects the initial storage as a string *) +let multisig_storage_string ~counter ~threshold ~keys () = + multisig_create_storage ~counter ~threshold ~keys () >>=? fun expr -> + return @@ Format.asprintf "%a" Michelson_v1_printer.print_expr expr + +let multisig_create_param ~counter ~generic ~action ~optional_signatures () : + Script.expr tzresult Lwt.t = + let loc = 0 in + let open Tezos_micheline.Micheline in + List.map_es + (fun sig_opt -> + match sig_opt with + | None -> return @@ none ~loc () + | Some signature -> + return @@ some ~loc (String (loc, Signature.to_b58check signature))) + optional_signatures + >>=? fun l -> + Lwt.return @@ action_to_expr ~loc:0 ~generic action >>=? fun expr -> + return @@ strip_locations + @@ pair ~loc (pair ~loc (int ~loc counter) expr) (Seq (loc, l)) + +let multisig_param_string ~counter ~action ~optional_signatures ~generic () = + multisig_create_param ~counter ~action ~optional_signatures ~generic () + >>=? fun expr -> + return @@ Format.asprintf "%a" Michelson_v1_printer.print_expr expr + +let get_contract_address_maybe_chain_id ~descr ~loc ~chain_id contract = + let address = + bytes ~loc (Data_encoding.Binary.to_bytes_exn Contract.encoding contract) + in + if descr.requires_chain_id then + let chain_id_bytes = + bytes ~loc (Data_encoding.Binary.to_bytes_exn Chain_id.encoding chain_id) + in + pair ~loc chain_id_bytes address + else address + +let multisig_bytes ~counter ~action ~contract ~chain_id ~descr () = + let loc = 0 in + Lwt.return @@ action_to_expr ~loc ~generic:descr.generic action + >>=? fun expr -> + let triple = + pair + ~loc + (get_contract_address_maybe_chain_id ~descr ~loc ~chain_id contract) + (pair ~loc (int ~loc counter) expr) + in + let bytes = + Data_encoding.Binary.to_bytes_exn Script.expr_encoding + @@ Tezos_micheline.Micheline.strip_locations @@ triple + in + return @@ Bytes.cat (Bytes.of_string "\005") bytes + +let check_threshold ~threshold ~keys () = + let nkeys = List.length keys in + let threshold = Z.to_int threshold in + if Compare.Int.(List.length keys < threshold) then + fail (Threshold_too_high (threshold, nkeys)) + else if Compare.Int.(threshold <= 0) then + fail (Non_positive_threshold threshold) + else return_unit + +let originate_multisig (cctxt : #Protocol_client_context.full) ~chain ~block + ?confirmations ?dry_run ?branch ?fee ?gas_limit ?storage_limit + ?verbose_signing ~delegate ~threshold ~keys ~balance ~source ~src_pk ~src_sk + ~fee_parameter () = + multisig_storage_string ~counter:Z.zero ~threshold ~keys () + >>=? fun initial_storage -> + check_threshold ~threshold ~keys () >>=? fun () -> + Client_proto_context.originate_contract + cctxt + ~chain + ~block + ?branch + ?confirmations + ?dry_run + ?fee + ?gas_limit + ?storage_limit + ?verbose_signing + ~delegate + ~initial_storage + ~balance + ~source + ~src_pk + ~src_sk + ~code:multisig_script + ~fee_parameter + () + +type multisig_prepared_action = { + bytes : Bytes.t; + threshold : Z.t; + keys : public_key list; + counter : Z.t; + entrypoint : string option; + generic : bool; +} + +let check_parameter_type (cctxt : #Protocol_client_context.full) ?gas ?legacy + ~destination ~entrypoint ~parameter_type ~parameter () = + trace + (Ill_typed_argument (destination, entrypoint, parameter_type, parameter)) + @@ Plugin.RPC.Scripts.typecheck_data + cctxt + (cctxt#chain, cctxt#block) + ~data:parameter + ~ty:parameter_type + ?gas + ?legacy + >>=? fun _ -> return_unit + +let check_action (cctxt : #Protocol_client_context.full) ~action ~balance ?gas + ?legacy () = + match action with + | Change_keys (threshold, keys) -> + check_threshold ~threshold ~keys () >>=? fun () -> return_unit + | Transfer {amount; destination; entrypoint; parameter_type; parameter} -> + check_parameter_type + cctxt + ~destination + ~entrypoint + ~parameter_type + ~parameter + () + >>=? fun () -> + if Tez.(amount > balance) then + (* This is warning only because the contract can be filled + before sending the signatures or even in the same + transaction *) + Format.eprintf + "Transferred amount is bigger than current multisig balance" ; + return_unit + | Lambda code -> + let action_t = + Tezos_micheline.Micheline.strip_locations (lambda_action_t ~loc:0) + in + trace (Ill_typed_lambda (code, action_t)) + @@ Plugin.RPC.Scripts.typecheck_data + cctxt + (cctxt#chain, cctxt#block) + ~data:code + ~ty:action_t + ?gas + ?legacy + >>=? fun _remaining_gas -> return_unit + | _ -> return_unit + +let prepare_multisig_transaction (cctxt : #Protocol_client_context.full) ~chain + ~block ~multisig_contract ~action () = + let contract = multisig_contract in + check_multisig_contract cctxt ~chain ~block contract >>=? fun descr -> + multisig_get_information cctxt ~chain ~block contract + >>=? fun {counter; threshold; keys} -> + Chain_services.chain_id cctxt ~chain () >>=? fun chain_id -> + multisig_bytes ~counter ~action ~contract ~descr ~chain_id () + >>=? fun bytes -> + Client_proto_context.get_balance + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + contract + >>=? fun balance -> + check_action cctxt ~action ~balance () >>=? fun () -> + return + { + bytes; + threshold; + keys; + counter; + entrypoint = descr.main_entrypoint; + generic = descr.generic; + } + +let check_multisig_signatures ~bytes ~threshold ~keys signatures = + let key_array = Array.of_list keys in + let nkeys = Array.length key_array in + let opt_sigs_arr = Array.make nkeys None in + let matching_key_found = ref false in + let check_signature_against_key_number signature i key = + if Signature.check key signature bytes then ( + matching_key_found := true ; + opt_sigs_arr.(i) <- Some signature) + in + List.iter_ep + (fun signature -> + matching_key_found := false ; + List.iteri (check_signature_against_key_number signature) keys ; + fail_unless !matching_key_found (Invalid_signature signature)) + signatures + >>=? fun () -> + let opt_sigs = Array.to_list opt_sigs_arr in + let signature_count = + List.fold_left + (fun n sig_opt -> match sig_opt with Some _ -> n + 1 | None -> n) + 0 + opt_sigs + in + let threshold_int = Z.to_int threshold in + if signature_count >= threshold_int then return opt_sigs + else fail (Not_enough_signatures (threshold_int, signature_count)) + +let call_multisig (cctxt : #Protocol_client_context.full) ~chain ~block + ?confirmations ?dry_run ?verbose_signing ?branch ~source ~src_pk ~src_sk + ~multisig_contract ~action ~signatures ~amount ?fee ?gas_limit + ?storage_limit ?counter ~fee_parameter () = + prepare_multisig_transaction cctxt ~chain ~block ~multisig_contract ~action () + >>=? fun { + bytes; + threshold; + keys; + counter = stored_counter; + entrypoint; + generic; + } -> + check_multisig_signatures ~bytes ~threshold ~keys signatures + >>=? fun optional_signatures -> + multisig_param_string + ~counter:stored_counter + ~action + ~optional_signatures + ~generic + () + >>=? fun arg -> + Client_proto_context.transfer + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?branch + ~source + ~src_pk + ~src_sk + ~destination:multisig_contract + ?entrypoint + ~arg + ~amount + ?fee + ?gas_limit + ?storage_limit + ?counter + ~fee_parameter + ?verbose_signing + () + +let action_of_bytes ~multisig_contract ~stored_counter ~descr ~chain_id bytes = + if + Compare.Int.(Bytes.length bytes >= 1) + && Compare.Int.(TzEndian.get_uint8 bytes 0 = 0x05) + then + let nbytes = Bytes.sub bytes 1 (Bytes.length bytes - 1) in + match Data_encoding.Binary.of_bytes_opt Script.expr_encoding nbytes with + | None -> fail (Bytes_deserialisation_error bytes) + | Some e -> ( + match Tezos_micheline.Micheline.root e with + | Tezos_micheline.Micheline.Prim + ( _, + Script.D_Pair, + [ + Tezos_micheline.Micheline.Bytes (_, contract_bytes); + Tezos_micheline.Micheline.Prim + ( _, + Script.D_Pair, + [Tezos_micheline.Micheline.Int (_, counter); e], + [] ); + ], + [] ) + when not descr.requires_chain_id -> + let contract = + Data_encoding.Binary.of_bytes_exn Contract.encoding contract_bytes + in + if counter = stored_counter then + if Contract.(multisig_contract = contract) then + action_of_expr ~generic:descr.generic e + else + fail (Bad_deserialized_contract (contract, multisig_contract)) + else fail (Bad_deserialized_counter (counter, stored_counter)) + | Tezos_micheline.Micheline.Prim + ( _, + Script.D_Pair, + [ + Tezos_micheline.Micheline.Prim + ( _, + Script.D_Pair, + [ + Tezos_micheline.Micheline.Bytes (_, chain_id_bytes); + Tezos_micheline.Micheline.Bytes (_, contract_bytes); + ], + [] ); + Tezos_micheline.Micheline.Prim + ( _, + Script.D_Pair, + [Tezos_micheline.Micheline.Int (_, counter); e], + [] ); + ], + [] ) + when descr.requires_chain_id -> + let contract = + Data_encoding.Binary.of_bytes_exn Contract.encoding contract_bytes + in + let cid = + Data_encoding.Binary.of_bytes_exn Chain_id.encoding chain_id_bytes + in + if counter = stored_counter then + if multisig_contract = contract && chain_id = cid then + action_of_expr ~generic:descr.generic e + else + fail (Bad_deserialized_contract (contract, multisig_contract)) + else fail (Bad_deserialized_counter (counter, stored_counter)) + | _ -> fail (Bytes_deserialisation_error bytes)) + else fail (Bytes_deserialisation_error bytes) + +let call_multisig_on_bytes (cctxt : #Protocol_client_context.full) ~chain ~block + ?confirmations ?dry_run ?verbose_signing ?branch ~source ~src_pk ~src_sk + ~multisig_contract ~bytes ~signatures ~amount ?fee ?gas_limit ?storage_limit + ?counter ~fee_parameter () = + multisig_get_information cctxt ~chain ~block multisig_contract + >>=? fun info -> + check_multisig_contract cctxt ~chain ~block multisig_contract + >>=? fun descr -> + Chain_services.chain_id cctxt ~chain () >>=? fun chain_id -> + action_of_bytes + ~multisig_contract + ~stored_counter:info.counter + ~chain_id + ~descr + bytes + >>=? fun action -> + call_multisig + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?branch + ~source + ~src_pk + ~src_sk + ~multisig_contract + ~action + ~signatures + ~amount + ?fee + ?gas_limit + ?storage_limit + ?counter + ~fee_parameter + ?verbose_signing + () diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_multisig.mli b/src/proto_011_PtHangzH/lib_client/client_proto_multisig.mli new file mode 100644 index 000000000000..ad4a6306d60c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_multisig.mli @@ -0,0 +1,150 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Protocol_client_context + +(* The script of the recommended version of the multisig contract. + This is the script originated by [originate_multisig]. *) +val multisig_script : Script.expr + +(* A description of the possible actions that a multisig contract can run. *) +type multisig_action = + | Transfer of { + amount : Tez.t; + destination : Contract.t; + entrypoint : string; + parameter_type : Script.expr; + parameter : Script.expr; + } + | Change_delegate of public_key_hash option + | Lambda of Script.expr + | Change_keys of Z.t * public_key list + +(* A prepared action is the byte sequence that needs to be signed to run the + action together with some data that can be useful for the user and to call + the multisig contracts once enough signatures are provided. *) +type multisig_prepared_action = { + (* The sequence of bytes to be signed. *) + bytes : Bytes.t; + (* Information reported to the user so that she knows who can sign and how + many signatures are required. *) + threshold : Z.t; + keys : public_key list; + (* Information needed to execute the action ones enough signatures have been + gathered. *) + counter : Z.t; + entrypoint : string option; + generic : bool; +} + +(* The client will refuse to interact with a multisig contract if the hash of + its script is not in this list. *) +val known_multisig_hashes : Script_expr_hash.t list + +(* Originate a new multisig contract *) +val originate_multisig : + full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?branch:int -> + ?fee:Tez.t -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + ?verbose_signing:bool -> + delegate:public_key_hash option -> + threshold:Z.t -> + keys:public_key list -> + balance:Tez.t -> + source:public_key_hash -> + src_pk:public_key -> + src_sk:Client_keys.sk_uri -> + fee_parameter:Injection.fee_parameter -> + unit -> + (Kind.origination Kind.manager Injection.result * Contract.t) tzresult Lwt.t + +(* Prepare an action, see [multisig_prepared_action]. *) +val prepare_multisig_transaction : + full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + multisig_contract:Contract.t -> + action:multisig_action -> + unit -> + multisig_prepared_action tzresult Lwt.t + +(* Call a multisig contract, requesting it to run an action. *) +val call_multisig : + full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?branch:int -> + source:public_key_hash -> + src_pk:public_key -> + src_sk:Client_keys.sk_uri -> + multisig_contract:Contract.t -> + action:multisig_action -> + signatures:Signature.t list -> + amount:Tez.t -> + ?fee:Tez.t -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + ?counter:Z.t -> + fee_parameter:Injection.fee_parameter -> + unit -> + (Kind.transaction Kind.manager Injection.result * Contract.t list) tzresult + Lwt.t + +(* Same as [call_multisig] but the action to be performed is reconstructed from + the byte sequence that was signed. *) +val call_multisig_on_bytes : + full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?branch:int -> + source:public_key_hash -> + src_pk:public_key -> + src_sk:Client_keys.sk_uri -> + multisig_contract:Contract.t -> + bytes:Bytes.t -> + signatures:Signature.t list -> + amount:Tez.t -> + ?fee:Tez.t -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + ?counter:Z.t -> + fee_parameter:Injection.fee_parameter -> + unit -> + (Kind.transaction Kind.manager Injection.result * Contract.t list) tzresult + Lwt.t diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_programs.ml b/src/proto_011_PtHangzH/lib_client/client_proto_programs.ml new file mode 100644 index 000000000000..32fde70f2852 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_programs.ml @@ -0,0 +1,296 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Tezos_micheline +open Michelson_v1_printer + +module Program = Client_aliases.Alias (struct + type t = Michelson_v1_parser.parsed Micheline_parser.parsing_result + + include Compare.Make (struct + type nonrec t = t + + let compare = Micheline_parser.compare Michelson_v1_parser.compare_parsed + end) + + let encoding = + Data_encoding.conv + (fun ({Michelson_v1_parser.source; _}, _) -> source) + (fun source -> Michelson_v1_parser.parse_toplevel source) + Data_encoding.string + + let of_source source = return (Michelson_v1_parser.parse_toplevel source) + + let to_source ({Michelson_v1_parser.source; _}, _) = return source + + let name = "script" +end) + +let print_errors ?parsed (cctxt : #Client_context.printer) errs ~show_source = + cctxt#warning + "%a" + (Michelson_v1_error_reporter.report_errors + ~details:false + ?parsed + ~show_source) + errs + >>= fun () -> + cctxt#error "error running script" >>= fun () -> return_unit + +let print_view_result (cctxt : #Client_context.printer) = function + | Ok expr -> cctxt#message "%a" print_expr expr >>= fun () -> return_unit + | Error errs -> print_errors cctxt ~show_source:false errs + +let print_run_result (cctxt : #Client_context.printer) ~show_source ~parsed = + function + | Ok (storage, operations, maybe_lazy_storage_diff) -> + cctxt#message + "@[@[storage@,\ + %a@]@,\ + @[emitted operations@,\ + %a@]@,\ + @[big_map diff@,\ + %a@]@]@." + print_expr + storage + (Format.pp_print_list Operation_result.pp_internal_operation) + operations + (fun ppf -> function + | None -> () + | Some diff -> print_big_map_diff ppf diff) + maybe_lazy_storage_diff + >>= fun () -> return_unit + | Error errs -> print_errors cctxt errs ~show_source ~parsed + +let print_trace_result (cctxt : #Client_context.printer) ~show_source ~parsed = + function + | Ok (storage, operations, trace, maybe_lazy_storage_diff) -> + cctxt#message + "@[@[storage@,\ + %a@]@,\ + @[emitted operations@,\ + %a@]@,\ + @[big_map diff@,\ + %a@]@,\ + @[trace@,\ + %a@]@]@." + print_expr + storage + (Format.pp_print_list Operation_result.pp_internal_operation) + operations + (fun ppf -> function + | None -> () + | Some diff -> print_big_map_diff ppf diff) + maybe_lazy_storage_diff + print_execution_trace + trace + >>= fun () -> return_unit + | Error errs -> print_errors cctxt errs ~show_source ~parsed + +let run_view (cctxt : #Protocol_client_context.rpc_context) + ~(chain : Chain_services.chain) ~block ~(contract : Contract.t) ~entrypoint + ~(input : Michelson_v1_parser.parsed) + ~(unparsing_mode : Script_ir_translator.unparsing_mode) ?source ?payer ?gas + () = + Chain_services.chain_id cctxt ~chain () >>=? fun chain_id -> + Plugin.RPC.Scripts.run_view + cctxt + (chain, block) + ?gas + ~contract + ~entrypoint + ~input:input.expanded + ~chain_id + ?source + ?payer + ~unparsing_mode + +let run (cctxt : #Protocol_client_context.rpc_context) + ~(chain : Chain_services.chain) ~block ?(amount = Tez.fifty_cents) ~balance + ~(program : Michelson_v1_parser.parsed) + ~(storage : Michelson_v1_parser.parsed) + ~(input : Michelson_v1_parser.parsed) + ~(unparsing_mode : Script_ir_translator.unparsing_mode) ?source ?payer ?gas + ?entrypoint () = + Chain_services.chain_id cctxt ~chain () >>=? fun chain_id -> + Plugin.RPC.Scripts.run_code + cctxt + (chain, block) + ?gas + ?entrypoint + ~unparsing_mode + ~script:program.expanded + ~storage:storage.expanded + ~input:input.expanded + ~amount + ~balance + ~chain_id + ~source + ~payer + +let trace (cctxt : #Protocol_client_context.rpc_context) + ~(chain : Chain_services.chain) ~block ?(amount = Tez.fifty_cents) ~balance + ~(program : Michelson_v1_parser.parsed) + ~(storage : Michelson_v1_parser.parsed) + ~(input : Michelson_v1_parser.parsed) + ~(unparsing_mode : Script_ir_translator.unparsing_mode) ?source ?payer ?gas + ?entrypoint () = + Chain_services.chain_id cctxt ~chain () >>=? fun chain_id -> + Plugin.RPC.Scripts.trace_code + cctxt + (chain, block) + ?gas + ?entrypoint + ~unparsing_mode + ~script:program.expanded + ~storage:storage.expanded + ~input:input.expanded + ~amount + ~balance + ~chain_id + ~source + ~payer + +let typecheck_data cctxt ~(chain : Chain_services.chain) ~block ?gas ?legacy + ~(data : Michelson_v1_parser.parsed) ~(ty : Michelson_v1_parser.parsed) () = + Plugin.RPC.Scripts.typecheck_data + cctxt + (chain, block) + ?gas + ?legacy + ~data:data.expanded + ~ty:ty.expanded + +let typecheck_program cctxt ~(chain : Chain_services.chain) ~block ?gas ?legacy + (program : Michelson_v1_parser.parsed) = + Plugin.RPC.Scripts.typecheck_code + cctxt + (chain, block) + ?gas + ?legacy + ~script:program.expanded + +let script_size cctxt ~(chain : Chain_services.chain) ~block ?gas ?legacy + ~(program : Michelson_v1_parser.parsed) + ~(storage : Michelson_v1_parser.parsed) () = + Plugin.RPC.Scripts.script_size + cctxt + (chain, block) + ?gas + ?legacy + ~script:program.expanded + ~storage:storage.expanded + +let print_typecheck_result ~emacs ~show_types ~print_source_on_error program res + (cctxt : #Client_context.printer) = + if emacs then + let (type_map, errs, _gas) = + match res with + | Ok (type_map, gas) -> (type_map, [], Some gas) + | Error + (Environment.Ecoproto_error + (Script_tc_errors.Ill_typed_contract (_, type_map)) + :: _ as errs) -> + (type_map, errs, None) + | Error errs -> ([], errs, None) + in + cctxt#message + "(@[(types . %a)@ (errors . %a)@])" + Michelson_v1_emacs.print_type_map + (program, type_map) + Michelson_v1_emacs.report_errors + (program, errs) + >>= fun () -> return_unit + else + match res with + | Ok (type_map, gas) -> + let program = Michelson_v1_printer.inject_types type_map program in + cctxt#message "@[Well typed@,Gas remaining: %a@]" Gas.pp gas + >>= fun () -> + if show_types then + cctxt#message "%a" Micheline_printer.print_expr program >>= fun () -> + return_unit + else return_unit + | Error errs -> + cctxt#warning + "%a" + (Michelson_v1_error_reporter.report_errors + ~details:show_types + ~show_source:print_source_on_error + ~parsed:program) + errs + >>= fun () -> cctxt#error "ill-typed script" + +let entrypoint_type cctxt ~(chain : Chain_services.chain) ~block + (program : Michelson_v1_parser.parsed) ~entrypoint = + Michelson_v1_entrypoints.script_entrypoint_type + cctxt + ~chain + ~block + program.expanded + ~entrypoint + +let print_entrypoint_type (cctxt : #Client_context.printer) ~emacs ?script_name + ~show_source ~parsed ~entrypoint ty = + Michelson_v1_entrypoints.print_entrypoint_type + cctxt + ~entrypoint + ~emacs + ?script_name + ~on_errors:(print_errors cctxt ~show_source ~parsed) + ty + +let list_entrypoints cctxt ~(chain : Chain_services.chain) ~block + (program : Michelson_v1_parser.parsed) = + Michelson_v1_entrypoints.list_entrypoints cctxt ~chain ~block program.expanded + +let print_entrypoints_list (cctxt : #Client_context.printer) ~emacs ?script_name + ~show_source ~parsed ty = + Michelson_v1_entrypoints.print_entrypoints_list + cctxt + ~emacs + ?script_name + ~on_errors:(print_errors cctxt ~show_source ~parsed) + ty + +let list_unreachables cctxt ~(chain : Chain_services.chain) ~block + (program : Michelson_v1_parser.parsed) = + Michelson_v1_entrypoints.list_unreachables + cctxt + ~chain + ~block + program.expanded + +let print_unreachables (cctxt : #Client_context.printer) ~emacs ?script_name + ~show_source ~parsed ty = + Michelson_v1_entrypoints.print_unreachables + cctxt + ~emacs + ?script_name + ~on_errors:(print_errors cctxt ~show_source ~parsed) + ty diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_programs.mli b/src/proto_011_PtHangzH/lib_client/client_proto_programs.mli new file mode 100644 index 000000000000..9d214b490a95 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_programs.mli @@ -0,0 +1,202 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Tezos_micheline + +module Program : + Client_aliases.Alias + with type t = Michelson_v1_parser.parsed Micheline_parser.parsing_result + +val run_view : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + contract:Contract.t -> + entrypoint:string -> + input:Michelson_v1_parser.parsed -> + unparsing_mode:Script_ir_translator.unparsing_mode -> + ?source:Contract.t -> + ?payer:Contract.t -> + ?gas:Gas.Arith.integral -> + unit -> + Script.expr tzresult Lwt.t + +val run : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?amount:Tez.t -> + balance:Tez.t -> + program:Michelson_v1_parser.parsed -> + storage:Michelson_v1_parser.parsed -> + input:Michelson_v1_parser.parsed -> + unparsing_mode:Script_ir_translator.unparsing_mode -> + ?source:Contract.t -> + ?payer:Contract.t -> + ?gas:Gas.Arith.integral -> + ?entrypoint:string -> + unit -> + (Script.expr * packed_internal_operation list * Lazy_storage.diffs option) + tzresult + Lwt.t + +val trace : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?amount:Tez.t -> + balance:Tez.t -> + program:Michelson_v1_parser.parsed -> + storage:Michelson_v1_parser.parsed -> + input:Michelson_v1_parser.parsed -> + unparsing_mode:Script_ir_translator.unparsing_mode -> + ?source:Contract.t -> + ?payer:Contract.t -> + ?gas:Gas.Arith.integral -> + ?entrypoint:string -> + unit -> + (Script.expr + * packed_internal_operation list + * Script_typed_ir.execution_trace + * Lazy_storage.diffs option) + tzresult + Lwt.t + +val print_view_result : + #Client_context.printer -> Script_repr.expr tzresult -> unit tzresult Lwt.t + +val print_run_result : + #Client_context.printer -> + show_source:bool -> + parsed:Michelson_v1_parser.parsed -> + (Script_repr.expr + * packed_internal_operation list + * Lazy_storage.diffs option) + tzresult -> + unit tzresult Lwt.t + +val print_trace_result : + #Client_context.printer -> + show_source:bool -> + parsed:Michelson_v1_parser.parsed -> + (Script_repr.expr + * packed_internal_operation list + * Script_typed_ir.execution_trace + * Lazy_storage.diffs option) + tzresult -> + unit tzresult Lwt.t + +val typecheck_data : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?gas:Gas.Arith.integral -> + ?legacy:bool -> + data:Michelson_v1_parser.parsed -> + ty:Michelson_v1_parser.parsed -> + unit -> + Gas.t tzresult Lwt.t + +val typecheck_program : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?gas:Gas.Arith.integral -> + ?legacy:bool -> + Michelson_v1_parser.parsed -> + (Script_tc_errors.type_map * Gas.t) tzresult Lwt.t + +val print_typecheck_result : + emacs:bool -> + show_types:bool -> + print_source_on_error:bool -> + Michelson_v1_parser.parsed -> + (Script_tc_errors.type_map * Gas.t) tzresult -> + #Client_context.printer -> + unit tzresult Lwt.t + +val script_size : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?gas:Gas.Arith.integral -> + ?legacy:bool -> + program:Michelson_v1_parser.parsed -> + storage:Michelson_v1_parser.parsed -> + unit -> + int tzresult Lwt.t + +val entrypoint_type : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + Michelson_v1_parser.parsed -> + entrypoint:string -> + Script.expr option tzresult Lwt.t + +val print_entrypoint_type : + #Client_context.printer -> + emacs:bool -> + ?script_name:string -> + show_source:bool -> + parsed:Michelson_v1_parser.parsed -> + entrypoint:string -> + Script_repr.expr option tzresult -> + unit tzresult Lwt.t + +val list_entrypoints : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + Michelson_v1_parser.parsed -> + (string * Script.expr) list tzresult Lwt.t + +val print_entrypoints_list : + #Client_context.printer -> + emacs:bool -> + ?script_name:string -> + show_source:bool -> + parsed:Michelson_v1_parser.parsed -> + (string * Script.expr) list tzresult -> + unit tzresult Lwt.t + +val list_unreachables : + #Protocol_client_context.rpc_context -> + chain:Shell_services.chain -> + block:Shell_services.block -> + Michelson_v1_parser.parsed -> + Michelson_v1_primitives.prim list list tzresult Lwt.t + +val print_unreachables : + #Client_context.printer -> + emacs:bool -> + ?script_name:string -> + show_source:bool -> + parsed:Michelson_v1_parser.parsed -> + Michelson_v1_primitives.prim list list tzresult -> + unit tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_utils.ml b/src/proto_011_PtHangzH/lib_client/client_proto_utils.ml new file mode 100644 index 000000000000..27fec54d342a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_utils.ml @@ -0,0 +1,55 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Protocol_client_context + +let to_json_and_bytes branch message = + let op = + ( Environment.Operation.{branch}, + Contents_list (Single (Failing_noop message)) ) + in + let encoding = Operation.unsigned_encoding in + ( Data_encoding.Json.construct encoding op, + Data_encoding.Binary.to_bytes_exn encoding op ) + +let sign_message (cctxt : #full) ~src_sk ~block ~message = + let (json, bytes) = to_json_and_bytes block message in + cctxt#message "signed content: @[%a@]" Data_encoding.Json.pp json + >>= fun () -> + Client_keys.sign cctxt ~watermark:Signature.Generic_operation src_sk bytes + +let check_message (cctxt : #full) ~block ~key_locator ~quiet ~message ~signature + = + let (json, bytes) = to_json_and_bytes block message in + (if quiet then Lwt.return_unit + else cctxt#message "checked content: @[%a@]" Data_encoding.Json.pp json) + >>= fun () -> + Client_keys.check + ~watermark:Signature.Generic_operation + key_locator + signature + bytes diff --git a/src/proto_011_PtHangzH/lib_client/client_proto_utils.mli b/src/proto_011_PtHangzH/lib_client/client_proto_utils.mli new file mode 100644 index 000000000000..c535e4b24ecb --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/client_proto_utils.mli @@ -0,0 +1,40 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val sign_message : + #Protocol_client_context.full -> + src_sk:Client_keys.sk_uri -> + block:Block_hash.t -> + message:string -> + Signature.t tzresult Lwt.t + +val check_message : + #Protocol_client_context.full -> + block:Block_hash.t -> + key_locator:Client_keys.pk_uri -> + quiet:bool -> + message:string -> + signature:Signature.t -> + bool tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_client/dune b/src/proto_011_PtHangzH/lib_client/dune new file mode 100644 index 000000000000..6d02d1916415 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/dune @@ -0,0 +1,24 @@ +(library + (name tezos_client_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-client-011-PtHangzH) + (libraries tezos-base + tezos-protocol-011-PtHangzH + tezos-shell-services + tezos-client-base + tezos-mockup-registration + tezos-proxy + tezos-rpc + tezos-signer-backends + tezos-protocol-011-PtHangzH-parameters + tezos-protocol-plugin-011-PtHangzH) + (inline_tests) + (preprocess (pps ppx_inline_test)) + (library_flags (:standard -linkall)) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_shell_services + -open Tezos_client_base + -open Tezos_protocol_011_PtHangzH + -open Tezos_protocol_plugin_011_PtHangzH + -open Tezos_protocol_011_PtHangzH_parameters + -open Tezos_rpc))) diff --git a/src/proto_011_PtHangzH/lib_client/dune-project b/src/proto_011_PtHangzH/lib_client/dune-project new file mode 100644 index 000000000000..90c61de348f1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(formatting (enabled_for ocaml)) +(name tezos-client-alpha) diff --git a/src/proto_011_PtHangzH/lib_client/injection.ml b/src/proto_011_PtHangzH/lib_client/injection.ml new file mode 100644 index 000000000000..cc4f39b750b0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/injection.ml @@ -0,0 +1,958 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2018 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Apply_results +open Protocol_client_context + +(* Under normal network conditions and an attacker with less + than 33% of stake, an operation can be considered final with + quasi-certainty if there are at least 5 blocks built on top of it. + See Emmy* TZIP for more detailed explanations. *) +let num_confirmation_blocks = 5 + +let get_branch (rpc_config : #Protocol_client_context.full) ~chain + ~(block : Block_services.block) branch = + let branch = Option.value ~default:0 branch in + (* TODO export parameter *) + (match block with + | `Head n -> return (`Head (n + branch)) + | `Hash (h, n) -> return (`Hash (h, n + branch)) + | `Alias (a, n) -> return (`Alias (a, n)) + | `Genesis -> return `Genesis + | `Level i -> return (`Level i)) + >>=? fun block -> + Shell_services.Blocks.hash rpc_config ~chain ~block () >>=? fun hash -> + Shell_services.Chain.chain_id rpc_config ~chain () >>=? fun chain_id -> + return (chain_id, hash) + +type 'kind preapply_result = + Operation_hash.t * 'kind operation * 'kind operation_metadata + +type 'kind result_list = + Operation_hash.t * 'kind contents_list * 'kind contents_result_list + +type 'kind result = Operation_hash.t * 'kind contents * 'kind contents_result + +let get_manager_operation_gas_and_fee contents = + let open Operation in + let l = to_list (Contents_list contents) in + List.fold_left + (fun acc -> function + | Contents (Manager_operation {fee; gas_limit; _}) -> ( + match acc with + | Error _ as e -> e + | Ok (total_fee, total_gas) -> ( + match Tez.(total_fee +? fee) with + | Ok total_fee -> Ok (total_fee, Gas.Arith.add total_gas gas_limit) + | Error _ as e -> e)) + | _ -> acc) + (Ok (Tez.zero, Gas.Arith.zero)) + l + +type fee_parameter = { + minimal_fees : Tez.t; + minimal_nanotez_per_byte : Q.t; + minimal_nanotez_per_gas_unit : Q.t; + force_low_fee : bool; + fee_cap : Tez.t; + burn_cap : Tez.t; +} + +let dummy_fee_parameter = + { + minimal_fees = Tez.zero; + minimal_nanotez_per_byte = Q.zero; + minimal_nanotez_per_gas_unit = Q.zero; + force_low_fee = false; + fee_cap = Tez.one; + burn_cap = Tez.zero; + } + +(* Rounding up (see Z.cdiv) *) +let z_mutez_of_q_nanotez (ntz : Q.t) = + let q_mutez = Q.div ntz (Q.of_int 1000) in + Z.cdiv q_mutez.Q.num q_mutez.Q.den + +let check_fees : + type t. + #Protocol_client_context.full -> + fee_parameter -> + t contents_list -> + int -> + unit Lwt.t = + fun cctxt config op size -> + match get_manager_operation_gas_and_fee op with + | Error _ -> assert false (* FIXME *) + | Ok (fee, gas) -> + if Tez.compare fee config.fee_cap > 0 then + cctxt#error + "The proposed fee (%s%a) are higher than the configured fee cap \ + (%s%a).@\n\ + \ Use `--fee-cap %a` to emit this operation anyway." + Client_proto_args.tez_sym + Tez.pp + fee + Client_proto_args.tez_sym + Tez.pp + config.fee_cap + Tez.pp + fee + >>= fun () -> exit 1 + else + let fees_in_nanotez = + Q.mul (Q.of_int64 (Tez.to_mutez fee)) (Q.of_int 1000) + in + let minimal_fees_in_nanotez = + Q.mul (Q.of_int64 (Tez.to_mutez config.minimal_fees)) (Q.of_int 1000) + in + let minimal_fees_for_gas_in_nanotez = + Q.mul + config.minimal_nanotez_per_gas_unit + (Q.of_bigint (Gas.Arith.integral_to_z gas)) + in + let minimal_fees_for_size_in_nanotez = + Q.mul config.minimal_nanotez_per_byte (Q.of_int size) + in + let estimated_fees_in_nanotez = + Q.add + minimal_fees_in_nanotez + (Q.add + minimal_fees_for_gas_in_nanotez + minimal_fees_for_size_in_nanotez) + in + let estimated_fees_in_mutez = + z_mutez_of_q_nanotez estimated_fees_in_nanotez + in + let estimated_fees = + match Tez.of_mutez (Z.to_int64 estimated_fees_in_mutez) with + | None -> assert false + | Some fee -> fee + in + if + (not config.force_low_fee) + && Q.compare fees_in_nanotez estimated_fees_in_nanotez < 0 + then + cctxt#error + "The proposed fee (%s%a) are lower than the fee that baker expect \ + by default (%s%a).@\n\ + \ Use `--force-low-fee` to emit this operation anyway." + Client_proto_args.tez_sym + Tez.pp + fee + Client_proto_args.tez_sym + Tez.pp + estimated_fees + >>= fun () -> exit 1 + else Lwt.return_unit + +let print_for_verbose_signing ppf ~watermark ~bytes ~branch ~contents = + let open Format in + pp_open_vbox ppf 0 ; + let item f = + pp_open_hovbox ppf 4 ; + pp_print_string ppf " * " ; + f ppf () ; + pp_close_box ppf () ; + pp_print_cut ppf () + in + let hash_pp l = + fprintf ppf "%s" (Base58.raw_encode Blake2B.(hash_bytes l |> to_string)) + in + item (fun ppf () -> + pp_print_text ppf "Branch: " ; + Block_hash.pp ppf branch) ; + item (fun ppf () -> + fprintf + ppf + "Watermark: `%a` (0x%s)" + Signature.pp_watermark + watermark + (Hex.of_bytes (Signature.bytes_of_watermark watermark) |> Hex.show)) ; + item (fun ppf () -> + pp_print_text ppf "Operation bytes: " ; + TzString.fold_left (* We split the bytes into lines for display: *) + (fun n c -> + pp_print_char ppf c ; + if + n < 72 + (* is the email-body standard width, ideal for copy-pasting. *) + then n + 1 + else ( + pp_print_space ppf () ; + 0)) + 0 + (Hex.of_bytes bytes |> Hex.show) + |> ignore) ; + item (fun ppf () -> + pp_print_text ppf "Blake 2B Hash (raw): " ; + hash_pp [bytes]) ; + item (fun ppf () -> + pp_print_text + ppf + "Blake 2B Hash (ledger-style, with operation watermark): " ; + hash_pp [Signature.bytes_of_watermark watermark; bytes]) ; + let json = + Data_encoding.Json.construct + Operation.unsigned_encoding + ({branch}, Contents_list contents) + in + item (fun ppf () -> + pp_print_text ppf "JSON encoding: " ; + Data_encoding.Json.pp ppf json) ; + pp_close_box ppf () + +let preapply (type t) (cctxt : #Protocol_client_context.full) ~chain ~block + ?(verbose_signing = false) ?fee_parameter ?branch ?src_sk + (contents : t contents_list) = + get_branch cctxt ~chain ~block branch >>=? fun (chain_id, branch) -> + let bytes = + Data_encoding.Binary.to_bytes_exn + Operation.unsigned_encoding + ({branch}, Contents_list contents) + in + (match src_sk with + | None -> return_none + | Some src_sk -> + let watermark = + match contents with + | Single (Endorsement _) -> Signature.(Endorsement chain_id) + | _ -> Signature.Generic_operation + in + (if verbose_signing then + cctxt#message + "Pre-signature information (verbose signing):@.%t%!" + (print_for_verbose_signing ~watermark ~bytes ~branch ~contents) + else Lwt.return_unit) + >>= fun () -> + Client_keys.sign cctxt ~watermark src_sk bytes >>=? fun signature -> + return_some signature) + >>=? fun signature -> + let op : _ Operation.t = + {shell = {branch}; protocol_data = {contents; signature}} + in + let oph = Operation.hash op in + let size = Bytes.length bytes + Signature.size in + (match fee_parameter with + | Some fee_parameter -> check_fees cctxt fee_parameter contents size + | None -> Lwt.return_unit) + >>= fun () -> + Protocol_client_context.Alpha_block_services.Helpers.Preapply.operations + cctxt + ~chain + ~block + [Operation.pack op] + >>=? function + | [(Operation_data op', Operation_metadata result)] -> ( + match + ( Operation.equal op {shell = {branch}; protocol_data = op'}, + Apply_results.kind_equal_list contents result.contents ) + with + | (Some Operation.Eq, Some Apply_results.Eq) -> + return ((oph, op, result) : t preapply_result) + | _ -> failwith "Unexpected result") + | _ -> failwith "Unexpected result" + +let simulate (type t) (cctxt : #Protocol_client_context.full) ~chain ~block + ?branch ?(latency = Plugin.default_operation_inclusion_latency) + (contents : t contents_list) = + get_branch cctxt ~chain ~block branch >>=? fun (_chain_id, branch) -> + let op : _ Operation.t = + {shell = {branch}; protocol_data = {contents; signature = None}} + in + let oph = Operation.hash op in + Chain_services.chain_id cctxt ~chain () >>=? fun chain_id -> + Plugin.RPC.Scripts.simulate_operation + cctxt + (chain, block) + ~op:(Operation.pack op) + ~chain_id + ~latency + >>=? function + | (Operation_data op', Operation_metadata result) -> ( + match + ( Operation.equal op {shell = {branch}; protocol_data = op'}, + Apply_results.kind_equal_list contents result.contents ) + with + | (Some Operation.Eq, Some Apply_results.Eq) -> + return ((oph, op, result) : t preapply_result) + | _ -> failwith "Unexpected result") + | _ -> failwith "Unexpected result" + +let estimated_gas_single (type kind) + (Manager_operation_result {operation_result; internal_operation_results; _} : + kind Kind.manager contents_result) = + let consumed_gas (type kind) (result : kind manager_operation_result) = + match result with + | Applied (Transaction_result {consumed_gas; _}) -> Ok consumed_gas + | Applied (Origination_result {consumed_gas; _}) -> Ok consumed_gas + | Applied (Reveal_result {consumed_gas}) -> Ok consumed_gas + | Applied (Delegation_result {consumed_gas}) -> Ok consumed_gas + | Applied (Register_global_constant_result {consumed_gas; _}) -> + Ok consumed_gas + | Skipped _ -> assert false + | Backtracked (_, None) -> + Ok Gas.Arith.zero (* there must be another error for this to happen *) + | Backtracked (_, Some errs) -> Error (Environment.wrap_tztrace errs) + | Failed (_, errs) -> Error (Environment.wrap_tztrace errs) + in + List.fold_left + (fun acc (Internal_operation_result (_, r)) -> + acc >>? fun acc -> + consumed_gas r >>? fun gas -> Ok (Gas.Arith.add acc gas)) + (consumed_gas operation_result) + internal_operation_results + +let estimated_storage_single (type kind) origination_size + (Manager_operation_result {operation_result; internal_operation_results; _} : + kind Kind.manager contents_result) = + let storage_size_diff (type kind) (result : kind manager_operation_result) = + match result with + | Applied + (Transaction_result + {paid_storage_size_diff; allocated_destination_contract; _}) -> + if allocated_destination_contract then + Ok (Z.add paid_storage_size_diff origination_size) + else Ok paid_storage_size_diff + | Applied (Origination_result {paid_storage_size_diff; _}) -> + Ok (Z.add paid_storage_size_diff origination_size) + | Applied (Reveal_result _) -> Ok Z.zero + | Applied (Delegation_result _) -> Ok Z.zero + | Applied (Register_global_constant_result {size_of_constant; _}) -> + Ok size_of_constant + | Skipped _ -> assert false + | Backtracked (_, None) -> + Ok Z.zero (* there must be another error for this to happen *) + | Backtracked (_, Some errs) -> Error (Environment.wrap_tztrace errs) + | Failed (_, errs) -> Error (Environment.wrap_tztrace errs) + in + List.fold_left + (fun acc (Internal_operation_result (_, r)) -> + acc >>? fun acc -> + storage_size_diff r >>? fun storage -> Ok (Z.add acc storage)) + (storage_size_diff operation_result) + internal_operation_results + +let estimated_storage origination_size res = + let rec estimated_storage : type kind. kind contents_result_list -> _ = + function + | Single_result (Manager_operation_result _ as res) -> + estimated_storage_single origination_size res + | Single_result _ -> Ok Z.zero + | Cons_result (res, rest) -> + estimated_storage_single origination_size res >>? fun storage1 -> + estimated_storage rest >>? fun storage2 -> Ok (Z.add storage1 storage2) + in + estimated_storage res >>? fun diff -> Ok (Z.max Z.zero diff) + +let originated_contracts_single (type kind) + (Manager_operation_result {operation_result; internal_operation_results; _} : + kind Kind.manager contents_result) = + let originated_contracts (type kind) (result : kind manager_operation_result) + = + match result with + | Applied (Transaction_result {originated_contracts; _}) -> + Ok originated_contracts + | Applied (Origination_result {originated_contracts; _}) -> + Ok originated_contracts + | Applied (Register_global_constant_result _) -> Ok [] + | Applied (Reveal_result _) -> Ok [] + | Applied (Delegation_result _) -> Ok [] + | Skipped _ -> assert false + | Backtracked (_, None) -> + Ok [] (* there must be another error for this to happen *) + | Backtracked (_, Some errs) -> Error (Environment.wrap_tztrace errs) + | Failed (_, errs) -> Error (Environment.wrap_tztrace errs) + in + List.fold_left + (fun acc (Internal_operation_result (_, r)) -> + acc >>? fun acc -> + originated_contracts r >>? fun contracts -> + Ok (List.rev_append contracts acc)) + (originated_contracts operation_result >|? List.rev) + internal_operation_results + +let rec originated_contracts : type kind. kind contents_result_list -> _ = + function + | Single_result (Manager_operation_result _ as res) -> + originated_contracts_single res >|? List.rev + | Single_result _ -> Ok [] + | Cons_result (res, rest) -> + originated_contracts_single res >>? fun contracts1 -> + originated_contracts rest >>? fun contracts2 -> + Ok (List.rev_append contracts1 contracts2) + +let detect_script_failure : type kind. kind operation_metadata -> _ = + let rec detect_script_failure : type kind. kind contents_result_list -> _ = + let detect_script_failure_single (type kind) + (Manager_operation_result + {operation_result; internal_operation_results; _} : + kind Kind.manager contents_result) = + let detect_script_failure (type kind) + (result : kind manager_operation_result) = + match result with + | Applied _ -> Ok () + | Skipped _ -> assert false + | Backtracked (_, None) -> + (* there must be another error for this to happen *) + Ok () + | Backtracked (_, Some errs) -> + record_trace + (failure "The transfer simulation failed.") + (Error (Environment.wrap_tztrace errs)) + | Failed (_, errs) -> + record_trace + (failure "The transfer simulation failed.") + (Error (Environment.wrap_tztrace errs)) + in + List.fold_left + (fun acc (Internal_operation_result (_, r)) -> + acc >>? fun () -> detect_script_failure r) + (detect_script_failure operation_result) + internal_operation_results + in + function + | Single_result (Manager_operation_result _ as res) -> + detect_script_failure_single res + | Single_result _ -> Ok () + | Cons_result (res, rest) -> + detect_script_failure_single res >>? fun () -> + detect_script_failure rest + in + fun {contents} -> detect_script_failure contents + +(* This value is used as a safety guard for gas limit. *) +let safety_guard = Gas.Arith.(integral_of_int_exn 100) + +let may_patch_limits (type kind) (cctxt : #Protocol_client_context.full) + ~fee_parameter ~chain ~block ?branch + (annotated_contents : kind Annotated_manager_operation.annotated_list) : + kind Kind.manager contents_list tzresult Lwt.t = + Tezos_client_base.Client_confirmations.wait_for_bootstrapped cctxt + >>=? fun () -> + Alpha_services.Constants.all cctxt (chain, block) + >>=? fun { + parametric = + { + hard_gas_limit_per_operation; + hard_storage_limit_per_operation; + origination_size; + cost_per_byte; + _; + }; + _; + } -> + let user_gas_limit_needs_patching user_gas_limit = + Limit.fold user_gas_limit ~unknown:true ~known:(fun user_gas_limit -> + Gas.Arith.( + user_gas_limit < zero || hard_gas_limit_per_operation < user_gas_limit)) + in + let user_storage_limit_needs_patching user_storage_limit = + Limit.fold + user_storage_limit + ~unknown:true + ~known:(fun user_storage_limit -> + Z.Compare.( + user_storage_limit < Z.zero + || hard_storage_limit_per_operation < user_storage_limit)) + in + let may_need_patching_single : + type kind. + kind Annotated_manager_operation.t -> + kind Annotated_manager_operation.t option = function + | Manager_info c -> + let needs_patching = + Limit.is_unknown c.fee + || user_gas_limit_needs_patching c.gas_limit + || user_storage_limit_needs_patching c.storage_limit + in + if not needs_patching then None + else + (* Set limits for simulation purposes *) + let gas_limit = + if user_gas_limit_needs_patching c.gas_limit then + Limit.known hard_gas_limit_per_operation + else c.gas_limit + in + let storage_limit = + if user_storage_limit_needs_patching c.storage_limit then + Limit.known hard_storage_limit_per_operation + else c.storage_limit + in + let fee = Limit.value ~when_unknown:Tez.zero c.fee in + Some + (Manager_info + {c with gas_limit; storage_limit; fee = Limit.known fee}) + in + let rec may_need_patching : + type kind. + kind Annotated_manager_operation.annotated_list -> + kind Annotated_manager_operation.annotated_list option = function + | Single_manager annotated_op -> ( + match may_need_patching_single annotated_op with + | None -> None + | Some annotated_op -> Some (Single_manager annotated_op)) + | Cons_manager (annotated_op, rest) -> ( + let annotated_op_opt = may_need_patching_single annotated_op in + let rest_opt = may_need_patching rest in + match (annotated_op_opt, rest_opt) with + | (None, None) -> None + | _ -> + let op = Option.value ~default:annotated_op annotated_op_opt in + let rest = Option.value ~default:rest rest_opt in + Some (Cons_manager (op, rest))) + in + let rec patch_fee : type kind. first:bool -> kind contents -> kind contents = + fun ~first -> function + | Manager_operation c as op -> ( + let size = + if first then + (WithExceptions.Option.get ~loc:__LOC__ + @@ Data_encoding.Binary.fixed_length + Tezos_base.Operation.shell_header_encoding) + + Data_encoding.Binary.length + Operation.contents_encoding + (Contents op) + + Signature.size + else + Data_encoding.Binary.length + Operation.contents_encoding + (Contents op) + in + let minimal_fees_in_nanotez = + Q.mul + (Q.of_int64 (Tez.to_mutez fee_parameter.minimal_fees)) + (Q.of_int 1000) + in + let minimal_fees_for_gas_in_nanotez = + Q.mul + fee_parameter.minimal_nanotez_per_gas_unit + (Q.of_bigint @@ Gas.Arith.integral_to_z c.gas_limit) + in + let minimal_fees_for_size_in_nanotez = + Q.mul fee_parameter.minimal_nanotez_per_byte (Q.of_int size) + in + let fees_in_nanotez = + Q.add minimal_fees_in_nanotez + @@ Q.add + minimal_fees_for_gas_in_nanotez + minimal_fees_for_size_in_nanotez + in + let fees_in_mutez = z_mutez_of_q_nanotez fees_in_nanotez in + match Tez.of_mutez (Z.to_int64 fees_in_mutez) with + | None -> assert false + | Some fee -> + if Tez.(fee <= c.fee) then op + else patch_fee ~first (Manager_operation {c with fee})) + | c -> c + in + let patch : + type kind. + first:bool -> + kind Annotated_manager_operation.t * kind Kind.manager contents_result -> + kind Kind.manager contents tzresult Lwt.t = + fun ~first -> function + | ((Manager_info c as op), (Manager_operation_result _ as result)) -> + (if user_gas_limit_needs_patching c.gas_limit then + Lwt.return (estimated_gas_single result) >>=? fun gas -> + if Gas.Arith.(gas = zero) then + cctxt#message "Estimated gas: none" >>= fun () -> + return + (Annotated_manager_operation.set_gas_limit + (Limit.known Gas.Arith.zero) + op) + else + cctxt#message + "Estimated gas: %a units (will add 100 for safety)" + Gas.Arith.pp + gas + >>= fun () -> + let safe_gas = Gas.Arith.(add (ceil gas) safety_guard) in + let patched_gas = + Gas.Arith.min safe_gas hard_gas_limit_per_operation + in + return + (Annotated_manager_operation.set_gas_limit + (Limit.known patched_gas) + op) + else return op) + >>=? fun op -> + (if user_storage_limit_needs_patching c.storage_limit then + Lwt.return + (estimated_storage_single (Z.of_int origination_size) result) + >>=? fun storage -> + if Z.equal storage Z.zero then + cctxt#message "Estimated storage: no bytes added" >>= fun () -> + return + (Annotated_manager_operation.set_storage_limit + (Limit.known Z.zero) + op) + else + cctxt#message + "Estimated storage: %s bytes added (will add 20 for safety)" + (Z.to_string storage) + >>= fun () -> + let storage_limit = + Z.min + (Z.add storage (Z.of_int 20)) + hard_storage_limit_per_operation + in + return + (Annotated_manager_operation.set_storage_limit + (Limit.known storage_limit) + op) + else return op) + >>=? fun op -> + if Limit.is_unknown c.fee then + (* Setting a dummy fee is required for converting to manager op *) + let op = + Annotated_manager_operation.set_fee (Limit.known Tez.zero) op + in + Annotated_manager_operation.manager_from_annotated op >>?= fun cm -> + return (patch_fee ~first cm) + else Lwt.return (Annotated_manager_operation.manager_from_annotated op) + in + let rec patch_list : + type kind. + bool -> + kind Annotated_manager_operation.annotated_list -> + kind Kind.manager contents_result_list -> + kind Kind.manager contents_list tzresult Lwt.t = + fun first annotated_list result_list -> + match (annotated_list, result_list) with + | (Single_manager annotated, Single_result res) -> + patch ~first (annotated, res) >>=? fun op -> return (Single op) + | (Cons_manager (annotated, annotated_rest), Cons_result (res, res_rest)) -> + patch ~first (annotated, res) >>=? fun op -> + patch_list false annotated_rest res_rest >>=? fun rest -> + return (Cons (op, rest)) + | _ -> assert false + in + match may_need_patching annotated_contents with + | Some annotated_for_simulation -> + Lwt.return + (Annotated_manager_operation.manager_list_from_annotated + annotated_for_simulation) + >>=? fun contents_for_simulation -> + simulate cctxt ~chain ~block ?branch contents_for_simulation + >>=? fun (_, _, result) -> + (match detect_script_failure result with + | Ok () -> return_unit + | Error _ -> + cctxt#message + "@[This simulation failed:@,%a@]" + Operation_result.pp_operation_result + (contents_for_simulation, result.contents) + >>= fun () -> return_unit) + >>=? fun () -> + ( Lwt.return + (estimated_storage (Z.of_int origination_size) result.contents) + >>=? fun storage -> + Lwt.return + (Environment.wrap_tzresult Tez.(cost_per_byte *? Z.to_int64 storage)) + >>=? fun burn -> + if Tez.(burn > fee_parameter.burn_cap) then + cctxt#error + "The operation will burn %s%a which is higher than the configured \ + burn cap (%s%a).@\n\ + \ Use `--burn-cap %a` to emit this operation." + Client_proto_args.tez_sym + Tez.pp + burn + Client_proto_args.tez_sym + Tez.pp + fee_parameter.burn_cap + Tez.pp + burn + >>= fun () -> exit 1 + else return_unit ) + >>=? fun () -> patch_list true annotated_contents result.contents + | None -> + Lwt.return + (Annotated_manager_operation.manager_list_from_annotated + annotated_contents) + +let inject_operation_internal (type kind) cctxt ~chain ~block ?confirmations + ?(dry_run = false) ?(simulation = false) ?branch ?src_sk ?verbose_signing + ~fee_parameter (contents : kind contents_list) = + (if simulation then simulate cctxt ~chain ~block ?branch contents + else + preapply + cctxt + ~chain + ~block + ~fee_parameter + ?verbose_signing + ?branch + ?src_sk + contents) + >>=? fun (_oph, op, result) -> + (match detect_script_failure result with + | Ok () -> return_unit + | Error _ as res -> + cctxt#message + "@[This simulation failed:@,%a@]" + Operation_result.pp_operation_result + (op.protocol_data.contents, result.contents) + >>= fun () -> Lwt.return res) + >>=? fun () -> + let bytes = + Data_encoding.Binary.to_bytes_exn Operation.encoding (Operation.pack op) + in + if dry_run || simulation then + let oph = Operation_hash.hash_bytes [bytes] in + cctxt#message + "@[Operation: 0x%a@,Operation hash is '%a'@]" + Hex.pp + (Hex.of_bytes bytes) + Operation_hash.pp + oph + >>= fun () -> + cctxt#message + "@[Simulation result:@,%a@]" + Operation_result.pp_operation_result + (op.protocol_data.contents, result.contents) + >>= fun () -> return (oph, op.protocol_data.contents, result.contents) + else + Shell_services.Injection.operation cctxt ~chain bytes >>=? fun oph -> + cctxt#message "Operation successfully injected in the node." >>= fun () -> + cctxt#message "Operation hash is '%a'" Operation_hash.pp oph >>= fun () -> + (match confirmations with + | None -> + cctxt#message + "@[NOT waiting for the operation to be included.@,\ + Use command@,\ + \ tezos-client wait for %a to be included --confirmations %d \ + --branch %a@,\ + and/or an external block explorer to make sure that it has been \ + included.@]" + Operation_hash.pp + oph + num_confirmation_blocks + Block_hash.pp + op.shell.branch + >>= fun () -> return result + | Some confirmations -> ( + cctxt#message "Waiting for the operation to be included..." + >>= fun () -> + Client_confirmations.wait_for_operation_inclusion + ~branch:op.shell.branch + ~confirmations + cctxt + ~chain + oph + >>=? fun (h, i, j) -> + Alpha_block_services.Operations.operation + cctxt + ~chain + ~block:(`Hash (h, 0)) + i + j + >>=? fun op' -> + match op'.receipt with + | None -> failwith "Internal error: pruned metadata." + | Some No_operation_metadata -> + failwith "Internal error: unexpected receipt." + | Some (Operation_metadata receipt) -> ( + match Apply_results.kind_equal_list contents receipt.contents with + | Some Apply_results.Eq -> + return (receipt : kind operation_metadata) + | None -> failwith "Internal error: unexpected receipt."))) + >>=? fun result -> + cctxt#message + "@[This sequence of operations was run:@,%a@]" + Operation_result.pp_operation_result + (op.protocol_data.contents, result.contents) + >>= fun () -> + Lwt.return (originated_contracts result.contents) >>=? fun contracts -> + List.iter_s + (fun c -> cctxt#message "New contract %a originated." Contract.pp c) + contracts + >>= fun () -> + (match confirmations with + | None -> Lwt.return_unit + | Some number -> + if number >= num_confirmation_blocks then + cctxt#message + "The operation was included in a block %d blocks ago." + number + else + cctxt#message + "@[The operation has only been included %d blocks ago.@,\ + We recommend to wait more.@,\ + Use command@,\ + \ tezos-client wait for %a to be included --confirmations %d \ + --branch %a@,\ + and/or an external block explorer.@]" + number + Operation_hash.pp + oph + num_confirmation_blocks + Block_hash.pp + op.shell.branch) + >>= fun () -> return (oph, op.protocol_data.contents, result.contents) + +let inject_operation (type kind) cctxt ~chain ~block ?confirmations + ?(dry_run = false) ?(simulation = false) ?branch ?src_sk ?verbose_signing + ~fee_parameter (contents : kind contents_list) = + Tezos_client_base.Client_confirmations.wait_for_bootstrapped cctxt + >>=? fun () -> + inject_operation_internal + cctxt + ~chain + ~block + ?confirmations + ~dry_run + ~simulation + ?branch + ?src_sk + ?verbose_signing + ~fee_parameter + (contents : kind contents_list) + +let prepare_manager_operation ~fee ~gas_limit ~storage_limit operation = + Annotated_manager_operation.Manager_info + {source = None; fee; gas_limit; storage_limit; counter = None; operation} + +(* [gas_limit] must correspond to + [Michelson_v1_gas.Cost_of.manager_operation] *) +let cost_of_manager_operation = Gas.Arith.integral_of_int_exn 1_000 + +let reveal_error_message = + "Requested operation requires to perform a public key revelation beforehand.\n\ + This cannot be done automatically when a custom fee or storage limit is \ + given.\n\ + If you wish to use a custom fee or storage limit, please first perform the \ + reveal operation separately using the dedicated command.\n\ + Otherwise, please do not specify custom fee or storage parameters." + +let reveal_error (cctxt : #Protocol_client_context.full) = + cctxt#error "%s" reveal_error_message + +let inject_manager_operation cctxt ~chain ~block ?branch ?confirmations ?dry_run + ?verbose_signing ?simulation ~source ~src_pk ~src_sk ~fee ~gas_limit + ~storage_limit ?counter ~fee_parameter (type kind) + (operations : kind Annotated_manager_operation.annotated_list) : + (Operation_hash.t + * kind Kind.manager contents_list + * kind Kind.manager contents_result_list) + tzresult + Lwt.t = + (match counter with + | None -> + Alpha_services.Contract.counter cctxt (chain, block) source + >>=? fun pcounter -> + let counter = Z.succ pcounter in + return counter + | Some counter -> return counter) + >>=? fun counter -> + Alpha_services.Contract.manager_key cctxt (chain, block) source + >>=? fun key -> + (* [has_reveal] assumes that a Reveal operation only appears as the first of a batch *) + let has_reveal : + type kind. kind Annotated_manager_operation.annotated_list -> bool = + function + | Single_manager (Manager_info {operation = Reveal _; _}) -> true + | Cons_manager (Manager_info {operation = Reveal _; _}, _) -> true + | _ -> false + in + let apply_specified_options counter op = + Annotated_manager_operation.set_source source op >>? fun op -> + Annotated_manager_operation.set_counter counter op >>? fun op -> + Annotated_manager_operation.join_fee fee op >>? fun op -> + Annotated_manager_operation.join_gas_limit gas_limit op >>? fun op -> + Annotated_manager_operation.join_storage_limit storage_limit op + in + let rec build_contents : + type kind. + Z.t -> + kind Annotated_manager_operation.annotated_list -> + kind Annotated_manager_operation.annotated_list tzresult = + fun counter -> function + | Single_manager op -> + apply_specified_options counter op >|? fun op -> + Annotated_manager_operation.Single_manager op + | Cons_manager (op, rest) -> + apply_specified_options counter op >>? fun op -> + build_contents (Z.succ counter) rest >|? fun rest -> + Annotated_manager_operation.Cons_manager (op, rest) + in + match key with + | None when not (has_reveal operations) -> ( + (if not (Limit.is_unknown fee && Limit.is_unknown storage_limit) then + reveal_error cctxt + else return_unit) + >>=? fun () -> + let reveal = + prepare_manager_operation + ~fee:Limit.unknown + ~gas_limit:(Limit.known cost_of_manager_operation) + ~storage_limit:Limit.unknown + (Reveal src_pk) + in + Annotated_manager_operation.set_source source reveal >>?= fun reveal -> + Annotated_manager_operation.set_counter counter reveal >>?= fun reveal -> + build_contents (Z.succ counter) operations >>?= fun rest -> + let contents = Annotated_manager_operation.Cons_manager (reveal, rest) in + may_patch_limits cctxt ~fee_parameter ~chain ~block ?branch contents + >>=? fun contents -> + inject_operation_internal + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?simulation + ~fee_parameter + ?verbose_signing + ?branch + ~src_sk + contents + >>=? fun (oph, op, result) -> + match pack_contents_list op result with + | Cons_and_result (_, _, rest) -> + let (op, result) = unpack_contents_list rest in + return (oph, op, result) + | _ -> assert false) + | Some _ when has_reveal operations -> + failwith "The manager key was previously revealed." + | _ -> + build_contents counter operations >>?= fun contents -> + may_patch_limits cctxt ~fee_parameter ~chain ~block ?branch contents + >>=? fun contents -> + inject_operation_internal + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ?simulation + ~fee_parameter + ?branch + ~src_sk + contents diff --git a/src/proto_011_PtHangzH/lib_client/injection.mli b/src/proto_011_PtHangzH/lib_client/injection.mli new file mode 100644 index 000000000000..d8f99d620510 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/injection.mli @@ -0,0 +1,105 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Apply_results + +type 'kind preapply_result = + Operation_hash.t * 'kind operation * 'kind operation_metadata + +type fee_parameter = { + minimal_fees : Tez.t; + minimal_nanotez_per_byte : Q.t; + minimal_nanotez_per_gas_unit : Q.t; + force_low_fee : bool; + fee_cap : Tez.t; + burn_cap : Tez.t; +} + +val dummy_fee_parameter : fee_parameter + +val preapply : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?verbose_signing:bool -> + ?fee_parameter:fee_parameter -> + ?branch:int -> + ?src_sk:Client_keys.sk_uri -> + 'kind contents_list -> + 'kind preapply_result tzresult Lwt.t + +type 'kind result_list = + Operation_hash.t * 'kind contents_list * 'kind contents_result_list + +(** /!\ [inject_operation] does not perform automatic patching of + gas, storage and fees; use [inject_manager_operation] to inject + manager operations. *) +val inject_operation : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?simulation:bool -> + ?branch:int -> + ?src_sk:Client_keys.sk_uri -> + ?verbose_signing:bool -> + fee_parameter:fee_parameter -> + 'kind contents_list -> + 'kind result_list tzresult Lwt.t + +type 'kind result = Operation_hash.t * 'kind contents * 'kind contents_result + +val prepare_manager_operation : + fee:Tez.t Limit.t -> + gas_limit:Gas.Arith.integral Limit.t -> + storage_limit:Z.t Limit.t -> + 'kind manager_operation -> + 'kind Annotated_manager_operation.t + +val inject_manager_operation : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?branch:int -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?simulation:bool -> + source:Signature.Public_key_hash.t -> + src_pk:Signature.public_key -> + src_sk:Client_keys.sk_uri -> + fee:Tez.t Limit.t -> + gas_limit:Gas.Arith.integral Limit.t -> + storage_limit:Z.t Limit.t -> + ?counter:Z.t -> + fee_parameter:fee_parameter -> + 'kind Annotated_manager_operation.annotated_list -> + 'kind Kind.manager result_list tzresult Lwt.t + +val originated_contracts : + 'kind contents_result_list -> Contract.t list tzresult diff --git a/src/proto_011_PtHangzH/lib_client/light.ml b/src/proto_011_PtHangzH/lib_client/light.ml new file mode 100644 index 000000000000..038624664ec0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/light.ml @@ -0,0 +1,37 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module M : Tezos_proxy.Light_proto.PROTO_RPCS = struct + let merkle_tree (pgi : Tezos_proxy.Proxy.proxy_getter_input) key leaf_kind = + Protocol_client_context.Alpha_block_services.Context.merkle_tree + pgi.rpc_context + ~chain:pgi.chain + ~block:pgi.block + ~holey: + (match leaf_kind with + | Tezos_shell_services.Block_services.Hole -> true + | Tezos_shell_services.Block_services.Raw_context -> false) + key +end diff --git a/src/proto_011_PtHangzH/lib_client/limit.ml b/src/proto_011_PtHangzH/lib_client/limit.ml new file mode 100644 index 000000000000..ea1f4e0db243 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/limit.ml @@ -0,0 +1,64 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type 'a t = 'a option + +let unknown = None + +let known x = Some x + +let of_option = Fun.id + +let is_unknown = Option.is_none + +let join (type a) ~where eq (l1 : a t) (l2 : a t) = + match (l1, l2) with + | (None, None) -> Result.return_none + | (Some x, None) | (None, Some x) -> Result.return_some x + | (Some x, Some y) -> + if eq x y then Result.return_some x + else generic_error "Limit.join: error (%s)" where + +let%test "join" = + let check res y = + match res with Ok x -> Option.equal Bool.equal x y | Error _ -> false + in + check (join ~where:__LOC__ Bool.equal (Some true) (Some true)) (Some true) + && check (join ~where:__LOC__ Bool.equal None None) None + && check (join ~where:__LOC__ Bool.equal None (Some true)) (Some true) + && check (join ~where:__LOC__ Bool.equal (Some true) None) (Some true) + && not + (Result.is_ok (join ~where:__LOC__ Bool.equal (Some true) (Some false))) + +let get ~when_unknown = function + | None -> generic_error "Limit.get: %s" when_unknown + | Some x -> ok x + +let%test "get" = + match get ~when_unknown:"" (Some true) with Ok true -> true | _ -> false + +let fold ~unknown ~known x = match x with None -> unknown | Some x -> known x + +let value ~when_unknown = function None -> when_unknown | Some x -> x diff --git a/src/proto_011_PtHangzH/lib_client/limit.mli b/src/proto_011_PtHangzH/lib_client/limit.mli new file mode 100644 index 000000000000..3ce610e3450c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/limit.mli @@ -0,0 +1,49 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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 helper module allows to handle partially specified limits during the + injection process. *) + +(** A value of type ['a t] is either [unknown] of [known]. *) +type 'a t + +val unknown : 'a t + +val known : 'a -> 'a t + +val of_option : 'a option -> 'a t + +val is_unknown : 'a t -> bool + +(** [join ~where eq x y] computes the order-theoretic union of [x] and [y]. + If both [x] and [y] are not [Unknown], the function fails iff their + contents are not equal according to [eq]. *) +val join : where:string -> ('a -> 'a -> bool) -> 'a t -> 'a t -> 'a t tzresult + +val fold : unknown:'a -> known:('b -> 'a) -> 'b t -> 'a + +val get : when_unknown:string -> 'a t -> 'a tzresult + +val value : when_unknown:'a -> 'a t -> 'a diff --git a/src/proto_011_PtHangzH/lib_client/managed_contract.ml b/src/proto_011_PtHangzH/lib_client/managed_contract.ml new file mode 100644 index 000000000000..29bb3d976b63 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/managed_contract.ml @@ -0,0 +1,321 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) +open Protocol +open Alpha_context +open Protocol_client_context +open Tezos_micheline + +let return_single_manager_result (oph, op, result) = + match Apply_results.pack_contents_list op result with + | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> + return (oph, op, result) + | _ -> assert false + +let get_contract_manager (cctxt : #full) contract = + let open Micheline in + let open Michelson_v1_primitives in + Client_proto_context.get_storage + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~unparsing_mode:Optimized + contract + >>=? function + | None -> cctxt#error "This is not a smart contract." + | Some storage -> ( + match root storage with + | Prim (_, D_Pair, Bytes (_, bytes) :: _, _) | Bytes (_, bytes) -> ( + match + Data_encoding.Binary.of_bytes_opt + Signature.Public_key_hash.encoding + bytes + with + | Some k -> return k + | None -> + cctxt#error + "Cannot find a manager key in contracts storage (decoding \ + bytes failed).\n\ + Transfer from scripted contract are currently only supported \ + for \"manager\" contract.") + | Prim (_, D_Pair, String (_, value) :: _, _) | String (_, value) -> ( + match Signature.Public_key_hash.of_b58check_opt value with + | Some k -> return k + | None -> + cctxt#error + "Cannot find a manager key in contracts storage (\"%s\" is not \ + a valid key).\n\ + Transfer from scripted contract are currently only supported \ + for \"manager\" contract." + value) + | _raw_storage -> + cctxt#error + "Cannot find a manager key in contracts storage (wrong storage \ + format : @[%a@]).\n\ + Transfer from scripted contract are currently only supported for \ + \"manager\" contract." + Michelson_v1_printer.print_expr + storage) + +let parse code = + Lwt.return + ( Micheline_parser.no_parsing_error + @@ Michelson_v1_parser.parse_expression code + >>? fun exp -> + Error_monad.ok @@ Script.lazy_expr Michelson_v1_parser.(exp.expanded) ) + +let build_lambda_for_set_delegate ~delegate = + match delegate with + | Some delegate -> + let (`Hex delegate) = Signature.Public_key_hash.to_hex delegate in + Format.asprintf + "{ DROP ; NIL operation ; PUSH key_hash 0x%s ; SOME ; SET_DELEGATE ; \ + CONS }" + delegate + | None -> "{ DROP ; NIL operation ; NONE key_hash ; SET_DELEGATE ; CONS }" + +let build_delegate_operation (cctxt : #full) ~chain ~block ?fee + contract (* the KT1 to delegate *) + (delegate : Signature.public_key_hash option) = + let entrypoint = "do" in + (Michelson_v1_entrypoints.contract_entrypoint_type + cctxt + ~chain + ~block + ~contract + ~entrypoint + >>=? function + | Some _ -> + (* their is a "do" entrypoint (we could check its type here)*) + parse @@ build_lambda_for_set_delegate ~delegate >>=? fun param -> + return (param, entrypoint) + | None -> ( + (* their is no "do" entrypoint trying "set/remove_delegate" *) + let entrypoint = + match delegate with + | Some _ -> "set_delegate" + | None -> "remove_delegate" + in + Michelson_v1_entrypoints.contract_entrypoint_type + cctxt + ~chain + ~block + ~contract + ~entrypoint + >>=? function + | Some _ -> + (* their is a "set/remove_delegate" entrypoint *) + let delegate_data = + match delegate with + | Some delegate -> + let (`Hex delegate) = + Signature.Public_key_hash.to_hex delegate + in + "0x" ^ delegate + | None -> "Unit" + in + parse delegate_data >>=? fun param -> return (param, entrypoint) + | None -> + cctxt#error + "Cannot find a %%do or %%set_delegate entrypoint in contract@.")) + >>=? fun (parameters, entrypoint) -> + return + (Client_proto_context.build_transaction_operation + ~amount:Tez.zero + ~parameters + ~entrypoint + ?fee + contract) + +let set_delegate (cctxt : #full) ~chain ~block ?confirmations ?dry_run + ?verbose_signing ?simulation ?branch ~fee_parameter ?fee ~source ~src_pk + ~src_sk contract (* the KT1 to delegate *) + (delegate : Signature.public_key_hash option) = + build_delegate_operation cctxt ~chain ~block ?fee contract delegate + >>=? fun operation -> + let operation = Annotated_manager_operation.Single_manager operation in + Injection.inject_manager_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ?simulation + ?branch + ~source + ~fee:(Limit.of_option fee) + ~gas_limit:Limit.unknown + ~storage_limit:(Limit.known Z.zero) + ~src_pk + ~src_sk + ~fee_parameter + operation + >>=? return_single_manager_result + +let d_unit = + Micheline.strip_locations (Prim (0, Michelson_v1_primitives.D_Unit, [], [])) + +let t_unit = + Micheline.strip_locations (Prim (0, Michelson_v1_primitives.T_unit, [], [])) + +let build_lambda_for_transfer_to_implicit ~destination ~amount = + let (`Hex destination) = Signature.Public_key_hash.to_hex destination in + Format.asprintf + "{ DROP ; NIL operation ;PUSH key_hash 0x%s; IMPLICIT_ACCOUNT;PUSH mutez \ + %Ld ;UNIT;TRANSFER_TOKENS ; CONS }" + destination + (Tez.to_mutez amount) + +let build_lambda_for_transfer_to_originated ~destination ~entrypoint ~amount + ~parameter_type ~parameter = + let destination = + Data_encoding.Binary.to_bytes_exn Contract.encoding destination + in + let amount = Tez.to_mutez amount in + let (`Hex destination) = Hex.of_bytes destination in + let entrypoint = match entrypoint with "default" -> "" | s -> "%" ^ s in + if parameter_type = t_unit then + Format.asprintf + "{ DROP ; NIL operation ;PUSH address 0x%s; CONTRACT %s %a; \ + ASSERT_SOME;PUSH mutez %Ld ;UNIT;TRANSFER_TOKENS ; CONS }" + destination + entrypoint + Michelson_v1_printer.print_expr + parameter_type + amount + else + Format.asprintf + "{ DROP ; NIL operation ;PUSH address 0x%s; CONTRACT %s %a; \ + ASSERT_SOME;PUSH mutez %Ld ;PUSH %a %a;TRANSFER_TOKENS ; CONS }" + destination + entrypoint + Michelson_v1_printer.print_expr + parameter_type + amount + Michelson_v1_printer.print_expr + parameter_type + Michelson_v1_printer.print_expr + parameter + +let build_transaction_operation (cctxt : #full) ~chain ~block ~contract + ~destination ?(entrypoint = "default") ?arg ~amount ?fee ?gas_limit + ?storage_limit () = + (match Alpha_context.Contract.is_implicit destination with + | Some destination when entrypoint = "default" -> + return @@ build_lambda_for_transfer_to_implicit ~destination ~amount + | Some _ -> + cctxt#error + "Implicit accounts have no entrypoints. (targeted entrypoint %%%s on \ + contract %a)" + entrypoint + Contract.pp + destination + | None -> + (Michelson_v1_entrypoints.contract_entrypoint_type + cctxt + ~chain + ~block + ~contract:destination + ~entrypoint + >>=? function + | None -> + cctxt#error + "Contract %a has no entrypoint named %s" + Contract.pp + destination + entrypoint + | Some parameter_type -> return parameter_type) + >>=? fun parameter_type -> + (match arg with + | Some arg -> + Lwt.return @@ Micheline_parser.no_parsing_error + @@ Michelson_v1_parser.parse_expression arg + >>=? fun {expanded = arg; _} -> return_some arg + | None -> return_none) + >>=? fun parameter -> + let parameter = Option.value ~default:d_unit parameter in + return + @@ build_lambda_for_transfer_to_originated + ~destination + ~entrypoint + ~amount + ~parameter_type + ~parameter) + >>=? fun lambda -> + parse lambda >>=? fun parameters -> + let entrypoint = "do" in + return + (Client_proto_context.build_transaction_operation + ~amount:Tez.zero + ~parameters + ~entrypoint + ?fee + ?gas_limit + ?storage_limit + contract) + +let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run + ?verbose_signing ?simulation ?branch ~source ~src_pk ~src_sk ~contract + ~destination ?(entrypoint = "default") ?arg ~amount ?fee ?gas_limit + ?storage_limit ?counter ~fee_parameter () : + (Kind.transaction Kind.manager Injection.result * Contract.t list) tzresult + Lwt.t = + build_transaction_operation + cctxt + ~chain + ~block + ~contract + ~destination + ~entrypoint + ?arg + ~amount + ?fee + ?gas_limit + ?storage_limit + () + >>=? fun operation -> + let operation = Annotated_manager_operation.Single_manager operation in + Injection.inject_manager_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ?simulation + ?branch + ~source + ~fee:(Limit.of_option fee) + ~gas_limit:(Limit.of_option gas_limit) + ~storage_limit:(Limit.of_option storage_limit) + ?counter + ~src_pk + ~src_sk + ~fee_parameter + operation + >>=? fun (oph, op, result) -> + Lwt.return (Injection.originated_contracts result) >>=? fun contracts -> + return_single_manager_result (oph, op, result) >>=? fun res -> + return (res, contracts) diff --git a/src/proto_011_PtHangzH/lib_client/managed_contract.mli b/src/proto_011_PtHangzH/lib_client/managed_contract.mli new file mode 100644 index 000000000000..ae532c986987 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/managed_contract.mli @@ -0,0 +1,125 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) +open Protocol +open Alpha_context +open Protocol_client_context + +(** Retrieve the manager key in a contract storage. + The storage has to be of type `pair key_hash 'a`. +*) +val get_contract_manager : #full -> Contract.t -> public_key_hash tzresult Lwt.t + +(** Builds a delegation operation ready for injection *) +val build_delegate_operation : + #Protocol_client_context.full -> + chain:Chain_services.chain -> + block:Block_services.block -> + ?fee:Tez.t -> + Contract.t -> + public_key_hash option -> + Kind.transaction Annotated_manager_operation.t tzresult Lwt.t + +(** Set the delegate of a manageable contract. + For a contract with a `do`entrypoint, it builds the lambda that set + the provided delegate. + `~source` has to be the registered manager of the contract. +*) +val set_delegate : + #Protocol_client_context.full -> + chain:Chain_services.chain -> + block:Block_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?simulation:bool -> + ?branch:int -> + fee_parameter:Injection.fee_parameter -> + ?fee:Tez.t -> + source:public_key_hash -> + src_pk:public_key -> + src_sk:Client_keys.sk_uri -> + Contract.t -> + public_key_hash option -> + Kind.transaction Kind.manager Injection.result tzresult Lwt.t + +(** Builds a transaction operation ready for injection *) +val build_transaction_operation : + #Protocol_client_context.full -> + chain:Chain_services.chain -> + block:Block_services.block -> + contract:Contract.t -> + destination:Contract.t -> + ?entrypoint:string -> + ?arg:string -> + amount:Tez.t -> + ?fee:Tez.t -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:counter -> + unit -> + Kind.transaction Annotated_manager_operation.t tzresult Lwt.t + +(** Perform a transfer on behalf of a managed contract . + For a contract with a `do`entrypoint, it builds the lambda that + does the requested operation. + `~source` has to be the registered manager of the contract. +*) +val transfer : + #Protocol_client_context.full -> + chain:Chain_services.chain -> + block:Block_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?simulation:bool -> + ?branch:int -> + source:public_key_hash -> + src_pk:public_key -> + src_sk:Client_keys.sk_uri -> + contract:Contract.t -> + destination:Contract.t -> + ?entrypoint:string -> + ?arg:string -> + amount:Tez.t -> + ?fee:Tez.t -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:counter -> + ?counter:counter -> + fee_parameter:Injection.fee_parameter -> + unit -> + (Kind.transaction Kind.manager Injection.result * Contract.t list) tzresult + Lwt.t + +val build_lambda_for_set_delegate : delegate:public_key_hash option -> string + +val build_lambda_for_transfer_to_implicit : + destination:public_key_hash -> amount:Tez.t -> string + +val build_lambda_for_transfer_to_originated : + destination:Contract.t -> + entrypoint:string -> + amount:Tez.t -> + parameter_type:Script.expr -> + parameter:Script.expr -> + string diff --git a/src/proto_011_PtHangzH/lib_client/michelson_v1_emacs.ml b/src/proto_011_PtHangzH/lib_client/michelson_v1_emacs.ml new file mode 100644 index 000000000000..aaed4a26d0bc --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/michelson_v1_emacs.ml @@ -0,0 +1,234 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Tezos_micheline +open Micheline + +let print_expr ppf expr = + let print_annot ppf = function + | [] -> () + | annots -> Format.fprintf ppf " %s" (String.concat " " annots) + in + let rec print_expr ppf = function + | Int (_, value) -> Format.fprintf ppf "%s" (Z.to_string value) + | String (_, value) -> Micheline_printer.print_string ppf value + | Bytes (_, value) -> Format.fprintf ppf "0x%a" Hex.pp (Hex.of_bytes value) + | Seq (_, items) -> + Format.fprintf + ppf + "(seq %a)" + (Format.pp_print_list ~pp_sep:Format.pp_print_space print_expr) + items + | Prim (_, name, [], []) -> Format.fprintf ppf "%s" name + | Prim (_, name, items, annot) -> + Format.fprintf + ppf + "(%s%a%s%a)" + name + print_annot + annot + (if items = [] then "" else " ") + (Format.pp_print_list ~pp_sep:Format.pp_print_space print_expr) + items + in + let root = root (Michelson_v1_primitives.strings_of_prims expr) in + Format.fprintf ppf "@[%a@]" print_expr root + +let print_var_annots ppf = List.iter (Format.fprintf ppf "%s ") + +let print_annot_expr ppf (expr, annot) = + Format.fprintf ppf "(%a%a)" print_var_annots annot print_expr expr + +open Micheline_parser +open Script_tc_errors + +let print_type_map ppf (parsed, type_map) = + let rec print_expr_types ppf = function + | Seq (loc, []) + | Prim (loc, _, [], _) + | Int (loc, _) + | Bytes (loc, _) + | String (loc, _) -> + print_item ppf loc + | Seq (loc, items) | Prim (loc, _, items, _) -> + print_item ppf loc ; + List.iter (print_expr_types ppf) items + and print_stack ppf items = + Format.fprintf + ppf + "(%a)" + (Format.pp_print_list ~pp_sep:Format.pp_print_space print_annot_expr) + items + and print_item ppf loc = + (let ( >?? ) = Option.bind in + List.assoc ~equal:Int.equal loc parsed.Michelson_v1_parser.expansion_table + >?? fun ({start = {point = s; _}; stop = {point = e; _}}, locs) -> + let locs = List.sort Stdlib.compare locs in + List.hd locs >?? fun hd_loc -> + List.assoc ~equal:Int.equal hd_loc type_map >?? fun (bef, aft) -> + Some (s, e, bef, aft)) + |> Option.iter (fun (s, e, bef, aft) -> + Format.fprintf + ppf + "(@[%d %d %a %a@])@," + s + e + print_stack + bef + print_stack + aft) + in + Format.fprintf ppf "(@[%a@])" print_expr_types (root parsed.unexpanded) + +let first_error_location errs = + let rec find = function + | [] -> 0 + | ( Inconsistent_type_annotations (loc, _, _) + | Unexpected_annotation loc + | Ill_formed_type (_, _, loc) + | Invalid_arity (loc, _, _, _) + | Invalid_seq_arity (loc, _, _) + | Invalid_namespace (loc, _, _, _) + | Invalid_primitive (loc, _, _) + | Invalid_kind (loc, _, _) + | Invalid_never_expr loc + | Fail_not_in_tail_position loc + | Undefined_binop (loc, _, _, _) + | Undefined_unop (loc, _, _) + | Bad_return (loc, _, _) + | Bad_stack (loc, _, _, _) + | Unmatched_branches (loc, _, _) + | Invalid_constant (loc, _, _) + | Invalid_syntactic_constant (loc, _, _) + | Invalid_contract (loc, _) + | Comparable_type_expected (loc, _) + | Michelson_v1_primitives.Invalid_primitive_name (_, loc) ) + :: _ -> + loc + | _ :: rest -> find rest + in + find errs + +let report_errors ppf (parsed, errs) = + let (eco, out) = + List.fold_left + (fun (eco, out) -> function + | Environment.Ecoproto_error err -> (err :: eco, out) + | err -> (eco, err :: out)) + ([], []) + errs + in + let (eco, out) = (List.rev eco, List.rev out) in + Format.fprintf + ppf + "(@[%a@,%a@])" + (fun ppf errs -> + let find_location loc = + let oloc = + WithExceptions.Option.get ~loc:__LOC__ + @@ List.assoc + ~equal:Int.equal + loc + parsed.Michelson_v1_parser.unexpansion_table + in + fst + (WithExceptions.Option.get ~loc:__LOC__ + @@ List.assoc ~equal:Int.equal oloc parsed.expansion_table) + in + match errs with + | top :: errs -> + let (errs, loc) = + ( List.map (fun e -> Environment.Ecoproto_error e) (top :: errs), + match top with + | Ill_typed_contract (expr, _) | Ill_typed_data (_, expr, _) -> + if expr = parsed.expanded then + find_location (first_error_location (top :: errs)) + else find_location 0 + | Michelson_v1_primitives.Invalid_primitive_name (expr, loc) -> + if + Micheline.strip_locations + (Michelson_v1_macros.unexpand_rec (Micheline.root expr)) + = parsed.Michelson_v1_parser.unexpanded + then find_location loc + else find_location 0 + | _ -> find_location 0 ) + in + let message = + Format.asprintf + "%a" + (Michelson_v1_error_reporter.report_errors + ~details:false + ~show_source:false + ~parsed) + errs + in + let {start = {point = s; _}; stop = {point = e; _}} = loc in + Format.fprintf ppf "(%d %d %S)" (s + 1) (e + 1) message + | [] -> ()) + eco + (Format.pp_print_list (fun ppf err -> + let find_location loc = + let oloc = + WithExceptions.Option.get ~loc:__LOC__ + @@ List.assoc + ~equal:Int.equal + loc + parsed.Michelson_v1_parser.unexpansion_table + in + fst + (WithExceptions.Option.get ~loc:__LOC__ + @@ List.assoc ~equal:Int.equal oloc parsed.expansion_table) + in + let loc = + match err with + | Invalid_utf8_sequence (point, _) + | Unexpected_character (point, _) + | Undefined_escape_sequence (point, _) + | Missing_break_after_number point -> + {start = point; stop = point} + | Unterminated_string loc + | Unterminated_integer loc + | Unterminated_comment loc + | Odd_lengthed_bytes loc + | Unclosed {loc; _} + | Unexpected {loc; _} + | Extra {loc; _} -> + loc + | Misaligned node -> location node + | _ -> find_location 0 + in + let message = + Format.asprintf + "%a" + (Michelson_v1_error_reporter.report_errors + ~details:false + ~show_source:false + ~parsed) + [err] + in + let {start = {point = s; _}; stop = {point = e; _}} = loc in + Format.fprintf ppf "(%d %d %S)" (s + 1) (e + 1) message)) + out diff --git a/src/proto_011_PtHangzH/lib_client/michelson_v1_emacs.mli b/src/proto_011_PtHangzH/lib_client/michelson_v1_emacs.mli new file mode 100644 index 000000000000..6694308d4b02 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/michelson_v1_emacs.mli @@ -0,0 +1,39 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +val print_expr : Format.formatter -> Script.expr -> unit + +val print_type_map : + Format.formatter -> + Michelson_v1_parser.parsed * Script_tc_errors.type_map -> + unit + +val report_errors : + Format.formatter -> + Michelson_v1_parser.parsed * Error_monad.error list -> + unit diff --git a/src/proto_011_PtHangzH/lib_client/michelson_v1_entrypoints.ml b/src/proto_011_PtHangzH/lib_client/michelson_v1_entrypoints.ml new file mode 100644 index 000000000000..e2b69532d45f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/michelson_v1_entrypoints.ml @@ -0,0 +1,216 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Protocol_client_context +open Alpha_context + +type error += Contract_without_code of Contract.t + +let () = + register_error_kind + `Permanent + ~id:"contractWithoutCode" + ~title:"The given contract has no code" + ~description: + "Attempt to get the code of a contract failed because it has nocode. No \ + scriptless contract should remain." + ~pp:(fun ppf contract -> + Format.fprintf ppf "Contract has no code %a." Contract.pp contract) + Data_encoding.(obj1 (req "contract" Contract.encoding)) + (function Contract_without_code c -> Some c | _ -> None) + (fun c -> Contract_without_code c) + +let print_errors (cctxt : #Client_context.printer) errs = + cctxt#error "%a" Error_monad.pp_print_error errs >>= fun () -> return_unit + +let script_entrypoint_type cctxt ~(chain : Chain_services.chain) ~block + (program : Script.expr) ~entrypoint = + Plugin.RPC.Scripts.entrypoint_type + cctxt + (chain, block) + ~script:program + ~entrypoint + >>= function + | Ok ty -> return_some ty + | Error + (Environment.Ecoproto_error (Script_tc_errors.No_such_entrypoint _) :: _) + -> + return None + | Error _ as err -> Lwt.return err + +let contract_entrypoint_type cctxt ~(chain : Chain_services.chain) ~block + ~contract ~entrypoint = + Alpha_services.Contract.entrypoint_type + cctxt + (chain, block) + contract + entrypoint + >>= function + | Ok ty -> return_some ty + | Error (RPC_context.Not_found _ :: _) -> return None + | Error _ as err -> Lwt.return err + +let print_entrypoint_type (cctxt : #Client_context.printer) + ?(on_errors = print_errors cctxt) ~emacs ?contract ?script_name ~entrypoint + = function + | Ok (Some ty) -> + (if emacs then + cctxt#message + "@[((entrypoint . %s) (type . %a))@]@." + entrypoint + Michelson_v1_emacs.print_expr + ty + else + cctxt#message + "@[Entrypoint %s: %a@]@." + entrypoint + Michelson_v1_printer.print_expr + ty) + >>= fun () -> return_unit + | Ok None -> + cctxt#message + "@[No entrypoint named %s%a%a@]@." + entrypoint + (Format.pp_print_option (fun ppf -> + Format.fprintf ppf " for contract %a" Contract.pp)) + contract + (Format.pp_print_option (fun ppf -> Format.fprintf ppf " for script %s")) + script_name + >>= fun () -> return_unit + | Error errs -> on_errors errs + +let list_contract_unreachables_and_entrypoints cctxt ~chain ~block ~contract = + Alpha_services.Contract.list_entrypoints cctxt (chain, block) contract + +let list_contract_unreachables cctxt ~chain ~block ~contract = + list_contract_unreachables_and_entrypoints cctxt ~chain ~block ~contract + >>=? fun (unreachables, _) -> return unreachables + +let list_contract_entrypoints cctxt ~chain ~block ~contract = + list_contract_unreachables_and_entrypoints cctxt ~chain ~block ~contract + >>=? fun (_, entrypoints) -> + if not @@ List.mem_assoc ~equal:String.equal "default" entrypoints then + contract_entrypoint_type cctxt ~chain ~block ~contract ~entrypoint:"default" + >>= function + | Ok (Some ty) -> return (("default", ty) :: entrypoints) + | Ok None -> return entrypoints + | Error _ as err -> Lwt.return err + else return entrypoints + +let list_unreachables cctxt ~chain ~block (program : Script.expr) = + Plugin.RPC.Scripts.list_entrypoints cctxt (chain, block) ~script:program + >>=? fun (unreachables, _) -> return unreachables + +let list_entrypoints cctxt ~chain ~block (program : Script.expr) = + Plugin.RPC.Scripts.list_entrypoints cctxt (chain, block) ~script:program + >>=? fun (_, entrypoints) -> + if not @@ List.mem_assoc ~equal:String.equal "default" entrypoints then + script_entrypoint_type cctxt ~chain ~block program ~entrypoint:"default" + >>= function + | Ok (Some ty) -> return (("default", ty) :: entrypoints) + | Ok None -> return entrypoints + | Error _ as err -> Lwt.return err + else return entrypoints + +let print_entrypoints_list (cctxt : #Client_context.printer) + ?(on_errors = print_errors cctxt) ~emacs ?contract ?script_name = function + | Ok entrypoint_list -> + (if emacs then + cctxt#message + "@[(@[%a@])@." + (Format.pp_print_list + ~pp_sep:Format.pp_print_cut + (fun ppf (entrypoint, ty) -> + Format.fprintf + ppf + "@[( ( entrypoint . %s ) ( type . @[%a@]))@]" + entrypoint + Michelson_v1_emacs.print_expr + ty)) + entrypoint_list + else + cctxt#message + "@[Entrypoints%a%a: @,%a@]@." + (Format.pp_print_option (fun ppf -> + Format.fprintf ppf " for contract %a" Contract.pp)) + contract + (Format.pp_print_option (fun ppf -> + Format.fprintf ppf " for script %s")) + script_name + (Format.pp_print_list + ~pp_sep:Format.pp_print_cut + (fun ppf (entrypoint, ty) -> + Format.fprintf + ppf + "@[%s: @[%a@]@]" + entrypoint + Michelson_v1_printer.print_expr + ty)) + entrypoint_list) + >>= fun () -> return_unit + | Error errs -> on_errors errs + +let print_unreachables (cctxt : #Client_context.printer) + ?(on_errors = print_errors cctxt) ~emacs ?contract ?script_name = function + | Ok unreachable -> + (if emacs then + cctxt#message + "@[(@[%a@])@." + (Format.pp_print_list ~pp_sep:Format.pp_print_cut (fun ppf path -> + Format.fprintf + ppf + "@[( unreachable-path . %a )@]" + (Format.pp_print_list + ~pp_sep:Format.pp_print_space + (fun ppf prim -> + Format.pp_print_string ppf + @@ Michelson_v1_primitives.string_of_prim prim)) + path)) + unreachable + else + match unreachable with + | [] -> cctxt#message "@[None.@]@." + | _ -> + cctxt#message + "@[Unreachable paths in the argument%a%a: @[%a@]@." + (Format.pp_print_option (fun ppf -> + Format.fprintf ppf " of contract %a" Contract.pp)) + contract + (Format.pp_print_option (fun ppf -> + Format.fprintf ppf " of script %s")) + script_name + (Format.pp_print_list ~pp_sep:Format.pp_print_cut (fun ppf -> + Format.fprintf + ppf + "@[ %a @]" + (Format.pp_print_list + ~pp_sep:(fun ppf _ -> Format.pp_print_string ppf "/") + (fun ppf prim -> + Format.pp_print_string ppf + @@ Michelson_v1_primitives.string_of_prim prim)))) + unreachable) + >>= fun () -> return_unit + | Error errs -> on_errors errs diff --git a/src/proto_011_PtHangzH/lib_client/michelson_v1_entrypoints.mli b/src/proto_011_PtHangzH/lib_client/michelson_v1_entrypoints.mli new file mode 100644 index 000000000000..96d3ad82c2f0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/michelson_v1_entrypoints.mli @@ -0,0 +1,108 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(** Returns [Some type] if the contract has an entrypoint of type [type]. None if it does not exists. *) +val script_entrypoint_type : + #Protocol_client_context.rpc_context -> + chain:Chain_services.chain -> + block:Block_services.block -> + Alpha_context.Script.expr -> + entrypoint:string -> + Alpha_context.Script.expr option tzresult Lwt.t + +(** Returns [Some type] if the script has an entrypoint of type [type]. None if it does not exists. *) +val contract_entrypoint_type : + #Protocol_client_context.rpc_context -> + chain:Chain_services.chain -> + block:Block_services.block -> + contract:Alpha_context.Contract.t -> + entrypoint:string -> + Alpha_context.Script.expr option tzresult Lwt.t + +val print_entrypoint_type : + #Client_context.printer -> + ?on_errors:(error list -> unit tzresult Lwt.t) -> + emacs:bool -> + ?contract:Alpha_context.Contract.t -> + ?script_name:string -> + entrypoint:string -> + Alpha_context.Script.expr option tzresult -> + unit tzresult Lwt.t + +(** List paths of unreachable parameters. + Only useful to test the stitching, as no such parameter should be + allowed in originated contracts. *) +val list_contract_unreachables : + #Protocol_client_context.rpc_context -> + chain:Chain_services.chain -> + block:Block_services.block -> + contract:Alpha_context.Contract.t -> + Michelson_v1_primitives.prim list list tzresult Lwt.t + +val list_unreachables : + #Protocol_client_context.rpc_context -> + chain:Chain_services.chain -> + block:Block_services.block -> + Alpha_context.Script.expr -> + Michelson_v1_primitives.prim list list tzresult Lwt.t + +val print_unreachables : + #Client_context.printer -> + ?on_errors:(error list -> unit tzresult Lwt.t) -> + emacs:bool -> + ?contract:Alpha_context.Contract.t -> + ?script_name:string -> + Michelson_v1_primitives.prim list list tzresult -> + unit tzresult Lwt.t + +(** List the contract entrypoints with their types. + If their is no explicit default, th type of default entrypoint will still be given. +*) +val list_contract_entrypoints : + #Protocol_client_context.rpc_context -> + chain:Chain_services.chain -> + block:Block_services.block -> + contract:Alpha_context.Contract.t -> + (string * Alpha_context.Script.expr) list tzresult Lwt.t + +(** List the script entrypoints with their types. *) +val list_entrypoints : + #Protocol_client_context.rpc_context -> + chain:Chain_services.chain -> + block:Block_services.block -> + Alpha_context.Script.expr -> + (string * Alpha_context.Script.expr) list tzresult Lwt.t + +(** Print the contract entrypoints with their types. *) +val print_entrypoints_list : + #Client_context.printer -> + ?on_errors:(error list -> unit tzresult Lwt.t) -> + emacs:bool -> + ?contract:Alpha_context.Contract.t -> + ?script_name:string -> + (string * Alpha_context.Script.expr) list tzresult -> + unit tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_client/michelson_v1_error_reporter.ml b/src/proto_011_PtHangzH/lib_client/michelson_v1_error_reporter.ml new file mode 100644 index 000000000000..93d58a5cd984 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/michelson_v1_error_reporter.ml @@ -0,0 +1,773 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Tezos_micheline +open Script_tc_errors +open Script_interpreter +open Michelson_v1_printer + +let print_ty ppf ty = Michelson_v1_printer.print_expr_unwrapped ppf ty + +let print_var_annot ppf annot = List.iter (Format.fprintf ppf "@ %s") annot + +let print_stack_ty ?(depth = max_int) ppf s = + let rec loop depth ppf = function + | [] -> () + | _ when depth <= 0 -> Format.fprintf ppf "..." + | [(last, annot)] -> + Format.fprintf ppf "%a%a" print_ty last print_var_annot annot + | (last, annot) :: rest -> + Format.fprintf + ppf + "%a%a@ :@ %a" + print_ty + last + print_var_annot + annot + (loop (depth - 1)) + rest + in + match s with + | [] -> Format.fprintf ppf "[]" + | sty -> Format.fprintf ppf "@[[ %a ]@]" (loop depth) sty + +let rec print_enumeration ppf = function + | [single] -> Format.fprintf ppf "%a" Format.pp_print_text single + | [prev; last] -> + Format.fprintf + ppf + "%a@ or@ %a" + Format.pp_print_text + prev + Format.pp_print_text + last + | first :: rest -> + Format.fprintf + ppf + "%a,@ %a" + Format.pp_print_text + first + print_enumeration + rest + | [] -> assert false + +let collect_error_locations errs = + let rec collect acc = function + | Environment.Ecoproto_error + ( Ill_formed_type (_, _, _) + | No_such_entrypoint _ | Duplicate_entrypoint _ + | Unreachable_entrypoint _ + | Runtime_contract_error (_, _) + | Michelson_v1_primitives.Invalid_primitive_name (_, _) + | Ill_typed_data (_, _, _) + | Ill_typed_contract (_, _) ) + :: _ + | [] -> + acc + | Environment.Ecoproto_error + ( Invalid_arity (loc, _, _, _) + | Invalid_seq_arity (loc, _, _) + | Inconsistent_type_annotations (loc, _, _) + | Unexpected_annotation loc + | Ungrouped_annotations loc + | Type_too_large (loc, _) + | Invalid_namespace (loc, _, _, _) + | Invalid_primitive (loc, _, _) + | Invalid_kind (loc, _, _) + | Invalid_never_expr loc + | Duplicate_field (loc, _) + | Unexpected_lazy_storage loc + | Unexpected_operation loc + | Fail_not_in_tail_position loc + | Undefined_binop (loc, _, _, _) + | Undefined_unop (loc, _, _) + | Bad_return (loc, _, _) + | Bad_stack (loc, _, _, _) + | Unmatched_branches (loc, _, _) + | Self_in_lambda loc + | Invalid_constant (loc, _, _) + | Invalid_syntactic_constant (loc, _, _) + | Invalid_contract (loc, _) + | Comparable_type_expected (loc, _) + | Overflow (loc, _) + | Reject (loc, _, _) + | Pair_bad_argument loc + | Unpair_bad_argument loc + | Dup_n_bad_argument loc ) + :: rest -> + collect (loc :: acc) rest + | _ :: rest -> collect acc rest + in + collect [] errs + +let report_errors ~details ~show_source ?parsed ppf errs = + let rec print_trace locations errs = + let print_loc ppf loc = + match locations loc with + | None -> Format.fprintf ppf "At (unshown) location %d, " loc + | Some loc -> + Format.fprintf + ppf + "%s,@ " + (String.capitalize_ascii + (Format.asprintf "%a" Micheline_parser.print_location loc)) + in + let parsed_locations parsed loc = + let ( >?? ) = Option.bind in + List.assoc + ~equal:Int.equal + loc + parsed.Michelson_v1_parser.unexpansion_table + >?? fun oloc -> + List.assoc ~equal:Int.equal oloc parsed.expansion_table + >?? fun (ploc, _) -> Some ploc + in + let print_source ppf (parsed, _hilights) (* TODO *) = + let lines = String.split_on_char '\n' parsed.Michelson_v1_parser.source in + let cols = String.length (string_of_int (List.length lines)) in + Format.fprintf + ppf + "@[%a@]" + (Format.pp_print_list (fun ppf (i, l) -> + Format.fprintf ppf "%0*d: %s" cols i l)) + (List.rev_mapi (fun i x -> (i + 1, x)) lines |> List.rev) + in + match errs with + | [] -> () + | Environment.Ecoproto_error + (Michelson_v1_primitives.Invalid_primitive_name (expr, loc)) + :: rest -> + let parsed = + match parsed with + | Some parsed -> + if + Micheline.strip_locations + (Michelson_v1_macros.unexpand_rec (Micheline.root expr)) + = parsed.Michelson_v1_parser.unexpanded + then parsed + else Michelson_v1_printer.unparse_invalid expr + | None -> Michelson_v1_printer.unparse_invalid expr + in + let hilights = loc :: collect_error_locations rest in + if show_source then + Format.fprintf + ppf + "@[@[Invalid primitive:@ %a@]@]" + print_source + (parsed, hilights) + else Format.fprintf ppf "Invalid primitive." ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace (parsed_locations parsed) rest + | Environment.Ecoproto_error (Ill_typed_data (name, expr, ty)) :: rest -> + let parsed = + match parsed with + | Some parsed when expr = parsed.Michelson_v1_parser.expanded -> + parsed + | Some _ | None -> Michelson_v1_printer.unparse_expression expr + in + let hilights = collect_error_locations rest in + Format.fprintf + ppf + "@[@[Ill typed %adata:@ %a@]@ @[is not an \ + expression of type@ %a@]@]" + (fun ppf -> function + | None -> () + | Some s -> Format.fprintf ppf "%s " s) + name + print_source + (parsed, hilights) + print_ty + ty ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace (parsed_locations parsed) rest + | Environment.Ecoproto_error (No_such_entrypoint entrypoint) :: rest -> + Format.fprintf ppf "Contract has no entrypoint named %s" entrypoint ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error (Duplicate_entrypoint entrypoint) :: rest -> + Format.fprintf ppf "Contract has two entrypoints named %s" entrypoint ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error (Unreachable_entrypoint path) :: rest -> + let path = + String.concat + "/" + (List.map Michelson_v1_primitives.string_of_prim path) + in + Format.fprintf ppf "Entrypoint at path %s is not reachable" path ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error (Ill_formed_type (_, expr, loc)) :: rest -> + let parsed = + match parsed with + | Some parsed when expr = parsed.Michelson_v1_parser.expanded -> + parsed + | Some _ | None -> Michelson_v1_printer.unparse_expression expr + in + let hilights = loc :: collect_error_locations errs in + if show_source then + Format.fprintf + ppf + "@[%aill formed type:@ %a@]" + print_loc + loc + print_source + (parsed, hilights) + else Format.fprintf ppf "Ill formed type." ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace (parsed_locations parsed) rest + | Environment.Ecoproto_error (Ill_typed_contract (expr, type_map)) :: rest + -> + let parsed = + match parsed with + | Some parsed + when (not details) && expr = parsed.Michelson_v1_parser.expanded -> + parsed + | Some _ | None -> + Michelson_v1_printer.unparse_toplevel ~type_map expr + in + let hilights = collect_error_locations rest in + if show_source then + Format.fprintf + ppf + "@[Ill typed contract:@, %a@]" + print_source + (parsed, hilights) + else Format.fprintf ppf "Ill typed contract." ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace (parsed_locations parsed) rest + | Environment.Ecoproto_error Apply.Gas_quota_exceeded_init_deserialize + :: rest -> + Format.fprintf + ppf + "@[Not enough gas to deserialize the operation.@,\ + Injecting such a transaction could have you banned from mempools.@]" ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error Cannot_serialize_error :: rest -> + Format.fprintf + ppf + "Error too big to serialize within the provided gas bounds." ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error (Deprecated_instruction prim) :: rest -> + Format.fprintf + ppf + "@[Use of deprecated instruction: %s@]" + (Michelson_v1_primitives.string_of_prim prim) ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error Cannot_serialize_storage :: rest -> + Format.fprintf + ppf + "Cannot serialize the resulting storage value within the provided \ + gas bounds." ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error (Missing_field prim) :: rest -> + Format.fprintf + ppf + "@[Missing contract field: %s@]" + (Michelson_v1_primitives.string_of_prim prim) ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error (Duplicate_field (loc, prim)) :: rest -> + Format.fprintf + ppf + "@[%aduplicate contract field: %s@]" + print_loc + loc + (Michelson_v1_primitives.string_of_prim prim) ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error (Unexpected_lazy_storage loc) :: rest -> + Format.fprintf + ppf + "%abig_map or sapling_state type not expected here" + print_loc + loc ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error (Unexpected_operation loc) :: rest -> + Format.fprintf + ppf + "%aoperation type forbidden in parameter, storage and constants" + print_loc + loc ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error (Unexpected_contract loc) :: rest -> + Format.fprintf + ppf + "%acontract type forbidden in storage and constants" + print_loc + loc ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error (Runtime_contract_error (contract, expr)) + :: rest -> + let parsed = + match parsed with + | Some parsed when expr = parsed.Michelson_v1_parser.expanded -> + parsed + | Some _ | None -> Michelson_v1_printer.unparse_toplevel expr + in + let hilights = collect_error_locations rest in + Format.fprintf + ppf + "@[Runtime error in contract %a:@ %a@]" + Contract.pp + contract + print_source + (parsed, hilights) ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace (parsed_locations parsed) rest + | Environment.Ecoproto_error (Apply.Internal_operation_replay op) :: rest -> + Format.fprintf + ppf + "@[Internal operation replay attempt:@,%a@]" + Operation_result.pp_internal_operation + op ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error Gas.Gas_limit_too_high :: rest -> + Format.fprintf + ppf + "Gas limit for the operation is out of the protocol hard bounds." ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error Gas.Block_quota_exceeded :: rest -> + Format.fprintf + ppf + "Gas limit for the block exceeded during typechecking or execution." ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error Gas.Operation_quota_exceeded :: rest -> + Format.fprintf + ppf + "@[Gas limit exceeded during typechecking or execution.@,\ + Try again with a higher gas limit.@]" ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | Environment.Ecoproto_error Fees.Operation_quota_exceeded :: rest -> + Format.fprintf + ppf + "@[Storage limit exceeded during typechecking or execution.@,\ + Try again with a higher storage limit.@]" ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | [Environment.Ecoproto_error (Script_interpreter.Bad_contract_parameter c)] + -> + Format.fprintf + ppf + "@[Account %a is not a smart contract, it does not take \ + arguments.@,\ + The `-arg' flag should not be used when transferring to an \ + account.@]" + Contract.pp + c + | Environment.Ecoproto_error err :: rest -> + (match err with + | Script_interpreter.Bad_contract_parameter c -> + Format.fprintf + ppf + "Invalid argument passed to contract %a." + Contract.pp + c + | Invalid_arity (loc, name, exp, got) -> + Format.fprintf + ppf + "%aprimitive %s expects %d arguments but is given %d." + print_loc + loc + (Michelson_v1_primitives.string_of_prim name) + exp + got + | Invalid_seq_arity (loc, exp, got) -> + Format.fprintf + ppf + "%asequence expects at least %d elements but is given %d." + print_loc + loc + exp + got + | Invalid_namespace (loc, name, exp, got) -> + let human_namespace = function + | Michelson_v1_primitives.Instr_namespace -> ("an", "instruction") + | Type_namespace -> ("a", "type name") + | Constant_namespace -> ("a", "constant constructor") + | Keyword_namespace -> ("a", "keyword") + | Constant_hash_namespace -> ("a", "constant hash") + in + Format.fprintf + ppf + "@[%aunexpected %s %s, only %s %s can be used here." + print_loc + loc + (snd (human_namespace got)) + (Michelson_v1_primitives.string_of_prim name) + (fst (human_namespace exp)) + (snd (human_namespace exp)) + | Invalid_primitive (loc, exp, got) -> + Format.fprintf + ppf + "@[%ainvalid primitive %s, only %a can be used here." + print_loc + loc + (Michelson_v1_primitives.string_of_prim got) + print_enumeration + (List.map Michelson_v1_primitives.string_of_prim exp) + | Invalid_kind (loc, exp, got) -> + let human_kind = function + | Seq_kind -> ("a", "sequence") + | Prim_kind -> ("a", "primitive") + | Int_kind -> ("an", "int") + | String_kind -> ("a", "string") + | Bytes_kind -> ("a", "byte sequence") + in + Format.fprintf + ppf + "@[%aunexpected %s, only@ %a@ can be used here." + print_loc + loc + (snd (human_kind got)) + print_enumeration + (List.map + (fun k -> + let (a, n) = human_kind k in + a ^ " " ^ n) + exp) + | Invalid_never_expr loc -> + Format.fprintf + ppf + "@[%athis expression should have type never but type never has \ + no inhabitant." + print_loc + loc + | Duplicate_map_keys (_, expr) -> + Format.fprintf + ppf + "@[Map literals cannot contain duplicate keys, however a \ + duplicate key was found:@ @[%a@]" + print_expr + expr + | Unordered_map_keys (_, expr) -> + Format.fprintf + ppf + "@[Keys in a map literal must be in strictly ascending \ + order, but they were unordered in literal:@ @[%a@]" + print_expr + expr + | Duplicate_set_values (_, expr) -> + Format.fprintf + ppf + "@[Set literals cannot contain duplicate values, however a \ + duplicate value was found:@ @[%a@]" + print_expr + expr + | Unordered_set_values (_, expr) -> + Format.fprintf + ppf + "@[Values in a set literal must be in strictly ascending \ + order, but they were unordered in literal:@ @[%a@]" + print_expr + expr + | Fail_not_in_tail_position loc -> + Format.fprintf + ppf + "%aThe FAIL instruction must appear in a tail position." + print_loc + loc + | Undefined_binop (loc, name, tya, tyb) -> + Format.fprintf + ppf + "@[@[%aoperator %s is undefined between@ %a@]@ \ + @[and@ %a.@]@]" + print_loc + loc + (Michelson_v1_primitives.string_of_prim name) + print_ty + tya + print_ty + tyb + | Undefined_unop (loc, name, ty) -> + Format.fprintf + ppf + "@[@[%aoperator %s is undefined on@ %a@]@]" + print_loc + loc + (Michelson_v1_primitives.string_of_prim name) + print_ty + ty + | Bad_return (loc, got, exp) -> + Format.fprintf + ppf + "@[%awrong stack type at end of body:@,\ + - @[expected return stack type:@ %a,@]@,\ + - @[actual stack type:@ %a.@]@]" + print_loc + loc + (fun ppf -> print_stack_ty ppf) + [(exp, [])] + (fun ppf -> print_stack_ty ppf) + got + | Bad_stack (loc, name, depth, sty) -> + Format.fprintf + ppf + "@[%awrong stack type for instruction %s:@ %a.@]" + print_loc + loc + (Michelson_v1_primitives.string_of_prim name) + (print_stack_ty ~depth) + sty + | Unmatched_branches (loc, sta, stb) -> + Format.fprintf + ppf + "@[%atwo branches don't end with the same stack type:@,\ + - @[first stack type:@ %a,@]@,\ + - @[other stack type:@ %a.@]@]" + print_loc + loc + (fun ppf -> print_stack_ty ppf) + sta + (fun ppf -> print_stack_ty ppf) + stb + | Bad_view_name loc -> + Format.fprintf + ppf + "@[%athe name of view should be of type string @]" + print_loc + loc + | Duplicated_view_name loc -> + Format.fprintf + ppf + "@[%athe name of view in toplevel should be unique @]" + print_loc + loc + | Ill_typed_view {loc; actual; expected} -> + Format.fprintf + ppf + "@[%athe return of a view block did not match the expected \ + type.@,\ + - @[resulted view stack type:@ %a,@]@,\ + - @[expected view stack type:@ %a.@]@]" + print_loc + loc + (fun ppf -> print_stack_ty ppf) + actual + (fun ppf -> print_stack_ty ppf) + expected + | View_name_too_long name -> + Format.fprintf + ppf + "@[ A view name, \"%s\", exceeds the maximum length of 31 \ + characters." + name + | Inconsistent_annotations (annot1, annot2) -> + Format.fprintf + ppf + "@[The two annotations do not match:@,\ + - @[%s@]@,\ + - @[%s@]@]" + annot1 + annot2 + | Inconsistent_field_annotations (annot1, annot2) -> + Format.fprintf + ppf + "@[The field access annotation does not match:@,\ + - @[%s@]@,\ + - @[%s@]@]" + annot1 + annot2 + | Inconsistent_type_annotations (loc, ty1, ty2) -> + Format.fprintf + ppf + "@[%athe two types contain incompatible annotations:@,\ + - @[%a@]@,\ + - @[%a@]@]" + print_loc + loc + print_ty + ty1 + print_ty + ty2 + | Inconsistent_type_sizes (size1, size2) -> + Format.fprintf + ppf + "@[The two types have different sizes, the first one is of \ + size %d while the other one is of size %d@]" + size1 + size2 + | Unexpected_annotation loc -> + Format.fprintf ppf "@[%aunexpected annotation." print_loc loc + | Ungrouped_annotations loc -> + Format.fprintf + ppf + "@[%aAnnotations of the same kind must be grouped." + print_loc + loc + | Type_too_large (loc, maximum_size) -> + Format.fprintf + ppf + "@[%atype exceeded maximum type size (%d)." + print_loc + loc + maximum_size + | Pair_bad_argument loc -> + Format.fprintf + ppf + "%aPAIR expects an argument of at least 2." + print_loc + loc + | Unpair_bad_argument loc -> + Format.fprintf + ppf + "%aUNPAIR expects an argument of at least 2." + print_loc + loc + | Dup_n_bad_argument loc -> + Format.fprintf + ppf + "%aDUP n expects an argument of at least 1 (passed 0)." + print_loc + loc + | Self_in_lambda loc -> + Format.fprintf + ppf + "%aThe SELF instruction cannot appear in a lambda." + print_loc + loc + | Non_dupable_type (loc, ty) -> + Format.fprintf + ppf + "%atype %a cannot be used here because it is not duplicable. \ + Only duplicable types can be used with the DUP instruction and \ + as view inputs and outputs." + print_loc + loc + print_ty + ty + | Unexpected_ticket loc -> + Format.fprintf + ppf + "%aTicket in unauthorized position (type error)." + print_loc + loc + | Bad_stack_length -> Format.fprintf ppf "Bad stack length." + | Bad_stack_item lvl -> Format.fprintf ppf "Bad stack item %d." lvl + | Unexpected_forged_value loc -> + Format.fprintf ppf "%aUnexpected forged value." print_loc loc + | Invalid_constant (loc, got, exp) -> + Format.fprintf + ppf + "@[@[%avalue@ %a@]@ @[is invalid for type@ \ + %a.@]@]" + print_loc + loc + print_expr + got + print_ty + exp + | Invalid_syntactic_constant (loc, got, exp) -> + Format.fprintf + ppf + "@[@[%avalue@ %a@]@ @[is invalid, expected@ \ + %s@]@]" + print_loc + loc + print_expr + got + exp + | Invalid_contract (loc, contract) -> + Format.fprintf + ppf + "%ainvalid contract %a." + print_loc + loc + Contract.pp + contract + | Comparable_type_expected (loc, ty) -> + Format.fprintf ppf "%acomparable type expected." print_loc loc ; + Format.fprintf + ppf + "@[@[Type@ %a@]@ is not comparable.@]" + print_ty + ty + | Inconsistent_types (opt_loc, tya, tyb) -> + Format.fprintf + ppf + "@[@[%aType@ %a@]@ @[is not compatible with \ + type@ %a.@]@]" + (fun fmt -> function None -> () | Some loc -> print_loc fmt loc) + opt_loc + print_ty + tya + print_ty + tyb + | Reject (loc, v, trace) -> + Format.fprintf + ppf + "%ascript reached FAILWITH instruction@ @[with@ %a@]%a" + print_loc + loc + print_expr + v + (fun ppf -> function + | None -> () + | Some trace -> + Format.fprintf + ppf + "@,@[trace@,%a@]" + print_execution_trace + trace) + trace + | Overflow (loc, trace) -> + Format.fprintf + ppf + "%aunexpected arithmetic overflow%a" + print_loc + loc + (fun ppf -> function + | None -> () + | Some trace -> + Format.fprintf + ppf + "@,@[trace@,%a@]" + print_execution_trace + trace) + trace + | err -> Format.fprintf ppf "%a" Environment.Error_monad.pp err) ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + | err :: rest -> + Format.fprintf ppf "%a" Error_monad.pp err ; + if rest <> [] then Format.fprintf ppf "@," ; + print_trace locations rest + in + Format.fprintf ppf "@[" ; + print_trace (fun _ -> None) errs ; + Format.fprintf ppf "@]" diff --git a/src/proto_011_PtHangzH/lib_client/michelson_v1_error_reporter.mli b/src/proto_011_PtHangzH/lib_client/michelson_v1_error_reporter.mli new file mode 100644 index 000000000000..e1bbea6eb12c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/michelson_v1_error_reporter.mli @@ -0,0 +1,32 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val report_errors : + details:bool -> + show_source:bool -> + ?parsed:Michelson_v1_parser.parsed -> + Format.formatter -> + Error_monad.error list -> + unit diff --git a/src/proto_011_PtHangzH/lib_client/michelson_v1_helpers.ml b/src/proto_011_PtHangzH/lib_client/michelson_v1_helpers.ml new file mode 100644 index 000000000000..40d1698fff37 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/michelson_v1_helpers.ml @@ -0,0 +1,60 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Generic Michelson building functions *) + +open Tezos_micheline.Micheline +open Protocol.Alpha_context.Script + +let seq ~loc l = Seq (loc, l) + +let pair ~loc a b = Prim (loc, D_Pair, [a; b], []) + +let none ~loc () = Prim (loc, D_None, [], []) + +let some ~loc a = Prim (loc, D_Some, [a], []) + +let left ~loc a = Prim (loc, D_Left, [a], []) + +let right ~loc b = Prim (loc, D_Right, [b], []) + +let int ~loc i = Int (loc, i) + +let bytes ~loc s = Bytes (loc, s) + +let unit_t ~loc = Prim (loc, T_unit, [], []) + +let unit ~loc = Prim (loc, D_Unit, [], []) + +let lambda_from_string code = + Tezos_micheline.Micheline_parser.no_parsing_error + @@ Michelson_v1_parser.parse_expression code + >|? fun parsed -> root Michelson_v1_parser.(parsed.expanded) + +let lambda_t ~loc param res = Prim (loc, T_lambda, [param; res], []) + +let operation_t ~loc = Prim (loc, T_operation, [], []) + +let operations_t ~loc = Prim (loc, T_list, [operation_t ~loc], []) diff --git a/src/proto_011_PtHangzH/lib_client/michelson_v1_macros.ml b/src/proto_011_PtHangzH/lib_client/michelson_v1_macros.ml new file mode 100644 index 000000000000..448bd000108e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/michelson_v1_macros.ml @@ -0,0 +1,1519 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol_client_context +open Tezos_micheline +open Micheline +module IntMap = Map.Make (Compare.Int) + +type 'l node = ('l, string) Micheline.node + +type error += Unexpected_macro_annotation of string + +type error += Sequence_expected of string + +type error += Invalid_arity of string * int * int + +let rec check_letters str i j f = + i > j || (f str.[i] && check_letters str (i + 1) j f) + +let expand_caddadr original = + match original with + | Prim (loc, str, args, annot) -> + let len = String.length str in + if + len > 3 + && str.[0] = 'C' + && str.[len - 1] = 'R' + && check_letters str 1 (len - 2) (function + | 'A' | 'D' -> true + | _ -> false) + then + (match args with + | [] -> ok () + | _ :: _ -> error (Invalid_arity (str, List.length args, 0))) + >>? fun () -> + let path_annot = + List.filter (function "@%" | "@%%" -> true | _ -> false) annot + in + let rec parse i acc = + if i = 0 then Seq (loc, acc) + else + let annot = if i = len - 2 then annot else path_annot in + match str.[i] with + | 'A' -> parse (i - 1) (Prim (loc, "CAR", [], annot) :: acc) + | 'D' -> parse (i - 1) (Prim (loc, "CDR", [], annot) :: acc) + | _ -> assert false + in + ok (Some (parse (len - 2) [])) + else ok None + | _ -> ok None + +let expand_carn original = + match original with + | Prim (loc, "CAR", [Int (loc2, n)], annot) -> + ok + (Some + (Seq + ( loc, + [ + Prim + ( loc, + "GET", + [Int (loc2, Z.(of_int 1 + (n * of_int 2)))], + annot ); + ] ))) + | _ -> ok None + +let expand_cdrn original = + match original with + | Prim (loc, "CDR", [Int (loc2, n)], annot) -> + ok + (Some + (Seq (loc, [Prim (loc, "GET", [Int (loc2, Z.(n * of_int 2))], annot)]))) + | _ -> ok None + +let extract_field_annots annot = + List.partition + (fun a -> + match a.[0] with + | '%' -> true + | _ -> false + | exception Invalid_argument _ -> false) + annot + +let expand_set_caddadr original = + match original with + | Prim (loc, str, args, annot) -> + let len = String.length str in + if + len >= 7 + && String.sub str 0 5 = "SET_C" + && str.[len - 1] = 'R' + && check_letters str 5 (len - 2) (function + | 'A' | 'D' -> true + | _ -> false) + then + (match args with + | [] -> ok () + | _ :: _ -> error (Invalid_arity (str, List.length args, 0))) + >>? fun () -> + (match extract_field_annots annot with + | ([], annot) -> ok (None, annot) + | ([f], annot) -> ok (Some f, annot) + | (_, _) -> error (Unexpected_macro_annotation str)) + >>? fun (field_annot, annot) -> + let rec parse i acc = + if i = 4 then acc + else + let annot = if i = 5 then annot else [] in + match str.[i] with + | 'A' -> + let acc = + Seq + ( loc, + [ + Prim (loc, "DUP", [], []); + Prim + ( loc, + "DIP", + [Seq (loc, [Prim (loc, "CAR", [], ["@%%"]); acc])], + [] ); + Prim (loc, "CDR", [], ["@%%"]); + Prim (loc, "SWAP", [], []); + Prim (loc, "PAIR", [], "%@" :: "%@" :: annot); + ] ) + in + parse (i - 1) acc + | 'D' -> + let acc = + Seq + ( loc, + [ + Prim (loc, "DUP", [], []); + Prim + ( loc, + "DIP", + [Seq (loc, [Prim (loc, "CDR", [], ["@%%"]); acc])], + [] ); + Prim (loc, "CAR", [], ["@%%"]); + Prim (loc, "PAIR", [], "%@" :: "%@" :: annot); + ] ) + in + parse (i - 1) acc + | _ -> assert false + in + match str.[len - 2] with + | 'A' -> + let access_check = + match field_annot with + | None -> [] + | Some f -> + [ + Prim (loc, "DUP", [], []); + Prim (loc, "CAR", [], [f]); + Prim (loc, "DROP", [], []); + ] + in + let encoding = + [Prim (loc, "CDR", [], ["@%%"]); Prim (loc, "SWAP", [], [])] + in + let pair = + [ + Prim + ( loc, + "PAIR", + [], + [Option.value field_annot ~default:"%"; "%@"] ); + ] + in + let init = Seq (loc, access_check @ encoding @ pair) in + ok (Some (parse (len - 3) init)) + | 'D' -> + let access_check = + match field_annot with + | None -> [] + | Some f -> + [ + Prim (loc, "DUP", [], []); + Prim (loc, "CDR", [], [f]); + Prim (loc, "DROP", [], []); + ] + in + let encoding = [Prim (loc, "CAR", [], ["@%%"])] in + let pair = + [ + Prim + ( loc, + "PAIR", + [], + ["%@"; Option.value field_annot ~default:"%"] ); + ] + in + let init = Seq (loc, access_check @ encoding @ pair) in + ok (Some (parse (len - 3) init)) + | _ -> assert false + else ok None + | _ -> ok None + +let expand_map_caddadr original = + match original with + | Prim (loc, str, args, annot) -> + let len = String.length str in + if + len >= 7 + && String.sub str 0 5 = "MAP_C" + && str.[len - 1] = 'R' + && check_letters str 5 (len - 2) (function + | 'A' | 'D' -> true + | _ -> false) + then + (match args with + | [(Seq _ as code)] -> ok code + | [_] -> error (Sequence_expected str) + | [] | _ :: _ :: _ -> error (Invalid_arity (str, List.length args, 1))) + >>? fun code -> + (match extract_field_annots annot with + | ([], annot) -> ok (None, annot) + | ([f], annot) -> ok (Some f, annot) + | (_, _) -> error (Unexpected_macro_annotation str)) + >>? fun (field_annot, annot) -> + let rec parse i acc = + if i = 4 then acc + else + let annot = if i = 5 then annot else [] in + match str.[i] with + | 'A' -> + let acc = + Seq + ( loc, + [ + Prim (loc, "DUP", [], []); + Prim + ( loc, + "DIP", + [Seq (loc, [Prim (loc, "CAR", [], ["@%%"]); acc])], + [] ); + Prim (loc, "CDR", [], ["@%%"]); + Prim (loc, "SWAP", [], []); + Prim (loc, "PAIR", [], "%@" :: "%@" :: annot); + ] ) + in + parse (i - 1) acc + | 'D' -> + let acc = + Seq + ( loc, + [ + Prim (loc, "DUP", [], []); + Prim + ( loc, + "DIP", + [Seq (loc, [Prim (loc, "CDR", [], ["@%%"]); acc])], + [] ); + Prim (loc, "CAR", [], ["@%%"]); + Prim (loc, "PAIR", [], "%@" :: "%@" :: annot); + ] ) + in + parse (i - 1) acc + | _ -> assert false + in + let cr_annot = + match field_annot with + | None -> [] + | Some f -> ["@" ^ String.sub f 1 (String.length f - 1)] + in + match str.[len - 2] with + | 'A' -> + let init = + Seq + ( loc, + [ + Prim (loc, "DUP", [], []); + Prim (loc, "CDR", [], ["@%%"]); + Prim + ( loc, + "DIP", + [Seq (loc, [Prim (loc, "CAR", [], cr_annot); code])], + [] ); + Prim (loc, "SWAP", [], []); + Prim + ( loc, + "PAIR", + [], + [Option.value field_annot ~default:"%"; "%@"] ); + ] ) + in + ok (Some (parse (len - 3) init)) + | 'D' -> + let init = + Seq + ( loc, + [ + Prim (loc, "DUP", [], []); + Prim (loc, "CDR", [], cr_annot); + code; + Prim (loc, "SWAP", [], []); + Prim (loc, "CAR", [], ["@%%"]); + Prim + ( loc, + "PAIR", + [], + ["%@"; Option.value field_annot ~default:"%"] ); + ] ) + in + ok (Some (parse (len - 3) init)) + | _ -> assert false + else ok None + | _ -> ok None + +exception Not_a_roman + +let decimal_of_roman roman = + (* http://rosettacode.org/wiki/Roman_numerals/Decode#OCaml *) + let arabic = ref 0 in + let lastval = ref 0 in + for i = String.length roman - 1 downto 0 do + let n = + match roman.[i] with + | 'M' -> 1000 + | 'D' -> 500 + | 'C' -> 100 + | 'L' -> 50 + | 'X' -> 10 + | 'V' -> 5 + | 'I' -> 1 + | _ -> raise_notrace Not_a_roman + in + if Compare.Int.(n < !lastval) then arabic := !arabic - n + else arabic := !arabic + n ; + lastval := n + done ; + !arabic + +let dip ~loc ?(annot = []) depth instr = + assert (depth >= 0) ; + if depth = 1 then Prim (loc, "DIP", [instr], annot) + else Prim (loc, "DIP", [Int (loc, Z.of_int depth); instr], annot) + +let expand_deprecated_dxiiivp original = + (* transparently expands deprecated macro [DI...IP] to instruction [DIP n] *) + match original with + | Prim (loc, str, args, annot) -> + let len = String.length str in + if len > 3 && str.[0] = 'D' && str.[len - 1] = 'P' then + try + let depth = decimal_of_roman (String.sub str 1 (len - 2)) in + match args with + | [(Seq (_, _) as arg)] -> ok @@ Some (dip ~loc ~annot depth arg) + | [_] -> error (Sequence_expected str) + | [] | _ :: _ :: _ -> error (Invalid_arity (str, List.length args, 1)) + with Not_a_roman -> ok None + else ok None + | _ -> ok None + +exception Not_a_pair + +type pair_item = A | I | P of int * pair_item * pair_item + +let parse_pair_substr str ~len start = + let rec parse ?left i = + if i = len - 1 then raise_notrace Not_a_pair + else if str.[i] = 'P' then + let (next_i, l) = parse ~left:true (i + 1) in + let (next_i, r) = parse ~left:false next_i in + (next_i, P (i, l, r)) + else if str.[i] = 'A' && left = Some true then (i + 1, A) + else if str.[i] = 'I' && left <> Some true then (i + 1, I) + else raise_notrace Not_a_pair + in + let (last, ast) = parse start in + if last <> len - 1 then raise_notrace Not_a_pair else ast + +let unparse_pair_item ast = + let rec unparse ast acc = + match ast with + | P (_, l, r) -> unparse r (unparse l ("P" :: acc)) + | A -> "A" :: acc + | I -> "I" :: acc + in + List.rev ("R" :: unparse ast []) |> String.concat "" + +let pappaiir_annots_pos ast annot = + let rec find_annots_pos p_pos ast annots acc = + match (ast, annots) with + | (_, []) -> (annots, acc) + | (P (i, left, right), _) -> + let (annots, acc) = find_annots_pos i left annots acc in + find_annots_pos i right annots acc + | (A, a :: annots) -> + let pos = + match IntMap.find p_pos acc with + | None -> ([a], []) + | Some (_, cdr) -> ([a], cdr) + in + (annots, IntMap.add p_pos pos acc) + | (I, a :: annots) -> + let pos = + match IntMap.find p_pos acc with + | None -> ([], [a]) + | Some (car, _) -> (car, [a]) + in + (annots, IntMap.add p_pos pos acc) + in + snd (find_annots_pos 0 ast annot IntMap.empty) + +let expand_pappaiir original = + match original with + | Prim (loc, str, args, annot) -> + let len = String.length str in + if + len > 4 + && str.[0] = 'P' + && str.[len - 1] = 'R' + && check_letters str 1 (len - 2) (function + | 'P' | 'A' | 'I' -> true + | _ -> false) + then + try + let (field_annots, annot) = extract_field_annots annot in + let ast = parse_pair_substr str ~len 0 in + let field_annots_pos = pappaiir_annots_pos ast field_annots in + let rec parse p (depth, acc) = + match p with + | P (i, left, right) -> + let annot = + match (i, IntMap.find i field_annots_pos) with + | (0, None) -> annot + | (_, None) -> [] + | (0, Some ([], cdr_annot)) -> "%" :: cdr_annot @ annot + | (_, Some ([], cdr_annot)) -> "%" :: cdr_annot + | (0, Some (car_annot, cdr_annot)) -> + car_annot @ cdr_annot @ annot + | (_, Some (car_annot, cdr_annot)) -> car_annot @ cdr_annot + in + let acc = + if depth = 0 then Prim (loc, "PAIR", [], annot) :: acc + else + dip ~loc depth (Seq (loc, [Prim (loc, "PAIR", [], annot)])) + :: acc + in + (depth, acc) |> parse left |> parse right + | A | I -> (depth + 1, acc) + in + let (_, expanded) = parse ast (0, []) in + (match args with + | [] -> ok () + | _ :: _ -> error (Invalid_arity (str, List.length args, 0))) + >>? fun () -> ok (Some (Seq (loc, expanded))) + with Not_a_pair -> ok None + else ok None + | _ -> ok None + +let expand_unpappaiir original = + match original with + | Prim (loc, str, args, _annot) -> + let len = String.length str in + if + len > 6 + && String.sub str 0 3 = "UNP" + && str.[len - 1] = 'R' + && check_letters str 3 (len - 2) (function + | 'P' | 'A' | 'I' -> true + | _ -> false) + then + try + let unpair = Prim (loc, "UNPAIR", [], []) in + let ast = parse_pair_substr str ~len 2 in + let rec parse p (depth, acc) = + match p with + | P (_i, left, right) -> + let acc = + if depth = 0 then unpair :: acc + else dip ~loc depth (Seq (loc, [unpair])) :: acc + in + (depth, acc) |> parse left |> parse right + | A | I -> (depth + 1, acc) + in + let (_, rev_expanded) = parse ast (0, []) in + let expanded = Seq (loc, List.rev rev_expanded) in + (match args with + | [] -> ok () + | _ :: _ -> error (Invalid_arity (str, List.length args, 0))) + >>? fun () -> ok (Some expanded) + with Not_a_pair -> ok None + else ok None + | _ -> ok None + +exception Not_a_dup + +let expand_deprecated_duuuuup original = + (* transparently expands deprecated macro [DU...UP] to [{ DUP n }] *) + match original with + | Prim (loc, str, args, annot) -> + let len = String.length str in + if + len > 3 + && str.[0] = 'D' + && str.[len - 1] = 'P' + && check_letters str 1 (len - 2) (( = ) 'U') + then + (match args with + | [] -> ok () + | _ :: _ -> error (Invalid_arity (str, List.length args, 0))) + >>? fun () -> + try + let rec parse i = + if i = 1 then + Prim (loc, "DUP", [Int (loc, Z.of_int (len - 2))], annot) + else if str.[i] = 'U' then parse (i - 1) + else raise_notrace Not_a_dup + in + ok (Some (parse (len - 2))) + with Not_a_dup -> ok None + else ok None + | _ -> ok None + +let expand_compare original = + let cmp loc is annot = + let is = + match List.rev_map (fun i -> Prim (loc, i, [], [])) is with + | Prim (loc, i, args, _) :: r -> + List.rev (Prim (loc, i, args, annot) :: r) + | is -> List.rev is + in + ok (Some (Seq (loc, is))) + in + let ifcmp loc is l r annot = + let is = + List.map (fun i -> Prim (loc, i, [], [])) is + @ [Prim (loc, "IF", [l; r], annot)] + in + ok (Some (Seq (loc, is))) + in + match original with + | Prim (loc, "CMPEQ", [], annot) -> cmp loc ["COMPARE"; "EQ"] annot + | Prim (loc, "CMPNEQ", [], annot) -> cmp loc ["COMPARE"; "NEQ"] annot + | Prim (loc, "CMPLT", [], annot) -> cmp loc ["COMPARE"; "LT"] annot + | Prim (loc, "CMPGT", [], annot) -> cmp loc ["COMPARE"; "GT"] annot + | Prim (loc, "CMPLE", [], annot) -> cmp loc ["COMPARE"; "LE"] annot + | Prim (loc, "CMPGE", [], annot) -> cmp loc ["COMPARE"; "GE"] annot + | Prim + ( _, + (("CMPEQ" | "CMPNEQ" | "CMPLT" | "CMPGT" | "CMPLE" | "CMPGE") as str), + args, + [] ) -> + error (Invalid_arity (str, List.length args, 0)) + | Prim (loc, "IFCMPEQ", [l; r], annot) -> + ifcmp loc ["COMPARE"; "EQ"] l r annot + | Prim (loc, "IFCMPNEQ", [l; r], annot) -> + ifcmp loc ["COMPARE"; "NEQ"] l r annot + | Prim (loc, "IFCMPLT", [l; r], annot) -> + ifcmp loc ["COMPARE"; "LT"] l r annot + | Prim (loc, "IFCMPGT", [l; r], annot) -> + ifcmp loc ["COMPARE"; "GT"] l r annot + | Prim (loc, "IFCMPLE", [l; r], annot) -> + ifcmp loc ["COMPARE"; "LE"] l r annot + | Prim (loc, "IFCMPGE", [l; r], annot) -> + ifcmp loc ["COMPARE"; "GE"] l r annot + | Prim (loc, "IFEQ", [l; r], annot) -> ifcmp loc ["EQ"] l r annot + | Prim (loc, "IFNEQ", [l; r], annot) -> ifcmp loc ["NEQ"] l r annot + | Prim (loc, "IFLT", [l; r], annot) -> ifcmp loc ["LT"] l r annot + | Prim (loc, "IFGT", [l; r], annot) -> ifcmp loc ["GT"] l r annot + | Prim (loc, "IFLE", [l; r], annot) -> ifcmp loc ["LE"] l r annot + | Prim (loc, "IFGE", [l; r], annot) -> ifcmp loc ["GE"] l r annot + | Prim + ( _, + (( "IFCMPEQ" | "IFCMPNEQ" | "IFCMPLT" | "IFCMPGT" | "IFCMPLE" + | "IFCMPGE" | "IFEQ" | "IFNEQ" | "IFLT" | "IFGT" | "IFLE" | "IFGE" ) as + str), + args, + [] ) -> + error (Invalid_arity (str, List.length args, 2)) + | Prim + ( _, + (( "IFCMPEQ" | "IFCMPNEQ" | "IFCMPLT" | "IFCMPGT" | "IFCMPLE" + | "IFCMPGE" | "IFEQ" | "IFNEQ" | "IFLT" | "IFGT" | "IFLE" | "IFGE" ) as + str), + [], + _ :: _ ) -> + error (Unexpected_macro_annotation str) + | _ -> ok None + +let expand_asserts original = + let may_rename loc = function + | [] -> Seq (loc, []) + | annot -> Seq (loc, [Prim (loc, "RENAME", [], annot)]) + in + let fail_false ?(annot = []) loc = + [may_rename loc annot; Seq (loc, [Prim (loc, "FAIL", [], [])])] + in + let fail_true ?(annot = []) loc = + [Seq (loc, [Prim (loc, "FAIL", [], [])]); may_rename loc annot] + in + match original with + | Prim (loc, "ASSERT", [], []) -> + ok @@ Some (Seq (loc, [Prim (loc, "IF", fail_false loc, [])])) + | Prim (loc, "ASSERT_NONE", [], []) -> + ok @@ Some (Seq (loc, [Prim (loc, "IF_NONE", fail_false loc, [])])) + | Prim (loc, "ASSERT_SOME", [], annot) -> + ok @@ Some (Seq (loc, [Prim (loc, "IF_NONE", fail_true ~annot loc, [])])) + | Prim (loc, "ASSERT_LEFT", [], annot) -> + ok @@ Some (Seq (loc, [Prim (loc, "IF_LEFT", fail_false ~annot loc, [])])) + | Prim (loc, "ASSERT_RIGHT", [], annot) -> + ok @@ Some (Seq (loc, [Prim (loc, "IF_LEFT", fail_true ~annot loc, [])])) + | Prim + ( _, + (( "ASSERT" | "ASSERT_NONE" | "ASSERT_SOME" | "ASSERT_LEFT" + | "ASSERT_RIGHT" ) as str), + args, + [] ) -> + error (Invalid_arity (str, List.length args, 0)) + | Prim (_, (("ASSERT" | "ASSERT_NONE") as str), [], _ :: _) -> + error (Unexpected_macro_annotation str) + | Prim (loc, s, args, annot) + when String.(length s > 7 && equal (sub s 0 7) "ASSERT_") -> ( + (match args with + | [] -> ok () + | _ :: _ -> error (Invalid_arity (s, List.length args, 0))) + >>? fun () -> + (match annot with + | _ :: _ -> error (Unexpected_macro_annotation s) + | [] -> ok ()) + >>? fun () -> + let remaining = String.(sub s 7 (length s - 7)) in + let remaining_prim = Prim (loc, remaining, [], []) in + match remaining with + | "EQ" | "NEQ" | "LT" | "LE" | "GE" | "GT" -> + ok + @@ Some + (Seq (loc, [remaining_prim; Prim (loc, "IF", fail_false loc, [])])) + | _ -> ( + expand_compare remaining_prim >|? function + | None -> None + | Some seq -> + Some (Seq (loc, [seq; Prim (loc, "IF", fail_false loc, [])])))) + | _ -> ok None + +let expand_if_some = function + | Prim (loc, "IF_SOME", [right; left], annot) -> + ok @@ Some (Seq (loc, [Prim (loc, "IF_NONE", [left; right], annot)])) + | Prim (_, "IF_SOME", args, _annot) -> + error (Invalid_arity ("IF_SOME", List.length args, 2)) + | _ -> ok @@ None + +let expand_if_right = function + | Prim (loc, "IF_RIGHT", [right; left], annot) -> + ok @@ Some (Seq (loc, [Prim (loc, "IF_LEFT", [left; right], annot)])) + | Prim (_, "IF_RIGHT", args, _annot) -> + error (Invalid_arity ("IF_RIGHT", List.length args, 2)) + | _ -> ok @@ None + +let expand_fail = function + | Prim (loc, "FAIL", [], []) -> + ok + @@ Some + (Seq + (loc, [Prim (loc, "UNIT", [], []); Prim (loc, "FAILWITH", [], [])])) + | _ -> ok @@ None + +let expand original = + let rec try_expansions = function + | [] -> ok @@ original + | expander :: expanders -> ( + expander original >>? function + | None -> try_expansions expanders + | Some rewritten -> ok rewritten) + in + try_expansions + [ + expand_carn; + expand_cdrn; + expand_caddadr; + expand_set_caddadr; + expand_map_caddadr; + expand_deprecated_dxiiivp; + (* expand_paaiair ; *) + expand_pappaiir; + (* expand_unpaaiair ; *) + expand_unpappaiir; + expand_deprecated_duuuuup; + expand_compare; + expand_asserts; + expand_if_some; + expand_if_right; + expand_fail; + ] + +let expand_rec expr = + let rec error_map (expanded, errors) f = function + | [] -> (List.rev expanded, List.rev errors) + | hd :: tl -> + let (new_expanded, new_errors) = f hd in + error_map + (new_expanded :: expanded, List.rev_append new_errors errors) + f + tl + in + let error_map = error_map ([], []) in + let rec expand_rec expr = + match expand expr with + | Ok expanded -> ( + match expanded with + | Seq (loc, items) -> + let (items, errors) = error_map expand_rec items in + (Seq (loc, items), errors) + | Prim (loc, name, args, annot) -> + let (args, errors) = error_map expand_rec args in + (Prim (loc, name, args, annot), errors) + | (Int _ | String _ | Bytes _) as atom -> (atom, [])) + | Error errors -> (expr, errors) + in + expand_rec expr + +let unexpand_carn_and_cdrn expanded = + match expanded with + | Seq (loc, [Prim (_, "GET", [Int (locn, n)], annot)]) -> + let (half, parity) = Z.ediv_rem n (Z.of_int 2) in + if Z.(parity = zero) then + Some (Prim (loc, "CDR", [Int (locn, half)], annot)) + else Some (Prim (loc, "CAR", [Int (locn, half)], annot)) + | _ -> None + +let unexpand_caddadr expanded = + let rec rsteps acc = function + | [] -> Some acc + | Prim (_, "CAR", [], []) :: rest -> rsteps ("A" :: acc) rest + | Prim (_, "CDR", [], []) :: rest -> rsteps ("D" :: acc) rest + | _ -> None + in + match expanded with + | Seq (loc, (Prim (_, "CAR", [], []) :: _ as nodes)) + | Seq (loc, (Prim (_, "CDR", [], []) :: _ as nodes)) -> ( + match rsteps [] nodes with + | Some steps -> + let name = String.concat "" ("C" :: List.rev ("R" :: steps)) in + Some (Prim (loc, name, [], [])) + | None -> None) + | _ -> None + +let unexpand_set_caddadr expanded = + let rec steps acc annots = function + | Seq + ( loc, + [ + Prim (_, "CDR", [], _); + Prim (_, "SWAP", [], _); + Prim (_, "PAIR", [], _); + ] ) -> + Some (loc, "A" :: acc, annots) + | Seq + ( loc, + [ + Prim (_, "DUP", [], []); + Prim (_, "CAR", [], [field_annot]); + Prim (_, "DROP", [], []); + Prim (_, "CDR", [], _); + Prim (_, "SWAP", [], []); + Prim (_, "PAIR", [], _); + ] ) -> + Some (loc, "A" :: acc, field_annot :: annots) + | Seq (loc, [Prim (_, "CAR", [], _); Prim (_, "PAIR", [], _)]) -> + Some (loc, "D" :: acc, annots) + | Seq + ( loc, + [ + Prim (_, "DUP", [], []); + Prim (_, "CDR", [], [field_annot]); + Prim (_, "DROP", [], []); + Prim (_, "CAR", [], _); + Prim (_, "PAIR", [], _); + ] ) -> + Some (loc, "D" :: acc, field_annot :: annots) + | Seq + ( _, + [ + Prim (_, "DUP", [], []); + Prim (_, "DIP", [Seq (_, [Prim (_, "CAR", [], _); sub])], []); + Prim (_, "CDR", [], _); + Prim (_, "SWAP", [], []); + Prim (_, "PAIR", [], pair_annots); + ] ) -> + let (_, pair_annots) = extract_field_annots pair_annots in + steps ("A" :: acc) (List.rev_append pair_annots annots) sub + | Seq + ( _, + [ + Prim (_, "DUP", [], []); + Prim (_, "DIP", [Seq (_, [Prim (_, "CDR", [], _); sub])], []); + Prim (_, "CAR", [], _); + Prim (_, "PAIR", [], pair_annots); + ] ) -> + let (_, pair_annots) = extract_field_annots pair_annots in + steps ("D" :: acc) (List.rev_append pair_annots annots) sub + | _ -> None + in + match steps [] [] expanded with + | Some (loc, steps, annots) -> + let name = String.concat "" ("SET_C" :: List.rev ("R" :: steps)) in + Some (Prim (loc, name, [], List.rev annots)) + | None -> None + +let unexpand_map_caddadr expanded = + let rec steps acc annots = function + | Seq + ( loc, + [ + Prim (_, "DUP", [], []); + Prim (_, "CDR", [], _); + Prim (_, "SWAP", [], []); + Prim (_, "DIP", [Seq (_, [Prim (_, "CAR", [], []); code])], []); + Prim (_, "PAIR", [], _); + ] ) -> + Some (loc, "A" :: acc, annots, code) + | Seq + ( loc, + [ + Prim (_, "DUP", [], []); + Prim (_, "CDR", [], _); + Prim (_, "SWAP", [], []); + Prim + ( _, + "DIP", + [Seq (_, [Prim (_, "CAR", [], [field_annot]); code])], + [] ); + Prim (_, "PAIR", [], _); + ] ) -> + Some (loc, "A" :: acc, field_annot :: annots, code) + | Seq + ( loc, + [ + Prim (_, "DUP", [], []); + Prim (_, "CDR", [], []); + code; + Prim (_, "SWAP", [], []); + Prim (_, "CAR", [], _); + Prim (_, "PAIR", [], _); + ] ) -> + Some (loc, "D" :: acc, annots, code) + | Seq + ( loc, + [ + Prim (_, "DUP", [], []); + Prim (_, "CDR", [], [field_annot]); + code; + Prim (_, "SWAP", [], []); + Prim (_, "CAR", [], _); + Prim (_, "PAIR", [], _); + ] ) -> + Some (loc, "D" :: acc, field_annot :: annots, code) + | Seq + ( _, + [ + Prim (_, "DUP", [], []); + Prim (_, "DIP", [Seq (_, [Prim (_, "CAR", [], _); sub])], []); + Prim (_, "CDR", [], _); + Prim (_, "SWAP", [], []); + Prim (_, "PAIR", [], pair_annots); + ] ) -> + let (_, pair_annots) = extract_field_annots pair_annots in + steps ("A" :: acc) (List.rev_append pair_annots annots) sub + | Seq + ( _, + [ + Prim (_, "DUP", [], []); + Prim (_, "DIP", [Seq (_, [Prim (_, "CDR", [], []); sub])], []); + Prim (_, "CAR", [], []); + Prim (_, "PAIR", [], pair_annots); + ] ) -> + let (_, pair_annots) = extract_field_annots pair_annots in + steps ("D" :: acc) (List.rev_append pair_annots annots) sub + | _ -> None + in + match steps [] [] expanded with + | Some (loc, steps, annots, code) -> + let name = String.concat "" ("MAP_C" :: List.rev ("R" :: steps)) in + Some (Prim (loc, name, [code], List.rev annots)) + | None -> None + +let unexpand_deprecated_dxiiivp expanded = + (* transparently turn the old expansion of deprecated [DI...IP] to [DIP n] *) + match expanded with + | Seq + ( loc, + [Prim (_, "DIP", [(Seq (_, [Prim (_, "DIP", [_], [])]) as sub)], [])] ) + -> + let rec count acc = function + | Seq (_, [Prim (_, "DIP", [sub], [])]) -> count (acc + 1) sub + | sub -> (acc, sub) + in + let (depth, sub) = count 1 sub in + Some (Prim (loc, "DIP", [Int (loc, Z.of_int depth); sub], [])) + | _ -> None + +let unexpand_dupn expanded = + match expanded with + | Seq + ( loc, + [ + Prim + (_, "DIP", [Int (_, np); Seq (_, [Prim (_, "DUP", [], annot)])], []); + Prim (_, "DIG", [Int (nloc, ng)], []); + ] ) + when Z.equal np (Z.pred ng) -> + Some (Prim (loc, "DUP", [Int (nloc, ng)], annot)) + | _ -> None + +let unexpand_deprecated_duuuuup expanded = + (* transparently turn the old expansion of deprecated [DU...UP] to [DUP n] *) + let rec expand n = function + | Seq (loc, [Prim (nloc, "DUP", [], annot)]) -> + if n = 1 then None + else Some (Prim (loc, "DUP", [Int (nloc, Z.of_int n)], annot)) + | Seq (_, [Prim (_, "DIP", [expanded'], []); Prim (_, "SWAP", [], [])]) -> + expand (n + 1) expanded' + | _ -> None + in + expand 1 expanded + +let rec normalize_pair_item ?(right = false) = function + | P (i, a, b) -> + P (i, normalize_pair_item a, normalize_pair_item ~right:true b) + | A when right -> I + | A -> A + | I -> I + +let unexpand_pappaiir expanded = + match expanded with + | Seq (_, [Prim (_, "PAIR", [], [])]) -> Some expanded + | Seq (loc, (_ :: _ as nodes)) -> ( + let rec exec stack nodes = + match (nodes, stack) with + | ([], _) -> stack + (* support new expansion using [DIP n] *) + | ( Prim (ploc, "DIP", [Int (loc, n); Seq (sloc, sub)], []) :: rest, + a :: rstack ) + when Z.to_int n > 1 -> + exec + (a + :: + exec + rstack + [ + Prim (ploc, "DIP", [Int (loc, Z.pred n); Seq (sloc, sub)], []); + ]) + rest + | (Prim (_, "DIP", [Int (_, n); Seq (_, sub)], []) :: rest, a :: rstack) + when Z.to_int n = 1 -> + exec (a :: exec rstack sub) rest + | (Prim (ploc, "DIP", [Int (loc, n); Seq (sloc, sub)], []) :: rest, []) + when Z.to_int n > 1 -> + exec + (A + :: + exec + [] + [ + Prim (ploc, "DIP", [Int (loc, Z.pred n); Seq (sloc, sub)], []); + ]) + rest + | (Prim (_, "DIP", [Int (_, n); Seq (_, sub)], []) :: rest, []) + when Z.to_int n = 1 -> + exec (A :: exec [] sub) rest + (* support old expansion using [DIP] *) + | (Prim (_, "DIP", [Seq (_, sub)], []) :: rest, a :: rstack) -> + exec (a :: exec rstack sub) rest + | (Prim (_, "DIP", [Seq (_, sub)], []) :: rest, []) -> + exec (A :: exec [] sub) rest + | (Prim (_, "PAIR", [], []) :: rest, a :: b :: rstack) -> + exec (P (0, a, b) :: rstack) rest + | (Prim (_, "PAIR", [], []) :: rest, [a]) -> exec [P (0, a, I)] rest + | (Prim (_, "PAIR", [], []) :: rest, []) -> exec [P (0, A, I)] rest + | _ -> raise_notrace Not_a_pair + in + match exec [] nodes with + | [] -> None + | res :: _ -> + let res = normalize_pair_item res in + let name = unparse_pair_item res in + Some (Prim (loc, name, [], [])) + | exception Not_a_pair -> None) + | _ -> None + +let unexpand_unpappaiir expanded = + match expanded with + | Seq (loc, (_ :: _ as nodes)) -> ( + let rec exec stack nodes = + match (nodes, stack) with + | ([], _) -> stack + (* support new expansion using [DIP n] *) + | ( Prim (ploc, "DIP", [Int (loc, n); Seq (sloc, sub)], []) :: rest, + a :: rstack ) + when Z.to_int n > 1 -> + exec + (a + :: + exec + rstack + [ + Prim (ploc, "DIP", [Int (loc, Z.pred n); Seq (sloc, sub)], []); + ]) + rest + | (Prim (_, "DIP", [Int (_, n); Seq (_, sub)], []) :: rest, a :: rstack) + when Z.to_int n = 1 -> + exec (a :: exec rstack sub) rest + | (Prim (ploc, "DIP", [Int (loc, n); Seq (sloc, sub)], []) :: rest, []) + when Z.to_int n > 1 -> + exec + (A + :: + exec + [] + [ + Prim (ploc, "DIP", [Int (loc, Z.pred n); Seq (sloc, sub)], []); + ]) + rest + | (Prim (_, "DIP", [Int (_, n); Seq (_, sub)], []) :: rest, []) + when Z.to_int n = 1 -> + exec (A :: exec [] sub) rest + (* support old expansion using [DIP] *) + | (Prim (_, "DIP", [Seq (_, sub)], []) :: rest, a :: rstack) -> + exec (a :: exec rstack sub) rest + | (Prim (_, "DIP", [Seq (_, sub)], []) :: rest, []) -> + exec (A :: exec [] sub) rest + | ( Seq + ( _, + [ + Prim (_, "DUP", [], []); + Prim (_, "CAR", [], []); + Prim (_, "DIP", [Seq (_, [Prim (_, "CDR", [], [])])], []); + ] ) + :: rest, + a :: b :: rstack ) -> + exec (P (0, a, b) :: rstack) rest + | ( Seq + ( _, + [ + Prim (_, "DUP", [], []); + Prim (_, "CAR", [], []); + Prim (_, "DIP", [Seq (_, [Prim (_, "CDR", [], [])])], []); + ] ) + :: rest, + [a] ) -> + exec [P (0, a, I)] rest + | ( Seq + ( _, + [ + Prim (_, "DUP", [], []); + Prim (_, "CAR", [], []); + Prim (_, "DIP", [Seq (_, [Prim (_, "CDR", [], [])])], []); + ] ) + :: rest, + [] ) -> + exec [P (0, A, I)] rest + | _ -> raise_notrace Not_a_pair + in + match exec [] (List.rev nodes) with + | [] -> None + | res :: _ -> + let res = normalize_pair_item res in + let name = "UN" ^ unparse_pair_item res in + Some (Prim (loc, name, [], [])) + | exception Not_a_pair -> None) + | _ -> None + +let unexpand_compare expanded = + match expanded with + | Seq (loc, [Prim (_, "COMPARE", [], _); Prim (_, "EQ", [], annot)]) -> + Some (Prim (loc, "CMPEQ", [], annot)) + | Seq (loc, [Prim (_, "COMPARE", [], _); Prim (_, "NEQ", [], annot)]) -> + Some (Prim (loc, "CMPNEQ", [], annot)) + | Seq (loc, [Prim (_, "COMPARE", [], _); Prim (_, "LT", [], annot)]) -> + Some (Prim (loc, "CMPLT", [], annot)) + | Seq (loc, [Prim (_, "COMPARE", [], _); Prim (_, "GT", [], annot)]) -> + Some (Prim (loc, "CMPGT", [], annot)) + | Seq (loc, [Prim (_, "COMPARE", [], _); Prim (_, "LE", [], annot)]) -> + Some (Prim (loc, "CMPLE", [], annot)) + | Seq (loc, [Prim (_, "COMPARE", [], _); Prim (_, "GE", [], annot)]) -> + Some (Prim (loc, "CMPGE", [], annot)) + | Seq + ( loc, + [ + Prim (_, "COMPARE", [], _); + Prim (_, "EQ", [], _); + Prim (_, "IF", args, annot); + ] ) -> + Some (Prim (loc, "IFCMPEQ", args, annot)) + | Seq + ( loc, + [ + Prim (_, "COMPARE", [], _); + Prim (_, "NEQ", [], _); + Prim (_, "IF", args, annot); + ] ) -> + Some (Prim (loc, "IFCMPNEQ", args, annot)) + | Seq + ( loc, + [ + Prim (_, "COMPARE", [], _); + Prim (_, "LT", [], _); + Prim (_, "IF", args, annot); + ] ) -> + Some (Prim (loc, "IFCMPLT", args, annot)) + | Seq + ( loc, + [ + Prim (_, "COMPARE", [], _); + Prim (_, "GT", [], _); + Prim (_, "IF", args, annot); + ] ) -> + Some (Prim (loc, "IFCMPGT", args, annot)) + | Seq + ( loc, + [ + Prim (_, "COMPARE", [], _); + Prim (_, "LE", [], _); + Prim (_, "IF", args, annot); + ] ) -> + Some (Prim (loc, "IFCMPLE", args, annot)) + | Seq + ( loc, + [ + Prim (_, "COMPARE", [], _); + Prim (_, "GE", [], _); + Prim (_, "IF", args, annot); + ] ) -> + Some (Prim (loc, "IFCMPGE", args, annot)) + | Seq (loc, [Prim (_, "EQ", [], _); Prim (_, "IF", args, annot)]) -> + Some (Prim (loc, "IFEQ", args, annot)) + | Seq (loc, [Prim (_, "NEQ", [], _); Prim (_, "IF", args, annot)]) -> + Some (Prim (loc, "IFNEQ", args, annot)) + | Seq (loc, [Prim (_, "LT", [], _); Prim (_, "IF", args, annot)]) -> + Some (Prim (loc, "IFLT", args, annot)) + | Seq (loc, [Prim (_, "GT", [], _); Prim (_, "IF", args, annot)]) -> + Some (Prim (loc, "IFGT", args, annot)) + | Seq (loc, [Prim (_, "LE", [], _); Prim (_, "IF", args, annot)]) -> + Some (Prim (loc, "IFLE", args, annot)) + | Seq (loc, [Prim (_, "GE", [], _); Prim (_, "IF", args, annot)]) -> + Some (Prim (loc, "IFGE", args, annot)) + | _ -> None + +let unexpand_asserts expanded = + match expanded with + | Seq + ( loc, + [ + Prim + ( _, + "IF", + [ + Seq (_, []); + Seq + ( _, + [ + Seq + ( _, + [ + Prim (_, "UNIT", [], []); + Prim (_, "FAILWITH", [], []); + ] ); + ] ); + ], + [] ); + ] ) -> + Some (Prim (loc, "ASSERT", [], [])) + | Seq + ( loc, + [ + Seq (_, [Prim (_, "COMPARE", [], []); Prim (_, comparison, [], [])]); + Prim + ( _, + "IF", + [ + Seq (_, []); + Seq + ( _, + [ + Seq + ( _, + [ + Prim (_, "UNIT", [], []); + Prim (_, "FAILWITH", [], []); + ] ); + ] ); + ], + [] ); + ] ) -> + Some (Prim (loc, "ASSERT_CMP" ^ comparison, [], [])) + | Seq + ( loc, + [ + Prim (_, comparison, [], []); + Prim + ( _, + "IF", + [ + Seq (_, []); + Seq + ( _, + [ + Seq + ( _, + [ + Prim (_, "UNIT", [], []); + Prim (_, "FAILWITH", [], []); + ] ); + ] ); + ], + [] ); + ] ) -> + Some (Prim (loc, "ASSERT_" ^ comparison, [], [])) + | Seq + ( loc, + [ + Prim + ( _, + "IF_NONE", + [ + Seq (_, [Prim (_, "RENAME", [], annot)]); + Seq + ( _, + [ + Seq + ( _, + [ + Prim (_, "UNIT", [], []); + Prim (_, "FAILWITH", [], []); + ] ); + ] ); + ], + [] ); + ] ) -> + Some (Prim (loc, "ASSERT_NONE", [], annot)) + | Seq + ( loc, + [ + Prim + ( _, + "IF_NONE", + [ + Seq (_, []); + Seq + ( _, + [ + Seq + ( _, + [ + Prim (_, "UNIT", [], []); + Prim (_, "FAILWITH", [], []); + ] ); + ] ); + ], + [] ); + ] ) -> + Some (Prim (loc, "ASSERT_NONE", [], [])) + | Seq + ( loc, + [ + Prim + ( _, + "IF_NONE", + [ + Seq + ( _, + [ + Seq + ( _, + [ + Prim (_, "UNIT", [], []); + Prim (_, "FAILWITH", [], []); + ] ); + ] ); + Seq (_, []); + ], + [] ); + ] ) -> + Some (Prim (loc, "ASSERT_SOME", [], [])) + | Seq + ( loc, + [ + Prim + ( _, + "IF_NONE", + [ + Seq + ( _, + [ + Seq + ( _, + [ + Prim (_, "UNIT", [], []); + Prim (_, "FAILWITH", [], []); + ] ); + ] ); + Seq (_, [Prim (_, "RENAME", [], annot)]); + ], + [] ); + ] ) -> + Some (Prim (loc, "ASSERT_SOME", [], annot)) + | Seq + ( loc, + [ + Prim + ( _, + "IF_LEFT", + [ + Seq (_, []); + Seq + ( _, + [ + Seq + ( _, + [ + Prim (_, "UNIT", [], []); + Prim (_, "FAILWITH", [], []); + ] ); + ] ); + ], + [] ); + ] ) -> + Some (Prim (loc, "ASSERT_LEFT", [], [])) + | Seq + ( loc, + [ + Prim + ( _, + "IF_LEFT", + [ + Seq (_, [Prim (_, "RENAME", [], annot)]); + Seq + ( _, + [ + Seq + ( _, + [ + Prim (_, "UNIT", [], []); + Prim (_, "FAILWITH", [], []); + ] ); + ] ); + ], + [] ); + ] ) -> + Some (Prim (loc, "ASSERT_LEFT", [], annot)) + | Seq + ( loc, + [ + Prim + ( _, + "IF_LEFT", + [ + Seq + ( _, + [ + Seq + ( _, + [ + Prim (_, "UNIT", [], []); + Prim (_, "FAILWITH", [], []); + ] ); + ] ); + Seq (_, []); + ], + [] ); + ] ) -> + Some (Prim (loc, "ASSERT_RIGHT", [], [])) + | Seq + ( loc, + [ + Prim + ( _, + "IF_LEFT", + [ + Seq + ( _, + [ + Seq + ( _, + [ + Prim (_, "UNIT", [], []); + Prim (_, "FAILWITH", [], []); + ] ); + ] ); + Seq (_, [Prim (_, "RENAME", [], annot)]); + ], + [] ); + ] ) -> + Some (Prim (loc, "ASSERT_RIGHT", [], annot)) + | _ -> None + +let unexpand_if_some = function + | Seq (loc, [Prim (_, "IF_NONE", [left; right], annot)]) -> + Some (Prim (loc, "IF_SOME", [right; left], annot)) + | _ -> None + +let unexpand_if_right = function + | Seq (loc, [Prim (_, "IF_LEFT", [left; right], annot)]) -> + Some (Prim (loc, "IF_RIGHT", [right; left], annot)) + | _ -> None + +let unexpand_fail = function + | Seq (loc, [Prim (_, "UNIT", [], []); Prim (_, "FAILWITH", [], [])]) -> + Some (Prim (loc, "FAIL", [], [])) + | _ -> None + +let unexpand original = + let try_unexpansions unexpanders = + Option.value + ~default:original + (List.fold_left + (fun acc f -> Option.either_f acc (fun () -> f original)) + None + unexpanders) + in + try_unexpansions + [ + unexpand_asserts; + unexpand_carn_and_cdrn; + unexpand_caddadr; + unexpand_set_caddadr; + unexpand_map_caddadr; + unexpand_deprecated_dxiiivp; + unexpand_pappaiir; + unexpand_unpappaiir; + unexpand_deprecated_duuuuup; + unexpand_dupn; + unexpand_compare; + unexpand_if_some; + unexpand_if_right; + unexpand_fail; + ] + +(* + If an argument of Prim is a sequence, we do not want to unexpand + its root in case the source already contains an expanded macro. In + which case unexpansion would remove surrounding braces and generate + ill-formed code. + + For example, DIIP { DIP { DUP }; SWAP } is not unexpandable but + DIIP {{ DIP { DUP }; SWAP }} (note the double braces) is unexpanded + to DIIP { DUUP }. + + unexpand_rec_but_root is the same as unexpand_rec but does not try + to unexpand at root *) + +let rec unexpand_rec expr = unexpand_rec_but_root (unexpand expr) + +and unexpand_rec_but_root = function + | Seq (loc, items) -> Seq (loc, List.map unexpand_rec items) + | Prim (loc, name, args, annot) -> + Prim (loc, name, List.map unexpand_rec_but_root args, annot) + | (Int _ | String _ | Bytes _) as atom -> atom + +let () = + let open Data_encoding in + register_error_kind + `Permanent + ~id:"michelson.macros.unexpected_annotation" + ~title:"Unexpected annotation" + ~description: + "A macro had an annotation, but no annotation was permitted on this \ + macro." + ~pp:(fun ppf -> Format.fprintf ppf "Unexpected annotation on macro %s.") + (obj1 (req "macro_name" string)) + (function Unexpected_macro_annotation str -> Some str | _ -> None) + (fun s -> Unexpected_macro_annotation s) ; + register_error_kind + `Permanent + ~id:"michelson.macros.sequence_expected" + ~title:"Macro expects a sequence" + ~description:"An macro expects a sequence, but a sequence was not provided" + ~pp:(fun ppf name -> + Format.fprintf + ppf + "Macro %s expects a sequence, but did not receive one." + name) + (obj1 (req "macro_name" string)) + (function Sequence_expected name -> Some name | _ -> None) + (fun name -> Sequence_expected name) ; + register_error_kind + `Permanent + ~id:"michelson.macros.bas_arity" + ~title:"Wrong number of arguments to macro" + ~description:"A wrong number of arguments was provided to a macro" + ~pp:(fun ppf (name, got, exp) -> + Format.fprintf + ppf + "Macro %s expects %d arguments, was given %d." + name + exp + got) + (obj3 + (req "macro_name" string) + (req "given_number_of_arguments" uint16) + (req "expected_number_of_arguments" uint16)) + (function + | Invalid_arity (name, got, exp) -> Some (name, got, exp) | _ -> None) + (fun (name, got, exp) -> Invalid_arity (name, got, exp)) diff --git a/src/proto_011_PtHangzH/lib_client/michelson_v1_macros.mli b/src/proto_011_PtHangzH/lib_client/michelson_v1_macros.mli new file mode 100644 index 000000000000..352a59b00a9e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/michelson_v1_macros.mli @@ -0,0 +1,86 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Tezos_micheline + +type 'l node = ('l, string) Micheline.node + +type error += Unexpected_macro_annotation of string + +type error += Sequence_expected of string + +type error += Invalid_arity of string * int * int + +val expand : 'l node -> 'l node tzresult + +val expand_rec : 'l node -> 'l node * error list + +val expand_caddadr : 'l node -> 'l node option tzresult + +val expand_set_caddadr : 'l node -> 'l node option tzresult + +val expand_map_caddadr : 'l node -> 'l node option tzresult + +val expand_deprecated_dxiiivp : 'l node -> 'l node option tzresult + +val expand_pappaiir : 'l node -> 'l node option tzresult + +val expand_deprecated_duuuuup : 'l node -> 'l node option tzresult + +val expand_compare : 'l node -> 'l node option tzresult + +val expand_asserts : 'l node -> 'l node option tzresult + +val expand_unpappaiir : 'l node -> 'l node option tzresult + +val expand_if_some : 'l node -> 'l node option tzresult + +val expand_if_right : 'l node -> 'l node option tzresult + +val unexpand : 'l node -> 'l node + +val unexpand_rec : 'l node -> 'l node + +val unexpand_caddadr : 'l node -> 'l node option + +val unexpand_set_caddadr : 'l node -> 'l node option + +val unexpand_map_caddadr : 'l node -> 'l node option + +val unexpand_deprecated_dxiiivp : 'l node -> 'l node option + +val unexpand_pappaiir : 'l node -> 'l node option + +val unexpand_deprecated_duuuuup : 'l node -> 'l node option + +val unexpand_compare : 'l node -> 'l node option + +val unexpand_asserts : 'l node -> 'l node option + +val unexpand_unpappaiir : 'l node -> 'l node option + +val unexpand_if_some : 'l node -> 'l node option + +val unexpand_if_right : 'l node -> 'l node option diff --git a/src/proto_011_PtHangzH/lib_client/michelson_v1_parser.ml b/src/proto_011_PtHangzH/lib_client/michelson_v1_parser.ml new file mode 100644 index 000000000000..2f44d22c1fca --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/michelson_v1_parser.ml @@ -0,0 +1,103 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Tezos_micheline +open Micheline_parser +open Micheline + +type parsed = { + source : string; + unexpanded : string canonical; + expanded : Michelson_v1_primitives.prim canonical; + expansion_table : (int * (Micheline_parser.location * int list)) list; + unexpansion_table : (int * int) list; +} + +let compare_parsed = Stdlib.compare + +(* Unexpanded toplevel expression should be a sequence *) +let expand_all source ast errors = + let (unexpanded, loc_table) = extract_locations ast in + let (expanded, expansion_errors) = + Michelson_v1_macros.expand_rec (root unexpanded) + in + let (expanded, unexpansion_table) = extract_locations expanded in + let expansion_table = + let sorted = + List.sort (fun (_, a) (_, b) -> Stdlib.compare a b) unexpansion_table + in + let grouped = + let rec group = function + | (acc, []) -> acc + | ([], (u, e) :: r) -> group ([(e, [u])], r) + | (((pe, us) :: racc as acc), (u, e) :: r) -> + if e = pe then group ((e, u :: us) :: racc, r) + else group ((e, [u]) :: acc, r) + in + group ([], sorted) + in + match + List.map2 + ~when_different_lengths:() + (fun (l, ploc) (l', elocs) -> + assert (l = l') ; + (l, (ploc, elocs))) + (List.sort Stdlib.compare loc_table) + (List.sort Stdlib.compare grouped) + with + | Ok v -> v + | Error () -> invalid_arg "Michelson_v1_parser.expand_all" + in + match Michelson_v1_primitives.prims_of_strings expanded with + | Ok expanded -> + ( {source; unexpanded; expanded; expansion_table; unexpansion_table}, + errors @ expansion_errors ) + | Error errs -> + let errs = Environment.wrap_tztrace errs in + ( { + source; + unexpanded; + expanded = Micheline.strip_locations (Seq ((), [])); + expansion_table; + unexpansion_table; + }, + errors @ expansion_errors @ errs ) + +let parse_toplevel ?check source = + let (tokens, lexing_errors) = Micheline_parser.tokenize source in + let (asts, parsing_errors) = Micheline_parser.parse_toplevel ?check tokens in + let ast = + let start = min_point asts and stop = max_point asts in + Seq ({start; stop}, asts) + in + expand_all source ast (lexing_errors @ parsing_errors) + +let parse_expression ?check source = + let (tokens, lexing_errors) = Micheline_parser.tokenize source in + let (ast, parsing_errors) = Micheline_parser.parse_expression ?check tokens in + expand_all source ast (lexing_errors @ parsing_errors) + +let expand_all ~source ~original = expand_all source original [] diff --git a/src/proto_011_PtHangzH/lib_client/michelson_v1_parser.mli b/src/proto_011_PtHangzH/lib_client/michelson_v1_parser.mli new file mode 100644 index 000000000000..6aa29676741a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/michelson_v1_parser.mli @@ -0,0 +1,55 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Tezos_micheline + +(** The result of parsing and expanding a Michelson V1 script or data. *) +type parsed = { + source : string; (** The original source code. *) + unexpanded : string Micheline.canonical; + (** Original expression with macros. *) + expanded : Script.expr; (** Expression with macros fully expanded. *) + expansion_table : (int * (Micheline_parser.location * int list)) list; + (** Associates unexpanded nodes to their parsing locations and + the nodes expanded from it in the expanded expression. *) + unexpansion_table : (int * int) list; + (** Associates an expanded node to its source in the unexpanded + expression. *) +} + +val compare_parsed : parsed -> parsed -> int + +val parse_toplevel : + ?check:bool -> string -> parsed Micheline_parser.parsing_result + +val parse_expression : + ?check:bool -> string -> parsed Micheline_parser.parsing_result + +val expand_all : + source:string -> + original:Micheline_parser.node -> + parsed Micheline_parser.parsing_result diff --git a/src/proto_011_PtHangzH/lib_client/michelson_v1_printer.ml b/src/proto_011_PtHangzH/lib_client/michelson_v1_printer.ml new file mode 100644 index 000000000000..5eeb4e1fd88c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/michelson_v1_printer.ml @@ -0,0 +1,241 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Tezos_micheline +open Micheline +open Micheline_printer + +let anon = {comment = None} + +let print_expr ppf expr = + expr |> Michelson_v1_primitives.strings_of_prims + |> Micheline.inject_locations (fun _ -> anon) + |> print_expr ppf + +let print_expr_unwrapped ppf expr = + expr |> Michelson_v1_primitives.strings_of_prims + |> Micheline.inject_locations (fun _ -> anon) + |> print_expr_unwrapped ppf + +let print_var_annots ppf = List.iter (Format.fprintf ppf "%s ") + +let print_annot_expr_unwrapped ppf (expr, annot) = + Format.fprintf ppf "%a%a" print_var_annots annot print_expr_unwrapped expr + +let print_stack ppf = function + | [] -> Format.fprintf ppf "[]" + | more -> + Format.fprintf + ppf + "@[[ %a ]@]" + (Format.pp_print_list + ~pp_sep:(fun ppf () -> Format.fprintf ppf "@ : ") + print_annot_expr_unwrapped) + more + +let print_execution_trace ppf trace = + Format.pp_print_list + (fun ppf (loc, gas, stack) -> + Format.fprintf + ppf + "- @[location: %d (remaining gas: %a)@,[ @[%a ]@]@]" + loc + Gas.pp + gas + (Format.pp_print_list (fun ppf (e, annot) -> + Format.fprintf + ppf + "@[%a \t%s@]" + print_expr + e + (match annot with None -> "" | Some a -> a))) + stack) + ppf + trace + +let print_big_map_diff ppf lazy_storage_diff = + let diff = + Contract.Legacy_big_map_diff.of_lazy_storage_diff lazy_storage_diff + in + let pp_map ppf id = + if Compare.Z.(id < Z.zero) then + Format.fprintf ppf "temp(%s)" (Z.to_string (Z.neg id)) + else Format.fprintf ppf "map(%s)" (Z.to_string id) + in + Format.fprintf + ppf + "@[%a@]" + (Format.pp_print_list ~pp_sep:Format.pp_print_space (fun ppf -> function + | Contract.Legacy_big_map_diff.Clear id -> + Format.fprintf ppf "Clear %a" pp_map id + | Contract.Legacy_big_map_diff.Alloc {big_map; key_type; value_type} -> + Format.fprintf + ppf + "New %a of type (big_map %a %a)" + pp_map + big_map + print_expr + key_type + print_expr + value_type + | Contract.Legacy_big_map_diff.Copy {src; dst} -> + Format.fprintf ppf "Copy %a to %a" pp_map src pp_map dst + | Contract.Legacy_big_map_diff.Update {big_map; diff_key; diff_value; _} + -> + Format.fprintf + ppf + "%s %a[%a]%a" + (match diff_value with None -> "Unset" | Some _ -> "Set") + pp_map + big_map + print_expr + diff_key + (fun ppf -> function + | None -> () + | Some x -> Format.fprintf ppf " to %a" print_expr x) + diff_value)) + (diff :> Contract.Legacy_big_map_diff.item list) + +let inject_types type_map parsed = + let rec inject_expr = function + | Seq (loc, items) -> + Seq (inject_loc `before loc, List.map inject_expr items) + | Prim (loc, name, items, annot) -> + Prim (inject_loc `after loc, name, List.map inject_expr items, annot) + | Int (loc, value) -> Int (inject_loc `after loc, value) + | String (loc, value) -> String (inject_loc `after loc, value) + | Bytes (loc, value) -> Bytes (inject_loc `after loc, value) + and inject_loc which loc = + let comment = + let ( >?? ) = Option.bind in + List.assoc ~equal:Int.equal loc parsed.Michelson_v1_parser.expansion_table + >?? fun (_, locs) -> + let locs = List.sort compare locs in + List.hd locs >?? fun head_loc -> + List.assoc ~equal:Int.equal head_loc type_map >?? fun (bef, aft) -> + let stack = match which with `before -> bef | `after -> aft in + Some (Format.asprintf "%a" print_stack stack) + in + {comment} + in + inject_expr (root parsed.unexpanded) + +let unparse ?type_map parse expanded = + let source = + match type_map with + | Some type_map -> + let (unexpanded, unexpansion_table) = + expanded |> Michelson_v1_primitives.strings_of_prims |> root + |> Michelson_v1_macros.unexpand_rec |> Micheline.extract_locations + in + let rec inject_expr = function + | Seq (loc, items) -> + Seq (inject_loc `before loc, List.map inject_expr items) + | Prim (loc, name, items, annot) -> + Prim + (inject_loc `after loc, name, List.map inject_expr items, annot) + | Int (loc, value) -> Int (inject_loc `after loc, value) + | String (loc, value) -> String (inject_loc `after loc, value) + | Bytes (loc, value) -> Bytes (inject_loc `after loc, value) + and inject_loc which loc = + let comment = + let ( >?? ) = Option.bind in + List.assoc ~equal:Int.equal loc unexpansion_table >?? fun loc -> + List.assoc ~equal:Int.equal loc type_map >?? fun (bef, aft) -> + let stack = match which with `before -> bef | `after -> aft in + Some (Format.asprintf "%a" print_stack stack) + in + {comment} + in + unexpanded |> root |> inject_expr + |> Format.asprintf "%a" Micheline_printer.print_expr + | None -> + expanded |> Michelson_v1_primitives.strings_of_prims |> root + |> Michelson_v1_macros.unexpand_rec |> Micheline.strip_locations + |> Micheline_printer.printable (fun n -> n) + |> Format.asprintf "%a" Micheline_printer.print_expr + in + match parse source with + | (res, []) -> res + | (_, _ :: _) -> Stdlib.failwith "Michelson_v1_printer.unparse" + +let unparse_toplevel ?type_map = + unparse ?type_map Michelson_v1_parser.parse_toplevel + +let unparse_expression = unparse Michelson_v1_parser.parse_expression + +let unparse_invalid expanded = + let source = + expanded |> root |> Michelson_v1_macros.unexpand_rec + |> Micheline.strip_locations + |> Micheline_printer.printable (fun n -> n) + |> Format.asprintf "%a" Micheline_printer.print_expr_unwrapped + in + fst (Michelson_v1_parser.parse_toplevel source) + +let ocaml_constructor_of_prim prim = + (* Assuming all the prim constructor prefixes match the + [[Michelson_v1_primitives.namespace]]. *) + let prefix = + Michelson_v1_primitives.(namespace prim |> string_of_namespace) + in + Format.asprintf "%s_%s" prefix @@ Michelson_v1_primitives.string_of_prim prim + +let micheline_string_of_expression ~zero_loc expression = + let string_of_list : string list -> string = + fun xs -> String.concat "; " xs |> Format.asprintf "[%s]" + in + let show_loc loc = if zero_loc then 0 else loc in + let rec string_of_node = function + | Int (loc, i) -> + let z = + match Z.to_int i with + | 0 -> "Z.zero" + | 1 -> "Z.one" + | i -> Format.asprintf "Z.of_int %d" i + in + Format.asprintf "Int (%d, %s)" (show_loc loc) z + | String (loc, s) -> Format.asprintf "String (%d, \"%s\")" (show_loc loc) s + | Bytes (loc, b) -> + Format.asprintf + "Bytes (%d, Bytes.of_string \"%s\")" + (show_loc loc) + Bytes.(escaped b |> to_string) + | Prim (loc, prim, nodes, annot) -> + Format.asprintf + "Prim (%d, %s, %s, %s)" + (show_loc loc) + (ocaml_constructor_of_prim prim) + (string_of_list @@ List.map string_of_node nodes) + (string_of_list @@ List.map (Format.asprintf "\"%s\"") annot) + | Seq (loc, nodes) -> + Format.asprintf + "Seq (%d, %s)" + (show_loc loc) + (string_of_list @@ List.map string_of_node nodes) + in + string_of_node (root expression) diff --git a/src/proto_011_PtHangzH/lib_client/michelson_v1_printer.mli b/src/proto_011_PtHangzH/lib_client/michelson_v1_printer.mli new file mode 100644 index 000000000000..07cb29ae8556 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/michelson_v1_printer.mli @@ -0,0 +1,65 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Tezos_micheline + +val print_expr : Format.formatter -> Script_repr.expr -> unit + +val print_expr_unwrapped : Format.formatter -> Script_repr.expr -> unit + +val print_execution_trace : + Format.formatter -> + (Script.location * Gas.t * (Script.expr * string option) list) list -> + unit + +val print_big_map_diff : Format.formatter -> Lazy_storage.diffs -> unit + +(** Insert the type map returned by the typechecker as comments in a + printable Micheline AST. *) +val inject_types : + Script_tc_errors.type_map -> + Michelson_v1_parser.parsed -> + Micheline_printer.node + +(** Unexpand the macros and produce the result of parsing an + intermediate pretty printed source. Useful when working with + contracts extracted from the blockchain and not local files. *) +val unparse_toplevel : + ?type_map:Script_tc_errors.type_map -> + Script.expr -> + Michelson_v1_parser.parsed + +val unparse_expression : Script.expr -> Michelson_v1_parser.parsed + +(** Unexpand the macros and produce the result of parsing an + intermediate pretty printed source. Works on generic trees,for + programs that fail to be converted to a specific script version. *) +val unparse_invalid : string Micheline.canonical -> Michelson_v1_parser.parsed + +val ocaml_constructor_of_prim : Michelson_v1_primitives.prim -> string + +val micheline_string_of_expression : zero_loc:bool -> Script.expr -> string diff --git a/src/proto_011_PtHangzH/lib_client/mockup.ml b/src/proto_011_PtHangzH/lib_client/mockup.ml new file mode 100644 index 000000000000..3e0567d50381 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/mockup.ml @@ -0,0 +1,992 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol.Alpha_context + +(* ------------------------------------------------------------------------- *) +(* Mockup protocol parameters *) + +(** Protocol constants overriding logic. *) +module Protocol_constants_overrides = struct + (** Equivalent of [Constants.parametric] with additionally [chain_id] and [timestamp] but each field is wrapped in an [option]. + [Some] is an override, [None] means "Use the default value". + *) + type t = { + preserved_cycles : int option; + blocks_per_cycle : int32 option; + blocks_per_commitment : int32 option; + blocks_per_roll_snapshot : int32 option; + blocks_per_voting_period : int32 option; + time_between_blocks : Period.t list option; + minimal_block_delay : Period.t option; + endorsers_per_block : int option; + hard_gas_limit_per_operation : Gas.Arith.integral option; + hard_gas_limit_per_block : Gas.Arith.integral option; + proof_of_work_threshold : int64 option; + tokens_per_roll : Tez.t option; + seed_nonce_revelation_tip : Tez.t option; + origination_size : int option; + block_security_deposit : Tez.t option; + endorsement_security_deposit : Tez.t option; + baking_reward_per_endorsement : Tez.t list option; + endorsement_reward : Tez.t list option; + cost_per_byte : Tez.t option; + hard_storage_limit_per_operation : Z.t option; + quorum_min : int32 option; + quorum_max : int32 option; + min_proposal_quorum : int32 option; + initial_endorsers : int option; + delay_per_missing_endorsement : Period.t option; + liquidity_baking_subsidy : Tez.t option; + liquidity_baking_sunset_level : int32 option; + liquidity_baking_escape_ema_threshold : int32 option; + (* Additional, "bastard" parameters (they are not protocol constants but partially treated the same way). *) + chain_id : Chain_id.t option; + timestamp : Time.Protocol.t option; + } + + (** Shamefully copied from [Constants_repr.parametric_encoding] and adapted ([opt] instead of [req]). *) + let encoding : t Data_encoding.t = + let open Data_encoding in + conv + (fun c -> + ( ( c.preserved_cycles, + c.blocks_per_cycle, + c.blocks_per_commitment, + c.blocks_per_roll_snapshot, + c.blocks_per_voting_period, + c.time_between_blocks, + c.endorsers_per_block, + c.hard_gas_limit_per_operation, + c.hard_gas_limit_per_block, + c.proof_of_work_threshold ), + ( ( c.tokens_per_roll, + c.seed_nonce_revelation_tip, + c.origination_size, + c.block_security_deposit, + c.endorsement_security_deposit, + c.baking_reward_per_endorsement, + c.endorsement_reward, + c.cost_per_byte, + c.hard_storage_limit_per_operation ), + ( ( c.quorum_min, + c.quorum_max, + c.min_proposal_quorum, + c.initial_endorsers, + c.delay_per_missing_endorsement, + c.minimal_block_delay, + c.liquidity_baking_subsidy, + c.liquidity_baking_sunset_level, + c.liquidity_baking_escape_ema_threshold ), + (c.chain_id, c.timestamp) ) ) )) + (fun ( ( preserved_cycles, + blocks_per_cycle, + blocks_per_commitment, + blocks_per_roll_snapshot, + blocks_per_voting_period, + time_between_blocks, + endorsers_per_block, + hard_gas_limit_per_operation, + hard_gas_limit_per_block, + proof_of_work_threshold ), + ( ( tokens_per_roll, + seed_nonce_revelation_tip, + origination_size, + block_security_deposit, + endorsement_security_deposit, + baking_reward_per_endorsement, + endorsement_reward, + cost_per_byte, + hard_storage_limit_per_operation ), + ( ( quorum_min, + quorum_max, + min_proposal_quorum, + initial_endorsers, + delay_per_missing_endorsement, + minimal_block_delay, + liquidity_baking_subsidy, + liquidity_baking_sunset_level, + liquidity_baking_escape_ema_threshold ), + (chain_id, timestamp) ) ) ) -> + { + preserved_cycles; + blocks_per_cycle; + blocks_per_commitment; + blocks_per_roll_snapshot; + blocks_per_voting_period; + time_between_blocks; + endorsers_per_block; + hard_gas_limit_per_operation; + hard_gas_limit_per_block; + proof_of_work_threshold; + tokens_per_roll; + seed_nonce_revelation_tip; + origination_size; + block_security_deposit; + endorsement_security_deposit; + baking_reward_per_endorsement; + endorsement_reward; + cost_per_byte; + hard_storage_limit_per_operation; + quorum_min; + quorum_max; + min_proposal_quorum; + initial_endorsers; + delay_per_missing_endorsement; + minimal_block_delay; + liquidity_baking_subsidy; + liquidity_baking_sunset_level; + liquidity_baking_escape_ema_threshold; + chain_id; + timestamp; + }) + (merge_objs + (obj10 + (opt "preserved_cycles" uint8) + (opt "blocks_per_cycle" int32) + (opt "blocks_per_commitment" int32) + (opt "blocks_per_roll_snapshot" int32) + (opt "blocks_per_voting_period" int32) + (opt "time_between_blocks" (list Period.encoding)) + (opt "endorsers_per_block" uint16) + (opt "hard_gas_limit_per_operation" Gas.Arith.z_integral_encoding) + (opt "hard_gas_limit_per_block" Gas.Arith.z_integral_encoding) + (opt "proof_of_work_threshold" int64)) + (merge_objs + (obj9 + (opt "tokens_per_roll" Tez.encoding) + (opt "seed_nonce_revelation_tip" Tez.encoding) + (opt "origination_size" int31) + (opt "block_security_deposit" Tez.encoding) + (opt "endorsement_security_deposit" Tez.encoding) + (opt "baking_reward_per_endorsement" (list Tez.encoding)) + (opt "endorsement_reward" (list Tez.encoding)) + (opt "cost_per_byte" Tez.encoding) + (opt "hard_storage_limit_per_operation" z)) + (merge_objs + (obj9 + (opt "quorum_min" int32) + (opt "quorum_max" int32) + (opt "min_proposal_quorum" int32) + (opt "initial_endorsers" uint16) + (opt "delay_per_missing_endorsement" Period.encoding) + (opt "minimal_block_delay" Period.encoding) + (opt "liquidity_baking_subsidy" Tez.encoding) + (opt "liquidity_baking_sunset_level" int32) + (opt "liquidity_baking_escape_ema_threshold" int32)) + (obj2 + (opt "chain_id" Chain_id.encoding) + (opt "initial_timestamp" Time.Protocol.encoding))))) + + let default_value (cctxt : Tezos_client_base.Client_context.full) : + t tzresult Lwt.t = + let cpctxt = new Protocol_client_context.wrap_full cctxt in + Protocol.Constants_services.all cpctxt (cpctxt#chain, cpctxt#block) + >>=? fun {parametric; _} -> + let to_chain_id_opt = function `Hash c -> Some c | _ -> None in + Shell_services.Blocks.Header.shell_header + cpctxt + ~chain:cpctxt#chain + ~block:cpctxt#block + () + >>=? fun header -> + return + { + preserved_cycles = Some parametric.preserved_cycles; + blocks_per_cycle = Some parametric.blocks_per_cycle; + blocks_per_commitment = Some parametric.blocks_per_commitment; + blocks_per_roll_snapshot = Some parametric.blocks_per_roll_snapshot; + blocks_per_voting_period = Some parametric.blocks_per_voting_period; + time_between_blocks = Some parametric.time_between_blocks; + minimal_block_delay = Some parametric.minimal_block_delay; + endorsers_per_block = Some parametric.endorsers_per_block; + hard_gas_limit_per_operation = + Some parametric.hard_gas_limit_per_operation; + hard_gas_limit_per_block = Some parametric.hard_gas_limit_per_block; + proof_of_work_threshold = Some parametric.proof_of_work_threshold; + tokens_per_roll = Some parametric.tokens_per_roll; + seed_nonce_revelation_tip = Some parametric.seed_nonce_revelation_tip; + origination_size = Some parametric.origination_size; + block_security_deposit = Some parametric.block_security_deposit; + endorsement_security_deposit = + Some parametric.endorsement_security_deposit; + baking_reward_per_endorsement = + Some parametric.baking_reward_per_endorsement; + endorsement_reward = Some parametric.endorsement_reward; + cost_per_byte = Some parametric.cost_per_byte; + hard_storage_limit_per_operation = + Some parametric.hard_storage_limit_per_operation; + quorum_min = Some parametric.quorum_min; + quorum_max = Some parametric.quorum_max; + min_proposal_quorum = Some parametric.min_proposal_quorum; + initial_endorsers = Some parametric.initial_endorsers; + delay_per_missing_endorsement = + Some parametric.delay_per_missing_endorsement; + liquidity_baking_subsidy = Some parametric.liquidity_baking_subsidy; + liquidity_baking_sunset_level = + Some parametric.liquidity_baking_sunset_level; + liquidity_baking_escape_ema_threshold = + Some parametric.liquidity_baking_escape_ema_threshold; + (* Bastard, additional parameters. *) + chain_id = to_chain_id_opt cpctxt#chain; + timestamp = Some header.timestamp; + } + + let no_overrides : t = + { + preserved_cycles = None; + blocks_per_cycle = None; + blocks_per_commitment = None; + blocks_per_roll_snapshot = None; + blocks_per_voting_period = None; + time_between_blocks = None; + minimal_block_delay = None; + endorsers_per_block = None; + hard_gas_limit_per_operation = None; + hard_gas_limit_per_block = None; + proof_of_work_threshold = None; + tokens_per_roll = None; + seed_nonce_revelation_tip = None; + origination_size = None; + block_security_deposit = None; + endorsement_security_deposit = None; + baking_reward_per_endorsement = None; + endorsement_reward = None; + cost_per_byte = None; + hard_storage_limit_per_operation = None; + quorum_min = None; + quorum_max = None; + min_proposal_quorum = None; + initial_endorsers = None; + delay_per_missing_endorsement = None; + liquidity_baking_subsidy = None; + liquidity_baking_sunset_level = None; + liquidity_baking_escape_ema_threshold = None; + chain_id = None; + timestamp = None; + } + + (** Existential wrapper to support heterogeneous lists/maps. *) + type field = + | O : { + name : string; + override_value : 'a option; + pp : Format.formatter -> 'a -> unit; + } + -> field + + let field_pp ppf (O {name; override_value; pp; _}) = + match override_value with + | None -> () + | Some value -> Format.fprintf ppf "@[%s: %a@]" name pp value + + let apply_overrides (cctxt : Tezos_client_base.Client_context.full) (o : t) + (c : Constants.parametric) : Constants.parametric tzresult Lwt.t = + let open Format in + let pp_print_int32 ppf i = fprintf ppf "%li" i in + let pp_print_int64 ppf i = fprintf ppf "%Li" i in + let fields : field list = + [ + O + { + name = "preserved_cycles"; + override_value = o.preserved_cycles; + pp = pp_print_int; + }; + O + { + name = "blocks_per_cycle"; + override_value = o.blocks_per_cycle; + pp = pp_print_int32; + }; + O + { + name = "blocks_per_commitment"; + override_value = o.blocks_per_commitment; + pp = pp_print_int32; + }; + O + { + name = "blocks_per_roll_snapshot"; + override_value = o.blocks_per_roll_snapshot; + pp = pp_print_int32; + }; + O + { + name = "blocks_per_voting_period"; + override_value = o.blocks_per_voting_period; + pp = pp_print_int32; + }; + O + { + name = "time_between_blocks"; + override_value = o.time_between_blocks; + pp = pp_print_list Period.pp; + }; + O + { + name = "minimal_block_delay"; + override_value = o.minimal_block_delay; + pp = Period.pp; + }; + O + { + name = "endorsers_per_block"; + override_value = o.endorsers_per_block; + pp = pp_print_int; + }; + O + { + name = "hard_gas_limit_per_operation"; + override_value = o.hard_gas_limit_per_operation; + pp = Gas.Arith.pp_integral; + }; + O + { + name = "hard_gas_limit_per_block"; + override_value = o.hard_gas_limit_per_block; + pp = Gas.Arith.pp_integral; + }; + O + { + name = "proof_of_work_threshold"; + override_value = o.proof_of_work_threshold; + pp = pp_print_int64; + }; + O + { + name = "tokens_per_roll"; + override_value = o.tokens_per_roll; + pp = Tez.pp; + }; + O + { + name = "seed_nonce_revelation_tip"; + override_value = o.seed_nonce_revelation_tip; + pp = Tez.pp; + }; + O + { + name = "origination_size"; + override_value = o.origination_size; + pp = pp_print_int; + }; + O + { + name = "block_security_deposit"; + override_value = o.block_security_deposit; + pp = Tez.pp; + }; + O + { + name = "endorsement_security_deposit"; + override_value = o.endorsement_security_deposit; + pp = Tez.pp; + }; + O + { + name = "baking_reward_per_endorsement"; + override_value = o.baking_reward_per_endorsement; + pp = pp_print_list Tez.pp; + }; + O + { + name = "endorsement_reward"; + override_value = o.endorsement_reward; + pp = pp_print_list Tez.pp; + }; + O + { + name = "cost_per_byte"; + override_value = o.cost_per_byte; + pp = Tez.pp; + }; + O + { + name = "hard_storage_limit_per_operation"; + override_value = o.hard_storage_limit_per_operation; + pp = Z.pp_print; + }; + O + { + name = "quorum_min"; + override_value = o.quorum_min; + pp = pp_print_int32; + }; + O + { + name = "quorum_max"; + override_value = o.quorum_max; + pp = pp_print_int32; + }; + O + { + name = "min_proposal_quorum"; + override_value = o.min_proposal_quorum; + pp = pp_print_int32; + }; + O + { + name = "initial_endorsers"; + override_value = o.initial_endorsers; + pp = pp_print_int; + }; + O + { + name = "delay_per_missing_endorsement"; + override_value = o.delay_per_missing_endorsement; + pp = Period.pp; + }; + O + { + name = "liquidity_baking_subsidy"; + override_value = o.liquidity_baking_subsidy; + pp = Tez.pp; + }; + O + { + name = "liquidity_baking_sunset_level"; + override_value = o.liquidity_baking_sunset_level; + pp = pp_print_int32; + }; + O + { + name = "liquidity_baking_escape_ema_threshold"; + override_value = o.liquidity_baking_escape_ema_threshold; + pp = pp_print_int32; + }; + O {name = "chain_id"; override_value = o.chain_id; pp = Chain_id.pp}; + O + { + name = "timestamp"; + override_value = o.timestamp; + pp = Time.Protocol.pp_hum; + }; + ] + in + let fields_with_override = + fields + |> List.filter (fun (O {override_value; _}) -> + Option.is_some override_value) + in + (if fields_with_override <> [] then + cctxt#message + "@[mockup client uses protocol overrides:@,%a@]@?" + (pp_print_list field_pp) + fields_with_override + else Lwt.return_unit) + >>= fun () -> + return + ({ + preserved_cycles = + Option.value ~default:c.preserved_cycles o.preserved_cycles; + blocks_per_cycle = + Option.value ~default:c.blocks_per_cycle o.blocks_per_cycle; + blocks_per_commitment = + Option.value ~default:c.blocks_per_commitment o.blocks_per_commitment; + blocks_per_roll_snapshot = + Option.value + ~default:c.blocks_per_roll_snapshot + o.blocks_per_roll_snapshot; + blocks_per_voting_period = + Option.value + ~default:c.blocks_per_voting_period + o.blocks_per_voting_period; + time_between_blocks = + Option.value ~default:c.time_between_blocks o.time_between_blocks; + minimal_block_delay = + Option.value ~default:c.minimal_block_delay o.minimal_block_delay; + endorsers_per_block = + Option.value ~default:c.endorsers_per_block o.endorsers_per_block; + hard_gas_limit_per_operation = + Option.value + ~default:c.hard_gas_limit_per_operation + o.hard_gas_limit_per_operation; + hard_gas_limit_per_block = + Option.value + ~default:c.hard_gas_limit_per_block + o.hard_gas_limit_per_block; + proof_of_work_threshold = + Option.value + ~default:c.proof_of_work_threshold + o.proof_of_work_threshold; + tokens_per_roll = + Option.value ~default:c.tokens_per_roll o.tokens_per_roll; + seed_nonce_revelation_tip = + Option.value + ~default:c.seed_nonce_revelation_tip + o.seed_nonce_revelation_tip; + origination_size = + Option.value ~default:c.origination_size o.origination_size; + block_security_deposit = + Option.value + ~default:c.block_security_deposit + o.block_security_deposit; + endorsement_security_deposit = + Option.value + ~default:c.endorsement_security_deposit + o.endorsement_security_deposit; + baking_reward_per_endorsement = + Option.value + ~default:c.baking_reward_per_endorsement + o.baking_reward_per_endorsement; + endorsement_reward = + Option.value ~default:c.endorsement_reward o.endorsement_reward; + cost_per_byte = Option.value ~default:c.cost_per_byte o.cost_per_byte; + hard_storage_limit_per_operation = + Option.value + ~default:c.hard_storage_limit_per_operation + o.hard_storage_limit_per_operation; + quorum_min = Option.value ~default:c.quorum_min o.quorum_min; + quorum_max = Option.value ~default:c.quorum_max o.quorum_max; + min_proposal_quorum = + Option.value ~default:c.min_proposal_quorum o.min_proposal_quorum; + initial_endorsers = + Option.value ~default:c.initial_endorsers o.initial_endorsers; + delay_per_missing_endorsement = + Option.value + ~default:c.delay_per_missing_endorsement + o.delay_per_missing_endorsement; + liquidity_baking_subsidy = + Option.value + ~default:c.liquidity_baking_subsidy + o.liquidity_baking_subsidy; + liquidity_baking_sunset_level = + Option.value + ~default:c.liquidity_baking_sunset_level + o.liquidity_baking_sunset_level; + liquidity_baking_escape_ema_threshold = + Option.value + ~default:c.liquidity_baking_escape_ema_threshold + o.liquidity_baking_escape_ema_threshold + (* Notice that the chain_id and the timestamp are not used here as they are not protocol constants... *); + } + : Constants.parametric) +end + +module Parsed_account = struct + type t = {name : string; sk_uri : Client_keys.sk_uri; amount : Tez.t} + + let pp ppf account = + let open Format in + let format_amount ppf value = fprintf ppf "amount:%a" Tez.pp value in + fprintf + ppf + "@[name:%s@,sk_uri:%s@,%a@]" + account.name + (Uri.to_string (account.sk_uri :> Uri.t)) + format_amount + account.amount + + let encoding = + let open Data_encoding in + conv + (fun p -> (p.name, p.sk_uri, p.amount)) + (fun (name, sk_uri, amount) -> {name; sk_uri; amount}) + (obj3 + (req "name" string) + (req "sk_uri" Client_keys.Secret_key.encoding) + (req "amount" Tez.encoding)) + + let to_bootstrap_account repr = + Tezos_client_base.Client_keys.neuterize repr.sk_uri >>=? fun pk_uri -> + Tezos_client_base.Client_keys.public_key pk_uri >>=? fun public_key -> + let public_key_hash = Signature.Public_key.hash public_key in + return + Parameters. + {public_key_hash; public_key = Some public_key; amount = repr.amount} + + let default_to_json (cctxt : Tezos_client_base.Client_context.full) : + string tzresult Lwt.t = + let rpc_context = new Protocol_client_context.wrap_full cctxt in + let wallet = (cctxt :> Client_context.wallet) in + let parsed_account_reprs = ref [] in + let errors = ref [] in + Client_keys.list_keys wallet >>=? fun all_keys -> + List.iter_s + (function + | (name, pkh, _pk_opt, Some sk_uri) -> ( + let contract = Contract.implicit_contract pkh in + Client_proto_context.get_balance + rpc_context + ~chain:cctxt#chain + ~block:cctxt#block + contract + >>= fun tz_balance -> + match tz_balance with + | Ok balance -> ( + let tez_repr = Tez.of_mutez @@ Tez.to_mutez balance in + match tez_repr with + | None -> + (* we're reading the wallet, it's content MUST be valid *) + assert false + | Some amount -> + parsed_account_reprs := + {name; sk_uri; amount} :: !parsed_account_reprs ; + Lwt.return_unit) + | Error err -> + errors := err :: !errors ; + Lwt.return_unit) + | _ -> Lwt.return_unit) + all_keys + >>= fun () -> + match !errors with + | [] -> + let json = + Data_encoding.Json.construct + (Data_encoding.list encoding) + !parsed_account_reprs + in + return @@ Data_encoding.Json.to_string json + | errs -> Lwt.return_error @@ List.concat errs +end + +module Bootstrap_account = struct + let encoding : Parameters.bootstrap_account Data_encoding.t = + let open Data_encoding in + let open Parameters in + conv + (fun {public_key_hash; public_key; amount} -> + (public_key_hash, public_key, amount)) + (fun (public_key_hash, public_key, amount) -> + {public_key_hash; public_key; amount}) + (obj3 + (req "public_key_hash" Signature.Public_key_hash.encoding) + (opt "public_key" Signature.Public_key.encoding) + (req "amount" Tez.encoding)) +end + +module Bootstrap_contract = struct + let encoding : Parameters.bootstrap_contract Data_encoding.t = + let open Data_encoding in + let open Parameters in + conv + (fun {delegate; amount; script} -> (delegate, amount, script)) + (fun (delegate, amount, script) -> {delegate; amount; script}) + (obj3 + (req "delegate" Signature.Public_key_hash.encoding) + (req "amount" Tez.encoding) + (req "script" Script.encoding)) +end + +module Protocol_parameters = struct + type t = { + initial_timestamp : Time.Protocol.t; + bootstrap_accounts : Parameters.bootstrap_account list; + bootstrap_contracts : Parameters.bootstrap_contract list; + constants : Constants.parametric; + } + + let encoding : t Data_encoding.t = + let open Data_encoding in + conv + (fun p -> + ( p.initial_timestamp, + p.bootstrap_accounts, + p.bootstrap_contracts, + p.constants )) + (fun ( initial_timestamp, + bootstrap_accounts, + bootstrap_contracts, + constants ) -> + {initial_timestamp; bootstrap_accounts; bootstrap_contracts; constants}) + (obj4 + (req "initial_timestamp" Time.Protocol.encoding) + (req "bootstrap_accounts" (list Bootstrap_account.encoding)) + (req "bootstrap_contracts" (list Bootstrap_contract.encoding)) + (req "constants" Constants.parametric_encoding)) + + let default_value : t = + let parameters = + Default_parameters.parameters_of_constants + Default_parameters.constants_sandbox + in + { + initial_timestamp = Time.Protocol.epoch; + bootstrap_accounts = parameters.bootstrap_accounts; + bootstrap_contracts = parameters.bootstrap_contracts; + constants = parameters.constants; + } +end + +(* This encoding extends [Protocol_constants_overrides.encoding] to allow + reading json files as produced by lib_parameters. Sadly, this require + copying partially [bootstrap_account_encoding], which is not exposed + in parameters_repr.ml. *) +let lib_parameters_json_encoding = + let bootstrap_account_encoding = + let open Data_encoding in + conv + (function + | {Parameters.public_key; amount; _} -> ( + match public_key with + | None -> assert false + | Some pk -> (pk, amount))) + (fun (pk, amount) -> + { + Parameters.public_key = Some pk; + public_key_hash = Signature.Public_key.hash pk; + amount; + }) + (tup2 Signature.Public_key.encoding Tez.encoding) + in + Data_encoding.( + merge_objs + (obj2 + (opt "bootstrap_accounts" (list bootstrap_account_encoding)) + (opt "commitments" (list Commitment.encoding))) + Protocol_constants_overrides.encoding) + +(* ------------------------------------------------------------------------- *) +(* Blocks *) + +type block = { + hash : Block_hash.t; + header : Block_header.t; + operations : Operation.packed list; + context : Protocol.Environment.Context.t; +} + +module Forge = struct + let default_proof_of_work_nonce = + Bytes.create Constants.proof_of_work_nonce_size + + let make_shell ~level ~predecessor ~timestamp ~fitness ~operations_hash = + Tezos_base.Block_header. + { + level; + predecessor; + timestamp; + fitness; + operations_hash; + proto_level = 0; + validation_passes = 0; + context = Context_hash.zero; + } +end + +(* ------------------------------------------------------------------------- *) +(* RPC context *) + +let initial_context chain_id (header : Block_header.shell_header) + ({bootstrap_accounts; bootstrap_contracts; constants; _} : + Protocol_parameters.t) = + let parameters = + Default_parameters.parameters_of_constants + ~bootstrap_accounts + ~bootstrap_contracts + ~with_commitments:false + constants + in + let json = Default_parameters.json_of_parameters parameters in + let proto_params = + Data_encoding.Binary.to_bytes_exn Data_encoding.json json + in + Tezos_protocol_environment.Context.( + let empty = Memory_context.empty in + add empty ["version"] (Bytes.of_string "genesis") >>= fun ctxt -> + add ctxt ["protocol_parameters"] proto_params) + >>= fun ctxt -> + Protocol.Main.init ctxt header >|= Protocol.Environment.wrap_tzresult + >>=? fun {context; _} -> + let ({ + timestamp = predecessor_timestamp; + level = predecessor_level; + fitness = predecessor_fitness; + _; + } + : Block_header.shell_header) = + header + in + let timestamp = + Time.System.to_protocol (Tezos_stdlib_unix.Systime_os.now ()) + in + (* + + We need to forge a predecessor hash to pass it to [value_of_key]. + This initial context is used for RPC, hence this piece of + information is not important and does not have to be meaningful + + *) + let predecessor = + Tezos_base.Block_header.hash {shell = header; protocol_data = Bytes.empty} + in + Protocol.Main.value_of_key + ~chain_id + ~predecessor_context:context + ~predecessor_timestamp + ~predecessor_level + ~predecessor_fitness + ~predecessor + ~timestamp + >|= Protocol.Environment.wrap_tzresult + >>=? fun value_of_key -> + (* + In the mockup mode, reactivity is important and there are + no constraints to be consistent with other nodes. For this + reason, the mockup mode loads the cache lazily. + See {!Environment_context.source_of_cache}. + *) + Tezos_protocol_environment.Context.load_cache context `Lazy (fun key -> + value_of_key key >|= Protocol.Environment.wrap_tzresult) + >>=? fun context -> return context + +let mem_init : + cctxt:Tezos_client_base.Client_context.full -> + parameters:Protocol_parameters.t -> + constants_overrides_json:Data_encoding.json option -> + bootstrap_accounts_json:Data_encoding.json option -> + (Chain_id.t * Tezos_protocol_environment.rpc_context) tzresult Lwt.t = + fun ~cctxt ~parameters ~constants_overrides_json ~bootstrap_accounts_json -> + let hash = + Block_hash.of_b58check_exn + "BLockGenesisGenesisGenesisGenesisGenesisCCCCCeZiLHU" + in + (* Need to read this Json file before since timestamp modification may be in + there *) + (match constants_overrides_json with + | None -> return Protocol_constants_overrides.no_overrides + | Some json -> ( + match Data_encoding.Json.destruct lib_parameters_json_encoding json with + | (_, x) -> return x + | exception error -> + failwith + "cannot read protocol constants overrides: %a" + (Data_encoding.Json.print_error ?print_unknown:None) + error)) + >>=? fun protocol_overrides -> + let default = parameters.initial_timestamp in + let timestamp = Option.value ~default protocol_overrides.timestamp in + (if not @@ Time.Protocol.equal default timestamp then + cctxt#message "@[initial_timestamp: %a@]" Time.Protocol.pp_hum timestamp + else Lwt.return_unit) + >>= fun () -> + let shell_header = + Forge.make_shell + ~level:0l + ~predecessor:hash + ~timestamp + ~fitness:(Fitness.from_int64 0L) + ~operations_hash:Operation_list_list_hash.zero + in + Protocol_constants_overrides.apply_overrides + cctxt + protocol_overrides + parameters.constants + >>=? fun protocol_custom -> + (match bootstrap_accounts_json with + | None -> return None + | Some json -> ( + match + Data_encoding.Json.destruct + (Data_encoding.list Parsed_account.encoding) + json + with + | accounts -> + cctxt#message "@[mockup client uses custom bootstrap accounts:@]" + >>= fun () -> + let open Format in + cctxt#message + "@[%a@]" + (pp_print_list + ~pp_sep:(fun ppf () -> fprintf ppf ";@ ") + Parsed_account.pp) + accounts + >>= fun () -> + List.map_es Parsed_account.to_bootstrap_account accounts + >>=? fun bootstrap_accounts -> return (Some bootstrap_accounts) + | exception error -> + failwith + "cannot read definitions of bootstrap accounts: %a" + (Data_encoding.Json.print_error ?print_unknown:None) + error)) + >>=? fun bootstrap_accounts_custom -> + let chain_id = + Tezos_mockup_registration.Mockup_args.Chain_id.choose + ~from_config_file:protocol_overrides.chain_id + in + initial_context + chain_id + shell_header + { + parameters with + bootstrap_accounts = + Option.value + ~default:parameters.bootstrap_accounts + bootstrap_accounts_custom; + constants = protocol_custom; + } + >>=? fun context -> + return + ( chain_id, + Tezos_protocol_environment. + {block_hash = hash; block_header = shell_header; context} ) + +let migrate : + Chain_id.t * Tezos_protocol_environment.rpc_context -> + (Chain_id.t * Tezos_protocol_environment.rpc_context) tzresult Lwt.t = + fun (chain_id, rpc_context) -> + let Tezos_protocol_environment.{block_hash; context; block_header} = + rpc_context + in + Protocol.Main.init context block_header >|= Protocol.Environment.wrap_tzresult + >>=? fun {context; _} -> + let rpc_context = + Tezos_protocol_environment.{block_hash; block_header; context} + in + return (chain_id, rpc_context) + +(* ------------------------------------------------------------------------- *) +(* Register mockup *) + +let () = + let open Tezos_mockup_registration.Registration in + let module Mockup : MOCKUP = struct + type parameters = Protocol_parameters.t + + type protocol_constants = Protocol_constants_overrides.t + + let parameters_encoding = Protocol_parameters.encoding + + let default_parameters = Protocol_parameters.default_value + + let protocol_constants_encoding = Protocol_constants_overrides.encoding + + let default_protocol_constants = Protocol_constants_overrides.default_value + + let default_bootstrap_accounts = Parsed_account.default_to_json + + let protocol_hash = Protocol.hash + + module Protocol = Protocol_client_context.Lifted_protocol + module Block_services = Protocol_client_context.Alpha_block_services + + let directory = Plugin.RPC.rpc_services + + let init = mem_init + + let migrate = migrate + end in + register_mockup_environment (module Mockup) diff --git a/src/proto_011_PtHangzH/lib_client/operation_result.ml b/src/proto_011_PtHangzH/lib_client/operation_result.ml new file mode 100644 index 000000000000..a2e72c4a8de5 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/operation_result.ml @@ -0,0 +1,567 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Apply_results + +let pp_manager_operation_content (type kind) source internal pp_result ppf + ((operation, result) : kind manager_operation * _) = + Format.fprintf ppf "@[" ; + (match operation with + | Transaction {destination; amount; parameters; entrypoint} -> + Format.fprintf + ppf + "@[%s:@,Amount: %s%a@,From: %a@,To: %a" + (if internal then "Internal transaction" else "Transaction") + Client_proto_args.tez_sym + Tez.pp + amount + Contract.pp + source + Contract.pp + destination ; + (match entrypoint with + | "default" -> () + | _ -> Format.fprintf ppf "@,Entrypoint: %s" entrypoint) ; + (if not (Script_repr.is_unit_parameter parameters) then + let expr = + WithExceptions.Option.to_exn + ~none:(Failure "ill-serialized argument") + (Data_encoding.force_decode parameters) + in + Format.fprintf + ppf + "@,Parameter: @[%a@]" + Michelson_v1_printer.print_expr + expr) ; + pp_result ppf result ; + Format.fprintf ppf "@]" + | Origination {delegate; credit; script = {code; storage}; preorigination = _} + -> + Format.fprintf + ppf + "@[%s:@,From: %a@,Credit: %s%a" + (if internal then "Internal origination" else "Origination") + Contract.pp + source + Client_proto_args.tez_sym + Tez.pp + credit ; + let code = + WithExceptions.Option.to_exn + ~none:(Failure "ill-serialized code") + (Data_encoding.force_decode code) + and storage = + WithExceptions.Option.to_exn + ~none:(Failure "ill-serialized storage") + (Data_encoding.force_decode storage) + in + let {Michelson_v1_parser.source; _} = + Michelson_v1_printer.unparse_toplevel code + in + Format.fprintf + ppf + "@,@[Script:@ @[%a@]@,@[Initial storage:@ %a@]" + Format.pp_print_text + source + Michelson_v1_printer.print_expr + storage ; + (match delegate with + | None -> Format.fprintf ppf "@,No delegate for this contract" + | Some delegate -> + Format.fprintf + ppf + "@,Delegate: %a" + Signature.Public_key_hash.pp + delegate) ; + pp_result ppf result ; + Format.fprintf ppf "@]" + | Reveal key -> + Format.fprintf + ppf + "@[%s of manager public key:@,Contract: %a@,Key: %a%a@]" + (if internal then "Internal revelation" else "Revelation") + Contract.pp + source + Signature.Public_key.pp + key + pp_result + result + | Delegation None -> + Format.fprintf + ppf + "@[%s:@,Contract: %a@,To: nobody%a@]" + (if internal then "Internal Delegation" else "Delegation") + Contract.pp + source + pp_result + result + | Delegation (Some delegate) -> + Format.fprintf + ppf + "@[%s:@,Contract: %a@,To: %a%a@]" + (if internal then "Internal Delegation" else "Delegation") + Contract.pp + source + Signature.Public_key_hash.pp + delegate + pp_result + result + | Register_global_constant {value = lazy_value} -> + let value = + WithExceptions.Option.to_exn + ~none:(Failure "ill-serialized value") + (Data_encoding.force_decode lazy_value) + in + Format.fprintf + ppf + "Register Global:@,@[ Value: %a%a@]" + Michelson_v1_printer.print_expr + value + pp_result + result) ; + Format.fprintf ppf "@]" + +let pp_balance_updates ppf = function + | [] -> () + | balance_updates -> + let open Receipt in + (* For dry runs, the baker's key is zero + (tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU). Instead of printing this + key hash, we want to make the result more informative. *) + let pp_baker ppf baker = + if Signature.Public_key_hash.equal baker Signature.Public_key_hash.zero + then Format.fprintf ppf "the baker who will include this operation" + else Signature.Public_key_hash.pp ppf baker + in + let balance_updates = + List.map + (fun (balance, update, origin) -> + let balance = + match balance with + | Contract c -> Format.asprintf "%a" Contract.pp c + | Rewards (pkh, l) -> + Format.asprintf "rewards(%a,%a)" pp_baker pkh Cycle.pp l + | Fees (pkh, l) -> + Format.asprintf "fees(%a,%a)" pp_baker pkh Cycle.pp l + | Deposits (pkh, l) -> + Format.asprintf "deposits(%a,%a)" pp_baker pkh Cycle.pp l + in + let balance = + match origin with + | Block_application -> balance + | Protocol_migration -> Format.asprintf "migration %s" balance + | Subsidy -> Format.asprintf "subsidy %s" balance + in + (balance, update)) + balance_updates + in + let column_size = + List.fold_left + (fun acc (balance, _) -> Compare.Int.max acc (String.length balance)) + 0 + balance_updates + in + let pp_update ppf = function + | Credited amount -> + Format.fprintf ppf "+%s%a" Client_proto_args.tez_sym Tez.pp amount + | Debited amount -> + Format.fprintf ppf "-%s%a" Client_proto_args.tez_sym Tez.pp amount + in + let pp_one ppf (balance, update) = + let to_fill = column_size + 3 - String.length balance in + let filler = String.make to_fill '.' in + Format.fprintf ppf "%s %s %a" balance filler pp_update update + in + Format.fprintf + ppf + "@[%a@]" + (Format.pp_print_list pp_one) + balance_updates + +let pp_manager_operation_contents_and_result ppf + ( Manager_operation + {source; fee; operation; counter; gas_limit; storage_limit}, + Manager_operation_result + {balance_updates; operation_result; internal_operation_results} ) = + let pp_lazy_storage_diff = function + | None -> () + | Some lazy_storage_diff -> ( + let big_map_diff = + Contract.Legacy_big_map_diff.of_lazy_storage_diff lazy_storage_diff + in + match (big_map_diff :> Contract.Legacy_big_map_diff.item list) with + | [] -> () + | _ :: _ -> + (* TODO: print all lazy storage diff *) + Format.fprintf + ppf + "@,@[Updated big_maps:@ %a@]" + Michelson_v1_printer.print_big_map_diff + lazy_storage_diff) + in + let pp_transaction_result + (Transaction_result + { + balance_updates; + consumed_gas; + storage; + originated_contracts; + storage_size; + paid_storage_size_diff; + lazy_storage_diff; + allocated_destination_contract = _; + }) = + (match originated_contracts with + | [] -> () + | contracts -> + Format.fprintf + ppf + "@,@[Originated contracts:@,%a@]" + (Format.pp_print_list Contract.pp) + contracts) ; + (match storage with + | None -> () + | Some expr -> + Format.fprintf + ppf + "@,@[Updated storage:@ %a@]" + Michelson_v1_printer.print_expr + expr) ; + pp_lazy_storage_diff lazy_storage_diff ; + if storage_size <> Z.zero then + Format.fprintf ppf "@,Storage size: %s bytes" (Z.to_string storage_size) ; + if paid_storage_size_diff <> Z.zero then + Format.fprintf + ppf + "@,Paid storage size diff: %s bytes" + (Z.to_string paid_storage_size_diff) ; + Format.fprintf ppf "@,Consumed gas: %a" Gas.Arith.pp consumed_gas ; + match balance_updates with + | [] -> () + | balance_updates -> + Format.fprintf + ppf + "@,Balance updates:@, %a" + pp_balance_updates + balance_updates + in + let pp_origination_result + (Origination_result + { + lazy_storage_diff; + balance_updates; + consumed_gas; + originated_contracts; + storage_size; + paid_storage_size_diff; + }) = + (match originated_contracts with + | [] -> () + | contracts -> + Format.fprintf + ppf + "@,@[Originated contracts:@,%a@]" + (Format.pp_print_list Contract.pp) + contracts) ; + if storage_size <> Z.zero then + Format.fprintf ppf "@,Storage size: %s bytes" (Z.to_string storage_size) ; + pp_lazy_storage_diff lazy_storage_diff ; + if paid_storage_size_diff <> Z.zero then + Format.fprintf + ppf + "@,Paid storage size diff: %s bytes" + (Z.to_string paid_storage_size_diff) ; + Format.fprintf ppf "@,Consumed gas: %a" Gas.Arith.pp consumed_gas ; + match balance_updates with + | [] -> () + | balance_updates -> + Format.fprintf + ppf + "@,Balance updates:@, %a" + pp_balance_updates + balance_updates + in + let pp_register_global_constant_result + (Register_global_constant_result + {balance_updates; consumed_gas; size_of_constant; global_address}) = + (match balance_updates with + | [] -> + (* Not possible - register global constant operation always returns + balance updates. *) + assert false + | balance_updates -> + Format.fprintf + ppf + "@,Balance updates:@, %a" + pp_balance_updates + balance_updates) ; + Format.fprintf ppf "@,Consumed gas: %a" Gas.Arith.pp consumed_gas ; + Format.fprintf ppf "@,Storage size: %s bytes" (Z.to_string size_of_constant) ; + Format.fprintf ppf "@,Global address: %a" Script_expr_hash.pp global_address + in + let pp_result (type kind) ppf (result : kind manager_operation_result) = + Format.fprintf ppf "@," ; + match result with + | Skipped _ -> Format.fprintf ppf "This operation was skipped" + | Failed (_, _errs) -> Format.fprintf ppf "This operation FAILED." + | Applied (Reveal_result {consumed_gas}) -> + Format.fprintf ppf "This revelation was successfully applied" ; + Format.fprintf ppf "@,Consumed gas: %a" Gas.Arith.pp consumed_gas + | Backtracked (Reveal_result _, _) -> + Format.fprintf + ppf + "@[This revelation was BACKTRACKED, its expected effects were \ + NOT applied.@]" + | Applied (Delegation_result {consumed_gas}) -> + Format.fprintf ppf "This delegation was successfully applied" ; + Format.fprintf ppf "@,Consumed gas: %a" Gas.Arith.pp consumed_gas + | Backtracked (Delegation_result _, _) -> + Format.fprintf + ppf + "@[This delegation was BACKTRACKED, its expected effects were \ + NOT applied.@]" + | Applied (Transaction_result _ as tx) -> + Format.fprintf ppf "This transaction was successfully applied" ; + pp_transaction_result tx + | Backtracked ((Transaction_result _ as tx), _errs) -> + Format.fprintf + ppf + "@[This transaction was BACKTRACKED, its expected effects (as \ + follow) were NOT applied.@]" ; + pp_transaction_result tx + | Applied (Origination_result _ as op) -> + Format.fprintf ppf "This origination was successfully applied" ; + pp_origination_result op + | Backtracked ((Origination_result _ as op), _errs) -> + Format.fprintf + ppf + "@[This origination was BACKTRACKED, its expected effects (as \ + follow) were NOT applied.@]" ; + pp_origination_result op + | Applied (Register_global_constant_result _ as op) -> + Format.fprintf + ppf + "This global constant registration was successfully applied" ; + pp_register_global_constant_result op + | Backtracked ((Register_global_constant_result _ as op), _errs) -> + Format.fprintf + ppf + "@[This registration of a global constant was BACKTRACKED, its \ + expected effects (as follow) were NOT applied.@]" ; + pp_register_global_constant_result op + in + Format.fprintf + ppf + "@[@[Manager signed operations:@,\ + From: %a@,\ + Fee to the baker: %s%a@,\ + Expected counter: %s@,\ + Gas limit: %a@,\ + Storage limit: %s bytes" + Signature.Public_key_hash.pp + source + Client_proto_args.tez_sym + Tez.pp + fee + (Z.to_string counter) + Gas.Arith.pp_integral + gas_limit + (Z.to_string storage_limit) ; + (match balance_updates with + | [] -> () + | balance_updates -> + Format.fprintf + ppf + "@,Balance updates:@, %a" + pp_balance_updates + balance_updates) ; + Format.fprintf + ppf + "@,%a" + (pp_manager_operation_content + (Contract.implicit_contract source) + false + pp_result) + (operation, operation_result) ; + (match internal_operation_results with + | [] -> () + | _ :: _ -> + Format.fprintf + ppf + "@,@[Internal operations:@ %a@]" + (Format.pp_print_list (fun ppf (Internal_operation_result (op, res)) -> + pp_manager_operation_content + op.source + false + pp_result + ppf + (op.operation, res))) + internal_operation_results) ; + Format.fprintf ppf "@]" + +let rec pp_contents_and_result_list : + type kind. Format.formatter -> kind contents_and_result_list -> unit = + fun ppf -> function + | Single_and_result + (Seed_nonce_revelation {level; nonce}, Seed_nonce_revelation_result bus) + -> + Format.fprintf + ppf + "@[Seed nonce revelation:@,\ + Level: %a@,\ + Nonce (hash): %a@,\ + Balance updates:@,\ + \ %a@]" + Raw_level.pp + level + Nonce_hash.pp + (Nonce.hash nonce) + pp_balance_updates + bus + | Single_and_result + (Double_baking_evidence {bh1; bh2}, Double_baking_evidence_result bus) -> + Format.fprintf + ppf + "@[Double baking evidence:@,\ + Exhibit A: %a@,\ + Exhibit B: %a@,\ + Balance updates:@,\ + \ %a@]" + Block_hash.pp + (Block_header.hash bh1) + Block_hash.pp + (Block_header.hash bh2) + pp_balance_updates + bus + | Single_and_result + ( Double_endorsement_evidence {op1; op2; slot = _}, + Double_endorsement_evidence_result bus ) -> + Format.fprintf + ppf + "@[Double endorsement evidence:@,\ + Exhibit A: %a@,\ + Exhibit B: %a@,\ + Balance updates:@,\ + \ %a@]" + Operation_hash.pp + (Operation.hash op1) + Operation_hash.pp + (Operation.hash op2) + pp_balance_updates + bus + | Single_and_result (Activate_account {id; _}, Activate_account_result bus) -> + Format.fprintf + ppf + "@[Genesis account activation:@,\ + Account: %a@,\ + Balance updates:@,\ + \ %a@]" + Ed25519.Public_key_hash.pp + id + pp_balance_updates + bus + | Single_and_result + ( Endorsement_with_slot + { + endorsement = + {protocol_data = {contents = Single (Endorsement {level}); _}; _}; + _; + }, + Endorsement_with_slot_result + (Endorsement_result {balance_updates; delegate; slots}) ) + | Single_and_result + ( Endorsement {level}, + Endorsement_result {balance_updates; delegate; slots} ) -> + Format.fprintf + ppf + "@[Endorsement:@,\ + Level: %a@,\ + Balance updates:%a@,\ + Delegate: %a@,\ + Slots: %a@]" + Raw_level.pp + level + pp_balance_updates + balance_updates + Signature.Public_key_hash.pp + delegate + (Format.pp_print_list ~pp_sep:Format.pp_print_space Format.pp_print_int) + slots + | Single_and_result (Proposals {source; period; proposals}, Proposals_result) + -> + Format.fprintf + ppf + "@[Proposals:@,From: %a@,Period: %ld@,Protocols:@, @[%a@]@]" + Signature.Public_key_hash.pp + source + period + (Format.pp_print_list Protocol_hash.pp) + proposals + | Single_and_result (Ballot {source; period; proposal; ballot}, Ballot_result) + -> + Format.fprintf + ppf + "@[Ballot:@,From: %a@,Period: %ld@,Protocol: %a@,Vote: %a@]" + Signature.Public_key_hash.pp + source + period + Protocol_hash.pp + proposal + Data_encoding.Json.pp + (Data_encoding.Json.construct Vote.ballot_encoding ballot) + | Single_and_result (Failing_noop _arbitrary, _) -> + (* the Failing_noop operation always fails and can't have result *) + . + | Single_and_result + ((Manager_operation _ as op), (Manager_operation_result _ as res)) -> + Format.fprintf ppf "%a" pp_manager_operation_contents_and_result (op, res) + | Cons_and_result + ((Manager_operation _ as op), (Manager_operation_result _ as res), rest) + -> + Format.fprintf + ppf + "%a@\n%a" + pp_manager_operation_contents_and_result + (op, res) + pp_contents_and_result_list + rest + +let pp_operation_result ppf + ((op, res) : 'kind contents_list * 'kind contents_result_list) = + Format.fprintf ppf "@[" ; + let contents_and_result_list = Apply_results.pack_contents_list op res in + pp_contents_and_result_list ppf contents_and_result_list ; + Format.fprintf ppf "@]@." + +let pp_internal_operation ppf + (Internal_operation {source; operation; nonce = _}) = + pp_manager_operation_content + source + true + (fun _ppf () -> ()) + ppf + (operation, ()) diff --git a/src/proto_011_PtHangzH/lib_client/operation_result.mli b/src/proto_011_PtHangzH/lib_client/operation_result.mli new file mode 100644 index 000000000000..cc03abfcd36b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/operation_result.mli @@ -0,0 +1,35 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +val pp_internal_operation : + Format.formatter -> packed_internal_operation -> unit + +val pp_operation_result : + Format.formatter -> + 'kind contents_list * 'kind Apply_results.contents_result_list -> + unit diff --git a/src/proto_011_PtHangzH/lib_client/protocol_client_context.ml b/src/proto_011_PtHangzH/lib_client/protocol_client_context.ml new file mode 100644 index 000000000000..2063d712c002 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/protocol_client_context.ml @@ -0,0 +1,281 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module Lifted_protocol = struct + include Protocol.Environment.Lift (Protocol) + + let hash = Protocol.hash +end + +module Alpha_block_services = + Block_services.Make (Lifted_protocol) (Lifted_protocol) + +(** Client RPC context *) +class type rpc_context = + object + inherit RPC_context.json + + inherit + [Shell_services.chain * Shell_services.block] Protocol.Environment + .RPC_context + .simple + end + +(** The class [wrap_rpc_context] is a wrapper class used by the proxy + mode clients. From a general-purpose RPC_context.json [t], the + class is augmented with shell services to provide RPC calls that + are protocol-dependent. *) +class wrap_rpc_context (t : RPC_context.json) : rpc_context = + object + method base : Uri.t = t#base + + method generic_json_call = t#generic_json_call + + method call_service + : 'm 'p 'q 'i 'o. + (([< Resto.meth] as 'm), unit, 'p, 'q, 'i, 'o) RPC_service.t -> + 'p -> + 'q -> + 'i -> + 'o tzresult Lwt.t = + t#call_service + + method call_streamed_service + : 'm 'p 'q 'i 'o. + (([< Resto.meth] as 'm), unit, 'p, 'q, 'i, 'o) RPC_service.t -> + on_chunk:('o -> unit) -> + on_close:(unit -> unit) -> + 'p -> + 'q -> + 'i -> + (unit -> unit) tzresult Lwt.t = + t#call_streamed_service + + (** Abstracts variables and in protocol RPCs + prefixed by "/chains//blocks//...". *) + inherit + [Shell_services.chain, Shell_services.block] Protocol.Environment + .proto_rpc_context + (t :> RPC_context.t) + Shell_services.Blocks.path + end + +(** The class type [full] allows to create contexts that are + explicitly used by low-level shell functions, while containing + various information (I/O services, RPCs...). Then, depending on the + usage, the type may be coerced into one of its following ascendants + to serve for explicit operations on blocks, chain or daemon for + instance. *) +class type full = + object + (** The class Client_context.full provides I/O services for the + client, the wallet, etc. *) + inherit Client_context.full + + (** Base interface provided to call RPCs, i.e., communication + with the node. A client context is defined by mapping all + RPCs protocol-generic to a specific procotol. *) + inherit + [Shell_services.chain * Shell_services.block] Protocol.Environment + .RPC_context + .simple + + (** Protocol RPCs exposed through the environment (using + an additional chainpath). *) + inherit + [Shell_services.chain, Shell_services.block] Protocol.Environment + .proto_rpc_context + end + +(** From a [Client_context.full], the class allows to call RPCs from + the node and those defined by the protocol. *) +class wrap_full (t : Client_context.full) : full = + object + inherit Client_context.proxy_context t + + inherit + [Shell_services.chain, Shell_services.block] Protocol.Environment + .proto_rpc_context + (t :> RPC_context.t) + Shell_services.Blocks.path + end + +let register_error_kind category ~id ~title ~description ?pp encoding from_error + to_error = + let id = "client." ^ Protocol.name ^ "." ^ id in + register_error_kind + category + ~id + ~title + ~description + ?pp + encoding + from_error + to_error + +(** Initialization calls that run on start-up. Register the various + protocol encodings. *) +let () = + let open Data_encoding.Registration in + register Protocol.Alpha_context.Lazy_storage.encoding ; + (* These encodings are missing a def field which we add before registering them. + These defs should be moved inside their encodings in the protocol code. *) + let def id ids ?title ?description encoding = + Data_encoding.def + (String.concat "." (Protocol.name :: id :: ids)) + ?title + ?description + encoding + in + register @@ def "parameters" [] Protocol.Parameters_repr.encoding ; + register ~pp:Protocol.Alpha_context.Tez.pp + @@ def "tez" [] Protocol.Alpha_context.Tez.encoding ; + register @@ def "roll" [] Protocol.Alpha_context.Roll.encoding ; + register ~pp:Protocol.Alpha_context.Fitness.pp + @@ def "fitness" [] Protocol.Alpha_context.Fitness.encoding ; + register ~pp:Protocol.Alpha_context.Timestamp.pp + @@ def "timestamp" [] Protocol.Alpha_context.Timestamp.encoding ; + register ~pp:Protocol.Alpha_context.Raw_level.pp + @@ def "raw_level" [] Protocol.Alpha_context.Raw_level.encoding ; + register @@ def "vote" ["ballot"] Protocol.Alpha_context.Vote.ballot_encoding ; + register + @@ def "vote" ["ballots"] Protocol.Alpha_context.Vote.ballots_encoding ; + register + @@ def "vote" ["listings"] Protocol.Alpha_context.Vote.listings_encoding ; + register @@ def "seed" [] Protocol.Alpha_context.Seed.seed_encoding ; + register ~pp:Protocol.Alpha_context.Gas.pp + @@ def "gas" [] Protocol.Alpha_context.Gas.encoding ; + register ~pp:Protocol.Alpha_context.Gas.pp_cost + @@ def "gas" ["cost"] Protocol.Alpha_context.Gas.cost_encoding ; + register @@ def "script" [] Protocol.Alpha_context.Script.encoding ; + register @@ def "script" ["expr"] Protocol.Alpha_context.Script.expr_encoding ; + register @@ def "script" ["prim"] Protocol.Alpha_context.Script.prim_encoding ; + register + @@ def "script" ["lazy_expr"] Protocol.Alpha_context.Script.lazy_expr_encoding ; + register + @@ def "script" ["loc"] Protocol.Alpha_context.Script.location_encoding ; + register ~pp:Protocol.Alpha_context.Contract.pp + @@ def "contract" [] Protocol.Alpha_context.Contract.encoding ; + register + @@ def + "contract" + ["big_map_diff"] + Protocol.Alpha_context.Lazy_storage.legacy_big_map_diff_encoding ; + register + @@ def + "delegate" + ["frozen_balance"] + Protocol.Alpha_context.Delegate.frozen_balance_encoding ; + register + @@ def + "delegate" + ["frozen_balance_by_cycles"] + Protocol.Alpha_context.Delegate.frozen_balance_by_cycle_encoding ; + register + @@ def + "receipt" + ["balance_updates"] + Protocol.Alpha_context.Receipt.balance_updates_encoding ; + register ~pp:Protocol.Alpha_context.Level.pp_full + @@ def "level" [] Protocol.Alpha_context.Level.encoding ; + register @@ def "operation" [] Protocol.Alpha_context.Operation.encoding ; + register + @@ def + "operation" + ["contents"] + Protocol.Alpha_context.Operation.contents_encoding ; + register + @@ def + "operation" + ["contents_list"] + Protocol.Alpha_context.Operation.contents_list_encoding ; + register + @@ def + "operation" + ["protocol_data"] + Protocol.Alpha_context.Operation.protocol_data_encoding ; + register + @@ def "operation" ["raw"] Protocol.Alpha_context.Operation.raw_encoding ; + register + @@ def + "operation" + ["internal"] + Protocol.Alpha_context.Operation.internal_operation_encoding ; + register + @@ def + "operation" + ["unsigned"] + Protocol.Alpha_context.Operation.unsigned_encoding ; + register ~pp:Protocol.Alpha_context.Period.pp + @@ def "period" [] Protocol.Alpha_context.Period.encoding ; + register ~pp:Protocol.Alpha_context.Cycle.pp + @@ def "cycle" [] Protocol.Alpha_context.Cycle.encoding ; + register @@ def "constants" [] Protocol.Alpha_context.Constants.encoding ; + register + @@ def "constants" ["fixed"] Protocol.Alpha_context.Constants.fixed_encoding ; + register + @@ def + "constants" + ["parametric"] + Protocol.Alpha_context.Constants.parametric_encoding ; + register @@ def "nonce" [] Protocol.Alpha_context.Nonce.encoding ; + register @@ def "block_header" [] Protocol.Alpha_context.Block_header.encoding ; + register + @@ def + "block_header" + ["unsigned"] + Protocol.Alpha_context.Block_header.unsigned_encoding ; + register + @@ def "block_header" ["raw"] Protocol.Alpha_context.Block_header.raw_encoding ; + register + @@ def + "block_header" + ["contents"] + Protocol.Alpha_context.Block_header.contents_encoding ; + register + @@ def + "block_header" + ["shell_header"] + Protocol.Alpha_context.Block_header.shell_header_encoding ; + register + @@ def + "block_header" + ["protocol_data"] + Protocol.Alpha_context.Block_header.protocol_data_encoding ; + register ~pp:Protocol.Alpha_context.Voting_period.pp + @@ def "voting_period" [] Protocol.Alpha_context.Voting_period.encoding ; + register + @@ def + "voting_period" + ["kind"] + Protocol.Alpha_context.Voting_period.kind_encoding ; + register + @@ def + "errors" + [] + ~description: + "The full list of RPC errors would be too long to include.It is\n\ + available through the RPC `/errors` (GET)." + error_encoding diff --git a/src/proto_011_PtHangzH/lib_client/proxy.ml b/src/proto_011_PtHangzH/lib_client/proxy.ml new file mode 100644 index 000000000000..16b79f4f5693 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/proxy.ml @@ -0,0 +1,183 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module L = (val Tezos_proxy.Logger.logger ~protocol_name:Protocol.name + : Tezos_proxy.Logger.S) + +let proxy_block_header (rpc_context : RPC_context.json) + (chain : Tezos_shell_services.Block_services.chain) + (block : Tezos_shell_services.Block_services.block) = + let rpc_context = new Protocol_client_context.wrap_rpc_context rpc_context in + L.emit + L.proxy_block_header + ( Tezos_shell_services.Block_services.chain_to_string chain, + Tezos_shell_services.Block_services.to_string block ) + >>= fun () -> + Protocol_client_context.Alpha_block_services.header + rpc_context + ~chain + ~block + () + +module ProtoRpc : Tezos_proxy.Proxy_proto.PROTO_RPC = struct + (** Split done only when the mode is [Tezos_proxy.Proxy.server]. Getting + an entire big map at once is useful for dapp developers that + iterate a lot on big maps and that use proxy servers in their + internal infra. *) + let split_server key = + match key with + (* matches paths like: + big_maps/index/i/contents/tail *) + | "big_maps" :: "index" :: i :: "contents" :: tail -> + Some (["big_maps"; "index"; i; "contents"], tail) + | _ -> None + + (** Split that is always done, no matter the mode *) + let split_always key = + match key with + (* matches paths like: + contracts/index/000002298c03ed7d454a101eb7022bc95f7e5f41ac78/tail *) + | "contracts" :: "index" :: i :: tail -> + Some (["contracts"; "index"; i], tail) + | "cycle" :: i :: tail -> Some (["cycle"; i], tail) + (* matches paths like: + rolls/owner/snapshot/19/1/tail *) + | "rolls" :: "owner" :: "snapshot" :: i :: j :: tail -> + Some (["rolls"; "owner"; "snapshot"; i; j], tail) + | "v1" :: tail -> Some (["v1"], tail) + | _ -> None + + let split_key (mode : Tezos_proxy.Proxy.mode) (key : Proxy_context.M.key) : + (Proxy_context.M.key * Proxy_context.M.key) option = + match split_always key with + | Some _ as res -> + res (* No need to inspect the mode, this split is always done *) + | None -> ( + match mode with + | Client -> + (* There are strictly less splits in Client mode: return immediately *) + None + | Server -> split_server key) + + let failure_is_permanent = function + | ["pending_migration_balance_updates"] + | ["pending_migration_operation_results"] -> + true + | _ -> false + + let do_rpc (pgi : Tezos_proxy.Proxy.proxy_getter_input) + (key : Proxy_context.M.key) = + let chain = pgi.chain in + let block = pgi.block in + L.emit + L.proxy_block_rpc + ( Tezos_shell_services.Block_services.chain_to_string chain, + Tezos_shell_services.Block_services.to_string block, + key ) + >>= fun () -> + Protocol_client_context.Alpha_block_services.Context.read + pgi.rpc_context + ~chain + ~block + key + >>=? fun (raw_context : Block_services.raw_context) -> + L.emit L.tree_received + @@ Int64.of_int (Tezos_proxy.Proxy_getter.raw_context_size raw_context) + >>= fun () -> return raw_context +end + +let initial_context + (proxy_builder : + Tezos_proxy.Proxy_proto.proto_rpc -> + Tezos_proxy.Proxy_getter.proxy_m Lwt.t) (rpc_context : RPC_context.json) + (mode : Tezos_proxy.Proxy.mode) + (chain : Tezos_shell_services.Block_services.chain) + (block : Tezos_shell_services.Block_services.block) : + Environment_context.Context.t Lwt.t = + let p_rpc = (module ProtoRpc : Tezos_proxy.Proxy_proto.PROTO_RPC) in + proxy_builder p_rpc >>= fun (module M) -> + L.emit + L.proxy_getter_created + ( Tezos_shell_services.Block_services.chain_to_string chain, + Tezos_shell_services.Block_services.to_string block ) + >>= fun () -> + let pgi : Tezos_proxy.Proxy.proxy_getter_input = + {rpc_context = (rpc_context :> RPC_context.simple); mode; chain; block} + in + let module N : Proxy_context.M.ProxyDelegate = struct + let proxy_dir_mem = M.proxy_dir_mem pgi + + let proxy_get = M.proxy_get pgi + + let proxy_mem = M.proxy_mem pgi + end in + let empty = Proxy_context.empty @@ Some (module N) in + let version_value = "hangzhou_011" in + Tezos_protocol_environment.Context.add + empty + ["version"] + (Bytes.of_string version_value) + >>= fun ctxt -> Protocol.Main.init_context ctxt + +let time_between_blocks (rpc_context : RPC_context.json) + (chain : Tezos_shell_services.Block_services.chain) + (block : Tezos_shell_services.Block_services.block) = + let open Protocol in + let rpc_context = new Protocol_client_context.wrap_rpc_context rpc_context in + Constants_services.all rpc_context (chain, block) >>=? fun constants -> + let times = constants.parametric.time_between_blocks in + return @@ Option.map Alpha_context.Period.to_seconds (List.hd times) + +let init_env_rpc_context (_printer : Tezos_client_base.Client_context.printer) + (proxy_builder : + Tezos_proxy.Proxy_proto.proto_rpc -> + Tezos_proxy.Proxy_getter.proxy_m Lwt.t) (rpc_context : RPC_context.json) + (mode : Tezos_proxy.Proxy.mode) + (chain : Tezos_shell_services.Block_services.chain) + (block : Tezos_shell_services.Block_services.block) : + Tezos_protocol_environment.rpc_context tzresult Lwt.t = + proxy_block_header rpc_context chain block >>=? fun {shell; hash; _} -> + let block_hash = hash in + initial_context proxy_builder rpc_context mode chain block >>= fun context -> + return {Tezos_protocol_environment.block_hash; block_header = shell; context} + +let () = + let open Tezos_proxy.Registration in + let module M : Proxy_sig = struct + module Protocol = Protocol_client_context.Lifted_protocol + + let protocol_hash = Protocol.hash + + let directory = Plugin.RPC.rpc_services + + let hash = Protocol_client_context.Alpha_block_services.hash + + let init_env_rpc_context = init_env_rpc_context + + let time_between_blocks = time_between_blocks + + include Light.M + end in + register_proxy_context (module M) diff --git a/src/proto_011_PtHangzH/lib_client/test/.ocamlformat b/src/proto_011_PtHangzH/lib_client/test/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/test/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_client/test/assert.ml b/src/proto_011_PtHangzH/lib_client/test/assert.ml new file mode 100644 index 000000000000..3d414c2eafa9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/test/assert.ml @@ -0,0 +1,37 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let fail expected given msg = + Format.kasprintf + Stdlib.failwith + "@[%s@ expected: %s@ got: %s@]" + msg + expected + given + +let default_printer _ = "" + +let equal ?(eq = ( = )) ?(print = default_printer) ?(msg = "") x y = + if not (eq x y) then fail (print x) (print y) msg diff --git a/src/proto_011_PtHangzH/lib_client/test/dune b/src/proto_011_PtHangzH/lib_client/test/dune new file mode 100644 index 000000000000..45ac61cc7d1a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/test/dune @@ -0,0 +1,17 @@ +(tests + (names test_michelson_v1_macros test_client_proto_contracts test_client_proto_context test_proxy) + (libraries tezos-base + tezos-micheline + tezos-protocol-011-PtHangzH + tezos-client-011-PtHangzH + tezos-base-test-helpers + tezos-test-helpers + alcotest-lwt + qcheck-alcotest) + (package tezos-client-011-PtHangzH) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_micheline + -open Tezos_client_011_PtHangzH + -open Tezos_protocol_011_PtHangzH + -open Tezos_base_test_helpers + -open Lib_test))) diff --git a/src/proto_011_PtHangzH/lib_client/test/test_client_proto_context.ml b/src/proto_011_PtHangzH/lib_client/test/test_client_proto_context.ml new file mode 100644 index 000000000000..ee5786be4739 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/test/test_client_proto_context.ml @@ -0,0 +1,71 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Testing + ------- + Component: Client + Invocation: dune exec src/proto_alpha/lib_client/test/test_client_proto_context.exe + Subject: Tests roundtrips of batch_transfer_operation_encoding +*) + +open Protocol +open Alpha_context +open Qcheck_helpers + +let binary_roundtrip ?pp encoding t = + let b = Data_encoding.Binary.to_bytes_exn encoding t in + let actual = Data_encoding.Binary.of_bytes_exn encoding b in + qcheck_eq' ?pp ~expected:t ~actual () + +let arb_batch_transfer_operation_encoding : + Client_proto_context.batch_transfer_operation QCheck.arbitrary = + let open QCheck.Gen in + let gen_z = sized @@ fun n -> map Z.of_bits (string_size (return n)) in + let gen_gas_arith_integral = + map Gas.Arith.integral_of_int_exn (int_range 0 (Int.div Int.max_int 1000)) + in + let gen_batch_transfer_operation_encoding = + let* destination = string ?gen:None in + let* fee = opt string in + let* gas_limit = opt gen_gas_arith_integral in + let* storage_limit = opt gen_z in + let* amount = string ?gen:None in + let* arg = opt string in + let* entrypoint = opt string in + return + Client_proto_context. + {destination; fee; gas_limit; storage_limit; amount; arg; entrypoint} + in + QCheck.make gen_batch_transfer_operation_encoding + +let tests = + [ + QCheck.Test.make + ~name:"test_batch_transfer_operation_encoding_roundtrip" + arb_batch_transfer_operation_encoding + (binary_roundtrip Client_proto_context.batch_transfer_operation_encoding); + ] + +let () = Alcotest.run "Client proto context" [("Encodings", qcheck_wrap tests)] diff --git a/src/proto_011_PtHangzH/lib_client/test/test_client_proto_contracts.ml b/src/proto_011_PtHangzH/lib_client/test/test_client_proto_contracts.ml new file mode 100644 index 000000000000..a89e6d5694ae --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/test/test_client_proto_contracts.ml @@ -0,0 +1,94 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Client + Invocation: dune exec src/proto_alpha/lib_client/test/test_client_proto_contracts.exe + Subject: Unit tests for Client_proto_contracts +*) + +(** [mock_wallet entities] is a mock of the + [Tezos_client_base.Client_context.wallet] class that only + implements the [load] method. This methods returns a key-value + association as given by the json string [entities] that should have + the form: ["[{"name": "alias", "value": "key" }, <...>]"]. *) +class mock_wallet (entities : string) : Tezos_client_base.Client_context.wallet + = + object + method load_passwords = None + + method read_file _path = failwith "mock_wallet:read_file" + + method get_base_dir = assert false + + method with_lock : type a. (unit -> a Lwt.t) -> a Lwt.t = fun _f -> _f () + + method load : type a. + string -> default:a -> a Data_encoding.encoding -> a tzresult Lwt.t = + fun _alias_name ~default:_default _encoding -> + let json = (Ezjsonm.from_string entities :> Data_encoding.json) in + return @@ Data_encoding.Json.destruct _encoding json + + method write : type a. + string -> a -> a Data_encoding.encoding -> unit tzresult Lwt.t = + fun _alias_name _list _encoding -> failwith "mock_wallet:write" + end + +(** + Test. + Tests different lookups of + [Client_proto_contracts.ContractAlias.find_destination]. +*) +let test_find_destination _ = + let bootstrap1 = "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" in + let wallet_json = + Format.asprintf {| [{"name": "test_alias", "value": "%s" }] |} bootstrap1 + in + let w = new mock_wallet wallet_json in + let test msg key exp_source = + Client_proto_contracts.ContractAlias.find_destination w key + >>=? fun (_, contract) -> + Client_proto_contracts.RawContractAlias.to_source contract + >>=? fun source -> + (* Alcotest equality assertion *) + Alcotest.(check string msg source exp_source) ; + return_unit + in + test "Expected alias:test_alias = bootstrap1" "alias:test_alias" bootstrap1 + >>=? fun () -> + test "Expected key:test_alias = bootstrap1" "key:test_alias" bootstrap1 + >>=? fun () -> + test "Expected bootstrap1 = bootstrap1" bootstrap1 bootstrap1 >>=? fun () -> + test "Expected test_alias bootstrap1" "test_alias" bootstrap1 + +let () = + Alcotest_lwt.run + "tezos-lib-client-proto-contracts" + [ + ( "client_proto_contracts", + [Tztest.tztest "test_find_destination" `Quick test_find_destination] ); + ] + |> Lwt_main.run diff --git a/src/proto_011_PtHangzH/lib_client/test/test_michelson_v1_macros.ml b/src/proto_011_PtHangzH/lib_client/test/test_michelson_v1_macros.ml new file mode 100644 index 000000000000..d493c09e2cab --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/test/test_michelson_v1_macros.ml @@ -0,0 +1,1359 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Client + Invocation: dune build @src/proto_alpha/lib_client/runtest + Dependencies: src/proto_alpha/lib_client/test/assert.ml + Subject: Expansion and unexpansion of Micheline terms. +*) + +open Protocol + +let print expr : string = + expr + |> Micheline_printer.printable (fun s -> s) + |> Format.asprintf "%a" Micheline_printer.print_expr + +(* expands : expression with macros fully expanded *) + +let assert_expands + (original : (Micheline_parser.location, string) Micheline.node) + (expanded : (Micheline_parser.location, string) Micheline.node) = + let ({Michelson_v1_parser.expanded = expansion; _}, errors) = + let source = print (Micheline.strip_locations original) in + Michelson_v1_parser.expand_all ~source ~original + in + match errors with + | [] -> + Assert.equal + ~print + (Michelson_v1_primitives.strings_of_prims expansion) + (Micheline.strip_locations expanded) ; + ok () + | errors -> Error errors + +(****************************************************************************) + +open Micheline + +let zero_loc = Micheline_parser.location_zero + +let left_branch = Seq (zero_loc, [Prim (zero_loc, "SWAP", [], [])]) + +let right_branch = Seq (zero_loc, []) + +(***************************************************************************) +(* Test expands *) +(***************************************************************************) + +(** [prim_name] is the syntactic sugar to be expanded, while [compare_name] + is syntactic atom. *) +let assert_compare_macro prim_name compare_name = + assert_expands + (Prim (zero_loc, prim_name, [], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, "COMPARE", [], []); + Prim (zero_loc, compare_name, [], []); + ] )) + +(** Expand "COMP{EQ|NEQ|LT|GT|LE|GE}" + into "COMPARE ; {EQ|NEQ|LT|GT|LE|GE}". +*) +let test_compare_marco_expansion () = + assert_compare_macro "CMPEQ" "EQ" >>? fun () -> + assert_compare_macro "CMPNEQ" "NEQ" >>? fun () -> + assert_compare_macro "CMPLT" "LT" >>? fun () -> + assert_compare_macro "CMPGT" "GT" >>? fun () -> + assert_compare_macro "CMPLE" "LE" >>? fun () -> + assert_compare_macro "CMPGE" "GE" + +let assert_if_macro prim_name compare_name = + assert_expands + (Prim (zero_loc, prim_name, [left_branch; right_branch], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, compare_name, [], []); + Prim (zero_loc, "IF", [left_branch; right_branch], []); + ] )) + +(** Expand "IF{EQ|NEQ|LT|GT|LE|GE}" + into "{EQ|NEQ|LT|GT|LE|GE} ; IF" +*) +let test_if_compare_macros_expansion () = + assert_if_macro "IFEQ" "EQ" >>? fun () -> + assert_if_macro "IFNEQ" "NEQ" >>? fun () -> + assert_if_macro "IFLT" "LT" >>? fun () -> + assert_if_macro "IFGT" "GT" >>? fun () -> + assert_if_macro "IFLE" "LE" >>? fun () -> assert_if_macro "IFGE" "GE" + +let assert_if_cmp_macros prim_name compare_name = + assert_expands + (Prim (zero_loc, prim_name, [left_branch; right_branch], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, "COMPARE", [], []); + Prim (zero_loc, compare_name, [], []); + Prim (zero_loc, "IF", [left_branch; right_branch], []); + ] )) + +(** Expand "IF{EQ|NEQ|LT|GT|LE|GE}" + into "{EQ|NEQ|LT|GT|LE|GE} ; IF" +*) +let test_if_cmp_macros_expansion () = + assert_if_cmp_macros "IFCMPEQ" "EQ" >>? fun () -> + assert_if_cmp_macros "IFCMPNEQ" "NEQ" >>? fun () -> + assert_if_cmp_macros "IFCMPLT" "LT" >>? fun () -> + assert_if_cmp_macros "IFCMPGT" "GT" >>? fun () -> + assert_if_cmp_macros "IFCMPLE" "LE" >>? fun () -> + assert_if_cmp_macros "IFCMPGE" "GE" + +(****************************************************************************) +(* Fail *) + +(** Expand "FAIL" + into "UNIT ; FAILWITH" +*) +let test_fail_expansion () = + assert_expands + (Prim (zero_loc, "FAIL", [], [])) + (Seq + ( zero_loc, + [Prim (zero_loc, "UNIT", [], []); Prim (zero_loc, "FAILWITH", [], [])] + )) + +(**********************************************************************) +(* assertion *) + +let seq_unit_failwith = + Seq + ( zero_loc, + [Prim (zero_loc, "UNIT", [], []); Prim (zero_loc, "FAILWITH", [], [])] ) + +(* {} {FAIL} *) +let fail_false = [Seq (zero_loc, []); Seq (zero_loc, [seq_unit_failwith])] + +(* {FAIL} {} *) +let fail_true = [Seq (zero_loc, [seq_unit_failwith]); Seq (zero_loc, [])] + +(** Expand "ASSERT" + into "IF {} {FAIL}" +*) +let test_assert_expansion () = + assert_expands + (Prim (zero_loc, "ASSERT", [], [])) + (Seq (zero_loc, [Prim (zero_loc, "IF", fail_false, [])])) + +let assert_assert_if_compare prim_name compare_name = + assert_expands + (Prim (zero_loc, prim_name, [], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, compare_name, [], []); + Prim (zero_loc, "IF", fail_false, []); + ] )) + +(** Expand "ASSERT_{EQ|NEQ|LT|GT|LE|GE}" + into "{EQ|NEQ|LT|GT|LE|GE} ; IF {} {FAIL}" +*) +let test_assert_if () = + assert_assert_if_compare "ASSERT_EQ" "EQ" >>? fun () -> + assert_assert_if_compare "ASSERT_NEQ" "NEQ" >>? fun () -> + assert_assert_if_compare "ASSERT_LT" "LT" >>? fun () -> + assert_assert_if_compare "ASSERT_LE" "LE" >>? fun () -> + assert_assert_if_compare "ASSERT_GT" "GT" >>? fun () -> + assert_assert_if_compare "ASSERT_GE" "GE" + +let assert_cmp_if prim_name compare_name = + assert_expands + (Prim (zero_loc, prim_name, [], [])) + (Seq + ( zero_loc, + [ + Seq + ( zero_loc, + [ + Prim (zero_loc, "COMPARE", [], []); + Prim (zero_loc, compare_name, [], []); + ] ); + Prim (zero_loc, "IF", fail_false, []); + ] )) + +(** Expand "ASSERT_CMP{EQ|NEQ|LT|GT|LE|GE}" + into "COMPARE ; {EQ|NEQ|LT|GT|LE|GE} ; IF {} {FAIL}" +*) +let test_assert_cmp_if () = + assert_cmp_if "ASSERT_CMPEQ" "EQ" >>? fun () -> + assert_cmp_if "ASSERT_CMPNEQ" "NEQ" >>? fun () -> + assert_cmp_if "ASSERT_CMPLT" "LT" >>? fun () -> + assert_cmp_if "ASSERT_CMPLE" "LE" >>? fun () -> + assert_cmp_if "ASSERT_CMPGT" "GT" >>? fun () -> + assert_cmp_if "ASSERT_CMPGE" "GE" + +(* The work of merge request !628 + > ASSERT_LEFT @x => IF_LEFT {RENAME @x} {FAIL} + > ASSERT_RIGHT @x => IF_LEFT {FAIL} {RENAME @x} + > ASSERT_SOME @x => IF_NONE {FAIL} {RENAME @x} +*) + +let may_rename annot = Seq (zero_loc, [Prim (zero_loc, "RENAME", [], annot)]) + +let fail_false_may_rename = + [ + may_rename ["@annot"]; + Seq + ( zero_loc, + [ + Seq + ( zero_loc, + [ + Prim (zero_loc, "UNIT", [], []); + Prim (zero_loc, "FAILWITH", [], []); + ] ); + ] ); + ] + +let fail_true_may_rename = + [ + Seq + ( zero_loc, + [ + Seq + ( zero_loc, + [ + Prim (zero_loc, "UNIT", [], []); + Prim (zero_loc, "FAILWITH", [], []); + ] ); + ] ); + may_rename ["@annot"]; + ] + +(** Expand "ASSERT_SOME @annot" + into "IF_NONE { } {UNIT;FAILWITH}" + using variable annotation "@annot" +*) +let test_assert_some_annot () = + assert_expands + (Prim (zero_loc, "ASSERT_SOME", [], ["@annot"])) + (Seq (zero_loc, [Prim (zero_loc, "IF_NONE", fail_true_may_rename, [])])) + +(** Expand "ASSERT_SOME" + into "IF_NONE { UNIT;FAILWITH } { }" +*) +let test_assert_some () = + assert_expands + (Prim (zero_loc, "ASSERT_SOME", [], [])) + (Seq (zero_loc, [Prim (zero_loc, "IF_NONE", fail_true, [])])) + +(** Expand "ASSERT_LEFT @annot" + into "IF_LEFT { } {UNIT;FAILWITH}" + using variable annotation "@annot" +*) +let test_assert_left_annot () = + assert_expands + (Prim (zero_loc, "ASSERT_LEFT", [], ["@annot"])) + (Seq (zero_loc, [Prim (zero_loc, "IF_LEFT", fail_false_may_rename, [])])) + +(** Expand "ASSERT_LEFT" + into "IF_LEFT { } {UNIT;FAILWITH}" +*) +let test_assert_left () = + assert_expands + (Prim (zero_loc, "ASSERT_LEFT", [], [])) + (Seq (zero_loc, [Prim (zero_loc, "IF_LEFT", fail_false, [])])) + +(** Expand "ASSERT_RIGHT @annot" + into "IF_LEFT {UNIT;FAILWITH} { }" + using variable annotation "@annot" +*) +let test_assert_right_annot () = + assert_expands + (Prim (zero_loc, "ASSERT_RIGHT", [], ["@annot"])) + (Seq (zero_loc, [Prim (zero_loc, "IF_LEFT", fail_true_may_rename, [])])) + +(** Expand "ASSERT_RIGHT" + into "IF_LEFT {UNIT;FAILWITH} { }" +*) +let test_assert_right () = + assert_expands + (Prim (zero_loc, "ASSERT_RIGHT", [], [])) + (Seq (zero_loc, [Prim (zero_loc, "IF_LEFT", fail_true, [])])) + +(** Expand "ASSERT_NONE" + into "IF_NONE { } { UNIT;FAILWITH }" +*) +let test_assert_none () = + assert_expands + (Prim (zero_loc, "ASSERT_NONE", [], [])) + (Seq (zero_loc, [Prim (zero_loc, "IF_NONE", fail_false, [])])) + +(***********************************************************************) +(*Syntactic Conveniences*) + +(* diip *) + +(** Expand "DIP" into "DIP". + Expand "DIIIIIIIIP" into "DIP 8". + Expand "DIIP" into "DIP 2". +*) +let test_diip () = + let code = Seq (zero_loc, [Prim (zero_loc, "CAR", [], [])]) in + assert_expands + (Prim (zero_loc, "DIP", [code], [])) + (Prim (zero_loc, "DIP", [code], [])) + >>? fun () -> + assert_expands + (Prim (zero_loc, "DIIIIIIIIP", [code], [])) + (Prim (zero_loc, "DIP", [Int (zero_loc, Z.of_int 8); code], [])) + >>? fun () -> + assert_expands + (Prim (zero_loc, "DIIP", [code], [])) + (Prim (zero_loc, "DIP", [Int (zero_loc, Z.of_int 2); code], [])) + +(* pair *) + +(** Expand "PAIR" + into "PAIR" +*) +let test_pair () = + assert_expands + (Prim (zero_loc, "PAIR", [], [])) + (Prim (zero_loc, "PAIR", [], [])) + +(** Expand "PAPPAIIR" + into "DIP {PAIR}; DIP {PAIR}; PAIR" +*) +let test_pappaiir () = + let pair = Prim (zero_loc, "PAIR", [], []) in + assert_expands + (Prim (zero_loc, "PAPPAIIR", [], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DIP", [Seq (zero_loc, [pair])], []); + Prim (zero_loc, "DIP", [Seq (zero_loc, [pair])], []); + pair; + ] )) + +(* unpair *) + +(** Expand "UNPAIR" + into "DUP ; CAR ; DIP {CDR}" +*) +let test_unpair () = + assert_expands + (Prim (zero_loc, "UNPAIR", [], [])) + (Prim (zero_loc, "UNPAIR", [], [])) + +(* duup *) + +(** Expand "DUUP" + into "DIP {DUP} ; SWAP" +*) +let test_duup () = + assert_expands + (Prim (zero_loc, "DUUP", [], [])) + (Prim (zero_loc, "DUP", [Int (zero_loc, Z.of_int 2)], [])) + +(* car/cdr *) + +(** Expand "CAR" into "CAR" + Expand "CDR" into "CDR" + Expand "CADR" into "CAR ; CDR" + Expand "CDAR" into "CDR ; CAR" +*) +let test_caddadr_expansion () = + let car = Prim (zero_loc, "CAR", [], []) in + assert_expands (Prim (zero_loc, "CAR", [], [])) car >>? fun () -> + let cdr = Prim (zero_loc, "CDR", [], []) in + assert_expands (Prim (zero_loc, "CDR", [], [])) cdr >>? fun () -> + assert_expands (Prim (zero_loc, "CADR", [], [])) (Seq (zero_loc, [car; cdr])) + >>? fun () -> + assert_expands (Prim (zero_loc, "CDAR", [], [])) (Seq (zero_loc, [cdr; car])) + +let test_carn_cdrn_expansion () = + let car n = Prim (zero_loc, "CAR", [Int (zero_loc, Z.of_int n)], []) in + let cdr n = Prim (zero_loc, "CDR", [Int (zero_loc, Z.of_int n)], []) in + let get n = + Seq (zero_loc, [Prim (zero_loc, "GET", [Int (zero_loc, Z.of_int n)], [])]) + in + assert_expands (cdr 0) (get 0) >>? fun () -> + assert_expands (car 0) (get 1) >>? fun () -> + assert_expands (cdr 1) (get 2) >>? fun () -> + assert_expands (car 1) (get 3) >>? fun () -> assert_expands (cdr 2) (get 4) + +(* if_some *) + +(** Expand "IF_SOME { 1 } { 2 }" + into "IF_NONE { 2 } { 1 }" +*) +let test_if_some () = + assert_expands + (Prim (zero_loc, "IF_SOME", [right_branch; left_branch], [])) + (Seq + (zero_loc, [Prim (zero_loc, "IF_NONE", [left_branch; right_branch], [])])) + +(*set_caddadr*) + +(** Expand "SET_CAR" + into "CDR; SWAP; PAIR" +*) +let test_set_car_expansion () = + assert_expands + (Prim (zero_loc, "SET_CAR", [], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%"; "%@"]); + ] )) + +(** Expand "SET_CDR" + into "CAR; PAIR" +*) +let test_set_cdr_expansion () = + assert_expands + (Prim (zero_loc, "SET_CDR", [], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, "CAR", [], ["@%%"]); + Prim (zero_loc, "PAIR", [], ["%@"; "%"]); + ] )) + +(** Expand "SET_CADR" + into "DUP; DIP {CAR; { CAR; PAIR }}; CDR; SWAP; PAIR" +*) +let test_set_cadr_expansion () = + let set_car = + Seq + ( zero_loc, + [ + Prim (zero_loc, "CAR", [], ["@%%"]); + Prim (zero_loc, "PAIR", [], ["%@"; "%"]); + ] ) + in + assert_expands + (Prim (zero_loc, "SET_CADR", [], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "CAR", [], ["@%%"]); set_car])], + [] ); + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%@"; "%@"]); + ] )) + +(** Expand "SET_CDAR" + into "DUP; DIP {CDR; { CDR; SWAP; PAIR }}; CAR; PAIR" +*) +let test_set_cdar_expansion () = + let set_cdr = + Seq + ( zero_loc, + [ + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%"; "%@"]); + ] ) + in + assert_expands + (Prim (zero_loc, "SET_CDAR", [], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "CDR", [], ["@%%"]); set_cdr])], + [] ); + Prim (zero_loc, "CAR", [], ["@%%"]); + Prim (zero_loc, "PAIR", [], ["%@"; "%@"]); + ] )) + +(* TO BE CHANGE IN THE DOCUMENTATION: @MR!791 + FROM: + > MAP_CAR code => DUP ; CDR ; DIP { CAR ; code } ; SWAP ; PAIR + TO: + > MAP_CAR code => DUP ; CDR ; DIP { CAR ; {code} } ; SWAP ; PAIR +*) + +(** Expand "MAP_CAR {CAR}" + into "DUP; CDR; DIP {CAR; CAR}; SWAP; PAIR" +*) +let test_map_car () = + (* code is a sequence *) + let code = Seq (zero_loc, [Prim (zero_loc, "CAR", [], [])]) in + assert_expands + (Prim (zero_loc, "MAP_CAR", [code], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "CAR", [], []); code])], + [] ); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%"; "%@"]); + ] )) + +(** Expand "MAP_CDR {CAR}" + into "DUP; CDR; CAR; SWAP; CAR; PAIR" +*) +let test_map_cdr () = + let code = Seq (zero_loc, [Prim (zero_loc, "CAR", [], [])]) in + assert_expands + (Prim (zero_loc, "MAP_CDR", [code], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim (zero_loc, "CDR", [], []); + code; + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "CAR", [], ["@%%"]); + Prim (zero_loc, "PAIR", [], ["%@"; "%"]); + ] )) + +(** Expand "MAP_CAADR {CAR}" + into "DUP; + DIP { CAR; + DUP; + DIP { CAR; + DUP; + CDR; + CAR; + SWAP; + CAR; + PAIR + } + CDR; + SWAP; + PAIR + }; + CDR; + SWAP; + PAIR" +*) +let test_map_caadr () = + let code = Seq (zero_loc, [Prim (zero_loc, "CAR", [], [])]) in + let map_cdr = + Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim (zero_loc, "CDR", [], []); + code; + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "CAR", [], ["@%%"]); + Prim (zero_loc, "PAIR", [], ["%@"; "%"]); + ] ) + in + let map_cadr = + Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "CAR", [], ["@%%"]); map_cdr])], + [] ); + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%@"; "%@"]); + ] ) + in + assert_expands + (Prim (zero_loc, "MAP_CAADR", [code], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "CAR", [], ["@%%"]); map_cadr])], + [] ); + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%@"; "%@"]); + ] )) + +(** Expand "MAP_CDADR" + into "DUP; + DIP { CDR; + DUP; + DIP { CAR; + DUP; + CDR; + CAR; + SWAP; + CAR; + PAIR + }; + CDR; + CAR; + PAIR + }; + CAR; + PAIR" +*) +let test_map_cdadr () = + let code = Seq (zero_loc, [Prim (zero_loc, "CAR", [], [])]) in + let map_cdr = + Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim (zero_loc, "CDR", [], []); + code; + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "CAR", [], ["@%%"]); + Prim (zero_loc, "PAIR", [], ["%@"; "%"]); + ] ) + in + let map_cadr = + Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "CAR", [], ["@%%"]); map_cdr])], + [] ); + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%@"; "%@"]); + ] ) + in + assert_expands + (Prim (zero_loc, "MAP_CDADR", [code], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "CDR", [], ["@%%"]); map_cadr])], + [] ); + Prim (zero_loc, "CAR", [], ["@%%"]); + Prim (zero_loc, "PAIR", [], ["%@"; "%@"]); + ] )) + +(****************************************************************************) +(* Unexpand tests *) +(****************************************************************************) + +(** Asserts that unexpanding the expression [original] conforms with + the canonical form of [ex]. + [unparse.Michelson_v1_parser.unexpanded] contains the original + expression with macros *) +let assert_unexpansion original ex = + let ({Michelson_v1_parser.expanded; _}, errors) = + let source = print (Micheline.strip_locations original) in + Michelson_v1_parser.expand_all ~source ~original + in + let unparse = Michelson_v1_printer.unparse_expression expanded in + match errors with + | [] -> + Assert.equal + ~print + unparse.Michelson_v1_parser.unexpanded + (Micheline.strip_locations ex) ; + ok () + | _ :: _ -> Error errors + +let assert_unexpansion_consistent original = + let ({Michelson_v1_parser.expanded; _}, errors) = + let source = print (Micheline.strip_locations original) in + Michelson_v1_parser.expand_all ~source ~original + in + match errors with + | _ :: _ -> Error errors + | [] -> + let {Michelson_v1_parser.unexpanded; _} = + Michelson_v1_printer.unparse_expression expanded + in + Assert.equal ~print unexpanded (Micheline.strip_locations original) ; + ok () + +(** Unexpanding "UNIT; FAILWITH" + yields "FAIL" +*) +let test_unexpand_fail () = + assert_unexpansion + (Seq + ( zero_loc, + [Prim (zero_loc, "UNIT", [], []); Prim (zero_loc, "FAILWITH", [], [])] + )) + (Prim (zero_loc, "FAIL", [], [])) + +(** Unexpanding "IF_LEFT { 1 } { 2 }" + yields "IF_RIGHT { 2 } { 1 }" +*) +let test_unexpand_if_right () = + assert_unexpansion + (Seq + (zero_loc, [Prim (zero_loc, "IF_LEFT", [left_branch; right_branch], [])])) + (Prim (zero_loc, "IF_RIGHT", [right_branch; left_branch], [])) + +(** IF_NONE + Unexpanding "IF_NONE { 1 } { 2 }" + yields "IF_SOME { 2 } { 1 }" +*) +let test_unexpand_if_some () = + assert_unexpansion + (Seq + (zero_loc, [Prim (zero_loc, "IF_NONE", [left_branch; right_branch], [])])) + (Prim (zero_loc, "IF_SOME", [right_branch; left_branch], [])) + +(** Unexpanding "IF {} { UNIT; FAILWITH }" + yields "ASSERT" +*) +let test_unexpand_assert () = + assert_unexpansion + (Seq (zero_loc, [Prim (zero_loc, "IF", fail_false, [])])) + (Prim (zero_loc, "ASSERT", [], [])) + +let assert_unexpansion_assert_if_compare compare_name prim_name = + assert_unexpansion + (Seq + ( zero_loc, + [ + Prim (zero_loc, compare_name, [], []); + Prim (zero_loc, "IF", fail_false, []); + ] )) + (Prim (zero_loc, prim_name, [], [])) + +(** Unexpanding "{EQ|NEQ|LT|LE|GT|GE} ; IF {} {FAIL}" + yields "ASSERT_{EQ|NEQ|LT|LE|GT|GE}" +*) +let test_unexpand_assert_if () = + assert_unexpansion_assert_if_compare "EQ" "ASSERT_EQ" >>? fun () -> + assert_unexpansion_assert_if_compare "NEQ" "ASSERT_NEQ" >>? fun () -> + assert_unexpansion_assert_if_compare "LT" "ASSERT_LT" >>? fun () -> + assert_unexpansion_assert_if_compare "LE" "ASSERT_LE" >>? fun () -> + assert_unexpansion_assert_if_compare "GT" "ASSERT_GT" >>? fun () -> + assert_unexpansion_assert_if_compare "GE" "ASSERT_GE" + +let assert_unexpansion_assert_cmp_if_compare compare_name prim_name = + assert_unexpansion + (Seq + ( zero_loc, + [ + Seq + ( zero_loc, + [ + Prim (zero_loc, "COMPARE", [], []); + Prim (zero_loc, compare_name, [], []); + ] ); + Prim (zero_loc, "IF", fail_false, []); + ] )) + (Prim (zero_loc, prim_name, [], [])) + +(** Unexpanding "COMPARE; {EQ|NEQ|LT|LE|GT|GE}; IF {} {FAIL}" + yields "ASSERT_CMP{EQ|NEQ|LT|LE|GT|GE}" +*) +let test_unexpansion_assert_cmp_if () = + assert_unexpansion_assert_cmp_if_compare "EQ" "ASSERT_CMPEQ" >>? fun () -> + assert_unexpansion_assert_cmp_if_compare "NEQ" "ASSERT_CMPNEQ" >>? fun () -> + assert_unexpansion_assert_cmp_if_compare "LT" "ASSERT_CMPLT" >>? fun () -> + assert_unexpansion_assert_cmp_if_compare "LE" "ASSERT_CMPLE" >>? fun () -> + assert_unexpansion_assert_cmp_if_compare "GT" "ASSERT_CMPGT" >>? fun () -> + assert_unexpansion_assert_cmp_if_compare "GE" "ASSERT_CMPGE" + +(** Unexpanding "IF_NONE { FAIL } { RENAME @annot }" + yields "ASSERT_SOME @annot" +*) +let test_unexpand_assert_some_annot () = + assert_unexpansion + (Seq (zero_loc, [Prim (zero_loc, "IF_NONE", fail_true_may_rename, [])])) + (Prim (zero_loc, "ASSERT_SOME", [], ["@annot"])) + +(** Unexpanding "IF_LEFT { RENAME @annot } { FAIL }" + yields "ASSERT_LEFT @annot" +*) +let test_unexpand_assert_left_annot () = + assert_unexpansion + (Seq (zero_loc, [Prim (zero_loc, "IF_LEFT", fail_false_may_rename, [])])) + (Prim (zero_loc, "ASSERT_LEFT", [], ["@annot"])) + +(** Unexpanding "IF_LEFT { FAIL } { RENAME @annot }" + yields "ASSERT_RIGHT @annot" +*) +let test_unexpand_assert_right_annot () = + assert_unexpansion + (Seq (zero_loc, [Prim (zero_loc, "IF_LEFT", fail_true_may_rename, [])])) + (Prim (zero_loc, "ASSERT_RIGHT", [], ["@annot"])) + +(** Unexpanding "IF_NONE {} { FAIL }" + yields "ASSERT_NONE" +*) +let test_unexpand_assert_none () = + assert_unexpansion + (Seq (zero_loc, [Prim (zero_loc, "IF_NONE", fail_false, [])])) + (Prim (zero_loc, "ASSERT_NONE", [], [])) + +(** Unexpanding "IF_NONE { FAIL } {}" + yields "ASSERT_SOME" +*) +let test_unexpand_assert_some () = + assert_unexpansion + (Seq (zero_loc, [Prim (zero_loc, "IF_NONE", fail_true, [])])) + (Prim (zero_loc, "ASSERT_SOME", [], [])) + +(** Unexpanding "IF_LEFT {} { FAIL }" + yields "ASSERT_LEFT" +*) +let test_unexpand_assert_left () = + assert_unexpansion + (Seq (zero_loc, [Prim (zero_loc, "IF_LEFT", fail_false, [])])) + (Prim (zero_loc, "ASSERT_LEFT", [], [])) + +(** Unexpanding "IF_LEFT { FAIL } {}" + yields "ASSERT_RIGHT" +*) +let test_unexpand_assert_right () = + assert_unexpansion + (Seq (zero_loc, [Prim (zero_loc, "IF_LEFT", fail_true, [])])) + (Prim (zero_loc, "ASSERT_RIGHT", [], [])) + +(** Unexpanding "DUP; CAR; DIP { CDR }" + yields "UNPAIR" +*) +let test_unexpand_unpair () = + assert_unexpansion + (Prim (zero_loc, "UNPAIR", [], [])) + (Prim (zero_loc, "UNPAIR", [], [])) + +(** Unexpanding "PAIR" + yields "PAIR" +*) +let test_unexpand_pair () = + assert_unexpansion + (Prim (zero_loc, "PAIR", [], [])) + (Prim (zero_loc, "PAIR", [], [])) + +(** Unexpanding "DIP { PAIR }; DIP { PAIR }; PAIR" + yields "PAPPAIIR" +*) +let test_unexpand_pappaiir () = + assert_unexpansion + (Seq + ( zero_loc, + [ + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "PAIR", [], [])])], + [] ); + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "PAIR", [], [])])], + [] ); + Prim (zero_loc, "PAIR", [], []); + ] )) + (Prim (zero_loc, "PAPPAIIR", [], [])) + +(** Unexpanding "DIP { DUP }; SWAP" + yields "DUP 2" +*) +let test_unexpand_duup () = + assert_unexpansion + (Seq + ( zero_loc, + [ + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "DUP", [], [])])], + [] ); + Prim (zero_loc, "SWAP", [], []); + ] )) + (Prim (zero_loc, "DUP", [Int (zero_loc, Z.of_int 2)], [])) + +(** Unexpanding "CAR" yields "CAR" + Unexpanding "CDR" yields "CDR" + Unexpanding "CAR; CDR" yields "CADR" + Unexpanding "CDR; CAR" yields "CDAR" +*) +let test_unexpand_caddadr () = + let car = Prim (zero_loc, "CAR", [], []) in + let cdr = Prim (zero_loc, "CDR", [], []) in + assert_unexpansion (Seq (zero_loc, [car])) car >>? fun () -> + assert_unexpansion (Seq (zero_loc, [cdr])) cdr >>? fun () -> + assert_unexpansion + (Seq (zero_loc, [car; cdr])) + (Prim (zero_loc, "CADR", [], [])) + >>? fun () -> + assert_unexpansion + (Seq (zero_loc, [cdr; car])) + (Prim (zero_loc, "CDAR", [], [])) + +let test_unexpand_carn_cdrn () = + let car n = Prim (zero_loc, "CAR", [Int (zero_loc, Z.of_int n)], []) in + let cdr n = Prim (zero_loc, "CDR", [Int (zero_loc, Z.of_int n)], []) in + let get n = + Seq (zero_loc, [Prim (zero_loc, "GET", [Int (zero_loc, Z.of_int n)], [])]) + in + assert_unexpansion (get 0) (cdr 0) >>? fun () -> + assert_unexpansion (get 1) (car 0) >>? fun () -> + assert_unexpansion (get 2) (cdr 1) >>? fun () -> + assert_unexpansion (get 3) (car 1) >>? fun () -> + assert_unexpansion (get 4) (cdr 2) + +(** Unexpanding "CDR; SWAP; PAIR" + yields "SET_CAR" +*) +let test_unexpand_set_car () = + assert_unexpansion + (Seq + ( zero_loc, + [ + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%"; "%@"]); + ] )) + (Prim (zero_loc, "SET_CAR", [], [])) + +(** Unexpanding "CAR; PAIR" + yields "SET_CDR" +*) +let test_unexpand_set_cdr () = + assert_unexpansion + (Seq + ( zero_loc, + [ + Prim (zero_loc, "CAR", [], ["@%%"]); + Prim (zero_loc, "PAIR", [], ["%@"; "%"]); + ] )) + (Prim (zero_loc, "SET_CDR", [], [])) + +(** Unexpanding "DUP; CAR; DROP; CDR; SWAP; PAIR" + yields "SET_CAR" +*) +let test_unexpand_set_car_annot () = + assert_unexpansion + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim (zero_loc, "CAR", [], ["%@"]); + Prim (zero_loc, "DROP", [], []); + Prim (zero_loc, "CDR", [], []); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], []); + ] )) + (Prim (zero_loc, "SET_CAR", [], ["%@"])) + +(** Unexpanding "DUP; CDR; DROP; CAR; PAIR" + yields "SET_CDR" +*) +let test_unexpand_set_cdr_annot () = + assert_unexpansion + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim (zero_loc, "CDR", [], ["%@"]); + Prim (zero_loc, "DROP", [], []); + Prim (zero_loc, "CAR", [], []); + Prim (zero_loc, "PAIR", [], []); + ] )) + (Prim (zero_loc, "SET_CDR", [], ["%@"])) + +(** Unexpanding "DUP; DIP { CAR; CAR; PAIR }; CDR; SWAP; PAIR" + yields "SET_CADR" +*) +let test_unexpand_set_cadr () = + let set_car = + Seq + ( zero_loc, + [ + Prim (zero_loc, "CAR", [], ["@%%"]); + Prim (zero_loc, "PAIR", [], ["%@"; "%"]); + ] ) + in + assert_unexpansion + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "CAR", [], ["@%%"]); set_car])], + [] ); + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%@"; "%@"]); + ] )) + (Prim (zero_loc, "SET_CADR", [], [])) + +let test_unexpand_set_cdar () = + let set_cdr = + Seq + ( zero_loc, + [ + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%"; "%@"]); + ] ) + in + assert_unexpansion + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "CDR", [], ["@%%"]); set_cdr])], + [] ); + Prim (zero_loc, "CAR", [], ["@%%"]); + Prim (zero_loc, "PAIR", [], ["%@"; "%@"]); + ] )) + (Prim (zero_loc, "SET_CDAR", [], [])) + +(* FIXME: Seq()(Prim): does not parse, raise an error unparse *) +let test_unexpand_map_car () = + let code = Seq (zero_loc, [Prim (zero_loc, "CAR", [], [])]) in + assert_unexpansion + (Prim (zero_loc, "MAP_CAR", [code], [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim + ( zero_loc, + "DIP", + [ + Seq + ( zero_loc, + [ + Prim (zero_loc, "CAR", [], []); + Prim (zero_loc, "CAR", [], []); + ] ); + ], + [] ); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%"; "%@"]); + ] )) + +(***********************************************************************) +(*BUG: the test with MAP_CDR or any map with "D" inside fail *) + +let _test_unexpand_map_cdr () = + let code = Seq (zero_loc, [Prim (zero_loc, "CAR", [], [])]) in + assert_unexpansion + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim (zero_loc, "CDR", [], []); + code; + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "CAR", [], []); + Prim (zero_loc, "PAIR", [], []); + ] )) + (Prim (zero_loc, "MAP_CDR", [code], [])) + +let _test_unexpand_map_caadr () = + let code = [Seq (zero_loc, [Prim (zero_loc, "CAR", [], [])])] in + let map_cdr = + Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim + ( zero_loc, + "DIP", + [ + Seq + ( zero_loc, + [ + Prim (zero_loc, "CAR", [], ["@%%"]); + Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim (zero_loc, "CDR", [], []); + Seq (zero_loc, [Prim (zero_loc, "CAR", [], [])]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "CAR", [], ["@%%"]); + Prim (zero_loc, "PAIR", [], ["%@"; "%"]); + ] ); + ] ); + ], + [] ); + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%@"; "%@"]); + ] ) + in + assert_unexpansion + (Prim (zero_loc, "MAP_CAAR", code, [])) + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "CAR", [], ["@%%"]); map_cdr])], + [] ); + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%@"; "%@"]); + ] )) + +let _test_unexpand_map_cdadr () = + let code = [Seq (zero_loc, [Prim (zero_loc, "CAR", [], [])])] in + let map_cdr = + Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim + ( zero_loc, + "DIP", + [ + Seq + ( zero_loc, + [ + Prim (zero_loc, "CAR", [], ["@%%"]); + Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim (zero_loc, "CDR", [], []); + Seq (zero_loc, [Prim (zero_loc, "CAR", [], [])]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "CAR", [], ["@%%"]); + Prim (zero_loc, "PAIR", [], ["%@"; "%"]); + ] ); + ] ); + ], + [] ); + Prim (zero_loc, "CDR", [], ["@%%"]); + Prim (zero_loc, "SWAP", [], []); + Prim (zero_loc, "PAIR", [], ["%@"; "%@"]); + ] ) + in + assert_unexpansion + (Seq + ( zero_loc, + [ + Prim (zero_loc, "DUP", [], []); + Prim + ( zero_loc, + "DIP", + [Seq (zero_loc, [Prim (zero_loc, "CDR", [], ["@%%"]); map_cdr])], + [] ); + Prim (zero_loc, "CAR", [], ["@%%"]); + Prim (zero_loc, "PAIR", [], ["%@"; "%@"]); + ] )) + (Prim (zero_loc, "MAP_CDADR", code, [])) + +let test_unexpand_diip () = + let code = Seq (zero_loc, [Prim (zero_loc, "CAR", [], [])]) in + assert_unexpansion + (Prim (zero_loc, "DIIP", [code], [])) + (Prim (zero_loc, "DIP", [Int (zero_loc, Z.of_int 2); code], [])) + +(** Unexpanding "DIP { DIP { DIP { DUP }; SWAP" + yields "DIIP { DIP { DUP }; SWAP }" +*) +let test_unexpand_diip_duup1 () = + let single code = Seq (zero_loc, [code]) in + let cst str = Prim (zero_loc, str, [], []) in + let app str code = Prim (zero_loc, str, [code], []) in + let dip = app "DIP" in + let diip code = + Prim (zero_loc, "DIP", [Int (zero_loc, Z.of_int 2); code], []) + in + let dup = cst "DUP" in + let swap = cst "SWAP" in + let dip_dup_swap = Seq (zero_loc, [dip (single dup); swap]) in + assert_unexpansion + (* { DIP { DIP { DIP { DUP }; SWAP }}} *) + (single (dip (single (dip dip_dup_swap)))) + (* DIIP { DIP { DUP }; SWAP } *) + (diip dip_dup_swap) + +(** Unexpanding "DIP { DIP {{ DIP { DUP }; SWAP" + yields "DIIP { DUUP }" +*) +let test_unexpand_diip_duup2 () = + let single code = Seq (zero_loc, [code]) in + let cst str = Prim (zero_loc, str, [], []) in + let app str code = Prim (zero_loc, str, [code], []) in + let dip = app "DIP" in + let diip code = + Prim (zero_loc, "DIP", [Int (zero_loc, Z.of_int 2); code], []) + in + let dup = cst "DUP" in + let duup = Prim (zero_loc, "DUP", [Int (zero_loc, Z.of_int 2)], []) in + let swap = cst "SWAP" in + let dip_dup_swap = Seq (zero_loc, [dip (single dup); swap]) in + assert_unexpansion + (* { DIP { DIP {{ DIP { DUP }; SWAP }}}} *) + (single (dip (single (dip (single dip_dup_swap))))) + (* DIIP { DUUP } *) + (diip (single duup)) + +(*****************************************************************************) +(* Test *) +(*****************************************************************************) + +let tests = + [ + (*compare*) + ("compare expansion", fun _ -> Lwt.return (test_compare_marco_expansion ())); + ( "if compare expansion", + fun _ -> Lwt.return (test_if_compare_macros_expansion ()) ); + ( "if compare expansion: IFCMP", + fun _ -> Lwt.return (test_if_cmp_macros_expansion ()) ); + (*fail*) + ("fail expansion", fun _ -> Lwt.return (test_fail_expansion ())); + (*assertion*) + ("assert expansion", fun _ -> Lwt.return (test_assert_expansion ())); + ("assert if expansion", fun _ -> Lwt.return (test_assert_if ())); + ("assert cmpif expansion", fun _ -> Lwt.return (test_assert_cmp_if ())); + ("assert none expansion", fun _ -> Lwt.return (test_assert_none ())); + ("assert some expansion", fun _ -> Lwt.return (test_assert_some ())); + ("assert left expansion", fun _ -> Lwt.return (test_assert_left ())); + ("assert right expansion", fun _ -> Lwt.return (test_assert_right ())); + ( "assert some annot expansion", + fun _ -> Lwt.return (test_assert_some_annot ()) ); + ( "assert left annot expansion", + fun _ -> Lwt.return (test_assert_left_annot ()) ); + ( "assert right annot expansion", + fun _ -> Lwt.return (test_assert_right_annot ()) ); + (*syntactic conveniences*) + ("diip expansion", fun _ -> Lwt.return (test_diip ())); + ("duup expansion", fun _ -> Lwt.return (test_duup ())); + ("pair expansion", fun _ -> Lwt.return (test_pair ())); + ("pappaiir expansion", fun _ -> Lwt.return (test_pappaiir ())); + ("unpair expansion", fun _ -> Lwt.return (test_unpair ())); + ("caddadr expansion", fun _ -> Lwt.return (test_caddadr_expansion ())); + ( "carn and cdrn expansion", + fun _ -> Lwt.return (test_carn_cdrn_expansion ()) ); + ("if_some expansion", fun _ -> Lwt.return (test_if_some ())); + ("set_car expansion", fun _ -> Lwt.return (test_set_car_expansion ())); + ("set_cdr expansion", fun _ -> Lwt.return (test_set_cdr_expansion ())); + ("set_cadr expansion", fun _ -> Lwt.return (test_set_cadr_expansion ())); + ("set_cdar expansion", fun _ -> Lwt.return (test_set_cdar_expansion ())); + ("map_car expansion", fun _ -> Lwt.return (test_map_car ())); + ("map_cdr expansion", fun _ -> Lwt.return (test_map_cdr ())); + ("map_caadr expansion", fun _ -> Lwt.return (test_map_caadr ())); + ("map_cdadr expansion", fun _ -> Lwt.return (test_map_cdadr ())); + (*Unexpand*) + ("fail unexpansion", fun _ -> Lwt.return (test_unexpand_fail ())); + ("if_right unexpansion", fun _ -> Lwt.return (test_unexpand_if_right ())); + ("if_some unexpansion", fun _ -> Lwt.return (test_unexpand_if_some ())); + ("assert unexpansion", fun _ -> Lwt.return (test_unexpand_assert ())); + ("assert_if unexpansion", fun _ -> Lwt.return (test_unexpand_assert_if ())); + ( "assert_cmp_if unexpansion", + fun _ -> Lwt.return (test_unexpansion_assert_cmp_if ()) ); + ( "assert_none unexpansion", + fun _ -> Lwt.return (test_unexpand_assert_none ()) ); + ( "assert_some unexpansion", + fun _ -> Lwt.return (test_unexpand_assert_some ()) ); + ( "assert_left unexpansion", + fun _ -> Lwt.return (test_unexpand_assert_left ()) ); + ( "assert_right unexpansion", + fun _ -> Lwt.return (test_unexpand_assert_right ()) ); + ( "assert_some annot unexpansion", + fun _ -> Lwt.return (test_unexpand_assert_some_annot ()) ); + ( "assert_left annot unexpansion", + fun _ -> Lwt.return (test_unexpand_assert_left_annot ()) ); + ( "assert_right annot unexpansion", + fun _ -> Lwt.return (test_unexpand_assert_right_annot ()) ); + ("unpair unexpansion", fun _ -> Lwt.return (test_unexpand_unpair ())); + ("pair unexpansion", fun _ -> Lwt.return (test_unexpand_pair ())); + ("pappaiir unexpansion", fun _ -> Lwt.return (test_unexpand_pappaiir ())); + ("duup unexpansion", fun _ -> Lwt.return (test_unexpand_duup ())); + ("caddadr unexpansion", fun _ -> Lwt.return (test_unexpand_caddadr ())); + ( "carn and cdrn unexpansion", + fun _ -> Lwt.return (test_unexpand_carn_cdrn ()) ); + ("set_car unexpansion", fun _ -> Lwt.return (test_unexpand_set_car ())); + ("set_cdr unexpansion", fun _ -> Lwt.return (test_unexpand_set_cdr ())); + ("set_cdar unexpansion", fun _ -> Lwt.return (test_unexpand_set_cdar ())); + ("set_cadr unexpansion", fun _ -> Lwt.return (test_unexpand_set_cadr ())); + ( "set_car annot unexpansion", + fun _ -> Lwt.return (test_unexpand_set_car_annot ()) ); + ( "set_cdr annot unexpansion", + fun _ -> Lwt.return (test_unexpand_set_cdr_annot ()) ); + ("map_car unexpansion", fun _ -> Lwt.return (test_unexpand_map_car ())); + ("diip unexpansion", fun _ -> Lwt.return (test_unexpand_diip ())); + ("diip_duup1 unexpansion", fun _ -> Lwt.return (test_unexpand_diip_duup1 ())); + ("diip_duup2 unexpansion", fun _ -> Lwt.return (test_unexpand_diip_duup2 ())); + (***********************************************************************) + (*BUG + the function in Michelson_v1_macros.unexpand_map_caddadr + failed to test the case with the character "D". + It returns an empty {} for the expand *) + (*"diip unexpansion", (fun _ -> Lwt.return (test_unexpand_diip ())) ;*) + (*"map_cdr unexpansion", (fun _ -> Lwt.return (test_unexpand_map_cdr ())) ;*) + (*"map_caadr unexpansion", (fun _ -> Lwt.return (test_unexpand_map_caadr ())) ;*) + (*"map_cdadr unexpansion", (fun _ -> Lwt.return (test_unexpand_map_cdadr ())) ;*) + ] + +let wrap (n, f) = + Alcotest_lwt.test_case n `Quick (fun _ () -> + f () >>= function + | Ok () -> Lwt.return_unit + | Error error -> + Format.kasprintf Stdlib.failwith "%a" pp_print_error error) + +let () = + Alcotest_lwt.run + ~argv:[|""|] + "tezos-lib-client" + [("micheline v1 macros", List.map wrap tests)] + |> Lwt_main.run diff --git a/src/proto_011_PtHangzH/lib_client/test/test_proxy.ml b/src/proto_011_PtHangzH/lib_client/test/test_proxy.ml new file mode 100644 index 000000000000..d6973017918b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/test/test_proxy.ml @@ -0,0 +1,89 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Client + Invocation: dune build @src/proto_alpha/lib_client/runtest + Subject: Test of --mode proxy and tezos-proxy-server heuristic +*) + +let proxy_mode_arb = + QCheck.make (QCheck.Gen.oneofl Tezos_proxy.Proxy.[Client; Server]) + +let key_gen : string list QCheck.Gen.t = + (* Segments taken from the implementation of split_key in src/proto_alpha/lib_client/proxy.ml *) + let keys = + QCheck.Gen.oneofl + [ + "big_maps"; + "index"; + "contents"; + "contracts"; + "cycle"; + "cycle"; + "rolls"; + "owner"; + "snapshot"; + "v1"; + ] + |> QCheck.Gen.list + in + QCheck.Gen.frequency QCheck.Gen.[(9, keys); (1, list string)] + +(** Whether [t1] is a prefix of [t2] *) +let rec is_prefix t1 t2 = + match (t1, t2) with + | ([], _) -> true + | (_, []) -> false + | (x1 :: rest1, x2 :: rest2) when x1 = x2 -> is_prefix rest1 rest2 + | _ -> false + +let test_split_key = + let fmt = + let pp_sep fmt () = Format.fprintf fmt "/" in + Format.pp_print_list ~pp_sep Format.pp_print_string + in + QCheck.Test.make + ~name:"[fst (split_key s)] is a prefix of [s]" + QCheck.(pair proxy_mode_arb (QCheck.make key_gen)) + @@ fun (mode, key) -> + match Proxy.ProtoRpc.split_key mode key with + | None -> true + | Some (shorter, _) -> + if is_prefix shorter key then true + else + QCheck.Test.fail_reportf + "Expected result of split_key to be a prefix of the input key. But \ + %a is not a prefix of %a." + fmt + shorter + fmt + key + +let () = + Alcotest.run + "tezos-lib-client-proxy" + [("proxy", Lib_test.Qcheck_helpers.qcheck_wrap [test_split_key])] diff --git a/src/proto_011_PtHangzH/lib_client/tezos-client-011-PtHangzH.opam b/src/proto_011_PtHangzH/lib_client/tezos-client-011-PtHangzH.opam new file mode 100644 index 000000000000..d10920b90bb0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client/tezos-client-011-PtHangzH.opam @@ -0,0 +1,31 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-base" + "tezos-protocol-environment" + "tezos-protocol-011-PtHangzH" + "tezos-shell-services" + "tezos-client-base-unix" + "tezos-mockup-registration" + "tezos-proxy" + "tezos-signer-backends" + "tezos-protocol-011-PtHangzH-parameters" + "tezos-protocol-plugin-011-PtHangzH" + "alcotest-lwt" { with-test & >= "1.1.0" } + "tezos-test-helpers" { with-test } + "tezos-base-test-helpers" { with-test } + "ppx_inline_test" + "qcheck-alcotest" { with-test } + "tezos-test-helpers" { with-test } +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: protocol specific library for `tezos-client`" diff --git a/src/proto_011_PtHangzH/lib_client_commands/.ocamlformat b/src/proto_011_PtHangzH/lib_client_commands/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_client_commands/alpha_commands_registration.ml b/src/proto_011_PtHangzH/lib_client_commands/alpha_commands_registration.ml new file mode 100644 index 000000000000..9d4231dc9a12 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/alpha_commands_registration.ml @@ -0,0 +1,38 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let () = + Client_commands.register Protocol.hash @@ fun network -> + List.map (Clic.map_command (new Protocol_client_context.wrap_full)) + @@ Client_proto_programs_commands.commands () + @ Client_proto_contracts_commands.commands () + @ Client_proto_context_commands.commands network () + @ Client_proto_multisig_commands.commands () + @ Client_proto_mockup_commands.commands () + @ Client_sapling_commands.commands () + @ Client_proto_utils_commands.commands () + @ Client_proto_stresstest_commands.commands network () + @ Client_proto_fa12_commands.commands () diff --git a/src/proto_011_PtHangzH/lib_client_commands/client_proto_context_commands.ml b/src/proto_011_PtHangzH/lib_client_commands/client_proto_context_commands.ml new file mode 100644 index 000000000000..107f3f43a9f9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/client_proto_context_commands.ml @@ -0,0 +1,1770 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Tezos_micheline +open Client_proto_context +open Client_proto_contracts +open Client_proto_programs +open Client_keys +open Client_proto_args + +let encrypted_switch = + Clic.switch ~long:"encrypted" ~doc:"encrypt the key on-disk" () + +let dry_run_switch = + Clic.switch + ~long:"dry-run" + ~short:'D' + ~doc:"don't inject the operation, just display it" + () + +let verbose_signing_switch = + Clic.switch + ~long:"verbose-signing" + ~doc:"display extra information before signing the operation" + () + +let simulate_switch = + Clic.switch + ~long:"simulation" + ~doc: + "Simulate the execution of the command, without needing any signatures." + () + +let report_michelson_errors ?(no_print_source = false) ~msg + (cctxt : #Client_context.printer) = function + | Error errs -> + cctxt#warning + "%a" + (Michelson_v1_error_reporter.report_errors + ~details:(not no_print_source) + ~show_source:(not no_print_source) + ?parsed:None) + errs + >>= fun () -> + cctxt#error "%s" msg >>= fun () -> Lwt.return_none + | Ok data -> Lwt.return_some data + +let json_file_or_text_parameter = + Clic.parameter (fun _ p -> + match String.split ~limit:1 ':' p with + | ["text"; text] -> return (Ezjsonm.from_string text) + | ["file"; path] -> Lwt_utils_unix.Json.read_file path + | _ -> ( + if Sys.file_exists p then Lwt_utils_unix.Json.read_file p + else + try return (Ezjsonm.from_string p) + with Ezjsonm.Parse_error _ -> + failwith "Neither an existing file nor valid JSON: '%s'" p)) + +let non_negative_param = + Clic.parameter (fun _ s -> + match int_of_string_opt s with + | Some i when i >= 0 -> return i + | _ -> failwith "Parameter should be a non-negative integer literal") + +let block_hash_param = + Clic.parameter (fun _ s -> + try return (Block_hash.of_b58check_exn s) + with _ -> failwith "Parameter '%s' is an invalid block hash" s) + +let group = + { + Clic.name = "context"; + title = "Block contextual commands (see option -block)"; + } + +let alphanet = {Clic.name = "alphanet"; title = "Alphanet only commands"} + +let binary_description = + {Clic.name = "description"; title = "Binary Description"} + +let transfer_command amount source destination cctxt + ( fee, + dry_run, + verbose_signing, + simulation, + gas_limit, + storage_limit, + counter, + arg, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap, + entrypoint ) = + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + (match Contract.is_implicit source with + | None -> + let contract = source in + Managed_contract.get_contract_manager cctxt source >>=? fun source -> + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + Managed_contract.transfer + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~simulation + ~fee_parameter + ?fee + ~contract + ~source + ~src_pk + ~src_sk + ~destination + ?entrypoint + ?arg + ~amount + ?gas_limit + ?storage_limit + ?counter + () + | Some source -> + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + transfer + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~simulation + ~verbose_signing + ~fee_parameter + ~source + ?fee + ~src_pk + ~src_sk + ~destination + ?entrypoint + ?arg + ~amount + ?gas_limit + ?storage_limit + ?counter + ()) + >>= report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + >>= function + | None -> return_unit + | Some (_res, _contracts) -> return_unit + +let tez_of_string_exn index field s = + match Tez.of_string s with + | Some t -> return t + | None -> + failwith + "Invalid \xEA\x9C\xA9 notation at entry %i, field \"%s\": %s" + index + field + s + +let tez_of_opt_string_exn index field s = + match s with + | None -> return None + | Some s -> tez_of_string_exn index field s >>=? fun s -> return (Some s) + +let prepare_batch_operation cctxt ?arg ?fee ?gas_limit ?storage_limit + ?entrypoint source index batch = + Client_proto_contracts.ContractAlias.find_destination cctxt batch.destination + >>=? fun (_, destination) -> + tez_of_string_exn index "amount" batch.amount >>=? fun amount -> + tez_of_opt_string_exn index "fee" batch.fee >>=? fun batch_fee -> + let fee = Option.either batch_fee fee in + let arg = Option.either batch.arg arg in + let gas_limit = Option.either batch.gas_limit gas_limit in + let storage_limit = Option.either batch.storage_limit storage_limit in + let entrypoint = Option.either batch.entrypoint entrypoint in + parse_arg_transfer arg >>=? fun parameters -> + (match Contract.is_implicit source with + | None -> + Managed_contract.build_transaction_operation + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract:source + ~destination + ?entrypoint + ?arg + ~amount + ?fee + ?gas_limit + ?storage_limit + () + | Some _ -> + return + (build_transaction_operation + ~amount + ~parameters + ?entrypoint + ?fee + ?gas_limit + ?storage_limit + destination)) + >>=? fun operation -> + return (Annotated_manager_operation.Annotated_manager_operation operation) + +let commands network () = + let open Clic in + [ + command + ~group + ~desc:"Access the timestamp of the block." + (args1 + (switch ~doc:"output time in seconds" ~short:'s' ~long:"seconds" ())) + (fixed ["get"; "timestamp"]) + (fun seconds (cctxt : Protocol_client_context.full) -> + Shell_services.Blocks.Header.shell_header + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + () + >>=? fun {timestamp = v; _} -> + (if seconds then cctxt#message "%Ld" (Time.Protocol.to_seconds v) + else cctxt#message "%s" (Time.Protocol.to_notation v)) + >>= fun () -> return_unit); + command + ~group + ~desc:"Lists all non empty contracts of the block." + no_options + (fixed ["list"; "contracts"]) + (fun () (cctxt : Protocol_client_context.full) -> + list_contract_labels cctxt ~chain:cctxt#chain ~block:cctxt#block + >>=? fun contracts -> + List.iter_s + (fun (alias, hash, kind) -> cctxt#message "%s%s%s" hash kind alias) + contracts + >>= fun () -> return_unit); + command + ~group + ~desc:"Lists cached contracts and their age in LRU ordering." + no_options + (prefixes ["list"; "cached"; "contracts"] @@ stop) + (fun () (cctxt : Protocol_client_context.full) -> + cached_contracts cctxt ~chain:cctxt#chain ~block:cctxt#block + >>=? fun keys -> + List.iter_s + (fun (key, size) -> + cctxt#message "%a %d" Alpha_context.Contract.pp key size) + keys + >>= fun () -> return_unit); + command + ~group + ~desc:"Get the key rank of a cache key." + no_options + (prefixes ["get"; "cached"; "contract"; "rank"; "for"] + @@ ContractAlias.destination_param ~name:"src" ~desc:"contract" + @@ stop) + (fun () (_, contract) (cctxt : Protocol_client_context.full) -> + contract_rank cctxt ~chain:cctxt#chain ~block:cctxt#block contract + >>=? fun rank -> + match rank with + | None -> + cctxt#error + "Invalid contract: %a" + Alpha_context.Contract.pp + contract + >>= fun () -> return_unit + | Some rank -> cctxt#message "%d" rank >>= fun () -> return_unit); + command + ~group + ~desc:"Get cache contract size." + no_options + (prefixes ["get"; "cache"; "contract"; "size"] @@ stop) + (fun () (cctxt : Protocol_client_context.full) -> + contract_cache_size cctxt ~chain:cctxt#chain ~block:cctxt#block + >>=? fun t -> + cctxt#message "%d" t >>= fun () -> return_unit); + command + ~group + ~desc:"Get cache contract size limit." + no_options + (prefixes ["get"; "cache"; "contract"; "size"; "limit"] @@ stop) + (fun () (cctxt : Protocol_client_context.full) -> + contract_cache_size_limit cctxt ~chain:cctxt#chain ~block:cctxt#block + >>=? fun t -> + cctxt#message "%d" t >>= fun () -> return_unit); + command + ~group + ~desc:"Get the balance of a contract." + no_options + (prefixes ["get"; "balance"; "for"] + @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" + @@ stop) + (fun () (_, contract) (cctxt : Protocol_client_context.full) -> + get_balance cctxt ~chain:cctxt#chain ~block:cctxt#block contract + >>=? fun amount -> + cctxt#answer "%a %s" Tez.pp amount Client_proto_args.tez_sym + >>= fun () -> return_unit); + command + ~group + ~desc:"Get the storage of a contract." + (args1 (unparsing_mode_arg ~default:"Readable")) + (prefixes ["get"; "contract"; "storage"; "for"] + @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" + @@ stop) + (fun unparsing_mode (_, contract) (cctxt : Protocol_client_context.full) -> + get_storage + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~unparsing_mode + contract + >>=? function + | None -> cctxt#error "This is not a smart contract." + | Some storage -> + cctxt#answer "%a" Michelson_v1_printer.print_expr_unwrapped storage + >>= fun () -> return_unit); + command + ~group + ~desc: + "Get the value associated to a key in the big map storage of a \ + contract (deprecated)." + no_options + (prefixes ["get"; "big"; "map"; "value"; "for"] + @@ Clic.param ~name:"key" ~desc:"the key to look for" data_parameter + @@ prefixes ["of"; "type"] + @@ Clic.param ~name:"type" ~desc:"type of the key" data_parameter + @@ prefix "in" + @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" + @@ stop) + (fun () key key_type (_, contract) (cctxt : Protocol_client_context.full) -> + get_contract_big_map_value + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + contract + (key.expanded, key_type.expanded) + >>=? function + | None -> cctxt#error "No value associated to this key." + | Some value -> + cctxt#answer "%a" Michelson_v1_printer.print_expr_unwrapped value + >>= fun () -> return_unit); + command + ~group + ~desc:"Get a value in a big map." + (args1 (unparsing_mode_arg ~default:"Readable")) + (prefixes ["get"; "element"] + @@ Clic.param + ~name:"key" + ~desc:"the key to look for" + (Clic.parameter (fun _ s -> + return (Script_expr_hash.of_b58check_exn s))) + @@ prefixes ["of"; "big"; "map"] + @@ Clic.param + ~name:"big_map" + ~desc:"identifier of the big_map" + int_parameter + @@ stop) + (fun unparsing_mode key id (cctxt : Protocol_client_context.full) -> + get_big_map_value + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~unparsing_mode + (Big_map.Id.parse_z (Z.of_int id)) + key + >>=? fun value -> + cctxt#answer "%a" Michelson_v1_printer.print_expr_unwrapped value + >>= fun () -> return_unit); + command + ~group + ~desc:"Get the code of a contract." + (args1 (unparsing_mode_arg ~default:"Readable")) + (prefixes ["get"; "contract"; "code"; "for"] + @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" + @@ stop) + (fun unparsing_mode (_, contract) (cctxt : Protocol_client_context.full) -> + get_script + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~unparsing_mode + contract + >>=? function + | None -> cctxt#error "This is not a smart contract." + | Some {code; storage = _} -> ( + match Script_repr.force_decode code with + | Error errs -> + cctxt#error "%a" Environment.Error_monad.pp_trace errs + | Ok code -> + let {Michelson_v1_parser.source; _} = + Michelson_v1_printer.unparse_toplevel code + in + cctxt#answer "%s" source >>= return)); + command + ~group + ~desc:"Get the `BLAKE2B` script hash of a contract." + no_options + (prefixes ["get"; "contract"; "script"; "hash"; "for"] + @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" + @@ stop) + (fun () (_, contract) (cctxt : Protocol_client_context.full) -> + get_script_hash cctxt ~chain:cctxt#chain ~block:cctxt#block contract + >>= function + | Error errs -> cctxt#error "%a" pp_print_error errs + | Ok None -> cctxt#error "This is not a smart contract." + | Ok (Some hash) -> cctxt#answer "%a" Script_expr_hash.pp hash >|= ok); + command + ~group + ~desc:"Get the type of an entrypoint of a contract." + no_options + (prefixes ["get"; "contract"; "entrypoint"; "type"; "of"] + @@ Clic.string ~name:"entrypoint" ~desc:"the entrypoint to describe" + @@ prefixes ["for"] + @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" + @@ stop) + (fun () entrypoint (_, contract) (cctxt : Protocol_client_context.full) -> + Michelson_v1_entrypoints.contract_entrypoint_type + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract + ~entrypoint + >>= Michelson_v1_entrypoints.print_entrypoint_type + cctxt + ~emacs:false + ~contract + ~entrypoint); + command + ~group + ~desc:"Get the entrypoint list of a contract." + no_options + (prefixes ["get"; "contract"; "entrypoints"; "for"] + @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" + @@ stop) + (fun () (_, contract) (cctxt : Protocol_client_context.full) -> + Michelson_v1_entrypoints.list_contract_entrypoints + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract + >>= Michelson_v1_entrypoints.print_entrypoints_list + cctxt + ~emacs:false + ~contract); + command + ~group + ~desc:"Get the list of unreachable paths in a contract's parameter type." + no_options + (prefixes ["get"; "contract"; "unreachable"; "paths"; "for"] + @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" + @@ stop) + (fun () (_, contract) (cctxt : Protocol_client_context.full) -> + Michelson_v1_entrypoints.list_contract_unreachables + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract + >>= Michelson_v1_entrypoints.print_unreachables + cctxt + ~emacs:false + ~contract); + command + ~group + ~desc:"Get the delegate of a contract." + no_options + (prefixes ["get"; "delegate"; "for"] + @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" + @@ stop) + (fun () (_, contract) (cctxt : Protocol_client_context.full) -> + Client_proto_contracts.get_delegate + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + contract + >>=? function + | None -> cctxt#message "none" >>= fun () -> return_unit + | Some delegate -> + Public_key_hash.rev_find cctxt delegate >>=? fun mn -> + Public_key_hash.to_source delegate >>=? fun m -> + cctxt#message + "%s (%s)" + m + (match mn with None -> "unknown" | Some n -> "known as " ^ n) + >>= fun () -> return_unit); + command + ~group + ~desc:"Set the delegate of a contract." + (args10 + fee_arg + dry_run_switch + verbose_signing_switch + simulate_switch + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg) + (prefixes ["set"; "delegate"; "for"] + @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" + @@ prefix "to" + @@ Public_key_hash.source_param + ~name:"dlgt" + ~desc:"new delegate of the contract" + @@ stop) + (fun ( fee, + dry_run, + verbose_signing, + simulation, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + (_, contract) + delegate + (cctxt : Protocol_client_context.full) -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + match Contract.is_implicit contract with + | None -> + Managed_contract.get_contract_manager cctxt contract + >>=? fun source -> + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + Managed_contract.set_delegate + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~simulation + ~fee_parameter + ?fee + ~source + ~src_pk + ~src_sk + contract + (Some delegate) + >>= fun errors -> + report_michelson_errors + ~no_print_source:true + ~msg:"Setting delegate through entrypoints failed." + cctxt + errors + >>= fun _ -> return_unit + | Some mgr -> + Client_keys.get_key cctxt mgr >>=? fun (_, src_pk, manager_sk) -> + set_delegate + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~simulation + ~fee_parameter + ?fee + mgr + (Some delegate) + ~src_pk + ~manager_sk + >>=? fun _ -> return_unit); + command + ~group + ~desc:"Withdraw the delegate from a contract." + (args9 + fee_arg + dry_run_switch + verbose_signing_switch + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg) + (prefixes ["withdraw"; "delegate"; "from"] + @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" + @@ stop) + (fun ( fee, + dry_run, + verbose_signing, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + (_, contract) + (cctxt : Protocol_client_context.full) -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + match Contract.is_implicit contract with + | None -> + Managed_contract.get_contract_manager cctxt contract + >>=? fun source -> + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + Managed_contract.set_delegate + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~fee_parameter + ?fee + ~source + ~src_pk + ~src_sk + contract + None + >>= fun errors -> + report_michelson_errors + ~no_print_source:true + ~msg:"Withdrawing delegate through entrypoints failed." + cctxt + errors + >>= fun _ -> return_unit + | Some mgr -> + Client_keys.get_key cctxt mgr >>=? fun (_, src_pk, manager_sk) -> + set_delegate + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~fee_parameter + mgr + None + ?fee + ~src_pk + ~manager_sk + >>= fun _ -> return_unit); + command + ~group + ~desc:"Launch a smart contract on the blockchain." + (args15 + fee_arg + dry_run_switch + verbose_signing_switch + gas_limit_arg + storage_limit_arg + delegate_arg + (Client_keys.force_switch ()) + init_arg + no_print_source_flag + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg) + (prefixes ["originate"; "contract"] + @@ RawContractAlias.fresh_alias_param + ~name:"new" + ~desc:"name of the new contract" + @@ prefix "transferring" + @@ tez_param ~name:"qty" ~desc:"amount taken from source" + @@ prefix "from" + @@ ContractAlias.destination_param + ~name:"src" + ~desc:"name of the source contract" + @@ prefix "running" + @@ Program.source_param + ~name:"prg" + ~desc: + "script of the account\n\ + Combine with -init if the storage type is not unit." + @@ stop) + (fun ( fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + delegate, + force, + initial_storage, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + alias_name + balance + (_, source) + program + (cctxt : Protocol_client_context.full) -> + RawContractAlias.of_fresh cctxt force alias_name >>=? fun alias_name -> + Lwt.return (Micheline_parser.no_parsing_error program) + >>=? fun {expanded = code; _} -> + match Contract.is_implicit source with + | None -> + failwith + "only implicit accounts can be the source of an origination" + | Some source -> ( + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + originate_contract + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ?fee + ?gas_limit + ?storage_limit + ~delegate + ~initial_storage + ~balance + ~source + ~src_pk + ~src_sk + ~code + ~fee_parameter + () + >>= fun errors -> + report_michelson_errors + ~no_print_source + ~msg:"origination simulation failed" + cctxt + errors + >>= function + | None -> return_unit + | Some (_res, contract) -> + if dry_run then return_unit + else + save_contract ~force cctxt alias_name contract >>=? fun () -> + return_unit)); + command + ~group + ~desc: + "Execute multiple transfers from a single source account.\n\ + If one of the transfers fails, none of them get executed." + (args16 + default_fee_arg + dry_run_switch + verbose_signing_switch + simulate_switch + default_gas_limit_arg + default_storage_limit_arg + counter_arg + default_arg_arg + no_print_source_flag + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg + default_entrypoint_arg) + (prefixes ["multiple"; "transfers"; "from"] + @@ ContractAlias.destination_param + ~name:"src" + ~desc:"name of the source contract" + @@ prefix "using" + @@ param + ~name:"transfers.json" + ~desc: + "List of operations originating from the source contract in JSON \ + format (from a file or directly inlined). The input JSON must be \ + an array of objects of the form: '[ {\"destination\": dst, \ + \"amount\": qty (, : ...) } (, ...) ]', where an \ + optional can either be \"fee\", \"gas-limit\", \ + \"storage-limit\", \"arg\", or \"entrypoint\"." + json_file_or_text_parameter + @@ stop) + (fun ( fee, + dry_run, + verbose_signing, + simulation, + gas_limit, + storage_limit, + counter, + arg, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap, + entrypoint ) + (_, source) + operations_json + cctxt -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + let prepare i = + prepare_batch_operation + cctxt + ?arg + ?fee + ?gas_limit + ?storage_limit + ?entrypoint + source + i + in + match + Data_encoding.Json.destruct + (Data_encoding.list + Client_proto_context.batch_transfer_operation_encoding) + operations_json + with + | [] -> failwith "Empty operation list" + | operations -> + (match Contract.is_implicit source with + | None -> + Managed_contract.get_contract_manager cctxt source + >>=? fun source -> + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + return (source, src_pk, src_sk) + | Some source -> + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + return (source, src_pk, src_sk)) + >>=? fun (source, src_pk, src_sk) -> + List.mapi_ep prepare operations >>=? fun contents -> + let (Manager_list contents) = + Annotated_manager_operation.manager_of_list contents + in + Injection.inject_manager_operation + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~simulation + ~source + ~fee:(Limit.of_option fee) + ~gas_limit:(Limit.of_option gas_limit) + ~storage_limit:(Limit.of_option storage_limit) + ?counter + ~src_pk + ~src_sk + ~fee_parameter + contents + >>= report_michelson_errors + ~no_print_source + ~msg:"multiple transfers simulation failed" + cctxt + >>= fun _ -> return_unit + | exception (Data_encoding.Json.Cannot_destruct (path, exn2) as exn) + -> ( + match (path, operations_json) with + | ([`Index n], `A lj) -> ( + match List.nth_opt lj n with + | Some j -> + failwith + "Invalid transfer at index %i: %a %a" + n + (fun ppf -> Data_encoding.Json.print_error ppf) + exn2 + Data_encoding.Json.pp + j + | _ -> + failwith + "Invalid transfer at index %i: %a" + n + (fun ppf -> Data_encoding.Json.print_error ppf) + exn2) + | _ -> + failwith + "Invalid transfer file: %a %a" + (fun ppf -> Data_encoding.Json.print_error ppf) + exn + Data_encoding.Json.pp + operations_json)); + command + ~group + ~desc:"Transfer tokens / call a smart contract." + (args16 + fee_arg + dry_run_switch + verbose_signing_switch + simulate_switch + gas_limit_arg + storage_limit_arg + counter_arg + arg_arg + no_print_source_flag + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg + entrypoint_arg) + (prefixes ["transfer"] + @@ tez_param ~name:"qty" ~desc:"amount taken from source" + @@ prefix "from" + @@ ContractAlias.destination_param + ~name:"src" + ~desc:"name of the source contract" + @@ prefix "to" + @@ ContractAlias.destination_param + ~name:"dst" + ~desc:"name/literal of the destination contract" + @@ stop) + (fun ( fee, + dry_run, + verbose_signing, + simulation, + gas_limit, + storage_limit, + counter, + arg, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap, + entrypoint ) + amount + (_, source) + (_, destination) + cctxt -> + transfer_command + amount + source + destination + cctxt + ( fee, + dry_run, + verbose_signing, + simulation, + gas_limit, + storage_limit, + counter, + arg, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap, + entrypoint )); + command + ~group + ~desc:"Register a global constant" + (args12 + fee_arg + dry_run_switch + verbose_signing_switch + simulate_switch + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + storage_limit_arg + counter_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg) + (prefixes ["register"; "global"; "constant"] + @@ global_constant_param + ~name:"expression" + ~desc: + "Michelson expression to register. Note the value is not \ + typechecked before registration." + @@ prefix "from" + @@ ContractAlias.destination_param + ~name:"src" + ~desc:"name of the account registering the global constant" + @@ stop) + (fun ( fee, + dry_run, + verbose_signing, + simulation, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + storage_limit, + counter, + force_low_fee, + fee_cap, + burn_cap ) + global_constant_str + (_, source) + cctxt -> + match Contract.is_implicit source with + | None -> + failwith "Only implicit accounts can register global constants" + | Some source -> + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + register_global_constant + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?dry_run:(Some dry_run) + ?verbose_signing:(Some verbose_signing) + ?fee + ?storage_limit + ?counter + ?confirmations:cctxt#confirmations + ~simulation + ~source + ~src_pk + ~src_sk + ~fee_parameter + ~constant:global_constant_str + () + >>= fun errors -> + report_michelson_errors + ~no_print_source:false + ~msg:"register global constant simulation failed" + cctxt + errors + >>= fun _ -> return_unit); + command + ~group + ~desc:"Call a smart contract (same as 'transfer 0')." + (args16 + fee_arg + dry_run_switch + verbose_signing_switch + simulate_switch + gas_limit_arg + storage_limit_arg + counter_arg + arg_arg + no_print_source_flag + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg + entrypoint_arg) + (prefixes ["call"] + @@ ContractAlias.destination_param + ~name:"dst" + ~desc:"name/literal of the destination contract" + @@ prefix "from" + @@ ContractAlias.destination_param + ~name:"src" + ~desc:"name of the source contract" + @@ stop) + (fun ( fee, + dry_run, + verbose_signing, + simulation, + gas_limit, + storage_limit, + counter, + arg, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap, + entrypoint ) + (_, destination) + (_, source) + cctxt -> + let amount = Tez.zero in + transfer_command + amount + source + destination + cctxt + ( fee, + dry_run, + verbose_signing, + simulation, + gas_limit, + storage_limit, + counter, + arg, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap, + entrypoint )); + command + ~group + ~desc:"Reveal the public key of the contract manager." + (args9 + fee_arg + dry_run_switch + verbose_signing_switch + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg) + (prefixes ["reveal"; "key"; "for"] + @@ ContractAlias.alias_param + ~name:"src" + ~desc:"name of the source contract" + @@ stop) + (fun ( fee, + dry_run, + verbose_signing, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + (_, source) + cctxt -> + match Contract.is_implicit source with + | None -> failwith "only implicit accounts can be revealed" + | Some source -> + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + reveal + cctxt + ~dry_run + ~verbose_signing + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~source + ?fee + ~src_pk + ~src_sk + ~fee_parameter + () + >>=? fun _res -> return_unit); + command + ~group + ~desc:"Register the public key hash as a delegate." + (args9 + fee_arg + dry_run_switch + verbose_signing_switch + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg) + (prefixes ["register"; "key"] + @@ Public_key_hash.source_param ~name:"mgr" ~desc:"the delegate key" + @@ prefixes ["as"; "delegate"] + @@ stop) + (fun ( fee, + dry_run, + verbose_signing, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + src_pkh + cctxt -> + Client_keys.get_key cctxt src_pkh >>=? fun (_, src_pk, src_sk) -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + register_as_delegate + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~fee_parameter + ~verbose_signing + ?fee + ~manager_sk:src_sk + src_pk + >>= function + | Ok _ -> return_unit + | Error [Environment.Ecoproto_error Delegate_storage.Active_delegate] -> + cctxt#message "Delegate already activated." >>= fun () -> + return_unit + | Error el -> Lwt.return_error el); + ] + @ (match network with + | Some `Mainnet -> [] + | Some `Testnet | None -> + [ + command + ~group + ~desc:"Register and activate an Alphanet/Zeronet faucet account." + (args2 (Secret_key.force_switch ()) encrypted_switch) + (prefixes ["activate"; "account"] + @@ Secret_key.fresh_alias_param + @@ prefixes ["with"] + @@ param + ~name:"activation_key" + ~desc: + "Activate an Alphanet/Zeronet faucet account from the JSON \ + (file or directly inlined)." + json_file_or_text_parameter + @@ stop) + (fun (force, encrypted) name activation_json cctxt -> + Secret_key.of_fresh cctxt force name >>=? fun name -> + match + Data_encoding.Json.destruct + Client_proto_context.activation_key_encoding + activation_json + with + | exception (Data_encoding.Json.Cannot_destruct _ as exn) -> + Format.kasprintf + (fun s -> failwith "%s" s) + "Invalid activation file: %a %a" + (fun ppf -> Data_encoding.Json.print_error ppf) + exn + Data_encoding.Json.pp + activation_json + | key -> + activate_account + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~encrypted + ~force + key + name + >>=? fun _res -> return_unit); + ]) + @ (match network with + | Some `Testnet | None -> [] + | Some `Mainnet -> + [ + command + ~group + ~desc:"Activate a fundraiser account." + (args1 dry_run_switch) + (prefixes ["activate"; "fundraiser"; "account"] + @@ Public_key_hash.alias_param + @@ prefixes ["with"] + @@ param + ~name:"code" + (Clic.parameter (fun _ctx code -> + protect (fun () -> + return + (Blinded_public_key_hash.activation_code_of_hex + code)))) + ~desc:"Activation code obtained from the Tezos foundation." + @@ stop) + (fun dry_run (name, _pkh) code cctxt -> + activate_existing_account + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + name + code + >>=? fun _res -> return_unit); + ]) + @ [ + command + ~desc:"Wait until an operation is included in a block" + (args3 + (default_arg + ~long:"confirmations" + ~placeholder:"num_blocks" + ~doc: + "wait until 'N' additional blocks after the operation appears \ + in the considered chain" + ~default:"0" + non_negative_param) + (default_arg + ~long:"check-previous" + ~placeholder:"num_blocks" + ~doc:"number of previous blocks to check" + ~default:"10" + non_negative_param) + (arg + ~long:"branch" + ~placeholder:"block_hash" + ~doc: + "hash of the oldest block where we should look for the \ + operation" + block_hash_param)) + (prefixes ["wait"; "for"] + @@ param + ~name:"operation" + ~desc:"Operation to be included" + (parameter (fun _ x -> + match Operation_hash.of_b58check_opt x with + | None -> + Error_monad.failwith "Invalid operation hash: '%s'" x + | Some hash -> return hash)) + @@ prefixes ["to"; "be"; "included"] + @@ stop) + (fun (confirmations, predecessors, branch) + operation_hash + (ctxt : Protocol_client_context.full) -> + Client_confirmations.wait_for_operation_inclusion + ctxt + ~chain:ctxt#chain + ~confirmations + ~predecessors + ?branch + operation_hash + >>=? fun _ -> return_unit); + command + ~desc:"Get receipt for past operation" + (args1 + (default_arg + ~long:"check-previous" + ~placeholder:"num_blocks" + ~doc:"number of previous blocks to check" + ~default:"10" + non_negative_param)) + (prefixes ["get"; "receipt"; "for"] + @@ param + ~name:"operation" + ~desc:"Operation to be looked up" + (parameter (fun _ x -> + match Operation_hash.of_b58check_opt x with + | None -> + Error_monad.failwith "Invalid operation hash: '%s'" x + | Some hash -> return hash)) + @@ stop) + (fun predecessors operation_hash (ctxt : Protocol_client_context.full) -> + display_receipt_for_operation + ctxt + ~chain:ctxt#chain + ~predecessors + operation_hash + >>=? fun _ -> return_unit); + command + ~group:binary_description + ~desc:"Describe unsigned block header" + no_options + (fixed ["describe"; "unsigned"; "block"; "header"]) + (fun () (cctxt : Protocol_client_context.full) -> + cctxt#message + "%a" + Data_encoding.Binary_schema.pp + (Data_encoding.Binary.describe + Alpha_context.Block_header.unsigned_encoding) + >>= fun () -> return_unit); + command + ~group:binary_description + ~desc:"Describe unsigned operation" + no_options + (fixed ["describe"; "unsigned"; "operation"]) + (fun () (cctxt : Protocol_client_context.full) -> + cctxt#message + "%a" + Data_encoding.Binary_schema.pp + (Data_encoding.Binary.describe + Alpha_context.Operation.unsigned_encoding) + >>= fun () -> return_unit); + command + ~group + ~desc:"Submit protocol proposals" + (args3 + dry_run_switch + verbose_signing_switch + (switch + ~doc: + "Do not fail when the checks that try to prevent the user from \ + shooting themselves in the foot do." + ~long:"force" + ())) + (prefixes ["submit"; "proposals"; "for"] + @@ ContractAlias.destination_param + ~name:"delegate" + ~desc:"the delegate who makes the proposal" + @@ seq_of_param + (param + ~name:"proposal" + ~desc:"the protocol hash proposal to be submitted" + (parameter (fun _ x -> + match Protocol_hash.of_b58check_opt x with + | None -> + Error_monad.failwith "Invalid proposal hash: '%s'" x + | Some hash -> return hash)))) + (fun (dry_run, verbose_signing, force) + (_name, source) + proposals + (cctxt : Protocol_client_context.full) -> + match Contract.is_implicit source with + | None -> failwith "only implicit accounts can submit proposals" + | Some src_pkh -> ( + Client_keys.get_key cctxt src_pkh + >>=? fun (src_name, _src_pk, src_sk) -> + get_period_info + (* Find period info of the successor, because the operation will + be injected on the next block at the earliest *) + ~successor:true + ~chain:cctxt#chain + ~block:cctxt#block + cctxt + >>=? fun info -> + (match info.current_period_kind with + | Proposal -> return_unit + | _ -> cctxt#error "Not in a proposal period") + >>=? fun () -> + Shell_services.Protocol.list cctxt >>=? fun known_protos -> + get_proposals ~chain:cctxt#chain ~block:cctxt#block cctxt + >>=? fun known_proposals -> + Alpha_services.Voting.listings cctxt (cctxt#chain, cctxt#block) + >>=? fun listings -> + (* for a proposal to be valid it must either a protocol that was already + proposed by somebody else or a protocol known by the node, because + the user is the first proposer and just injected it with + tezos-admin-client *) + let check_proposals proposals : bool tzresult Lwt.t = + let n = List.length proposals in + let errors = ref [] in + let error ppf = + Format.kasprintf (fun s -> errors := s :: !errors) ppf + in + if n = 0 then error "Empty proposal list." ; + if n > Constants.fixed.max_proposals_per_delegate then + error + "Too many proposals: %d > %d." + n + Constants.fixed.max_proposals_per_delegate ; + (match + Base.List.find_all_dups + ~compare:Protocol_hash.compare + proposals + with + | [] -> () + | dups -> + error + "There %s: %a." + (if List.length dups = 1 then "is a duplicate proposal" + else "are duplicate proposals") + Format.( + pp_print_list + ~pp_sep:(fun ppf () -> pp_print_string ppf ", ") + Protocol_hash.pp) + dups) ; + List.iter + (fun (p : Protocol_hash.t) -> + if + List.mem ~equal:Protocol_hash.equal p known_protos + || Environment.Protocol_hash.Map.mem p known_proposals + then () + else + error + "Protocol %a is not a known proposal." + Protocol_hash.pp + p) + proposals ; + if + not + (List.exists + (fun (pkh, _) -> + Signature.Public_key_hash.equal pkh src_pkh) + listings) + then + error + "Public-key-hash `%a` from account `%s` does not appear to \ + have voting rights." + Signature.Public_key_hash.pp + src_pkh + src_name ; + if !errors <> [] then + cctxt#message + "There %s with the submission:%t" + (if List.length !errors = 1 then "is an issue" + else "are issues") + Format.( + fun ppf -> + pp_print_cut ppf () ; + pp_open_vbox ppf 0 ; + List.iter + (fun msg -> + pp_open_hovbox ppf 2 ; + pp_print_string ppf "* " ; + pp_print_text ppf msg ; + pp_close_box ppf () ; + pp_print_cut ppf ()) + !errors ; + pp_close_box ppf ()) + >>= fun () -> return_false + else return_true + in + check_proposals proposals >>=? fun all_valid -> + (if all_valid then cctxt#message "All proposals are valid." + else if force then + cctxt#message + "Some proposals are not valid, but `--force` was used." + else cctxt#error "Submission failed because of invalid proposals.") + >>= fun () -> + submit_proposals + ~dry_run + ~verbose_signing + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~src_sk + src_pkh + proposals + >>= function + | Ok _res -> return_unit + | Error errs -> + (match errs with + | [ + Unregistered_error + (`O [("kind", `String "generic"); ("error", `String msg)]); + ] -> + cctxt#message + "Error:@[@.%a@]" + Format.pp_print_text + (String.split_on_char ' ' msg + |> List.filter (function + | "" | "\n" -> false + | _ -> true) + |> String.concat " " + |> String.map (function '\n' | '\t' -> ' ' | c -> c)) + | el -> cctxt#message "Error:@ %a" pp_print_error el) + >>= fun () -> failwith "Failed to submit proposals")); + command + ~group + ~desc:"Submit a ballot" + (args2 verbose_signing_switch dry_run_switch) + (prefixes ["submit"; "ballot"; "for"] + @@ ContractAlias.destination_param + ~name:"delegate" + ~desc:"the delegate who votes" + @@ param + ~name:"proposal" + ~desc:"the protocol hash proposal to vote for" + (parameter (fun _ x -> + match Protocol_hash.of_b58check_opt x with + | None -> failwith "Invalid proposal hash: '%s'" x + | Some hash -> return hash)) + @@ param + ~name:"ballot" + ~desc:"the ballot value (yea/yay, nay, or pass)" + (parameter + ~autocomplete:(fun _ -> return ["yea"; "nay"; "pass"]) + (fun _ s -> + (* We should have [Vote.of_string]. *) + match String.lowercase_ascii s with + | "yay" | "yea" -> return Vote.Yay + | "nay" -> return Vote.Nay + | "pass" -> return Vote.Pass + | s -> failwith "Invalid ballot: '%s'" s)) + @@ stop) + (fun (verbose_signing, dry_run) + (_name, source) + proposal + ballot + (cctxt : Protocol_client_context.full) -> + match Contract.is_implicit source with + | None -> failwith "only implicit accounts can submit ballot" + | Some src_pkh -> + Client_keys.get_key cctxt src_pkh + >>=? fun (_src_name, _src_pk, src_sk) -> + get_period_info + (* Find period info of the successor, because the operation will + be injected on the next block at the earliest *) + ~successor:true + ~chain:cctxt#chain + ~block:cctxt#block + cctxt + >>=? fun info -> + (match info.current_period_kind with + | Exploration | Promotion -> return_unit + | _ -> cctxt#error "Not in Exploration or Promotion period") + >>=? fun () -> + submit_ballot + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~src_sk + src_pkh + ~verbose_signing + ~dry_run + proposal + ballot + >>=? fun _res -> return_unit); + command + ~group + ~desc:"Summarize the current voting period" + no_options + (fixed ["show"; "voting"; "period"]) + (fun () (cctxt : Protocol_client_context.full) -> + get_period_info ~chain:cctxt#chain ~block:cctxt#block cctxt + >>=? fun info -> + cctxt#message + "Current period: %a\nBlocks remaining until end of period: %ld" + Data_encoding.Json.pp + (Data_encoding.Json.construct + Alpha_context.Voting_period.kind_encoding + info.current_period_kind) + info.remaining + >>= fun () -> + Shell_services.Protocol.list cctxt >>=? fun known_protos -> + get_proposals ~chain:cctxt#chain ~block:cctxt#block cctxt + >>=? fun props -> + let ranks = + Environment.Protocol_hash.Map.bindings props + |> List.sort (fun (_, v1) (_, v2) -> Int32.(compare v2 v1)) + in + let print_proposal = function + | None -> + cctxt#message "The current proposal has already been cleared." + (* The proposal is cleared on the last block of adoption period, and + also on the last block of the exploration and promotion + periods when the proposal is not approved *) + | Some proposal -> + cctxt#message "Current proposal: %a" Protocol_hash.pp proposal + in + match info.current_period_kind with + | Proposal -> + (* the current proposals are cleared on the last block of the + proposal period *) + if info.remaining <> 0l then + cctxt#answer + "Current proposals:%t" + Format.( + fun ppf -> + pp_print_cut ppf () ; + pp_open_vbox ppf 0 ; + List.iter + (fun (p, w) -> + fprintf + ppf + "* %a %ld (%sknown by the node)@." + Protocol_hash.pp + p + w + (if + List.mem ~equal:Protocol_hash.equal p known_protos + then "" + else "not ")) + ranks ; + pp_close_box ppf ()) + >>= fun () -> return_unit + else + cctxt#message "The proposals have already been cleared." + >>= fun () -> return_unit + | Exploration | Promotion -> + print_proposal info.current_proposal >>= fun () -> + (* the ballots are cleared on the last block of these periods *) + if info.remaining <> 0l then + get_ballots_info ~chain:cctxt#chain ~block:cctxt#block cctxt + >>=? fun ballots_info -> + cctxt#answer + "Ballots: %a@,\ + Current participation %.2f%%, necessary quorum %.2f%%@,\ + Current in favor %ld, needed supermajority %ld" + Data_encoding.Json.pp + (Data_encoding.Json.construct + Vote.ballots_encoding + ballots_info.ballots) + (Int32.to_float ballots_info.participation /. 100.) + (Int32.to_float ballots_info.current_quorum /. 100.) + ballots_info.ballots.yay + ballots_info.supermajority + >>= fun () -> return_unit + else + cctxt#message "The ballots have already been cleared." + >>= fun () -> return_unit + | Cooldown -> + print_proposal info.current_proposal >>= fun () -> return_unit + | Adoption -> + print_proposal info.current_proposal >>= fun () -> return_unit); + ] diff --git a/src/proto_011_PtHangzH/lib_client_commands/client_proto_contracts_commands.ml b/src/proto_011_PtHangzH/lib_client_commands/client_proto_contracts_commands.ml new file mode 100644 index 000000000000..ca9e65e08a1e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/client_proto_contracts_commands.ml @@ -0,0 +1,87 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Client_proto_contracts + +let group = + { + Clic.name = "contracts"; + title = "Commands for managing the record of known contracts"; + } + +let commands () = + let open Clic in + [ + command + ~group + ~desc:"Add a contract to the wallet." + (args1 (RawContractAlias.force_switch ())) + (prefixes ["remember"; "contract"] + @@ RawContractAlias.fresh_alias_param @@ RawContractAlias.source_param + @@ stop) + (fun force name hash cctxt -> + RawContractAlias.of_fresh cctxt force name >>=? fun name -> + RawContractAlias.add ~force cctxt name hash); + command + ~group + ~desc:"Remove a contract from the wallet." + no_options + (prefixes ["forget"; "contract"] @@ RawContractAlias.alias_param @@ stop) + (fun () (name, _) cctxt -> RawContractAlias.del cctxt name); + command + ~group + ~desc:"Lists all known contracts in the wallet." + no_options + (fixed ["list"; "known"; "contracts"]) + (fun () (cctxt : Protocol_client_context.full) -> + list_contracts cctxt >>=? fun contracts -> + List.iter_es + (fun (prefix, alias, contract) -> + cctxt#message + "%s%s: %s" + prefix + alias + (Contract.to_b58check contract) + >>= return) + contracts); + command + ~group + ~desc:"Forget the entire wallet of known contracts." + (args1 (RawContractAlias.force_switch ())) + (fixed ["forget"; "all"; "contracts"]) + (fun force cctxt -> + fail_unless force (failure "this can only used with option -force") + >>=? fun () -> RawContractAlias.set cctxt []); + command + ~group + ~desc:"Display a contract from the wallet." + no_options + (prefixes ["show"; "known"; "contract"] + @@ RawContractAlias.alias_param @@ stop) + (fun () (_, contract) (cctxt : Protocol_client_context.full) -> + cctxt#message "%a\n%!" Contract.pp contract >>= fun () -> return_unit); + ] diff --git a/src/proto_011_PtHangzH/lib_client_commands/client_proto_fa12_commands.ml b/src/proto_011_PtHangzH/lib_client_commands/client_proto_fa12_commands.ml new file mode 100644 index 000000000000..624a7c6c4a54 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/client_proto_fa12_commands.ml @@ -0,0 +1,757 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Client_proto_args + +let group = + { + Clic.name = "tokens"; + title = "Commands for managing FA1.2-compatible smart contracts"; + } + +let alias_param = Client_proto_contracts.ContractAlias.destination_param + +let token_contract_param () = + alias_param + ~name:"contract" + ~desc:"name or address of the FA1.2-compatible contract" + +let from_param () = + alias_param ~name:"from" ~desc:"name or address of the sender" + +let to_param () = alias_param ~name:"to" ~desc:"name or address of the receiver" + +let amount_param () = + Clic.param + ~name:"amount" + ~desc:"number of tokens" + (Clic.parameter (fun _ s -> + try + let v = Z.of_string s in + assert (Compare.Z.(v >= Z.zero)) ; + return v + with _ -> failwith "invalid amount (must be a non-negative number)")) + +let tez_amount_arg = + tez_arg ~default:"0" ~parameter:"tez-amount" ~doc:"amount in \xEA\x9C\xA9" + +let as_arg = + Client_proto_contracts.ContractAlias.destination_arg + ~name:"as" + ~doc:"name or address of the caller of the contract" + () + +let payer_arg = + Client_proto_contracts.ContractAlias.destination_arg + ~name:"payer" + ~doc:"name of the payer (i.e. SOURCE) contract for the transaction" + () + +let callback_entrypoint_arg = + Clic.arg + ~doc:"Entrypoint the view should use to callback to" + ~long:"callback-entrypoint" + ~placeholder:"name" + string_parameter + +let contract_call_options = + Clic.args14 + tez_amount_arg + fee_arg + Client_proto_context_commands.dry_run_switch + Client_proto_context_commands.verbose_signing_switch + gas_limit_arg + storage_limit_arg + counter_arg + no_print_source_flag + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg + +let contract_view_options = + Clic.args15 + callback_entrypoint_arg + tez_amount_arg + fee_arg + Client_proto_context_commands.dry_run_switch + Client_proto_context_commands.verbose_signing_switch + gas_limit_arg + storage_limit_arg + counter_arg + no_print_source_flag + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg + +let view_options = + Clic.args3 + run_gas_limit_arg + payer_arg + (unparsing_mode_arg ~default:"Readable") + +let dummy_callback = Contract.implicit_contract Signature.Public_key_hash.zero + +let get_contract_caller_keys cctxt caller = + match Contract.is_implicit caller with + | None -> + failwith "only implicit accounts can be the source of a contract call" + | Some source -> + Client_keys.get_key cctxt source >>=? fun (_, caller_pk, caller_sk) -> + return (source, caller_pk, caller_sk) + +let commands () : #Protocol_client_context.full Clic.command list = + let open Client_proto_args in + Clic. + [ + command + ~group + ~desc:"Check that a contract is FA1.2-compatible." + no_options + (prefixes ["check"; "contract"] + @@ token_contract_param () + @@ prefixes ["implements"; "fa1.2"] + @@ stop) + (fun () (_, contract) (cctxt : #Protocol_client_context.full) -> + Client_proto_fa12.contract_has_fa12_interface + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract + () + >>=? fun _ -> + Format.printf + "Contract %a has an FA1.2 interface.\n%!" + Contract.pp + contract ; + return_unit); + command + ~group + ~desc:"Transfer tokens between two given accounts" + (Clic.args15 + as_arg + tez_amount_arg + fee_arg + Client_proto_context_commands.dry_run_switch + Client_proto_context_commands.verbose_signing_switch + gas_limit_arg + storage_limit_arg + counter_arg + no_print_source_flag + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg) + (prefixes ["from"; "fa1.2"; "contract"] + @@ token_contract_param () @@ prefix "transfer" @@ amount_param () + @@ prefix "from" @@ from_param () @@ prefix "to" @@ to_param () @@ stop + ) + (fun ( as_address, + tez_amount, + fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + (_, contract) + amount + src + (_, dst) + (cctxt : #Protocol_client_context.full) -> + let (_, caller) = Option.value ~default:src as_address in + get_contract_caller_keys cctxt caller + >>=? fun (source, caller_pk, caller_sk) -> + let action = Client_proto_fa12.Transfer (snd src, dst, amount) in + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Client_proto_fa12.call_contract + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract + ~action + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ?fee + ~source + ~src_pk:caller_pk + ~src_sk:caller_sk + ~tez_amount + ?gas_limit + ?storage_limit + ?counter + ~fee_parameter + () + >>= Client_proto_context_commands.report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + >>= fun _ -> return_unit); + command + ~group + ~desc:"Allow account to transfer an amount of token" + contract_call_options + (prefixes ["from"; "fa1.2"; "contract"] + @@ token_contract_param () @@ prefix "as" + @@ alias_param ~name:"as" ~desc:"name or address of the sender" + @@ prefix "approve" @@ amount_param () @@ prefix "from" + @@ alias_param + ~name:"from" + ~desc:"name or address to approve withdrawal" + @@ stop) + (fun ( tez_amount, + fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + (_, contract) + (_, source) + amount + (_, dst) + (cctxt : #Protocol_client_context.full) -> + get_contract_caller_keys cctxt source + >>=? fun (source, src_pk, src_sk) -> + let action = Client_proto_fa12.Approve (dst, amount) in + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Client_proto_fa12.call_contract + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract + ~action + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ?fee + ~source + ~src_pk + ~src_sk + ~tez_amount + ?gas_limit + ?storage_limit + ?counter + ~fee_parameter + () + >>= Client_proto_context_commands.report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + >>= fun _ -> return_unit); + command + ~group + ~desc:"Ask for an address's balance offchain" + view_options + (prefixes ["from"; "fa1.2"; "contract"] + @@ token_contract_param () + @@ prefixes ["get"; "balance"; "for"] + @@ alias_param + ~name:"from" + ~desc: + "name or address of the account to lookup (also the source \ + contract)" + @@ stop) + (fun (gas, payer, unparsing_mode) + (_, contract) + (_, addr) + (cctxt : #Protocol_client_context.full) -> + let action = + Client_proto_fa12.Get_balance (addr, (dummy_callback, None)) + in + let payer = Option.map snd payer in + Client_proto_fa12.run_view_action + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract + ~action + ~source:addr + ?gas + ?payer + ~unparsing_mode + () + >>= fun res -> Client_proto_programs.print_view_result cctxt res); + command + ~group + ~desc:"Ask for an address's allowance offchain" + view_options + (prefixes ["from"; "fa1.2"; "contract"] + @@ token_contract_param () + @@ prefixes ["get"; "allowance"; "on"] + @@ alias_param + ~name:"owner" + ~desc:"name or address of the account giving the allowance" + @@ prefix "as" + @@ alias_param + ~name:"operator" + ~desc:"name or address of the account receiving the allowance" + @@ stop) + (fun (gas, payer, unparsing_mode) + (_, contract) + (_, source) + (_, destination) + (cctxt : #Protocol_client_context.full) -> + let action = + Client_proto_fa12.Get_allowance + (source, destination, (dummy_callback, None)) + in + let payer = Option.map snd payer in + Client_proto_fa12.run_view_action + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract + ~action + ~source + ?gas + ?payer + ~unparsing_mode + () + >>= fun res -> Client_proto_programs.print_view_result cctxt res); + command + ~group + ~desc:"Ask for the contract's total token supply offchain" + view_options + (prefixes ["from"; "fa1.2"; "contract"] + @@ token_contract_param () + @@ prefixes ["get"; "total"; "supply"] + @@ stop) + (fun (gas, payer, unparsing_mode) + (_, contract) + (cctxt : #Protocol_client_context.full) -> + let action = + Client_proto_fa12.Get_total_supply (dummy_callback, None) + in + let payer = Option.map snd payer in + Client_proto_fa12.run_view_action + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract + ~action + ?gas + ?payer + ~unparsing_mode + () + >>= fun res -> Client_proto_programs.print_view_result cctxt res); + command + ~group + ~desc:"Ask for an address's balance using a callback contract" + contract_view_options + (prefixes ["from"; "fa1.2"; "contract"] + @@ token_contract_param () + @@ prefixes ["get"; "balance"; "for"] + @@ alias_param + ~name:"from" + ~desc: + "name or address of the account to lookup (also the source \ + contract)" + @@ prefixes ["callback"; "on"] + @@ alias_param + ~name:"callback" + ~desc:"name or address of the callback contract" + @@ stop) + (fun ( callback_entrypoint, + tez_amount, + fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + (_, contract) + (_, addr) + (_, callback) + (cctxt : #Protocol_client_context.full) -> + get_contract_caller_keys cctxt addr + >>=? fun (source, src_pk, src_sk) -> + let action = + Client_proto_fa12.Get_balance (addr, (callback, callback_entrypoint)) + in + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Client_proto_fa12.call_contract + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract + ~action + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ?fee + ~source + ~src_pk + ~src_sk + ~tez_amount + ?gas_limit + ?storage_limit + ?counter + ~fee_parameter + () + >>= Client_proto_context_commands.report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + >>= fun _ -> return_unit); + command + ~group + ~desc:"Ask for an address's allowance using a callback contract" + contract_view_options + (prefixes ["from"; "fa1.2"; "contract"] + @@ token_contract_param () + @@ prefixes ["get"; "allowance"; "on"] + @@ alias_param + ~name:"from" + ~desc:"name or address of the account giving the allowance" + @@ prefix "as" + @@ alias_param + ~name:"to" + ~desc:"name or address of the account receiving the allowance" + @@ prefixes ["callback"; "on"] + @@ alias_param + ~name:"callback" + ~desc:"name or address of the callback contract" + @@ stop) + (fun ( callback_entrypoint, + tez_amount, + fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + (_, contract) + (_, src) + (_, dst) + (_, callback) + (cctxt : #Protocol_client_context.full) -> + get_contract_caller_keys cctxt src + >>=? fun (source, src_pk, src_sk) -> + let action = + Client_proto_fa12.Get_allowance + (src, dst, (callback, callback_entrypoint)) + in + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Client_proto_fa12.call_contract + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract + ~action + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ?fee + ~source + ~src_pk + ~src_sk + ~tez_amount + ?gas_limit + ?storage_limit + ?counter + ~fee_parameter + () + >>= Client_proto_context_commands.report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + >>= fun _ -> return_unit); + command + ~group + ~desc: + "Ask for a contract's total token supply using a callback contract" + contract_view_options + (prefixes ["from"; "fa1.2"; "contract"] + @@ token_contract_param () + @@ prefixes ["get"; "total"; "supply"; "as"] + @@ alias_param + ~name:"from" + ~desc:"name or address of the source account" + @@ prefixes ["callback"; "on"] + @@ alias_param + ~name:"callback" + ~desc:"name or address of the callback contract" + @@ stop) + (fun ( callback_entrypoint, + tez_amount, + fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + (_, contract) + (_, addr) + (_, callback) + (cctxt : #Protocol_client_context.full) -> + get_contract_caller_keys cctxt addr + >>=? fun (source, src_pk, src_sk) -> + let action = + Client_proto_fa12.Get_total_supply (callback, callback_entrypoint) + in + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Client_proto_fa12.call_contract + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract + ~action + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ?fee + ~source + ~src_pk + ~src_sk + ~tez_amount + ?gas_limit + ?storage_limit + ?counter + ~fee_parameter + () + >>= Client_proto_context_commands.report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + >>= fun _ -> return_unit); + command + ~group + ~desc: + "Execute multiple token transfers from a single source account. If \ + one of the token transfers fails, none of them are executed." + (args14 + default_fee_arg + as_arg + Client_proto_context_commands.dry_run_switch + Client_proto_context_commands.verbose_signing_switch + default_gas_limit_arg + default_storage_limit_arg + counter_arg + no_print_source_flag + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg) + (prefixes ["multiple"; "fa1.2"; "transfers"; "from"] + @@ alias_param + ~name:"src" + ~desc:"name or address of the source of the transfers" + @@ prefix "using" + @@ param + ~name:"transfers.json" + ~desc: + (Format.sprintf + "List of token transfers to inject from the source contract \ + in JSON format (as a file or string). The JSON must be an \ + array of objects of the form: '[ {\"token_contract\": \ + address or alias, \"destination\": address or alias, \ + \"amount\": non-negative integer (, : ...) } \ + (, ...) ]', where an optional can either be \ + \"tez-amount\", \"fee\", \"gas-limit\" or \ + \"storage-limit\". The complete schema can be inspected via \ + `tezos-codec describe %s.fa1.2.token_transfer json schema`." + Protocol.name) + Client_proto_context_commands.json_file_or_text_parameter + @@ stop) + (fun ( fee, + as_address, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + src + operations_json + cctxt -> + let (_, caller) = Option.value ~default:src as_address in + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + match + Data_encoding.Json.destruct + (Data_encoding.list Client_proto_fa12.token_transfer_encoding) + operations_json + with + | [] -> failwith "Empty operation list" + | operations -> + get_contract_caller_keys cctxt caller + >>=? fun (source, src_pk, src_sk) -> + Client_proto_fa12.inject_token_transfer_batch + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~sender:(snd src) + ~source + ~src_pk + ~src_sk + ~token_transfers:operations + ~fee_parameter + ?counter + ?default_fee:fee + ?default_gas_limit:gas_limit + ?default_storage_limit:storage_limit + () + >>= Client_proto_context_commands.report_michelson_errors + ~no_print_source + ~msg:"multiple transfers simulation failed" + cctxt + >>= fun _ -> return_unit + | exception (Data_encoding.Json.Cannot_destruct (path, exn2) as exn) + -> ( + match (path, operations_json) with + | ([`Index n], `A lj) -> ( + match List.nth_opt lj n with + | Some j -> + failwith + "Invalid transfer at index %i: %a %a" + n + (fun ppf -> Data_encoding.Json.print_error ppf) + exn2 + Data_encoding.Json.pp + j + | _ -> + failwith + "Invalid transfer at index %i: %a" + n + (fun ppf -> Data_encoding.Json.print_error ppf) + exn2) + | _ -> + failwith + "Invalid transfer file: %a %a" + (fun ppf -> Data_encoding.Json.print_error ppf) + exn + Data_encoding.Json.pp + operations_json)); + ] diff --git a/src/proto_011_PtHangzH/lib_client_commands/client_proto_mockup_commands.ml b/src/proto_011_PtHangzH/lib_client_commands/client_proto_mockup_commands.ml new file mode 100644 index 000000000000..47c00a38eebf --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/client_proto_mockup_commands.ml @@ -0,0 +1,81 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Tezos_clic + +let protocol_constants_arg = + Clic.arg + ~doc:"a JSON file that contains protocol constants to set." + ~long:"protocol-constants" + ~placeholder:"path" + (Clic.parameter (fun _ x -> return x)) + +let bootstrap_accounts_arg = + Clic.arg + ~doc: + "a JSON file that contains definitions of bootstrap accounts to create." + ~long:"bootstrap-accounts" + ~placeholder:"path" + (Clic.parameter (fun _ x -> return x)) + +let asynchronous_flag = + Clic.switch + ~long:"asynchronous" + ~doc:"put operations in mempool and require baking to include in the chain" + () + +let load_json_file (cctxt : Protocol_client_context.full) json_file = + match json_file with + | None -> return None + | Some filename -> + cctxt#read_file filename >>=? fun json_string -> + return (Some (Ezjsonm.from_string json_string :> Data_encoding.json)) + +let create_mockup_command_handler + (constants_overrides_file, bootstrap_accounts_file, asynchronous) + (cctxt : Protocol_client_context.full) = + load_json_file cctxt constants_overrides_file + >>=? fun constants_overrides_json -> + load_json_file cctxt bootstrap_accounts_file + >>=? fun bootstrap_accounts_json -> + Tezos_mockup.Persistence.create_mockup + ~cctxt:(cctxt :> Tezos_client_base.Client_context.full) + ~protocol_hash:Protocol.hash + ~constants_overrides_json + ~bootstrap_accounts_json + ~asynchronous + >>=? fun () -> + Tezos_mockup_commands.Mockup_wallet.populate cctxt bootstrap_accounts_file + +let create_mockup_command : Protocol_client_context.full Clic.command = + let open Clic in + command + ~group:Tezos_mockup_commands.Mockup_commands.group + ~desc:"Create a mockup environment." + (args3 protocol_constants_arg bootstrap_accounts_arg asynchronous_flag) + (prefixes ["create"; "mockup"] @@ stop) + create_mockup_command_handler + +let commands () = [create_mockup_command] diff --git a/src/proto_011_PtHangzH/lib_client_commands/client_proto_mockup_commands.mli b/src/proto_011_PtHangzH/lib_client_commands/client_proto_mockup_commands.mli new file mode 100644 index 000000000000..765437d4365e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/client_proto_mockup_commands.mli @@ -0,0 +1,26 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val commands : unit -> Protocol_client_context.full Clic.command list diff --git a/src/proto_011_PtHangzH/lib_client_commands/client_proto_multisig_commands.ml b/src/proto_011_PtHangzH/lib_client_commands/client_proto_multisig_commands.ml new file mode 100644 index 000000000000..2ec9ea5bec9d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/client_proto_multisig_commands.ml @@ -0,0 +1,1129 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Client_proto_args +open Tezos_micheline + +let group = + { + Clic.name = "multisig"; + title = "Commands for managing a multisig smart contract"; + } + +let threshold_param () = + Clic.param + ~name:"threshold" + ~desc:"Number of required signatures" + Client_proto_args.int_parameter + +let public_key_param () = + Client_keys.Public_key.source_param + ~name:"key" + ~desc:"Each signer of the multisig contract" + +let secret_key_param () = + Client_keys.Secret_key.source_param + ~name:"key" + ~desc: + "Secret key corresponding to one of the public keys stored on the \ + multisig contract" + +let signature_param () = + Clic.param + ~name:"signature" + ~desc:"Each signer of the multisig contract" + Client_proto_args.signature_parameter + +let lambda_param () = + Clic.param + ~name:"lambda" + ~desc:"the lambda to execute, of type lambda unit (list operation)" + string_parameter + +let bytes_only_switch = + Clic.switch + ~long:"bytes-only" + ~doc:"return only the byte sequence to be signed" + () + +let bytes_param ~name ~desc = + Clic.param ~name ~desc Client_proto_args.bytes_parameter + +let transfer_options = + Clic.args15 + Client_proto_args.fee_arg + Client_proto_context_commands.dry_run_switch + Client_proto_context_commands.verbose_signing_switch + Client_proto_args.gas_limit_arg + Client_proto_args.storage_limit_arg + Client_proto_args.counter_arg + Client_proto_args.arg_arg + Client_proto_args.no_print_source_flag + Client_proto_args.minimal_fees_arg + Client_proto_args.minimal_nanotez_per_byte_arg + Client_proto_args.minimal_nanotez_per_gas_unit_arg + Client_proto_args.force_low_fee_arg + Client_proto_args.fee_cap_arg + Client_proto_args.burn_cap_arg + Client_proto_args.entrypoint_arg + +let non_transfer_options = + Clic.args13 + Client_proto_args.fee_arg + Client_proto_context_commands.dry_run_switch + Client_proto_context_commands.verbose_signing_switch + Client_proto_args.gas_limit_arg + Client_proto_args.storage_limit_arg + Client_proto_args.counter_arg + Client_proto_args.no_print_source_flag + Client_proto_args.minimal_fees_arg + Client_proto_args.minimal_nanotez_per_byte_arg + Client_proto_args.minimal_nanotez_per_gas_unit_arg + Client_proto_args.force_low_fee_arg + Client_proto_args.fee_cap_arg + Client_proto_args.burn_cap_arg + +let prepare_command_display prepared_command bytes_only = + if bytes_only then + Format.printf + "0x%a@." + Hex.pp + (Hex.of_bytes prepared_command.Client_proto_multisig.bytes) + else + Format.printf + "%a@.%a@.%a@.%a@." + (fun ppf x -> + Format.fprintf ppf "Bytes to sign: '0x%a'" Hex.pp (Hex.of_bytes x)) + prepared_command.Client_proto_multisig.bytes + (fun ppf x -> + Format.fprintf + ppf + "Blake 2B Hash: '%s'" + (Base58.raw_encode Blake2B.(hash_bytes [x] |> to_string))) + prepared_command.Client_proto_multisig.bytes + (fun ppf z -> + Format.fprintf + ppf + "Threshold (number of signatures required): %s" + (Z.to_string z)) + prepared_command.Client_proto_multisig.threshold + (fun ppf -> + Format.fprintf + ppf + "@[<2>Public keys of the signers:@ %a@]" + (Format.pp_print_list + ~pp_sep:(fun ppf () -> Format.fprintf ppf "@ ") + Signature.Public_key.pp)) + prepared_command.Client_proto_multisig.keys + +let get_parameter_type (cctxt : #Protocol_client_context.full) ~destination + ~entrypoint = + match Contract.is_implicit destination with + | Some _ -> + let open Micheline in + return @@ strip_locations @@ Prim (0, Script.T_unit, [], []) + | None -> ( + Michelson_v1_entrypoints.contract_entrypoint_type + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~contract:destination + ~entrypoint + >>=? function + | None -> + cctxt#error + "Contract %a has no entrypoint named %s" + Contract.pp + destination + entrypoint + | Some parameter_type -> return parameter_type) + +let commands () : #Protocol_client_context.full Clic.command list = + Clic. + [ + command + ~group + ~desc:"Originate a new multisig contract." + (args14 + Client_proto_args.fee_arg + Client_proto_context_commands.dry_run_switch + Client_proto_args.gas_limit_arg + Client_proto_args.storage_limit_arg + Client_proto_args.delegate_arg + (Client_keys.force_switch ()) + Client_proto_args.no_print_source_flag + Client_proto_args.minimal_fees_arg + Client_proto_args.minimal_nanotez_per_byte_arg + Client_proto_args.minimal_nanotez_per_gas_unit_arg + Client_proto_args.force_low_fee_arg + Client_proto_args.fee_cap_arg + Client_proto_context_commands.verbose_signing_switch + Client_proto_args.burn_cap_arg) + (prefixes ["deploy"; "multisig"] + @@ Client_proto_contracts.RawContractAlias.fresh_alias_param + ~name:"new_multisig" + ~desc:"name of the new multisig contract" + @@ prefix "transferring" + @@ Client_proto_args.tez_param + ~name:"qty" + ~desc:"amount taken from source" + @@ prefix "from" + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"src" + ~desc:"name of the source contract" + @@ prefixes ["with"; "threshold"] + @@ threshold_param () + @@ prefixes ["on"; "public"; "keys"] + @@ seq_of_param (public_key_param ())) + (fun ( fee, + dry_run, + gas_limit, + storage_limit, + delegate, + force, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + verbose_signing, + burn_cap ) + alias_name + balance + (_, source) + threshold + keys + (cctxt : #Protocol_client_context.full) -> + Client_proto_contracts.RawContractAlias.of_fresh + cctxt + force + alias_name + >>=? fun alias_name -> + match Contract.is_implicit source with + | None -> + failwith + "only implicit accounts can be the source of an origination" + | Some source -> ( + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + List.map_es + (fun (pk_uri, _) -> Client_keys.public_key pk_uri) + keys + >>=? fun keys -> + Client_proto_multisig.originate_multisig + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ?fee + ?gas_limit + ?storage_limit + ~verbose_signing + ~delegate + ~threshold:(Z.of_int threshold) + ~keys + ~balance + ~source + ~src_pk + ~src_sk + ~fee_parameter + () + >>= fun errors -> + Client_proto_context_commands.report_michelson_errors + ~no_print_source + ~msg:"multisig origination simulation failed" + cctxt + errors + >>= function + | None -> return_unit + | Some (_res, contract) -> + if dry_run then return_unit + else + Client_proto_context.save_contract + ~force + cctxt + alias_name + contract + >>=? fun () -> return_unit)); + command + ~group + ~desc: + "Display the threshold, public keys, and byte sequence to sign for a \ + multisigned transfer." + (args3 bytes_only_switch arg_arg entrypoint_arg) + (prefixes ["prepare"; "multisig"; "transaction"; "on"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefix "transferring" + @@ Client_proto_args.tez_param + ~name:"qty" + ~desc:"amount taken from source" + @@ prefix "to" + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"dst" + ~desc:"name/literal of the destination contract" + @@ stop) + (fun (bytes_only, parameter, entrypoint) + (_, multisig_contract) + amount + (_, destination) + (cctxt : #Protocol_client_context.full) -> + let entrypoint = Option.value ~default:"default" entrypoint in + let parameter = Option.value ~default:"Unit" parameter in + Lwt.return @@ Micheline_parser.no_parsing_error + @@ Michelson_v1_parser.parse_expression parameter + >>=? fun {expanded = parameter; _} -> + get_parameter_type cctxt ~destination ~entrypoint + >>=? fun parameter_type -> + Client_proto_multisig.prepare_multisig_transaction + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~multisig_contract + ~action: + (Client_proto_multisig.Transfer + {amount; destination; entrypoint; parameter_type; parameter}) + () + >>=? fun prepared_command -> + return @@ prepare_command_display prepared_command bytes_only); + command + ~group + ~desc: + "Display the threshold, public keys, and byte sequence to sign for a \ + multisigned lambda execution in a generic multisig contract." + (args1 bytes_only_switch) + (prefixes ["prepare"; "multisig"; "transaction"; "on"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefixes ["running"; "lambda"] + @@ lambda_param () @@ stop) + (fun bytes_only + (_, multisig_contract) + lambda + (cctxt : #Protocol_client_context.full) -> + Lwt.return @@ Micheline_parser.no_parsing_error + @@ Michelson_v1_parser.parse_expression lambda + >>=? fun {expanded = lambda; _} -> + Client_proto_multisig.prepare_multisig_transaction + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~multisig_contract + ~action:(Client_proto_multisig.Lambda lambda) + () + >>=? fun prepared_command -> + return @@ prepare_command_display prepared_command bytes_only); + command + ~group + ~desc: + "Display the threshold, public keys, and byte sequence to sign for a \ + multisigned delegate change." + (args1 bytes_only_switch) + (prefixes ["prepare"; "multisig"; "transaction"; "on"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefixes ["setting"; "delegate"; "to"] + @@ Client_keys.Public_key_hash.source_param + ~name:"dlgt" + ~desc:"new delegate of the new multisig contract" + @@ stop) + (fun bytes_only + (_, multisig_contract) + new_delegate + (cctxt : #Protocol_client_context.full) -> + Client_proto_multisig.prepare_multisig_transaction + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~multisig_contract + ~action:(Client_proto_multisig.Change_delegate (Some new_delegate)) + () + >>=? fun prepared_command -> + return @@ prepare_command_display prepared_command bytes_only); + command + ~group + ~desc: + "Display the threshold, public keys, and byte sequence to sign for a \ + multisigned delegate withdraw." + (args1 bytes_only_switch) + (prefixes ["prepare"; "multisig"; "transaction"; "on"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefixes ["withdrawing"; "delegate"] + @@ stop) + (fun bytes_only + (_, multisig_contract) + (cctxt : #Protocol_client_context.full) -> + Client_proto_multisig.prepare_multisig_transaction + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~multisig_contract + ~action:(Client_proto_multisig.Change_delegate None) + () + >>=? fun prepared_command -> + return @@ prepare_command_display prepared_command bytes_only); + command + ~group + ~desc: + "Display the threshold, public keys, and byte sequence to sign for a \ + multisigned change of keys and threshold." + (args1 bytes_only_switch) + (prefixes ["prepare"; "multisig"; "transaction"; "on"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefixes ["setting"; "threshold"; "to"] + @@ threshold_param () + @@ prefixes ["and"; "public"; "keys"; "to"] + @@ seq_of_param (public_key_param ())) + (fun bytes_only + (_, multisig_contract) + new_threshold + new_keys + (cctxt : #Protocol_client_context.full) -> + List.map_es + (fun (pk_uri, _) -> Client_keys.public_key pk_uri) + new_keys + >>=? fun keys -> + Client_proto_multisig.prepare_multisig_transaction + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~multisig_contract + ~action: + (Client_proto_multisig.Change_keys (Z.of_int new_threshold, keys)) + () + >>=? fun prepared_command -> + return @@ prepare_command_display prepared_command bytes_only); + command + ~group + ~desc:"Sign a transaction for a multisig contract." + (args2 arg_arg entrypoint_arg) + (prefixes ["sign"; "multisig"; "transaction"; "on"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefix "transferring" + @@ Client_proto_args.tez_param + ~name:"qty" + ~desc:"amount taken from source" + @@ prefix "to" + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"dst" + ~desc:"name/literal of the destination contract" + @@ prefixes ["using"; "secret"; "key"] + @@ secret_key_param () @@ stop) + (fun (parameter, entrypoint) + (_, multisig_contract) + amount + (_, destination) + sk + (cctxt : #Protocol_client_context.full) -> + let entrypoint = Option.value ~default:"default" entrypoint in + let parameter = Option.value ~default:"Unit" parameter in + Lwt.return @@ Micheline_parser.no_parsing_error + @@ Michelson_v1_parser.parse_expression parameter + >>=? fun {expanded = parameter; _} -> + get_parameter_type cctxt ~destination ~entrypoint + >>=? fun parameter_type -> + Client_proto_multisig.prepare_multisig_transaction + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~multisig_contract + ~action: + (Client_proto_multisig.Transfer + {amount; destination; entrypoint; parameter_type; parameter}) + () + >>=? fun prepared_command -> + Client_keys.sign cctxt sk prepared_command.bytes >>=? fun signature -> + return @@ Format.printf "%a@." Signature.pp signature); + command + ~group + ~desc:"Sign a lambda for a generic multisig contract." + no_options + (prefixes ["sign"; "multisig"; "transaction"; "on"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefixes ["running"; "lambda"] + @@ lambda_param () + @@ prefixes ["using"; "secret"; "key"] + @@ secret_key_param () @@ stop) + (fun () + (_, multisig_contract) + lambda + sk + (cctxt : #Protocol_client_context.full) -> + Lwt.return @@ Micheline_parser.no_parsing_error + @@ Michelson_v1_parser.parse_expression lambda + >>=? fun {expanded = lambda; _} -> + Client_proto_multisig.prepare_multisig_transaction + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~multisig_contract + ~action:(Lambda lambda) + () + >>=? fun prepared_command -> + Client_keys.sign cctxt sk prepared_command.bytes >>=? fun signature -> + return @@ Format.printf "%a@." Signature.pp signature); + command + ~group + ~desc:"Sign a delegate change for a multisig contract." + no_options + (prefixes ["sign"; "multisig"; "transaction"; "on"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefixes ["setting"; "delegate"; "to"] + @@ Client_keys.Public_key_hash.source_param + ~name:"dlgt" + ~desc:"new delegate of the new multisig contract" + @@ prefixes ["using"; "secret"; "key"] + @@ secret_key_param () @@ stop) + (fun () + (_, multisig_contract) + delegate + sk + (cctxt : #Protocol_client_context.full) -> + Client_proto_multisig.prepare_multisig_transaction + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~multisig_contract + ~action:(Client_proto_multisig.Change_delegate (Some delegate)) + () + >>=? fun prepared_command -> + Client_keys.sign cctxt sk prepared_command.bytes >>=? fun signature -> + return @@ Format.printf "%a@." Signature.pp signature); + command + ~group + ~desc:"Sign a delegate withdraw for a multisig contract." + no_options + (prefixes ["sign"; "multisig"; "transaction"; "on"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefixes ["withdrawing"; "delegate"] + @@ prefixes ["using"; "secret"; "key"] + @@ secret_key_param () @@ stop) + (fun () + (_, multisig_contract) + sk + (cctxt : #Protocol_client_context.full) -> + Client_proto_multisig.prepare_multisig_transaction + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~multisig_contract + ~action:(Client_proto_multisig.Change_delegate None) + () + >>=? fun prepared_command -> + Client_keys.sign cctxt sk prepared_command.bytes >>=? fun signature -> + return @@ Format.printf "%a@." Signature.pp signature); + command + ~group + ~desc: + "Sign a change of public keys and threshold for a multisig contract." + no_options + (prefixes ["sign"; "multisig"; "transaction"; "on"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefixes ["using"; "secret"; "key"] + @@ secret_key_param () + @@ prefixes ["setting"; "threshold"; "to"] + @@ threshold_param () + @@ prefixes ["and"; "public"; "keys"; "to"] + @@ seq_of_param (public_key_param ())) + (fun () + (_, multisig_contract) + sk + new_threshold + new_keys + (cctxt : #Protocol_client_context.full) -> + List.map_es + (fun (pk_uri, _) -> Client_keys.public_key pk_uri) + new_keys + >>=? fun keys -> + Client_proto_multisig.prepare_multisig_transaction + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~multisig_contract + ~action: + (Client_proto_multisig.Change_keys (Z.of_int new_threshold, keys)) + () + >>=? fun prepared_command -> + Client_keys.sign cctxt sk prepared_command.bytes >>=? fun signature -> + return @@ Format.printf "%a@." Signature.pp signature); + command + ~group + ~desc:"Transfer tokens using a multisig contract." + transfer_options + (prefixes ["from"; "multisig"; "contract"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name/literal of the multisig contract" + @@ prefix "transfer" + @@ Client_proto_args.tez_param + ~name:"qty" + ~desc:"amount taken from the multisig contract" + @@ prefix "to" + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"dst" + ~desc:"name/literal of the destination contract" + @@ prefixes ["on"; "behalf"; "of"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"src" + ~desc:"source calling the multisig contract" + @@ prefixes ["with"; "signatures"] + @@ seq_of_param (signature_param ())) + (fun ( fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + parameter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap, + entrypoint ) + (_, multisig_contract) + amount + (_, destination) + (_, source) + signatures + (cctxt : #Protocol_client_context.full) -> + let entrypoint = Option.value ~default:"default" entrypoint in + let parameter = Option.value ~default:"Unit" parameter in + Lwt.return @@ Micheline_parser.no_parsing_error + @@ Michelson_v1_parser.parse_expression parameter + >>=? fun {expanded = parameter; _} -> + get_parameter_type cctxt ~destination ~entrypoint + >>=? fun parameter_type -> + match Contract.is_implicit source with + | None -> + failwith + "only implicit accounts can be the source of a contract call" + | Some source -> ( + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Client_proto_multisig.call_multisig + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~fee_parameter + ~source + ?fee + ~src_pk + ~src_sk + ~multisig_contract + ~action: + (Client_proto_multisig.Transfer + { + amount; + destination; + entrypoint; + parameter_type; + parameter; + }) + ~signatures + ~amount:Tez.zero + ?gas_limit + ?storage_limit + ?counter + () + >>= Client_proto_context_commands.report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + >>= function + | None -> return_unit + | Some (_res, _contracts) -> return_unit)); + command + ~group + ~desc:"Run a lambda on a generic multisig contract." + non_transfer_options + (prefixes ["from"; "multisig"; "contract"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name/literal of the multisig contract" + @@ prefixes ["run"; "lambda"] + @@ lambda_param () + @@ prefixes ["on"; "behalf"; "of"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"src" + ~desc:"source calling the multisig contract" + @@ prefixes ["with"; "signatures"] + @@ seq_of_param (signature_param ())) + (fun ( fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + (_, multisig_contract) + lambda + (_, source) + signatures + (cctxt : #Protocol_client_context.full) -> + match Contract.is_implicit source with + | None -> + failwith + "only implicit accounts can be the source of a contract call" + | Some source -> ( + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Lwt.return @@ Micheline_parser.no_parsing_error + @@ Michelson_v1_parser.parse_expression lambda + >>=? fun {expanded = lambda; _} -> + Client_proto_multisig.call_multisig + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~fee_parameter + ~source + ?fee + ~src_pk + ~src_sk + ~multisig_contract + ~action:(Client_proto_multisig.Lambda lambda) + ~signatures + ~amount:Tez.zero + ?gas_limit + ?storage_limit + ?counter + () + >>= Client_proto_context_commands.report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + >>= function + | None -> return_unit + | Some (_res, _contracts) -> return_unit)); + command + ~group + ~desc:"Change the delegate of a multisig contract." + non_transfer_options + (prefixes ["set"; "delegate"; "of"; "multisig"; "contract"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefix "to" + @@ Client_keys.Public_key_hash.source_param + ~name:"dlgt" + ~desc:"new delegate of the new multisig contract" + @@ prefixes ["on"; "behalf"; "of"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"src" + ~desc:"source calling the multisig contract" + @@ prefixes ["with"; "signatures"] + @@ seq_of_param (signature_param ())) + (fun ( fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + (_, multisig_contract) + delegate + (_, source) + signatures + (cctxt : #Protocol_client_context.full) -> + match Contract.is_implicit source with + | None -> + failwith + "only implicit accounts can be the source of a contract call" + | Some source -> ( + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Client_proto_multisig.call_multisig + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~fee_parameter + ~source + ?fee + ~src_pk + ~src_sk + ~multisig_contract + ~action:(Client_proto_multisig.Change_delegate (Some delegate)) + ~signatures + ~amount:Tez.zero + ?gas_limit + ?storage_limit + ?counter + () + >>= Client_proto_context_commands.report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + >>= function + | None -> return_unit + | Some (_res, _contracts) -> return_unit)); + command + ~group + ~desc:"Withdraw the delegate of a multisig contract." + non_transfer_options + (prefixes ["withdraw"; "delegate"; "of"; "multisig"; "contract"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefixes ["on"; "behalf"; "of"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"src" + ~desc:"source calling the multisig contract" + @@ prefixes ["with"; "signatures"] + @@ seq_of_param (signature_param ())) + (fun ( fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + (_, multisig_contract) + (_, source) + signatures + (cctxt : #Protocol_client_context.full) -> + match Contract.is_implicit source with + | None -> + failwith + "only implicit accounts can be the source of a contract call" + | Some source -> ( + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Client_proto_multisig.call_multisig + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~fee_parameter + ~source + ?fee + ~src_pk + ~src_sk + ~multisig_contract + ~action:(Client_proto_multisig.Change_delegate None) + ~signatures + ~amount:Tez.zero + ?gas_limit + ?storage_limit + ?counter + () + >>= Client_proto_context_commands.report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + >>= function + | None -> return_unit + | Some (_res, _contracts) -> return_unit)); + command + ~group + ~desc:"Change public keys and threshold for a multisig contract." + non_transfer_options + (prefixes ["set"; "threshold"; "of"; "multisig"; "contract"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefixes ["to"] + @@ threshold_param () + @@ prefixes ["and"; "public"; "keys"; "to"] + @@ non_terminal_seq (public_key_param ()) ~suffix:["on"; "behalf"; "of"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"src" + ~desc:"source calling the multisig contract" + @@ prefixes ["with"; "signatures"] + @@ seq_of_param (signature_param ())) + (fun ( fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + (_, multisig_contract) + new_threshold + new_keys + (_, source) + signatures + (cctxt : #Protocol_client_context.full) -> + match Contract.is_implicit source with + | None -> + failwith + "only implicit accounts can be the source of a contract call" + | Some source -> ( + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + List.map_es + (fun (pk_uri, _) -> Client_keys.public_key pk_uri) + new_keys + >>=? fun keys -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Client_proto_multisig.call_multisig + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~fee_parameter + ~source + ?fee + ~src_pk + ~src_sk + ~multisig_contract + ~action: + (Client_proto_multisig.Change_keys + (Z.of_int new_threshold, keys)) + ~signatures + ~amount:Tez.zero + ?gas_limit + ?storage_limit + ?counter + () + >>= Client_proto_context_commands.report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + >>= function + | None -> return_unit + | Some (_res, _contracts) -> return_unit)); + (* This command is no longer necessary as Clic now supports non terminal + lists of parameters, however, it is kept for compatibility. *) + command + ~group + ~desc: + "Run a transaction described by a sequence of bytes on a multisig \ + contract." + non_transfer_options + (prefixes ["run"; "transaction"] + @@ bytes_param + ~name:"bytes" + ~desc: + "the sequence of bytes to deserialize as a multisig action, can \ + be obtained by one of the \"prepare multisig transaction\" \ + commands" + @@ prefixes ["on"; "multisig"; "contract"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"multisig" + ~desc:"name or address of the originated multisig contract" + @@ prefixes ["on"; "behalf"; "of"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"src" + ~desc:"source calling the multisig contract" + @@ prefixes ["with"; "signatures"] + @@ seq_of_param (signature_param ())) + (fun ( fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + bytes + (_, multisig_contract) + (_, source) + signatures + (cctxt : #Protocol_client_context.full) -> + match Contract.is_implicit source with + | None -> + failwith + "only implicit accounts can be the source of a contract call" + | Some source -> ( + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Client_proto_multisig.call_multisig_on_bytes + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~fee_parameter + ~source + ?fee + ~src_pk + ~src_sk + ~multisig_contract + ~bytes + ~signatures + ~amount:Tez.zero + ?gas_limit + ?storage_limit + ?counter + () + >>= Client_proto_context_commands.report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + >>= function + | None -> return_unit + | Some (_res, _contracts) -> return_unit)); + command + ~group + ~desc:"Show the hashes of the supported multisig contracts." + no_options + (fixed ["show"; "supported"; "multisig"; "hashes"]) + (fun () _cctxt -> + Format.printf "Hashes of supported multisig contracts:@." ; + List.iter + (fun h -> Format.printf "%a@." Script_expr_hash.pp h) + Client_proto_multisig.known_multisig_hashes ; + return_unit); + command + ~group + ~desc:"Show the script of the recommended multisig contract." + no_options + (fixed ["show"; "multisig"; "script"]) + (fun () _cctxt -> + let {Michelson_v1_parser.source; _} = + Michelson_v1_printer.unparse_toplevel + Client_proto_multisig.multisig_script + in + Format.printf "%s@." source ; + return_unit); + ] diff --git a/src/proto_011_PtHangzH/lib_client_commands/client_proto_multisig_commands.mli b/src/proto_011_PtHangzH/lib_client_commands/client_proto_multisig_commands.mli new file mode 100644 index 000000000000..c328ace47c3f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/client_proto_multisig_commands.mli @@ -0,0 +1,26 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val commands : unit -> Protocol_client_context.full Clic.command list diff --git a/src/proto_011_PtHangzH/lib_client_commands/client_proto_programs_commands.ml b/src/proto_011_PtHangzH/lib_client_commands/client_proto_programs_commands.ml new file mode 100644 index 000000000000..f476cbcc2546 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/client_proto_programs_commands.ml @@ -0,0 +1,955 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +let group = + { + Clic.name = "scripts"; + title = "Commands for managing the library of known scripts"; + } + +open Tezos_micheline +open Client_proto_programs +open Client_proto_args +open Client_proto_contracts + +let commands () = + let open Clic in + let show_types_switch = + switch + ~long:"details" + ~short:'v' + ~doc:"show the types of each instruction" + () + in + let emacs_mode_switch = + switch + ~long:"emacs" + ?short:None + ~doc:"output in `michelson-mode.el` compatible format" + () + in + let trace_stack_switch = + switch ~long:"trace-stack" ~doc:"show the stack after each step" () + in + let zero_loc_switch = + switch ~short:'z' ~long:"zero-loc" ~doc:"replace location with \"0\"" () + in + let legacy_switch = + switch + ~long:"legacy" + ~doc:"typecheck in legacy mode as if the data was taken from the chain" + () + in + let amount_arg = + Client_proto_args.tez_arg + ~parameter:"amount" + ~doc:"amount of the transfer in \xEA\x9C\xA9" + ~default:"0.05" + in + let source_arg = + ContractAlias.destination_arg + ~name:"source" + ~doc:"name of the source (i.e. SENDER) contract for the transaction" + () + in + let payer_arg = + ContractAlias.destination_arg + ~name:"payer" + ~doc:"name of the payer (i.e. SOURCE) contract for the transaction" + () + in + let balance_arg = + Client_proto_args.tez_arg + ~parameter:"balance" + ~doc:"balance of run contract in \xEA\x9C\xA9" + ~default:"4_000_000" + in + let resolve_max_gas cctxt block = function + | None -> + Alpha_services.Constants.all cctxt (cctxt#chain, block) + >>=? fun {parametric = {hard_gas_limit_per_operation; _}; _} -> + return hard_gas_limit_per_operation + | Some gas -> return gas + in + let parse_expr expr = + Lwt.return @@ Micheline_parser.no_parsing_error + @@ Michelson_v1_parser.parse_expression expr + in + let data_type_arg = + arg + ~doc:"the given data will be type-checked against this type" + ~short:'t' + ~long:"type" + ~placeholder:"unit" + data_parameter + in + let bytes_parameter ~name ~desc = + param ~name ~desc Client_proto_args.bytes_parameter + in + let signature_parameter = + parameter (fun _cctxt s -> + match Signature.of_b58check_opt s with + | Some s -> return s + | None -> failwith "Not given a valid signature") + in + let convert_input_format_param = + param + ~name:"input_format" + ~desc:"format of the input for conversion" + (parameter + ~autocomplete:(fun _ -> return ["michelson"; "json"; "binary"]) + (fun _ s -> + match String.lowercase_ascii s with + | "michelson" -> return `Michelson + | "json" -> return `JSON + | "binary" -> return `Binary + | _ -> + failwith + "invalid input format, expecting one of \"michelson\", \ + \"json\" or \"binary\".")) + in + let convert_output_format_param = + param + ~name:"output_format" + ~desc:"format of the conversion output" + (parameter + ~autocomplete:(fun _ -> + return ["michelson"; "json"; "binary"; "ocaml"]) + (fun _ s -> + match String.lowercase_ascii s with + | "michelson" -> return `Michelson + | "json" -> return `JSON + | "binary" -> return `Binary + | "ocaml" -> return `OCaml + | _ -> + failwith + "invalid output format, expecting one of \"michelson\", \ + \"json\", \"binary\" or \"ocaml\".")) + in + let file_or_literal_param () = + param + ~name:"source" + ~desc:"literal or a path to a file" + (parameter (fun cctxt s -> + cctxt#read_file s >>= function + | Ok v -> return (Some s, v) + | Error _ -> return (None, s))) + in + let handle_parsing_error label (cctxt : Protocol_client_context.full) + (emacs_mode, no_print_source) program body = + match program with + | (program, []) -> body program + | res_with_errors when emacs_mode -> + cctxt#message + "(@[(%s . ())@ (errors . %a)@])" + label + Michelson_v1_emacs.report_errors + res_with_errors + >>= fun () -> return_unit + | (parsed, errors) -> + cctxt#message + "%a" + (fun ppf () -> + Michelson_v1_error_reporter.report_errors + ~details:(not no_print_source) + ~parsed + ~show_source:(not no_print_source) + ppf + errors) + () + >>= fun () -> cctxt#error "syntax error in program" + in + [ + command + ~group + ~desc:"Lists all scripts in the library." + no_options + (fixed ["list"; "known"; "scripts"]) + (fun () (cctxt : Protocol_client_context.full) -> + Program.load cctxt >>=? fun list -> + List.iter_s (fun (n, _) -> cctxt#message "%s" n) list >>= fun () -> + return_unit); + command + ~group + ~desc:"Add a script to the library." + (args1 (Program.force_switch ())) + (prefixes ["remember"; "script"] + @@ Program.fresh_alias_param @@ Program.source_param @@ stop) + (fun force name hash cctxt -> + Program.of_fresh cctxt force name >>=? fun name -> + Program.add ~force cctxt name hash); + command + ~group + ~desc:"Remove a script from the library." + no_options + (prefixes ["forget"; "script"] @@ Program.alias_param @@ stop) + (fun () (name, _) cctxt -> Program.del cctxt name); + command + ~group + ~desc:"Display a script from the library." + no_options + (prefixes ["show"; "known"; "script"] @@ Program.alias_param @@ stop) + (fun () (_, program) (cctxt : Protocol_client_context.full) -> + Program.to_source program >>=? fun source -> + cctxt#message "%s\n" source >>= fun () -> return_unit); + command + ~group + ~desc:"Ask the node to run a script." + (args9 + trace_stack_switch + amount_arg + balance_arg + source_arg + payer_arg + no_print_source_flag + run_gas_limit_arg + entrypoint_arg + (unparsing_mode_arg ~default:"Readable")) + (prefixes ["run"; "script"] + @@ Program.source_param + @@ prefixes ["on"; "storage"] + @@ param ~name:"storage" ~desc:"the storage data" data_parameter + @@ prefixes ["and"; "input"] + @@ param ~name:"input" ~desc:"the input data" data_parameter + @@ stop) + (fun ( trace_exec, + amount, + balance, + source, + payer, + no_print_source, + gas, + entrypoint, + unparsing_mode ) + program + storage + input + cctxt -> + let source = Option.map snd source in + let payer = Option.map snd payer in + Lwt.return @@ Micheline_parser.no_parsing_error program + >>=? fun program -> + let show_source = not no_print_source in + if trace_exec then + trace + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~amount + ~balance + ~program + ~storage + ~input + ~unparsing_mode + ?source + ?payer + ?gas + ?entrypoint + () + >>= fun res -> + print_trace_result cctxt ~show_source ~parsed:program res + else + run + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~amount + ~balance + ~program + ~storage + ~input + ~unparsing_mode + ?source + ?payer + ?gas + ?entrypoint + () + >>= fun res -> print_run_result cctxt ~show_source ~parsed:program res); + command + ~group + ~desc:"Ask the node to compute the size of a script." + (args4 + emacs_mode_switch + no_print_source_flag + run_gas_limit_arg + legacy_switch) + (prefixes ["compute"; "size"; "for"; "script"] + @@ Program.source_param + @@ prefixes ["on"; "storage"] + @@ param ~name:"storage" ~desc:"the storage data" data_parameter + @@ stop) + (fun (emacs_mode, no_print_source, original_gas, legacy) + program + storage + cctxt -> + let setup = (emacs_mode, no_print_source) in + resolve_max_gas cctxt cctxt#block original_gas >>=? fun original_gas -> + handle_parsing_error "size" cctxt setup program @@ fun program -> + script_size + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~gas:original_gas + ~legacy + ~program + ~storage + () + >>=? fun code_size -> + cctxt#message "%d" code_size >>= fun _ -> return ()); + command + ~group + ~desc:"Ask the node to typecheck a script." + (args5 + show_types_switch + emacs_mode_switch + no_print_source_flag + run_gas_limit_arg + legacy_switch) + (prefixes ["typecheck"; "script"] @@ Program.source_param @@ stop) + (fun (show_types, emacs_mode, no_print_source, original_gas, legacy) + program + cctxt -> + let setup = (emacs_mode, no_print_source) in + handle_parsing_error "types" cctxt setup program @@ fun program -> + resolve_max_gas cctxt cctxt#block original_gas >>=? fun original_gas -> + typecheck_program + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~gas:original_gas + ~legacy + program + >>= fun res -> + print_typecheck_result + ~emacs:emacs_mode + ~show_types + ~print_source_on_error:(not no_print_source) + program + res + cctxt); + command + ~group + ~desc:"Ask the node to typecheck a data expression." + (args3 no_print_source_flag run_gas_limit_arg legacy_switch) + (prefixes ["typecheck"; "data"] + @@ param ~name:"data" ~desc:"the data to typecheck" data_parameter + @@ prefixes ["against"; "type"] + @@ param ~name:"type" ~desc:"the expected type" data_parameter + @@ stop) + (fun (no_print_source, custom_gas, legacy) data ty cctxt -> + resolve_max_gas cctxt cctxt#block custom_gas >>=? fun original_gas -> + Client_proto_programs.typecheck_data + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~gas:original_gas + ~legacy + ~data + ~ty + () + >>= function + | Ok gas -> + cctxt#message + "@[Well typed@,Gas remaining: %a@]" + Alpha_context.Gas.pp + gas + >>= fun () -> return_unit + | Error errs -> + cctxt#warning + "%a" + (Michelson_v1_error_reporter.report_errors + ~details:false + ~show_source:(not no_print_source) + ?parsed:None) + errs + >>= fun () -> cctxt#error "ill-typed data"); + command + ~group + ~desc: + "Ask the node to pack a data expression.\n\ + The returned hash is the same as what Michelson instruction `PACK` \ + would have produced.\n\ + Also displays the result of hashing this packed data with `BLAKE2B`, \ + `SHA256` or `SHA512` instruction." + (args2 run_gas_limit_arg (Tezos_clic_unix.Scriptable.clic_arg ())) + (prefixes ["hash"; "data"] + @@ param ~name:"data" ~desc:"the data to hash" data_parameter + @@ prefixes ["of"; "type"] + @@ param ~name:"type" ~desc:"type of the data" data_parameter + @@ stop) + (fun (custom_gas, scriptable) data typ cctxt -> + resolve_max_gas cctxt cctxt#block custom_gas >>=? fun original_gas -> + Plugin.RPC.Scripts.pack_data + cctxt + (cctxt#chain, cctxt#block) + ~gas:original_gas + ~data:data.expanded + ~ty:typ.expanded + >>= function + | Ok (bytes, remaining_gas) -> + let hash = Script_expr_hash.hash_bytes [bytes] in + let name_value_rows = + Format. + [ + ( "Raw packed data", + asprintf "0x%a" Hex.pp (Hex.of_bytes bytes) ); + ( "Script-expression-ID-Hash", + asprintf "%a" Script_expr_hash.pp hash ); + ( "Raw Script-expression-ID-Hash", + asprintf + "0x%a" + Hex.pp + (Hex.of_bytes (Script_expr_hash.to_bytes hash)) ); + ( "Ledger Blake2b hash", + Base58.raw_encode Blake2B.(hash_bytes [bytes] |> to_string) + ); + ( "Raw Sha256 hash", + asprintf + "0x%a" + Hex.pp + (Hex.of_bytes (Environment.Raw_hashes.sha256 bytes)) ); + ( "Raw Sha512 hash", + asprintf + "0x%a" + Hex.pp + (Hex.of_bytes (Environment.Raw_hashes.sha512 bytes)) ); + ( "Gas remaining", + asprintf "%a" Alpha_context.Gas.pp remaining_gas ); + ] + in + Tezos_clic_unix.Scriptable.output + scriptable + ~for_human:(fun () -> + List.iter_s + (fun (name, value) -> cctxt#message "%s: %s" name value) + name_value_rows + >|= ok) + ~for_script:(fun () -> + name_value_rows |> List.map (fun (name, value) -> [name; value])) + | Error errs -> + cctxt#warning + "%a" + (Michelson_v1_error_reporter.report_errors + ~details:false + ~show_source:false + ?parsed:None) + errs + >>= fun () -> cctxt#error "ill-formed data"); + command + ~group + ~desc:"Ask the node to hash a Michelson script with `BLAKE2B`." + (args3 + enforce_indentation_flag + display_names_flag + (Tezos_clic_unix.Scriptable.clic_arg ())) + (prefixes ["hash"; "script"] @@ seq_of_param @@ file_or_literal_param ()) + (fun (check, display_names, scriptable) + expr_strings + (cctxt : Protocol_client_context.full) -> + if List.length expr_strings == 0 then + cctxt#warning "No scripts were specified on the command line" >|= ok + else + List.mapi_ep + (fun i (src, expr_string) -> + let program = + Michelson_v1_parser.parse_toplevel ~check expr_string + in + Micheline_parser.no_parsing_error program >>?= fun program -> + let code = program.expanded in + let bytes = + Data_encoding.Binary.to_bytes_exn + Alpha_context.Script.expr_encoding + code + in + let hash = + Format.asprintf + "%a" + Script_expr_hash.pp + (Script_expr_hash.hash_bytes [bytes]) + in + let name = + Option.value + src + ~default:("Literal script " ^ string_of_int (i + 1)) + in + return (hash, name)) + expr_strings + >>=? fun hash_name_rows -> + Tezos_clic_unix.Scriptable.output + scriptable + ~for_human:(fun () -> + List.iter_s + (fun (hash, name) -> + if display_names then cctxt#answer "%s\t%s" hash name + else cctxt#answer "%s" hash) + hash_name_rows + >|= ok) + ~for_script:(fun () -> + List.map + (fun (hash, name) -> + if display_names then [hash; name] else [hash]) + hash_name_rows)); + command + ~group + ~desc: + "Parse a byte sequence (in hexadecimal notation) as a data expression, \ + as per Michelson instruction `UNPACK`." + no_options + (prefixes ["unpack"; "michelson"; "data"] + @@ bytes_parameter ~name:"bytes" ~desc:"the packed data to parse" + @@ stop) + (fun () bytes cctxt -> + (if Bytes.get bytes 0 != '\005' then + failwith + "Not a piece of packed Michelson data (must start with `0x05`)" + else return_unit) + >>=? fun () -> + (* Remove first byte *) + let bytes = Bytes.sub bytes 1 (Bytes.length bytes - 1) in + match + Data_encoding.Binary.of_bytes_opt + Alpha_context.Script.expr_encoding + bytes + with + | None -> failwith "Could not decode bytes" + | Some expr -> + cctxt#message "%a" Michelson_v1_printer.print_expr_unwrapped expr + >>= fun () -> return_unit); + command + ~group + ~desc:"Ask the node to normalize a script." + (args1 (unparsing_mode_arg ~default:"Readable")) + (prefixes ["normalize"; "script"] @@ Program.source_param @@ stop) + (fun unparsing_mode program cctxt -> + Lwt.return @@ Micheline_parser.no_parsing_error program + >>=? fun program -> + Plugin.RPC.Scripts.normalize_script + cctxt + (cctxt#chain, cctxt#block) + ~script:program.expanded + ~unparsing_mode + >>= function + | Ok program -> + cctxt#message + "%a" + (fun ppf () : unit -> + Michelson_v1_printer.print_expr_unwrapped ppf program) + () + >>= fun () -> return_unit + | Error errs -> + cctxt#warning + "%a" + (Michelson_v1_error_reporter.report_errors + ~details:false + ~show_source:false + ?parsed:None) + errs + >>= fun () -> cctxt#error "ill-typed script"); + command + ~group + ~desc:"Ask the node to normalize a data expression." + (args2 (unparsing_mode_arg ~default:"Readable") legacy_switch) + (prefixes ["normalize"; "data"] + @@ param + ~name:"data" + ~desc:"the data expression to normalize" + data_parameter + @@ prefixes ["of"; "type"] + @@ param ~name:"type" ~desc:"type of the data expression" data_parameter + @@ stop) + (fun (unparsing_mode, legacy) data typ cctxt -> + Plugin.RPC.Scripts.normalize_data + cctxt + (cctxt#chain, cctxt#block) + ~legacy + ~data:data.expanded + ~ty:typ.expanded + ~unparsing_mode + >>= function + | Ok expr -> + cctxt#message "%a" Michelson_v1_printer.print_expr_unwrapped expr + >>= fun () -> return_unit + | Error errs -> + cctxt#warning + "%a" + (Michelson_v1_error_reporter.report_errors + ~details:false + ~show_source:false + ?parsed:None) + errs + >>= fun () -> cctxt#error "ill-typed data expression"); + command + ~group + ~desc:"Ask the node to normalize a type." + no_options + (prefixes ["normalize"; "type"] + @@ param + ~name:"typ" + ~desc:"the Michelson type to normalize" + data_parameter + @@ stop) + (fun () typ cctxt -> + Plugin.RPC.Scripts.normalize_type + cctxt + (cctxt#chain, cctxt#block) + ~ty:typ.expanded + >>= function + | Ok expr -> + cctxt#message "%a" Michelson_v1_printer.print_expr_unwrapped expr + >>= fun () -> return_unit + | Error errs -> + cctxt#warning + "%a" + (Michelson_v1_error_reporter.report_errors + ~details:false + ~show_source:false + ?parsed:None) + errs + >>= fun () -> cctxt#error "ill-formed type"); + command + ~group + ~desc: + "Sign a raw sequence of bytes and display it using the format expected \ + by Michelson instruction `CHECK_SIGNATURE`." + no_options + (prefixes ["sign"; "bytes"] + @@ bytes_parameter ~name:"data" ~desc:"the raw data to sign" + @@ prefixes ["for"] + @@ Client_keys.Secret_key.source_param @@ stop) + (fun () bytes sk cctxt -> + Client_keys.sign cctxt sk bytes >>=? fun signature -> + cctxt#message "Signature: %a" Signature.pp signature >>= fun () -> + return_unit); + command + ~group + ~desc: + "Check the signature of a byte sequence as per Michelson instruction \ + `CHECK_SIGNATURE`." + (args1 (switch ~doc:"Use only exit codes" ~short:'q' ~long:"quiet" ())) + (prefixes ["check"; "that"; "bytes"] + @@ bytes_parameter ~name:"bytes" ~desc:"the signed data" + @@ prefixes ["were"; "signed"; "by"] + @@ Client_keys.Public_key.alias_param ~name:"key" + @@ prefixes ["to"; "produce"] + @@ param + ~name:"signature" + ~desc:"the signature to check" + signature_parameter + @@ stop) + (fun quiet + bytes + (_, (key_locator, _)) + signature + (cctxt : #Protocol_client_context.full) -> + Client_keys.check key_locator signature bytes >>=? function + | false -> cctxt#error "invalid signature" + | true -> + if quiet then return_unit + else + cctxt#message "Signature check successful." >>= fun () -> + return_unit); + command + ~group + ~desc:"Ask the type of an entrypoint of a script." + (args2 emacs_mode_switch no_print_source_flag) + (prefixes ["get"; "script"; "entrypoint"; "type"; "of"] + @@ string ~name:"entrypoint" ~desc:"the entrypoint to describe" + @@ prefixes ["for"] + @@ Program.source_param @@ stop) + (fun ((emacs_mode, no_print_source) as setup) entrypoint program cctxt -> + handle_parsing_error "entrypoint" cctxt setup program @@ fun program -> + entrypoint_type + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + program + ~entrypoint + >>= fun entrypoint_type -> + print_entrypoint_type + ~emacs:emacs_mode + ~show_source:(not no_print_source) + ~parsed:program + ~entrypoint + cctxt + entrypoint_type); + command + ~group + ~desc:"Ask the node to list the entrypoints of a script." + (args2 emacs_mode_switch no_print_source_flag) + (prefixes ["get"; "script"; "entrypoints"; "for"] + @@ Program.source_param @@ stop) + (fun ((emacs_mode, no_print_source) as setup) program cctxt -> + handle_parsing_error "entrypoints" cctxt setup program @@ fun program -> + list_entrypoints cctxt ~chain:cctxt#chain ~block:cctxt#block program + >>= fun entrypoints -> + print_entrypoints_list + ~emacs:emacs_mode + ~show_source:(not no_print_source) + ~parsed:program + cctxt + entrypoints); + command + ~group + ~desc: + "Ask the node to list the unreachable paths in a script's parameter \ + type." + (args2 emacs_mode_switch no_print_source_flag) + (prefixes ["get"; "script"; "unreachable"; "paths"; "for"] + @@ Program.source_param @@ stop) + (fun ((emacs_mode, no_print_source) as setup) program cctxt -> + handle_parsing_error "entrypoints" cctxt setup program @@ fun program -> + list_unreachables cctxt ~chain:cctxt#chain ~block:cctxt#block program + >>= fun entrypoints -> + print_unreachables + ~emacs:emacs_mode + ~show_source:(not no_print_source) + ~parsed:program + cctxt + entrypoints); + command + ~group + ~desc:"Ask the node to expand the Michelson macros in a script." + no_options + (prefixes ["expand"; "macros"; "in"] @@ Program.source_param @@ stop) + (fun () program (cctxt : Protocol_client_context.full) -> + Lwt.return @@ Micheline_parser.no_parsing_error program + >>=? fun program -> + cctxt#message + "%a" + (fun ppf () : unit -> + Michelson_v1_printer.print_expr_unwrapped ppf program.expanded) + () + >>= fun () -> return_unit); + command + ~desc: + "Conversion of Michelson script from Micheline, JSON or binary to \ + Micheline, JSON, binary or OCaml" + (args3 zero_loc_switch legacy_switch enforce_indentation_flag) + (prefixes ["convert"; "script"] + @@ file_or_literal_param () @@ prefix "from" @@ convert_input_format_param + @@ prefix "to" @@ convert_output_format_param @@ stop) + (fun (zero_loc, legacy, check) + (_, expr_string) + from_format + to_format + (cctxt : Protocol_client_context.full) -> + (match from_format with + | `Michelson -> + let program = + Michelson_v1_parser.parse_toplevel ~check expr_string + in + Lwt.return @@ Micheline_parser.no_parsing_error program + >>=? fun program -> + (typecheck_program + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~legacy + program + >>= function + | Error _ as res -> + print_typecheck_result + ~emacs:false + ~show_types:true + ~print_source_on_error:true + program + res + cctxt + | Ok _ -> return_unit) + >>=? fun () -> return program.expanded + | `JSON -> ( + match Data_encoding.Json.from_string expr_string with + | Error err -> cctxt#error "%s" err + | Ok json -> + return + @@ Data_encoding.Json.destruct + Alpha_context.Script.expr_encoding + json) + | `Binary -> ( + bytes_of_prefixed_string expr_string >>=? fun bytes -> + match + Data_encoding.Binary.of_bytes_opt + Alpha_context.Script.expr_encoding + bytes + with + | None -> failwith "Could not decode bytes" + | Some expr -> return expr)) + >>=? fun (expression : Alpha_context.Script.expr) -> + let output = + match to_format with + | `Michelson -> + Micheline_printer.printable + Michelson_v1_primitives.string_of_prim + expression + |> Format.asprintf "%a" Micheline_printer.print_expr + | `JSON -> + Data_encoding.Json.( + construct Alpha_context.Script.expr_encoding expression + |> to_string) + | `Binary -> + Format.asprintf + "0x%s" + (Data_encoding.Binary.( + to_bytes_exn Alpha_context.Script.expr_encoding expression) + |> Hex.of_bytes |> Hex.show) + | `OCaml -> + Michelson_v1_printer.micheline_string_of_expression + ~zero_loc + expression + in + cctxt#message "%s" output >>= fun () -> return_unit); + command + ~desc: + "Conversion of Micheline expression from Micheline, JSON or binary to \ + Micheline, JSON, binary or OCaml" + (args2 zero_loc_switch data_type_arg) + (prefixes ["convert"; "data"] + @@ file_or_literal_param () @@ prefix "from" @@ convert_input_format_param + @@ prefix "to" @@ convert_output_format_param @@ stop) + (fun (zero_loc, data_ty) + (_, data_string) + from_format + to_format + (cctxt : Protocol_client_context.full) -> + let micheline_of_expr expr = + Micheline_printer.printable + Michelson_v1_primitives.string_of_prim + expr + |> Format.asprintf "%a" Micheline_printer.print_expr + in + let typecheck_parsed ~data ~ty = + Client_proto_programs.typecheck_data + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~data + ~ty + () + >>= function + | Error errs -> + failwith + "%a" + (Michelson_v1_error_reporter.report_errors + ~details:false + ~show_source:false + ?parsed:None) + errs + | Ok _gas -> return data.expanded + in + let typecheck_expr ~expr ~ty = + let data_string = micheline_of_expr expr in + parse_expr data_string >>=? fun data -> typecheck_parsed ~data ~ty + in + (match from_format with + | `Michelson -> ( + parse_expr data_string >>=? fun data -> + match data_ty with + | Some ty -> typecheck_parsed ~data ~ty + | None -> return data.expanded) + | `JSON -> ( + match Data_encoding.Json.from_string data_string with + | Error err -> cctxt#error "%s" err + | Ok json -> ( + return + @@ Data_encoding.Json.destruct + Alpha_context.Script.expr_encoding + json + >>=? fun expr -> + match data_ty with + | None -> return expr + | Some ty -> typecheck_expr ~expr ~ty)) + | `Binary -> ( + bytes_of_prefixed_string data_string >>=? fun bytes -> + match + Data_encoding.Binary.of_bytes_opt + Alpha_context.Script.expr_encoding + bytes + with + | None -> failwith "Could not decode bytes" + | Some expr -> ( + match data_ty with + | None -> return expr + | Some ty -> typecheck_expr ~expr ~ty))) + >>=? fun (expression : Alpha_context.Script.expr) -> + let output = + match to_format with + | `Michelson -> micheline_of_expr expression + | `JSON -> + Data_encoding.Json.( + construct Alpha_context.Script.expr_encoding expression + |> to_string) + | `Binary -> + Format.asprintf + "0x%s" + (Data_encoding.Binary.( + to_bytes_exn Alpha_context.Script.expr_encoding expression) + |> Hex.of_bytes |> Hex.show) + | `OCaml -> + Michelson_v1_printer.micheline_string_of_expression + ~zero_loc + expression + in + cctxt#message "%s" output >>= fun () -> return_unit); + command + ~group + ~desc:"Ask the node to run a TZIP-4 view." + (args4 + source_arg + payer_arg + run_gas_limit_arg + (unparsing_mode_arg ~default:"Readable")) + (prefixes ["run"; "tzip4"; "view"] + @@ param ~name:"entrypoint" ~desc:"the name of the view" string_parameter + @@ prefixes ["on"; "contract"] + @@ ContractAlias.destination_param + ~name:"contract" + ~desc:"viewed contract" + @@ prefixes ["with"; "input"] + @@ param ~name:"input" ~desc:"the input data" data_parameter + @@ stop) + (fun (source, payer, gas, unparsing_mode) + entrypoint + (_, contract) + input + cctxt -> + let source = Option.map snd source in + let payer = Option.map snd payer in + Client_proto_programs.run_view + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?gas + ~contract + ~entrypoint + ~input + ?source + ?payer + ~unparsing_mode + () + >>= fun res -> print_view_result cctxt res); + ] diff --git a/src/proto_011_PtHangzH/lib_client_commands/client_proto_programs_commands.mli b/src/proto_011_PtHangzH/lib_client_commands/client_proto_programs_commands.mli new file mode 100644 index 000000000000..6e352b98be7f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/client_proto_programs_commands.mli @@ -0,0 +1,26 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val commands : unit -> Protocol_client_context.full Clic.command list diff --git a/src/proto_011_PtHangzH/lib_client_commands/client_proto_stresstest_commands.ml b/src/proto_011_PtHangzH/lib_client_commands/client_proto_stresstest_commands.ml new file mode 100644 index 000000000000..8a3bb8ebbff0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/client_proto_stresstest_commands.ml @@ -0,0 +1,847 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +type transfer_strategy = + | Fixed_amount of {mutez : Tez.t} (** Amount to transfer *) + | Evaporation of {fraction : float} + (** Maximum fraction of current wealth to transfer. + Minimum amount is 1 mutez regardless of total wealth. *) + +type parameters = { + seed : int; + fresh_probability : float; + (** Per-transfer probability that the destination will be fresh *) + tps : float; (** Transaction per seconds target *) + strategy : transfer_strategy; + fee_mutez : Tez.t; (** fees for each transfer, in mutez *) + gas_limit : Gas.Arith.integral; (** gas limit per operation *) + storage_limit : Z.t; (** storage limit per operation *) + account_creation_storage : Z.t; + (** upper bound on bytes consumed when creating a tz1 account *) + total_transfers : int option; + (** total number of transfers to perform; unbounded if None *) + single_op_per_pkh_per_block : bool; + (** if true, a single operation will be injected by pkh by block to + improve the chance for the injected operations to be included in the + next block **) +} + +type source = { + pkh : public_key_hash; + pk : public_key; + sk : Signature.secret_key; +} + +type transfer = { + src : source; + dst : public_key_hash; + fee : Tez.t; + amount : Tez.t; + counter : Z.t option; + fresh_dst : bool; +} + +type state = { + current_head_on_start : Block_hash.t; + counters : (Block_hash.t * Z.t) Signature.Public_key_hash.Table.t; + mutable pool : source list; + mutable pool_size : int; + (* [Some l] if [single_op_per_pkh_per_block] is true *) + mutable shuffled_pool : source list option; + mutable last_block : Block_hash.t; + new_block_condition : unit Lwt_condition.t; + injected_operations : Operation_hash.t list Block_hash.Table.t; +} + +let verbose = ref false + +let debug = ref false + +let debug_msg msg = if !debug then msg () else Lwt.return_unit + +let default_parameters = + { + seed = 0x533D; + fresh_probability = 0.001; + tps = 5.0; + strategy = Fixed_amount {mutez = Tez.one}; + fee_mutez = Tez.of_mutez_exn 2_000L; + gas_limit = Gas.Arith.integral_of_int_exn 1_600; + (* [gas_limit] corresponds to a slight overapproximation of the + gas needed to inject an operation. It was obtained by simulating + the operation using the client. *) + storage_limit = Z.zero; + account_creation_storage = Z.of_int 300; + (* [account_creation_storage] corresponds to a slight overapproximation + of the storage consumed when allocating a new implicit account. + It was obtained by simulating the operation using the client. *) + total_transfers = None; + single_op_per_pkh_per_block = false; + } + +let source_encoding = + let open Data_encoding in + conv + (fun {pkh; pk; sk} -> (pkh, pk, sk)) + (fun (pkh, pk, sk) -> {pkh; pk; sk}) + (obj3 + (req "pkh" Signature.Public_key_hash.encoding) + (req "pk" Signature.Public_key.encoding) + (req "sk" Signature.Secret_key.encoding)) + +let source_list_encoding = + let open Data_encoding in + list source_encoding + +let injected_operations_encoding = + let open Data_encoding in + list + (obj2 + (req "block_hash_when_injected" Block_hash.encoding) + (req "operation_hashes" (list Operation_hash.encoding))) + +let parse_strategy s = + match String.split ~limit:1 ':' s with + | ["fixed"; parameter] -> ( + match int_of_string parameter with + | exception _ -> Error "invalid integer literal" + | mutez when mutez <= 0 -> Error "negative amount" + | mutez -> ( + match Tez.of_mutez (Int64.of_int mutez) with + | None -> Error "invalid mutez" + | Some mutez -> Ok (Fixed_amount {mutez}))) + | ["evaporation"; parameter] -> ( + match float_of_string parameter with + | exception _ -> Error "invalid float literal" + | fraction when fraction < 0.0 || fraction > 1.0 -> + Error "invalid evaporation rate" + | fraction -> Ok (Evaporation {fraction})) + | _ -> Error "invalid argument" + +let rec sample_from_pool state rng_state (cctxt : Protocol_client_context.full) + = + match state.shuffled_pool with + | None -> ( + let idx = Random.State.int rng_state state.pool_size in + match List.nth state.pool idx with + | None -> assert false + | Some src -> Lwt.return src) + | Some (source :: l) -> + state.shuffled_pool <- Some l ; + debug_msg (fun () -> + cctxt#message + "sample_transfer: %d unused sources for the block next to %a" + (List.length l) + Block_hash.pp + state.last_block) + >>= fun () -> Lwt.return source + | Some [] -> + cctxt#message + "all available sources have been used for block next to %a" + Block_hash.pp + state.last_block + >>= fun () -> + Lwt_condition.wait state.new_block_condition >>= fun () -> + sample_from_pool state rng_state cctxt + +let random_seed rng_state = + Bytes.init 32 (fun _ -> Char.chr (Random.State.int rng_state 256)) + +let generate_fresh pool rng_state = + let seed = random_seed rng_state in + let (pkh, pk, sk) = Signature.generate_key ~seed () in + let fresh = {pkh; pk; sk} in + pool.pool <- fresh :: pool.pool ; + pool.pool_size <- pool.pool_size + 1 ; + fresh + +(* [on_new_head cctxt f] calls [f head] each time there is a new head + received by the streamed RPC /monitor/heads/main *) +let on_new_head (cctxt : Protocol_client_context.full) f = + Shell_services.Monitor.heads cctxt `Main >>=? fun (heads_stream, stopper) -> + Lwt_stream.iter_s f heads_stream >>= fun () -> + stopper () ; + return_unit + +(* We perform rejection sampling of valid sources. + We could maintain a local cache of existing contracts with sufficient balance. *) +let rec sample_transfer (cctxt : Protocol_client_context.full) chain block + (parameters : parameters) (state : state) rng_state = + sample_from_pool state rng_state cctxt >>= fun src -> + Alpha_services.Contract.balance + cctxt + (chain, block) + (Contract.implicit_contract src.pkh) + >>=? fun tez -> + if Tez.(tez = zero) then + debug_msg (fun () -> + cctxt#message + "sample_transfer: invalid balance %a" + Signature.Public_key_hash.pp + src.pkh) + >>= fun () -> + (* Sampled source has zero balance: the transfer that created that + address was not included yet. Retry *) + sample_transfer cctxt chain block parameters state rng_state + else + let fresh = + Random.State.float rng_state 1.0 < parameters.fresh_probability + in + (if fresh then Lwt.return (generate_fresh state rng_state) + else sample_from_pool state rng_state cctxt) + >>= fun dest -> + let amount = + match parameters.strategy with + | Fixed_amount {mutez} -> mutez + | Evaporation {fraction} -> + let mutez = Int64.to_float (Tez.to_mutez tez) in + let max_fraction = Int64.of_float (mutez *. fraction) in + let amount = + if max_fraction = 0L then 1L + else max 1L (Random.State.int64 rng_state max_fraction) + in + Tez.of_mutez_exn amount + in + let fee = parameters.fee_mutez in + return {src; dst = dest.pkh; fee; amount; counter = None; fresh_dst = fresh} + +let inject_contents (cctxt : Protocol_client_context.full) chain branch sk + contents = + let bytes = + Data_encoding.Binary.to_bytes_exn + Operation.unsigned_encoding + ({branch}, Contents_list contents) + in + let signature = + Some (Signature.sign ~watermark:Signature.Generic_operation sk bytes) + in + let op : _ Operation.t = + {shell = {branch}; protocol_data = {contents; signature}} + in + let bytes = + Data_encoding.Binary.to_bytes_exn Operation.encoding (Operation.pack op) + in + Shell_services.Injection.operation cctxt ~chain bytes + +(* counter _must_ be set before calling this function *) +let manager_op_of_transfer parameters + {src; dst; fee; amount; counter; fresh_dst} = + let source = src.pkh in + let gas_limit = parameters.gas_limit in + let storage_limit = + if fresh_dst then + Z.add parameters.account_creation_storage parameters.storage_limit + else parameters.storage_limit + in + let operation = + let parameters = + let open Tezos_micheline in + Script.lazy_expr + @@ Micheline.strip_locations + (Prim (0, Michelson_v1_primitives.D_Unit, [], [])) + in + let entrypoint = "default" in + let destination = Contract.implicit_contract dst in + Transaction {amount; parameters; entrypoint; destination} + in + match counter with + | None -> assert false + | Some counter -> + Manager_operation + {source; fee; counter; operation; gas_limit; storage_limit} + +let cost_of_manager_operation = Gas.Arith.integral_of_int_exn 1_000 + +let inject_transfer (cctxt : Protocol_client_context.full) parameters state + rng_state chain block transfer = + Alpha_services.Contract.counter cctxt (chain, block) transfer.src.pkh + >>=? fun pcounter -> + Shell_services.Blocks.hash cctxt ~chain ~block () >>=? fun branch -> + (* If there is a new block refresh the fresh_pool *) + if not (Block_hash.equal branch state.last_block) then ( + state.last_block <- branch ; + if Option.is_some state.shuffled_pool then + state.shuffled_pool <- Some (List.shuffle ~rng_state state.pool)) ; + let freshest_counter = + match + Signature.Public_key_hash.Table.find state.counters transfer.src.pkh + with + | None -> + (* This is the first operation we inject for this pkh: the counter given + by the RPC _must_ be the freshest one. *) + pcounter + | Some (previous_branch, previous_counter) -> + if Block_hash.equal branch previous_branch then + (* We already injected an operation on top of this block: the one stored + locally is the freshest one. *) + previous_counter + else + (* It seems the block changed since we last injected an operation: + this invalidates the previously stored counter. We return the counter + given by the RPC. *) + pcounter + in + (Alpha_services.Contract.manager_key cctxt (chain, block) transfer.src.pkh + >>=? function + | None -> + let reveal_counter = Z.succ freshest_counter in + let transf_counter = Z.succ reveal_counter in + let reveal = + Manager_operation + { + source = transfer.src.pkh; + fee = Tez.zero; + counter = reveal_counter; + gas_limit = cost_of_manager_operation; + storage_limit = Z.zero; + operation = Reveal transfer.src.pk; + } + in + let manager_op = + manager_op_of_transfer + parameters + {transfer with counter = Some transf_counter} + in + let list = Cons (reveal, Single manager_op) in + Signature.Public_key_hash.Table.remove state.counters transfer.src.pkh ; + Signature.Public_key_hash.Table.add + state.counters + transfer.src.pkh + (branch, transf_counter) ; + (if !verbose then + cctxt#message + "injecting reveal+transfer from %a (counters=%a,%a) to %a" + Signature.Public_key_hash.pp + transfer.src.pkh + Z.pp_print + reveal_counter + Z.pp_print + transf_counter + Signature.Public_key_hash.pp + transfer.dst + else Lwt.return_unit) + >>= fun () -> + (* NB: regardless of our best efforts to keep track of counters, injection can fail with + "counter in the future" if a block switch happens in between the moment we + get the branch and the moment we inject, and the new block does not include + all the operations we injected. *) + inject_contents cctxt chain branch transfer.src.sk list + | Some _ -> + let transf_counter = Z.succ freshest_counter in + let manager_op = + manager_op_of_transfer + parameters + {transfer with counter = Some transf_counter} + in + let list = Single manager_op in + Signature.Public_key_hash.Table.remove state.counters transfer.src.pkh ; + Signature.Public_key_hash.Table.add + state.counters + transfer.src.pkh + (branch, transf_counter) ; + (if !verbose then + cctxt#message + "injecting transfer from %a (counter=%a) to %a" + Signature.Public_key_hash.pp + transfer.src.pkh + Z.pp_print + transf_counter + Signature.Public_key_hash.pp + transfer.dst + else Lwt.return_unit) + >>= fun () -> + (* See comment above. *) + inject_contents cctxt chain branch transfer.src.sk list) + >>= function + | Ok op_hash -> + debug_msg (fun () -> + cctxt#message + "inject_transfer: op injected %a" + Operation_hash.pp + op_hash) + >>= fun () -> + let ops = + Option.value + ~default:[] + (Block_hash.Table.find state.injected_operations branch) + in + Block_hash.Table.replace state.injected_operations branch (op_hash :: ops) ; + return_unit + | Error e -> + debug_msg (fun () -> + cctxt#message + "inject_transfer: error, op not injected: %a" + Error_monad.pp_print_error + e) + >>= fun () -> return_unit + +let save_injected_operations (cctxt : Protocol_client_context.full) state = + let json = + Data_encoding.Json.construct + injected_operations_encoding + (Block_hash.Table.fold + (fun k v acc -> (k, v) :: acc) + state.injected_operations + []) + in + let path = + Filename.temp_file "client-stresstest-injected_operations-" ".json" + in + cctxt#message "writing injected operations in file %s" path >>= fun () -> + Lwt_utils_unix.Json.write_file path json >>= function + | Error e -> + cctxt#message + "could not write injected operations json file: %a" + Error_monad.pp_print_error + e + | Ok _ -> Lwt.return_unit + +let stat_on_exit (cctxt : Protocol_client_context.full) state = + let ratio_injected_included_op () = + Shell_services.Blocks.hash cctxt () >>=? fun current_head_on_exit -> + let inter_cardinal s1 s2 = + Operation_hash.Set.cardinal + (Operation_hash.Set.inter + (Operation_hash.Set.of_list s1) + (Operation_hash.Set.of_list s2)) + in + let get_included_ops older_block = + let rec get_included_ops block acc_included_ops = + if block = older_block then return acc_included_ops + else + Shell_services.Chain.Blocks.Operation_hashes.operation_hashes_in_pass + cctxt + ~chain:`Main + ~block:(`Hash (block, 0)) + 3 + >>=? fun included_ops -> + Shell_services.Blocks.list + cctxt + ~chain:`Main + ~heads:[block] + ~length:2 + () + >>=? function + | [[current; predecessor]] when current = block -> + get_included_ops + predecessor + (List.append acc_included_ops included_ops) + | _ -> cctxt#error "Error while computing stats: invalid block list" + in + get_included_ops current_head_on_exit [] + in + let injected_ops = + Block_hash.Table.fold + (fun k l acc -> + (* The operations injected during the last block are ignored because + they should not be currently included. *) + if current_head_on_exit <> k then List.append acc l else acc) + state.injected_operations + [] + in + get_included_ops state.current_head_on_start >>=? fun included_ops -> + let included_ops_count = inter_cardinal injected_ops included_ops in + debug_msg (fun () -> + cctxt#message + "injected : %a\nincluded: %a" + (Format.pp_print_list Operation_hash.pp) + injected_ops + (Format.pp_print_list Operation_hash.pp) + included_ops) + >>= fun () -> + cctxt#message + "%d%% of the injected operations has been included (%d injected, %d \ + included)" + (included_ops_count * 100 / List.length injected_ops) + (List.length injected_ops) + included_ops_count + >>= fun () -> return_unit + in + ratio_injected_included_op () + +let launch (cctxt : Protocol_client_context.full) (parameters : parameters) + state rng_state save_pool_callback = + let injected = ref 0 in + let dt = 1. /. parameters.tps in + let terminated () = + match parameters.total_transfers with + | None -> false + | Some bound -> bound <= !injected + in + let rec loop () = + if terminated () then + save_pool_callback () >>= fun () -> + save_injected_operations cctxt state >>= fun () -> + stat_on_exit cctxt state + else + let start = Mtime_clock.elapsed () in + debug_msg (fun () -> cctxt#message "launch.loop: invoke sample_transfer") + >>= fun () -> + sample_transfer cctxt cctxt#chain cctxt#block parameters state rng_state + >>=? fun transfer -> + debug_msg (fun () -> cctxt#message "launch.loop: invoke inject_transfer") + >>= fun () -> + inject_transfer + cctxt + parameters + state + rng_state + cctxt#chain + cctxt#block + transfer + >>=? fun () -> + incr injected ; + let stop = Mtime_clock.elapsed () in + let elapsed = Mtime.Span.(to_s stop -. to_s start) in + let remaining = dt -. elapsed in + (if remaining <= 0.0 then + cctxt#warning + "warning: tps target could not be reached, consider using a lower \ + value for --tps" + else Lwt_unix.sleep remaining) + >>= loop + in + (* True, if and only if [single_op_per_pkh_per_block] is true. *) + if Option.is_some state.shuffled_pool then + dont_wait + (fun () -> + on_new_head cctxt (fun (block, _) -> + state.last_block <- block ; + state.shuffled_pool <- Some (List.shuffle ~rng_state state.pool) ; + Lwt_condition.broadcast state.new_block_condition () ; + Lwt.return_unit)) + (fun trace -> + ignore + (cctxt#error + "an error while getting the new head has been returned: %a" + Error_monad.pp_print_error + trace)) + (fun exn -> + ignore + (cctxt#error + "an exception while getting the new head has been raised: %s" + (Printexc.to_string exn))) ; + loop () + +let group = + Clic.{name = "stresstest"; title = "Commands for stress-testing the network"} + +type pool_source = + | From_string of {json : Ezjsonm.value} + | From_file of {path : string; json : Ezjsonm.value} + +let json_of_pool_source = function + | From_string {json} | From_file {json; _} -> json + +let json_file_or_text_parameter = + Clic.parameter (fun _ p -> + match String.split ~limit:1 ':' p with + | ["text"; text] -> return (From_string {json = Ezjsonm.from_string text}) + | ["file"; path] -> + Lwt_utils_unix.Json.read_file path >|=? fun json -> + From_file {path; json} + | _ -> ( + if Sys.file_exists p then + Lwt_utils_unix.Json.read_file p >|=? fun json -> + From_file {path = p; json} + else + try return (From_string {json = Ezjsonm.from_string p}) + with Ezjsonm.Parse_error _ -> + failwith "Neither an existing file nor valid JSON: '%s'" p)) + +let seed_arg = + let open Clic in + arg + ~long:"seed" + ~placeholder:"int" + ~doc:"random seed" + (parameter (fun (cctxt : Protocol_client_context.full) s -> + match int_of_string s with + | exception _ -> + cctxt#error + "While parsing --seed: could not convert argument to int" + | i -> return i)) + +let tps_arg = + let open Clic in + arg + ~long:"tps" + ~placeholder:"float" + ~doc:"transactions per seconds target" + (parameter (fun (cctxt : Protocol_client_context.full) s -> + match float_of_string s with + | exception _ -> + cctxt#error + "While parsing --tps: could not convert argument to float" + | f when f < 0.0 -> + cctxt#error "While parsing --tps: negative argument" + | f -> return f)) + +let fresh_probability_arg = + let open Clic in + arg + ~long:"fresh-probability" + ~placeholder:"float in [0;1]" + ~doc:"probability for a destination to be a fresh account" + (parameter (fun (cctxt : Protocol_client_context.full) s -> + match float_of_string s with + | exception _ -> + cctxt#error + "While parsing --fresh-probability: could not convert argument \ + to float" + | f when f < 0.0 || f > 1.0 -> + cctxt#error "While parsing --fresh-probability: invalid argument" + | f -> return f)) + +let strategy_arg = + let open Clic in + arg + ~long:"strategy" + ~placeholder:"fixed:mutez | evaporation:[0;1]" + ~doc:"wealth redistribution strategy" + (parameter (fun (cctxt : Protocol_client_context.full) s -> + match parse_strategy s with + | Error msg -> cctxt#error "While parsing --strategy: %s" msg + | Ok strategy -> return strategy)) + +let gas_limit_arg = + let open Clic in + let gas_limit_kind = + parameter (fun _ s -> + try + let v = Z.of_string s in + return (Gas.Arith.integral_exn v) + with _ -> failwith "invalid gas limit (must be a positive number)") + in + arg + ~long:"gas-limit" + ~short:'G' + ~placeholder:"amount" + ~doc: + (Format.asprintf + "Set the gas limit of the transaction instead of using the default \ + value of %a" + Gas.Arith.pp_integral + default_parameters.gas_limit) + gas_limit_kind + +let storage_limit_arg = + let open Clic in + let storage_limit_kind = + parameter (fun _ s -> + try + let v = Z.of_string s in + assert (Compare.Z.(v >= Z.zero)) ; + return v + with _ -> + failwith "invalid storage limit (must be a positive number of bytes)") + in + arg + ~long:"storage-limit" + ~short:'S' + ~placeholder:"amount" + ~doc: + (Format.asprintf + "Set the storage limit of the transaction instead of using the \ + default value of %a" + Z.pp_print + default_parameters.storage_limit) + storage_limit_kind + +let transfers_arg = + let open Clic in + arg + ~long:"transfers" + ~placeholder:"integer" + ~doc:"total number of transfers to perform, unbounded if not specified" + (parameter (fun (cctxt : Protocol_client_context.full) s -> + match int_of_string s with + | exception _ -> + cctxt#error "While parsing --transfers: invalid integer literal" + | i when i <= 0 -> + cctxt#error "While parsing --transfers: negative integer" + | i -> return i)) + +let single_op_per_pkh_per_block_arg = + Clic.switch + ~long:"single-op-per-pkh-per-block" + ~doc: + "ensure that the operations are not rejected by limiting the injection \ + to 1 operation per public_key_hash per block." + () + +let verbose_arg = + Clic.switch + ~long:"verbose" + ~doc:"Display detailed logs of the injected operations" + () + +let debug_arg = Clic.switch ~long:"debug" ~doc:"Display debug logs" () + +let set_option opt f x = Option.fold ~none:x ~some:(f x) opt + +let save_pool_callback (cctxt : Protocol_client_context.full) pool_source state + = + let json = Data_encoding.Json.construct source_list_encoding state.pool in + let catch_write_error = function + | Error e -> + cctxt#message + "could not write back json file: %a" + Error_monad.pp_print_error + e + | Ok () -> Lwt.return_unit + in + match pool_source with + | From_string _ -> + (* If the initial pool was given directly as json, save pool to + a temp file. *) + let path = Filename.temp_file "client-stresstest-pool-" ".json" in + cctxt#message "writing back address pool in file %s" path >>= fun () -> + Lwt_utils_unix.Json.write_file path json >>= catch_write_error + | From_file {path; _} -> + (* If the pool specification was a json file, save pool to + the same file. *) + cctxt#message "writing back address pool in file %s" path >>= fun () -> + Lwt_utils_unix.Json.write_file path json >>= catch_write_error + +let generate_random_transactions = + let open Clic in + command + ~group + ~desc:"Generate random transactions" + (args11 + seed_arg + tps_arg + fresh_probability_arg + strategy_arg + Client_proto_args.fee_arg + gas_limit_arg + storage_limit_arg + transfers_arg + single_op_per_pkh_per_block_arg + verbose_arg + debug_arg) + (prefixes ["stresstest"; "transfer"; "using"] + @@ param + ~name:"sources.json" + ~desc: + "List of accounts from which to perform transfers in JSON format. \ + The input JSON must be an array of objects of the form \ + '[{\"pkh\":pkh;\"pk\":pk;\"sk\":sk}; ...]' with the pkh, pk and sk \ + encoded in B58 form." + json_file_or_text_parameter + @@ stop) + (fun ( seed, + tps, + freshp, + strat, + fee, + gas_limit, + storage_limit, + transfers, + single_op_per_pkh_per_block, + verbose_flag, + debug_flag ) + sources_json + (cctxt : Protocol_client_context.full) -> + verbose := verbose_flag ; + debug := debug_flag ; + let parameters = + default_parameters + |> set_option seed (fun parameter seed -> {parameter with seed}) + |> set_option tps (fun parameter tps -> {parameter with tps}) + |> set_option freshp (fun parameter fresh_probability -> + {parameter with fresh_probability}) + |> set_option strat (fun parameter strategy -> + {parameter with strategy}) + |> set_option fee (fun parameter fee_mutez -> + {parameter with fee_mutez}) + |> set_option gas_limit (fun parameter gas_limit -> + {parameter with gas_limit}) + |> set_option storage_limit (fun parameter storage_limit -> + {parameter with storage_limit}) + |> set_option transfers (fun parameter transfers -> + {parameter with total_transfers = Some transfers}) + |> fun parameter -> {parameter with single_op_per_pkh_per_block} + in + match + Data_encoding.Json.destruct + source_list_encoding + (json_of_pool_source sources_json) + with + | exception _ -> cctxt#error "Could not decode list of sources" + | [] -> cctxt#error "It is required to provide sources" + | sources -> + let counters = Signature.Public_key_hash.Table.create 1023 in + let rng_state = Random.State.make [|parameters.seed|] in + Shell_services.Blocks.hash cctxt () >>=? fun current_head_on_start -> + let state = + { + current_head_on_start; + counters; + pool = sources; + pool_size = List.length sources; + shuffled_pool = + (if parameters.single_op_per_pkh_per_block then + Some (List.shuffle ~rng_state sources) + else None); + last_block = current_head_on_start; + new_block_condition = Lwt_condition.create (); + injected_operations = Block_hash.Table.create 1023; + } + in + let exit_callback_id = + Lwt_exit.register_clean_up_callback ~loc:__LOC__ (fun _retcode -> + stat_on_exit cctxt state >>= function + | Ok () -> Lwt.return_unit + | Error e -> + cctxt#message "Error: %a" Error_monad.pp_print_error e) + in + let save_pool () = save_pool_callback cctxt sources_json state in + (* Register a callback for saving the pool when the tool is interrupted + through ctrl-c *) + let exit_callback_id = + Lwt_exit.register_clean_up_callback + ~loc:__LOC__ + ~after:[exit_callback_id] + (fun _retcode -> save_pool ()) + in + let save_injected_operations () = + save_injected_operations cctxt state + in + ignore + (Lwt_exit.register_clean_up_callback + ~loc:__LOC__ + ~after:[exit_callback_id] + (fun _retcode -> save_injected_operations ())) ; + launch cctxt parameters state rng_state save_pool) + +let commands network () = + match network with + | Some `Mainnet -> [] + | Some `Testnet | None -> [generate_random_transactions] diff --git a/src/proto_011_PtHangzH/lib_client_commands/client_proto_utils_commands.ml b/src/proto_011_PtHangzH/lib_client_commands/client_proto_utils_commands.ml new file mode 100644 index 000000000000..d155d1a224d2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/client_proto_utils_commands.ml @@ -0,0 +1,105 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Client_proto_utils + +let group = {Clic.name = "utilities"; title = "Utility Commands"} + +let commands () = + let open Clic in + let string_param ~name ~desc = + param ~name ~desc Client_proto_args.string_parameter + in + let block_arg = + default_arg + ~long:"branch" + ~short:'b' + ~placeholder:"hash|tag" + ~doc: + "Block hash used to create the no-op operation to sign (possible tags \ + are 'head' and 'genesis'). Defaults to 'genesis'. Note that the the \ + genesis block hash is network-dependent." + ~default:(Block_services.to_string `Genesis) + (Client_config.block_parameter ()) + in + [ + command + ~group + ~desc: + "Sign a message and display it using the failing_noop operation. This \ + operation is not executable in the protocol. Please note that \ + signing/checking an arbitrary message in itself is not sufficient to \ + verify a key ownership" + (args1 block_arg) + (prefixes ["sign"; "message"] + @@ string_param ~name:"message" ~desc:"message to sign" + @@ prefixes ["for"] + @@ Client_keys.Secret_key.source_param + ~name:"src" + ~desc:"name of the signer contract" + @@ stop) + (fun block_head message src_sk cctxt -> + Shell_services.Blocks.hash cctxt ~chain:cctxt#chain ~block:block_head () + >>=? fun block -> + sign_message cctxt ~src_sk ~block ~message >>=? fun signature -> + cctxt#message "Signature: %a" Signature.pp signature >>= fun () -> + return_unit); + command + ~group + ~desc: + "Check the signature of an arbitrary message using the failing_noop \ + operation. Please note that signing/checking an arbitrary message in \ + itself is not sufficient to verify a key ownership." + (args2 + block_arg + (switch ~doc:"Use only exit codes" ~short:'q' ~long:"quiet" ())) + (prefixes ["check"; "that"; "message"] + @@ string_param ~name:"message" ~desc:"signed message" + @@ prefixes ["was"; "signed"; "by"] + @@ Client_keys.Public_key.alias_param + ~name:"signer" + ~desc:"name of the signer contract" + @@ prefixes ["to"; "produce"] + @@ param + ~name:"signature" + ~desc:"the signature to check" + Client_proto_args.signature_parameter + @@ stop) + (fun (block_head, quiet) + message + (_, (key_locator, _)) + signature + (cctxt : #Protocol_client_context.full) -> + Shell_services.Blocks.hash cctxt ~chain:cctxt#chain ~block:block_head () + >>=? fun block -> + check_message cctxt ~key_locator ~block ~quiet ~message ~signature + >>=? function + | false -> cctxt#error "invalid signature" + | true -> + if quiet then return_unit + else + cctxt#message "Signature check successful" >>= fun () -> + return_unit); + ] diff --git a/src/proto_011_PtHangzH/lib_client_commands/client_proto_utils_commands.mli b/src/proto_011_PtHangzH/lib_client_commands/client_proto_utils_commands.mli new file mode 100644 index 000000000000..0d38cde9a251 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/client_proto_utils_commands.mli @@ -0,0 +1,26 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val commands : unit -> Protocol_client_context.full Clic.command list diff --git a/src/proto_011_PtHangzH/lib_client_commands/dune b/src/proto_011_PtHangzH/lib_client_commands/dune new file mode 100644 index 000000000000..6a16b5e42505 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/dune @@ -0,0 +1,57 @@ +(library + (name tezos_client_011_PtHangzH_commands) + (instrumentation (backend bisect_ppx)) + (public_name tezos-client-011-PtHangzH-commands) + (libraries tezos-base + tezos-stdlib-unix + tezos-protocol-011-PtHangzH + tezos-protocol-environment + tezos-shell-services + tezos-mockup + tezos-mockup-registration + tezos-mockup-commands + tezos-client-base-unix + tezos-client-011-PtHangzH + tezos-client-commands + tezos-rpc + tezos-protocol-plugin-011-PtHangzH) + (library_flags (:standard -linkall)) + (modules (:standard \ alpha_commands_registration)) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_protocol_011_PtHangzH + -open Tezos_stdlib_unix + -open Tezos_shell_services + -open Tezos_client_base + -open Tezos_client_011_PtHangzH + -open Tezos_client_commands + -open Tezos_rpc + -open Tezos_client_base_unix + -open Tezos_protocol_plugin_011_PtHangzH))) + +(library + (name tezos_client_011_PtHangzH_commands_registration) + (instrumentation (backend bisect_ppx)) + (public_name tezos-client-011-PtHangzH-commands-registration) + (libraries tezos-base + tezos-protocol-011-PtHangzH + tezos-protocol-environment + tezos-shell-services + tezos-client-base + tezos-client-011-PtHangzH + tezos-client-commands + tezos-client-011-PtHangzH-commands + tezos-client-sapling-011-PtHangzH + tezos-rpc + tezos-protocol-plugin-011-PtHangzH) + (library_flags (:standard -linkall)) + (modules alpha_commands_registration) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_protocol_011_PtHangzH + -open Tezos_shell_services + -open Tezos_client_base + -open Tezos_client_011_PtHangzH + -open Tezos_client_commands + -open Tezos_client_011_PtHangzH_commands + -open Tezos_client_sapling_011_PtHangzH + -open Tezos_rpc + -open Tezos_protocol_plugin_011_PtHangzH))) diff --git a/src/proto_011_PtHangzH/lib_client_commands/dune-project b/src/proto_011_PtHangzH/lib_client_commands/dune-project new file mode 100644 index 000000000000..7cc9e6db1fec --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(formatting (enabled_for ocaml)) +(name tezos-client-alpha-commands) diff --git a/src/proto_011_PtHangzH/lib_client_commands/tezos-client-011-PtHangzH-commands-registration.opam b/src/proto_011_PtHangzH/lib_client_commands/tezos-client-011-PtHangzH-commands-registration.opam new file mode 100644 index 000000000000..f6a627d96934 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/tezos-client-011-PtHangzH-commands-registration.opam @@ -0,0 +1,24 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-base" + "tezos-protocol-environment" + "tezos-protocol-011-PtHangzH" + "tezos-shell-services" + "tezos-client-base" + "tezos-client-011-PtHangzH" + "tezos-client-011-PtHangzH-commands" + "tezos-client-sapling-011-PtHangzH" + "tezos-client-commands" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: protocol-specific commands for `tezos-client`" diff --git a/src/proto_011_PtHangzH/lib_client_commands/tezos-client-011-PtHangzH-commands.opam b/src/proto_011_PtHangzH/lib_client_commands/tezos-client-011-PtHangzH-commands.opam new file mode 100644 index 000000000000..3ccd431e81bf --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_commands/tezos-client-011-PtHangzH-commands.opam @@ -0,0 +1,22 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-base" + "tezos-protocol-environment" + "tezos-protocol-011-PtHangzH" + "tezos-shell-services" + "tezos-client-base-unix" + "tezos-client-011-PtHangzH" + "tezos-client-commands" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: protocol-specific commands for `tezos-client`" diff --git a/src/proto_011_PtHangzH/lib_client_sapling/.ocamlformat b/src/proto_011_PtHangzH/lib_client_sapling/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_sapling/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_client_sapling/client_sapling_commands.ml b/src/proto_011_PtHangzH/lib_client_sapling/client_sapling_commands.ml new file mode 100644 index 000000000000..cfe8e01e77a5 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_sapling/client_sapling_commands.ml @@ -0,0 +1,796 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Clic +open Client_keys +open Tezos_sapling.Core.Client + +let json_switch = switch ~long:"json" ~doc:"Use JSON format" () + +let save_json_to_file json file = + let output_channel = open_out_bin file in + let ppf = Format.formatter_of_out_channel output_channel in + Data_encoding.Json.pp ppf json ; + Format.pp_print_flush ppf () ; + close_out output_channel + +let group = + { + Clic.name = "sapling"; + title = "Commands for working with Sapling transactions"; + } + +let keys_of_implicit_account cctxt source = + match Protocol.Alpha_context.Contract.is_implicit source with + | None -> assert false + | Some src -> + Client_keys.get_key cctxt src >>=? fun (_, pk, sk) -> return (src, pk, sk) + +let viewing_key_of_string s = + let exception Unknown_sapling_address in + let encoding = Viewing_key.address_b58check_encoding in + WithExceptions.Option.to_exn + ~none:Unknown_sapling_address + (Base58.simple_decode encoding s) + +(** All signatures are done with an anti-replay string. + In Tezos' protocol this string is set to be chain_id + KT1. **) +let anti_replay cctxt contract = + Tezos_shell_services.Chain_services.chain_id cctxt ~chain:cctxt#chain () + >>=? fun chain_id -> + let address = Protocol.Alpha_context.Contract.to_b58check contract in + let chain_id = Chain_id.to_b58check chain_id in + return (address ^ chain_id) + +let do_unshield cctxt contract src_name stez dst = + anti_replay cctxt contract >>=? fun anti_replay -> + Wallet.new_address cctxt src_name None >>=? fun (src, _, backdst) -> + Context.Client_state.sync_and_scan cctxt contract >>=? fun contract_state -> + Lwt.return + @@ Context.unshield ~src ~dst ~backdst stez contract_state anti_replay + +let do_shield cctxt ?message contract utez dst = + anti_replay cctxt contract >>=? fun anti_replay -> + Context.Client_state.sync_and_scan cctxt contract >>=? fun contract_state -> + let dst = viewing_key_of_string dst in + Context.shield cctxt ~dst ?message utez contract_state anti_replay + +let do_sapling_transfer cctxt ?message contract src_name amount dst = + anti_replay cctxt contract >>=? fun anti_replay -> + Wallet.new_address cctxt src_name None >>=? fun (src, _, backdst) -> + Context.Client_state.sync_and_scan cctxt contract >>=? fun contract_state -> + let dst = viewing_key_of_string dst in + Context.transfer + cctxt + ~src + ~dst + ~backdst + ?message + amount + contract_state + anti_replay + +let message_arg = + let open Clic in + arg + ~long:"message" + ~placeholder:"" + ~doc:"Message for Sapling transaction" + (parameter (fun _ x -> return @@ Bytes.of_string x)) + +let memo_size_arg = + let open Clic in + arg + ~long:"memo-size" + ~placeholder:"memo-size" + ~doc:"Expected length for message of Sapling transaction" + (parameter (fun _ s -> + match + let i = int_of_string s in + assert (i >= 0 && i <= 65535) ; + i + with + | i -> return i + | exception _ -> + failwith "invalid memo-size (must be between 0 and 65535)")) + +let shield_cmd = + let open Client_proto_args in + let open Client_proto_context_commands in + let open Protocol.Alpha_context in + let open Client_proto_contracts in + command + ~group + ~desc:"Shield tokens from an implicit account to a Sapling address." + (args14 + fee_arg + dry_run_switch + verbose_signing_switch + gas_limit_arg + storage_limit_arg + counter_arg + no_print_source_flag + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg + message_arg) + (prefixes ["sapling"; "shield"] + @@ tez_param + ~name:"qty" + ~desc:"Amount taken from transparent wallet of source." + @@ prefix "from" + @@ ContractAlias.destination_param + ~name:"src-tz" + ~desc:"Transparent source account." + @@ prefix "to" + @@ Clic.string ~name:"dst-sap" ~desc:"Sapling address of destination." + @@ prefix "using" + @@ ContractAlias.destination_param + ~name:"sapling contract" + ~desc:"Smart contract to submit this transaction to." + @@ stop) + (fun ( fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap, + message ) + amount + (_, source) + sapling_dst + (_contract_name, contract_dst) + cctxt -> + keys_of_implicit_account cctxt source >>=? fun (pkh, src_pk, src_sk) -> + let open Context in + cctxt#warning + "Shielding %a from %a to %s@ entails a loss of privacy@." + Tez.pp + amount + Contract.pp + source + sapling_dst + >>= fun () -> + do_shield cctxt ?message contract_dst amount sapling_dst + >>=? fun sapling_input -> + let arg = Shielded_tez_contract_input.as_arg sapling_input in + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Client_proto_context.transfer + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~fee_parameter + ~amount + ~src_pk + ~src_sk + ~destination:contract_dst + ~source:pkh + ~arg + ?confirmations:cctxt#confirmations + ?fee + ~dry_run + ~verbose_signing + ?gas_limit + ?storage_limit + ?counter + () + >>= fun errors -> + report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + errors + >>= function + | None -> return_unit + | Some (_res, _contracts) -> return_unit) + +let unshield_cmd = + let open Client_proto_args in + let open Client_proto_context_commands in + let open Protocol.Alpha_context in + let open Client_proto_contracts in + command + ~group + ~desc:"Unshield tokens from a Sapling address to an implicit account." + (args13 + fee_arg + dry_run_switch + verbose_signing_switch + gas_limit_arg + storage_limit_arg + counter_arg + no_print_source_flag + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg) + (prefixes ["sapling"; "unshield"] + @@ tez_param + ~name:"qty" + ~desc:"Amount taken from shielded wallet of source." + @@ prefix "from" + @@ Sapling_key.alias_param + ~name:"src-sap" + ~desc:"Sapling account of source." + @@ prefix "to" + @@ ContractAlias.destination_param + ~name:"dst-tz" + ~desc:"Transparent destination account." + @@ prefix "using" + @@ ContractAlias.destination_param + ~name:"sapling contract" + ~desc:"Smart contract to submit this transaction to." + @@ stop) + (fun ( fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap ) + amount + (name, _sapling_uri) + (_, tz_dst) + (_contract_name, contract_dst) + cctxt -> + let open Context in + let stez = Shielded_tez.of_tez amount in + cctxt#warning + "Unshielding %a from %s to %a@ entails a loss of privacy@." + Shielded_tez.pp + stez + name + Contract.pp + tz_dst + >>= fun () -> + keys_of_implicit_account cctxt tz_dst >>=? fun (source, src_pk, src_sk) -> + do_unshield cctxt contract_dst name stez source >>=? fun sapling_input -> + let arg = Shielded_tez_contract_input.as_arg sapling_input in + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Client_proto_context.transfer + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~fee_parameter + ~amount:Tez.zero + ~src_pk + ~src_sk + ~destination:contract_dst + ~source + ~arg + ?confirmations:cctxt#confirmations + ?fee + ~dry_run + ~verbose_signing + ?gas_limit + ?storage_limit + ?counter + () + >>= fun errors -> + report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + errors + >>= function + | None -> return_unit + | Some (_res, _contracts) -> return_unit) + +(* Default name for Sapling transaction file *) +let sapling_transaction_file = "sapling_transaction" + +let file_arg default_filename = + let open Clic in + arg + ~long:"file" + ~placeholder:default_filename + ~doc:"file name" + (parameter (fun _ x -> return x)) + +(** Shielded transaction are first forged and printed in a file. + Then they are submitted with the next command. **) +let forge_shielded_cmd = + let open Client_proto_args in + let open Client_proto_context_commands in + let open Client_proto_contracts in + command + ~group + ~desc:"Forge a sapling transaction and save it to a file." + (args16 + fee_arg + dry_run_switch + verbose_signing_switch + gas_limit_arg + storage_limit_arg + counter_arg + no_print_source_flag + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg + message_arg + (file_arg sapling_transaction_file) + json_switch) + (prefixes ["sapling"; "forge"; "transaction"] + @@ tez_param + ~name:"qty" + ~desc:"Amount taken from shielded wallet of source." + @@ prefix "from" + @@ Sapling_key.alias_param + ~name:"src-sap" + ~desc:"Sapling account of source." + @@ prefix "to" + @@ Clic.string ~name:"dst-sap" ~desc:"Sapling address of destination." + @@ prefix "using" + @@ ContractAlias.destination_param + ~name:"sapling contract" + ~desc:"Smart contract to submit this transaction to." + @@ stop) + (fun ( _fee, + _dry_run, + _verbose_signing, + _gas_limit, + _storage_limit, + _counter, + _no_print_source, + _minimal_fees, + _minimal_nanotez_per_byte, + _minimal_nanotez_per_gas_unit, + _force_low_fee, + _fee_cap, + _burn_cap, + message, + file, + use_json_format ) + amount + (name, _sapling_uri) + destination + (_contract_name, contract_dst) + cctxt -> + let open Context in + let stez = Shielded_tez.of_tez amount in + do_sapling_transfer cctxt ?message contract_dst name stez destination + >>=? fun transaction -> + let file = Option.value ~default:sapling_transaction_file file in + cctxt#message "Writing transaction to %s@." file >>= fun () -> + (if use_json_format then + save_json_to_file + (Data_encoding.Json.construct UTXO.transaction_encoding transaction) + file + else + let bytes = + Hex.of_bytes + (Data_encoding.Binary.to_bytes_exn + UTXO.transaction_encoding + transaction) + in + let file = open_out_bin file in + Printf.fprintf file "0x%s" (Hex.show bytes) ; + close_out file) ; + return_unit) + +let submit_shielded_cmd = + let open Client_proto_context_commands in + let open Client_proto_args in + let open Client_proto_contracts in + command + ~group + ~desc:"Submit a forged sapling transaction." + (args14 + fee_arg + dry_run_switch + verbose_signing_switch + gas_limit_arg + storage_limit_arg + counter_arg + no_print_source_flag + minimal_fees_arg + minimal_nanotez_per_byte_arg + minimal_nanotez_per_gas_unit_arg + force_low_fee_arg + fee_cap_arg + burn_cap_arg + json_switch) + (prefixes ["sapling"; "submit"] + (* TODO: Add a dedicated abstracted Clic element to parse filenames, + potentially using Sys.file_exists *) + @@ Clic.string ~name:"file" ~desc:"Filename of the forged transaction." + @@ prefix "from" + @@ ContractAlias.destination_param + ~name:"alias-tz" + ~desc:"Transparent account paying the fees." + @@ prefix "using" + @@ ContractAlias.destination_param + ~name:"sapling contract" + ~desc:"Smart contract to submit this transaction to." + @@ stop) + (fun ( fee, + dry_run, + verbose_signing, + gas_limit, + storage_limit, + counter, + no_print_source, + minimal_fees, + minimal_nanotez_per_byte, + minimal_nanotez_per_gas_unit, + force_low_fee, + fee_cap, + burn_cap, + use_json_format ) + filename + (_, source) + (contract_name, destination) + (cctxt : Protocol_client_context.full) -> + cctxt#message + "Reading forge transaction from file %s -- sending it to %s@." + filename + contract_name + >>= fun () -> + let open Context in + (if use_json_format then + Lwt_utils_unix.Json.read_file filename >>=? fun json -> + return @@ Data_encoding.Json.destruct UTXO.transaction_encoding json + else + Lwt_utils_unix.read_file filename >>= fun hex -> + let hex = + (* remove 0x *) + String.sub hex 2 (String.length hex - 2) + in + return + @@ Data_encoding.Binary.of_bytes_exn + UTXO.transaction_encoding + Hex.(to_bytes (`Hex hex))) + >>=? fun transaction -> + return Shielded_tez_contract_input.(as_arg (create transaction)) + >>=? fun contract_input -> + let chain = cctxt#chain and block = cctxt#block in + keys_of_implicit_account cctxt source >>=? fun (source, src_pk, src_sk) -> + let open Protocol.Alpha_context in + let fee_parameter = + { + Injection.minimal_fees; + minimal_nanotez_per_byte; + minimal_nanotez_per_gas_unit; + force_low_fee; + fee_cap; + burn_cap; + } + in + Client_proto_context.transfer + cctxt + ~chain + ~block + ~fee_parameter + ~amount:Tez.zero + ~src_pk + ~src_sk + ~destination + ~source + ~arg:contract_input + ?confirmations:cctxt#confirmations + ?fee + ~dry_run + ~verbose_signing + ?gas_limit + ?storage_limit + ?counter + () + >>= fun errors -> + report_michelson_errors + ~no_print_source + ~msg:"transfer simulation failed" + cctxt + errors + >>= function + | None -> return_unit + | Some (_res, _contracts) -> return_unit) + +let for_contract_arg = + Client_proto_contracts.ContractAlias.destination_arg + ~name:"for-contract" + ~doc:"name of the contract to associate new key with" + () + +let unencrypted_switch () = + Clic.switch + ~long:"unencrypted" + ~doc:"Do not encrypt the key on-disk (for testing and debugging)." + () + +let generate_key_cmd = + command + ~group + ~desc:"Generate a new sapling key." + (args2 (Sapling_key.force_switch ()) (unencrypted_switch ())) + (prefixes ["sapling"; "gen"; "key"] @@ Sapling_key.fresh_alias_param @@ stop) + (fun (force, unencrypted) name (cctxt : Protocol_client_context.full) -> + Sapling_key.of_fresh cctxt force name >>=? fun name -> + let mnemonic = Wallet.Mnemonic.new_random in + cctxt#message + "It is important to save this mnemonic in a secure place:@\n\ + @\n\ + %a@\n\ + @\n\ + The mnemonic can be used to recover your spending key.@." + Wallet.Mnemonic.words_pp + (Bip39.to_words mnemonic) + >>= fun () -> + Wallet.register cctxt ~force ~unencrypted mnemonic name >>=? fun _vk -> + return_unit) + +let use_key_for_contract_cmd = + command + ~group + ~desc:"Use a sapling key for a contract." + (args1 memo_size_arg) + (prefixes ["sapling"; "use"; "key"] + @@ Sapling_key.alias_param + ~name:"sapling-key" + ~desc:"Sapling key to use for the contract." + @@ prefixes ["for"; "contract"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"contract" + ~desc:"Contract the key will be used on." + @@ stop) + (fun default_memo_size + (name, _sapling_uri) + (_contract_name, contract) + (cctxt : Protocol_client_context.full) -> + Wallet.find_vk cctxt name >>=? fun vk -> + Context.Client_state.register + cctxt + ~default_memo_size + ~force:false + contract + vk) + +let import_key_cmd = + command + ~group + ~desc:"Restore a sapling key from mnemonic." + (args3 + (Sapling_key.force_switch ()) + (unencrypted_switch ()) + (Clic.arg + ~long:"mnemonic" + ~placeholder:"mnemonic" + ~doc:"Mnemonic as an option, only used for testing and debugging." + Client_proto_args.string_parameter)) + (prefixes ["sapling"; "import"; "key"] + @@ Sapling_key.fresh_alias_param @@ stop) + (fun (force, unencrypted, mnemonic_opt) + fresh_name + (cctxt : Protocol_client_context.full) -> + (match mnemonic_opt with + | None -> + let rec loop_words (acc : string list) i = + if i > 23 then return (List.rev acc) + else + cctxt#prompt_password "Enter word %d: " i >>=? fun word_raw -> + let word = Bytes.to_string word_raw in + match Bip39.index_of_word word with + | None -> loop_words acc i + | Some _ -> loop_words (word :: acc) (succ i) + in + loop_words [] 0 + | Some mnemonic -> return (String.split_on_char ' ' mnemonic)) + >>=? fun words -> + match Bip39.of_words words with + | None -> failwith "Not a valid mnemonic" + | Some mnemonic -> + Sapling_key.of_fresh cctxt force fresh_name >>=? fun name -> + Wallet.register cctxt ~force ~unencrypted mnemonic name >>=? fun _ -> + return_unit) + +let commands () = + let child_index_param = + Clic.param + ~name:"child-index" + ~desc:"Index of the child to derive." + Client_proto_args.int_parameter + in + let index_arg = + Clic.arg + ~doc:"index of the address to generate" + ~long:"address-index" + ~placeholder:"idx" + Client_proto_args.int_parameter + in + [ + generate_key_cmd; + use_key_for_contract_cmd; + import_key_cmd; + command + ~group + ~desc:"Derive a key from an existing one using zip32." + (args4 + (Sapling_key.force_switch ()) + for_contract_arg + (unencrypted_switch ()) + memo_size_arg) + (prefixes ["sapling"; "derive"; "key"] + @@ Sapling_key.fresh_alias_param @@ prefix "from" + @@ Sapling_key.alias_param + @@ prefixes ["at"; "index"] + @@ child_index_param @@ stop) + (fun (force, contract_opt, unencrypted, default_memo_size) + fresh_name + (existing_name, _existing_uri) + child_index + (cctxt : Protocol_client_context.full) -> + Sapling_key.of_fresh cctxt force fresh_name >>=? fun new_name -> + Wallet.derive + cctxt + ~force + ~unencrypted + existing_name + new_name + child_index + >>=? fun (path, vk) -> + cctxt#message + "Derived new key %s from %s with path %s@." + new_name + existing_name + path + >>= fun () -> + (* TODO must pass contract address for now *) + let (_, contract) = + WithExceptions.Option.get ~loc:__LOC__ contract_opt + in + Context.Client_state.register + cctxt + ~default_memo_size + ~force + contract + vk); + command + ~group + ~desc:"Generate an address for a key referenced by alias." + (args1 index_arg) + (prefixes ["sapling"; "gen"; "address"] @@ Sapling_key.alias_param @@ stop) + (fun index_opt (name, _sapling_uri) (cctxt : Protocol_client_context.full) -> + Wallet.new_address cctxt name index_opt + >>=? fun (_, corrected_index, address) -> + let address_b58 = + Base58.simple_encode Viewing_key.address_b58check_encoding address + in + cctxt#message + "Generated address:@.%s@.at index %Ld" + address_b58 + (Viewing_key.index_to_int64 corrected_index) + >>= fun () -> return_unit); + command + ~group + ~desc:"Save a sapling viewing key in a JSON file." + no_options + (prefixes ["sapling"; "export"; "key"] + @@ Sapling_key.alias_param @@ prefix "in" + @@ Clic.param + ~name:"file" + ~desc:"Filename." + Client_proto_args.string_parameter + @@ stop) + (fun () (name, _sapling_uri) file (cctxt : Protocol_client_context.full) -> + Wallet.export_vk cctxt name >>=? fun vk_json -> + return (save_json_to_file vk_json file)); + command + ~group + ~desc:"Get balance associated with given sapling key and contract" + (args1 + (Clic.switch + ~doc:"Print the collection of non-spent inputs." + ~short:'v' + ~long:"verbose" + ())) + (prefixes ["sapling"; "get"; "balance"; "for"] + @@ Sapling_key.alias_param + ~name:"sapling-key" + ~desc:"Sapling key we get balance for." + @@ prefixes ["in"; "contract"] + @@ Client_proto_contracts.ContractAlias.destination_param + ~name:"contract" + ~desc:"Contract we get balance from." + @@ stop) + (fun verbose + (name, _sapling_uri) + (_contract_name, contract) + (cctxt : Protocol_client_context.full) -> + Wallet.find_vk cctxt name >>= function + | Error _ -> cctxt#error "Account %s not found" name + | Ok vk -> ( + Context.Client_state.sync_and_scan cctxt contract + >>=? fun contract_state -> + Context.Contract_state.find_account vk contract_state |> function + | None -> cctxt#error "Account %s not found" name + | Some account -> + (if verbose then + cctxt#answer + "@[Received Sapling transactions for %s@,@[%a@]@]" + name + Context.Account.pp_unspent + account + else Lwt.return_unit) + >>= fun () -> + cctxt#answer + "Total Sapling funds %a%s" + Context.Shielded_tez.pp + (Context.Account.balance account) + Client_proto_args.tez_sym + >>= fun () -> return_unit)); + command + ~group + ~desc:"List sapling keys." + no_options + (fixed ["sapling"; "list"; "keys"]) + (fun () (cctxt : Protocol_client_context.full) -> + Sapling_key.load cctxt >>=? fun l -> + List.iter_s + (fun (s, _) -> cctxt#message "%s" s) + (List.sort (fun (s1, _) (s2, _) -> String.compare s1 s2) l) + >>= fun () -> return_unit); + shield_cmd; + unshield_cmd; + forge_shielded_cmd; + submit_shielded_cmd; + ] diff --git a/src/proto_011_PtHangzH/lib_client_sapling/client_sapling_commands.mli b/src/proto_011_PtHangzH/lib_client_sapling/client_sapling_commands.mli new file mode 100644 index 000000000000..769a4eac58e9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_sapling/client_sapling_commands.mli @@ -0,0 +1,23 @@ +(* The MIT License (MIT) + * + * Copyright (c) 2019-2020 Nomadic Labs + * + * 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. *) + +val commands : unit -> Protocol_client_context.full Clic.command list diff --git a/src/proto_011_PtHangzH/lib_client_sapling/context.ml b/src/proto_011_PtHangzH/lib_client_sapling/context.ml new file mode 100644 index 000000000000..e12003adde36 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_sapling/context.ml @@ -0,0 +1,553 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Tezos_sapling.Core.Client + +let _ = Random.self_init () + +module Tez = Protocol.Alpha_context.Tez + +module Shielded_tez : sig + type t + + val encoding : t Data_encoding.t + + val pp : Format.formatter -> t -> unit + + val zero : t + + val of_mutez : int64 -> t option + + val to_mutez : t -> int64 + + val of_tez : Tez.t -> t + + val ( +? ) : t -> t -> t tzresult + + val ( -? ) : t -> t -> t tzresult +end = struct + include Tez + + let ( +? ) a b = a +? b |> Environment.wrap_tzresult + + let ( -? ) a b = a -? b |> Environment.wrap_tzresult + + let of_tez t = + let i = Tez.to_mutez t in + assert (UTXO.valid_amount i) ; + WithExceptions.Option.get ~loc:__LOC__ @@ of_mutez i +end + +module Shielded_tez_contract_input = struct + type t = UTXO.transaction * Signature.public_key_hash option + + let create ?pkh tr = (tr, pkh) + + let encoding = + let open Data_encoding in + obj2 + (req "transaction" UTXO.transaction_encoding) + (opt "pkh" Signature.Public_key_hash.encoding) + + let pp ppf t = + let open Data_encoding in + let json = Json.construct encoding t in + Json.pp ppf json + + let michelson (tr, pkopt) = + let open Tezos_micheline in + let open Protocol.Alpha_context in + let a = + Micheline.Bytes + (0, Data_encoding.Binary.to_bytes_exn UTXO.transaction_encoding tr) + in + let b = + match pkopt with + | None -> Micheline.Prim (0, Script.D_None, [], []) + | Some v -> + let value = + Micheline.Bytes + ( 0, + Data_encoding.Binary.to_bytes_exn + Signature.Public_key_hash.encoding + v ) + in + Micheline.Prim (0, Script.D_Some, [value], []) + in + Micheline.strip_locations + @@ Micheline.Seq (0, [Micheline.Prim (0, Script.D_Pair, [a; b], [])]) + + let pp_michelson ppf t = + let value = michelson t in + Michelson_v1_printer.print_expr ppf value + + let as_arg t = Format.asprintf "%a" pp_michelson t +end + +(** The inputs and outputs are shuffled to prevent meta-data analysis. **) +module Shuffle = struct + let list l = + let a = Array.of_list l in + let len = Array.length a in + for i = len downto 2 do + let idx = Random.int i in + let swp_idx = i - 1 in + let tmp = a.(swp_idx) in + a.(swp_idx) <- a.(idx) ; + a.(idx) <- tmp + done ; + Array.to_list a + + let pair x y = if Random.bool () then [y; x] else [x; y] +end + +type error += Balance_too_low of Shielded_tez.t * Shielded_tez.t + +let register_error_kind category ~id ~title ~description ?pp encoding from_error + to_error = + let id = "client_sapling." ^ Protocol.name ^ "." ^ id in + register_error_kind + category + ~id + ~title + ~description + ?pp + encoding + from_error + to_error + +let () = + register_error_kind + `Temporary + ~id:"balance_too_low" + ~title:"Balance too low" + ~description:"The sender contract does not have enough tokens." + ~pp:(fun ppf (balance, amount) -> + Format.fprintf + ppf + "@[Balance too low (%a) to spend %a@]" + Shielded_tez.pp + balance + Shielded_tez.pp + amount) + Data_encoding.( + obj2 + (req "actual_balance" Shielded_tez.encoding) + (req "amount" Shielded_tez.encoding)) + (function + | Balance_too_low (balance, amount) -> Some (balance, amount) | _ -> None) + (fun (balance, amount) -> Balance_too_low (balance, amount)) + +module Storage = Tezos_sapling.Storage +module F = Tezos_sapling.Forge + +module Input_set = struct + include Set.Make (F.Input) + + let to_list = elements + + let pp_f pp i = + Format.fprintf + pp + "@[%s %Ld@]" + (Base58.simple_encode + Viewing_key.address_b58check_encoding + (F.Input.address i)) + (F.Input.amount i) +end + +module Account = struct + type t = { + vk : Viewing_key.t; + unspents : Input_set.t; + balance : Shielded_tez.t; + } + + let encoding = + let open Data_encoding in + conv + (fun cs -> (cs.vk, Input_set.to_list cs.unspents, cs.balance)) + (fun (vk, unspents, balance) -> + {vk; unspents = Input_set.of_list unspents; balance}) + (obj3 + (req "vk" Viewing_key.encoding) + (req "unspents" (list F.Input.encoding)) + (req "balance" Shielded_tez.encoding)) + + let create vk = {vk; unspents = Input_set.empty; balance = Shielded_tez.zero} + + let balance c = c.balance + + let add_unspent c input = + let amount = + WithExceptions.Option.get ~loc:__LOC__ + @@ Shielded_tez.of_mutez (F.Input.amount input) + in + match Shielded_tez.(c.balance +? amount) with + | Error _ -> assert false (* overflow *) + | Ok balance -> + let unspents = Input_set.add input c.unspents in + {c with balance; unspents} + + let remove_unspent c input = + let amount = + WithExceptions.Option.get ~loc:__LOC__ + @@ Shielded_tez.of_mutez (F.Input.amount input) + in + match Shielded_tez.(c.balance -? amount) with + | Error _ -> assert false (* negative balance *) + | Ok balance -> + let unspents = Input_set.remove input c.unspents in + {c with balance; unspents} + + let filter_spent account storage = + Input_set.fold + (fun input acc -> + if F.Input.is_spent input storage account.vk then + remove_unspent acc input + else acc) + account.unspents + account + + let pick_input c = + let ( >?| ) x f = Option.map f x in + Input_set.choose c.unspents >?| fun unspent -> + let c = remove_unspent c unspent in + (unspent, c) + + let pp_unspent : Format.formatter -> t -> unit = + fun ppf a -> + (Format.pp_print_list ~pp_sep:Format.pp_print_cut Input_set.pp_f ppf) + (Input_set.elements a.unspents) +end + +module Contract_state = struct + module Accounts = struct + include Set.Make (struct + type t = Account.t + + let compare a b = + let open Account in + Bytes.compare (Viewing_key.to_bytes a.vk) (Viewing_key.to_bytes b.vk) + end) + + let replace a set = add a (remove a set) + + let find vk accounts = find (Account.create vk) accounts + end + + let accounts_encoding = + let open Data_encoding in + conv + Accounts.elements + (List.fold_left (fun m e -> Accounts.add e m) Accounts.empty) + (list Account.encoding) + + type t = {accounts : Accounts.t; storage : Storage.state} + + let encoding = + let open Data_encoding in + conv + (fun t -> (t.accounts, t.storage)) + (fun (accounts, storage) -> {accounts; storage}) + (obj2 + (req "accounts" accounts_encoding) + (req "storage" Storage.state_encoding)) + + let empty ~memo_size = + {accounts = Accounts.empty; storage = Storage.empty ~memo_size} + + let find_account vk contract_state = Accounts.find vk contract_state.accounts + + let init ~force vk state = + Accounts.find vk state.accounts |> function + | None -> + let accounts = Accounts.add (Account.create vk) state.accounts in + return {state with accounts} + | Some _ -> + if force then + let accounts = Accounts.add (Account.create vk) state.accounts in + return {state with accounts} + else failwith "vk already present" + + let add_unspent vk input accounts = + let account = + Accounts.find vk accounts |> WithExceptions.Option.get ~loc:__LOC__ + in + let account = Account.add_unspent account input in + Accounts.replace account accounts + + (** Scan the Sapling storage of a smart contract and update the accounts of + all known viewing keys for that contract *) + let scan state storage = + (* remove newly spent inputs *) + let accounts = + Accounts.map + (fun account -> Account.filter_spent account storage) + state.accounts + in + (* get all the vks that need to be scanned for *) + let vks = + Accounts.fold (fun account acc -> Account.(account.vk) :: acc) accounts [] + in + let (size, _) = Storage.size storage in + let rec aux pos accounts = + if pos < size then + (* try to decrypt each inputs with all vks *) + List.fold_left + (fun acc vk -> + match F.Input.get storage pos vk with + | None -> acc + | Some input -> (vk, input) :: acc) + [] + vks + |> function + | [] -> aux (Int64.succ pos) accounts + | [(vk, (_message, forge_input))] -> + let is_spent = F.Input.is_spent forge_input storage vk in + if is_spent then aux (Int64.succ pos) accounts + else aux (Int64.succ pos) (add_unspent vk forge_input accounts) + | _ -> assert false (* got more than one decrypting key *) + else accounts + in + let (current_size, _) = Storage.size state.storage in + let accounts = aux current_size accounts in + {accounts; storage} + + (** Update the Sapling storage of a smart contract using a diff, checking that + the resulting Merkle tree has a root equal to the one in the diff. *) + let update_storage contract_state (root, diff) = + let open Protocol.Alpha_context.Sapling in + let storage = + Tezos_sapling.Storage.add + contract_state.storage + diff.commitments_and_ciphertexts + in + let computed_root = Storage.get_root storage in + if computed_root <> root then + Stdlib.failwith "Commitment tree inconsistent wrt to node." + else + let storage = + List.fold_left + (fun s nf -> Storage.add_nullifier s nf) + storage + diff.nullifiers + in + scan contract_state storage +end + +module Client_state = struct + module Map = Map.Make (Protocol.Alpha_context.Contract) + + type t = Contract_state.t Map.t + + let encoding = + let open Data_encoding in + conv + Map.bindings + (List.fold_left (fun m (k, v) -> Map.add k v m) Map.empty) + (list + (obj2 + (req "contract" Protocol.Alpha_context.Contract.encoding) + (req "state" Contract_state.encoding))) + + let filename = "sapling_state" + + let load (cctxt : #Client_context.wallet) = + cctxt#load filename ~default:Map.empty encoding + + let write (cctxt : #Client_context.wallet) t = cctxt#write filename t encoding + + let get_or_init ~default_memo_size contract client_state = + Map.find contract client_state |> function + | None -> ( + match default_memo_size with + | None -> + failwith + "Unknown memo size for contract %s and none was provided in \ + options" + @@ Protocol.Alpha_context.Contract.to_b58check contract + | Some memo_size -> + let contract_state = Contract_state.empty ~memo_size in + let client_state = Map.add contract contract_state client_state in + return (contract_state, client_state)) + | Some contract_state -> return (contract_state, client_state) + + let register cctxt ~force ~default_memo_size contract vk = + load cctxt >>=? fun client_state -> + get_or_init ~default_memo_size contract client_state + >>=? fun (contract_state, client_state) -> + Contract_state.init ~force vk contract_state >>=? fun contract_state -> + let client_state = Map.add contract contract_state client_state in + write cctxt client_state + + let find (cctxt : #Client_context.full) contract state = + Map.find contract state |> function + | None -> + cctxt#error + "Contract %s not found" + (Protocol.Alpha_context.Contract.to_b58check contract) + | Some v -> return v + + (** Call the node RPC to obtain the storage diff of a contract *) + let get_diff cctxt contract offset_commitment offset_nullifier = + Protocol.Alpha_services.Contract.single_sapling_get_diff + cctxt + (cctxt#chain, cctxt#block) + contract + ~offset_commitment + ~offset_nullifier + () + + let sync_and_scan cctxt contract = + load cctxt >>=? fun state -> + find cctxt contract state >>=? fun contract_state -> + let (cm_pos, nf_pos) = Storage.size contract_state.storage in + get_diff cctxt contract cm_pos nf_pos >>=? fun diff -> + let contract_state = Contract_state.update_storage contract_state diff in + let state = Map.add contract contract_state state in + write cctxt state >>=? fun () -> return contract_state +end + +(** Truncate or pad the message to fit the memo_size *) +let adjust_message_length (cctxt : #Client_context.full) ?message memo_size = + match message with + | None -> + cctxt#warning + "no message provided, adding a zeroes filled message of the required \ + length: %d " + memo_size + >|= fun () -> Bytes.make memo_size '\000' + | Some message -> + let message_length = Bytes.length message in + if message_length = memo_size then Lwt.return message + else if message_length > memo_size then + cctxt#warning + "Your message is too long (%d bytes) and will therefore be truncated \ + to %d bytes" + message_length + memo_size + >|= fun () -> Bytes.sub message 0 memo_size + else + cctxt#warning + "Your message is too short (%d bytes) and will therefore be \ + right-padded with zero bytes to reach a %d-byte length" + message_length + memo_size + >|= fun () -> + Bytes.cat message (Bytes.make (memo_size - message_length) '\000') + +let create_payment ~message dst amount = + let amount = Shielded_tez.to_mutez amount in + F.make_output dst amount message + +(** Return a list of inputs belonging to an account sufficient to cover an + amount, together with the change remaining. *) +let get_shielded_amount amount account = + let balance = Account.balance account in + error_unless (balance >= amount) (Balance_too_low (balance, amount)) + >|? fun () -> + let to_pay = Shielded_tez.to_mutez amount in + let inputs_to_spend = [] in + let rec loop to_pay chosen_inputs account = + if Int64.(compare to_pay zero) > 0 then + Account.pick_input account |> function + | None -> + Stdlib.failwith "Not enough inputs" (* TODO raise a proper error *) + | Some (next_in, account) -> + let next_val = F.Input.amount next_in in + let rest_to_pay = Int64.sub to_pay next_val in + loop rest_to_pay (next_in :: chosen_inputs) account + else + let change = + WithExceptions.Option.get ~loc:__LOC__ + @@ Shielded_tez.of_mutez @@ Int64.abs to_pay + in + (chosen_inputs, change) + in + loop to_pay inputs_to_spend account + +let create_payback ~memo_size address amount = + let plaintext_message = Bytes.make memo_size '\000' in + let amount = Shielded_tez.to_mutez amount in + F.make_output address amount plaintext_message + +(* The caller should check that the account exists already *) +let unshield ~src ~dst ~backdst amount (state : Contract_state.t) anti_replay = + let vk = Viewing_key.of_sk src in + let account = + Contract_state.find_account vk state + |> WithExceptions.Option.get ~loc:__LOC__ + in + get_shielded_amount amount account >|? fun (inputs, change) -> + let memo_size = Storage.get_memo_size state.storage in + let payback = create_payback ~memo_size backdst change in + let sapling_transaction = + F.forge_transaction + (Shuffle.list inputs) + [payback] + src + anti_replay + state.storage + in + Shielded_tez_contract_input.create ~pkh:dst sapling_transaction + +let shield cctxt ~dst ?message amount (state : Contract_state.t) anti_replay = + let shielded_amount = Shielded_tez.of_tez amount in + let memo_size = Storage.get_memo_size Contract_state.(state.storage) in + adjust_message_length cctxt ?message memo_size >>= fun message -> + let payment = create_payment ~message dst shielded_amount in + let negative_amount = Int64.neg (Tez.to_mutez amount) in + let sapling_transaction = + F.forge_shield_transaction + [payment] + negative_amount + anti_replay + Contract_state.(state.storage) + in + return (Shielded_tez_contract_input.create sapling_transaction) + +(* The caller should check that the account exists already *) +let transfer cctxt ~src ~dst ~backdst ?message amount (state : Contract_state.t) + anti_replay = + let vk = Viewing_key.of_sk src in + let account = + Contract_state.find_account vk state + |> WithExceptions.Option.get ~loc:__LOC__ + in + let memo_size = Storage.get_memo_size state.storage in + adjust_message_length cctxt ?message memo_size >|= fun message -> + get_shielded_amount amount account >|? fun (inputs, change) -> + let payment = create_payment ~message dst amount in + let payback = create_payback ~memo_size backdst change in + let sapling_transaction = + F.forge_transaction + (Shuffle.list inputs) + (Shuffle.pair payback payment) + src + anti_replay + state.storage + in + sapling_transaction diff --git a/src/proto_011_PtHangzH/lib_client_sapling/context.mli b/src/proto_011_PtHangzH/lib_client_sapling/context.mli new file mode 100644 index 000000000000..72963733eb7c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_sapling/context.mli @@ -0,0 +1,157 @@ +(* The MIT License (MIT) + * + * Copyright (c) 2019-2020 Nomadic Labs + * + * 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 allows the creation Sapling transactions: shield, unshield and + transfer. + Because Sapling uses an UTXO model, it is necessary for the client to + maintain locally the set of unspent outputs for each viewing key, for each + smart contract. This operation is called scanning. + This local cache is updated downloading from the node only the difference + from the last scanned state. +*) + +open Tezos_sapling.Core.Client + +module Tez : module type of Protocol.Alpha_context.Tez + +(** This module is used to represent any shielded token to avoid confusing it + with Tez. *) +module Shielded_tez : sig + type t + + val encoding : t Data_encoding.t + + val pp : Format.formatter -> t -> unit + + val zero : t + + val of_mutez : int64 -> t option + + val to_mutez : t -> int64 + + val of_tez : Tez.t -> t + + val ( +? ) : t -> t -> t tzresult +end + +(** Actual input to a smart contract handling Sapling transactions *) +module Shielded_tez_contract_input : sig + type t + + val create : ?pkh:Signature.Public_key_hash.t -> UTXO.transaction -> t + + val encoding : t Data_encoding.t + + val pp : Format.formatter -> t -> unit + + val as_arg : t -> string +end + +(** Account corresponding to a contract and a viewing key *) +module Account : sig + type t + + val balance : t -> Shielded_tez.t + + val pp_unspent : Format.formatter -> t -> unit +end + +(** State of a contract, potentially involving several viewing keys *) +module Contract_state : sig + type t + + val find_account : Viewing_key.t -> t -> Account.t option +end + +module Client_state : sig + type t + + val find : + Protocol_client_context.full -> + Protocol.Alpha_context.Contract.t -> + t -> + Contract_state.t tzresult Lwt.t + + val register : + Protocol_client_context.full -> + force:bool -> + default_memo_size:int option -> + Protocol.Alpha_context.Contract.t -> + Viewing_key.t -> + unit tzresult Lwt.t + + (** Synchronise our local state with the blockchain's. + The state must be recent enough to craft correct transactions. + The limit enforced by the protocol if 120 blocks. + Also scans, ie. checks for incoming payments and add + them to our balance. + **) + val sync_and_scan : + Protocol_client_context.full -> + Protocol.Alpha_context.Contract.t -> + Contract_state.t tzresult Lwt.t +end + +(** [shield ~message ~dst tez cstate anti-replay] returns a transaction + shielding [tez] tez to a sapling address [dst] using a sapling + storage [cstate] and the anti-replay string. *) +val shield : + #Client_context.full -> + dst:Viewing_key.address -> + ?message:bytes -> + Tez.t -> + Contract_state.t -> + string -> + Shielded_tez_contract_input.t tzresult Lwt.t + +(** [unshield ~src_name ~src ~dst ~backdst stez cstate storage] returns + a transaction unshielding [stez] shielded tokens from a sapling wallet + [src] to a transparent tezos address [dst], sending the change back to + [backdst] and using a Sapling storage [cstate] and a anti-replay string. + The transaction is refused if there is an insufficient amount of shielded + tez in the wallet [src], the error is raised with [src_name]. + *) +val unshield : + src:Spending_key.t -> + dst:Signature.public_key_hash -> + backdst:Viewing_key.address -> + Shielded_tez.t -> + Contract_state.t -> + string -> + Shielded_tez_contract_input.t tzresult + +(** [transfer ~message ~src ~dst ~backdst amount cstate anti-replay] creates a + Sapling transaction of [amount] shielded tez from Sapling wallet [src] to + Sapling address [dst], sending the change to [backdst], using a Sapling + storage [cstate] and a anti-replay string. + [~message] is a message that will be uploaded encrypted on chain. *) +val transfer : + #Client_context.full -> + src:Spending_key.t -> + dst:Viewing_key.address -> + backdst:Viewing_key.address -> + ?message:bytes -> + Shielded_tez.t -> + Contract_state.t -> + string -> + UTXO.transaction tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_client_sapling/dune b/src/proto_011_PtHangzH/lib_client_sapling/dune new file mode 100644 index 000000000000..b4291e2bd78d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_sapling/dune @@ -0,0 +1,19 @@ +(library + (name tezos_client_sapling_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-client-sapling-011-PtHangzH) + (libraries tezos-base + tezos-crypto + tezos-client-base + tezos-signer-backends + tezos-client-011-PtHangzH + tezos-client-011-PtHangzH-commands + tezos-protocol-011-PtHangzH) + (library_flags (:standard -linkall)) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_stdlib_unix + -open Tezos_client_base + -open Tezos_client_011_PtHangzH + -open Tezos_client_011_PtHangzH_commands + -open Tezos_protocol_011_PtHangzH + -open Tezos_protocol_environment_011_PtHangzH))) diff --git a/src/proto_011_PtHangzH/lib_client_sapling/dune-project b/src/proto_011_PtHangzH/lib_client_sapling/dune-project new file mode 100644 index 000000000000..c587c56f3083 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_sapling/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(name tezos-client-sapling) +(formatting (enabled_for ocaml)) diff --git a/src/proto_011_PtHangzH/lib_client_sapling/tezos-client-sapling-011-PtHangzH.opam b/src/proto_011_PtHangzH/lib_client_sapling/tezos-client-sapling-011-PtHangzH.opam new file mode 100644 index 000000000000..66ea8f54c5a2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_sapling/tezos-client-sapling-011-PtHangzH.opam @@ -0,0 +1,24 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "ocamlfind" { build } + "dune" { >= "2.0" } + "tezos-base" + "tezos-clic" + "tezos-crypto" + "tezos-client-base" + "tezos-signer-backends" + "tezos-client-011-PtHangzH" + "tezos-client-011-PtHangzH-commands" + "tezos-protocol-011-PtHangzH" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos: sapling support for `tezos-client`" diff --git a/src/proto_011_PtHangzH/lib_client_sapling/wallet.ml b/src/proto_011_PtHangzH/lib_client_sapling/wallet.ml new file mode 100644 index 000000000000..7a9a4567dbbf --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_sapling/wallet.ml @@ -0,0 +1,126 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Client_keys +open Tezos_sapling.Core.Client + +module Mnemonic = struct + let new_random = Bip39.of_entropy (Hacl.Rand.gen 32) + + let to_sapling_key mnemonic = + (* Z-cash needs 32 bytes and BIP-39 gives 64 bytes of entropy. + We xor the two halves in case the entropy is not well distributed. *) + let seed_64_to_seed_32 (seed_64 : bytes) : bytes = + assert (Bytes.length seed_64 = 64) ; + let first_32 = Bytes.sub seed_64 0 32 in + let second_32 = Bytes.sub seed_64 32 32 in + let seed_32 = Bytes.create 32 in + for i = 0 to 31 do + Bytes.set + seed_32 + i + (Char.chr + (Char.code (Bytes.get first_32 i) + lxor Char.code (Bytes.get second_32 i))) + done ; + seed_32 + in + Spending_key.of_seed (seed_64_to_seed_32 (Bip39.to_seed mnemonic)) + + let words_pp = Format.(pp_print_list ~pp_sep:pp_print_space pp_print_string) +end + +(* Transform a spending key to an uri, encrypted or not. *) +let to_uri unencrypted cctxt sapling_key = + if unencrypted then + return (Tezos_signer_backends.Unencrypted.make_sapling_key sapling_key) + else Tezos_signer_backends.Encrypted.encrypt_sapling_key cctxt sapling_key + +(** Transform an uri into a spending key, asking for a password if the uri was + encrypted. *) +let from_uri (cctxt : #Client_context.full) uri = + Tezos_signer_backends.Encrypted.decrypt_sapling_key cctxt uri + +let register (cctxt : #Client_context.full) ?(force = false) + ?(unencrypted = false) mnemonic name = + let sk = Mnemonic.to_sapling_key mnemonic in + to_uri unencrypted cctxt sk >>=? fun sk_uri -> + let key = + { + sk = sk_uri; + path = [Spending_key.child_index sk]; + address_index = Viewing_key.default_index; + } + in + Sapling_key.add ~force cctxt name key >>=? fun () -> + return @@ Viewing_key.of_sk sk + +let derive (cctxt : #Client_context.full) ?(force = false) + ?(unencrypted = false) src_name dst_name child_index = + Sapling_key.find cctxt src_name >>=? fun k -> + from_uri cctxt k.sk >>=? fun src_sk -> + let child_index = Int32.of_int child_index in + let dst_sk = Spending_key.derive_key src_sk child_index in + to_uri unencrypted cctxt dst_sk >>=? fun dst_sk_uri -> + let dst_key = + { + sk = dst_sk_uri; + path = child_index :: k.path; + address_index = Viewing_key.default_index; + } + in + (* TODO check this force *) + let _ = force in + Sapling_key.add ~force:true cctxt dst_name dst_key >>=? fun () -> + let path = + String.concat "/" (List.map Int32.to_string (List.rev dst_key.path)) + in + return (path, Viewing_key.of_sk dst_sk) + +let find_vk cctxt name = + Sapling_key.find cctxt name >>=? fun k -> + from_uri cctxt k.sk >>=? fun sk -> return (Viewing_key.of_sk sk) + +let new_address (cctxt : #Client_context.full) name index_opt = + Sapling_key.find cctxt name >>=? fun k -> + let index = + match index_opt with + | None -> k.address_index + | Some i -> Viewing_key.index_of_int64 (Int64.of_int i) + in + from_uri cctxt k.sk >>=? fun sk -> + return (Viewing_key.of_sk sk) >>=? fun vk -> + (* Viewing_key.new_address finds the smallest index greater or equal to + [index] that generates a correct address. *) + let (corrected_index, address) = Viewing_key.new_address vk index in + Sapling_key.update + cctxt + name + {k with address_index = Viewing_key.index_succ corrected_index} + >>=? fun () -> return (sk, corrected_index, address) + +let export_vk cctxt name = + find_vk cctxt name >>=? fun vk -> + return (Data_encoding.Json.construct Viewing_key.encoding vk) diff --git a/src/proto_011_PtHangzH/lib_client_sapling/wallet.mli b/src/proto_011_PtHangzH/lib_client_sapling/wallet.mli new file mode 100644 index 000000000000..17e0e59d0af4 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_client_sapling/wallet.mli @@ -0,0 +1,75 @@ +(* The MIT License (MIT) + * + * Copyright (c) 2019-2020 Nomadic Labs + * + * 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. *) + +open Tezos_sapling.Core.Client + +(** Mnemonic of 24 common english words from which a key can be derived. + The mnemonic follows the BIP-39 spec. *) +module Mnemonic : sig + val new_random : Bip39.t + + (** Pretty printer for printing a list of words of a mnemonic. *) + val words_pp : Format.formatter -> string list -> unit +end + +(** Add to the wallet a new spending key derived from a mnemonic and identified + by an alias. The wallet is updated and the corresponding viewing key is + returned. + If [force] it will overwrite an existing alias. *) +val register : + #Client_context.full -> + ?force:bool -> + ?unencrypted:bool -> + Bip39.t -> + string -> + Viewing_key.t tzresult Lwt.t + +(** [derive parent child index] derives a key with alias [child] from an + existing key with alias [parent] at [index] using ZIP32. + If a new index is required the state of the wallet is updated. + The path and viewing key corresponding to the generated key are returned. *) +val derive : + #Client_context.full -> + ?force:bool -> + ?unencrypted:bool -> + string -> + string -> + int -> + (string * Viewing_key.t) tzresult Lwt.t + +val find_vk : #Client_context.full -> string -> Viewing_key.t tzresult Lwt.t + +(** Generate a new address. + If an optional index is provided, try to derive the address at this index, + otherwise use the first viable one. + Not all indexes correspond to a valid address so successive ones are tried. + Once a valid index is found it is recorded in the wallet. + Return also the corresponding sk and vk to avoid asking the user multiple + times for the description password. *) +val new_address : + #Client_context.full -> + string -> + int option -> + (Spending_key.t * Viewing_key.index * Viewing_key.address) tzresult Lwt.t + +val export_vk : + #Client_context.full -> string -> Data_encoding.Json.json tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_delegate/.ocamlformat b/src/proto_011_PtHangzH/lib_delegate/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_blocks.ml b/src/proto_011_PtHangzH/lib_delegate/client_baking_blocks.ml new file mode 100644 index 000000000000..9f2f884e51c7 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_blocks.ml @@ -0,0 +1,204 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +type block_info = { + hash : Block_hash.t; + chain_id : Chain_id.t; + predecessor : Block_hash.t; + fitness : Bytes.t list; + timestamp : Time.Protocol.t; + protocol : Protocol_hash.t; + next_protocol : Protocol_hash.t; + proto_level : int; + level : Raw_level.t; + context : Context_hash.t; + predecessor_block_metadata_hash : Block_metadata_hash.t option; + predecessor_operations_metadata_hash : + Operation_metadata_list_list_hash.t option; +} + +let raw_info cctxt ?(chain = `Main) hash shell_header = + let block = `Hash (hash, 0) in + Shell_services.Chain.chain_id cctxt ~chain () >>=? fun chain_id -> + Shell_services.Blocks.protocols cctxt ~chain ~block () + >>=? fun {current_protocol = protocol; next_protocol} -> + (Shell_services.Blocks.metadata_hash cctxt ~chain ~block () >>= function + | Ok predecessor_block_metadata_hash -> + return_some predecessor_block_metadata_hash + | Error _ -> return_none) + >>=? fun predecessor_block_metadata_hash -> + (Shell_services.Blocks.Operation_metadata_hashes.root cctxt ~chain ~block () + >>= function + | Ok predecessor_operations_metadata_hash -> + return_some predecessor_operations_metadata_hash + | Error _ -> return_none) + >>=? fun predecessor_operations_metadata_hash -> + let { + Tezos_base.Block_header.predecessor; + fitness; + timestamp; + level; + context; + proto_level; + _; + } = + shell_header + in + match Raw_level.of_int32 level with + | Ok level -> + return + { + hash; + chain_id; + predecessor; + fitness; + timestamp; + protocol; + next_protocol; + proto_level; + level; + context; + predecessor_block_metadata_hash; + predecessor_operations_metadata_hash; + } + | Error _ -> failwith "Cannot convert level into int32" + +let info cctxt ?(chain = `Main) block = + Shell_services.Blocks.hash cctxt ~chain ~block () >>=? fun hash -> + Shell_services.Blocks.Header.shell_header cctxt ~chain ~block () + >>=? fun shell_header -> raw_info cctxt ~chain hash shell_header + +module Block_seen_event = struct + type t = { + hash : Block_hash.t; + header : Tezos_base.Block_header.t; + occurrence : [`Valid_blocks of Chain_id.t | `Heads]; + } + + let make hash header occurrence () = {hash; header; occurrence} + + module Definition = struct + let section = None + + let name = "block-seen-" ^ Protocol.name + + type nonrec t = t + + let encoding = + let open Data_encoding in + let v0_encoding = + conv + (function {hash; header; occurrence} -> (hash, occurrence, header)) + (fun (b, o, h) -> make b h o ()) + (obj3 + (req "hash" Block_hash.encoding) + (* Occurrence has to come before header, because: + (Invalid_argument + "Cannot merge two objects when the left element is of + variable length and the right one of dynamic + length. You should use the reverse order, or wrap the + second one with Data_encoding.dynamic_size.") *) + (req + "occurrence" + (union + [ + case + ~title:"heads" + (Tag 0) + (obj1 (req "occurrence-kind" (constant "heads"))) + (function `Heads -> Some () | _ -> None) + (fun () -> `Heads); + case + ~title:"valid-blocks" + (Tag 1) + (obj2 + (req "occurrence-kind" (constant "valid-blocks")) + (req "chain-id" Chain_id.encoding)) + (function + | `Valid_blocks ch -> Some ((), ch) | _ -> None) + (fun ((), ch) -> `Valid_blocks ch); + ])) + (req "header" Tezos_base.Block_header.encoding)) + in + With_version.(encoding ~name (first_version v0_encoding)) + + let pp ~short:_ ppf {hash; _} = + Format.fprintf ppf "Saw block %a" Block_hash.pp_short hash + + let doc = "Block observed while monitoring a blockchain." + + let level _ = Internal_event.Info + end + + module Event = Internal_event.Make (Definition) +end + +let monitor_valid_blocks cctxt ?chains ?protocols ~next_protocols () = + Monitor_services.valid_blocks cctxt ?chains ?protocols ?next_protocols () + >>=? fun (block_stream, _stop) -> + return + (Lwt_stream.map_s + (fun ((chain, block), header) -> + Block_seen_event.(Event.emit (make block header (`Valid_blocks chain))) + >>=? fun () -> + raw_info + cctxt + ~chain:(`Hash chain) + block + header.Tezos_base.Block_header.shell) + block_stream) + +let monitor_heads cctxt ~next_protocols chain = + Monitor_services.heads cctxt ?next_protocols chain + >>=? fun (block_stream, _stop) -> + return + (Lwt_stream.map_s + (fun (block, ({Tezos_base.Block_header.shell; _} as header)) -> + Block_seen_event.(Event.emit (make block header `Heads)) >>=? fun () -> + raw_info cctxt ~chain block shell) + block_stream) + +let blocks_from_current_cycle cctxt ?(chain = `Main) block ?(offset = 0l) () = + Shell_services.Blocks.hash cctxt ~chain ~block () >>=? fun hash -> + Shell_services.Blocks.Header.shell_header cctxt ~chain ~block () + >>=? fun {level; _} -> + Plugin.RPC.levels_in_current_cycle cctxt ~offset (chain, block) >>= function + | Error (RPC_context.Not_found _ :: _) -> return_nil + | Error _ as err -> Lwt.return err + | Ok (first, last) -> ( + let length = Int32.to_int (Int32.sub level (Raw_level.to_int32 first)) in + Shell_services.Blocks.list cctxt ~chain ~heads:[hash] ~length () + >>=? function + | [] -> return_nil + | hd :: _ -> + let blocks = + List.remove (length - Int32.to_int (Raw_level.diff last first)) hd + in + if Int32.equal level (Raw_level.to_int32 last) then + return (hash :: blocks) + else return blocks) diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_blocks.mli b/src/proto_011_PtHangzH/lib_delegate/client_baking_blocks.mli new file mode 100644 index 000000000000..4167be75ce1b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_blocks.mli @@ -0,0 +1,71 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +type block_info = { + hash : Block_hash.t; + chain_id : Chain_id.t; + predecessor : Block_hash.t; + fitness : Bytes.t list; + timestamp : Time.Protocol.t; + protocol : Protocol_hash.t; + next_protocol : Protocol_hash.t; + proto_level : int; + level : Raw_level.t; + context : Context_hash.t; + predecessor_block_metadata_hash : Block_metadata_hash.t option; + predecessor_operations_metadata_hash : + Operation_metadata_list_list_hash.t option; +} + +val info : + #Protocol_client_context.rpc_context -> + ?chain:Chain_services.chain -> + Block_services.block -> + block_info tzresult Lwt.t + +val monitor_valid_blocks : + #Protocol_client_context.rpc_context -> + ?chains:Chain_services.chain list -> + ?protocols:Protocol_hash.t list -> + next_protocols:Protocol_hash.t list option -> + unit -> + block_info tzresult Lwt_stream.t tzresult Lwt.t + +val monitor_heads : + #Protocol_client_context.rpc_context -> + next_protocols:Protocol_hash.t list option -> + Chain_services.chain -> + block_info tzresult Lwt_stream.t tzresult Lwt.t + +val blocks_from_current_cycle : + #Protocol_client_context.rpc_context -> + ?chain:Chain_services.chain -> + Block_services.block -> + ?offset:int32 -> + unit -> + Block_hash.t list tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_denunciation.ml b/src/proto_011_PtHangzH/lib_delegate/client_baking_denunciation.ml new file mode 100644 index 000000000000..71de360db3e9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_denunciation.ml @@ -0,0 +1,309 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Protocol_client_context +open Client_baking_blocks +module Events = Delegate_events.Denunciator + +module HLevel = Hashtbl.Make (struct + type t = Chain_id.t * Raw_level.t + + let equal (c, l) (c', l') = Chain_id.equal c c' && Raw_level.equal l l' + + let hash (c, lvl) = Hashtbl.hash (c, lvl) +end) + +module Delegate_Map = Map.Make (Signature.Public_key_hash) + +type state = { + (* Endorsements seen so far *) + endorsements_table : Kind.endorsement operation Delegate_Map.t HLevel.t; + (* Blocks received so far *) + blocks_table : Block_hash.t Delegate_Map.t HLevel.t; + (* Maximum delta of level to register *) + preserved_levels : int; + (* Highest level seen in a block *) + mutable highest_level_encountered : Raw_level.t; +} + +let create_state ~preserved_levels = + Lwt.return + { + endorsements_table = HLevel.create preserved_levels; + blocks_table = HLevel.create preserved_levels; + preserved_levels; + highest_level_encountered = Raw_level.root (* 0l *); + } + +(* We choose a previous offset (5 blocks from head) to ensure that the + injected operation is branched from a valid predecessor. *) +let get_block_offset level = + match Raw_level.of_int32 5l with + | Ok min_level -> + Lwt.return (if Raw_level.(level < min_level) then `Head 0 else `Head 5) + | Error errs -> + Events.(emit invalid_level_conversion) (Environment.wrap_tztrace errs) + >>= fun () -> Lwt.return (`Head 0) + +let process_endorsements (cctxt : #Protocol_client_context.full) state + (endorsements : Alpha_block_services.operation list) level = + List.iter_es + (fun {Alpha_block_services.shell; chain_id; receipt; hash; protocol_data; _} -> + let chain = `Hash chain_id in + match (protocol_data, receipt) with + | ( Operation_data + { + contents = + Single + (Endorsement_with_slot + { + endorsement = + { + protocol_data = + {contents = Single (Endorsement _); _} as + protocol_data; + _; + }; + _; + }); + _; + }, + Some + Apply_results.( + Operation_metadata + { + contents = + Single_result + (Endorsement_with_slot_result + (Endorsement_result {delegate; slots = slot :: _; _})); + }) ) -> ( + let new_endorsement : Kind.endorsement Alpha_context.operation = + {shell; protocol_data} + in + let map = + Option.value ~default:Delegate_Map.empty + @@ HLevel.find state.endorsements_table (chain_id, level) + in + (* If a previous endorsement made by this pkh is found for + the same level we inject a double_endorsement *) + match Delegate_Map.find delegate map with + | None -> + return + @@ HLevel.add + state.endorsements_table + (chain_id, level) + (Delegate_Map.add delegate new_endorsement map) + | Some existing_endorsement + when Block_hash.( + existing_endorsement.shell.branch + <> new_endorsement.shell.branch) -> + get_block_offset level >>= fun block -> + Alpha_block_services.hash cctxt ~chain ~block () + >>=? fun block_hash -> + Plugin.RPC.Forge.double_endorsement_evidence + cctxt + (`Hash chain_id, block) + ~branch:block_hash + ~op1:existing_endorsement + ~op2:new_endorsement + ~slot + () + >>=? fun bytes -> + let bytes = Signature.concat bytes Signature.zero in + Events.(emit double_endorsement_detected) + ( Operation.hash existing_endorsement, + Operation.hash new_endorsement ) + >>= fun () -> + (* A denunciation may have already occurred *) + Shell_services.Injection.operation cctxt ~chain bytes + >>=? fun op_hash -> + Events.(emit double_endorsement_denounced) (op_hash, bytes) + >>= fun () -> + return + @@ HLevel.replace + state.endorsements_table + (chain_id, level) + (Delegate_Map.add delegate new_endorsement map) + | Some _ -> + (* This endorsement is already present in another + block but endorse the same predecessor *) + return_unit) + | _ -> + Events.(emit inconsistent_endorsement) hash >>= fun () -> return_unit) + endorsements + >>=? fun () -> return_unit + +let process_block (cctxt : #Protocol_client_context.full) state + (header : Alpha_block_services.block_info) = + match header with + | {hash; metadata = None; _} -> + Events.(emit unexpected_pruned_block) hash >>= fun () -> return_unit + | { + Alpha_block_services.chain_id; + hash; + metadata = Some {protocol_data = {baker; level_info = {level; _}; _}; _}; + _; + } -> ( + let chain = `Hash chain_id in + let map = + match HLevel.find state.blocks_table (chain_id, level) with + | None -> Delegate_Map.empty + | Some x -> x + in + match Delegate_Map.find baker map with + | None -> + return + @@ HLevel.add + state.blocks_table + (chain_id, level) + (Delegate_Map.add baker hash map) + | Some existing_hash when Block_hash.( = ) existing_hash hash -> + (* This case should never happen *) + Events.(emit double_baking_but_not) () >>= fun () -> + return + @@ HLevel.replace + state.blocks_table + (chain_id, level) + (Delegate_Map.add baker hash map) + | Some existing_hash -> + (* If a previous endorsement made by this pkh is found for + the same level we inject a double_endorsement *) + Alpha_block_services.header + cctxt + ~chain + ~block:(`Hash (existing_hash, 0)) + () + >>=? fun ({shell; protocol_data; _} : + Alpha_block_services.block_header) -> + let bh1 = {Alpha_context.Block_header.shell; protocol_data} in + Alpha_block_services.header cctxt ~chain ~block:(`Hash (hash, 0)) () + >>=? fun ({shell; protocol_data; _} : + Alpha_block_services.block_header) -> + let bh2 = {Alpha_context.Block_header.shell; protocol_data} in + (* If the blocks are on different chains then skip it *) + get_block_offset level >>= fun block -> + Alpha_block_services.hash cctxt ~chain ~block () + >>=? fun block_hash -> + Plugin.RPC.Forge.double_baking_evidence + cctxt + (chain, block) + ~branch:block_hash + ~bh1 + ~bh2 + () + >>=? fun bytes -> + let bytes = Signature.concat bytes Signature.zero in + Events.(emit double_baking_detected) () >>= fun () -> + (* A denunciation may have already occurred *) + Shell_services.Injection.operation cctxt ~chain bytes + >>=? fun op_hash -> + Events.(emit double_baking_denounced) (op_hash, bytes) >>= fun () -> + return + @@ HLevel.replace + state.blocks_table + (chain_id, level) + (Delegate_Map.add baker hash map)) + +(* Remove levels that are lower than the [highest_level_encountered] minus [preserved_levels] *) +let cleanup_old_operations state = + let highest_level_encountered = + Int32.to_int (Raw_level.to_int32 state.highest_level_encountered) + in + let diff = highest_level_encountered - state.preserved_levels in + let threshold = + if diff < 0 then Raw_level.root + else + Raw_level.of_int32 (Int32.of_int diff) |> function + | Ok threshold -> threshold + | Error _ -> Raw_level.root + in + let filter hmap = + HLevel.filter_map_inplace + (fun (_, level) x -> + if Raw_level.(level < threshold) then None else Some x) + hmap + in + filter state.endorsements_table ; + filter state.blocks_table ; + () + +let endorsements_index = 0 + +(* Each new block is processed : + - Checking that every endorser operated only once at this level + - Checking that every baker injected only once at this level +*) +let process_new_block (cctxt : #Protocol_client_context.full) state + {hash; chain_id; level; protocol; next_protocol; _} = + if Protocol_hash.(protocol <> next_protocol) then + Events.(emit protocol_change_detected) () >>= fun () -> return_unit + else + Events.(emit accuser_saw_block) (level, hash) >>= fun () -> + let chain = `Hash chain_id in + let block = `Hash (hash, 0) in + state.highest_level_encountered <- + Raw_level.max level state.highest_level_encountered ; + (* Processing blocks *) + (Alpha_block_services.info cctxt ~chain ~block () >>= function + | Ok block_info -> process_block cctxt state block_info + | Error errs -> + Events.(emit fetch_operations_error) (hash, errs) >>= fun () -> + return_unit) + >>=? fun () -> + (* Processing endorsements *) + (Alpha_block_services.Operations.operations cctxt ~chain ~block () + >>= function + | Ok operations -> ( + match List.nth operations endorsements_index with + | Some endorsements -> + process_endorsements cctxt state endorsements level + | None -> return_unit) + | Error errs -> + Events.(emit fetch_operations_error) (hash, errs) >>= fun () -> + return_unit) + >>=? fun () -> + cleanup_old_operations state ; + return_unit + +let create (cctxt : #Protocol_client_context.full) ~preserved_levels + valid_blocks_stream = + let process_block cctxt state bi = + process_new_block cctxt state bi >>= function + | Ok () -> Events.(emit accuser_processed_block) bi.hash >>= return + | Error errs -> Events.(emit accuser_block_error) (bi.hash, errs) >>= return + in + let state_maker _ = create_state ~preserved_levels >>= return in + Client_baking_scheduling.main + ~name:"accuser" + ~cctxt + ~stream:valid_blocks_stream + ~state_maker + ~pre_loop:(fun _ _ _ -> return_unit) + ~compute_timeout:(fun _ -> Lwt_utils.never_ending ()) + ~timeout_k:(fun _ _ () -> return_unit) + ~event_k:process_block + ~finalizer:(fun _ -> Lwt.return_unit) diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_denunciation.mli b/src/proto_011_PtHangzH/lib_delegate/client_baking_denunciation.mli new file mode 100644 index 000000000000..963ff969f83c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_denunciation.mli @@ -0,0 +1,30 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val create : + #Protocol_client_context.full -> + preserved_levels:int -> + Client_baking_blocks.block_info tzresult Lwt_stream.t -> + unit tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_endorsement.ml b/src/proto_011_PtHangzH/lib_delegate/client_baking_endorsement.ml new file mode 100644 index 000000000000..97672d81fda8 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_endorsement.ml @@ -0,0 +1,275 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Protocol_client_context +module Events = Delegate_events.Endorsement + +let get_signing_slots cctxt ~chain ~block delegate level = + Plugin.RPC.Endorsing_rights.get + cctxt + ~levels:[level] + ~delegates:[delegate] + (chain, block) + >>=? function + | [{slots; _}] -> return_some slots + | _ -> return_none + +let inject_endorsement (cctxt : #Protocol_client_context.full) ?async ~chain + ~block hash level delegate_sk delegate_pkh = + Plugin.RPC.Endorsing_rights.get + cctxt + ~levels:[level] + ~delegates:[delegate_pkh] + (chain, block) + >>=? function + | [{slots = []; _}] | [] | _ :: _ :: _ -> assert false + | [{slots = slot :: _; _}] -> + Plugin.RPC.Forge.endorsement cctxt (chain, block) ~branch:hash ~level () + >>=? fun bytes -> + let wallet = (cctxt :> Client_context.wallet) in + (* Double-check the right to inject an endorsement *) + let open Client_baking_highwatermarks in + wallet#with_lock (fun () -> + Client_baking_files.resolve_location cctxt ~chain `Endorsement + >>=? fun endorsement_location -> + may_inject_endorsement + cctxt + endorsement_location + ~delegate:delegate_pkh + level + >>=? function + | true -> + record_endorsement + cctxt + endorsement_location + ~delegate:delegate_pkh + level + >>=? fun () -> return_true + | false -> return_false) + >>=? fun is_allowed_to_endorse -> + if is_allowed_to_endorse then + Chain_services.chain_id cctxt ~chain () >>=? fun chain_id -> + Client_keys.append + cctxt + delegate_sk + ~watermark:(Endorsement chain_id) + bytes + >>=? fun signed_bytes -> + (* wrap the legacy endorsement in a slot-bearing wrapper *) + match + Data_encoding.Binary.of_bytes_opt + Alpha_context.Operation.encoding + signed_bytes + with + | Some + { + shell; + protocol_data = + Operation_data + ({contents = Single (Endorsement _); _} as protocol_data); + } -> + let wrapped = + { + shell; + protocol_data = + Operation_data + { + contents = + Single + (Endorsement_with_slot + {endorsement = {shell; protocol_data}; slot}); + signature = None; + }; + } + in + let wrapped_bytes = + Data_encoding.Binary.to_bytes_exn + Alpha_context.Operation.encoding + wrapped + in + Shell_services.Injection.operation cctxt ?async ~chain wrapped_bytes + >>=? fun oph -> return oph + | _ -> assert false + else + Events.(emit double_endorsement_near_miss) level >>= fun () -> + fail (Level_previously_endorsed level) + +let forge_endorsement (cctxt : #Protocol_client_context.full) ?async ~chain + ~block ~src_sk src_pk = + let src_pkh = Signature.Public_key.hash src_pk in + Alpha_block_services.metadata cctxt ~chain ~block () + >>=? fun {protocol_data = {level_info = {level; _}; _}; _} -> + Shell_services.Blocks.hash cctxt ~chain ~block () >>=? fun hash -> + inject_endorsement cctxt ?async ~chain ~block hash level src_sk src_pkh + >>=? fun oph -> + Client_keys.get_key cctxt src_pkh >>=? fun (name, _pk, _sk) -> + Events.(emit injected_endorsement) (hash, level, name, oph, src_pkh) + >>= fun () -> return oph + +(** Worker *) + +(* because of delegates *) +[@@@ocaml.warning "-30"] + +type state = { + delegates : public_key_hash list; + delay : int64; + mutable pending : endorsements option; +} + +and endorsements = { + time : Time.Protocol.t; + delegates : public_key_hash list; + block : Client_baking_blocks.block_info; +} + +[@@@ocaml.warning "+30"] + +let create_state delegates delay = {delegates; delay; pending = None} + +let get_delegates cctxt state = + match state.delegates with + | [] -> + Client_keys.get_keys cctxt >>=? fun keys -> + let delegates = List.map (fun (_, pkh, _, _) -> pkh) keys in + return Signature.Public_key_hash.Set.(delegates |> of_list |> elements) + | _ :: _ as delegates -> return delegates + +let endorse_for_delegate cctxt block delegate_pkh = + let {Client_baking_blocks.hash; level; chain_id; _} = block in + Client_keys.get_key cctxt delegate_pkh >>=? fun (name, _pk, delegate_sk) -> + Events.(emit endorsing) (hash, name, level) >>= fun () -> + let chain = `Hash chain_id in + let block = `Hash (hash, 0) in + inject_endorsement cctxt ~chain ~block hash level delegate_sk delegate_pkh + >>=? fun oph -> + Events.(emit injected_endorsement) (hash, level, name, oph, delegate_pkh) + >>= fun () -> return_unit + +let allowed_to_endorse cctxt bi delegate = + Client_keys.Public_key_hash.name cctxt delegate >>=? fun name -> + Events.(emit check_endorsement_ok) (bi.Client_baking_blocks.hash, name) + >>= fun () -> + let chain = `Hash bi.chain_id in + let block = `Hash (bi.hash, 0) in + let level = bi.level in + get_signing_slots cctxt ~chain ~block delegate level >>=? function + | None | Some [] -> + Events.(emit endorsement_no_slots_found) (bi.hash, name) >>= fun () -> + return_false + | Some (_ :: _ as slots) -> ( + Events.(emit endorsement_slots_found) (bi.hash, name, slots) >>= fun () -> + cctxt#with_lock (fun () -> + Client_baking_files.resolve_location cctxt ~chain `Endorsement + >>=? fun endorsement_location -> + Client_baking_highwatermarks.may_inject_endorsement + cctxt + endorsement_location + ~delegate + level) + >>=? function + | false -> + Events.(emit previously_endorsed) level >>= fun () -> return_false + | true -> return_true) + +let prepare_endorsement ~(max_past : int64) () + (cctxt : #Protocol_client_context.full) state bi = + let past = + Time.Protocol.diff + (Time.System.to_protocol (Systime_os.now ())) + bi.Client_baking_blocks.timestamp + in + if past > max_past then + Events.(emit endorsement_stale_block) bi.hash >>= fun () -> return_unit + else + Events.(emit endorsement_got_block) bi.hash >>= fun () -> + let time = + Time.Protocol.add + (Time.System.to_protocol (Systime_os.now ())) + state.delay + in + get_delegates cctxt state >>=? fun delegates -> + List.filter_ep (allowed_to_endorse cctxt bi) delegates >>=? fun delegates -> + state.pending <- Some {time; block = bi; delegates} ; + return_unit + +let compute_timeout state = + match state.pending with + | None -> Lwt_utils.never_ending () + | Some {time; block; delegates} -> ( + match Client_baking_scheduling.sleep_until time with + | None -> Lwt.return (block, delegates) + | Some timeout -> + let timespan = + let timespan = + Ptime.diff (Time.System.of_protocol_exn time) (Systime_os.now ()) + in + if Ptime.Span.compare timespan Ptime.Span.zero > 0 then timespan + else Ptime.Span.zero + in + Events.(emit wait_before_injecting) + (Time.System.of_protocol_exn time, timespan) + >>= fun () -> + timeout >>= fun () -> Lwt.return (block, delegates)) + +(* Refuse to endorse block that are more than 20min old. + 1200 is greater than 60 + 40*(p - 1) + 192*4 with p = 10, i.e. + we wait at least for the maximum delay for blocks with priority 10. *) +let default_max_past = 1200L + +let create (cctxt : #Protocol_client_context.full) + ?(max_past = default_max_past) ~delay delegates block_stream = + let state_maker _ = + let state = create_state delegates (Int64.of_int delay) in + return state + in + let timeout_k cctxt state (block, delegates) = + state.pending <- None ; + List.iter_es + (fun delegate -> + endorse_for_delegate cctxt block delegate >>= function + | Ok () -> return_unit + | Error errs -> + Events.(emit error_while_endorsing) (delegate, errs) >>= fun () -> + (* We continue anyway *) + return_unit) + delegates + in + let event_k cctxt state bi = + state.pending <- None ; + prepare_endorsement ~max_past () cctxt state bi + in + Client_baking_scheduling.main + ~name:"endorser" + ~cctxt + ~stream:block_stream + ~state_maker + ~pre_loop:(prepare_endorsement ~max_past ()) + ~compute_timeout + ~timeout_k + ~event_k + ~finalizer:(fun _ -> Lwt.return_unit) diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_endorsement.mli b/src/proto_011_PtHangzH/lib_delegate/client_baking_endorsement.mli new file mode 100644 index 000000000000..c03d37c2048e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_endorsement.mli @@ -0,0 +1,48 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2018 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +(** [forge_endorsement cctxt blk ~src_sk src_pk] emits an endorsement + operation for the block [blk] +*) +val forge_endorsement : + #Protocol_client_context.full -> + ?async:bool -> + chain:Chain_services.chain -> + block:Block_services.block -> + src_sk:Client_keys.sk_uri -> + public_key -> + Operation_hash.t tzresult Lwt.t + +val create : + #Protocol_client_context.full -> + ?max_past:int64 (* number of seconds *) -> + delay:int -> + public_key_hash list -> + Client_baking_blocks.block_info tzresult Lwt_stream.t -> + unit tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_files.ml b/src/proto_011_PtHangzH/lib_delegate/client_baking_files.ml new file mode 100644 index 000000000000..df24c5e3e4cb --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_files.ml @@ -0,0 +1,55 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type _ location = {filename : string; chain : Chain_services.chain} + +let resolve_location (cctxt : #Client_context.full) ~chain (kind : 'a) : + 'a location tzresult Lwt.t = + let basename = + match kind with + | `Block -> "block" + | `Endorsement -> "endorsement" + | `Nonce -> "nonce" + in + let test_filename chain_id = + Format.kasprintf return "test_%a_%s" Chain_id.pp_short chain_id basename + in + (match chain with + | `Main -> return basename + | `Test -> + (* FIXME: dead code. Cannot be removed because the type + Chain_services.chain is common to all the + protocols. *) + Chain_services.chain_id cctxt ~chain:`Test () >>=? fun chain_id -> + test_filename chain_id + | `Hash chain_id -> + Chain_services.chain_id cctxt ~chain:`Main () >>=? fun main_chain_id -> + if Chain_id.(chain_id = main_chain_id) then return basename + else test_filename chain_id) + >>=? fun filename -> return {filename; chain} + +let filename {filename; _} = filename + +let chain {chain; _} = chain diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_files.mli b/src/proto_011_PtHangzH/lib_delegate/client_baking_files.mli new file mode 100644 index 000000000000..a01f0b6a775c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_files.mli @@ -0,0 +1,36 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type _ location + +val resolve_location : + #Client_context.full -> + chain:Chain_services.chain -> + ([< `Block | `Endorsement | `Nonce] as 'kind) -> + 'kind location tzresult Lwt.t + +val filename : _ location -> string + +val chain : _ location -> Chain_services.chain diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_forge.ml b/src/proto_011_PtHangzH/lib_delegate/client_baking_forge.ml new file mode 100644 index 000000000000..4d5a9d1f808d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_forge.ml @@ -0,0 +1,1665 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Protocol_client_context +module Events = Delegate_events.Baking_forge + +(* The index of the different components of the protocol's validation passes *) +(* TODO: ideally, we would like this to be more abstract and possibly part of + the protocol, while retaining the generality of lists *) +(* Hypothesis : we suppose [List.length Protocol.Main.validation_passes = 4] *) +let endorsements_index = 0 + +let votes_index = 1 + +let anonymous_index = 2 + +let managers_index = 3 + +let default_max_priority = 64 + +let default_minimal_fees = + match Tez.of_mutez 100L with None -> assert false | Some t -> t + +let default_minimal_nanotez_per_gas_unit = Q.of_int 100 + +let default_minimal_nanotez_per_byte = Q.of_int 1000 + +let default_retry_counter = 5 + +type slot = + Time.Protocol.t * (Client_baking_blocks.block_info * int * public_key_hash) + +type state = { + context_path : string; + mutable index : Context.index; + (* Nonces file location *) + nonces_location : [`Nonce] Client_baking_files.location; + (* see [get_delegates] below to find delegates when the list is empty *) + delegates : public_key_hash list; + (* lazy-initialisation with retry-on-error *) + constants : Constants.t; + (* Minimal operation fee required to include an operation in a block *) + minimal_fees : Tez.t; + (* Minimal operation fee per gas required to include an operation in a block *) + minimal_nanotez_per_gas_unit : Q.t; + (* Minimal operation fee per byte required to include an operation in a block *) + minimal_nanotez_per_byte : Q.t; + (* truly mutable *) + mutable best_slot : slot option; + mutable retry_counter : int; +} + +let create_state ?(minimal_fees = default_minimal_fees) + ?(minimal_nanotez_per_gas_unit = default_minimal_nanotez_per_gas_unit) + ?(minimal_nanotez_per_byte = default_minimal_nanotez_per_byte) + ?(retry_counter = default_retry_counter) context_path index nonces_location + delegates constants = + { + context_path; + index; + nonces_location; + delegates; + constants; + minimal_fees; + minimal_nanotez_per_gas_unit; + minimal_nanotez_per_byte; + best_slot = None; + retry_counter; + } + +let get_delegates cctxt state = + match state.delegates with + | [] -> + Client_keys.get_keys cctxt >>=? fun keys -> + return (List.map (fun (_, pkh, _, _) -> pkh) keys) + | _ -> return state.delegates + +let generate_seed_nonce () = + match Nonce.of_bytes (Rand.generate Constants.nonce_length) with + | Error _errs -> assert false + | Ok nonce -> nonce + +let forge_block_header (cctxt : #Protocol_client_context.full) ~chain block + delegate_sk shell priority seed_nonce_hash ~liquidity_baking_escape_vote = + Client_baking_pow.mine cctxt chain block shell (fun proof_of_work_nonce -> + { + Block_header.priority; + seed_nonce_hash; + proof_of_work_nonce; + liquidity_baking_escape_vote; + }) + >>=? fun contents -> + let unsigned_header = + Data_encoding.Binary.to_bytes_exn + Alpha_context.Block_header.unsigned_encoding + (shell, contents) + in + Shell_services.Chain.chain_id cctxt ~chain () >>=? fun chain_id -> + Client_keys.append + cctxt + delegate_sk + ~watermark:(Block_header chain_id) + unsigned_header + +let forge_faked_protocol_data ~priority ~seed_nonce_hash + ~liquidity_baking_escape_vote = + Alpha_context.Block_header. + { + contents = + { + priority; + seed_nonce_hash; + proof_of_work_nonce = Client_baking_pow.empty_proof_of_work_nonce; + liquidity_baking_escape_vote; + }; + signature = Signature.zero; + } + +let assert_valid_operations_hash shell_header operations = + let operations_hash = + Operation_list_list_hash.compute + (List.map + Operation_list_hash.compute + (List.map (List.map Tezos_base.Operation.hash) operations)) + in + fail_unless + (Operation_list_list_hash.equal + operations_hash + shell_header.Tezos_base.Block_header.operations_hash) + (failure "Client_baking_forge.inject_block: inconsistent header.") + +let inject_block cctxt ?(force = false) ?seed_nonce_hash ~chain ~shell_header + ~priority ~delegate_pkh ~delegate_sk ~level operations + ~liquidity_baking_escape_vote = + assert_valid_operations_hash shell_header operations >>=? fun () -> + let block = `Hash (shell_header.Tezos_base.Block_header.predecessor, 0) in + forge_block_header + cctxt + ~chain + block + delegate_sk + shell_header + priority + seed_nonce_hash + ~liquidity_baking_escape_vote + >>=? fun signed_header -> + (* Record baked blocks to prevent double baking *) + let open Client_baking_highwatermarks in + cctxt#with_lock (fun () -> + Client_baking_files.resolve_location cctxt ~chain `Block + >>=? fun block_location -> + may_inject_block cctxt block_location ~delegate:delegate_pkh level + >>=? function + | true -> + record_block cctxt block_location ~delegate:delegate_pkh level + >>=? fun () -> return_true + | false -> + Events.(emit double_bake_near_miss) level >>= fun () -> return force) + >>=? function + | false -> fail (Level_previously_baked level) + | true -> + Shell_services.Injection.block + cctxt + ~force + ~chain + signed_header + operations + >>=? fun block_hash -> + Events.(emit inject_baked_block) (block_hash, signed_header, operations) + >>= fun () -> return block_hash + +type error += Failed_to_preapply of Tezos_base.Operation.t * error list + +let () = + register_error_kind + `Permanent + ~id:"Client_baking_forge.failed_to_preapply" + ~title:"Fail to preapply an operation" + ~description:"" + ~pp:(fun ppf (op, err) -> + let h = Tezos_base.Operation.hash op in + Format.fprintf + ppf + "@[Failed to preapply %a:@ @[%a@]@]" + Operation_hash.pp_short + h + pp_print_error + err) + Data_encoding.( + obj2 + (req "operation" (dynamic_size Tezos_base.Operation.encoding)) + (req "error" RPC_error.encoding)) + (function Failed_to_preapply (hash, err) -> Some (hash, err) | _ -> None) + (fun (hash, err) -> Failed_to_preapply (hash, err)) + +type manager_content = { + total_fee : Tez.t; + total_gas : Fixed_point_repr.integral_tag Gas.Arith.t; + source : public_key_hash; + counter : counter; +} + +let get_manager_content op = + let {protocol_data = Operation_data {contents; _}; _} = op in + let open Operation in + let l = to_list (Contents_list contents) in + List.fold_left_e + (fun ((first_source, first_counter, total_fee, total_gas) as acc) -> + function + | Contents (Manager_operation {source; counter; fee; gas_limit; _}) -> + (Environment.wrap_tzresult @@ Tez.(total_fee +? fee)) + >>? fun total_fee -> + (* There is only one unique source per packed transaction *) + let first_source = Option.value ~default:source first_source in + (* We only care about the first counter *) + let first_counter = Option.value ~default:counter first_counter in + ok + ( Some first_source, + Some first_counter, + total_fee, + Gas.Arith.add total_gas gas_limit ) + | _ -> ok acc) + (None, None, Tez.zero, Gas.Arith.zero) + l + |> function + | Ok (Some source, Some counter, total_fee, total_gas) -> + Some {total_fee; total_gas; source; counter} + | _ -> None + +(* Sort operation considering potential gas and storage usage. + Weight = fee / (max ( (size/size_total), (gas/gas_total))) *) +let sort_manager_operations ~max_size ~hard_gas_limit_per_block ~minimal_fees + ~minimal_nanotez_per_gas_unit ~minimal_nanotez_per_byte + (operations : packed_operation list) = + let compute_weight op (fee, gas) = + let size = Data_encoding.Binary.length Operation.encoding op in + let size_f = Q.of_int size in + let gas_f = Q.of_bigint (Gas.Arith.integral_to_z gas) in + let fee_f = Q.of_int64 (Tez.to_mutez fee) in + let size_ratio = Q.(size_f / Q.of_int max_size) in + let gas_ratio = + Q.(gas_f / Q.of_bigint (Gas.Arith.integral_to_z hard_gas_limit_per_block)) + in + (size, gas, Q.(fee_f / max size_ratio gas_ratio)) + in + List.filter_map + (fun op -> + match get_manager_content op with + | None -> None + | Some {total_fee; total_gas; source; counter} -> + if Tez.(total_fee < minimal_fees) then None + else + let (size, gas, weight_ratio) = + compute_weight op (total_fee, total_gas) + in + let fees_in_nanotez = + Q.mul (Q.of_int64 (Tez.to_mutez total_fee)) (Q.of_int 1000) + in + let enough_fees_for_gas = + let minimal_fees_in_nanotez = + Q.mul + minimal_nanotez_per_gas_unit + (Q.of_bigint @@ Gas.Arith.integral_to_z gas) + in + Q.compare minimal_fees_in_nanotez fees_in_nanotez <= 0 + in + let enough_fees_for_size = + let minimal_fees_in_nanotez = + Q.mul minimal_nanotez_per_byte (Q.of_int size) + in + Q.compare minimal_fees_in_nanotez fees_in_nanotez <= 0 + in + if enough_fees_for_size && enough_fees_for_gas then + Some (op, weight_ratio, source, counter) + else None) + operations + |> fun operations -> + (* We order the operations by their weights except if they belong + to the same manager, if they do, we order them by their + counter. *) + let compare (_op, weight_ratio, source, counter) + (_op', weight_ratio', source', counter') = + (* Be careful with the [compare]s *) + if Signature.Public_key_hash.equal source source' then + (* we want the smallest counter first *) + Z.compare counter counter' + else + (* We want the biggest weight first *) + Q.compare weight_ratio' weight_ratio + in + List.sort compare operations |> List.map (fun (op, _, _, _) -> op) + +let retain_operations_up_to_quota operations quota = + let {Tezos_protocol_environment.max_op; max_size} = quota in + let operations = + match max_op with Some n -> List.sub operations n | None -> operations + in + let exception Full of packed_operation list in + let operations = + try + List.fold_left + (fun (ops, size) op -> + let operation_size = + Data_encoding.Binary.length Alpha_context.Operation.encoding op + in + let new_size = size + operation_size in + if new_size > max_size then raise (Full ops) else (op :: ops, new_size)) + ([], 0) + operations + |> fst + with Full ops -> ops + in + List.rev operations + +let trim_manager_operations ~max_size ~hard_gas_limit_per_block + manager_operations = + let manager_operations = + List.filter_map + (fun op -> + match get_manager_content op with + | Some {total_gas; _} -> + let size = Data_encoding.Binary.length Operation.encoding op in + Some (op, (size, total_gas)) + | None -> None) + manager_operations + in + List.fold_left + (fun (total_size, total_gas, (good_ops, bad_ops)) (op, (size, gas)) -> + let new_size = total_size + size in + let new_gas = Gas.Arith.(add total_gas gas) in + if new_size > max_size || Gas.Arith.(new_gas > hard_gas_limit_per_block) + then (total_size, total_gas, (good_ops, op :: bad_ops)) + else (new_size, new_gas, (op :: good_ops, bad_ops))) + (0, Gas.Arith.zero, ([], [])) + manager_operations + |> fun (_, _, (good_ops, bad_ops)) -> + (* We keep the overflowing operations, it may be used for client-side validation *) + (List.rev good_ops, List.rev bad_ops) + +(* We classify operations, sort managers operation by interest and add bad ones at the end *) +(* Hypothesis : we suppose that the received manager operations have a valid gas_limit *) + +(** [classify_operations] classify the operation in 4 lists indexed as such : + - 0 -> Endorsements + - 1 -> Votes and proposals + - 2 -> Anonymous operations + - 3 -> High-priority manager operations. + Returns two list : + - A desired set of operations to be included + - Potentially overflowing operations *) +let classify_operations (cctxt : #Protocol_client_context.full) ~chain ~block + ~hard_gas_limit_per_block ~minimal_fees ~minimal_nanotez_per_gas_unit + ~minimal_nanotez_per_byte (ops : packed_operation list) = + Alpha_block_services.live_blocks cctxt ~chain ~block () + >>=? fun live_blocks -> + let t = + (* Remove operations that are too old *) + let ops = + List.filter + (fun {shell = {branch; _}; _} -> Block_hash.Set.mem branch live_blocks) + ops + in + let validation_passes_len = List.length Main.validation_passes in + let t = Array.make validation_passes_len [] in + List.iter + (fun (op : packed_operation) -> + List.iter + (fun pass -> t.(pass) <- op :: t.(pass)) + (Main.acceptable_passes op)) + ops ; + Array.map List.rev t + in + let overflowing_manager_operations = + (* Retrieve the optimist maximum paying manager operations *) + let manager_operations = t.(managers_index) in + let {Environment.Updater.max_size; _} = + WithExceptions.Option.get ~loc:__LOC__ + @@ List.nth Main.validation_passes managers_index + in + let ordered_operations = + sort_manager_operations + ~max_size + ~hard_gas_limit_per_block + ~minimal_fees + ~minimal_nanotez_per_gas_unit + ~minimal_nanotez_per_byte + manager_operations + in + (* Greedy heuristic *) + let (desired_manager_operations, overflowing_manager_operations) = + trim_manager_operations + ~max_size + ~hard_gas_limit_per_block + ordered_operations + in + t.(managers_index) <- desired_manager_operations ; + ok overflowing_manager_operations + in + Lwt.return + ( overflowing_manager_operations >>? fun overflowing_manager_operations -> + ok (Array.to_list t, overflowing_manager_operations) ) + +let forge (op : Operation.packed) : Operation.raw = + { + shell = op.shell; + proto = + Data_encoding.Binary.to_bytes_exn + Alpha_context.Operation.protocol_data_encoding + op.protocol_data; + } + +let ops_of_mempool (ops : Alpha_block_services.Mempool.t) = + (* We only retain the applied, unprocessed and delayed operations *) + List.rev + (Operation_hash.Map.fold (fun _ op acc -> op :: acc) ops.unprocessed + @@ Operation_hash.Map.fold + (fun _ (op, _) acc -> op :: acc) + ops.branch_delayed + @@ List.rev_map (fun (_, op) -> op) ops.applied) + +let unopt_operations cctxt chain mempool = function + | None -> ( + match mempool with + | None -> + Alpha_block_services.Mempool.pending_operations cctxt ~chain () + >>=? fun mpool -> + let ops = ops_of_mempool mpool in + return ops + | Some file -> + Tezos_stdlib_unix.Lwt_utils_unix.Json.read_file file >>=? fun json -> + let mpool = + Data_encoding.Json.destruct + Alpha_block_services.S.Mempool.encoding + json + in + let ops = ops_of_mempool mpool in + return ops) + | Some operations -> return operations + +let all_ops_valid (results : error Preapply_result.t list) = + let open Operation_hash.Map in + List.for_all + (fun (result : error Preapply_result.t) -> + is_empty result.refused + && is_empty result.branch_refused + && is_empty result.branch_delayed) + results + +let decode_priority cctxt chain block ~priority ~endorsing_power = + match priority with + | `Set priority -> + Alpha_services.Delegate.Minimal_valid_time.get + cctxt + (chain, block) + priority + endorsing_power + >>=? fun minimal_timestamp -> return (priority, minimal_timestamp) + | `Auto (src_pkh, max_priority) -> ( + Plugin.RPC.current_level cctxt ~offset:1l (chain, block) + >>=? fun {level; _} -> + Plugin.RPC.Baking_rights.get + cctxt + ?max_priority + ~levels:[level] + ~delegates:[src_pkh] + (chain, block) + >>=? fun possibilities -> + match + List.find + (fun p -> p.Plugin.RPC.Baking_rights.level = level) + possibilities + with + | Some {Plugin.RPC.Baking_rights.priority = prio; _} -> + Alpha_services.Delegate.Minimal_valid_time.get + cctxt + (chain, block) + prio + endorsing_power + >>=? fun minimal_timestamp -> return (prio, minimal_timestamp) + | None -> failwith "No slot found at level %a" Raw_level.pp level) + +let unopt_timestamp ?(force = false) timestamp minimal_timestamp = + let timestamp = + match timestamp with + | None -> minimal_timestamp + | Some timestamp -> timestamp + in + if (not force) && timestamp < minimal_timestamp then + failwith + "Proposed timestamp %a is earlier than minimal timestamp %a" + Time.Protocol.pp_hum + timestamp + Time.Protocol.pp_hum + minimal_timestamp + else return timestamp + +let merge_preapps (old : error Preapply_result.t) + (neu : error Preapply_result.t) = + let merge _ a b = (* merge ops *) Option.either b a in + let merge = (* merge op maps *) Operation_hash.Map.merge merge in + (* merge preapplies *) + { + Preapply_result.applied = []; + refused = merge old.refused neu.refused; + branch_refused = merge old.branch_refused neu.branch_refused; + branch_delayed = merge old.branch_delayed neu.branch_delayed; + } + +let error_of_op (result : error Preapply_result.t) op = + let op = forge op in + let h = Tezos_base.Operation.hash op in + match Operation_hash.Map.find h result.refused with + | Some (_, trace) -> Some (Failed_to_preapply (op, trace)) + | None -> ( + match Operation_hash.Map.find h result.branch_refused with + | Some (_, trace) -> Some (Failed_to_preapply (op, trace)) + | None -> ( + match Operation_hash.Map.find h result.branch_delayed with + | Some (_, trace) -> Some (Failed_to_preapply (op, trace)) + | None -> None)) + +let compute_endorsement_powers cctxt constants ~chain ~block = + Plugin.RPC.Endorsing_rights.get + cctxt + ~levels:[block.Client_baking_blocks.level] + (chain, `Hash (block.hash, 0)) + >>=? fun endorsing_rights -> + let slots_arr = Array.make constants.Constants.endorsers_per_block 0 in + (* Populate the array *) + List.iter + (fun {Plugin.RPC.Endorsing_rights.slots; _} -> + let endorsing_power = List.length slots in + List.iter (fun slot -> slots_arr.(slot) <- endorsing_power) slots) + endorsing_rights ; + return slots_arr + +let compute_endorsing_power endorsement_powers operations = + List.fold_left + (fun sum -> function + | { + Alpha_context.protocol_data = + Operation_data + {contents = Single (Endorsement_with_slot {slot; _}); _}; + _; + } -> ( + try + let endorsement_power = endorsement_powers.(slot) in + sum + endorsement_power + with _ -> sum) + | _ -> sum) + 0 + operations + +let compute_minimal_valid_time constants ~priority ~endorsing_power + ~predecessor_timestamp = + Environment.wrap_tzresult + (Baking.minimal_valid_time + constants + ~priority + ~endorsing_power + ~predecessor_timestamp) + +let filter_and_apply_operations cctxt state endorsements_map ~chain ~block + block_info ~priority ?protocol_data + ((operations : packed_operation list list), _overflowing_operations) = + (* Retrieve the minimal valid time for when the block can be baked with 0 endorsements *) + Delegate_services.Minimal_valid_time.get cctxt (chain, block) priority 0 + >>=? fun min_valid_timestamp -> + let open Client_baking_simulator in + Events.(emit baking_local_validation_start) + block_info.Client_baking_blocks.hash + >>= fun () -> + let quota : Environment.Updater.quota list = Main.validation_passes in + let endorsements = + retain_operations_up_to_quota + (WithExceptions.Option.get + ~loc:__LOC__ + (List.nth operations endorsements_index)) + (WithExceptions.Option.get ~loc:__LOC__ + @@ List.nth quota endorsements_index) + in + let votes = + retain_operations_up_to_quota + (WithExceptions.Option.get ~loc:__LOC__ @@ List.nth operations votes_index) + (WithExceptions.Option.get ~loc:__LOC__ @@ List.nth quota votes_index) + in + let anonymous = + retain_operations_up_to_quota + (WithExceptions.Option.get ~loc:__LOC__ + @@ List.nth operations anonymous_index) + (WithExceptions.Option.get ~loc:__LOC__ @@ List.nth quota anonymous_index) + in + let managers = + (* Managers are already trimmed *) + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth operations managers_index + in + (begin_construction + ~timestamp:min_valid_timestamp + ?protocol_data + state.index + block_info + >>= function + | Ok inc -> return inc + | Error errs -> + Events.(emit context_fetch_error) errs >>= fun () -> + Events.(emit reopen_context) () >>= fun () -> + Client_baking_simulator.load_context ~context_path:state.context_path + >>= fun index -> + begin_construction + ~timestamp:min_valid_timestamp + ?protocol_data + index + block_info + >>=? fun inc -> + state.index <- index ; + return inc) + >>=? fun initial_inc -> + let validate_operation inc op = + protect (fun () -> add_operation inc op) >>= function + | Error errs -> + Events.(emit baking_rejected_invalid_operation) + (Operation.hash_packed op, errs) + >>= fun () -> Lwt.return_none + | Ok (resulting_state, receipt) -> ( + try + (* Check that the metadata are serializable/deserializable *) + let _ = + Data_encoding.Binary.( + of_bytes_exn + Protocol.operation_receipt_encoding + (to_bytes_exn Protocol.operation_receipt_encoding receipt)) + in + Lwt.return_some resulting_state + with exn -> + let errs = + [Validation_errors.Cannot_serialize_operation_metadata; Exn exn] + in + Events.(emit baking_rejected_invalid_operation) + (Operation.hash_packed op, errs) + >>= fun () -> Lwt.return_none) + in + let filter_valid_operations inc ops = + List.fold_left_s + (fun (inc, acc) op -> + validate_operation inc op >>= function + | None -> Lwt.return (inc, acc) + | Some inc' -> Lwt.return (inc', op :: acc)) + (inc, []) + ops + >>= fun (inc, ops) -> Lwt.return (inc, List.rev ops) + in + (* Apply operations and filter the invalid ones *) + filter_valid_operations initial_inc endorsements + >>= fun (inc, endorsements) -> + filter_valid_operations inc votes >>= fun (inc, votes) -> + filter_valid_operations inc anonymous >>= fun (manager_inc, anonymous) -> + filter_valid_operations manager_inc managers >>= fun (inc, managers) -> + finalize_construction inc >>=? fun _ -> + let operations = [endorsements; votes; anonymous; managers] in + (* Construct a context with the valid operations and a correct timestamp *) + let current_endorsing_power = + compute_endorsing_power endorsements_map endorsements + in + compute_minimal_valid_time + state.constants.parametric + ~priority + ~endorsing_power:current_endorsing_power + ~predecessor_timestamp:block_info.timestamp + >>?= fun expected_validity -> + (* Finally, we construct a block with the minimal possible timestamp + given the endorsing power *) + begin_construction + ~timestamp:expected_validity + ?protocol_data + state.index + block_info + >>=? fun inc -> + List.fold_left_es + (fun inc op -> add_operation inc op >>=? fun (inc, _receipt) -> return inc) + inc + (List.flatten operations) + >>=? fun final_inc -> + let operations_hash : Operation_list_list_hash.t = + Operation_list_list_hash.compute + (List.map + (fun sl -> + Operation_list_hash.compute (List.map Operation.hash_packed sl)) + operations) + in + let validation_passes = List.length Main.validation_passes in + let final_inc = + { + final_inc with + header = + { + final_inc.header with + operations_hash; + validation_passes; + level = Int32.succ final_inc.header.level; + }; + } + in + finalize_construction final_inc >>=? fun (validation_result, metadata) -> + return + (final_inc, (validation_result, metadata), operations, expected_validity) + +(* Build the block header : mimics node prevalidation *) +let finalize_block_header shell_header ~timestamp validation_result + predecessor_block_metadata_hash predecessor_ops_metadata_hash = + let {Tezos_protocol_environment.context; fitness; message; _} = + validation_result + in + let header = + Tezos_base.Block_header. + {shell_header with fitness; context = Context_hash.zero} + in + let context = Shell_context.unwrap_disk_context context in + (match predecessor_block_metadata_hash with + | Some predecessor_block_metadata_hash -> + Context.add_predecessor_block_metadata_hash + context + predecessor_block_metadata_hash + | None -> Lwt.return context) + >>= fun context -> + (match predecessor_ops_metadata_hash with + | Some predecessor_ops_metadata_hash -> + Context.add_predecessor_ops_metadata_hash + context + predecessor_ops_metadata_hash + | None -> Lwt.return context) + >>= fun context -> + let context = Context.hash ~time:timestamp ?message context in + return {header with context} + +let forge_block cctxt ?force ?operations ?(best_effort = operations = None) + ?(sort = best_effort) ?(minimal_fees = default_minimal_fees) + ?(minimal_nanotez_per_gas_unit = default_minimal_nanotez_per_gas_unit) + ?(minimal_nanotez_per_byte = default_minimal_nanotez_per_byte) ?timestamp + ?mempool ?context_path ?seed_nonce_hash ~liquidity_baking_escape_vote ~chain + ~priority ~delegate_pkh ~delegate_sk block = + Alpha_services.Constants.all cctxt (chain, block) >>=? fun constants -> + (* making the arguments usable *) + unopt_operations cctxt chain mempool operations >>=? fun operations_arg -> + Client_baking_blocks.info cctxt ~chain block >>=? fun block_info -> + compute_endorsement_powers cctxt constants.parametric ~chain ~block:block_info + >>=? fun endorsement_powers -> + let endorsing_power = + compute_endorsing_power endorsement_powers operations_arg + in + decode_priority cctxt chain block ~priority ~endorsing_power + >>=? fun (priority, minimal_timestamp) -> + unopt_timestamp ?force timestamp minimal_timestamp >>=? fun timestamp -> + (* get basic building blocks *) + let protocol_data = + forge_faked_protocol_data + ~priority + ~seed_nonce_hash + ~liquidity_baking_escape_vote + in + classify_operations + cctxt + ~chain + ~hard_gas_limit_per_block:constants.parametric.hard_gas_limit_per_block + ~block + ~minimal_fees + ~minimal_nanotez_per_gas_unit + ~minimal_nanotez_per_byte + operations_arg + >>=? fun (operations, overflowing_ops) -> + (* Ensure that we retain operations up to the quota *) + let quota : Environment.Updater.quota list = Main.validation_passes in + let endorsements = + List.sub + (WithExceptions.Option.get ~loc:__LOC__ + @@ List.nth operations endorsements_index) + constants.parametric.endorsers_per_block + in + let votes = + retain_operations_up_to_quota + (WithExceptions.Option.get ~loc:__LOC__ @@ List.nth operations votes_index) + (WithExceptions.Option.get ~loc:__LOC__ @@ List.nth quota votes_index) + in + let anonymous = + retain_operations_up_to_quota + (WithExceptions.Option.get ~loc:__LOC__ + @@ List.nth operations anonymous_index) + (WithExceptions.Option.get ~loc:__LOC__ @@ List.nth quota anonymous_index) + in + (* Size/Gas check already occurred in classify operations *) + let managers = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth operations managers_index + in + let operations = [endorsements; votes; anonymous; managers] in + (match context_path with + | None -> + Alpha_block_services.Helpers.Preapply.block + cctxt + ~chain + ~block + ~timestamp + ~sort + ~protocol_data + operations + >>=? fun (shell_header, result) -> + let operations = + List.map (fun l -> List.map snd l.Preapply_result.applied) result + in + (* everything went well (or we don't care about errors): GO! *) + if best_effort || all_ops_valid result then + return (shell_header, operations) + (* some errors (and we care about them) *) + else + let result = + List.fold_left merge_preapps Preapply_result.empty result + in + Lwt.return_error @@ List.filter_map (error_of_op result) operations_arg + | Some context_path -> + assert sort ; + assert best_effort ; + Context.init ~readonly:true context_path >>= fun index -> + Client_baking_files.resolve_location cctxt ~chain `Nonce + >>=? fun nonces_location -> + let state = + { + context_path; + index; + nonces_location; + constants; + delegates = []; + best_slot = None; + minimal_fees = default_minimal_fees; + minimal_nanotez_per_gas_unit = default_minimal_nanotez_per_gas_unit; + minimal_nanotez_per_byte = default_minimal_nanotez_per_byte; + retry_counter = default_retry_counter; + } + in + compute_endorsement_powers + cctxt + constants.parametric + ~chain + ~block:block_info + >>=? fun endorsement_powers -> + filter_and_apply_operations + cctxt + state + endorsement_powers + ~chain + ~block + ~priority + ~protocol_data + block_info + (operations, overflowing_ops) + >>=? fun ( final_context, + (validation_result, _), + operations, + min_valid_timestamp ) -> + let current_protocol = block_info.next_protocol in + let context = + Shell_context.unwrap_disk_context validation_result.context + in + Context.get_protocol context >>= fun next_protocol -> + if Protocol_hash.equal current_protocol next_protocol then + finalize_block_header + final_context.header + ~timestamp:min_valid_timestamp + validation_result + block_info.predecessor_block_metadata_hash + block_info.predecessor_operations_metadata_hash + >>= function + | Error _ as errs -> Lwt.return errs + | Ok shell_header -> + return (shell_header, List.map (List.map forge) operations) + else + Events.(emit shell_prevalidation_new_protocol) () >>= fun () -> + Alpha_block_services.Helpers.Preapply.block + cctxt + ~chain + ~block + ~timestamp:min_valid_timestamp + ~sort + ~protocol_data + operations + >>=? fun (shell_header, _result) -> + return (shell_header, List.map (List.map forge) operations)) + >>=? fun (shell_header, operations) -> + (* Now for some logging *) + let total_op_count = List.length operations_arg in + let valid_op_count = List.length (List.concat operations) in + let time = Time.System.of_protocol_exn timestamp in + Events.(emit found_valid_operations) + (valid_op_count, total_op_count - valid_op_count, time, shell_header.fitness) + >>= fun () -> + (match Raw_level.of_int32 shell_header.level with + | Ok level -> return level + | Error errs -> + let errs = Environment.wrap_tztrace errs in + Events.(emit block_conversion_failed) errs >>= fun () -> + Lwt.return_error errs) + >>=? fun level -> + inject_block + cctxt + ?force + ~chain + ~shell_header + ~priority + ?seed_nonce_hash + ~delegate_pkh + ~delegate_sk + ~level + operations + ~liquidity_baking_escape_vote + >>= function + | Ok hash -> return hash + | Error errs as error -> + Events.(emit block_injection_failed) (List.concat operations, errs) + >>= fun () -> Lwt.return error + +let shell_prevalidation (cctxt : #Protocol_client_context.full) ~chain ~block + ~timestamp seed_nonce_hash operations + ((_, (bi, priority, delegate)) as _slot) = + let liquidity_baking_escape_vote = false in + let protocol_data = + forge_faked_protocol_data + ~priority + ~seed_nonce_hash + ~liquidity_baking_escape_vote + in + Alpha_block_services.Helpers.Preapply.block + cctxt + ~chain + ~block + ~timestamp + ~sort:true + ~protocol_data + operations + >>= function + | Error errs -> + Events.(emit built_invalid_block_error) errs >>= fun () -> return_none + | Ok (shell_header, operations) -> + let raw_ops = + List.map (fun l -> List.map snd l.Preapply_result.applied) operations + in + return_some + (bi, priority, shell_header, raw_ops, delegate, seed_nonce_hash) + +let extract_op_and_filter_outdated_endorsements expected_level ops = + List.filter_map + (function + | ( ( _, + ({ + Alpha_context.protocol_data = + Operation_data + { + contents = + Single + (Endorsement_with_slot + { + endorsement = + { + protocol_data = + { + contents = Single (Endorsement {level; _}); + _; + }; + _; + }; + _; + }); + _; + }; + _; + } as op) ), + _ ) -> + if Raw_level.equal expected_level level then Some op else None + | ((_, op), _) -> Some op) + ops + +(** [fetch_operations] retrieve the operations present in the + mempool. If no endorsements are present in the initial set, it + waits until it's able to build a valid block. *) +let fetch_operations (cctxt : #Protocol_client_context.full) ~chain state + endorsement_powers (_, (head, priority, _delegate)) = + Alpha_block_services.Mempool.monitor_operations + cctxt + ~chain + ~applied:true + ~branch_delayed:false + ~refused:false + ~branch_refused:false + () + >>=? fun (operation_stream, _stop) -> + let notify_endorsement_arrival operations = + List.iter_s + (function + | { + Alpha_context.protocol_data = + Operation_data + {contents = Single (Endorsement_with_slot {slot; _}); _}; + _; + } -> ( + try + let endorsing_power = endorsement_powers.(slot) in + Events.(emit endorsement_received (slot, endorsing_power)) + with _ -> Lwt.return_unit) + | _ -> Lwt.return_unit) + operations + in + (* Hypothesis : the first call to the stream returns instantly, even if the mempool is empty. *) + Lwt_stream.get operation_stream >>= function + | None -> + (* New head received : aborting block construction *) + return_none + | Some current_mempool -> + let operations = + ref + (extract_op_and_filter_outdated_endorsements + head.Client_baking_blocks.level + current_mempool) + in + notify_endorsement_arrival !operations >>= fun () -> + let current_endorsing_power = + ref (compute_endorsing_power endorsement_powers !operations) + in + let previous_endorsing_power = ref 0 in + let previous_expected_validity_time = ref None in + (* Actively request our peers' for missing operations *) + Shell_services.Mempool.request_operations cctxt ~chain () >>=? fun () -> + let compute_timeout () = + let compute_minimal_valid_time () = + compute_minimal_valid_time + state.constants.parametric + ~priority + ~endorsing_power:!current_endorsing_power + ~predecessor_timestamp:head.timestamp + >>?= fun expected_validity -> + Events.( + emit + expected_validity_time + (expected_validity, !current_endorsing_power)) + >>= fun () -> return expected_validity + in + (match !previous_expected_validity_time with + | None -> compute_minimal_valid_time () + | Some _ + when Compare.Int.( + !current_endorsing_power > !previous_endorsing_power) -> + compute_minimal_valid_time () + | Some previous_expected_validity_time -> + return previous_expected_validity_time) + >>=? fun expected_validity -> + previous_expected_validity_time := Some expected_validity ; + match Client_baking_scheduling.sleep_until expected_validity with + | None -> return_unit + | Some timeout -> timeout >>= fun () -> return_unit + in + let last_get_event = ref None in + let get_event () = + match !last_get_event with + | None -> + let t = Lwt_stream.get operation_stream in + last_get_event := Some t ; + t + | Some t -> t + in + let rec loop () = + Lwt.choose + [ + (compute_timeout () >|= fun _ -> `Timeout); + (get_event () >|= fun e -> `Event e); + ] + >>= function + | `Event (Some op_list) -> + last_get_event := None ; + let op_list = + extract_op_and_filter_outdated_endorsements head.level op_list + in + notify_endorsement_arrival op_list >>= fun () -> + let added_endorsing_power = + compute_endorsing_power endorsement_powers op_list + in + current_endorsing_power := + added_endorsing_power + !current_endorsing_power ; + operations := op_list @ !operations ; + loop () + | `Timeout -> + (* Retrieve the remaining operations present in the stream + before block construction *) + let remaining_operations = + extract_op_and_filter_outdated_endorsements + head.level + (List.flatten (Lwt_stream.get_available operation_stream)) + in + operations := remaining_operations @ !operations ; + compute_minimal_valid_time + state.constants.parametric + ~priority + ~endorsing_power:!current_endorsing_power + ~predecessor_timestamp:head.timestamp + >>?= fun expected_validity -> + return_some (!operations, expected_validity) + | `Event None -> + (* Got new head while waiting: + - not enough endorsements received ; + - late at baking *) + return_none + in + loop () + +(** Given a delegate baking slot [build_block] constructs a full block + with consistent operations that went through the client-side + validation *) +let build_block cctxt ~user_activated_upgrades state seed_nonce_hash + ((slot_timestamp, (bi, priority, delegate)) as slot) + ~liquidity_baking_escape_vote = + let chain = `Hash bi.Client_baking_blocks.chain_id in + let block = `Hash (bi.hash, 0) in + Plugin.RPC.current_level cctxt ~offset:1l (chain, block) + >>=? fun next_level -> + let seed_nonce_hash = + if next_level.expected_commitment then Some seed_nonce_hash else None + in + Client_keys.Public_key_hash.name cctxt delegate >>=? fun name -> + let time = Time.System.of_protocol_exn slot_timestamp in + Events.(emit try_baking) (bi.hash, priority, name, time) >>= fun () -> + compute_endorsement_powers cctxt state.constants.parametric ~chain ~block:bi + >>=? fun endorsement_powers -> + fetch_operations cctxt ~chain state endorsement_powers slot >>=? function + | None -> Events.(emit new_head_received) () >>= fun () -> return_none + | Some (operations, timestamp) -> ( + classify_operations + cctxt + ~chain + ~hard_gas_limit_per_block: + state.constants.parametric.hard_gas_limit_per_block + ~minimal_fees:state.minimal_fees + ~minimal_nanotez_per_gas_unit:state.minimal_nanotez_per_gas_unit + ~minimal_nanotez_per_byte:state.minimal_nanotez_per_byte + ~block + operations + >>=? fun (operations, overflowing_ops) -> + let next_version = + match + Tezos_base.Block_header.get_forced_protocol_upgrade + ~user_activated_upgrades + ~level:(Raw_level.to_int32 next_level.level) + with + | None -> bi.next_protocol + | Some hash -> hash + in + if Protocol_hash.(Protocol.hash <> next_version) then + (* Let the shell validate this *) + shell_prevalidation + cctxt + ~chain + ~block + ~timestamp + seed_nonce_hash + operations + slot + else + let protocol_data = + forge_faked_protocol_data + ~priority + ~seed_nonce_hash + ~liquidity_baking_escape_vote + in + filter_and_apply_operations + cctxt + state + endorsement_powers + ~chain + ~block + ~priority + ~protocol_data + bi + (operations, overflowing_ops) + >>= function + | Error errs -> + Events.(emit client_side_validation_error) errs >>= fun () -> + Events.(emit shell_prevalidation_notice) () >>= fun () -> + shell_prevalidation + cctxt + ~chain + ~block + ~timestamp + seed_nonce_hash + operations + slot + | Ok (final_context, (validation_result, _), operations, valid_timestamp) + -> + (if + Time.System.(Systime_os.now () < of_protocol_exn valid_timestamp) + then + Events.(emit waiting_before_injection) + (Systime_os.now (), Time.System.of_protocol_exn valid_timestamp) + >>= fun () -> + match Client_baking_scheduling.sleep_until valid_timestamp with + | None -> Lwt.return_unit + | Some timeout -> timeout + else Lwt.return_unit) + >>= fun () -> + Events.(emit try_forging) + (bi.hash, priority, name, Time.System.of_protocol_exn timestamp) + >>= fun () -> + let current_protocol = bi.next_protocol in + let context = + Shell_context.unwrap_disk_context validation_result.context + in + Context.get_protocol context >>= fun next_protocol -> + if Protocol_hash.equal current_protocol next_protocol then + finalize_block_header + final_context.header + ~timestamp:valid_timestamp + validation_result + bi.predecessor_block_metadata_hash + bi.predecessor_operations_metadata_hash + >>= function + | Error _ as errs -> Lwt.return errs + | Ok shell_header -> + let raw_ops = List.map (List.map forge) operations in + return_some + ( bi, + priority, + shell_header, + raw_ops, + delegate, + seed_nonce_hash ) + else + Events.(emit shell_prevalidation_new_protocol) () >>= fun () -> + shell_prevalidation + cctxt + ~chain + ~block + ~timestamp + seed_nonce_hash + operations + slot) + +type per_block_votes = {liquidity_baking_escape_vote : bool option} + +let per_block_votes_encoding = + let open Data_encoding in + def "per_block_votes.alpha" + @@ conv + (fun {liquidity_baking_escape_vote} -> liquidity_baking_escape_vote) + (fun liquidity_baking_escape_vote -> {liquidity_baking_escape_vote}) + (obj1 (opt "liquidity_baking_escape_vote" Data_encoding.bool)) + +type error += Block_vote_file_not_found of string + +type error += Block_vote_file_invalid of string + +type error += Block_vote_file_wrong_content of string + +type error += Block_vote_file_missing_liquidity_baking_escape_vote of string + +let () = + register_error_kind + `Permanent + ~id:"Client_baking_forge.block_vote_file_not_found" + ~title: + "The provided block vote file path does not point to an existing file." + ~description: + "A block vote file path was provided on the command line but the path \ + does not point to an existing file." + ~pp:(fun ppf file_path -> + Format.fprintf + ppf + "@[The provided block vote file path \"%s\" does not point to an \ + existing file.@]" + file_path) + Data_encoding.(obj1 (req "file_path" string)) + (function + | Block_vote_file_not_found file_path -> Some file_path | _ -> None) + (fun file_path -> Block_vote_file_not_found file_path) ; + register_error_kind + `Permanent + ~id:"Client_baking_forge.block_vote_file_invalid" + ~title: + "The provided block vote file path does not point to a valid JSON file." + ~description: + "A block vote file path was provided on the command line but the path \ + does not point to a valid JSON file." + ~pp:(fun ppf file_path -> + Format.fprintf + ppf + "@[The provided block vote file path \"%s\" does not point to a valid \ + JSON file. The file exists but its content is not valid JSON.@]" + file_path) + Data_encoding.(obj1 (req "file_path" string)) + (function Block_vote_file_invalid file_path -> Some file_path | _ -> None) + (fun file_path -> Block_vote_file_invalid file_path) ; + register_error_kind + `Permanent + ~id:"Client_baking_forge.block_vote_file_wrong_content" + ~title:"The content of the provided block vote file is unexpected." + ~description: + "The block vote file is valid JSON but its content is not the expected \ + one." + ~pp:(fun ppf file_path -> + Format.fprintf + ppf + "@[The provided block vote file \"%s\" is a valid JSON file but its \ + content is unexpected. Expecting a JSON file containing either \ + '{\"liquidity_baking_escape_vote\": true}' or \ + '{\"liquidity_baking_escape_vote\": false}'.@]" + file_path) + Data_encoding.(obj1 (req "file_path" string)) + (function + | Block_vote_file_wrong_content file_path -> Some file_path | _ -> None) + (fun file_path -> Block_vote_file_wrong_content file_path) ; + register_error_kind + `Permanent + ~id: + "Client_baking_forge.block_vote_file_missing_liquidity_baking_escape_vote" + ~title: + "In the provided block vote file, no entry for liquidity baking escape \ + vote was found" + ~description: + "In the provided block vote file, no entry for liquidity baking escape \ + vote was found." + ~pp:(fun ppf file_path -> + Format.fprintf + ppf + "@[In the provided block vote file \"%s\", the \ + \"liquidity_baking_escape_vote\" boolean field is missing. Expecting \ + a JSON file containing either '{\"liquidity_baking_escape_vote\": \ + true}' or '{\"liquidity_baking_escape_vote\": false}'.@]" + file_path) + Data_encoding.(obj1 (req "file_path" string)) + (function + | Block_vote_file_missing_liquidity_baking_escape_vote file_path -> + Some file_path + | _ -> None) + (fun file_path -> + Block_vote_file_missing_liquidity_baking_escape_vote file_path) + +let traced_option_to_result ~error = + Option.fold ~some:ok ~none:(Error_monad.error error) + +let check_file_exists file = + if Sys.file_exists file then Result.return_unit + else error (Block_vote_file_not_found file) + +let read_liquidity_baking_escape_vote ~per_block_vote_file = + Events.(emit reading_per_block) per_block_vote_file >>= fun () -> + check_file_exists per_block_vote_file >>?= fun () -> + trace (Block_vote_file_invalid per_block_vote_file) + @@ Lwt_utils_unix.Json.read_file per_block_vote_file + >>=? fun votes_json -> + Events.(emit per_block_vote_file_notice) "found" >>= fun () -> + trace (Block_vote_file_wrong_content per_block_vote_file) + @@ Error_monad.protect (fun () -> + return + @@ Data_encoding.Json.destruct per_block_votes_encoding votes_json) + >>=? fun votes -> + Events.(emit per_block_vote_file_notice) "JSON decoded" >>= fun () -> + traced_option_to_result + ~error: + (Block_vote_file_missing_liquidity_baking_escape_vote per_block_vote_file) + votes.liquidity_baking_escape_vote + >>?= fun liquidity_baking_escape_vote -> + Events.(emit reading_liquidity_baking) () >>= fun () -> + Events.(emit liquidity_baking_escape_vote) liquidity_baking_escape_vote + >>= fun () -> return liquidity_baking_escape_vote + +let read_liquidity_baking_escape_vote_no_fail ~per_block_vote_file = + read_liquidity_baking_escape_vote ~per_block_vote_file >>= function + | Ok vote -> Lwt.return vote + | Error errs -> + Events.(emit per_block_vote_file_fail) errs >>= fun () -> Lwt.return false + +(** [bake cctxt state] create a single block when woken up to do + so. All the necessary information is available in the + [state.best_slot]. *) +let bake ?per_block_vote_file (cctxt : #Protocol_client_context.full) + ~user_activated_upgrades ~chain state = + (match state.best_slot with + | None -> assert false (* unreachable *) + | Some slot -> return slot) + >>=? fun slot -> + let seed_nonce = generate_seed_nonce () in + let seed_nonce_hash = Nonce.hash seed_nonce in + Option.fold + ~none:(Lwt.return false) + ~some:(fun per_block_vote_file -> + read_liquidity_baking_escape_vote_no_fail ~per_block_vote_file) + per_block_vote_file + >>= fun liquidity_baking_escape_vote -> + build_block + cctxt + ~user_activated_upgrades + state + seed_nonce_hash + slot + ~liquidity_baking_escape_vote + >>=? function + | Some (head, priority, shell_header, operations, delegate, seed_nonce_hash) + -> ( + let level = Raw_level.succ head.level in + Client_keys.Public_key_hash.name cctxt delegate >>=? fun name -> + Events.(emit start_injecting_block) + ( priority, + shell_header.fitness, + name, + shell_header.predecessor, + delegate ) + >>= fun () -> + Client_keys.get_key cctxt delegate >>=? fun (_, _, delegate_sk) -> + inject_block + cctxt + ~chain + ~force:false + ~shell_header + ~priority + ?seed_nonce_hash + ~delegate_pkh:delegate + ~delegate_sk + ~level + operations + ~liquidity_baking_escape_vote + >>= function + | Error errs -> + Events.(emit block_injection_failed) (List.concat operations, errs) + >>= fun () -> return_unit + | Ok block_hash -> + Events.(emit injected_block) + ( block_hash, + name, + shell_header.predecessor, + level, + priority, + shell_header.fitness, + List.concat operations ) + >>= fun () -> + (if seed_nonce_hash <> None then + cctxt#with_lock (fun () -> + let open Client_baking_nonces in + load cctxt state.nonces_location >>=? fun nonces -> + let nonces = add nonces block_hash seed_nonce in + save cctxt state.nonces_location nonces) + |> trace_exn (Failure "Error while recording nonce") + else return_unit) + >>=? fun () -> return_unit) + | None -> return_unit + +(** [get_baking_slots] calls the node via RPC to retrieve the potential + slots for the given delegates within a given range of priority *) +let get_baking_slots cctxt ?(max_priority = default_max_priority) new_head + delegates = + let chain = `Hash new_head.Client_baking_blocks.chain_id in + let block = `Hash (new_head.hash, 0) in + let level = Raw_level.succ new_head.level in + Plugin.RPC.Baking_rights.get + cctxt + ~max_priority + ~levels:[level] + ~delegates + (chain, block) + >>= function + | Error errs -> + Events.(emit baking_slot_fetch_errors) errs >>= fun () -> Lwt.return_nil + | Ok [] -> Lwt.return_nil + | Ok slots -> + let slots = + List.filter_map + (function + | {Plugin.RPC.Baking_rights.timestamp = None; _} -> None + | {timestamp = Some timestamp; priority; delegate; _} -> + Some (timestamp, (new_head, priority, delegate))) + slots + in + Lwt.return slots + +(** [compute_best_slot_on_current_level] retrieves, among the given + delegates, the highest priority slot for the current level. Then, + it registers this slot in the state so the timeout knows when to + wake up. *) +let compute_best_slot_on_current_level ?max_priority + (cctxt : #Protocol_client_context.full) state new_head = + get_delegates cctxt state >>=? fun delegates -> + let level = Raw_level.succ new_head.Client_baking_blocks.level in + get_baking_slots cctxt ?max_priority new_head delegates >>= function + | [] -> + let max_priority = + Option.value ~default:default_max_priority max_priority + in + Events.(emit no_slot_found) (level, max_priority) >>= fun () -> + return_none + (* No slot found *) + | h :: t -> + (* One or more slot found, fetching the best (lowest) priority. + We do not suppose that the received slots are sorted. *) + let ((timestamp, (_, priority, delegate)) as best_slot) = + List.fold_left + (fun ((_, (_, priority, _)) as acc) ((_, (_, priority', _)) as slot) -> + if priority < priority' then acc else slot) + h + t + in + Client_keys.Public_key_hash.name cctxt delegate >>=? fun name -> + let time = Time.System.of_protocol_exn timestamp in + Events.(emit have_baking_slot) + (level, priority, time, name, new_head.hash, delegate) + >>= fun () -> + (* Found at least a slot *) + return_some best_slot + +(** [reveal_potential_nonces] reveal registered nonces *) +let reveal_potential_nonces (cctxt : #Client_context.full) constants ~chain + ~block = + cctxt#with_lock (fun () -> + Client_baking_files.resolve_location cctxt ~chain `Nonce + >>=? fun nonces_location -> + Client_baking_nonces.load cctxt nonces_location >>= function + | Error err -> Events.(emit read_nonce_fail) err >>= fun () -> return_unit + | Ok nonces -> ( + Client_baking_nonces.get_unrevealed_nonces + cctxt + nonces_location + nonces + >>= function + | Error err -> + Events.(emit nonce_retrieval_fail) err >>= fun () -> return_unit + | Ok [] -> return_unit + | Ok nonces_to_reveal -> ( + Client_baking_revelation.inject_seed_nonce_revelation + cctxt + ~chain + ~block + nonces_to_reveal + >>= function + | Error err -> + Events.(emit nonce_injection_fail) err >>= fun () -> + return_unit + | Ok () -> + (* If some nonces are to be revealed it means: + - We entered a new cycle and we can clear old nonces ; + - A revelation was not included yet in the cycle beginning. + So, it is safe to only filter outdated_nonces there *) + Client_baking_nonces.filter_outdated_nonces + cctxt + ~constants + nonces_location + nonces + >>=? fun live_nonces -> + Client_baking_nonces.save cctxt nonces_location live_nonces + >>=? fun () -> return_unit))) + +(** [create] starts the main loop of the baker. The loop monitors new blocks and + starts individual baking operations when baking-slots are available to any of + the [delegates] *) +let create (cctxt : #Protocol_client_context.full) ~user_activated_upgrades + ?minimal_fees ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte + ?max_priority ?per_block_vote_file ~chain ~context_path delegates + block_stream = + let state_maker bi = + Alpha_services.Constants.all cctxt (chain, `Head 0) >>=? fun constants -> + Client_baking_simulator.load_context ~context_path >>= fun index -> + Client_baking_simulator.check_context_consistency + index + bi.Client_baking_blocks.context + >>=? fun () -> + Client_baking_files.resolve_location cctxt ~chain `Nonce + >>=? fun nonces_location -> + let state = + create_state + ?minimal_fees + ?minimal_nanotez_per_gas_unit + ?minimal_nanotez_per_byte + context_path + index + nonces_location + delegates + constants + in + return state + in + let event_k cctxt state new_head = + reveal_potential_nonces + cctxt + state.constants + ~chain + ~block:(`Hash (new_head.Client_baking_blocks.hash, 0)) + >>= fun _ignore_nonce_err -> + compute_best_slot_on_current_level ?max_priority cctxt state new_head + >>=? fun slot -> + state.best_slot <- slot ; + return_unit + in + let compute_timeout state = + match state.best_slot with + | None -> + (* No slot, just wait for new blocks which will give more info *) + Lwt_utils.never_ending () + | Some (timestamp, _) -> ( + match Client_baking_scheduling.sleep_until timestamp with + | None -> Lwt.return_unit + | Some timeout -> timeout) + in + let timeout_k cctxt state () = + bake ?per_block_vote_file cctxt ~user_activated_upgrades ~chain state + >>= function + | Error err -> + if state.retry_counter = 0 then ( + (* Stop the timeout and wait for the next block *) + state.best_slot <- None ; + state.retry_counter <- default_retry_counter ; + Lwt.return (Error err)) + else + Events.(emit retrying_on_error) err >>= fun () -> + state.retry_counter <- pred state.retry_counter ; + return_unit + | Ok () -> + (* Stop the timeout and wait for the next block *) + state.best_slot <- None ; + state.retry_counter <- default_retry_counter ; + return_unit + in + let finalizer state = Context.close state.index in + Option.fold + ~none:return_unit + ~some:(fun per_block_vote_file -> + read_liquidity_baking_escape_vote ~per_block_vote_file + >>=? fun liquidity_baking_escape_vote -> + (if liquidity_baking_escape_vote then + Events.(emit liquidity_baking_escape) () + else Events.(emit liquidity_baking_continue) ()) + >>= fun () -> return_unit) + per_block_vote_file + >>=? fun () -> + Client_baking_scheduling.main + ~name:"baker" + ~cctxt + ~stream:block_stream + ~state_maker + ~pre_loop:event_k + ~compute_timeout + ~timeout_k + ~event_k + ~finalizer diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_forge.mli b/src/proto_011_PtHangzH/lib_delegate/client_baking_forge.mli new file mode 100644 index 000000000000..28bd86c529b5 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_forge.mli @@ -0,0 +1,110 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +(** [generate_seed_nonce ()] is a random nonce that is typically used + in block headers. When baking, bakers generate random nonces whose + hash is committed in the block they bake. They will typically + reveal the aforementioned nonce during the next cycle. *) +val generate_seed_nonce : unit -> Nonce.t + +(** [inject_block cctxt blk ?force ~priority ~timestamp ~fitness + ~seed_nonce ~src_sk ops liquidity_baking_escape_vote] + tries to inject a block in the node. If + [?force] is set, the fitness check will be bypassed. [priority] + will be used to compute the baking slot (level is + precomputed). [src_sk] is used to sign the block header. *) +val inject_block : + #Protocol_client_context.full -> + ?force:bool -> + ?seed_nonce_hash:Nonce_hash.t -> + chain:Chain_services.chain -> + shell_header:Block_header.shell_header -> + priority:int -> + delegate_pkh:Signature.Public_key_hash.t -> + delegate_sk:Client_keys.sk_uri -> + level:Raw_level.t -> + Operation.raw list list -> + liquidity_baking_escape_vote:bool -> + Block_hash.t tzresult Lwt.t + +type error += Failed_to_preapply of Tezos_base.Operation.t * error list + +(** [forge_block cctxt ?fee_threshold ?force ?operations ?best_effort + ?sort ?timestamp ?max_priority ?priority ~seed_nonce ~src_sk + pk_hash parent_blk] injects a block in the node. In addition of inject_block, + it will: + + * Operations: If [?operations] is [None], it will get pending + operations and add them to the block. Otherwise, provided + operations will be used. In both cases, they will be validated. + + * Baking priority: If [`Auto] is used, it will be computed from + the public key hash of the specified contract, optionally capped + to a maximum value, and optionally restricting for free baking slot. + + * Timestamp: If [?timestamp] is set, and is compatible with the + computed baking priority, it will be used. Otherwise, it will be + set at the best baking priority. + + * Fee Threshold: If [?fee_threshold] is given, operations with fees lower than it + are not added to the block. +*) +val forge_block : + #Protocol_client_context.full -> + ?force:bool -> + ?operations:Operation.packed list -> + ?best_effort:bool -> + ?sort:bool -> + ?minimal_fees:Tez.t -> + ?minimal_nanotez_per_gas_unit:Q.t -> + ?minimal_nanotez_per_byte:Q.t -> + ?timestamp:Time.Protocol.t -> + ?mempool:string -> + ?context_path:string -> + ?seed_nonce_hash:Nonce_hash.t -> + liquidity_baking_escape_vote:bool -> + chain:Chain_services.chain -> + priority:[`Set of int | `Auto of public_key_hash * int option] -> + delegate_pkh:Signature.Public_key_hash.t -> + delegate_sk:Client_keys.sk_uri -> + Block_services.block -> + Block_hash.t tzresult Lwt.t + +val create : + #Protocol_client_context.full -> + user_activated_upgrades:User_activated.upgrades -> + ?minimal_fees:Tez.t -> + ?minimal_nanotez_per_gas_unit:Q.t -> + ?minimal_nanotez_per_byte:Q.t -> + ?max_priority:int -> + ?per_block_vote_file:string -> + chain:Chain_services.chain -> + context_path:string -> + public_key_hash list -> + Client_baking_blocks.block_info tzresult Lwt_stream.t -> + unit tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_highwatermarks.ml b/src/proto_011_PtHangzH/lib_delegate/client_baking_highwatermarks.ml new file mode 100644 index 000000000000..b3cf8a68e17f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_highwatermarks.ml @@ -0,0 +1,115 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol_client_context +open Protocol +open Alpha_context + +type error += Level_previously_endorsed of Raw_level.t + +type error += Level_previously_baked of Raw_level.t + +let () = + let open Data_encoding in + register_error_kind + `Permanent + ~id:"highwatermarks.block_already_baked" + ~title:"Block already baked" + ~description:"Trying to bake a block for a level that was previously done" + ~pp:(fun ppf level -> + Format.fprintf ppf "Level %a previously baked " Raw_level.pp level) + (obj1 (req "level" Raw_level.encoding)) + (function Level_previously_baked level -> Some level | _ -> None) + (fun level -> Level_previously_baked level) ; + register_error_kind + `Permanent + ~id:"highwatermarks.block_already_endorsed" + ~title:"Fail to preapply an operation" + ~description: + "Trying to endorse a block for a level that was previously done" + ~pp:(fun ppf level -> + Format.fprintf ppf "Level %a previously endorsed " Raw_level.pp level) + (obj1 (req "level" Raw_level.encoding)) + (function Level_previously_endorsed level -> Some level | _ -> None) + (fun level -> Level_previously_endorsed level) + +type t = (string * Raw_level.t) list + +let encoding = + let open Data_encoding in + def "highwatermarks" @@ assoc Raw_level.encoding + +let empty = [] + +(* We do not lock these functions. The caller will be already locked. *) +let load_highwatermarks (cctxt : #Protocol_client_context.full) filename : + t tzresult Lwt.t = + cctxt#load filename encoding ~default:empty + +let save_highwatermarks (cctxt : #Protocol_client_context.full) filename + highwatermarks : unit tzresult Lwt.t = + cctxt#write filename highwatermarks encoding + +let retrieve_highwatermark cctxt filename = load_highwatermarks cctxt filename + +let may_inject (cctxt : #Protocol_client_context.full) location ~delegate level + = + retrieve_highwatermark cctxt (Client_baking_files.filename location) + >>=? fun highwatermark -> + let delegate = Signature.Public_key_hash.to_short_b58check delegate in + List.find_opt + (fun (delegate', _) -> String.compare delegate delegate' = 0) + highwatermark + |> function + | None -> return_true + | Some (_, past_level) -> return Raw_level.(past_level < level) + +let may_inject_block = may_inject + +let may_inject_endorsement = may_inject + +let record (cctxt : #Protocol_client_context.full) location ~delegate level = + let filename = Client_baking_files.filename location in + let delegate = Signature.Public_key_hash.to_short_b58check delegate in + load_highwatermarks cctxt filename >>=? fun highwatermarks -> + let level = + match List.assoc_opt ~equal:String.equal delegate highwatermarks with + | None -> level + | Some lower_prev_level when level >= lower_prev_level -> level + | Some higher_prev_level -> higher_prev_level + (* should only happen in `forced` mode *) + in + save_highwatermarks + cctxt + filename + ((delegate, level) + :: + List.filter + (fun (delegate', _) -> String.compare delegate delegate' <> 0) + highwatermarks) + +let record_block = record + +let record_endorsement = record diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_highwatermarks.mli b/src/proto_011_PtHangzH/lib_delegate/client_baking_highwatermarks.mli new file mode 100644 index 000000000000..2dd35c1ff777 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_highwatermarks.mli @@ -0,0 +1,63 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +type error += Level_previously_endorsed of Raw_level.t + +type error += Level_previously_baked of Raw_level.t + +type t + +val encoding : t Data_encoding.t + +val may_inject_block : + #Protocol_client_context.full -> + [`Block] Client_baking_files.location -> + delegate:Signature.public_key_hash -> + Raw_level.t -> + bool tzresult Lwt.t + +val may_inject_endorsement : + #Protocol_client_context.full -> + [`Endorsement] Client_baking_files.location -> + delegate:Signature.public_key_hash -> + Raw_level.t -> + bool tzresult Lwt.t + +val record_block : + #Protocol_client_context.full -> + [`Block] Client_baking_files.location -> + delegate:Signature.public_key_hash -> + Raw_level.t -> + unit tzresult Lwt.t + +val record_endorsement : + #Protocol_client_context.full -> + [`Endorsement] Client_baking_files.location -> + delegate:Signature.public_key_hash -> + Raw_level.t -> + unit tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_lib.ml b/src/proto_011_PtHangzH/lib_delegate/client_baking_lib.ml new file mode 100644 index 000000000000..a96996a2b306 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_lib.ml @@ -0,0 +1,160 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +let bake_block (cctxt : #Protocol_client_context.full) ?minimal_fees + ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?force ?max_priority + ?(minimal_timestamp = false) ?mempool ?context_path ?src_sk + ~liquidity_baking_escape_vote ~chain ~head delegate = + (match src_sk with + | None -> + Client_keys.get_key cctxt delegate >>=? fun (_, _, src_sk) -> + return src_sk + | Some sk -> return sk) + >>=? fun src_sk -> + Plugin.RPC.current_level cctxt ~offset:1l (chain, head) >>=? fun level -> + let (seed_nonce, seed_nonce_hash) = + if level.expected_commitment then + let seed_nonce = Client_baking_forge.generate_seed_nonce () in + let seed_nonce_hash = Nonce.hash seed_nonce in + (Some seed_nonce, Some seed_nonce_hash) + else (None, None) + in + let timestamp = + if minimal_timestamp then None + else Some Time.System.(to_protocol (Systime_os.now ())) + in + Client_baking_forge.forge_block + cctxt + ?force + ?minimal_fees + ?minimal_nanotez_per_gas_unit + ?minimal_nanotez_per_byte + ?timestamp + ?seed_nonce_hash + ?mempool + ?context_path + ~liquidity_baking_escape_vote + ~chain + ~priority:(`Auto (delegate, max_priority)) + ~delegate_pkh:delegate + ~delegate_sk:src_sk + head + >>=? fun block_hash -> + (match seed_nonce with + | None -> return_unit + | Some seed_nonce -> + cctxt#with_lock (fun () -> + let open Client_baking_nonces in + Client_baking_files.resolve_location cctxt ~chain `Nonce + >>=? fun nonces_location -> + load cctxt nonces_location >>=? fun nonces -> + let nonces = add nonces block_hash seed_nonce in + save cctxt nonces_location nonces) + |> trace_exn (Failure "Error while recording block")) + >>=? fun () -> + cctxt#message "Injected block %a" Block_hash.pp_short block_hash >>= fun () -> + return_unit + +let endorse_block cctxt ~chain delegate = + Client_keys.get_key cctxt delegate >>=? fun (_src_name, src_pk, src_sk) -> + Client_baking_endorsement.forge_endorsement + cctxt + ~chain + ~block:cctxt#block + ~src_sk + src_pk + >>=? fun oph -> + cctxt#answer "Operation successfully injected in the node." >>= fun () -> + cctxt#answer "Operation hash is '%a'." Operation_hash.pp oph >>= fun () -> + return_unit + +let get_predecessor_cycle (cctxt : #Client_context.printer) cycle = + match Cycle.pred cycle with + | None -> + if Cycle.(cycle = root) then + cctxt#error "No predecessor for the first cycle" + else + cctxt#error "Cannot compute the predecessor of cycle %a" Cycle.pp cycle + | Some cycle -> Lwt.return cycle + +let do_reveal cctxt ~chain ~block nonces = + Client_baking_revelation.inject_seed_nonce_revelation + cctxt + ~chain + ~block + nonces + >>=? fun () -> return_unit + +let reveal_block_nonces (cctxt : #Protocol_client_context.full) ~chain ~block + block_hashes = + cctxt#with_lock (fun () -> + Client_baking_files.resolve_location cctxt ~chain `Nonce + >>=? fun nonces_location -> + Client_baking_nonces.load cctxt nonces_location) + >>=? fun nonces -> + List.filter_map_p + (fun hash -> + Lwt.catch + (fun () -> + Client_baking_blocks.info cctxt (`Hash (hash, 0)) >>= function + | Ok bi -> Lwt.return_some bi + | Error _ -> Lwt.fail Not_found) + (fun _ -> + cctxt#warning + "Cannot find block %a in the chain. (ignoring)@." + Block_hash.pp_short + hash + >>= fun () -> Lwt.return_none)) + block_hashes + >>= fun block_infos -> + List.filter_map_es + (fun (bi : Client_baking_blocks.block_info) -> + match Client_baking_nonces.find_opt nonces bi.hash with + | None -> + cctxt#warning + "Cannot find nonces for block %a (ignoring)@." + Block_hash.pp_short + bi.hash + >>= fun () -> return_none + | Some nonce -> return_some (bi.hash, (bi.level, nonce))) + block_infos + >>=? fun nonces -> + let nonces = List.map snd nonces in + do_reveal cctxt ~chain ~block nonces + +let reveal_nonces (cctxt : #Protocol_client_context.full) ~chain ~block () = + let open Client_baking_nonces in + cctxt#with_lock (fun () -> + Client_baking_files.resolve_location cctxt ~chain `Nonce + >>=? fun nonces_location -> + load cctxt nonces_location >>=? fun nonces -> + get_unrevealed_nonces cctxt nonces_location nonces + >>=? fun nonces_to_reveal -> + do_reveal cctxt ~chain ~block nonces_to_reveal >>=? fun () -> + filter_outdated_nonces cctxt nonces_location nonces >>=? fun nonces -> + save cctxt nonces_location nonces >>=? fun () -> return_unit) diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_lib.mli b/src/proto_011_PtHangzH/lib_delegate/client_baking_lib.mli new file mode 100644 index 000000000000..a93daedc308c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_lib.mli @@ -0,0 +1,72 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +(** Mine a block *) +val bake_block : + #Protocol_client_context.full -> + ?minimal_fees:Tez.t -> + ?minimal_nanotez_per_gas_unit:Q.t -> + ?minimal_nanotez_per_byte:Q.t -> + ?force:bool -> + ?max_priority:int -> + ?minimal_timestamp:bool -> + ?mempool:string -> + ?context_path:string -> + ?src_sk:Client_keys.sk_uri -> + liquidity_baking_escape_vote:bool -> + chain:Chain_services.chain -> + head:Block_services.block -> + public_key_hash -> + unit tzresult Lwt.t + +(** Endorse a block *) +val endorse_block : + #Protocol_client_context.full -> + chain:Chain_services.chain -> + Client_keys.Public_key_hash.t -> + unit Error_monad.tzresult Lwt.t + +(** Get the previous cycle of the given cycle *) +val get_predecessor_cycle : + #Protocol_client_context.full -> Cycle.t -> Cycle.t Lwt.t + +(** Reveal the nonces used to bake each block in the given list *) +val reveal_block_nonces : + #Protocol_client_context.full -> + chain:Chain_services.chain -> + block:Block_services.block -> + Block_hash.t list -> + unit Error_monad.tzresult Lwt.t + +(** Reveal all unrevealed nonces *) +val reveal_nonces : + #Protocol_client_context.full -> + chain:Chain_services.chain -> + block:Block_services.block -> + unit -> + unit Error_monad.tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_nonces.ml b/src/proto_011_PtHangzH/lib_delegate/client_baking_nonces.ml new file mode 100644 index 000000000000..f692a4f33e22 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_nonces.ml @@ -0,0 +1,147 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +module Events = Delegate_events.Nonces + +type t = Nonce.t Block_hash.Map.t + +let empty = Block_hash.Map.empty + +let encoding = + let open Data_encoding in + def "seed_nonce" + @@ conv + (fun m -> + Block_hash.Map.fold (fun hash nonce acc -> (hash, nonce) :: acc) m []) + (fun l -> + List.fold_left + (fun map (hash, nonce) -> Block_hash.Map.add hash nonce map) + Block_hash.Map.empty + l) + @@ list (obj2 (req "block" Block_hash.encoding) (req "nonce" Nonce.encoding)) + +let load (wallet : #Client_context.wallet) location = + wallet#load (Client_baking_files.filename location) ~default:empty encoding + +let save (wallet : #Client_context.wallet) location nonces = + wallet#write (Client_baking_files.filename location) nonces encoding + +let mem nonces hash = Block_hash.Map.mem hash nonces + +let find_opt nonces hash = Block_hash.Map.find hash nonces + +let add nonces hash nonce = Block_hash.Map.add hash nonce nonces + +let add_all nonces nonces_to_add = + Block_hash.Map.fold + (fun hash nonce acc -> add acc hash nonce) + nonces_to_add + nonces + +let remove nonces hash = Block_hash.Map.remove hash nonces + +let remove_all nonces nonces_to_remove = + Block_hash.Map.fold + (fun hash _ acc -> remove acc hash) + nonces_to_remove + nonces + +let get_block_level_opt cctxt ~chain ~block = + Shell_services.Blocks.Header.shell_header cctxt ~chain ~block () >>= function + | Ok {level; _} -> Lwt.return_some level + | Error errs -> + Events.(emit cannot_retrieve_block_header) + (Block_services.to_string block, errs) + >>= fun () -> Lwt.return_none + +let get_outdated_nonces cctxt ?constants ~chain nonces = + (match constants with + | None -> Alpha_services.Constants.all cctxt (chain, `Head 0) + | Some constants -> return constants) + >>=? fun {Constants.parametric = {blocks_per_cycle; preserved_cycles; _}; _} + -> + get_block_level_opt cctxt ~chain ~block:(`Head 0) >>= function + | None -> + Events.(emit cannot_retrieve_head_level) () >>= fun () -> + return (empty, empty) + | Some current_level -> + let current_cycle = Int32.(div current_level blocks_per_cycle) in + let is_older_than_preserved_cycles block_level = + let block_cycle = Int32.(div block_level blocks_per_cycle) in + Int32.sub current_cycle block_cycle > Int32.of_int preserved_cycles + in + Block_hash.Map.fold + (fun hash nonce acc -> + acc >>=? fun (orphans, outdated) -> + get_block_level_opt cctxt ~chain ~block:(`Hash (hash, 0)) >>= function + | Some level -> + if is_older_than_preserved_cycles level then + return (orphans, add outdated hash nonce) + else acc + | None -> return (add orphans hash nonce, outdated)) + nonces + (return (empty, empty)) + +let filter_outdated_nonces cctxt ?constants location nonces = + let chain = Client_baking_files.chain location in + get_outdated_nonces cctxt ?constants ~chain nonces + >>=? fun (orphans, outdated_nonces) -> + (if Block_hash.Map.cardinal orphans >= 50 then + Events.(emit too_many_orphans) (Client_baking_files.filename location) + >>= fun () -> Lwt.return_unit + else Lwt.return_unit) + >>= fun () -> return (remove_all nonces outdated_nonces) + +let get_unrevealed_nonces cctxt location nonces = + let chain = Client_baking_files.chain location in + Client_baking_blocks.blocks_from_current_cycle + cctxt + ~chain + (`Head 0) + ~offset:(-1l) + () + >>=? fun blocks -> + List.filter_map_es + (fun hash -> + match find_opt nonces hash with + | None -> return_none + | Some nonce -> ( + get_block_level_opt cctxt ~chain ~block:(`Hash (hash, 0)) >>= function + | Some level -> ( + Environment.wrap_tzresult (Raw_level.of_int32 level) + >>?= fun level -> + Alpha_services.Nonce.get cctxt (chain, `Head 0) level + >>=? function + | Missing nonce_hash when Nonce.check_hash nonce nonce_hash -> + Events.(emit found_nonce) (hash, level) >>= fun () -> + return_some (level, nonce) + | Missing _nonce_hash -> + Events.(emit bad_nonce) level >>= fun () -> return_none + | Forgotten -> return_none + | Revealed _ -> return_none) + | None -> return_none)) + blocks diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_nonces.mli b/src/proto_011_PtHangzH/lib_delegate/client_baking_nonces.mli new file mode 100644 index 000000000000..b5c18d3b6a68 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_nonces.mli @@ -0,0 +1,81 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +type t = Nonce.t Block_hash.Map.t + +val encoding : t Data_encoding.t + +val empty : t + +val load : + #Client_context.wallet -> + [`Nonce] Client_baking_files.location -> + t tzresult Lwt.t + +val save : + #Client_context.wallet -> + [`Nonce] Client_baking_files.location -> + t -> + unit tzresult Lwt.t + +val mem : t -> Block_hash.t -> bool + +val find_opt : t -> Block_hash.t -> Nonce.t option + +val add : t -> Block_hash.t -> Nonce.t -> t + +val add_all : t -> t -> t + +val remove : t -> Block_hash.t -> t + +val remove_all : t -> t -> t + +(** [get_outdated_nonces] returns the nonces that cannot be associated + to blocks (orphans) and the nonces that are older than 5 cycles. *) +val get_outdated_nonces : + #Protocol_client_context.full -> + ?constants:Constants.t -> + chain:Block_services.chain -> + t -> + (t * t) tzresult Lwt.t + +(** [filter_outdated_nonces] filters nonces older than 5 cycles in the + nonce file. *) +val filter_outdated_nonces : + #Protocol_client_context.full -> + ?constants:Constants.t -> + [`Nonce] Client_baking_files.location -> + t -> + t tzresult Lwt.t + +(** [get_unrevealed_nonces] retrieve registered nonces *) +val get_unrevealed_nonces : + #Protocol_client_context.full -> + [`Nonce] Client_baking_files.location -> + t -> + (Raw_level.t * Nonce.t) list tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_pow.ml b/src/proto_011_PtHangzH/lib_delegate/client_baking_pow.ml new file mode 100644 index 000000000000..fd7c820402d3 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_pow.ml @@ -0,0 +1,82 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +let default_constant = "\x00\x00\x00\x05" + +let is_updated_constant = + let commit_hash = + if TzString.is_hex Tezos_version.Current_git_info.commit_hash then + Hex.to_string (`Hex Tezos_version.Current_git_info.commit_hash) + else Tezos_version.Current_git_info.commit_hash + in + if String.length commit_hash >= 4 then String.sub commit_hash 0 4 + else default_constant + +let is_updated_constant_len = String.length is_updated_constant + +(* add a version to the pow *) +let init_proof_of_work_nonce () = + let buf = + Bytes.make Alpha_context.Constants.proof_of_work_nonce_size '\000' + in + Bytes.blit_string is_updated_constant 0 buf 0 is_updated_constant_len ; + let max_z_len = + Alpha_context.Constants.proof_of_work_nonce_size - is_updated_constant_len + in + let rec aux z = + let z_len = (Z.numbits z + 7) / 8 in + if z_len > max_z_len then Seq.Nil + else ( + Bytes.blit_string (Z.to_bits z) 0 buf is_updated_constant_len z_len ; + Seq.Cons (buf, fun () -> aux (Z.succ z))) + in + aux Z.zero + +(* This was used before November 2018 *) +(* (\* Random proof of work *\) + * let generate_proof_of_work_nonce () = + * Rand.generate Alpha_context.Constants.proof_of_work_nonce_size *) + +let empty_proof_of_work_nonce = + Bytes.make Constants_repr.proof_of_work_nonce_size '\000' + +let mine cctxt chain block shell builder = + Alpha_services.Constants.all cctxt (chain, block) >>=? fun constants -> + let threshold = constants.parametric.proof_of_work_threshold in + let rec loop nonce_seq = + match nonce_seq with + | Seq.Nil -> + failwith + "Client_baking_pow.mine: couldn't find nonce for required proof of \ + work" + | Seq.Cons (nonce, seq) -> + let block = builder nonce in + if Baking.check_header_proof_of_work_stamp shell block threshold then + return block + else loop (seq ()) + in + loop (init_proof_of_work_nonce ()) diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_pow.mli b/src/proto_011_PtHangzH/lib_delegate/client_baking_pow.mli new file mode 100644 index 000000000000..f61d37970ba2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_pow.mli @@ -0,0 +1,42 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(** A null proof-of-work nonce. This should only be used to nonsensical blocks + of the correct size and shape. *) +val empty_proof_of_work_nonce : Bytes.t + +(** [mine cctxt chain block header builder] returns a block with a valid + proof-of-work nonce. The function [builder], provided by the caller, is used + to make the block. All the internal logic of generating nonces and checking + for the proof-of-work threshold is handled by [mine]. *) +val mine : + #Protocol_client_context.full -> + Shell_services.chain -> + Block_services.block -> + Block_header.shell_header -> + (Bytes.t -> Alpha_context.Block_header.contents) -> + Alpha_context.Block_header.contents tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_revelation.ml b/src/proto_011_PtHangzH/lib_delegate/client_baking_revelation.ml new file mode 100644 index 000000000000..bc47dbc23e1f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_revelation.ml @@ -0,0 +1,54 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module Events = Delegate_events.Revelation + +let inject_seed_nonce_revelation (cctxt : #Protocol_client_context.full) ~chain + ~block ?async nonces = + Shell_services.Blocks.hash cctxt ~chain ~block () >>=? fun hash -> + match nonces with + | [] -> Events.(emit no_nonce_reveal) hash >>= fun () -> return_unit + | _ -> + List.iter_es + (fun (level, nonce) -> + Plugin.RPC.Forge.seed_nonce_revelation + cctxt + (chain, block) + ~branch:hash + ~level + ~nonce + () + >>=? fun bytes -> + let bytes = Signature.concat bytes Signature.zero in + Shell_services.Injection.operation cctxt ?async ~chain bytes + >>=? fun oph -> + Events.(emit reveal_nonce) + ( nonce, + level, + Block_services.chain_to_string chain, + Block_services.to_string block, + oph ) + >>= fun () -> return_unit) + nonces diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_revelation.mli b/src/proto_011_PtHangzH/lib_delegate/client_baking_revelation.mli new file mode 100644 index 000000000000..f13532831a9a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_revelation.mli @@ -0,0 +1,35 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +val inject_seed_nonce_revelation : + #Protocol_client_context.full -> + chain:Chain_services.chain -> + block:Block_services.block -> + ?async:bool -> + (Raw_level.t * Nonce.t) list -> + unit tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_scheduling.ml b/src/proto_011_PtHangzH/lib_delegate/client_baking_scheduling.ml new file mode 100644 index 000000000000..a2e7d820492f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_scheduling.ml @@ -0,0 +1,127 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol_client_context + +type error += Node_connection_lost + +module Events = Delegate_events.Baking_scheduling + +let () = + register_error_kind + `Temporary + ~id:"client_baking_scheduling.node_connection_lost" + ~title:"Node connection lost" + ~description:"The connection with the node was lost." + ~pp:(fun fmt () -> Format.fprintf fmt "Lost connection with the node") + Data_encoding.empty + (function Node_connection_lost -> Some () | _ -> None) + (fun () -> Node_connection_lost) + +let sleep_until time = + (* Sleeping is a system op, baking is a protocol op, this is where we convert *) + let time = Time.System.of_protocol_exn time in + let delay = Ptime.diff time (Tezos_stdlib_unix.Systime_os.now ()) in + if Ptime.Span.compare delay Ptime.Span.zero < 0 then None + else Some (Lwt_unix.sleep (Ptime.Span.to_float_s delay)) + +let rec wait_for_first_event ~name stream = + Lwt_stream.get stream >>= function + | None | Some (Error _) -> + Events.(emit cannot_fetch_event) name >>= fun () -> + (* NOTE: this is not a tight loop because of Lwt_stream.get *) + wait_for_first_event ~name stream + | Some (Ok bi) -> Lwt.return bi + +let log_errors_and_continue ~name p = + p >>= function + | Ok () -> Lwt.return_unit + | Error errs -> Events.(emit daemon_error) (name, errs) + +let main ~(name : string) ~(cctxt : #Protocol_client_context.full) + ~(stream : 'event tzresult Lwt_stream.t) + ~(state_maker : 'event -> 'state tzresult Lwt.t) + ~(pre_loop : + #Protocol_client_context.full -> 'state -> 'event -> unit tzresult Lwt.t) + ~(compute_timeout : 'state -> 'timesup Lwt.t) + ~(timeout_k : + #Protocol_client_context.full -> + 'state -> + 'timesup -> + unit tzresult Lwt.t) + ~(event_k : + #Protocol_client_context.full -> 'state -> 'event -> unit tzresult Lwt.t) + ~finalizer = + Events.(emit daemon_setup) name >>= fun () -> + wait_for_first_event ~name stream >>= fun first_event -> + (* statefulness *) + let last_get_event = ref None in + let get_event () = + match !last_get_event with + | None -> + let t = Lwt_stream.get stream in + last_get_event := Some t ; + t + | Some t -> t + in + state_maker first_event >>=? fun state -> + (* main loop *) + let rec worker_loop () = + (* event construction *) + let timeout = compute_timeout state in + Lwt.choose + [ + (Lwt_exit.clean_up_starts >|= fun _ -> `Termination); + (timeout >|= fun timesup -> `Timeout timesup); + (get_event () >|= fun e -> `Event e); + ] + >>= function + (* event matching *) + | `Termination -> return_unit + | `Event (None | Some (Error _)) -> + (* exit when the node is unavailable *) + last_get_event := None ; + Events.(emit daemon_connection_lost) name >>= fun () -> + fail Node_connection_lost + | `Event (Some (Ok event)) -> + (* new event: cancel everything and execute callback *) + last_get_event := None ; + (* TODO: pretty-print events (requires passing a pp as argument) *) + log_errors_and_continue ~name @@ event_k cctxt state event >>= fun () -> + worker_loop () + | `Timeout timesup -> + (* main event: it's time *) + Events.(emit daemon_wakeup) name >>= fun () -> + (* core functionality *) + log_errors_and_continue ~name @@ timeout_k cctxt state timesup + >>= fun () -> worker_loop () + in + (* ignition *) + Events.(emit daemon_start) name >>= fun () -> + Lwt.finalize + (fun () -> + log_errors_and_continue ~name @@ pre_loop cctxt state first_event + >>= fun () -> worker_loop ()) + (fun () -> finalizer state) diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_scheduling.mli b/src/proto_011_PtHangzH/lib_delegate/client_baking_scheduling.mli new file mode 100644 index 000000000000..ba8494f2d135 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_scheduling.mli @@ -0,0 +1,56 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += Node_connection_lost + +val sleep_until : Time.Protocol.t -> unit Lwt.t option + +val wait_for_first_event : + name:string -> 'event tzresult Lwt_stream.t -> 'event Lwt.t + +val main : + name:string -> + cctxt:(#Protocol_client_context.full as 'a) -> + stream:'event tzresult Lwt_stream.t -> + state_maker:('event -> 'state tzresult Lwt.t) -> + pre_loop:('a -> 'state -> 'event -> unit tzresult Lwt.t) -> + compute_timeout:('state -> 'timesup Lwt.t) -> + timeout_k:('a -> 'state -> 'timesup -> unit tzresult Lwt.t) -> + event_k:('a -> 'state -> 'event -> unit tzresult Lwt.t) -> + finalizer:('state -> unit Lwt.t) -> + unit tzresult Lwt.t + +(** [main ~name ~cctxt ~stream ~state_maker ~pre_loop ~timeout_maker ~timeout_k + ~event_k] is an infinitely running loop that + monitors new events arriving on [stream]. The loop exits when the + [stream] gives an error. + + The function [pre_loop] is called before the loop starts. + + The loop maintains a state (of type ['state]) initialized by [state_maker] + and passed to the callbacks [timeout_maker] (used to set up waking-up + timeouts), [timeout_k] (when a computed timeout happens), and [event_k] + (when a new event arrives on the stream). +*) diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_simulator.ml b/src/proto_011_PtHangzH/lib_delegate/client_baking_simulator.ml new file mode 100644 index 000000000000..f4f43caad179 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_simulator.ml @@ -0,0 +1,114 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol_client_context +open Protocol +open Alpha_context + +type error += Failed_to_checkout_context + +type error += Invalid_context + +let ( >>=?? ) x k = + x >>= fun x -> Lwt.return (Environment.wrap_tzresult x) >>=? k + +let () = + register_error_kind + `Permanent + ~id:"Client_baking_simulator.failed_to_checkout_context" + ~title:"Failed to checkout context" + ~description:"The given context hash does not exists in the context." + ~pp:(fun ppf () -> Format.fprintf ppf "Failed to checkout the context") + Data_encoding.unit + (function Failed_to_checkout_context -> Some () | _ -> None) + (fun () -> Failed_to_checkout_context) ; + register_error_kind + `Permanent + ~id:"Client_baking_simulator.invalid_context" + ~title:"Invalid context" + ~description:"Occurs when the context is inconsistent." + ~pp:(fun ppf () -> Format.fprintf ppf "The given context is invalid.") + Data_encoding.unit + (function Invalid_context -> Some () | _ -> None) + (fun () -> Invalid_context) + +type incremental = { + predecessor : Client_baking_blocks.block_info; + context : Tezos_protocol_environment.Context.t; + state : Protocol.validation_state; + rev_operations : Operation.packed list; + header : Tezos_base.Block_header.shell_header; +} + +let load_context ~context_path = Context.init ~readonly:true context_path + +let check_context_consistency index context_hash = + (* Hypothesis : the version key exists *) + let version_key = ["version"] in + Context.checkout index context_hash >>= function + | None -> fail Failed_to_checkout_context + | Some context -> ( + Context.mem context version_key >>= function + | true -> return_unit + | false -> fail Invalid_context) + +let begin_construction ~timestamp ?protocol_data index predecessor = + let {Client_baking_blocks.context; _} = predecessor in + Shell_context.checkout index context >>= function + | None -> fail Failed_to_checkout_context + | Some context -> + let header : Tezos_base.Block_header.shell_header = + Tezos_base.Block_header. + { + predecessor = predecessor.hash; + proto_level = predecessor.proto_level; + validation_passes = 0; + fitness = predecessor.fitness; + timestamp; + level = Raw_level.to_int32 predecessor.level; + context = Context_hash.zero; + operations_hash = Operation_list_list_hash.zero; + } + in + Lifted_protocol.begin_construction + ~chain_id:predecessor.chain_id + ~predecessor_context:context + ~predecessor_timestamp:predecessor.timestamp + ~predecessor_fitness:predecessor.fitness + ~predecessor_level:(Raw_level.to_int32 predecessor.level) + ~predecessor:predecessor.hash + ?protocol_data + ~timestamp + ~cache:`Load + () + >>=? fun state -> + return {predecessor; context; state; rev_operations = []; header} + +let add_operation st (op : Operation.packed) = + Protocol.apply_operation st.state op >>=?? fun (state, receipt) -> + return ({st with state; rev_operations = op :: st.rev_operations}, receipt) + +let finalize_construction inc = + Protocol.finalize_block inc.state (Some inc.header) >>=?? return diff --git a/src/proto_011_PtHangzH/lib_delegate/client_baking_simulator.mli b/src/proto_011_PtHangzH/lib_delegate/client_baking_simulator.mli new file mode 100644 index 000000000000..912adb99f9d0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_baking_simulator.mli @@ -0,0 +1,59 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +type incremental = { + predecessor : Client_baking_blocks.block_info; + context : Tezos_protocol_environment.Context.t; + state : validation_state; + rev_operations : Operation.packed list; + header : Tezos_base.Block_header.shell_header; +} + +val load_context : context_path:string -> Context.index Lwt.t + +(** Make sure that the given context is consistent by trying to read in it *) +val check_context_consistency : + Context.index -> Context_hash.t -> unit tzresult Lwt.t + +val begin_construction : + timestamp:Time.Protocol.t -> + ?protocol_data:block_header_data -> + Context.index -> + Client_baking_blocks.block_info -> + incremental tzresult Lwt.t + +val add_operation : + incremental -> + Operation.packed -> + (incremental * operation_receipt) tzresult Lwt.t + +val finalize_construction : + incremental -> + (Tezos_protocol_environment.validation_result * block_header_metadata) + tzresult + Lwt.t diff --git a/src/proto_011_PtHangzH/lib_delegate/client_daemon.ml b/src/proto_011_PtHangzH/lib_delegate/client_daemon.ml new file mode 100644 index 000000000000..4f8c72efc605 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_daemon.ml @@ -0,0 +1,142 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let rec retry (cctxt : #Protocol_client_context.full) ?max_delay ~delay ~factor + ~tries f x = + f x >>= function + | Ok _ as r -> Lwt.return r + | Error + (RPC_client_errors.Request_failed {error = Connection_failed _; _} :: _) + as err + when tries > 0 -> ( + cctxt#message "Connection refused, retrying in %.2f seconds..." delay + >>= fun () -> + Lwt.pick + [ + (Lwt_unix.sleep delay >|= fun () -> `Continue); + (Lwt_exit.clean_up_starts >|= fun _ -> `Killed); + ] + >>= function + | `Killed -> Lwt.return err + | `Continue -> + let next_delay = delay *. factor in + let delay = + Option.fold + ~none:next_delay + ~some:(fun max_delay -> Float.min next_delay max_delay) + max_delay + in + retry cctxt ?max_delay ~delay ~factor ~tries:(tries - 1) f x) + | Error _ as err -> Lwt.return err + +let rec retry_on_disconnection (cctxt : #Protocol_client_context.full) f = + f () >>= function + | Ok () -> return_unit + | Error (Client_baking_scheduling.Node_connection_lost :: _) -> + cctxt#warning + "Lost connection with the node. Retrying to establish connection..." + >>= fun () -> + (* Wait forever when the node stops responding... *) + Client_confirmations.wait_for_bootstrapped + ~retry:(retry cctxt ~max_delay:10. ~delay:1. ~factor:1.5 ~tries:max_int) + cctxt + >>=? fun () -> retry_on_disconnection cctxt f + | Error err -> + cctxt#error "Unexpected error: %a. Exiting..." pp_print_error err + +module Endorser = struct + let run (cctxt : #Protocol_client_context.full) ~chain ~delay ~keep_alive + delegates = + let process () = + Client_baking_blocks.monitor_heads + ~next_protocols:(Some [Protocol.hash]) + cctxt + chain + >>=? fun block_stream -> + cctxt#message "Endorser started." >>= fun () -> + Client_baking_endorsement.create cctxt ~delay delegates block_stream + in + Client_confirmations.wait_for_bootstrapped + ~retry:(retry cctxt ~delay:1. ~factor:1.5 ~tries:5) + cctxt + >>=? fun () -> + if keep_alive then retry_on_disconnection cctxt process else process () +end + +module Baker = struct + let run (cctxt : #Protocol_client_context.full) ?minimal_fees + ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?max_priority + ?per_block_vote_file ~chain ~context_path ~keep_alive delegates = + let process () = + Config_services.user_activated_upgrades cctxt + >>=? fun user_activated_upgrades -> + Client_baking_blocks.monitor_heads + ~next_protocols:(Some [Protocol.hash]) + cctxt + chain + >>=? fun block_stream -> + cctxt#message "Baker started." >>= fun () -> + Client_baking_forge.create + cctxt + ~user_activated_upgrades + ?minimal_fees + ?minimal_nanotez_per_gas_unit + ?minimal_nanotez_per_byte + ?max_priority + ?per_block_vote_file + ~chain + ~context_path + delegates + block_stream + in + Client_confirmations.wait_for_bootstrapped + ~retry:(retry cctxt ~delay:1. ~factor:1.5 ~tries:5) + cctxt + >>=? fun () -> + if keep_alive then retry_on_disconnection cctxt process else process () +end + +module Accuser = struct + let run (cctxt : #Protocol_client_context.full) ~chain ~preserved_levels + ~keep_alive = + let process () = + Client_baking_blocks.monitor_valid_blocks + ~next_protocols:(Some [Protocol.hash]) + cctxt + ~chains:[chain] + () + >>=? fun valid_blocks_stream -> + cctxt#message "Accuser started." >>= fun () -> + Client_baking_denunciation.create + cctxt + ~preserved_levels + valid_blocks_stream + in + Client_confirmations.wait_for_bootstrapped + ~retry:(retry cctxt ~delay:1. ~factor:1.5 ~tries:5) + cctxt + >>=? fun () -> + if keep_alive then retry_on_disconnection cctxt process else process () +end diff --git a/src/proto_011_PtHangzH/lib_delegate/client_daemon.mli b/src/proto_011_PtHangzH/lib_delegate/client_daemon.mli new file mode 100644 index 000000000000..06ef103ca5b9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/client_daemon.mli @@ -0,0 +1,61 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +module Endorser : sig + val run : + #Protocol_client_context.full -> + chain:Chain_services.chain -> + delay:int -> + keep_alive:bool -> + public_key_hash list -> + unit tzresult Lwt.t +end + +module Baker : sig + val run : + #Protocol_client_context.full -> + ?minimal_fees:Tez.t -> + ?minimal_nanotez_per_gas_unit:Q.t -> + ?minimal_nanotez_per_byte:Q.t -> + ?max_priority:int -> + ?per_block_vote_file:string -> + chain:Chain_services.chain -> + context_path:string -> + keep_alive:bool -> + public_key_hash list -> + unit tzresult Lwt.t +end + +module Accuser : sig + val run : + #Protocol_client_context.full -> + chain:Chain_services.chain -> + preserved_levels:int -> + keep_alive:bool -> + unit tzresult Lwt.t +end diff --git a/src/proto_011_PtHangzH/lib_delegate/delegate_commands.ml b/src/proto_011_PtHangzH/lib_delegate/delegate_commands.ml new file mode 100644 index 000000000000..c6665d766b5f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/delegate_commands.ml @@ -0,0 +1,370 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Client_proto_args +open Client_baking_lib + +let group = + {Clic.name = "delegate"; title = "Commands related to delegate operations."} + +let directory_parameter = + Clic.parameter (fun _ p -> + if not (Sys.file_exists p && Sys.is_directory p) then + failwith "Directory doesn't exist: '%s'" p + else return p) + +let mempool_arg = + Clic.arg + ~long:"mempool" + ~placeholder:"file" + ~doc: + "When used the client will read the mempool in the provided file instead \ + of querying the node through an RPC (useful for debugging only)." + string_parameter + +let context_path_arg = + Clic.arg + ~long:"context" + ~placeholder:"path" + ~doc: + "When use the client will read in the local context at the provided path \ + in order to build the block, instead of relying on the 'preapply' RPC." + string_parameter + +let pidfile_arg = + Clic.arg + ~doc:"write process id in file" + ~short:'P' + ~long:"pidfile" + ~placeholder:"filename" + (Clic.parameter (fun _ s -> return s)) + +let may_lock_pidfile pidfile_opt f = + match pidfile_opt with + | None -> f () + | Some pidfile -> + Lwt_lock_file.try_with_lock + ~when_locked:(fun () -> + failwith "Failed to create the pidfile: %s" pidfile) + ~filename:pidfile + f + +let block_param t = + Clic.param + ~name:"block" + ~desc:"commitment blocks whose nonce should be revealed" + (Clic.parameter (fun _ str -> Lwt.return (Block_hash.of_b58check str))) + t + +let keep_alive_arg = + Clic.switch + ~doc: + "Keep the daemon process alive: when the connection with the node is \ + lost, the daemon periodically tries to reach it." + ~short:'K' + ~long:"keep-alive" + () + +let per_block_vote_file_arg = + Clic.arg + ~doc: + "Read per block votes as json file. The content of the file should be \ + either {\"liquidity_baking_escape_vote\": false} or \ + {\"liquidity_baking_escape_vote\": true}." + ~short:'V' + ~long:"votefile" + ~placeholder:"filename" + (Clic.parameter (fun _ s -> return s)) + +let liquidity_baking_escape_vote_switch = + Clic.switch + ~doc:"Vote to end the liquidity baking subsidy." + ~long:"liquidity-baking-escape-vote" + () + +let delegate_commands () = + let open Clic in + [ + command + ~group + ~desc:"Forge and inject block using the delegate rights." + (args9 + max_priority_arg + minimal_fees_arg + minimal_nanotez_per_gas_unit_arg + minimal_nanotez_per_byte_arg + force_switch + minimal_timestamp_switch + mempool_arg + context_path_arg + liquidity_baking_escape_vote_switch) + (prefixes ["bake"; "for"] + @@ Client_keys.Public_key_hash.source_param + ~name:"baker" + ~desc:"name of the delegate owning the baking right" + @@ stop) + (fun ( max_priority, + minimal_fees, + minimal_nanotez_per_gas_unit, + minimal_nanotez_per_byte, + force, + minimal_timestamp, + mempool, + context_path, + liquidity_baking_escape_vote ) + delegate + cctxt -> + bake_block + cctxt + ~minimal_fees + ~minimal_nanotez_per_gas_unit + ~minimal_nanotez_per_byte + ~force + ?max_priority + ~minimal_timestamp + ?mempool + ?context_path + ~liquidity_baking_escape_vote + ~chain:cctxt#chain + ~head:cctxt#block + delegate); + command + ~group + ~desc:"Forge and inject a seed-nonce revelation operation." + no_options + (prefixes ["reveal"; "nonce"; "for"] @@ seq_of_param block_param) + (fun () block_hashes cctxt -> + reveal_block_nonces + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + block_hashes); + command + ~group + ~desc: + "Forge and inject all the possible seed-nonce revelation operations." + no_options + (prefixes ["reveal"; "nonces"] @@ stop) + (fun () cctxt -> + reveal_nonces ~chain:cctxt#chain ~block:cctxt#block cctxt ()); + command + ~group + ~desc:"Forge and inject an endorsement operation." + no_options + (prefixes ["endorse"; "for"] + @@ Client_keys.Public_key_hash.source_param + ~name:"baker" + ~desc:"name of the delegate owning the endorsement right" + @@ stop) + (fun () delegate cctxt -> endorse_block cctxt ~chain:cctxt#chain delegate); + command + ~group + ~desc: + "Clear the nonces file by removing the nonces which blocks cannot be \ + found on the chain." + no_options + (prefixes ["filter"; "orphan"; "nonces"] @@ stop) + (fun () (cctxt : #Protocol_client_context.full) -> + cctxt#with_lock (fun () -> + let chain = cctxt#chain in + Client_baking_files.resolve_location cctxt ~chain `Nonce + >>=? fun nonces_location -> + let open Client_baking_nonces in + (* Filtering orphan nonces *) + load cctxt nonces_location >>=? fun nonces -> + Block_hash.Map.fold + (fun block nonce acc -> + acc >>= fun acc -> + Shell_services.Blocks.Header.shell_header + cctxt + ~chain + ~block:(`Hash (block, 0)) + () + >>= function + | Ok _ -> Lwt.return acc + | Error _ -> Lwt.return (Block_hash.Map.add block nonce acc)) + nonces + (Lwt.return empty) + >>= fun orphans -> + if Block_hash.Map.cardinal orphans = 0 then + cctxt#message "No orphan nonces found." >>= fun () -> return_unit + else + (* "Backup-ing" orphan nonces *) + let orphan_nonces_file = "orphan_nonce" in + cctxt#load orphan_nonces_file ~default:empty encoding + >>=? fun orphan_nonces -> + let orphan_nonces = add_all orphan_nonces orphans in + cctxt#write orphan_nonces_file orphan_nonces encoding + >>=? fun () -> + (* Don't forget the 's'. *) + let orphan_nonces_file = orphan_nonces_file ^ "s" in + cctxt#message + "Successfully filtered %d orphan nonces and moved them to \ + '$TEZOS_CLIENT/%s'." + (Block_hash.Map.cardinal orphans) + orphan_nonces_file + >>= fun () -> + let filtered_nonces = + Client_baking_nonces.remove_all nonces orphans + in + save cctxt nonces_location filtered_nonces >>=? fun () -> + return_unit)); + command + ~group + ~desc:"List orphan nonces." + no_options + (prefixes ["list"; "orphan"; "nonces"] @@ stop) + (fun () (cctxt : #Protocol_client_context.full) -> + cctxt#with_lock (fun () -> + let open Client_baking_nonces in + let orphan_nonces_file = "orphan_nonce" in + cctxt#load orphan_nonces_file ~default:empty encoding + >>=? fun orphan_nonces -> + let block_hashes = + List.map fst (Block_hash.Map.bindings orphan_nonces) + in + cctxt#message + "@[Found %d orphan nonces associated to the potentially \ + unknown following blocks:@ %a@]" + (Block_hash.Map.cardinal orphan_nonces) + (Format.pp_print_list ~pp_sep:Format.pp_print_cut Block_hash.pp) + block_hashes + >>= fun () -> return_unit)); + ] + +let baker_commands () = + let open Clic in + let group = + { + Clic.name = "delegate.baker"; + title = "Commands related to the baker daemon."; + } + in + [ + command + ~group + ~desc:"Launch the baker daemon." + (args7 + pidfile_arg + max_priority_arg + minimal_fees_arg + minimal_nanotez_per_gas_unit_arg + minimal_nanotez_per_byte_arg + keep_alive_arg + per_block_vote_file_arg) + (prefixes ["run"; "with"; "local"; "node"] + @@ param + ~name:"context_path" + ~desc:"Path to the node data directory (e.g. $HOME/.tezos-node)" + directory_parameter + @@ seq_of_param Client_keys.Public_key_hash.alias_param) + (fun ( pidfile, + max_priority, + minimal_fees, + minimal_nanotez_per_gas_unit, + minimal_nanotez_per_byte, + keep_alive, + per_block_vote_file ) + node_path + delegates + cctxt -> + may_lock_pidfile pidfile @@ fun () -> + Tezos_signer_backends.Encrypted.decrypt_list + cctxt + (List.map fst delegates) + >>=? fun () -> + Client_daemon.Baker.run + cctxt + ~chain:cctxt#chain + ~minimal_fees + ~minimal_nanotez_per_gas_unit + ~minimal_nanotez_per_byte + ?max_priority + ?per_block_vote_file + ~context_path:(Filename.concat node_path "context") + ~keep_alive + (List.map snd delegates)); + ] + +let endorser_commands () = + let open Clic in + let group = + { + Clic.name = "delegate.endorser"; + title = "Commands related to endorser daemon."; + } + in + [ + command + ~group + ~desc:"Launch the endorser daemon" + (args3 pidfile_arg endorsement_delay_arg keep_alive_arg) + (prefixes ["run"] @@ seq_of_param Client_keys.Public_key_hash.alias_param) + (fun (pidfile, endorsement_delay, keep_alive) delegates cctxt -> + may_lock_pidfile pidfile @@ fun () -> + Tezos_signer_backends.Encrypted.decrypt_list + cctxt + (List.map fst delegates) + >>=? fun () -> + let delegates = List.map snd delegates in + let delegates_no_duplicates = + Signature.Public_key_hash.Set.(delegates |> of_list |> elements) + in + (if List.length delegates <> List.length delegates_no_duplicates then + cctxt#message + "Warning: the list of public key hash aliases contains duplicate \ + hashes, which are ignored" + else Lwt.return ()) + >>= fun () -> + Client_daemon.Endorser.run + cctxt + ~chain:cctxt#chain + ~delay:endorsement_delay + ~keep_alive + delegates_no_duplicates); + ] + +let accuser_commands () = + let open Clic in + let group = + { + Clic.name = "delegate.accuser"; + title = "Commands related to the accuser daemon."; + } + in + [ + command + ~group + ~desc:"Launch the accuser daemon" + (args3 pidfile_arg preserved_levels_arg keep_alive_arg) + (prefixes ["run"] @@ stop) + (fun (pidfile, preserved_levels, keep_alive) cctxt -> + may_lock_pidfile pidfile @@ fun () -> + Client_daemon.Accuser.run + cctxt + ~chain:cctxt#chain + ~preserved_levels + ~keep_alive); + ] diff --git a/src/proto_011_PtHangzH/lib_delegate/delegate_commands.mli b/src/proto_011_PtHangzH/lib_delegate/delegate_commands.mli new file mode 100644 index 000000000000..0bf46215dce0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/delegate_commands.mli @@ -0,0 +1,32 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val delegate_commands : unit -> Protocol_client_context.full Clic.command list + +val baker_commands : unit -> Protocol_client_context.full Clic.command list + +val endorser_commands : unit -> Protocol_client_context.full Clic.command list + +val accuser_commands : unit -> Protocol_client_context.full Clic.command list diff --git a/src/proto_011_PtHangzH/lib_delegate/delegate_commands_registration.ml b/src/proto_011_PtHangzH/lib_delegate/delegate_commands_registration.ml new file mode 100644 index 000000000000..35216b207afc --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/delegate_commands_registration.ml @@ -0,0 +1,29 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let () = + Client_commands.register Protocol.hash @@ fun _network -> + List.map (Clic.map_command (new Protocol_client_context.wrap_full)) + @@ Delegate_commands.delegate_commands () diff --git a/src/proto_011_PtHangzH/lib_delegate/delegate_events.ml b/src/proto_011_PtHangzH/lib_delegate/delegate_events.ml new file mode 100644 index 000000000000..edf9b36ec47f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/delegate_events.ml @@ -0,0 +1,769 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Tocqueville Group, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +let level = Internal_event.Notice + +(* Ignore the value in the output. *) +let pp_ignore fmt _ = Format.pp_print_string fmt "" + +module Revelation = struct + include Internal_event.Simple + + let section = [Protocol.name; "delegate"; "reveal"] + + let no_nonce_reveal = + declare_1 + ~section + ~level + ~name:"no_nonce_reveal" + ~msg:"nothing to reveal for block {block}" + ("block", Block_hash.encoding) + + let reveal_nonce = + declare_5 + ~section + ~level + ~name:"reveal_nonce" + ~msg: + "revealing nonce {nonce} from level {level} for chain {chain}, block \ + {block} with operation {operation}" + ("nonce", Alpha_context.Nonce.encoding) + ("level", Alpha_context.Raw_level.encoding) + ("chain", Data_encoding.string) + ("block", Data_encoding.string) + ("operation", Operation_hash.encoding) +end + +module Nonces = struct + include Internal_event.Simple + + let section = [Protocol.name; "delegate"; "nonces"] + + let cannot_retrieve_block_header = + declare_2 + ~section + ~level:Warning + ~name:"cannot_retrieve_block_header" + ~msg:"cannot retrieve block {block} header associated to nonce: {errors}" + ~pp2:pp_print_error_first + ("block", Data_encoding.string) + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let cannot_retrieve_head_level = + declare_0 + ~section + ~level:Error + ~name:"cannot_retrieve_head_level" + ~msg:"cannot fetch chain's head level; aborting nonce filtering" + () + + let too_many_orphans = + declare_1 + ~section + ~level:Warning + ~name:"too_many_orphans" + ~msg: + "found too many nonces associated to blocks unknown by the node in \ + '$TEZOS_CLIENT/{filename}'; after checking that these blocks were \ + never included in the chain (e.g. via a block explorer), consider \ + using `tezos-client filter orphan nonces` to clear them" + ("filename", Data_encoding.string) + + let found_nonce = + declare_2 + ~section + ~level + ~name:"found_nonce" + ~msg:"found nonce to reveal for {hash} (level: {level})" + ("hash", Block_hash.encoding) + ("level", Alpha_context.Raw_level.encoding) + + let bad_nonce = + declare_1 + ~section + ~level:Error + ~name:"bad_nonce" + ~msg:"incoherent nonce for level {level}" + ("level", Alpha_context.Raw_level.encoding) +end + +module Denunciator = struct + include Internal_event.Simple + + let section = [Protocol.name; "delegate"; "denunciation"] + + let invalid_level_conversion = + declare_1 + ~section + ~level:Error + ~name:"invalid_level_conversion" + ~msg:"invalid level conversion: {errors}" + ~pp1:pp_print_error_first + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let double_endorsement_detected = + declare_2 + ~section + ~level + ~name:"double_endorsement_detected" + ~msg:"double endorsement detected" + ("existing_endorsement", Operation_hash.encoding) + ("new_endorsement", Operation_hash.encoding) + + let double_endorsement_denounced = + declare_2 + ~section + ~level + ~name:"double_endorsement_denounced" + ~msg:"double endorsement evidence injected: {hash}" + ("hash", Operation_hash.encoding) + ~pp2:pp_ignore + ("bytes", Data_encoding.bytes) + + let inconsistent_endorsement = + declare_1 + ~section + ~level:Error + ~name:"inconsistent_endorsement" + ~msg:"inconsistent endorsement found {hash}" + ("hash", Operation_hash.encoding) + + let unexpected_pruned_block = + declare_1 + ~section + ~level:Error + ~name:"unexpected_pruned_block" + ~msg:"unexpected pruned block: {hash}" + ("hash", Block_hash.encoding) + + let double_baking_but_not = + declare_0 + ~section + ~level:Debug + ~name:"double_baking_but_not" + ~msg:"double baking detected but block hashes are equivalent; skipping" + () + + let double_baking_detected = + declare_0 + ~section + ~level + ~name:"double_baking_detected" + ~msg:"double baking detected" + () + + let double_baking_denounced = + declare_2 + ~section + ~level + ~name:"double_baking_denounced" + ~msg:"double baking evidence injected {hash}" + ("hash", Operation_hash.encoding) + ~pp2:pp_ignore + ("bytes", Data_encoding.bytes) + + let protocol_change_detected = + declare_0 + ~section + ~level:Error + ~name:"protocol_change_detected" + ~msg:"protocol changing detected; skipping the block" + () + + let accuser_saw_block = + declare_2 + ~section + ~level:Debug + ~name:"accuser_saw_block" + ~msg:"block level: {level}" + ("level", Alpha_context.Raw_level.encoding) + ("hash", Block_hash.encoding) + + let fetch_operations_error = + declare_2 + ~section + ~level:Error + ~name:"fetch_operations_error" + ~msg:"error while fetching operations in block {hash} {errors}" + ~pp2:pp_print_error_first + ("hash", Block_hash.encoding) + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let accuser_processed_block = + declare_1 + ~section + ~level + ~name:"accuser_processed_block" + ~msg:"block {hash} registered" + ("hash", Block_hash.encoding) + + let accuser_block_error = + declare_2 + ~section + ~level:Error + ~name:"accuser_block_error" + ~msg:"error while processing block {hash} {errors}" + ~pp2:pp_print_error_first + ("hash", Block_hash.encoding) + ("errors", Error_monad.(TzTrace.encoding error_encoding)) +end + +module Baking_scheduling = struct + include Internal_event.Simple + + let section = [Protocol.name; "delegate"; "baking-scheduling"] + + let cannot_fetch_event = + declare_1 + ~section + ~level:Info + ~name:"cannot_fetch_event" + ~msg:"{worker}: can't fetch the current event; waiting for new event" + ("worker", Data_encoding.string) + + let daemon_error = + declare_2 + ~section + ~level:Error + ~name:"daemon_error" + ~msg:"{worker}: error while baking: {errors}" + ~pp2:pp_print_error_first + ("worker", Data_encoding.string) + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let daemon_setup = + declare_1 + ~section + ~level:Info + ~name:"daemon_setup" + ~msg:"setting up before the {worker} can start" + ("worker", Data_encoding.string) + + let daemon_connection_lost = + declare_1 + ~section + ~level:Error + ~name:"daemon_connection_lost" + ~msg:"connection to node lost, {worker} exiting" + ("worker", Data_encoding.string) + + let daemon_wakeup = + declare_1 + ~section + ~level:Debug + ~name:"daemon_wakeup" + ~msg:"waking up for {worker}" + ("worker", Data_encoding.string) + + let daemon_start = + declare_1 + ~section + ~level:Info + ~name:"daemon_start" + ~msg:"starting {worker} daemon" + ("worker", Data_encoding.string) +end + +module Baking_forge = struct + include Internal_event.Simple + + let section = [Protocol.name; "delegate"; "baking_forge"] + + let double_bake_near_miss = + declare_1 + ~section + ~level:Error + ~name:"double_bake_near_miss" + ~msg:"level {level}: previously baked" + ("level", Alpha_context.Raw_level.encoding) + + let inject_baked_block = + declare_3 + ~section + ~level:Info + ~name:"inject_baked_block" + ~msg:"Client_baking_forge.inject_block: inject {hash}" + ("hash", Block_hash.encoding) + ~pp2:pp_ignore + ("header", Data_encoding.bytes) + ~pp3:Format.(pp_print_list @@ pp_print_list @@ Operation.pp) + ( "operations", + Data_encoding.(list @@ list @@ dynamic_size Operation.encoding) ) + + let baking_local_validation_start = + declare_1 + ~section + ~level:Debug + ~name:"baking_local_validation_start" + ~msg:"starting client-side validation after {hash}" + ("hash", Block_hash.encoding) + + let context_fetch_error = + declare_1 + ~section + ~level:Error + ~name:"context_fetch_error" + ~msg:"error while fetching current context: {errors}" + ~pp1:pp_print_error_first + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let reopen_context = + declare_0 + ~section + ~level + ~name:"reopen_context" + ~msg:"retrying to open the context" + () + + let baking_rejected_invalid_operation = + declare_2 + ~section + ~level:Debug + ~name:"baking_rejected_invalid_operation" + ~msg:"client-side validation: filtered invalid operation {hash} {errors}" + ~pp2:pp_print_error_first + ("hash", Operation_hash.encoding) + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let shell_prevalidation_notice = + declare_0 + ~section + ~level + ~name:"shell_prevalidation_notice" + ~msg:"building a block using shell validation" + () + + let shell_prevalidation_new_protocol = + declare_0 + ~section + ~level + ~name:"shell_prevalidation_new_protocol" + ~msg:"new protocol detected: using shell validation" + () + + let found_valid_operations = + declare_4 + ~section + ~level + ~name:"found_valid_operations" + ~msg: + "found {valid_count} valid operations ({refused_count} refused) for \ + timestamp {timestamp} (fitness {fitness})" + ~pp4:Fitness.pp + ("valid_count", Data_encoding.int31) + ("refused_count", Data_encoding.int31) + ("timestamp", Time.System.encoding) + ("fitness", Fitness.encoding) + + let block_conversion_failed = + declare_1 + ~section + ~level:Error + ~name:"block_conversion_failed" + ~msg:"error on raw_level conversion: {errors}" + ~pp1:pp_print_error_first + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let block_injection_failed = + declare_2 + ~section + ~level:Error + ~name:"block_injection_failed" + ~msg: + "error while injecting block; included operations: {operations}; \ + errors: {errors}" + ~pp1:(Format.pp_print_list Operation.pp) + ~pp2:pp_print_error_first + ("operations", Data_encoding.(list @@ dynamic_size Operation.encoding)) + ("errors", Error_monad.trace_encoding) + + let built_invalid_block_error = + declare_1 + ~section + ~level:Error + ~name:"built_invalid_block_error" + ~msg: + "shell-side validation: error while prevalidating operations: {errors}" + ~pp1:pp_print_error_first + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let try_baking = + declare_4 + ~section + ~level:Debug + ~name:"try_baking" + ~msg: + "try baking after {hash} (slot {priority}) for {client} ({timestamp})" + ("hash", Block_hash.encoding) + ("priority", Data_encoding.int31) + ("client", Data_encoding.string) + ("timestamp", Time.System.encoding) + + let new_head_received = + declare_0 + ~section + ~level + ~name:"new_head_received" + ~msg: + "received a new head while waiting for operations; aborting this block" + () + + let client_side_validation_error = + declare_1 + ~section + ~level:Error + ~name:"client_side_validation_error" + ~msg: + "client-side validation: error while filtering invalid operations: \ + {errors}" + ~pp1:pp_print_error_first + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let waiting_before_injection = + declare_2 + ~section + ~level + ~name:"waiting_before_injection" + ~msg: + "[{current_timestamp}] not ready to inject yet, waiting until \ + {valid_timestamp}" + ("current_timestamp", Time.System.encoding) + ("valid_timestamp", Time.System.encoding) + + let try_forging = + declare_4 + ~section + ~level:Debug + ~name:"try_forging" + ~msg: + "try forging locally the block header for {hash} (slot {priority}) for \ + {client} ({timestamp})" + ("hash", Block_hash.encoding) + ("priority", Data_encoding.int31) + ("client", Data_encoding.string) + ("timestamp", Time.System.encoding) + + let start_injecting_block = + declare_5 + ~section + ~level:Info + ~name:"start_injecting_block" + ~msg: + "injecting block (priority {priority}, fitness {fitness}) for {client} \ + after {predecessor}" + ~pp2:Fitness.pp + ("priority", Data_encoding.int31) + ("fitness", Fitness.encoding) + ("client", Data_encoding.string) + ("predecessor", Block_hash.encoding) + ("baker", Client_keys.Public_key_hash.encoding) + + let injected_block = + declare_7 + ~section + ~level + ~name:"injected_block" + ~msg: + "injected block {block_hash} for {client} after {predecessor} (level \ + {level}, priority {priority}, fitness {fitness}, operations \ + {operations})" + ~pp6:Fitness.pp + ~pp7:Format.(pp_print_list Operation.pp) + ("block_hash", Block_hash.encoding) + ("client", Data_encoding.string) + ("predecessor", Block_hash.encoding) + ("level", Alpha_context.Raw_level.encoding) + ("priority", Data_encoding.int31) + ("fitness", Fitness.encoding) + ("operations", Data_encoding.(list @@ dynamic_size Operation.encoding)) + + let baking_slot_fetch_errors = + declare_1 + ~section + ~level:Error + ~name:"baking_slot_fetch_errors" + ~msg:"error while fetching baking possibilities: {errors}" + ~pp1:pp_print_error_first + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let no_slot_found = + declare_2 + ~section + ~level + ~name:"no_slot_found" + ~msg:"no slot found at level {level} (max_priority = {priority})" + ("level", Alpha_context.Raw_level.encoding) + ("priority", Data_encoding.int31) + + let have_baking_slot = + declare_6 + ~section + ~level + ~name:"have_baking_slot" + ~msg: + "new baking slot found (level {level}, priority {priority}) at \ + {timestamp} for {client} after {predecessor}" + ("level", Alpha_context.Raw_level.encoding) + ("priority", Data_encoding.int31) + ("timestamp", Time.System.encoding) + ("client", Data_encoding.string) + ("predecessor", Block_hash.encoding) + ("baker", Client_keys.Public_key_hash.encoding) + + let read_nonce_fail = + declare_1 + ~section + ~level:Error + ~name:"read_nonce_fail" + ~msg:"cannot read nonces: {errors}" + ~pp1:pp_print_error_first + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let nonce_retrieval_fail = + declare_1 + ~section + ~level:Error + ~name:"nonce_retrieval_fail" + ~msg:"cannot retrieve unrevealed nonces: {errors}" + ~pp1:pp_print_error_first + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let nonce_injection_fail = + declare_1 + ~section + ~level:Error + ~name:"nonce_injection_fail" + ~msg:"cannot inject nonces: {errors}" + ~pp1:pp_print_error_first + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let retrying_on_error = + declare_1 + ~section + ~level:Error + ~name:"retrying_on_error" + ~msg:"retrying after baking error {errors}" + ~pp1:pp_print_error_first + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let endorsement_received = + declare_2 + ~section + ~level:Info + ~name:"endorsement_received" + ~msg:"received endorsement for slot {slot} (power: {power})" + ~pp1:Format.pp_print_int + ("slot", Data_encoding.int31) + ~pp2:Format.pp_print_int + ("power", Data_encoding.int31) + + let expected_validity_time = + declare_2 + ~section + ~name:"expected_validity_time" + ~level:Info + ~msg:"expected validity time: {time} (endorsing power: {power})" + ~pp1:Alpha_context.Timestamp.pp + ("time", Alpha_context.Timestamp.encoding) + ~pp2:Format.pp_print_int + ("power", Data_encoding.int31) + + let reading_per_block = + declare_1 + ~section + ~name:"reading_per_block" + ~level:Notice + ~msg:"reading per block vote file path: {path}" + ("path", Data_encoding.string) + + let per_block_vote_file_notice = + declare_1 + ~section + ~name:"per_block_vote_file_notice" + ~level:Notice + ~msg:"per block vote file {event}" + ("event", Data_encoding.string) + + let reading_liquidity_baking = + declare_0 + ~section + ~name:"reading_liquidity_baking" + ~level:Notice + ~msg:"reading liquidity baking escape vote" + () + + let liquidity_baking_escape_vote = + declare_1 + ~section + ~name:"liquidity_baking_escape_vote" + ~level:Notice + ~msg:"liquidity baking escape vote = {value}" + ("value", Data_encoding.bool) + + let per_block_vote_file_fail = + declare_1 + ~section + ~name:"per_block_vote_file_error" + ~level:Notice + ~msg:"Error reading the block vote file: {errors}" + ~pp1:pp_print_error_first + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let liquidity_baking_escape = + declare_0 + ~section + ~name:"liquidity_baking_continue" + ~level:Notice + ~msg:"Will vote to escape Liquidity Baking" + () + + let liquidity_baking_continue = + declare_0 + ~section + ~name:"liquidity_baking_escape" + ~level:Notice + ~msg:"Will vote to continue Liquidity Baking" + () +end + +module Endorsement = struct + include Internal_event.Simple + + let section = [Protocol.name; "delegate"; "endorsement"] + + let double_endorsement_near_miss = + declare_1 + ~section + ~level:Error + ~name:"double_endorsement_near_miss" + ~msg:"level {level}: previously endorsed" + ("level", Alpha_context.Raw_level.encoding) + + let injected_endorsement = + declare_5 + ~section + ~level + ~name:"injected_endorsement" + ~msg: + "injected endorsement for block '{block_hash}' (level {level}, \ + contract {client}) '{op_hash}'" + ("block_hash", Block_hash.encoding) + ("level", Alpha_context.Raw_level.encoding) + ("client", Data_encoding.string) + ("op_hash", Operation_hash.encoding) + ("baker", Client_keys.Public_key_hash.encoding) + + let endorsing = + declare_3 + ~section + ~level:Debug + ~name:"endorsing" + ~msg:"endorsing {block} for {client} (level {level})!" + ("block", Block_hash.encoding) + ("client", Data_encoding.string) + ("level", Alpha_context.Raw_level.encoding) + + let check_endorsement_ok = + declare_2 + ~section + ~level:Debug + ~name:"check_endorsement_ok" + ~msg:"checking if allowed to endorse block {block} for {client}" + ("block", Block_hash.encoding) + ("client", Data_encoding.string) + + let endorsement_no_slots_found = + declare_2 + ~section + ~level:Debug + ~name:"endorsement_no_slots_found" + ~msg:"no slot found for {block}/{client}" + ("block", Block_hash.encoding) + ("client", Data_encoding.string) + + let endorsement_slots_found = + declare_3 + ~section + ~level:Debug + ~name:"endorsement_slots_found" + ~msg:"found slots for {block}/{client} ({slots})" + ~pp3: + Format.( + fun fmt -> + fprintf + fmt + "[%a]" + (pp_print_list + ~pp_sep:(fun f () -> pp_print_string f "; ") + Format.pp_print_int)) + ("block", Block_hash.encoding) + ("client", Data_encoding.string) + ("slots", Data_encoding.list Data_encoding.int31) + + let previously_endorsed = + declare_1 + ~section + ~level:Debug + ~name:"previously_endorsed" + ~msg:"level {level} (or higher) previously endorsed: do not endorse" + ("level", Alpha_context.Raw_level.encoding) + + let endorsement_stale_block = + declare_1 + ~section + ~level:Info + ~name:"endorsement_stale_block" + ~msg:"ignore block {block}: forged too far the past" + ("block", Block_hash.encoding) + + let endorsement_got_block = + declare_1 + ~section + ~level:Info + ~name:"endorsement_got_block" + ~msg:"received new block {block}" + ("block", Block_hash.encoding) + + let wait_before_injecting = + declare_2 + ~section + ~level:Info + ~name:"wait_before_injecting" + ~msg:"waiting until {timestamp} ({timespan}) to inject endorsements" + ("timestamp", Time.System.encoding) + ("timespan", Time.System.Span.encoding) + + let error_while_endorsing = + declare_2 + ~section + ~level:Error + ~name:"error_while_endorsing" + ~msg:"error while injecting endorsement for baker {baker}: {errors}" + ~pp2:pp_print_error_first + ("baker", Client_keys.Public_key_hash.encoding) + ("errors", Error_monad.(TzTrace.encoding error_encoding)) +end diff --git a/src/proto_011_PtHangzH/lib_delegate/dune b/src/proto_011_PtHangzH/lib_delegate/dune new file mode 100644 index 000000000000..b341587cbe1f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/dune @@ -0,0 +1,87 @@ +(library + (name tezos_baking_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-baking-011-PtHangzH) + (libraries tezos-base + tezos-version + tezos-protocol-011-PtHangzH + tezos-protocol-environment + tezos-shell-context + tezos-shell-services + tezos-client-base + tezos-client-011-PtHangzH + tezos-client-commands + tezos-stdlib + tezos-stdlib-unix + tezos-context + tezos-rpc-http + tezos-rpc + lwt-canceler + lwt-exit) + (library_flags (:standard -linkall)) + (modules (:standard \ + delegate_commands + delegate_commands_registration)) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_protocol_011_PtHangzH + -open Tezos_protocol_plugin_011_PtHangzH + -open Tezos_shell_services + -open Tezos_client_base + -open Tezos_client_011_PtHangzH + -open Tezos_client_commands + -open Tezos_stdlib + -open Tezos_stdlib_unix + -open Tezos_shell_context + -open Tezos_context + -open Tezos_rpc + -open Tezos_rpc_http))) + +(library + (name tezos_baking_011_PtHangzH_commands) + (instrumentation (backend bisect_ppx)) + (public_name tezos-baking-011-PtHangzH-commands) + (libraries tezos-base + tezos-protocol-011-PtHangzH + tezos-protocol-environment + tezos-shell-services + tezos-client-base + tezos-client-011-PtHangzH + tezos-client-commands + tezos-baking-011-PtHangzH) + (library_flags (:standard -linkall)) + (modules delegate_commands) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_protocol_011_PtHangzH + -open Tezos_stdlib_unix + -open Tezos_shell_services + -open Tezos_client_base + -open Tezos_client_011_PtHangzH + -open Tezos_client_commands + -open Tezos_baking_011_PtHangzH + -open Tezos_rpc))) + +(library + (name tezos_baking_011_PtHangzH_commands_registration) + (instrumentation (backend bisect_ppx)) + (public_name tezos-baking-011-PtHangzH-commands.registration) + (libraries tezos-base + tezos-protocol-011-PtHangzH + tezos-protocol-environment + tezos-shell-services + tezos-client-base + tezos-client-011-PtHangzH + tezos-client-commands + tezos-baking-011-PtHangzH + tezos-baking-011-PtHangzH-commands + tezos-rpc) + (library_flags (:standard -linkall)) + (modules delegate_commands_registration) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_protocol_011_PtHangzH + -open Tezos_shell_services + -open Tezos_client_base + -open Tezos_client_011_PtHangzH + -open Tezos_client_commands + -open Tezos_baking_011_PtHangzH + -open Tezos_baking_011_PtHangzH_commands + -open Tezos_rpc))) diff --git a/src/proto_011_PtHangzH/lib_delegate/dune-project b/src/proto_011_PtHangzH/lib_delegate/dune-project new file mode 100644 index 000000000000..bd82a425eaba --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(formatting (enabled_for ocaml)) +(name tezos-accuser-alpha-commands) diff --git a/src/proto_011_PtHangzH/lib_delegate/logging.ml b/src/proto_011_PtHangzH/lib_delegate/logging.ml new file mode 100644 index 000000000000..219300fa68d9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/logging.ml @@ -0,0 +1,153 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +let timestamp_tag = + Tag.def ~doc:"Timestamp when event occurred" "timestamp" Time.System.pp_hum + +let valid_ops = Tag.def ~doc:"Valid Operations" "valid_ops" Format.pp_print_int + +let op_count = + Tag.def ~doc:"Number of operations" "op_count" Format.pp_print_int + +let refused_ops = + Tag.def ~doc:"Refused Operations" "refused_ops" Format.pp_print_int + +let bake_priority_tag = + Tag.def ~doc:"Baking priority" "bake_priority" Format.pp_print_int + +let fitness_tag = Tag.def ~doc:"Fitness" "fitness" Fitness.pp + +let current_slots_tag = + Tag.def + ~doc:"Number of baking slots that can be baked at this time" + "current_slots" + Format.pp_print_int + +let future_slots_tag = + Tag.def + ~doc:"Number of baking slots in the foreseeable future but not yet bakeable" + "future_slots" + Format.pp_print_int + +let timespan_tag = Tag.def ~doc:"Timespan in seconds" "timespan" Ptime.Span.pp + +let filename_tag = Tag.def ~doc:"Filename" "filename" Format.pp_print_text + +let signed_header_tag = + Tag.def ~doc:"Signed header" "signed_header" (fun fmt x -> + Hex.pp fmt (Hex.of_bytes x)) + +let signed_operation_tag = + Tag.def ~doc:"Signed operation" "signed_operation" (fun fmt x -> + Hex.pp fmt (Hex.of_bytes x)) + +let operations_tag = + Tag.def + ~doc:"Block Operations" + "operations" + (Format.pp_print_list + ~pp_sep:(fun ppf () -> Format.fprintf ppf "+") + (fun ppf operations -> Format.fprintf ppf "%d" (List.length operations))) + +let raw_operations_tag = + Tag.def ~doc:"Raw operations" "raw_operations" (fun fmt raw_ops -> + let pp_op fmt op = + let json = Data_encoding.Json.construct Operation.raw_encoding op in + Format.fprintf fmt "%a" Data_encoding.Json.pp json + in + Format.fprintf + fmt + "@[%a@]" + (Format.pp_print_list ~pp_sep:Format.pp_print_cut pp_op) + raw_ops) + +let bake_op_count_tag = + Tag.def ~doc:"Bake Operation Count" "operation_count" Format.pp_print_int + +let endorsement_slot_tag = + Tag.def ~doc:"Endorsement Slot" "endorsement_slot" Format.pp_print_int + +let endorsement_slots_tag = + Tag.def + ~doc:"Endorsement Slots" + "endorsement_slots" + Format.(fun ppf v -> pp_print_int ppf (List.length v)) + +let denounced_endorsements_slots_tag = + Tag.def + ~doc:"Endorsement Slots" + "denounced_endorsement_slots" + Format.(pp_print_list pp_print_int) + +let denouncement_source_tag = + Tag.def ~doc:"Denounce Source" "source" Format.pp_print_text + +let level_tag = Tag.def ~doc:"Level" "level" Raw_level.pp + +let nonce_tag = + Tag.def + ~doc:"Nonce" + "nonce" + Data_encoding.Json.( + fun ppf nonce -> pp ppf (construct Nonce.encoding nonce)) + +let chain_tag = + Tag.def + ~doc:"Chain selector" + "chain" + Format.( + fun ppf chain -> + pp_print_string ppf @@ Block_services.chain_to_string chain) + +let block_tag = + Tag.def + ~doc:"Block selector" + "block" + Format.( + fun ppf block -> pp_print_string ppf @@ Block_services.to_string block) + +let worker_tag = + Tag.def ~doc:"Worker in which event occurred" "worker" Format.pp_print_text + +let block_header_tag = + Tag.def ~doc:"Raw block header" "block_header" (fun ppf _ -> + Format.fprintf ppf "[raw block header]") + +let conflicting_endorsements_tag = + Tag.def + ~doc:"Two conflicting endorsements signed by the same key" + "conflicting_endorsements" + Format.( + fun ppf (a, b) -> + fprintf + ppf + "%a / %a" + Operation_hash.pp + (Operation.hash a) + Operation_hash.pp + (Operation.hash b)) diff --git a/src/proto_011_PtHangzH/lib_delegate/logging.mli b/src/proto_011_PtHangzH/lib_delegate/logging.mli new file mode 100644 index 000000000000..544b2ef25007 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/logging.mli @@ -0,0 +1,80 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +val timestamp_tag : Time.System.t Tag.def + +val valid_ops : int Tag.def + +val op_count : int Tag.def + +val refused_ops : int Tag.def + +val bake_priority_tag : int Tag.def + +val fitness_tag : Fitness.t Tag.def + +val current_slots_tag : int Tag.def + +val future_slots_tag : int Tag.def + +val timespan_tag : Time.System.Span.t Tag.def + +val filename_tag : string Tag.def + +val signed_header_tag : Bytes.t Tag.def + +val signed_operation_tag : Bytes.t Tag.def + +val operations_tag : Tezos_base.Operation.t list list Tag.def + +val raw_operations_tag : Operation.raw list Tag.def + +val bake_op_count_tag : int Tag.def + +val endorsement_slot_tag : int Tag.def + +val endorsement_slots_tag : int list Tag.def + +val denounced_endorsements_slots_tag : int list Tag.def + +val denouncement_source_tag : string Tag.def + +val level_tag : Raw_level.t Tag.def + +val nonce_tag : Nonce.t Tag.def + +val chain_tag : Block_services.chain Tag.def + +val block_tag : Block_services.block Tag.def + +val worker_tag : string Tag.def + +val block_header_tag : Block_header.t Tag.def + +val conflicting_endorsements_tag : + (Kind.endorsement operation * Kind.endorsement operation) Tag.def diff --git a/src/proto_011_PtHangzH/lib_delegate/tezos-accuser-011-PtHangzH-commands.opam b/src/proto_011_PtHangzH/lib_delegate/tezos-accuser-011-PtHangzH-commands.opam new file mode 100644 index 000000000000..36cbf4693c7f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/tezos-accuser-011-PtHangzH-commands.opam @@ -0,0 +1,23 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-base" + "tezos-protocol-environment" + "tezos-protocol-011-PtHangzH" + "tezos-shell-services" + "tezos-client-base" + "tezos-client-commands" + "tezos-client-011-PtHangzH" + "tezos-baking-011-PtHangzH" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: protocol-specific commands for `tezos-accuser`" diff --git a/src/proto_011_PtHangzH/lib_delegate/tezos-baking-011-PtHangzH-commands.opam b/src/proto_011_PtHangzH/lib_delegate/tezos-baking-011-PtHangzH-commands.opam new file mode 100644 index 000000000000..03b8b8c44a17 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/tezos-baking-011-PtHangzH-commands.opam @@ -0,0 +1,24 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-base" + "tezos-protocol-environment" + "tezos-protocol-011-PtHangzH" + "tezos-shell-services" + "tezos-shell-context" + "tezos-client-base" + "tezos-client-commands" + "tezos-client-011-PtHangzH" + "tezos-baking-011-PtHangzH" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: protocol-specific commands for baking" diff --git a/src/proto_011_PtHangzH/lib_delegate/tezos-baking-011-PtHangzH.opam b/src/proto_011_PtHangzH/lib_delegate/tezos-baking-011-PtHangzH.opam new file mode 100644 index 000000000000..f68446216fc2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/tezos-baking-011-PtHangzH.opam @@ -0,0 +1,26 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-base" + "tezos-version" + "tezos-protocol-environment" + "tezos-protocol-011-PtHangzH" + "tezos-shell-context" + "tezos-shell-services" + "tezos-client-base" + "tezos-client-commands" + "tezos-client-011-PtHangzH" + "lwt-canceler" { >= "0.3" & < "0.4" } + "lwt-exit" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: base library for `tezos-baker/endorser/accuser`" diff --git a/src/proto_011_PtHangzH/lib_delegate/tezos-endorser-011-PtHangzH-commands.opam b/src/proto_011_PtHangzH/lib_delegate/tezos-endorser-011-PtHangzH-commands.opam new file mode 100644 index 000000000000..27572cc83b1a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_delegate/tezos-endorser-011-PtHangzH-commands.opam @@ -0,0 +1,23 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-base" + "tezos-protocol-environment" + "tezos-protocol-011-PtHangzH" + "tezos-shell-services" + "tezos-client-base" + "tezos-client-commands" + "tezos-client-011-PtHangzH" + "tezos-baking-011-PtHangzH" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: protocol-specific commands for `tezos-endorser`" diff --git a/src/proto_011_PtHangzH/lib_parameters/.ocamlformat b/src/proto_011_PtHangzH/lib_parameters/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_parameters/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_parameters/default_parameters.ml b/src/proto_011_PtHangzH/lib_parameters/default_parameters.ml new file mode 100644 index 000000000000..cc9bc015e8da --- /dev/null +++ b/src/proto_011_PtHangzH/lib_parameters/default_parameters.ml @@ -0,0 +1,166 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol.Alpha_context + +let constants_mainnet = + Constants. + { + preserved_cycles = 5; + blocks_per_cycle = 8192l; + blocks_per_commitment = 64l; + blocks_per_roll_snapshot = 512l; + blocks_per_voting_period = 40960l; + time_between_blocks = List.map Period.of_seconds_exn [60L; 40L]; + minimal_block_delay = Period.of_seconds_exn 30L; + endorsers_per_block = 256; + hard_gas_limit_per_operation = Gas.Arith.(integral_of_int_exn 1_040_000); + hard_gas_limit_per_block = Gas.Arith.(integral_of_int_exn 5_200_000); + proof_of_work_threshold = Int64.(sub (shift_left 1L 46) 1L); + tokens_per_roll = Tez.(mul_exn one 8_000); + seed_nonce_revelation_tip = + (match Tez.(one /? 8L) with Ok c -> c | Error _ -> assert false); + origination_size = 257; + block_security_deposit = Tez.(mul_exn one 640); + endorsement_security_deposit = Tez.(mul_exn one_cent 250); + baking_reward_per_endorsement = + Tez.[of_mutez_exn 78_125L; of_mutez_exn 11_719L]; + endorsement_reward = Tez.[of_mutez_exn 78_125L; of_mutez_exn 52_083L]; + hard_storage_limit_per_operation = Z.of_int 60_000; + cost_per_byte = Tez.of_mutez_exn 250L; + quorum_min = 20_00l; + (* quorum is in centile of a percentage *) + quorum_max = 70_00l; + min_proposal_quorum = 5_00l; + initial_endorsers = 192; + delay_per_missing_endorsement = Period.of_seconds_exn 4L; + (* liquidity_baking_subsidy is 1/16th of total rewards for a block of priority 0 with all endorsements *) + liquidity_baking_subsidy = Tez.of_mutez_exn 2_500_000L; + (* level after protocol activation when liquidity baking shuts off: + about 6 months after first activation on mainnet *) + liquidity_baking_sunset_level = 2_244_609l; + (* 1/2 window size of 2000 blocks with precision of 1000 for integer computation *) + liquidity_baking_escape_ema_threshold = 1_000_000l; + } + +let constants_sandbox = + Constants. + { + constants_mainnet with + preserved_cycles = 2; + blocks_per_cycle = 8l; + blocks_per_commitment = 4l; + blocks_per_roll_snapshot = 4l; + blocks_per_voting_period = 64l; + time_between_blocks = List.map Period.of_seconds_exn [1L; 0L]; + minimal_block_delay = Period.of_seconds_exn 1L; + proof_of_work_threshold = Int64.of_int (-1); + initial_endorsers = 1; + delay_per_missing_endorsement = Period.of_seconds_exn 1L; + liquidity_baking_sunset_level = 4096l; + } + +let constants_test = + Constants. + { + constants_mainnet with + blocks_per_cycle = 128l; + blocks_per_commitment = 4l; + blocks_per_roll_snapshot = 32l; + blocks_per_voting_period = 256l; + time_between_blocks = List.map Period.of_seconds_exn [1L; 0L]; + minimal_block_delay = Period.of_seconds_exn 1L; + proof_of_work_threshold = Int64.of_int (-1); + initial_endorsers = 1; + delay_per_missing_endorsement = Period.of_seconds_exn 1L; + liquidity_baking_sunset_level = 4096l; + } + +let bootstrap_accounts_strings = + [ + "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav"; + "edpktzNbDAUjUk697W7gYg2CRuBQjyPxbEg8dLccYYwKSKvkPvjtV9"; + "edpkuTXkJDGcFd5nh6VvMz8phXxU3Bi7h6hqgywNFi1vZTfQNnS1RV"; + "edpkuFrRoDSEbJYgxRtLx2ps82UdaYc1WwfS9sE11yhauZt5DgCHbU"; + "edpkv8EUUH68jmo3f7Um5PezmfGrRF24gnfLpH3sVNwJnV5bVCxL2n"; + ] + +let bootstrap_balance = Tez.of_mutez_exn 4_000_000_000_000L + +let bootstrap_accounts = + List.map + (fun s -> + let public_key = Signature.Public_key.of_b58check_exn s in + let public_key_hash = Signature.Public_key.hash public_key in + Parameters. + { + public_key_hash; + public_key = Some public_key; + amount = bootstrap_balance; + }) + bootstrap_accounts_strings + +(* TODO this could be generated from OCaml together with the faucet + for now these are hardcoded values in the tests *) +let commitments = + let json_result = + Data_encoding.Json.from_string + {json| + [ + [ "btz1bRL4X5BWo2Fj4EsBdUwexXqgTf75uf1qa", "23932454669343" ], + [ "btz1SxjV1syBgftgKy721czKi3arVkVwYUFSv", "72954577464032" ], + [ "btz1LtoNCjiW23txBTenALaf5H6NKF1L3c1gw", "217487035428348" ], + [ "btz1SUd3mMhEBcWudrn8u361MVAec4WYCcFoy", "4092742372031" ], + [ "btz1MvBXf4orko1tsGmzkjLbpYSgnwUjEe81r", "17590039016550" ], + [ "btz1LoDZ3zsjgG3k3cqTpUMc9bsXbchu9qMXT", "26322312350555" ], + [ "btz1RMfq456hFV5AeDiZcQuZhoMv2dMpb9hpP", "244951387881443" ], + [ "btz1Y9roTh4A7PsMBkp8AgdVFrqUDNaBE59y1", "80065050465525" ], + [ "btz1Q1N2ePwhVw5ED3aaRVek6EBzYs1GDkSVD", "3569618927693" ], + [ "btz1VFFVsVMYHd5WfaDTAt92BeQYGK8Ri4eLy", "9034781424478" ] + ]|json} + in + match json_result with + | Error err -> raise (Failure err) + | Ok json -> + Data_encoding.Json.destruct (Data_encoding.list Commitment.encoding) json + +let make_bootstrap_account (pkh, pk, amount) = + Parameters.{public_key_hash = pkh; public_key = Some pk; amount} + +let parameters_of_constants ?(bootstrap_accounts = bootstrap_accounts) + ?(bootstrap_contracts = []) ?(with_commitments = false) constants = + let commitments = if with_commitments then commitments else [] in + Parameters. + { + bootstrap_accounts; + bootstrap_contracts; + commitments; + constants; + security_deposit_ramp_up_cycles = None; + no_reward_cycles = None; + } + +let json_of_parameters parameters = + Data_encoding.Json.construct Parameters.encoding parameters diff --git a/src/proto_011_PtHangzH/lib_parameters/default_parameters.mli b/src/proto_011_PtHangzH/lib_parameters/default_parameters.mli new file mode 100644 index 000000000000..0a99181fe345 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_parameters/default_parameters.mli @@ -0,0 +1,45 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol.Alpha_context + +val constants_mainnet : Constants.parametric + +val constants_sandbox : Constants.parametric + +val constants_test : Constants.parametric + +val make_bootstrap_account : + Signature.public_key_hash * Signature.public_key * Tez.t -> + Parameters.bootstrap_account + +val parameters_of_constants : + ?bootstrap_accounts:Parameters.bootstrap_account list -> + ?bootstrap_contracts:Parameters.bootstrap_contract list -> + ?with_commitments:bool -> + Constants.parametric -> + Parameters.t + +val json_of_parameters : Parameters.t -> Data_encoding.json diff --git a/src/proto_011_PtHangzH/lib_parameters/dune b/src/proto_011_PtHangzH/lib_parameters/dune new file mode 100644 index 000000000000..adb2b87fa0b2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_parameters/dune @@ -0,0 +1,41 @@ +(library + (name tezos_protocol_011_PtHangzH_parameters) + (instrumentation (backend bisect_ppx)) + (public_name tezos-protocol-011-PtHangzH-parameters) + (modules :standard \ gen) + (libraries tezos-base + tezos-base.unix + tezos-protocol-environment + tezos-protocol-011-PtHangzH) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_protocol_011_PtHangzH + -linkall)) +) + +(executable + (name gen) + (libraries tezos-base + tezos-protocol-011-PtHangzH-parameters) + (modules gen) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_protocol_011_PtHangzH_parameters + -linkall))) + +(rule + (targets sandbox-parameters.json) + (deps gen.exe) + (action (run %{deps} --sandbox))) + +(rule + (targets test-parameters.json) + (deps gen.exe) + (action (run %{deps} --test))) + +(rule + (targets mainnet-parameters.json) + (deps gen.exe) + (action (run %{deps} --mainnet))) + +(install + (section lib) + (files sandbox-parameters.json test-parameters.json mainnet-parameters.json)) diff --git a/src/proto_011_PtHangzH/lib_parameters/dune-project b/src/proto_011_PtHangzH/lib_parameters/dune-project new file mode 100644 index 000000000000..f8fc7c727842 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_parameters/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(formatting (enabled_for ocaml)) +(name tezos-protocol-alpha-parameters) diff --git a/src/proto_011_PtHangzH/lib_parameters/gen.ml b/src/proto_011_PtHangzH/lib_parameters/gen.ml new file mode 100644 index 000000000000..aa1d7a3a1c67 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_parameters/gen.ml @@ -0,0 +1,61 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Prints the json encoding of the parametric constants of protocol alpha. + $ dune utop src/proto_alpha/lib_protocol/test/helpers/ constants.ml +*) + +let () = + let print_usage_and_fail s = + Printf.eprintf "Usage: %s [ --sandbox | --test | --mainnet ]" Sys.argv.(0) ; + raise (Invalid_argument s) + in + let dump parameters file = + let str = + Data_encoding.Json.to_string + (Default_parameters.json_of_parameters parameters) + in + let fd = open_out file in + output_string fd str ; + close_out fd + in + if Array.length Sys.argv < 2 then print_usage_and_fail "" + else + match Sys.argv.(1) with + | "--sandbox" -> + dump + Default_parameters.(parameters_of_constants constants_sandbox) + "sandbox-parameters.json" + | "--test" -> + dump + Default_parameters.( + parameters_of_constants ~with_commitments:true constants_sandbox) + "test-parameters.json" + | "--mainnet" -> + dump + Default_parameters.( + parameters_of_constants ~with_commitments:true constants_mainnet) + "mainnet-parameters.json" + | s -> print_usage_and_fail s diff --git a/src/proto_011_PtHangzH/lib_parameters/tezos-protocol-011-PtHangzH-parameters.opam b/src/proto_011_PtHangzH/lib_parameters/tezos-protocol-011-PtHangzH-parameters.opam new file mode 100644 index 000000000000..1ccc5cdac6d6 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_parameters/tezos-protocol-011-PtHangzH-parameters.opam @@ -0,0 +1,18 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-base" + "tezos-protocol-environment" + "tezos-protocol-011-PtHangzH" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: parameters" diff --git a/src/proto_011_PtHangzH/lib_plugin/.ocamlformat b/src/proto_011_PtHangzH/lib_plugin/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_plugin/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_plugin/dune b/src/proto_011_PtHangzH/lib_plugin/dune new file mode 100644 index 000000000000..33fc37432a9a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_plugin/dune @@ -0,0 +1,23 @@ +(library + (name tezos_protocol_plugin_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-protocol-plugin-011-PtHangzH) + (libraries tezos-base + tezos-protocol-011-PtHangzH) + (modules (:standard) \ Plugin_registerer) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_protocol_011_PtHangzH))) + +(library + (name tezos_protocol_plugin_011_PtHangzH_registerer) + (instrumentation (backend bisect_ppx)) + (public_name tezos-protocol-plugin-011-PtHangzH-registerer) + (libraries tezos-base + tezos-embedded-protocol-011-PtHangzH + tezos-protocol-plugin-011-PtHangzH + tezos-shell) + (modules Plugin_registerer) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_embedded_protocol_011_PtHangzH + -open Tezos_protocol_plugin_011_PtHangzH + -open Tezos_shell))) diff --git a/src/proto_011_PtHangzH/lib_plugin/dune-project b/src/proto_011_PtHangzH/lib_plugin/dune-project new file mode 100644 index 000000000000..88f641f73633 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_plugin/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(formatting (enabled_for ocaml)) +(name tezos-filters-alpha) diff --git a/src/proto_011_PtHangzH/lib_plugin/plugin.ml b/src/proto_011_PtHangzH/lib_plugin/plugin.ml new file mode 100644 index 000000000000..5c980460412a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_plugin/plugin.ml @@ -0,0 +1,2528 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Nomadic Development. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +(** The assumed number of blocks between operation-creation time and + the actual time when the operation is included in a block. *) +let default_operation_inclusion_latency = 3 + +type Environment.Error_monad.error += Cannot_parse_operation (* `Branch *) + +type Environment.Error_monad.error += Cannot_serialize_log + +let () = + Environment.Error_monad.register_error_kind + `Branch + ~id:"operation.cannot_parse" + ~title:"Cannot parse operation" + ~description:"The operation is ill-formed or for another protocol version" + ~pp:(fun ppf () -> Format.fprintf ppf "The operation cannot be parsed") + Data_encoding.unit + (function Cannot_parse_operation -> Some () | _ -> None) + (fun () -> Cannot_parse_operation) ; + (* Cannot serialize log *) + Environment.Error_monad.register_error_kind + `Temporary + ~id:"michelson_v1.cannot_serialize_log" + ~title:"Not enough gas to serialize execution trace" + ~description: + "Execution trace with stacks was to big to be serialized with the \ + provided gas" + Data_encoding.empty + (function Cannot_serialize_log -> Some () | _ -> None) + (fun () -> Cannot_serialize_log) + +module Mempool = struct + type nanotez = Q.t + + let nanotez_enc : nanotez Data_encoding.t = + let open Data_encoding in + def + "nanotez" + ~title:"A thousandth of a mutez" + ~description:"One thousand nanotez make a mutez (1 tez = 1e9 nanotez)" + (conv + (fun q -> (q.Q.num, q.Q.den)) + (fun (num, den) -> {Q.num; den}) + (tup2 z z)) + + type config = { + minimal_fees : Tez.t; + minimal_nanotez_per_gas_unit : nanotez; + minimal_nanotez_per_byte : nanotez; + allow_script_failure : bool; + } + + let default_minimal_fees = + match Tez.of_mutez 100L with None -> assert false | Some t -> t + + let default_minimal_nanotez_per_gas_unit = Q.of_int 100 + + let default_minimal_nanotez_per_byte = Q.of_int 1000 + + let config_encoding : config Data_encoding.t = + let open Data_encoding in + conv + (fun { + minimal_fees; + minimal_nanotez_per_gas_unit; + minimal_nanotez_per_byte; + allow_script_failure; + } -> + ( minimal_fees, + minimal_nanotez_per_gas_unit, + minimal_nanotez_per_byte, + allow_script_failure )) + (fun ( minimal_fees, + minimal_nanotez_per_gas_unit, + minimal_nanotez_per_byte, + allow_script_failure ) -> + { + minimal_fees; + minimal_nanotez_per_gas_unit; + minimal_nanotez_per_byte; + allow_script_failure; + }) + (obj4 + (dft "minimal_fees" Tez.encoding default_minimal_fees) + (dft + "minimal_nanotez_per_gas_unit" + nanotez_enc + default_minimal_nanotez_per_gas_unit) + (dft + "minimal_nanotez_per_byte" + nanotez_enc + default_minimal_nanotez_per_byte) + (dft "allow_script_failure" bool true)) + + let default_config = + { + minimal_fees = default_minimal_fees; + minimal_nanotez_per_gas_unit = default_minimal_nanotez_per_gas_unit; + minimal_nanotez_per_byte = default_minimal_nanotez_per_byte; + allow_script_failure = true; + } + + let get_manager_operation_gas_and_fee contents = + let open Operation in + let l = to_list (Contents_list contents) in + List.fold_left + (fun acc -> function + | Contents (Manager_operation {fee; gas_limit; _}) -> ( + match acc with + | Error _ as e -> e + | Ok (total_fee, total_gas) -> ( + match Tez.(total_fee +? fee) with + | Ok total_fee -> + Ok (total_fee, Gas.Arith.add total_gas gas_limit) + | Error _ as e -> e)) + | _ -> acc) + (Ok (Tez.zero, Gas.Arith.zero)) + l + + type Environment.Error_monad.error += Fees_too_low + + let () = + Environment.Error_monad.register_error_kind + `Permanent + ~id:"prefilter.fees_too_low" + ~title:"Operation fees are too low" + ~description:"Operation fees are too low" + ~pp:(fun ppf () -> Format.fprintf ppf "Operation fees are too low") + Data_encoding.unit + (function Fees_too_low -> Some () | _ -> None) + (fun () -> Fees_too_low) + + let pre_filter_manager : + type t. + config -> + t Kind.manager contents_list -> + int -> + [ `Undecided + | `Branch_refused of tztrace + | `Branch_delayed of tztrace + | `Refused of tztrace ] = + fun config op size -> + match get_manager_operation_gas_and_fee op with + | Error err -> + let err = Environment.wrap_tztrace err in + `Refused err + | Ok (fee, gas) -> + let fees_in_nanotez = + Q.mul (Q.of_int64 (Tez.to_mutez fee)) (Q.of_int 1000) + in + let minimal_fees_in_nanotez = + Q.mul (Q.of_int64 (Tez.to_mutez config.minimal_fees)) (Q.of_int 1000) + in + let minimal_fees_for_gas_in_nanotez = + Q.mul + config.minimal_nanotez_per_gas_unit + (Q.of_bigint @@ Gas.Arith.integral_to_z gas) + in + let minimal_fees_for_size_in_nanotez = + Q.mul config.minimal_nanotez_per_byte (Q.of_int size) + in + if + Q.compare + fees_in_nanotez + (Q.add + minimal_fees_in_nanotez + (Q.add + minimal_fees_for_gas_in_nanotez + minimal_fees_for_size_in_nanotez)) + >= 0 + then `Undecided + else `Refused [Environment.wrap_tzerror Fees_too_low] + + type Environment.Error_monad.error += Outdated_endorsement + + let () = + Environment.Error_monad.register_error_kind + `Temporary + ~id:"prefilter.outdated_endorsement" + ~title:"Endorsement is outdated" + ~description:"Endorsement is outdated" + ~pp:(fun ppf () -> Format.fprintf ppf "Endorsement is outdated") + Data_encoding.unit + (function Outdated_endorsement -> Some () | _ -> None) + (fun () -> Outdated_endorsement) + + type Environment.Error_monad.error += Wrong_operation + + let () = + Environment.Error_monad.register_error_kind + `Temporary + ~id:"prefilter.wrong_operation" + ~title:"Wrong operation" + ~description:"Failing_noop and old endorsement format are not accepted." + ~pp:(fun ppf () -> + Format.fprintf + ppf + "Failing_noop and old endorsement format are not accepted") + Data_encoding.unit + (function Wrong_operation -> Some () | _ -> None) + (fun () -> Wrong_operation) + + let pre_filter config ?validation_state_before + (Operation_data {contents; _} as op : Operation.packed_protocol_data) = + let bytes = + (WithExceptions.Option.get ~loc:__LOC__ + @@ Data_encoding.Binary.fixed_length + Tezos_base.Operation.shell_header_encoding) + + Data_encoding.Binary.length Operation.protocol_data_encoding op + in + match contents with + | Single (Endorsement _) | Single (Failing_noop _) -> + `Refused [Environment.wrap_tzerror Wrong_operation] + | Single + (Endorsement_with_slot + { + endorsement = + { + protocol_data = {contents = Single (Endorsement {level}); _}; + shell = {branch}; + }; + _; + }) -> ( + match validation_state_before with + | None -> `Undecided + | Some {ctxt; mode; _} -> ( + match mode with + | Partial_construction {predecessor} -> + if Block_hash.(predecessor = branch) then + (* conensus operation for the current head. *) + `Undecided + else + let current_level = (Level.current ctxt).level in + let delta = Raw_level.diff current_level level in + if delta > 2l then + (* consensus operation too far in the past. *) + `Refused [Environment.wrap_tzerror Outdated_endorsement] + else + (* consensus operation not too far in the past or in the + future. *) + `Branch_delayed + [Environment.wrap_tzerror Outdated_endorsement] + | _ -> assert false)) + | Single (Seed_nonce_revelation _) + | Single (Double_endorsement_evidence _) + | Single (Double_baking_evidence _) + | Single (Activate_account _) + | Single (Proposals _) + | Single (Ballot _) -> + `Undecided + | Single (Manager_operation _) as op -> pre_filter_manager config op bytes + | Cons (Manager_operation _, _) as op -> pre_filter_manager config op bytes + + open Apply_results + + let rec post_filter_manager : + type t. + Alpha_context.t -> + t Kind.manager contents_result_list -> + config -> + bool Lwt.t = + fun ctxt op config -> + match op with + | Single_result (Manager_operation_result {operation_result; _}) -> ( + match operation_result with + | Applied _ -> Lwt.return_true + | Skipped _ | Failed _ | Backtracked _ -> + Lwt.return config.allow_script_failure) + | Cons_result (Manager_operation_result res, rest) -> ( + post_filter_manager + ctxt + (Single_result (Manager_operation_result res)) + config + >>= function + | false -> Lwt.return_false + | true -> post_filter_manager ctxt rest config) + + let post_filter config ~validation_state_before:_ + ~validation_state_after:({ctxt; _} : validation_state) (_op, receipt) = + match receipt with + | No_operation_metadata -> assert false (* only for multipass validator *) + | Operation_metadata {contents} -> ( + match contents with + | Single_result (Endorsement_result _) -> + Lwt.return_false (* legacy format *) + | Single_result (Endorsement_with_slot_result _) -> Lwt.return_true + | Single_result (Seed_nonce_revelation_result _) -> Lwt.return_true + | Single_result (Double_endorsement_evidence_result _) -> + Lwt.return_true + | Single_result (Double_baking_evidence_result _) -> Lwt.return_true + | Single_result (Activate_account_result _) -> Lwt.return_true + | Single_result Proposals_result -> Lwt.return_true + | Single_result Ballot_result -> Lwt.return_true + | Single_result (Manager_operation_result _) as op -> + post_filter_manager ctxt op config + | Cons_result (Manager_operation_result _, _) as op -> + post_filter_manager ctxt op config) +end + +module View_helpers = struct + open Tezos_micheline + + type Environment.Error_monad.error += Viewed_contract_has_no_script + + type Environment.Error_monad.error += View_callback_origination_failed + + type Environment.Error_monad.error += + | Illformed_view_type of string * Script.expr + + type Environment.Error_monad.error += + | View_never_returns of string * Contract.t + + type Environment.Error_monad.error += + | View_unexpected_return of string * Contract.t + + let () = + Environment.Error_monad.register_error_kind + `Permanent + ~id:"viewedContractHasNoScript" + ~title:"Viewed contract has no script" + ~description:"A view was called on a contract with no script." + ~pp:(fun ppf () -> + Format.fprintf ppf "A view was called on a contract with no script.") + Data_encoding.(unit) + (function Viewed_contract_has_no_script -> Some () | _ -> None) + (fun () -> Viewed_contract_has_no_script) ; + Environment.Error_monad.register_error_kind + `Permanent + ~id:"viewCallbackOriginationFailed" + ~title:"View callback origination failed" + ~description:"View callback origination failed" + ~pp:(fun ppf () -> + Format.fprintf ppf "Error during origination of view callback contract.") + Data_encoding.(unit) + (function View_callback_origination_failed -> Some () | _ -> None) + (fun () -> View_callback_origination_failed) ; + Environment.Error_monad.register_error_kind + `Permanent + ~id:"illformedViewType" + ~title:"An entrypoint type is incompatible with TZIP-4 view type." + ~description:"An entrypoint type is incompatible with TZIP-4 view type." + ~pp:(fun ppf (entrypoint, typ) -> + Format.fprintf + ppf + "The view %s has type %a, it is not compatible with a TZIP-4 view \ + type." + entrypoint + Micheline_printer.print_expr + (Micheline_printer.printable + (fun x -> x) + (Michelson_v1_primitives.strings_of_prims typ))) + Data_encoding.( + obj2 (req "entrypoint" string) (req "type" Script.expr_encoding)) + (function Illformed_view_type (etp, exp) -> Some (etp, exp) | _ -> None) + (fun (etp, exp) -> Illformed_view_type (etp, exp)) ; + Environment.Error_monad.register_error_kind + `Permanent + ~id:"viewNeverReturns" + ~title: + "A view never returned a transaction to the given callback contract" + ~description: + "A view never initiated a transaction to the given callback contract." + ~pp:(fun ppf (entrypoint, callback) -> + Format.fprintf + ppf + "The view %s never initiated a transaction to the given callback \ + contract %a." + entrypoint + Contract.pp + callback) + Data_encoding.( + obj2 (req "entrypoint" string) (req "callback" Contract.encoding)) + (function View_never_returns (e, c) -> Some (e, c) | _ -> None) + (fun (e, c) -> View_never_returns (e, c)) ; + Environment.Error_monad.register_error_kind + `Permanent + ~id:"viewUnexpectedReturn" + ~title:"A view returned an unexpected list of operations" + ~description: + "A view initiated a list of operations while the TZIP-4 standard \ + expects only a transaction to the given callback contract." + ~pp:(fun ppf (entrypoint, callback) -> + Format.fprintf + ppf + "The view %s initiated a list of operations while the TZIP-4 \ + standard expects only a transaction to the given callback contract \ + %a." + entrypoint + Contract.pp + callback) + Data_encoding.( + obj2 (req "entrypoint" string) (req "callback" Contract.encoding)) + (function View_never_returns (e, c) -> Some (e, c) | _ -> None) + (fun (e, c) -> View_never_returns (e, c)) + + (* This script is actually never run, its usage is to ensure a + contract that has the type `contract ` is originated, which + will be required as callback of the view. *) + let make_viewer_script ty : Script.t = + let loc = 0 in + let ty = Micheline.root ty in + let code = + Micheline.strip_locations + @@ Micheline.Seq + ( loc, + [ + Micheline.Prim (loc, Script.K_parameter, [ty], []); + Micheline.Prim + ( loc, + Script.K_storage, + [Micheline.Prim (loc, Script.T_unit, [], [])], + [] ); + Micheline.Prim + ( loc, + Script.K_code, + [Micheline.Prim (loc, Script.I_FAILWITH, [], [])], + [] ); + ] ) + in + let storage = + Micheline.strip_locations (Micheline.Prim (loc, Script.D_Unit, [], [])) + in + {code = Script.lazy_expr code; storage = Script.lazy_expr storage} + + let make_view_parameter input callback = + let loc = 0 in + Micheline.strip_locations + (Micheline.Prim + ( loc, + Script.D_Pair, + [ + input; + Micheline.Bytes + ( loc, + Data_encoding.Binary.to_bytes_exn Contract.encoding callback ); + ], + [] )) + + let extract_view_output_type entrypoint ty = + match Micheline.root ty with + | Micheline.Prim + ( _, + Script.T_pair, + [_; Micheline.Prim (_, Script.T_contract, [ty], _)], + _ ) -> + ok (Micheline.strip_locations ty) + | _ -> Environment.Error_monad.error (Illformed_view_type (entrypoint, ty)) + + (* 'view' entrypoints returns their value by calling a callback contract, thus + the expected result is a unique internal transaction to this callback. *) + let extract_parameter_from_operations entrypoint operations callback = + let unexpected_return = + Environment.Error_monad.error + @@ View_unexpected_return (entrypoint, callback) + in + match operations with + | [ + Internal_operation + {operation = Transaction {destination; parameters; _}; _}; + ] + when Contract.equal destination callback -> + ok parameters + | [] -> + Environment.Error_monad.error + (View_never_returns (entrypoint, callback)) + | _ -> unexpected_return +end + +module RPC = struct + open Environment + open Alpha_context + open Environment.Error_monad + + let parse_operation (op : Operation.raw) = + match + Data_encoding.Binary.of_bytes_opt + Operation.protocol_data_encoding + op.proto + with + | Some protocol_data -> ok {shell = op.shell; protocol_data} + | None -> error Cannot_parse_operation + + let path = RPC_path.(open_root / "helpers") + + module Registration = struct + let patched_services = + ref (RPC_directory.empty : Updater.rpc_context RPC_directory.t) + + let register0_fullctxt ~chunked s f = + patched_services := + RPC_directory.register ~chunked !patched_services s (fun ctxt q i -> + Services_registration.rpc_init ctxt >>=? fun ctxt -> f ctxt q i) + + let register0 ~chunked s f = + register0_fullctxt ~chunked s (fun {context; _} -> f context) + + let register0_noctxt ~chunked s f = + patched_services := + RPC_directory.register ~chunked !patched_services s (fun _ q i -> f q i) + + let opt_register0_fullctxt ~chunked s f = + patched_services := + RPC_directory.opt_register ~chunked !patched_services s (fun ctxt q i -> + Services_registration.rpc_init ctxt >>=? fun ctxt -> f ctxt q i) + + let opt_register0 ~chunked s f = + opt_register0_fullctxt ~chunked s (fun {context; _} -> f context) + + let register1_fullctxt ~chunked s f = + patched_services := + RPC_directory.register + ~chunked + !patched_services + s + (fun (ctxt, arg) q i -> + Services_registration.rpc_init ctxt >>=? fun ctxt -> f ctxt arg q i) + + let register1 ~chunked s f = + register1_fullctxt ~chunked s (fun {context; _} x -> f context x) + + let register2_fullctxt ~chunked s f = + patched_services := + RPC_directory.register + ~chunked + !patched_services + s + (fun ((ctxt, arg1), arg2) q i -> + Services_registration.rpc_init ctxt >>=? fun ctxt -> + f ctxt arg1 arg2 q i) + + let register2 ~chunked s f = + register2_fullctxt ~chunked s (fun {context; _} a1 a2 q i -> + f context a1 a2 q i) + end + + let unparsing_mode_encoding = + let open Script_ir_translator in + let open Data_encoding in + union + ~tag_size:`Uint8 + [ + case + (Tag 0) + ~title:"Readable" + (constant "Readable") + (function + | Readable -> Some () | Optimized | Optimized_legacy -> None) + (fun () -> Readable); + case + (Tag 1) + ~title:"Optimized" + (constant "Optimized") + (function + | Optimized -> Some () | Readable | Optimized_legacy -> None) + (fun () -> Optimized); + case + (Tag 2) + ~title:"Optimized_legacy" + (constant "Optimized_legacy") + (function + | Optimized_legacy -> Some () | Readable | Optimized -> None) + (fun () -> Optimized_legacy); + ] + + module Scripts = struct + module S = struct + open Data_encoding + + let path = RPC_path.(path / "scripts") + + let run_code_input_encoding = + merge_objs + (obj10 + (req "script" Script.expr_encoding) + (req "storage" Script.expr_encoding) + (req "input" Script.expr_encoding) + (req "amount" Tez.encoding) + (req "balance" Tez.encoding) + (req "chain_id" Chain_id.encoding) + (opt "source" Contract.encoding) + (opt "payer" Contract.encoding) + (opt "gas" Gas.Arith.z_integral_encoding) + (dft "entrypoint" string "default")) + (obj1 (opt "unparsing_mode" unparsing_mode_encoding)) + + let run_code_output_encoding = + conv + (fun (storage, operations, lazy_storage_diff) -> + (storage, operations, lazy_storage_diff, lazy_storage_diff)) + (fun (storage, operations, legacy_lazy_storage_diff, lazy_storage_diff) + -> + let lazy_storage_diff = + Option.either lazy_storage_diff legacy_lazy_storage_diff + in + (storage, operations, lazy_storage_diff)) + (obj4 + (req "storage" Script.expr_encoding) + (req "operations" (list Operation.internal_operation_encoding)) + (opt "big_map_diff" Lazy_storage.legacy_big_map_diff_encoding) + (opt "lazy_storage_diff" Lazy_storage.encoding)) + + let trace_code_input_encoding = run_code_input_encoding + + let trace_encoding = + def "scripted.trace" @@ list + @@ obj3 + (req "location" Script.location_encoding) + (req "gas" Gas.encoding) + (req + "stack" + (list + (obj2 (req "item" Script.expr_encoding) (opt "annot" string)))) + + let trace_code_output_encoding = + conv + (fun (storage, operations, trace, lazy_storage_diff) -> + (storage, operations, trace, lazy_storage_diff, lazy_storage_diff)) + (fun ( storage, + operations, + trace, + legacy_lazy_storage_diff, + lazy_storage_diff ) -> + let lazy_storage_diff = + Option.either lazy_storage_diff legacy_lazy_storage_diff + in + (storage, operations, trace, lazy_storage_diff)) + (obj5 + (req "storage" Script.expr_encoding) + (req "operations" (list Operation.internal_operation_encoding)) + (req "trace" trace_encoding) + (opt "big_map_diff" Lazy_storage.legacy_big_map_diff_encoding) + (opt "lazy_storage_diff" Lazy_storage.encoding)) + + let run_view_encoding = + let open Data_encoding in + obj8 + (req "contract" Contract.encoding) + (req "entrypoint" string) + (req "input" Script.expr_encoding) + (req "chain_id" Chain_id.encoding) + (opt "source" Contract.encoding) + (opt "payer" Contract.encoding) + (opt "gas" Gas.Arith.z_integral_encoding) + (req "unparsing_mode" unparsing_mode_encoding) + + let run_code = + RPC_service.post_service + ~description:"Run a piece of code in the current context" + ~query:RPC_query.empty + ~input:run_code_input_encoding + ~output:run_code_output_encoding + RPC_path.(path / "run_code") + + let trace_code = + RPC_service.post_service + ~description: + "Run a piece of code in the current context, keeping a trace" + ~query:RPC_query.empty + ~input:trace_code_input_encoding + ~output:trace_code_output_encoding + RPC_path.(path / "trace_code") + + let run_view = + RPC_service.post_service + ~description: + "Simulate a call to a view following the TZIP-4 standard. See \ + https://gitlab.com/tzip/tzip/-/blob/master/proposals/tzip-4/tzip-4.md#view-entrypoints." + ~input:run_view_encoding + ~output:(obj1 (req "data" Script.expr_encoding)) + ~query:RPC_query.empty + RPC_path.(path / "run_view") + + let typecheck_code = + RPC_service.post_service + ~description:"Typecheck a piece of code in the current context" + ~query:RPC_query.empty + ~input: + (obj3 + (req "program" Script.expr_encoding) + (opt "gas" Gas.Arith.z_integral_encoding) + (opt "legacy" bool)) + ~output: + (obj2 + (req "type_map" Script_tc_errors_registration.type_map_enc) + (req "gas" Gas.encoding)) + RPC_path.(path / "typecheck_code") + + let script_size = + RPC_service.post_service + ~description:"Compute the size of a script in the current context" + ~query:RPC_query.empty + ~input: + (obj4 + (req "program" Script.expr_encoding) + (req "storage" Script.expr_encoding) + (opt "gas" Gas.Arith.z_integral_encoding) + (opt "legacy" bool)) + ~output:(obj1 (req "script_size" int31)) + RPC_path.(path / "script_size") + + let typecheck_data = + RPC_service.post_service + ~description: + "Check that some data expression is well formed and of a given \ + type in the current context" + ~query:RPC_query.empty + ~input: + (obj4 + (req "data" Script.expr_encoding) + (req "type" Script.expr_encoding) + (opt "gas" Gas.Arith.z_integral_encoding) + (opt "legacy" bool)) + ~output:(obj1 (req "gas" Gas.encoding)) + RPC_path.(path / "typecheck_data") + + let pack_data = + RPC_service.post_service + ~description: + "Computes the serialized version of some data expression using the \ + same algorithm as script instruction PACK" + ~input: + (obj3 + (req "data" Script.expr_encoding) + (req "type" Script.expr_encoding) + (opt "gas" Gas.Arith.z_integral_encoding)) + ~output:(obj2 (req "packed" bytes) (req "gas" Gas.encoding)) + ~query:RPC_query.empty + RPC_path.(path / "pack_data") + + let normalize_data = + RPC_service.post_service + ~description: + "Normalizes some data expression using the requested unparsing mode" + ~input: + (obj4 + (req "data" Script.expr_encoding) + (req "type" Script.expr_encoding) + (req "unparsing_mode" unparsing_mode_encoding) + (opt "legacy" bool)) + ~output:(obj1 (req "normalized" Script.expr_encoding)) + ~query:RPC_query.empty + RPC_path.(path / "normalize_data") + + let normalize_script = + RPC_service.post_service + ~description: + "Normalizes a Michelson script using the requested unparsing mode" + ~input: + (obj2 + (req "script" Script.expr_encoding) + (req "unparsing_mode" unparsing_mode_encoding)) + ~output:(obj1 (req "normalized" Script.expr_encoding)) + ~query:RPC_query.empty + RPC_path.(path / "normalize_script") + + let normalize_type = + RPC_service.post_service + ~description: + "Normalizes some Michelson type by expanding `pair a b c` as `pair \ + a (pair b c)" + ~input:(obj1 (req "type" Script.expr_encoding)) + ~output:(obj1 (req "normalized" Script.expr_encoding)) + ~query:RPC_query.empty + RPC_path.(path / "normalize_type") + + let run_operation = + RPC_service.post_service + ~description:"Run an operation without signature checks" + ~query:RPC_query.empty + ~input: + (obj2 + (req "operation" Operation.encoding) + (req "chain_id" Chain_id.encoding)) + ~output:Apply_results.operation_data_and_metadata_encoding + RPC_path.(path / "run_operation") + + let simulate_operation = + RPC_service.post_service + ~description:"Simulate an operation" + ~query:RPC_query.empty + ~input: + (obj3 + (req "operation" Operation.encoding) + (req "chain_id" Chain_id.encoding) + (dft "latency" int16 default_operation_inclusion_latency)) + ~output:Apply_results.operation_data_and_metadata_encoding + RPC_path.(path / "simulate_operation") + + let entrypoint_type = + RPC_service.post_service + ~description:"Return the type of the given entrypoint" + ~query:RPC_query.empty + ~input: + (obj2 + (req "script" Script.expr_encoding) + (dft "entrypoint" string "default")) + ~output:(obj1 (req "entrypoint_type" Script.expr_encoding)) + RPC_path.(path / "entrypoint") + + let list_entrypoints = + RPC_service.post_service + ~description:"Return the list of entrypoints of the given script" + ~query:RPC_query.empty + ~input:(obj1 (req "script" Script.expr_encoding)) + ~output: + (obj2 + (dft + "unreachable" + (Data_encoding.list + (obj1 + (req + "path" + (Data_encoding.list + Michelson_v1_primitives.prim_encoding)))) + []) + (req "entrypoints" (assoc Script.expr_encoding))) + RPC_path.(path / "entrypoints") + end + + module type UNPARSING_MODE = sig + val unparsing_mode : Script_ir_translator.unparsing_mode + end + + module Traced_interpreter (Unparsing_mode : UNPARSING_MODE) = struct + type log_element = + | Log : + context + * Script.location + * ('a * 's) + * ('a, 's) Script_typed_ir.stack_ty + -> log_element + + let unparse_stack ctxt (stack, stack_ty) = + (* We drop the gas limit as this function is only used for debugging/errors. *) + let ctxt = Gas.set_unlimited ctxt in + let rec unparse_stack : + type a s. + (a, s) Script_typed_ir.stack_ty * (a * s) -> + (Script.expr * string option) list tzresult Lwt.t = function + | (Bot_t, (EmptyCell, EmptyCell)) -> return_nil + | (Item_t (ty, rest_ty, annot), (v, rest)) -> + Script_ir_translator.unparse_data + ctxt + Unparsing_mode.unparsing_mode + ty + v + >>=? fun (data, _ctxt) -> + unparse_stack (rest_ty, rest) >|=? fun rest -> + let annot = + match Script_ir_annot.unparse_var_annot annot with + | [] -> None + | [a] -> Some a + | _ -> assert false + in + let data = Micheline.strip_locations data in + (data, annot) :: rest + in + unparse_stack (stack_ty, stack) + + let trace_logger () : Script_typed_ir.logger = + let log : log_element list ref = ref [] in + let log_interp _ ctxt loc sty stack = + log := Log (ctxt, loc, stack, sty) :: !log + in + let log_entry _ _ctxt _loc _sty _stack = () in + let log_exit _ ctxt loc sty stack = + log := Log (ctxt, loc, stack, sty) :: !log + in + let log_control _ = () in + let get_log () = + List.map_es + (fun (Log (ctxt, loc, stack, stack_ty)) -> + trace Cannot_serialize_log (unparse_stack ctxt (stack, stack_ty)) + >>=? fun stack -> return (loc, Gas.level ctxt, stack)) + !log + >>=? fun res -> return (Some (List.rev res)) + in + {log_exit; log_entry; log_interp; get_log; log_control} + + let execute ctxt step_constants ~script ~entrypoint ~parameter = + let open Script_interpreter in + let logger = trace_logger () in + execute + ~logger + ~cached_script:None + ctxt + Unparsing_mode.unparsing_mode + step_constants + ~script + ~entrypoint + ~parameter + ~internal:true + >>=? fun ({ctxt; storage; lazy_storage_diff; operations}, _) -> + logger.get_log () >|=? fun trace -> + let trace = Option.value ~default:[] trace in + ({ctxt; storage; lazy_storage_diff; operations}, trace) + end + + let typecheck_data : + legacy:bool -> + context -> + Script.expr * Script.expr -> + context tzresult Lwt.t = + fun ~legacy ctxt (data, exp_ty) -> + record_trace + (Script_tc_errors.Ill_formed_type (None, exp_ty, 0)) + (Script_ir_translator.parse_parameter_ty + ctxt + ~legacy + (Micheline.root exp_ty)) + >>?= fun (Ex_ty exp_ty, ctxt) -> + trace_eval + (fun () -> + Lwt.return + ( Script_ir_translator.serialize_ty_for_error ctxt exp_ty + >|? fun (exp_ty, _ctxt) -> + Script_tc_errors.Ill_typed_data (None, data, exp_ty) )) + (let allow_forged = + true + (* Safe since we ignore the value afterwards. *) + in + Script_ir_translator.parse_data + ctxt + ~legacy + ~allow_forged + exp_ty + (Micheline.root data)) + >|=? fun (_, ctxt) -> ctxt + + module Unparse_types = struct + (* Same as the unparsing functions for types in Script_ir_translator but + does not consume gas and never folds (pair a (pair b c)) *) + + open Script_ir_translator + open Micheline + open Michelson_v1_primitives + open Script_ir_annot + open Script_typed_ir + + let rec unparse_comparable_ty : type a. a comparable_ty -> Script.node = + function + | Unit_key meta -> Prim (-1, T_unit, [], unparse_type_annot meta.annot) + | Never_key meta -> Prim (-1, T_never, [], unparse_type_annot meta.annot) + | Int_key meta -> Prim (-1, T_int, [], unparse_type_annot meta.annot) + | Nat_key meta -> Prim (-1, T_nat, [], unparse_type_annot meta.annot) + | Signature_key meta -> + Prim (-1, T_signature, [], unparse_type_annot meta.annot) + | String_key meta -> + Prim (-1, T_string, [], unparse_type_annot meta.annot) + | Bytes_key meta -> Prim (-1, T_bytes, [], unparse_type_annot meta.annot) + | Mutez_key meta -> Prim (-1, T_mutez, [], unparse_type_annot meta.annot) + | Bool_key meta -> Prim (-1, T_bool, [], unparse_type_annot meta.annot) + | Key_hash_key meta -> + Prim (-1, T_key_hash, [], unparse_type_annot meta.annot) + | Key_key meta -> Prim (-1, T_key, [], unparse_type_annot meta.annot) + | Timestamp_key meta -> + Prim (-1, T_timestamp, [], unparse_type_annot meta.annot) + | Address_key meta -> + Prim (-1, T_address, [], unparse_type_annot meta.annot) + | Chain_id_key meta -> + Prim (-1, T_chain_id, [], unparse_type_annot meta.annot) + | Pair_key ((l, al), (r, ar), meta) -> + let tl = add_field_annot al None (unparse_comparable_ty l) in + let tr = add_field_annot ar None (unparse_comparable_ty r) in + Prim (-1, T_pair, [tl; tr], unparse_type_annot meta.annot) + | Union_key ((l, al), (r, ar), meta) -> + let tl = add_field_annot al None (unparse_comparable_ty l) in + let tr = add_field_annot ar None (unparse_comparable_ty r) in + Prim (-1, T_or, [tl; tr], unparse_type_annot meta.annot) + | Option_key (t, meta) -> + Prim + ( -1, + T_option, + [unparse_comparable_ty t], + unparse_type_annot meta.annot ) + + let unparse_memo_size memo_size = + let z = Alpha_context.Sapling.Memo_size.unparse_to_z memo_size in + Int (-1, z) + + let rec unparse_ty : type a. a ty -> Script.node = + fun ty -> + let return (name, args, annot) = Prim (-1, name, args, annot) in + match ty with + | Unit_t meta -> return (T_unit, [], unparse_type_annot meta.annot) + | Int_t meta -> return (T_int, [], unparse_type_annot meta.annot) + | Nat_t meta -> return (T_nat, [], unparse_type_annot meta.annot) + | Signature_t meta -> + return (T_signature, [], unparse_type_annot meta.annot) + | String_t meta -> return (T_string, [], unparse_type_annot meta.annot) + | Bytes_t meta -> return (T_bytes, [], unparse_type_annot meta.annot) + | Mutez_t meta -> return (T_mutez, [], unparse_type_annot meta.annot) + | Bool_t meta -> return (T_bool, [], unparse_type_annot meta.annot) + | Key_hash_t meta -> + return (T_key_hash, [], unparse_type_annot meta.annot) + | Key_t meta -> return (T_key, [], unparse_type_annot meta.annot) + | Timestamp_t meta -> + return (T_timestamp, [], unparse_type_annot meta.annot) + | Address_t meta -> return (T_address, [], unparse_type_annot meta.annot) + | Operation_t meta -> + return (T_operation, [], unparse_type_annot meta.annot) + | Chain_id_t meta -> + return (T_chain_id, [], unparse_type_annot meta.annot) + | Never_t meta -> return (T_never, [], unparse_type_annot meta.annot) + | Bls12_381_g1_t meta -> + return (T_bls12_381_g1, [], unparse_type_annot meta.annot) + | Bls12_381_g2_t meta -> + return (T_bls12_381_g2, [], unparse_type_annot meta.annot) + | Bls12_381_fr_t meta -> + return (T_bls12_381_fr, [], unparse_type_annot meta.annot) + | Contract_t (ut, meta) -> + let t = unparse_ty ut in + return (T_contract, [t], unparse_type_annot meta.annot) + | Pair_t ((utl, l_field, l_var), (utr, r_field, r_var), meta) -> + let annot = unparse_type_annot meta.annot in + let utl = unparse_ty utl in + let tl = add_field_annot l_field l_var utl in + let utr = unparse_ty utr in + let tr = add_field_annot r_field r_var utr in + return (T_pair, [tl; tr], annot) + | Union_t ((utl, l_field), (utr, r_field), meta) -> + let annot = unparse_type_annot meta.annot in + let utl = unparse_ty utl in + let tl = add_field_annot l_field None utl in + let utr = unparse_ty utr in + let tr = add_field_annot r_field None utr in + return (T_or, [tl; tr], annot) + | Lambda_t (uta, utr, meta) -> + let ta = unparse_ty uta in + let tr = unparse_ty utr in + return (T_lambda, [ta; tr], unparse_type_annot meta.annot) + | Option_t (ut, meta) -> + let annot = unparse_type_annot meta.annot in + let ut = unparse_ty ut in + return (T_option, [ut], annot) + | List_t (ut, meta) -> + let t = unparse_ty ut in + return (T_list, [t], unparse_type_annot meta.annot) + | Ticket_t (ut, meta) -> + let t = unparse_comparable_ty ut in + return (T_ticket, [t], unparse_type_annot meta.annot) + | Set_t (ut, meta) -> + let t = unparse_comparable_ty ut in + return (T_set, [t], unparse_type_annot meta.annot) + | Map_t (uta, utr, meta) -> + let ta = unparse_comparable_ty uta in + let tr = unparse_ty utr in + return (T_map, [ta; tr], unparse_type_annot meta.annot) + | Big_map_t (uta, utr, meta) -> + let ta = unparse_comparable_ty uta in + let tr = unparse_ty utr in + return (T_big_map, [ta; tr], unparse_type_annot meta.annot) + | Sapling_transaction_t (memo_size, meta) -> + return + ( T_sapling_transaction, + [unparse_memo_size memo_size], + unparse_type_annot meta.annot ) + | Sapling_state_t (memo_size, meta) -> + return + ( T_sapling_state, + [unparse_memo_size memo_size], + unparse_type_annot meta.annot ) + | Chest_t meta -> return (T_chest, [], unparse_type_annot meta.annot) + | Chest_key_t meta -> + return (T_chest_key, [], unparse_type_annot meta.annot) + end + + let run_operation_service ctxt () + ({shell; protocol_data = Operation_data protocol_data}, chain_id) = + (* this code is a duplicate of Apply without signature check *) + let partial_precheck_manager_contents (type kind) ctxt + (op : kind Kind.manager contents) : context tzresult Lwt.t = + let (Manager_operation + {source; fee; counter; operation; gas_limit; storage_limit}) = + op + in + Gas.consume_limit_in_block ctxt gas_limit >>?= fun ctxt -> + let ctxt = Gas.set_limit ctxt gas_limit in + Fees.check_storage_limit ctxt ~storage_limit >>?= fun () -> + Contract.must_be_allocated ctxt (Contract.implicit_contract source) + >>=? fun () -> + Contract.check_counter_increment ctxt source counter >>=? fun () -> + (match operation with + | Reveal pk -> Contract.reveal_manager_key ctxt source pk + | Transaction {parameters; _} -> + (* Here the data comes already deserialized, so we need to fake the deserialization to mimic apply *) + let arg_bytes = + Data_encoding.Binary.to_bytes_exn + Script.lazy_expr_encoding + parameters + in + let arg = + match + Data_encoding.Binary.of_bytes_opt + Script.lazy_expr_encoding + arg_bytes + with + | Some arg -> arg + | None -> assert false + in + Lwt.return + @@ record_trace Apply.Gas_quota_exceeded_init_deserialize + @@ (* Fail if not enough gas for complete deserialization cost *) + ( Script.force_decode_in_context ctxt arg >|? fun (_arg, ctxt) -> + ctxt ) + | Origination {script; _} -> + (* Here the data comes already deserialized, so we need to fake the deserialization to mimic apply *) + let script_bytes = + Data_encoding.Binary.to_bytes_exn Script.encoding script + in + let script = + match + Data_encoding.Binary.of_bytes_opt Script.encoding script_bytes + with + | Some script -> script + | None -> assert false + in + Lwt.return + @@ record_trace Apply.Gas_quota_exceeded_init_deserialize + @@ (* Fail if not enough gas for complete deserialization cost *) + ( Script.force_decode_in_context ctxt script.code + >>? fun (_code, ctxt) -> + Script.force_decode_in_context ctxt script.storage + >|? fun (_storage, ctxt) -> ctxt ) + | _ -> return ctxt) + >>=? fun ctxt -> + Contract.get_manager_key ctxt source >>=? fun _public_key -> + (* signature check unplugged from here *) + Contract.increment_counter ctxt source >>=? fun ctxt -> + Contract.spend ctxt (Contract.implicit_contract source) fee + in + let rec partial_precheck_manager_contents_list : + type kind. + Alpha_context.t -> + kind Kind.manager contents_list -> + context tzresult Lwt.t = + fun ctxt contents_list -> + match contents_list with + | Single (Manager_operation _ as op) -> + partial_precheck_manager_contents ctxt op + | Cons ((Manager_operation _ as op), rest) -> + partial_precheck_manager_contents ctxt op >>=? fun ctxt -> + partial_precheck_manager_contents_list ctxt rest + in + let ret contents = + ( Operation_data protocol_data, + Apply_results.Operation_metadata {contents} ) + in + let operation : _ operation = {shell; protocol_data} in + let hash = Operation.hash {shell; protocol_data} in + let ctxt = Contract.init_origination_nonce ctxt hash in + let baker = Signature.Public_key_hash.zero in + match protocol_data.contents with + | Single (Manager_operation _) as op -> + partial_precheck_manager_contents_list ctxt op >>=? fun ctxt -> + Apply.apply_manager_contents_list ctxt Optimized baker chain_id op + >|= fun (_ctxt, result) -> ok @@ ret result + | Cons (Manager_operation _, _) as op -> + partial_precheck_manager_contents_list ctxt op >>=? fun ctxt -> + Apply.apply_manager_contents_list ctxt Optimized baker chain_id op + >|= fun (_ctxt, result) -> ok @@ ret result + | _ -> + Apply.apply_contents_list + ctxt + chain_id + Optimized + shell.branch + baker + operation + operation.protocol_data.contents + >|=? fun (_ctxt, result) -> ret result + + (* + + The execution of an operation depends on the state of the + cache. In particular, gas consumption is usually impacted by + cache hits and misses. + + Unfortunately, the state of the cache is different between the + context at operation-creation time and the context when is + included in a block. + + Therefore, the simulation tries to predict the state of the + cache in a [time_in_blocks] assumed to be close to the inclusion + time of the operation. + + *) + let simulate_operation_service ctxt () (op, chain_id, time_in_blocks) = + let ctxt = Cache.Admin.future_cache_expectation ctxt ~time_in_blocks in + run_operation_service ctxt () (op, chain_id) + + let register () = + let originate_dummy_contract ctxt script balance = + let ctxt = Contract.init_origination_nonce ctxt Operation_hash.zero in + Lwt.return (Contract.fresh_contract_from_current_nonce ctxt) + >>=? fun (ctxt, dummy_contract) -> + Contract.originate + ctxt + dummy_contract + ~balance + ~delegate:None + ~script:(script, None) + >>=? fun ctxt -> return (ctxt, dummy_contract) + in + let script_entrypoint_type ctxt expr entrypoint = + let ctxt = Gas.set_unlimited ctxt in + let legacy = false in + let open Script_ir_translator in + Lwt.return + ( ( parse_toplevel ctxt ~legacy expr + >>? fun ({arg_type; root_name; _}, ctxt) -> + parse_parameter_ty ctxt ~legacy arg_type + >>? fun (Ex_ty arg_type, _) -> + Script_ir_translator.find_entrypoint + ~root_name + arg_type + entrypoint ) + >>? fun (_f, Ex_ty ty) -> + unparse_ty ctxt ty >|? fun (ty_node, _) -> + Micheline.strip_locations ty_node ) + in + Registration.register0 + ~chunked:true + S.run_code + (fun + ctxt + () + ( ( code, + storage, + parameter, + amount, + balance, + chain_id, + source, + payer, + gas, + entrypoint ), + unparsing_mode ) + -> + let unparsing_mode = Option.value ~default:Readable unparsing_mode in + let storage = Script.lazy_expr storage in + let code = Script.lazy_expr code in + originate_dummy_contract ctxt {storage; code} balance + >>=? fun (ctxt, dummy_contract) -> + let (source, payer) = + match (source, payer) with + | (Some source, Some payer) -> (source, payer) + | (Some source, None) -> (source, source) + | (None, Some payer) -> (payer, payer) + | (None, None) -> (dummy_contract, dummy_contract) + in + let gas = + match gas with + | Some gas -> gas + | None -> Constants.hard_gas_limit_per_operation ctxt + in + let ctxt = Gas.set_limit ctxt gas in + let step_constants = + let open Script_interpreter in + {source; payer; self = dummy_contract; amount; chain_id} + in + Script_interpreter.execute + ctxt + unparsing_mode + step_constants + ~cached_script:None + ~script:{storage; code} + ~entrypoint + ~parameter + ~internal:true + >|=? fun ( { + Script_interpreter.storage; + operations; + lazy_storage_diff; + _; + }, + _ ) -> (storage, operations, lazy_storage_diff)) ; + Registration.register0 + ~chunked:true + S.trace_code + (fun + ctxt + () + ( ( code, + storage, + parameter, + amount, + balance, + chain_id, + source, + payer, + gas, + entrypoint ), + unparsing_mode ) + -> + let unparsing_mode = Option.value ~default:Readable unparsing_mode in + let storage = Script.lazy_expr storage in + let code = Script.lazy_expr code in + originate_dummy_contract ctxt {storage; code} balance + >>=? fun (ctxt, dummy_contract) -> + let (source, payer) = + match (source, payer) with + | (Some source, Some payer) -> (source, payer) + | (Some source, None) -> (source, source) + | (None, Some payer) -> (payer, payer) + | (None, None) -> (dummy_contract, dummy_contract) + in + let gas = + match gas with + | Some gas -> gas + | None -> Constants.hard_gas_limit_per_operation ctxt + in + let ctxt = Gas.set_limit ctxt gas in + let step_constants = + let open Script_interpreter in + {source; payer; self = dummy_contract; amount; chain_id} + in + let module Unparsing_mode = struct + let unparsing_mode = unparsing_mode + end in + let module Interp = Traced_interpreter (Unparsing_mode) in + Interp.execute + ctxt + step_constants + ~script:{storage; code} + ~entrypoint + ~parameter + >|=? fun ( { + Script_interpreter.storage; + operations; + lazy_storage_diff; + _; + }, + trace ) -> (storage, operations, trace, lazy_storage_diff)) ; + Registration.register0 + ~chunked:true + S.run_view + (fun + ctxt + () + ( contract, + entrypoint, + input, + chain_id, + source, + payer, + gas, + unparsing_mode ) + -> + Contract.get_script ctxt contract >>=? fun (ctxt, script_opt) -> + Option.fold + ~some:ok + ~none:(Error_monad.error View_helpers.Viewed_contract_has_no_script) + script_opt + >>?= fun script -> + Script_repr.(force_decode script.code) >>?= fun decoded_script -> + script_entrypoint_type ctxt decoded_script entrypoint + >>=? fun view_ty -> + View_helpers.extract_view_output_type entrypoint view_ty + >>?= fun ty -> + Error_monad.trace View_helpers.View_callback_origination_failed + @@ originate_dummy_contract + ctxt + (View_helpers.make_viewer_script ty) + Tez.zero + >>=? fun (ctxt, viewer_contract) -> + let (source, payer) = + match (source, payer) with + | (Some source, Some payer) -> (source, payer) + | (Some source, None) -> (source, source) + | (None, Some payer) -> (payer, payer) + | (None, None) -> (contract, contract) + in + let gas = + Option.value + ~default:(Constants.hard_gas_limit_per_operation ctxt) + gas + in + let ctxt = Gas.set_limit ctxt gas in + let step_constants = + let open Script_interpreter in + {source; payer; self = contract; amount = Tez.zero; chain_id} + in + let parameter = + View_helpers.make_view_parameter + (Micheline.root input) + viewer_contract + in + Script_interpreter.execute + ctxt + unparsing_mode + step_constants + ~script + ~cached_script:None + ~entrypoint + ~parameter + ~internal:true + >>=? fun ({Script_interpreter.operations; _}, (_, _)) -> + View_helpers.extract_parameter_from_operations + entrypoint + operations + viewer_contract + >>?= fun parameter -> Lwt.return (Script_repr.force_decode parameter)) ; + Registration.register0 + ~chunked:false + S.typecheck_code + (fun ctxt () (expr, maybe_gas, legacy) -> + let legacy = Option.value ~default:false legacy in + let ctxt = + match maybe_gas with + | None -> Gas.set_unlimited ctxt + | Some gas -> Gas.set_limit ctxt gas + in + Script_ir_translator.typecheck_code ~legacy ctxt expr + >|=? fun (res, ctxt) -> (res, Gas.level ctxt)) ; + Registration.register0 + ~chunked:false + S.script_size + (fun ctxt () (expr, storage, maybe_gas, legacy) -> + let legacy = Option.value ~default:false legacy in + let ctxt = + match maybe_gas with + | None -> Gas.set_unlimited ctxt + | Some gas -> Gas.set_limit ctxt gas + in + let code = Script.lazy_expr expr in + Script_ir_translator.parse_code ~legacy ctxt ~code + >>=? fun ( Ex_code + { + code; + arg_type; + storage_type; + views; + root_name; + code_size; + }, + ctxt ) -> + Script_ir_translator.parse_data + ~legacy + ~allow_forged:true + ctxt + storage_type + (Micheline.root storage) + >>=? fun (storage, _) -> + let script = + Script_ir_translator.Ex_script + { + code; + arg_type; + storage_type; + views; + root_name; + code_size; + storage; + } + in + let (size, cost) = Script_ir_translator.script_size script in + Gas.consume ctxt cost >>?= fun _ctxt -> return @@ size) ; + + Registration.register0 + ~chunked:false + S.typecheck_data + (fun ctxt () (data, ty, maybe_gas, legacy) -> + let legacy = Option.value ~default:false legacy in + let ctxt = + match maybe_gas with + | None -> Gas.set_unlimited ctxt + | Some gas -> Gas.set_limit ctxt gas + in + typecheck_data ~legacy ctxt (data, ty) >|=? fun ctxt -> Gas.level ctxt) ; + Registration.register0 + ~chunked:true + S.pack_data + (fun ctxt () (expr, typ, maybe_gas) -> + let open Script_ir_translator in + let ctxt = + match maybe_gas with + | None -> Gas.set_unlimited ctxt + | Some gas -> Gas.set_limit ctxt gas + in + parse_packable_ty ctxt ~legacy:true (Micheline.root typ) + >>?= fun (Ex_ty typ, ctxt) -> + parse_data + ctxt + ~legacy:true + ~allow_forged:true + typ + (Micheline.root expr) + >>=? fun (data, ctxt) -> + Script_ir_translator.pack_data ctxt typ data >|=? fun (bytes, ctxt) -> + (bytes, Gas.level ctxt)) ; + Registration.register0 + ~chunked:true + S.normalize_data + (fun ctxt () (expr, typ, unparsing_mode, legacy) -> + let open Script_ir_translator in + let legacy = Option.value ~default:false legacy in + let ctxt = Gas.set_unlimited ctxt in + Script_ir_translator.parse_any_ty ctxt ~legacy (Micheline.root typ) + >>?= fun (Ex_ty typ, ctxt) -> + parse_data ctxt ~legacy ~allow_forged:true typ (Micheline.root expr) + >>=? fun (data, ctxt) -> + Script_ir_translator.unparse_data ctxt unparsing_mode typ data + >|=? fun (normalized, _ctxt) -> Micheline.strip_locations normalized) ; + Registration.register0 + ~chunked:true + S.normalize_script + (fun ctxt () (script, unparsing_mode) -> + let ctxt = Gas.set_unlimited ctxt in + Script_ir_translator.unparse_code + ctxt + unparsing_mode + (Micheline.root script) + >|=? fun (normalized, _ctxt) -> Micheline.strip_locations normalized) ; + Registration.register0 ~chunked:true S.normalize_type (fun ctxt () typ -> + let open Script_ir_translator in + let ctxt = Gas.set_unlimited ctxt in + (* Unfortunately, Script_ir_translator.parse_any_ty is not exported *) + Script_ir_translator.parse_ty + ctxt + ~legacy:true + ~allow_lazy_storage:true + ~allow_operation:true + ~allow_contract:true + ~allow_ticket:true + (Micheline.root typ) + >>?= fun (Ex_ty typ, _ctxt) -> + let normalized = Unparse_types.unparse_ty typ in + return @@ Micheline.strip_locations normalized) ; + Registration.register0 ~chunked:true S.run_operation run_operation_service ; + Registration.register0 + ~chunked:true + S.simulate_operation + simulate_operation_service ; + Registration.register0 + ~chunked:true + S.entrypoint_type + (fun ctxt () (expr, entrypoint) -> + script_entrypoint_type ctxt expr entrypoint) ; + Registration.register0 + ~chunked:true + S.list_entrypoints + (fun ctxt () expr -> + let ctxt = Gas.set_unlimited ctxt in + let legacy = false in + let open Script_ir_translator in + Lwt.return + ( parse_toplevel ~legacy ctxt expr + >>? fun ({arg_type; root_name; _}, ctxt) -> + parse_parameter_ty ctxt ~legacy arg_type + >>? fun (Ex_ty arg_type, _) -> + Script_ir_translator.list_entrypoints ~root_name arg_type ctxt + >|? fun (unreachable_entrypoint, map) -> + ( unreachable_entrypoint, + Entrypoints_map.fold + (fun entry (_, ty) acc -> + (entry, Micheline.strip_locations ty) :: acc) + map + [] ) )) + + let run_code ?unparsing_mode ?gas ?(entrypoint = "default") ~script ~storage + ~input ~amount ~balance ~chain_id ~source ~payer ctxt block = + RPC_context.make_call0 + S.run_code + ctxt + block + () + ( ( script, + storage, + input, + amount, + balance, + chain_id, + source, + payer, + gas, + entrypoint ), + unparsing_mode ) + + let trace_code ?unparsing_mode ?gas ?(entrypoint = "default") ~script + ~storage ~input ~amount ~balance ~chain_id ~source ~payer ctxt block = + RPC_context.make_call0 + S.trace_code + ctxt + block + () + ( ( script, + storage, + input, + amount, + balance, + chain_id, + source, + payer, + gas, + entrypoint ), + unparsing_mode ) + + let run_view ?gas ~contract ~entrypoint ~input ~chain_id ?source ?payer + ~unparsing_mode ctxt block = + RPC_context.make_call0 + S.run_view + ctxt + block + () + ( contract, + entrypoint, + input, + chain_id, + source, + payer, + gas, + unparsing_mode ) + + let typecheck_code ?gas ?legacy ~script ctxt block = + RPC_context.make_call0 S.typecheck_code ctxt block () (script, gas, legacy) + + let script_size ?gas ?legacy ~script ~storage ctxt block = + RPC_context.make_call0 + S.script_size + ctxt + block + () + (script, storage, gas, legacy) + + let typecheck_data ?gas ?legacy ~data ~ty ctxt block = + RPC_context.make_call0 + S.typecheck_data + ctxt + block + () + (data, ty, gas, legacy) + + let pack_data ?gas ~data ~ty ctxt block = + RPC_context.make_call0 S.pack_data ctxt block () (data, ty, gas) + + let normalize_data ?legacy ~data ~ty ~unparsing_mode ctxt block = + RPC_context.make_call0 + S.normalize_data + ctxt + block + () + (data, ty, unparsing_mode, legacy) + + let normalize_script ~script ~unparsing_mode ctxt block = + RPC_context.make_call0 + S.normalize_script + ctxt + block + () + (script, unparsing_mode) + + let normalize_type ~ty ctxt block = + RPC_context.make_call0 S.normalize_type ctxt block () ty + + let run_operation ~op ~chain_id ctxt block = + RPC_context.make_call0 S.run_operation ctxt block () (op, chain_id) + + let simulate_operation ~op ~chain_id ~latency ctxt block = + RPC_context.make_call0 + S.simulate_operation + ctxt + block + () + (op, chain_id, latency) + + let entrypoint_type ~script ~entrypoint ctxt block = + RPC_context.make_call0 S.entrypoint_type ctxt block () (script, entrypoint) + + let list_entrypoints ctxt block ~script = + RPC_context.make_call0 S.list_entrypoints ctxt block () script + end + + module Contract = struct + module S = struct + let path = + (RPC_path.(open_root / "context" / "contracts") + : RPC_context.t RPC_path.context) + + let get_storage_normalized = + let open Data_encoding in + RPC_service.post_service + ~description: + "Access the data of the contract and normalize it using the \ + requested unparsing mode." + ~input:(obj1 (req "unparsing_mode" unparsing_mode_encoding)) + ~query:RPC_query.empty + ~output:(option Script.expr_encoding) + RPC_path.(path /: Contract.rpc_arg / "storage" / "normalized") + + let get_script_normalized = + let open Data_encoding in + RPC_service.post_service + ~description: + "Access the script of the contract and normalize it using the \ + requested unparsing mode." + ~input:(obj1 (req "unparsing_mode" unparsing_mode_encoding)) + ~query:RPC_query.empty + ~output:(option Script.encoding) + RPC_path.(path /: Contract.rpc_arg / "script" / "normalized") + end + + let register () = + (* Patched RPC: get_storage *) + Registration.register1 + ~chunked:true + S.get_storage_normalized + (fun ctxt contract () unparsing_mode -> + Contract.get_script ctxt contract >>=? fun (ctxt, script) -> + match script with + | None -> return_none + | Some script -> + let ctxt = Gas.set_unlimited ctxt in + let open Script_ir_translator in + parse_script + ctxt + ~legacy:true + ~allow_forged_in_storage:true + script + >>=? fun (Ex_script script, ctxt) -> + unparse_script ctxt unparsing_mode script + >>=? fun (script, ctxt) -> + Script.force_decode_in_context ctxt script.storage + >>?= fun (storage, _ctxt) -> return_some storage) ; + (* Patched RPC: get_script *) + Registration.register1 + ~chunked:true + S.get_script_normalized + (fun ctxt contract () unparsing_mode -> + Contract.get_script ctxt contract >>=? fun (ctxt, script) -> + match script with + | None -> return_none + | Some script -> + let ctxt = Gas.set_unlimited ctxt in + let open Script_ir_translator in + parse_script + ctxt + ~legacy:true + ~allow_forged_in_storage:true + script + >>=? fun (Ex_script script, ctxt) -> + unparse_script ctxt unparsing_mode script + >>=? fun (script, _ctxt) -> return_some script) + + let get_storage_normalized ctxt block ~contract ~unparsing_mode = + RPC_context.make_call1 + S.get_storage_normalized + ctxt + block + contract + () + unparsing_mode + + let get_script_normalized ctxt block ~contract ~unparsing_mode = + RPC_context.make_call1 + S.get_script_normalized + ctxt + block + contract + () + unparsing_mode + end + + module Big_map = struct + module S = struct + let path = + (RPC_path.(open_root / "context" / "big_maps") + : RPC_context.t RPC_path.context) + + let big_map_get_normalized = + let open Data_encoding in + RPC_service.post_service + ~description: + "Access the value associated with a key in a big map, normalize \ + the output using the requested unparsing mode." + ~query:RPC_query.empty + ~input:(obj1 (req "unparsing_mode" unparsing_mode_encoding)) + ~output:Script.expr_encoding + RPC_path.( + path /: Big_map.Id.rpc_arg /: Script_expr_hash.rpc_arg + / "normalized") + end + + let register () = + Registration.register2 + ~chunked:true + S.big_map_get_normalized + (fun ctxt id key () unparsing_mode -> + let open Script_ir_translator in + let ctxt = Gas.set_unlimited ctxt in + Big_map.exists ctxt id >>=? fun (ctxt, types) -> + match types with + | None -> raise Not_found + | Some (_, value_type) -> ( + parse_big_map_value_ty + ctxt + ~legacy:true + (Micheline.root value_type) + >>?= fun (Ex_ty value_type, ctxt) -> + Big_map.get_opt ctxt id key >>=? fun (_ctxt, value) -> + match value with + | None -> raise Not_found + | Some value -> + parse_data + ctxt + ~legacy:true + ~allow_forged:true + value_type + (Micheline.root value) + >>=? fun (value, ctxt) -> + unparse_data ctxt unparsing_mode value_type value + >|=? fun (value, _ctxt) -> Micheline.strip_locations value)) + + let big_map_get_normalized ctxt block id key ~unparsing_mode = + RPC_context.make_call2 + S.big_map_get_normalized + ctxt + block + id + key + () + unparsing_mode + end + + module Forge = struct + module S = struct + open Data_encoding + + let path = RPC_path.(path / "forge") + + let operations = + RPC_service.post_service + ~description:"Forge an operation" + ~query:RPC_query.empty + ~input:Operation.unsigned_encoding + ~output:bytes + RPC_path.(path / "operations") + + let empty_proof_of_work_nonce = + Bytes.make Constants_repr.proof_of_work_nonce_size '\000' + + let protocol_data = + RPC_service.post_service + ~description:"Forge the protocol-specific part of a block header" + ~query:RPC_query.empty + ~input: + (obj4 + (req "priority" uint16) + (opt "nonce_hash" Nonce_hash.encoding) + (dft + "proof_of_work_nonce" + (Fixed.bytes Alpha_context.Constants.proof_of_work_nonce_size) + empty_proof_of_work_nonce) + (dft "liquidity_baking_escape_vote" bool false)) + ~output:(obj1 (req "protocol_data" bytes)) + RPC_path.(path / "protocol_data") + end + + let register () = + Registration.register0_noctxt + ~chunked:true + S.operations + (fun () (shell, proto) -> + return + (Data_encoding.Binary.to_bytes_exn + Operation.unsigned_encoding + (shell, proto))) ; + Registration.register0_noctxt + ~chunked:true + S.protocol_data + (fun + () + ( priority, + seed_nonce_hash, + proof_of_work_nonce, + liquidity_baking_escape_vote ) + -> + return + (Data_encoding.Binary.to_bytes_exn + Block_header.contents_encoding + { + priority; + seed_nonce_hash; + proof_of_work_nonce; + liquidity_baking_escape_vote; + })) + + module Manager = struct + let[@coq_axiom_with_reason "cast on e"] operations ctxt block ~branch + ~source ?sourcePubKey ~counter ~fee ~gas_limit ~storage_limit + operations = + Contract_services.manager_key ctxt block source >>= function + | Error _ as e -> Lwt.return e + | Ok revealed -> + let ops = + List.map + (fun (Manager operation) -> + Contents + (Manager_operation + { + source; + counter; + operation; + fee; + gas_limit; + storage_limit; + })) + operations + in + let ops = + match (sourcePubKey, revealed) with + | (None, _) | (_, Some _) -> ops + | (Some pk, None) -> + let operation = Reveal pk in + Contents + (Manager_operation + { + source; + counter; + operation; + fee; + gas_limit; + storage_limit; + }) + :: ops + in + Environment.wrap_tzresult @@ Operation.of_list ops >>?= fun ops -> + RPC_context.make_call0 S.operations ctxt block () ({branch}, ops) + + let reveal ctxt block ~branch ~source ~sourcePubKey ~counter ~fee () = + operations + ctxt + block + ~branch + ~source + ~sourcePubKey + ~counter + ~fee + ~gas_limit:Gas.Arith.zero + ~storage_limit:Z.zero + [] + + let transaction ctxt block ~branch ~source ?sourcePubKey ~counter ~amount + ~destination ?(entrypoint = "default") ?parameters ~gas_limit + ~storage_limit ~fee () = + let parameters = + Option.fold + ~some:Script.lazy_expr + ~none:Script.unit_parameter + parameters + in + operations + ctxt + block + ~branch + ~source + ?sourcePubKey + ~counter + ~fee + ~gas_limit + ~storage_limit + [Manager (Transaction {amount; parameters; destination; entrypoint})] + + let origination ctxt block ~branch ~source ?sourcePubKey ~counter ~balance + ?delegatePubKey ~script ~gas_limit ~storage_limit ~fee () = + operations + ctxt + block + ~branch + ~source + ?sourcePubKey + ~counter + ~fee + ~gas_limit + ~storage_limit + [ + Manager + (Origination + { + delegate = delegatePubKey; + script; + credit = balance; + preorigination = None; + }); + ] + + let delegation ctxt block ~branch ~source ?sourcePubKey ~counter ~fee + delegate = + operations + ctxt + block + ~branch + ~source + ?sourcePubKey + ~counter + ~fee + ~gas_limit:Gas.Arith.zero + ~storage_limit:Z.zero + [Manager (Delegation delegate)] + end + + let operation ctxt block ~branch operation = + RPC_context.make_call0 + S.operations + ctxt + block + () + ({branch}, Contents_list (Single operation)) + + let endorsement ctxt b ~branch ~level () = + operation ctxt b ~branch (Endorsement {level}) + + let proposals ctxt b ~branch ~source ~period ~proposals () = + operation ctxt b ~branch (Proposals {source; period; proposals}) + + let ballot ctxt b ~branch ~source ~period ~proposal ~ballot () = + operation ctxt b ~branch (Ballot {source; period; proposal; ballot}) + + let failing_noop ctxt b ~branch ~message () = + operation ctxt b ~branch (Failing_noop message) + + let seed_nonce_revelation ctxt block ~branch ~level ~nonce () = + operation ctxt block ~branch (Seed_nonce_revelation {level; nonce}) + + let double_baking_evidence ctxt block ~branch ~bh1 ~bh2 () = + operation ctxt block ~branch (Double_baking_evidence {bh1; bh2}) + + let double_endorsement_evidence ctxt block ~branch ~op1 ~op2 ~slot () = + operation + ctxt + block + ~branch + (Double_endorsement_evidence {op1; op2; slot}) + + let empty_proof_of_work_nonce = + Bytes.make Constants_repr.proof_of_work_nonce_size '\000' + + let protocol_data ctxt block ~priority ?seed_nonce_hash + ?(proof_of_work_nonce = empty_proof_of_work_nonce) + ~liquidity_baking_escape_vote () = + RPC_context.make_call0 + S.protocol_data + ctxt + block + () + ( priority, + seed_nonce_hash, + proof_of_work_nonce, + liquidity_baking_escape_vote ) + end + + module Parse = struct + module S = struct + open Data_encoding + + let path = RPC_path.(path / "parse") + + let operations = + RPC_service.post_service + ~description:"Parse operations" + ~query:RPC_query.empty + ~input: + (obj2 + (req "operations" (list (dynamic_size Operation.raw_encoding))) + (opt "check_signature" bool)) + ~output:(list (dynamic_size Operation.encoding)) + RPC_path.(path / "operations") + + let block = + RPC_service.post_service + ~description:"Parse a block" + ~query:RPC_query.empty + ~input:Block_header.raw_encoding + ~output:Block_header.protocol_data_encoding + RPC_path.(path / "block") + end + + let parse_protocol_data protocol_data = + match + Data_encoding.Binary.of_bytes_opt + Block_header.protocol_data_encoding + protocol_data + with + | None -> Stdlib.failwith "Cant_parse_protocol_data" + | Some protocol_data -> protocol_data + + let register () = + Registration.register0 + ~chunked:true + S.operations + (fun _ctxt () (operations, check) -> + List.map_es + (fun raw -> + parse_operation raw >>?= fun op -> + (match check with + | Some true -> return_unit (* FIXME *) + (* I.check_signature ctxt *) + (* op.protocol_data.signature op.shell op.protocol_data.contents *) + | Some false | None -> return_unit) + >|=? fun () -> op) + operations) ; + Registration.register0_noctxt ~chunked:false S.block (fun () raw_block -> + return @@ parse_protocol_data raw_block.protocol_data) + + let operations ctxt block ?check operations = + RPC_context.make_call0 S.operations ctxt block () (operations, check) + + let block ctxt block shell protocol_data = + RPC_context.make_call0 + S.block + ctxt + block + () + ({shell; protocol_data} : Block_header.raw) + end + + let requested_levels ~default ctxt cycles levels = + match (levels, cycles) with + | ([], []) -> ok [default] + | (levels, cycles) -> + (* explicitly fail when requested levels or cycle are in the past... + or too far in the future... *) + let levels = + List.sort_uniq + Level.compare + (List.concat + (List.map (Level.from_raw ctxt) levels + :: List.map (Level.levels_in_cycle ctxt) cycles)) + in + List.map_e + (fun level -> + let current_level = Level.current ctxt in + if Level.(level <= current_level) then ok (level, None) + else + Baking.earlier_predecessor_timestamp ctxt level + >|? fun timestamp -> (level, Some timestamp)) + levels + + module Baking_rights = struct + type t = { + level : Raw_level.t; + delegate : Signature.Public_key_hash.t; + priority : int; + timestamp : Timestamp.t option; + } + + let encoding = + let open Data_encoding in + conv + (fun {level; delegate; priority; timestamp} -> + (level, delegate, priority, timestamp)) + (fun (level, delegate, priority, timestamp) -> + {level; delegate; priority; timestamp}) + (obj4 + (req "level" Raw_level.encoding) + (req "delegate" Signature.Public_key_hash.encoding) + (req "priority" uint16) + (opt "estimated_time" Timestamp.encoding)) + + module S = struct + open Data_encoding + + let custom_root = RPC_path.(open_root / "helpers" / "baking_rights") + + type baking_rights_query = { + levels : Raw_level.t list; + cycles : Cycle.t list; + delegates : Signature.Public_key_hash.t list; + max_priority : int option; + all : bool; + } + + let baking_rights_query = + let open RPC_query in + query (fun levels cycles delegates max_priority all -> + {levels; cycles; delegates; max_priority; all}) + |+ multi_field "level" Raw_level.rpc_arg (fun t -> t.levels) + |+ multi_field "cycle" Cycle.rpc_arg (fun t -> t.cycles) + |+ multi_field "delegate" Signature.Public_key_hash.rpc_arg (fun t -> + t.delegates) + |+ opt_field "max_priority" RPC_arg.int (fun t -> t.max_priority) + |+ flag "all" (fun t -> t.all) + |> seal + + let baking_rights = + RPC_service.get_service + ~description: + "Retrieves the list of delegates allowed to bake a block.\n\ + By default, it gives the best baking priorities for bakers that \ + have at least one opportunity below the 64th priority for the \ + next block.\n\ + Parameters `level` and `cycle` can be used to specify the (valid) \ + level(s) in the past or future at which the baking rights have to \ + be returned. When asked for (a) whole cycle(s), baking \ + opportunities are given by default up to the priority 8.\n\ + Parameter `delegate` can be used to restrict the results to the \ + given delegates. If parameter `all` is set, all the baking \ + opportunities for each baker at each level are returned, instead \ + of just the first one.\n\ + Returns the list of baking slots. Also returns the minimal \ + timestamps that correspond to these slots. The timestamps are \ + omitted for levels in the past, and are only estimates for levels \ + later that the next block, based on the hypothesis that all \ + predecessor blocks were baked at the first priority." + ~query:baking_rights_query + ~output:(list encoding) + custom_root + end + + let baking_priorities ctxt max_prio (level, pred_timestamp) = + Baking.baking_priorities ctxt level >>=? fun contract_list -> + let rec loop l acc priority = + if Compare.Int.(priority > max_prio) then return (List.rev acc) + else + let (Misc.LCons (pk, next)) = l in + let delegate = Signature.Public_key.hash pk in + (match pred_timestamp with + | None -> ok_none + | Some pred_timestamp -> + Baking.minimal_time + (Constants.parametric ctxt) + ~priority + pred_timestamp + >|? fun t -> Some t) + >>?= fun timestamp -> + let acc = + {level = level.level; delegate; priority; timestamp} :: acc + in + next () >>=? fun l -> loop l acc (priority + 1) + in + loop contract_list [] 0 + + let baking_priorities_of_delegates ctxt ~all ~max_prio delegates + (level, pred_timestamp) = + Baking.baking_priorities ctxt level >>=? fun contract_list -> + let rec loop l acc priority delegates = + match delegates with + | [] -> return (List.rev acc) + | _ :: _ -> ( + if Compare.Int.(priority > max_prio) then return (List.rev acc) + else + let (Misc.LCons (pk, next)) = l in + next () >>=? fun l -> + match + List.partition + (fun (pk', _) -> Signature.Public_key.equal pk pk') + delegates + with + | ([], _) -> loop l acc (priority + 1) delegates + | ((_, delegate) :: _, delegates') -> + (match pred_timestamp with + | None -> ok_none + | Some pred_timestamp -> + Baking.minimal_time + (Constants.parametric ctxt) + ~priority + pred_timestamp + >|? fun t -> Some t) + >>?= fun timestamp -> + let acc = + {level = level.level; delegate; priority; timestamp} :: acc + in + let delegates'' = if all then delegates else delegates' in + loop l acc (priority + 1) delegates'') + in + loop contract_list [] 0 delegates + + let remove_duplicated_delegates rights = + List.rev @@ fst + @@ List.fold_left + (fun (acc, previous) r -> + if Signature.Public_key_hash.Set.mem r.delegate previous then + (acc, previous) + else + (r :: acc, Signature.Public_key_hash.Set.add r.delegate previous)) + ([], Signature.Public_key_hash.Set.empty) + rights + + let register () = + Registration.register0 ~chunked:true S.baking_rights (fun ctxt q () -> + requested_levels + ~default: + ( Level.succ ctxt (Level.current ctxt), + Some (Timestamp.current ctxt) ) + ctxt + q.cycles + q.levels + >>?= fun levels -> + let max_priority = + match q.max_priority with + | Some max -> max + | None -> ( match q.cycles with [] -> 64 | _ :: _ -> 8) + in + match q.delegates with + | [] -> + List.map_es (baking_priorities ctxt max_priority) levels + >|=? fun rights -> + let rights = + if q.all then rights + else List.map remove_duplicated_delegates rights + in + List.concat rights + | _ :: _ as delegates -> + List.filter_map_s + (fun delegate -> + Alpha_context.Contract.get_manager_key ctxt delegate + >>= function + | Ok pk -> Lwt.return (Some (pk, delegate)) + | Error _ -> Lwt.return_none) + delegates + >>= fun delegates -> + List.map_es + (fun level -> + baking_priorities_of_delegates + ctxt + ~all:q.all + ~max_prio:max_priority + delegates + level) + levels + >|=? List.concat) + + let get ctxt ?(levels = []) ?(cycles = []) ?(delegates = []) ?(all = false) + ?max_priority block = + RPC_context.make_call0 + S.baking_rights + ctxt + block + {levels; cycles; delegates; max_priority; all} + () + end + + module Endorsing_rights = struct + type t = { + level : Raw_level.t; + delegate : Signature.Public_key_hash.t; + slots : int list; + estimated_time : Time.t option; + } + + let encoding = + let open Data_encoding in + conv + (fun {level; delegate; slots; estimated_time} -> + (level, delegate, slots, estimated_time)) + (fun (level, delegate, slots, estimated_time) -> + {level; delegate; slots; estimated_time}) + (obj4 + (req "level" Raw_level.encoding) + (req "delegate" Signature.Public_key_hash.encoding) + (req "slots" (list uint16)) + (opt "estimated_time" Timestamp.encoding)) + + module S = struct + open Data_encoding + + let custom_root = RPC_path.(open_root / "helpers" / "endorsing_rights") + + type endorsing_rights_query = { + levels : Raw_level.t list; + cycles : Cycle.t list; + delegates : Signature.Public_key_hash.t list; + } + + let endorsing_rights_query = + let open RPC_query in + query (fun levels cycles delegates -> {levels; cycles; delegates}) + |+ multi_field "level" Raw_level.rpc_arg (fun t -> t.levels) + |+ multi_field "cycle" Cycle.rpc_arg (fun t -> t.cycles) + |+ multi_field "delegate" Signature.Public_key_hash.rpc_arg (fun t -> + t.delegates) + |> seal + + let endorsing_rights = + RPC_service.get_service + ~description: + "Retrieves the delegates allowed to endorse a block.\n\ + By default, it gives the endorsement slots for delegates that \ + have at least one in the next block.\n\ + Parameters `level` and `cycle` can be used to specify the (valid) \ + level(s) in the past or future at which the endorsement rights \ + have to be returned. Parameter `delegate` can be used to restrict \ + the results to the given delegates.\n\ + Returns the list of endorsement slots. Also returns the minimal \ + timestamps that correspond to these slots. The timestamps are \ + omitted for levels in the past, and are only estimates for levels \ + later that the next block, based on the hypothesis that all \ + predecessor blocks were baked at the first priority." + ~query:endorsing_rights_query + ~output:(list encoding) + custom_root + end + + let endorsement_slots ctxt (level, estimated_time) = + Baking.endorsement_rights ctxt level >|=? fun rights -> + Signature.Public_key_hash.Map.fold + (fun delegate (_, slots, _) acc -> + {level = level.level; delegate; slots; estimated_time} :: acc) + rights + [] + + let register () = + Registration.register0 ~chunked:true S.endorsing_rights (fun ctxt q () -> + requested_levels + ~default:(Level.current ctxt, Some (Timestamp.current ctxt)) + ctxt + q.cycles + q.levels + >>?= fun levels -> + List.map_es (endorsement_slots ctxt) levels >|=? fun rights -> + let rights = List.concat rights in + match q.delegates with + | [] -> rights + | _ :: _ as delegates -> + let is_requested p = + List.exists + (Signature.Public_key_hash.equal p.delegate) + delegates + in + List.filter is_requested rights) + + let get ctxt ?(levels = []) ?(cycles = []) ?(delegates = []) block = + RPC_context.make_call0 + S.endorsing_rights + ctxt + block + {levels; cycles; delegates} + () + end + + module S = struct + open Data_encoding + + type level_query = {offset : int32} + + let level_query : level_query RPC_query.t = + let open RPC_query in + query (fun offset -> {offset}) + |+ field "offset" RPC_arg.int32 0l (fun t -> t.offset) + |> seal + + let current_level = + RPC_service.get_service + ~description: + "Returns the level of the interrogated block, or the one of a block \ + located `offset` blocks after in the chain (or before when \ + negative). For instance, the next block if `offset` is 1." + ~query:level_query + ~output:Level.encoding + RPC_path.(path / "current_level") + + let levels_in_current_cycle = + RPC_service.get_service + ~description:"Levels of a cycle" + ~query:level_query + ~output: + (obj2 + (req "first" Raw_level.encoding) + (req "last" Raw_level.encoding)) + RPC_path.(path / "levels_in_current_cycle") + end + + let register () = + Scripts.register () ; + Forge.register () ; + Parse.register () ; + Contract.register () ; + Big_map.register () ; + Baking_rights.register () ; + Endorsing_rights.register () ; + Registration.register0 ~chunked:false S.current_level (fun ctxt q () -> + Lwt.return + (Level.from_raw_with_offset + ctxt + ~offset:q.offset + (Level.current ctxt).level)) ; + Registration.opt_register0 + ~chunked:true + S.levels_in_current_cycle + (fun ctxt q () -> + let rev_levels = + Level.levels_in_current_cycle ctxt ~offset:q.offset () + in + match rev_levels with + | [] -> return_none + | [level] -> return (Some (level.level, level.level)) + | last :: default_first :: rest -> + (* The [rev_levels] list is reversed, the last level is the head *) + let first = List.last default_first rest in + return (Some (first.level, last.level))) + + let current_level ctxt ?(offset = 0l) block = + RPC_context.make_call0 S.current_level ctxt block {offset} () + + let levels_in_current_cycle ctxt ?(offset = 0l) block = + RPC_context.make_call0 S.levels_in_current_cycle ctxt block {offset} () + + let rpc_services = + register () ; + RPC_directory.merge rpc_services !Registration.patched_services +end diff --git a/src/proto_011_PtHangzH/lib_plugin/plugin_registerer.ml b/src/proto_011_PtHangzH/lib_plugin/plugin_registerer.ml new file mode 100644 index 000000000000..03b4f9dccbac --- /dev/null +++ b/src/proto_011_PtHangzH/lib_plugin/plugin_registerer.ml @@ -0,0 +1,31 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Development. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module Plugin = struct + module Proto = Registerer.Registered + include Plugin +end + +let () = Prevalidator_filters.register (module Plugin) diff --git a/src/proto_011_PtHangzH/lib_plugin/tezos-protocol-plugin-011-PtHangzH-registerer.opam b/src/proto_011_PtHangzH/lib_plugin/tezos-protocol-plugin-011-PtHangzH-registerer.opam new file mode 100644 index 000000000000..64e458fca1f8 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_plugin/tezos-protocol-plugin-011-PtHangzH-registerer.opam @@ -0,0 +1,18 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-embedded-protocol-011-PtHangzH" + "tezos-protocol-plugin-011-PtHangzH" + "tezos-shell" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: protocol plugin registerer" diff --git a/src/proto_011_PtHangzH/lib_plugin/tezos-protocol-plugin-011-PtHangzH.opam b/src/proto_011_PtHangzH/lib_plugin/tezos-protocol-plugin-011-PtHangzH.opam new file mode 100644 index 000000000000..8500743e364a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_plugin/tezos-protocol-plugin-011-PtHangzH.opam @@ -0,0 +1,17 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-base" + "tezos-protocol-011-PtHangzH" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: protocol plugin" diff --git a/src/proto_011_PtHangzH/lib_protocol/.ocamlformat b/src/proto_011_PtHangzH/lib_protocol/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_protocol/TEZOS_PROTOCOL b/src/proto_011_PtHangzH/lib_protocol/TEZOS_PROTOCOL new file mode 100644 index 000000000000..0495fa7dc414 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/TEZOS_PROTOCOL @@ -0,0 +1,113 @@ +{ + "expected_env_version": 3, + "hash": "PtHangzHogokSuiMHemCuowEavgYTP8J5qQ9fQS793MHYFpCY3r", + "modules": [ + "Misc", + "Path_encoding", + "Storage_description", + "State_hash", + "Nonce_hash", + "Script_expr_hash", + "Contract_hash", + "Blinded_public_key_hash", + + "Tez_repr", + "Period_repr", + "Time_repr", + "Fixed_point_repr", + "Saturation_repr", + "Gas_limit_repr", + "Constants_repr", + "Fitness_repr", + "Raw_level_repr", + "Cycle_repr", + "Level_repr", + "Seed_repr", + "Voting_period_repr", + "Script_string_repr", + "Script_int_repr", + "Script_timestamp_repr", + "Michelson_v1_primitives", + "Script_repr", + "Cache_memory_helpers", + "Contract_repr", + "Roll_repr", + "Vote_repr", + "Block_header_repr", + "Operation_repr", + "Manager_repr", + "Commitment_repr", + "Parameters_repr", + "Sapling_repr", + "Lazy_storage_kind", + "Receipt_repr", + "Migration_repr", + + "Raw_context_intf", + "Raw_context", + "Storage_costs", + "Storage_sigs", + "Storage_functors", + "Storage", + + "Constants_storage", + "Level_storage", + "Nonce_storage", + "Seed_storage", + "Roll_storage", + "Delegate_storage", + "Sapling_storage", + "Lazy_storage_diff", + "Contract_storage", + "Bootstrap_storage", + "Fitness_storage", + "Voting_period_storage", + "Vote_storage", + "Commitment_storage", + "Fees_storage", + "Liquidity_baking_repr", + "Liquidity_baking_cpmm", + "Liquidity_baking_lqt", + "Liquidity_baking_migration", + "Init_storage", + "Sapling_validator", + + "Global_constants_costs", + "Global_constants_storage", + + "Cache_costs", + + "Alpha_context", + + "Script_tc_errors", + "Script_typed_ir", + "Script_typed_ir_size", + "Script_typed_ir_size_costs", + "Michelson_v1_gas", + "Script_ir_annot", + "Script_list", + "Script_comparable", + "Script_set", + "Script_map", + "Script_ir_translator", + "Script_cache", + "Script_tc_errors_registration", + "Script_interpreter_defs", + "Script_interpreter", + + "Baking", + "Amendment", + "Apply_results", + "Apply", + + "Services_registration", + "Constants_services", + "Sapling_services", + "Contract_services", + "Delegate_services", + "Voting_services", + "Alpha_services", + + "Main" + ] +} diff --git a/src/proto_011_PtHangzH/lib_protocol/alpha_context.ml b/src/proto_011_PtHangzH/lib_protocol/alpha_context.ml new file mode 100644 index 000000000000..3278d731af83 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/alpha_context.ml @@ -0,0 +1,548 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type t = Raw_context.t + +type context = t + +module type BASIC_DATA = sig + type t + + include Compare.S with type t := t + + val encoding : t Data_encoding.t + + val pp : Format.formatter -> t -> unit +end + +module Tez = Tez_repr +module Period = Period_repr + +module Timestamp = struct + include Time_repr + + let current = Raw_context.current_timestamp + + let predecessor = Raw_context.predecessor_timestamp +end + +include Operation_repr + +module Operation = struct + type 'kind t = 'kind operation = { + shell : Operation.shell_header; + protocol_data : 'kind protocol_data; + } + + type packed = packed_operation + + let unsigned_encoding = unsigned_operation_encoding + + include Operation_repr +end + +module Block_header = Block_header_repr + +module Vote = struct + include Vote_repr + include Vote_storage +end + +module Raw_level = Raw_level_repr +module Cycle = Cycle_repr +module Script_string = Script_string_repr +module Script_int = Script_int_repr + +module Script_timestamp = struct + include Script_timestamp_repr + + let now ctxt = + let {Constants_repr.minimal_block_delay; _} = Raw_context.constants ctxt in + let current_timestamp = Raw_context.predecessor_timestamp ctxt in + Time.add current_timestamp (Period_repr.to_seconds minimal_block_delay) + |> Timestamp.to_seconds |> of_int64 +end + +module Script = struct + include Michelson_v1_primitives + include Script_repr + + let force_decode_in_context ctxt lexpr = + Raw_context.consume_gas ctxt (Script_repr.force_decode_cost lexpr) + >>? fun ctxt -> + Script_repr.force_decode lexpr >|? fun v -> (v, ctxt) + + let force_bytes_in_context ctxt lexpr = + Raw_context.consume_gas ctxt (Script_repr.force_bytes_cost lexpr) + >>? fun ctxt -> + Script_repr.force_bytes lexpr >|? fun v -> (v, ctxt) +end + +module Fees = Fees_storage + +type public_key = Signature.Public_key.t + +type public_key_hash = Signature.Public_key_hash.t + +type signature = Signature.t + +module Constants = struct + include Constants_repr + include Constants_storage +end + +module Voting_period = struct + include Voting_period_repr + include Voting_period_storage +end + +module Gas = struct + include Gas_limit_repr + + type error += Gas_limit_too_high = Raw_context.Gas_limit_too_high + + type error += Block_quota_exceeded = Raw_context.Block_quota_exceeded + + type error += Operation_quota_exceeded = Raw_context.Operation_quota_exceeded + + let check_limit_is_valid = Raw_context.check_gas_limit_is_valid + + let set_limit = Raw_context.set_gas_limit + + let consume_limit_in_block = Raw_context.consume_gas_limit_in_block + + let set_unlimited = Raw_context.set_gas_unlimited + + let consume = Raw_context.consume_gas + + let remaining_operation_gas = Raw_context.remaining_operation_gas + + let update_remaining_operation_gas = + Raw_context.update_remaining_operation_gas + + let gas_exhausted_error = Raw_context.gas_exhausted_error + + let level = Raw_context.gas_level + + let consumed = Raw_context.gas_consumed + + let block_level = Raw_context.block_gas_level + + (* Necessary to inject costs for Storage_costs into Gas.cost *) + let cost_of_repr cost = cost +end + +module Level = struct + include Level_repr + include Level_storage +end + +module Lazy_storage = struct + module Kind = Lazy_storage_kind + module IdSet = Kind.IdSet + include Lazy_storage_diff + + let legacy_big_map_diff_encoding = + Data_encoding.conv + Contract_storage.Legacy_big_map_diff.of_lazy_storage_diff + Contract_storage.Legacy_big_map_diff.to_lazy_storage_diff + Contract_storage.Legacy_big_map_diff.encoding +end + +module Contract = struct + include Contract_repr + include Contract_storage + + let originate c contract ~balance ~script ~delegate = + raw_originate c contract ~balance ~script ~delegate + + let init_origination_nonce = Raw_context.init_origination_nonce + + let unset_origination_nonce = Raw_context.unset_origination_nonce +end + +module Global_constants_storage = Global_constants_storage + +module Big_map = struct + module Big_map = Lazy_storage_kind.Big_map + + module Id = struct + type t = Big_map.Id.t + + let encoding = Big_map.Id.encoding + + let rpc_arg = Big_map.Id.rpc_arg + + let parse_z = Big_map.Id.parse_z + + let unparse_to_z = Big_map.Id.unparse_to_z + end + + let fresh ~temporary c = Lazy_storage.fresh Big_map ~temporary c + + let mem c m k = Storage.Big_map.Contents.mem (c, m) k + + let get_opt c m k = Storage.Big_map.Contents.find (c, m) k + + let list_values ?offset ?length c m = + Storage.Big_map.Contents.list_values ?offset ?length (c, m) + + let exists c id = + Raw_context.consume_gas c (Gas_limit_repr.read_bytes_cost 0) >>?= fun c -> + Storage.Big_map.Key_type.find c id >>=? fun kt -> + match kt with + | None -> return (c, None) + | Some kt -> + Storage.Big_map.Value_type.get c id >|=? fun kv -> (c, Some (kt, kv)) + + type update = Big_map.update = { + key : Script_repr.expr; + key_hash : Script_expr_hash.t; + value : Script_repr.expr option; + } + + type updates = Big_map.updates + + type alloc = Big_map.alloc = { + key_type : Script_repr.expr; + value_type : Script_repr.expr; + } +end + +module Sapling = struct + module Sapling_state = Lazy_storage_kind.Sapling_state + + module Id = struct + type t = Sapling_state.Id.t + + let encoding = Sapling_state.Id.encoding + + let rpc_arg = Sapling_state.Id.rpc_arg + + let parse_z = Sapling_state.Id.parse_z + + let unparse_to_z = Sapling_state.Id.unparse_to_z + end + + include Sapling_repr + include Sapling_storage + include Sapling_validator + + let fresh ~temporary c = Lazy_storage.fresh Sapling_state ~temporary c + + type updates = Sapling_state.updates + + type alloc = Sapling_state.alloc = {memo_size : Sapling_repr.Memo_size.t} +end + +module Receipt = Receipt_repr +module Delegate = Delegate_storage + +module Roll = struct + include Roll_repr + include Roll_storage +end + +module Nonce = Nonce_storage + +module Seed = struct + include Seed_repr + include Seed_storage +end + +module Fitness = struct + include Fitness_repr + include Fitness + + type fitness = t + + include Fitness_storage +end + +module Bootstrap = Bootstrap_storage + +module Commitment = struct + include Commitment_repr + include Commitment_storage +end + +module Global = struct + let get_block_priority = Storage.Block_priority.get + + let set_block_priority = Storage.Block_priority.update +end + +module Migration = Migration_repr + +let prepare_first_block = Init_storage.prepare_first_block + +let prepare = Init_storage.prepare + +(* The rationale behind the value of this constant is that an + operation should be considered as alive for about one hour: + + minimal_block_delay context * max_operations_ttl = 3600 + + To avoid an unecessary computation, we have hard-coded the value of + this constant. *) +let max_operations_ttl = 120 + +let finalize ?commit_message:message c = + let fitness = Fitness.from_int64 (Fitness.current c) in + let context = Raw_context.recover c in + { + Updater.context; + fitness; + message; + max_operations_ttl; + last_allowed_fork_level = + Raw_level.to_int32 @@ Level.last_allowed_fork_level c; + } + +let activate = Raw_context.activate + +let record_endorsement = Raw_context.record_endorsement + +let allowed_endorsements = Raw_context.allowed_endorsements + +let init_endorsements = Raw_context.init_endorsements + +let included_endorsements = Raw_context.included_endorsements + +let reset_internal_nonce = Raw_context.reset_internal_nonce + +let fresh_internal_nonce = Raw_context.fresh_internal_nonce + +let record_internal_nonce = Raw_context.record_internal_nonce + +let internal_nonce_already_recorded = + Raw_context.internal_nonce_already_recorded + +let add_fees = Raw_context.add_fees + +let add_rewards = Raw_context.add_rewards + +let get_fees = Raw_context.get_fees + +let get_rewards = Raw_context.get_rewards + +let description = Raw_context.description + +module Parameters = Parameters_repr +module Liquidity_baking = Liquidity_baking_repr + +module Cache = struct + type index = int + + type size = int + + type identifier = string + + type namespace = string + + let compare_namespace = Compare.String.compare + + type internal_identifier = {namespace : namespace; id : identifier} + + let separator = '@' + + let sanitize namespace = + if String.contains namespace separator then + invalid_arg + (Format.asprintf + "Invalid cache namespace: '%s'. Character %c is forbidden." + namespace + separator) + else namespace + + let string_of_internal_identifier {namespace; id} = + namespace ^ String.make 1 separator ^ id + + let internal_identifier_of_string raw = + match String.split_on_char separator raw with + | [] -> assert false + | namespace :: id -> + (* An identifier may contain [separator], hence we concatenate + possibly splitted parts of [id]. *) + {namespace = sanitize namespace; id = String.concat "" id} + + let internal_identifier_of_key key = + let raw = Raw_context.Cache.identifier_of_key key in + internal_identifier_of_string raw + + let key_of_internal_identifier ~cache_index identifier = + let raw = string_of_internal_identifier identifier in + Raw_context.Cache.key_of_identifier ~cache_index raw + + let make_key = + let namespaces = ref [] in + fun ~cache_index ~namespace -> + let namespace = sanitize namespace in + if List.mem ~equal:String.equal namespace !namespaces then + invalid_arg + (Format.sprintf + "Cache key namespace %s already exist." + (namespace :> string)) + else ( + namespaces := namespace :: !namespaces ; + fun ~id -> + let identifier = {namespace; id} in + key_of_internal_identifier ~cache_index identifier) + + module NamespaceMap = Map.Make (struct + type t = namespace + + let compare = compare_namespace + end) + + type partial_key_handler = t -> string -> Context.Cache.value tzresult Lwt.t + + let value_of_key_handlers : partial_key_handler NamespaceMap.t ref = + ref NamespaceMap.empty + + module Admin = struct + include Raw_context.Cache + + let list_keys context ~cache_index = + Raw_context.Cache.list_keys context ~cache_index + + let key_rank context key = Raw_context.Cache.key_rank context key + + let value_of_key ctxt key = + (* [value_of_key] is a maintainance operation: it is typically run + when a node reboots. For this reason, this operation is not + carbonated. *) + let ctxt = Gas.set_unlimited ctxt in + let {namespace; id} = internal_identifier_of_key key in + match NamespaceMap.find namespace !value_of_key_handlers with + | Some value_of_key -> value_of_key ctxt id + | None -> + failwith + (Format.sprintf + "No handler for key `%s%c%s'" + namespace + separator + id) + end + + module type CLIENT = sig + val cache_index : int + + val namespace : namespace + + type cached_value + + val value_of_identifier : t -> identifier -> cached_value tzresult Lwt.t + end + + module type INTERFACE = sig + type cached_value + + val update : t -> identifier -> (cached_value * int) option -> t tzresult + + val find : t -> identifier -> cached_value option tzresult Lwt.t + + val list_identifiers : t -> (identifier * int) list + + val identifier_rank : t -> identifier -> int option + + val size : context -> size + + val size_limit : context -> size + end + + let register_exn (type cvalue) + (module C : CLIENT with type cached_value = cvalue) : + (module INTERFACE with type cached_value = cvalue) = + if + Compare.Int.( + C.cache_index < 0 + || C.cache_index >= List.length Constants_repr.cache_layout) + then invalid_arg "Cache index is invalid" ; + let mk = make_key ~cache_index:C.cache_index ~namespace:C.namespace in + (module struct + type cached_value = C.cached_value + + type Admin.value += K of cached_value + + let () = + let voi ctxt i = + C.value_of_identifier ctxt i >>=? fun v -> return (K v) + in + value_of_key_handlers := + NamespaceMap.add C.namespace voi !value_of_key_handlers + + let size ctxt = + Option.value ~default:max_int + @@ Admin.cache_size ctxt ~cache_index:C.cache_index + + let size_limit ctxt = + Option.value ~default:max_int + @@ Admin.cache_size_limit ctxt ~cache_index:C.cache_index + + let update ctxt id v = + let cache_size_in_bytes = size ctxt in + Raw_context.consume_gas + ctxt + (Cache_costs.cache_update ~cache_size_in_bytes) + >|? fun ctxt -> + let v = Option.map (fun (v, size) -> (K v, size)) v in + Admin.update ctxt (mk ~id) v + + let find ctxt id = + let cache_size_in_bytes = size ctxt in + Raw_context.consume_gas + ctxt + (Cache_costs.cache_update ~cache_size_in_bytes) + >>?= fun ctxt -> + Admin.find ctxt (mk ~id) >>= function + | None -> return None + | Some (K v) -> return (Some v) + | _ -> + (* This execution path is impossible because all the keys of + C's namespace (which is unique to C) are constructed with + [K]. This [assert false] could have been pushed into the + environment in exchange for extra complexity. The + argument that justifies this [assert false] seems + simple enough to keep the current design though. *) + assert false + + let list_identifiers ctxt = + Admin.list_keys ctxt ~cache_index:C.cache_index |> function + | None -> + (* `cache_index` is valid. *) + assert false + | Some list -> + List.filter_map + (fun (key, age) -> + let {namespace; id} = internal_identifier_of_key key in + if String.equal namespace C.namespace then Some (id, age) + else None) + list + + let identifier_rank ctxt id = Admin.key_rank ctxt (mk ~id) + end) +end diff --git a/src/proto_011_PtHangzH/lib_protocol/alpha_context.mli b/src/proto_011_PtHangzH/lib_protocol/alpha_context.mli new file mode 100644 index 000000000000..74c725e75a07 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/alpha_context.mli @@ -0,0 +1,2095 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** An [Alpha_context.t] is an immutable snapshot of the ledger state at some block + height, preserving + {{:https://tezos.gitlab.io/developer/entering_alpha.html#the-big-abstraction-barrier-alpha-context} + type-safety and invariants} of the ledger state. + + {2 Implementation} + + [Alpha_context.t] is a wrapper over [Raw_context.t], which in turn is a + wrapper around [Context.t] from the Protocol Environment. + + {2 Lifetime of an Alpha_context} + + - Creation, using [prepare] or [prepare_first_block] + + - Modification, using the operations defined in this signature + + - Finalization, using [finalize] + *) + +module type BASIC_DATA = sig + type t + + include Compare.S with type t := t + + val encoding : t Data_encoding.t + + val pp : Format.formatter -> t -> unit +end + +type t + +type context = t + +type public_key = Signature.Public_key.t + +type public_key_hash = Signature.Public_key_hash.t + +type signature = Signature.t + +module Tez : sig + include BASIC_DATA + + type tez = t + + val zero : tez + + val one_mutez : tez + + val one_cent : tez + + val fifty_cents : tez + + val one : tez + + val ( -? ) : tez -> tez -> tez tzresult + + val ( +? ) : tez -> tez -> tez tzresult + + val ( *? ) : tez -> int64 -> tez tzresult + + val ( /? ) : tez -> int64 -> tez tzresult + + val of_string : string -> tez option + + val to_string : tez -> string + + val of_mutez : int64 -> tez option + + val to_mutez : tez -> int64 + + val of_mutez_exn : int64 -> t + + val mul_exn : t -> int -> t +end + +module Period : sig + include BASIC_DATA + + type period = t + + val rpc_arg : period RPC_arg.arg + + val of_seconds : int64 -> period tzresult + + val of_seconds_exn : int64 -> period + + val to_seconds : period -> int64 + + val add : period -> period -> period tzresult + + val mult : int32 -> period -> period tzresult + + val zero : period + + val one_second : period + + val one_minute : period + + val one_hour : period + + val compare : period -> period -> int +end + +module Timestamp : sig + include BASIC_DATA with type t = Time.t + + type time = t + + val ( +? ) : time -> Period.t -> time tzresult + + val ( -? ) : time -> time -> Period.t tzresult + + val of_notation : string -> time option + + val to_notation : time -> string + + val of_seconds_string : string -> time option + + val to_seconds_string : time -> string + + val current : context -> time + + val predecessor : context -> time +end + +module Raw_level : sig + include BASIC_DATA + + type raw_level = t + + val rpc_arg : raw_level RPC_arg.arg + + val diff : raw_level -> raw_level -> int32 + + val root : raw_level + + val succ : raw_level -> raw_level + + val pred : raw_level -> raw_level option + + val to_int32 : raw_level -> int32 + + val of_int32 : int32 -> raw_level tzresult +end + +module Cycle : sig + include BASIC_DATA + + type cycle = t + + val rpc_arg : cycle RPC_arg.arg + + val root : cycle + + val succ : cycle -> cycle + + val pred : cycle -> cycle option + + val add : cycle -> int -> cycle + + val sub : cycle -> int -> cycle option + + val to_int32 : cycle -> int32 + + module Map : Map.S with type key = cycle +end + +module Gas : sig + (** This module implements the gas subsystem of the context. + + Gas reflects the computational cost of each operation to limit + the cost of operations and, by extension, the cost of blocks. + + There are two gas quotas: one for operation and one for + block. For this reason, we maintain two gas levels -- one for + operations and another one for blocks -- that correspond to the + remaining amounts of gas, initialized with the quota + limits and decreased each time gas is consumed. + + *) + + module Arith : + Fixed_point_repr.Safe + with type 'a t = Saturation_repr.may_saturate Saturation_repr.t + [@@coq_plain_module] + + (** For maintenance operations or for testing, gas can be + [Unaccounted]. Otherwise, the computation is [Limited] by the + [remaining] gas in the context. *) + type t = private Unaccounted | Limited of {remaining : Arith.fp} + + val encoding : t Data_encoding.encoding + + val pp : Format.formatter -> t -> unit + + (** [check_limit_is_valid ctxt limit] checks that the given gas + [limit] is well-formed, i.e., it does not exceed the hard gas + limit per operation as defined in [ctxt] and it is positive. *) + val check_limit_is_valid : context -> 'a Arith.t -> unit tzresult + + (** [set_limit ctxt limit] returns a context with a given + [limit] level of gas allocated for an operation. *) + val set_limit : context -> 'a Arith.t -> context + + (** [set_unlimited] allows unlimited gas consumption. *) + val set_unlimited : context -> context + + (** [remaining_operation_gas ctxt] returns the current gas level in + the context [ctxt] for the current operation. If gas is + [Unaccounted], an arbitrary value will be returned. *) + val remaining_operation_gas : context -> Arith.fp + + (** [level ctxt] is the current gas level in [ctxt] for the current + operation. *) + val level : context -> t + + (** [update_remaining_operation_gas ctxt remaining] sets the current + gas level for operations to [remaining]. *) + val update_remaining_operation_gas : context -> Arith.fp -> context + + (** [gas_exhausted_error ctxt] raises an error indicating the gas + has been exhausted. *) + val gas_exhausted_error : context -> 'a tzresult + + (** [consumed since until] is the operation gas level difference + between context [since] and context [until]. This function + returns [Arith.zero] if any of the two contexts allows for an + unlimited gas consumption. This function also returns + [Arith.zero] if [since] has less gas than [until]. *) + val consumed : since:context -> until:context -> Arith.fp + + (** [block_level ctxt] returns the block gas level in context [ctxt]. *) + val block_level : context -> Arith.fp + + (** Costs are computed using a saturating arithmetic. See + {!Saturation_repr}. *) + type cost = Saturation_repr.may_saturate Saturation_repr.t + + val cost_encoding : cost Data_encoding.encoding + + val pp_cost : Format.formatter -> cost -> unit + + (** [consume ctxt cost] subtracts [cost] to the current operation + gas level in [ctxt]. This operation may fail with + [Operation_quota_exceeded] if the operation gas level would + go below zero. *) + val consume : context -> cost -> context tzresult + + type error += Operation_quota_exceeded (* `Temporary *) + + (** [consume_limit_in_block ctxt limit] consumes [limit] in + the current block gas level of the context. This operation may + fail with error [Block_quota_exceeded] if not enough gas remains + in the block. This operation may also fail with + [Gas_limit_too_high] if [limit] is greater than the allowed + limit for operation gas level. *) + val consume_limit_in_block : context -> 'a Arith.t -> context tzresult + + type error += Block_quota_exceeded (* `Temporary *) + + type error += Gas_limit_too_high (* `Permanent *) + + (** The cost of free operation is [0]. *) + val free : cost + + (** [atomic_step_cost x] corresponds to [x] milliunit of gas. *) + val atomic_step_cost : _ Saturation_repr.t -> cost + + (** [step_cost x] corresponds to [x] units of gas. *) + val step_cost : _ Saturation_repr.t -> cost + + (** Cost of allocating qwords of storage. + [alloc_cost n] estimates the cost of allocating [n] qwords of storage. *) + val alloc_cost : _ Saturation_repr.t -> cost + + (** Cost of allocating bytes in the storage. + [alloc_bytes_cost b] estimates the cost of allocating [b] bytes of + storage. *) + val alloc_bytes_cost : int -> cost + + (** Cost of allocating bytes in the storage. + + [alloc_mbytes_cost b] estimates the cost of allocating [b] bytes of + storage and the cost of an header to describe these bytes. *) + val alloc_mbytes_cost : int -> cost + + (** Cost of reading the storage. + [read_bytes_cost n] estimates the cost of reading [n] bytes of storage. *) + val read_bytes_cost : int -> cost + + (** Cost of writing to storage. + [write_bytes_const n] estimates the cost of writing [n] bytes to the + storage. *) + val write_bytes_cost : int -> cost + + (** Multiply a cost by a factor. Both arguments are saturated arithmetic values, + so no negative numbers are involved. *) + val ( *@ ) : _ Saturation_repr.t -> cost -> cost + + (** Add two costs together. *) + val ( +@ ) : cost -> cost -> cost + + (** [cost_of_repr] is an internal operation needed to inject costs + for Storage_costs into Gas.cost. *) + val cost_of_repr : Gas_limit_repr.cost -> cost +end + +module Script_string : module type of Script_string_repr + +module Script_int : module type of Script_int_repr + +module Script_timestamp : sig + open Script_int + + type t + + val compare : t -> t -> int + + val to_string : t -> string + + val to_notation : t -> string option + + val to_num_str : t -> string + + val of_string : string -> t option + + val diff : t -> t -> z num + + val add_delta : t -> z num -> t + + val sub_delta : t -> z num -> t + + val now : context -> t + + val to_zint : t -> Z.t + + val of_zint : Z.t -> t +end + +module Script : sig + type prim = Michelson_v1_primitives.prim = + | K_parameter + | K_storage + | K_code + | K_view + | D_False + | D_Elt + | D_Left + | D_None + | D_Pair + | D_Right + | D_Some + | D_True + | D_Unit + | I_PACK + | I_UNPACK + | I_BLAKE2B + | I_SHA256 + | I_SHA512 + | I_ABS + | I_ADD + | I_AMOUNT + | I_AND + | I_BALANCE + | I_CAR + | I_CDR + | I_CHAIN_ID + | I_CHECK_SIGNATURE + | I_COMPARE + | I_CONCAT + | I_CONS + | I_CREATE_ACCOUNT + | I_CREATE_CONTRACT + | I_IMPLICIT_ACCOUNT + | I_DIP + | I_DROP + | I_DUP + | I_VIEW + | I_EDIV + | I_EMPTY_BIG_MAP + | I_EMPTY_MAP + | I_EMPTY_SET + | I_EQ + | I_EXEC + | I_APPLY + | I_FAILWITH + | I_GE + | I_GET + | I_GET_AND_UPDATE + | I_GT + | I_HASH_KEY + | I_IF + | I_IF_CONS + | I_IF_LEFT + | I_IF_NONE + | I_INT + | I_LAMBDA + | I_LE + | I_LEFT + | I_LEVEL + | I_LOOP + | I_LSL + | I_LSR + | I_LT + | I_MAP + | I_MEM + | I_MUL + | I_NEG + | I_NEQ + | I_NIL + | I_NONE + | I_NOT + | I_NOW + | I_OR + | I_PAIR + | I_UNPAIR + | I_PUSH + | I_RIGHT + | I_SIZE + | I_SOME + | I_SOURCE + | I_SENDER + | I_SELF + | I_SELF_ADDRESS + | I_SLICE + | I_STEPS_TO_QUOTA + | I_SUB + | I_SWAP + | I_TRANSFER_TOKENS + | I_SET_DELEGATE + | I_UNIT + | I_UPDATE + | I_XOR + | I_ITER + | I_LOOP_LEFT + | I_ADDRESS + | I_CONTRACT + | I_ISNAT + | I_CAST + | I_RENAME + | I_SAPLING_EMPTY_STATE + | I_SAPLING_VERIFY_UPDATE + | I_DIG + | I_DUG + | I_NEVER + | I_VOTING_POWER + | I_TOTAL_VOTING_POWER + | I_KECCAK + | I_SHA3 + | I_PAIRING_CHECK + | I_TICKET + | I_READ_TICKET + | I_SPLIT_TICKET + | I_JOIN_TICKETS + | I_OPEN_CHEST + | T_bool + | T_contract + | T_int + | T_key + | T_key_hash + | T_lambda + | T_list + | T_map + | T_big_map + | T_nat + | T_option + | T_or + | T_pair + | T_set + | T_signature + | T_string + | T_bytes + | T_mutez + | T_timestamp + | T_unit + | T_operation + | T_address + | T_sapling_transaction + | T_sapling_state + | T_chain_id + | T_never + | T_bls12_381_g1 + | T_bls12_381_g2 + | T_bls12_381_fr + | T_ticket + | T_chest_key + | T_chest + | H_constant + + type location = Micheline.canonical_location + + type annot = Micheline.annot + + type expr = prim Micheline.canonical + + type lazy_expr = expr Data_encoding.lazy_t + + val lazy_expr : expr -> lazy_expr + + type node = (location, prim) Micheline.node + + type t = {code : lazy_expr; storage : lazy_expr} + + val location_encoding : location Data_encoding.t + + val expr_encoding : expr Data_encoding.t + + val prim_encoding : prim Data_encoding.t + + val encoding : t Data_encoding.t + + val lazy_expr_encoding : lazy_expr Data_encoding.t + + val deserialization_cost_estimated_from_bytes : int -> Gas.cost + + val deserialized_cost : expr -> Gas.cost + + val serialized_cost : bytes -> Gas.cost + + val bytes_node_cost : bytes -> Gas.cost + + val force_decode_in_context : + context -> lazy_expr -> (expr * context) tzresult + + val force_bytes_in_context : + context -> lazy_expr -> (bytes * context) tzresult + + val unit_parameter : lazy_expr + + val strip_locations_cost : node -> Gas.cost +end + +module Constants : sig + (** Fixed constants *) + type fixed = { + proof_of_work_nonce_size : int; + nonce_length : int; + max_anon_ops_per_block : int; + max_operation_data_length : int; + max_proposals_per_delegate : int; + max_micheline_node_count : int; + max_micheline_bytes_limit : int; + max_allowed_global_constant_depth : int; + } + + val fixed_encoding : fixed Data_encoding.t + + val fixed : fixed + + val proof_of_work_nonce_size : int + + val nonce_length : int + + val max_anon_ops_per_block : int + + val max_operation_data_length : int + + val max_proposals_per_delegate : int + + val michelson_maximum_type_size : int + + (** Constants parameterized by context *) + type parametric = { + preserved_cycles : int; + blocks_per_cycle : int32; + blocks_per_commitment : int32; + blocks_per_roll_snapshot : int32; + blocks_per_voting_period : int32; + time_between_blocks : Period.t list; + minimal_block_delay : Period.t; + endorsers_per_block : int; + hard_gas_limit_per_operation : Gas.Arith.integral; + hard_gas_limit_per_block : Gas.Arith.integral; + proof_of_work_threshold : int64; + tokens_per_roll : Tez.t; + seed_nonce_revelation_tip : Tez.t; + origination_size : int; + block_security_deposit : Tez.t; + endorsement_security_deposit : Tez.t; + baking_reward_per_endorsement : Tez.t list; + endorsement_reward : Tez.t list; + cost_per_byte : Tez.t; + hard_storage_limit_per_operation : Z.t; + quorum_min : int32; + quorum_max : int32; + min_proposal_quorum : int32; + initial_endorsers : int; + delay_per_missing_endorsement : Period.t; + liquidity_baking_subsidy : Tez.t; + liquidity_baking_sunset_level : int32; + liquidity_baking_escape_ema_threshold : int32; + } + + val parametric_encoding : parametric Data_encoding.t + + val parametric : context -> parametric + + val preserved_cycles : context -> int + + val time_between_blocks : context -> Period.t list + + val minimal_block_delay : context -> Period.t + + val endorsers_per_block : context -> int + + val initial_endorsers : context -> int + + val delay_per_missing_endorsement : context -> Period.t + + val hard_gas_limit_per_operation : context -> Gas.Arith.integral + + val hard_gas_limit_per_block : context -> Gas.Arith.integral + + val cost_per_byte : context -> Tez.t + + val hard_storage_limit_per_operation : context -> Z.t + + val proof_of_work_threshold : context -> int64 + + val tokens_per_roll : context -> Tez.t + + val baking_reward_per_endorsement : context -> Tez.t list + + val endorsement_reward : context -> Tez.t list + + val seed_nonce_revelation_tip : context -> Tez.t + + val origination_size : context -> int + + val block_security_deposit : context -> Tez.t + + val endorsement_security_deposit : context -> Tez.t + + val quorum_min : context -> int32 + + val quorum_max : context -> int32 + + val min_proposal_quorum : context -> int32 + + val liquidity_baking_subsidy : context -> Tez.t + + val liquidity_baking_sunset_level : context -> int32 + + val liquidity_baking_escape_ema_threshold : context -> int32 + + (** All constants: fixed and parametric *) + type t = {fixed : fixed; parametric : parametric} + + val encoding : t Data_encoding.t +end + +module Global_constants_storage : sig + type error += Expression_too_deep + + type error += Expression_already_registered + + (** A constant is the prim of the literal characters "constant". + A constant must have a single argument, being a string with a + well formed hash of a Micheline expression (i.e generated by + [Script_expr_hash.to_b58check]). *) + type error += Badly_formed_constant_expression + + type error += Nonexistent_global + + (** [get context hash] retrieves the Micheline value with the given hash. + + Fails with [Nonexistent_global] if no value is found at the given hash. + + Fails with [Storage_error Corrupted_data] if the deserialisation fails. + + Consumes [Gas_repr.read_bytes_cost ]. *) + val get : t -> Script_expr_hash.t -> (t * Script.expr) tzresult Lwt.t + + (** [register context value] Register a constant in the global table of constants, + returning the hash and storage bytes consumed. + + Does not type-check the Micheline code being registered, allow potentially + ill-typed Michelson values (see note at top of module in global_constants_storage.mli). + + The constant is stored unexpanded, but it is temporarily expanded at registration + time only to check the expanded version respects the following limits. + + Fails with [Expression_too_deep] if, after fully, expanding all constants, + the expression would contain too many nested levels, that is more than + [Constants_repr.max_allowed_global_constant_depth]. + + Fails with [Badly_formed_constant_expression] if constants are not + well-formed (see declaration of [Badly_formed_constant_expression]) or with + [Nonexistent_global] if a referenced constant does not exist in the table. + + Consumes serialization cost. + Consumes [Gas_repr.write_bytes_cost ] where size is the number + of bytes in the binary serialization provided by [Script.expr_encoding].*) + val register : + t -> Script.expr -> (t * Script_expr_hash.t * Z.t) tzresult Lwt.t + + (** [expand context expr] Replaces every constant in the + given Michelson expression with its value stored in the global table. + + The expansion is applied recursively so that the returned expression + contains no constant. + + Fails with [Badly_formed_constant_expression] if constants are not + well-formed (see declaration of [Badly_formed_constant_expression]) or + with [Nonexistent_global] if a referenced constant does not exist in + the table. *) + val expand : t -> Script.expr -> (t * Script.expr) tzresult Lwt.t + + module Internal_for_tests : sig + (** [node_too_large node] returns true if: + - The number of sub-nodes in the [node] + exceeds [Global_constants_storage.node_size_limit]. + - The sum of the bytes in String, Int, + and Bytes sub-nodes of [node] exceeds + [Global_constants_storage.bytes_size_limit]. + + Otherwise returns false. *) + val node_too_large : Script.node -> bool + + (** [bottom_up_fold_cps initial_accumulator node initial_k f] + folds [node] and all its sub-nodes if any, starting from + [initial_accumulator], using an initial continuation [initial_k]. + At each node, [f] is called to transform the continuation [k] into + the next one. This explicit manipulation of the continuation + is typically useful to short-circuit. + + Notice that a common source of bug is to forget to properly call the + continuation in `f`. *) + val bottom_up_fold_cps : + 'accumulator -> + Script.node -> + ('accumulator -> Script.node -> 'return) -> + ('accumulator -> + Script_repr.node -> + ('accumulator -> Script.node -> 'return) -> + 'return) -> + 'return + + (** [expr_to_address_in_context context expr] converts [expr] + into a unique hash represented by a [Script_expr_hash.t]. + + Consumes gas corresponding to the cost of converting [expr] + to bytes and hashing the bytes. *) + val expr_to_address_in_context : + t -> Script.expr -> (t * Script_expr_hash.t) tzresult + end +end + +module Cache : sig + (** + + Frequently used data should be kept in memory and persist along a + chain of blocks. The caching mechanism allows the economic protocol + to declare such data and to rely on a Least Recently Used strategy + to keep the cache size under a fixed limit. + + Take a look at {!Environment_cache} and {!Environment_context} + for additional implementation details about the protocol cache. + + The protocol has two main kinds of interaction with the cache: + + 1. It is responsible for setting up the cache with appropriate + parameter values and callbacks. It must also compute cache nonces + to give the shell enough information to properly synchronize the + in-memory cache with the block contexts and protocol upgrades. + A typical place where this happens is {!Apply}. + This aspect must be implemented using {!Cache.Admin}. + + 2. It can exploit the cache to retrieve, to insert, and to update + cached values from the in-memory cache. The basic idea is to + avoid recomputing values from scratch at each block when they are + frequently used. {!Script_cache} is an example of such usage. + This aspect must be implemented using {!Cache.Interface}. + + *) + + (** Size for subcaches and values of the cache. *) + type size = int + + (** Index type to index caches. *) + type index = int + + (** + + The following module acts on the whole cache, not on a specific + sub-cache, unlike {!Interface}. It is used to administrate the + protocol cache, e.g., to maintain the cache in a consistent state + with respect to the chain. This module is typically used by + low-level layers of the protocol and by the shell. + + *) + module Admin : sig + (** A key uniquely identifies a cached [value] in some subcache. *) + type key + + (** Cached values. *) + type value + + (** [pp fmt ctxt] is a pretty printter for the [cache] of [ctxt]. *) + val pp : Format.formatter -> context -> unit + + (** [set_cache_layout ctxt layout] sets the caches of [ctxt] to + comply with given [layout]. If there was already a cache in + [ctxt], it is erased by the new layout. + + In that case, a fresh collection of empty caches is reconstructed + from the new [layout]. Notice that cache [key]s are invalidated + in that case, i.e., [find t k] will return [None]. *) + val set_cache_layout : context -> size list -> context Lwt.t + + (** [sync ctxt ~cache_nonce] updates the context with the domain of + the cache computed so far. Such function is expected to be called + at the end of the validation of a block, when there is no more + accesses to the cache. + + [cache_nonce] identifies the block that introduced new cache + entries. The nonce should identify uniquely the block which + modifies this value. It cannot be the block hash for circularity + reasons: The value of the nonce is stored onto the context and + consequently influences the context hash of the very same + block. Such nonce cannot be determined by the shell and its + computation is delegated to the economic protocol. *) + val sync : context -> cache_nonce:Bytes.t -> context Lwt.t + + (** [clear ctxt] removes all cache entries. *) + val clear : context -> context + + (** {3 Cache helpers for RPCs} *) + + (** [future_cache_expectation ctxt ~time_in_blocks] returns [ctxt] except + that the entries of the caches that are presumably too old to + still be in the caches in [n_blocks] are removed. + + This function is based on a heuristic. The context maintains + the median of the number of removed entries: this number is + multipled by `n_blocks` to determine the entries that are + likely to be removed in `n_blocks`. *) + val future_cache_expectation : context -> time_in_blocks:int -> context + + (** [cache_size ctxt ~cache_index] returns an overapproximation of + the size of the cache. Returns [None] if [cache_index] is + greater than the number of subcaches declared by the cache + layout. *) + val cache_size : context -> cache_index:int -> size option + + (** [cache_size_limit ctxt ~cache_index] returns the maximal size of + the cache indexed by [cache_index]. Returns [None] if + [cache_index] is greater than the number of subcaches declared + by the cache layout. *) + val cache_size_limit : context -> cache_index:int -> size option + + (** [value_of_key ctxt k] interprets the functions introduced by + [register] to construct a cacheable value for a key [k]. *) + val value_of_key : + context -> Context.Cache.key -> Context.Cache.value tzresult Lwt.t + end + + (** A client uses a unique namespace (represented as a string + without '@') to avoid collision with the keys of other + clients. *) + type namespace = string + + (** A key is fully determined by a namespace and an identifier. *) + type identifier = string + + (** + + To use the cache, a client must implement the [CLIENT] + interface. + + *) + module type CLIENT = sig + (** The type of value to be stored in the cache. *) + type cached_value + + (** The client must declare the index of the subcache where its + values shall live. [cache_index] must be between [0] and + [List.length Constants_repr.cache_layout - 1]. *) + val cache_index : index + + (** The client must declare a namespace. This namespace must + be unique. Otherwise, the program stops. + A namespace cannot contain '@'. *) + val namespace : namespace + + (** [value_of_identifier id] builds the cached value identified by + [id]. This function is called when the subcache is loaded into + memory from the on-disk representation of its domain. + + An error during the execution of this function is fatal as + witnessed by its type: an error embedded in a [tzresult] is not + supposed to be catched by the protocol. *) + val value_of_identifier : + context -> identifier -> cached_value tzresult Lwt.t + end + + (** + + An [INTERFACE] to the subcache where keys live in a given [namespace]. + + *) + module type INTERFACE = sig + (** The type of value to be stored in the cache. *) + type cached_value + + (** [update ctxt i (Some (e, size))] returns a context where the + value [e] of given [size] is associated to identifier [i] in + the subcache. If [i] is already in the subcache, the cache + entry is updated. + + [update ctxt i None] removes [i] from the subcache. *) + val update : + context -> identifier -> (cached_value * size) option -> context tzresult + + (** [find ctxt i = Some v] if [v] is the value associated to [i] + in the subcache. Returns [None] if there is no such value in + the subcache. This function is in the Lwt monad because if the + value may have not been constructed (see the lazy loading + mode in {!Environment_context}), it is constructed on the fly. *) + val find : context -> identifier -> cached_value option tzresult Lwt.t + + (** [list_identifiers ctxt] returns the list of the + identifiers of the cached values along with their respective + size. The returned list is sorted in terms of their age in the + cache, the oldest coming first. *) + val list_identifiers : context -> (string * int) list + + (** [identifier_rank ctxt identifier] returns the number of cached value + older than the one of [identifier]; or, [None] if the [identifier] has + no associated value in the subcache. *) + val identifier_rank : context -> string -> int option + + (** [size ctxt] returns an overapproximation of the subcache size + (in bytes). *) + val size : context -> int + + (** [size_limit ctxt] returns the maximal size of the subcache + (in bytes). *) + val size_limit : context -> int + end + + (** [register_exn client] produces an [Interface] specific to a + given [client]. This function can fail if [client] does not + respect the invariant declared in the documentation of + {!CLIENT}. *) + val register_exn : + (module CLIENT with type cached_value = 'a) -> + (module INTERFACE with type cached_value = 'a) +end + +module Level : sig + type t = private { + level : Raw_level.t; + level_position : int32; + cycle : Cycle.t; + cycle_position : int32; + expected_commitment : bool; + } + + include BASIC_DATA with type t := t + + val pp_full : Format.formatter -> t -> unit + + type level = t + + val root : context -> level + + val succ : context -> level -> level + + val pred : context -> level -> level option + + val from_raw : context -> Raw_level.t -> level + + (** Fails with [Negative_level_and_offset_sum] if the sum of the raw_level and the offset is negative. *) + val from_raw_with_offset : + context -> offset:int32 -> Raw_level.t -> level tzresult + + val diff : level -> level -> int32 + + val current : context -> level + + val last_level_in_cycle : context -> Cycle.t -> level + + val levels_in_cycle : context -> Cycle.t -> level list + + val levels_in_current_cycle : context -> ?offset:int32 -> unit -> level list + + val last_allowed_fork_level : context -> Raw_level.t + + val dawn_of_a_new_cycle : context -> Cycle.t option + + val may_snapshot_rolls : context -> bool +end + +module Fitness : sig + include module type of Fitness + + type fitness = t + + val increase : context -> context + + val current : context -> int64 + + val to_int64 : fitness -> int64 tzresult + + val from_int64 : int64 -> bytes list +end + +module Nonce : sig + type t + + type nonce = t + + val encoding : nonce Data_encoding.t + + type unrevealed = { + nonce_hash : Nonce_hash.t; + delegate : public_key_hash; + rewards : Tez.t; + fees : Tez.t; + } + + val record_hash : context -> unrevealed -> context tzresult Lwt.t + + val reveal : context -> Level.t -> nonce -> context tzresult Lwt.t + + type status = Unrevealed of unrevealed | Revealed of nonce + + val get : context -> Level.t -> status tzresult Lwt.t + + val of_bytes : bytes -> nonce tzresult + + val hash : nonce -> Nonce_hash.t + + val check_hash : nonce -> Nonce_hash.t -> bool +end + +module Seed : sig + type seed + + type error += Unknown of {oldest : Cycle.t; cycle : Cycle.t; latest : Cycle.t} + + val for_cycle : context -> Cycle.t -> seed tzresult Lwt.t + + val cycle_end : + context -> Cycle.t -> (context * Nonce.unrevealed list) tzresult Lwt.t + + val seed_encoding : seed Data_encoding.t +end + +module Big_map : sig + module Id : sig + type t + + val encoding : t Data_encoding.t + + val rpc_arg : t RPC_arg.arg + + (** In the protocol, to be used in parse_data only *) + val parse_z : Z.t -> t + + (** In the protocol, to be used in unparse_data only *) + val unparse_to_z : t -> Z.t + end + + val fresh : temporary:bool -> context -> (context * Id.t) tzresult Lwt.t + + val mem : + context -> Id.t -> Script_expr_hash.t -> (context * bool) tzresult Lwt.t + + val get_opt : + context -> + Id.t -> + Script_expr_hash.t -> + (context * Script.expr option) tzresult Lwt.t + + val exists : + context -> + Id.t -> + (context * (Script.expr * Script.expr) option) tzresult Lwt.t + + (** [list_values ?offset ?length ctxt id] lists all values stored in big map [id]. + + The first [offset] values are ignored (if passed). Negative offsets are treated as [0]. + + There will be no more than [length] values in the result list (if passed). + Negative values are treated as [0]. + + The returned {!context} takes into account gas consumption of loading values. + *) + val list_values : + ?offset:int -> + ?length:int -> + context -> + Id.t -> + (context * Script.expr list) tzresult Lwt.t + + type update = { + key : Script_repr.expr; + key_hash : Script_expr_hash.t; + value : Script_repr.expr option; + } + + type updates = update list + + type alloc = {key_type : Script_repr.expr; value_type : Script_repr.expr} +end + +module Sapling : sig + module Id : sig + type t + + val encoding : t Data_encoding.t + + val rpc_arg : t RPC_arg.arg + + val parse_z : Z.t -> t (* To be used in parse_data only *) + + val unparse_to_z : t -> Z.t (* To be used in unparse_data only *) + end + + val fresh : temporary:bool -> context -> (context * Id.t) tzresult Lwt.t + + type diff = private { + commitments_and_ciphertexts : + (Sapling.Commitment.t * Sapling.Ciphertext.t) list; + nullifiers : Sapling.Nullifier.t list; + } + + val diff_encoding : diff Data_encoding.t + + module Memo_size : sig + type t + + val encoding : t Data_encoding.t + + val equal : t -> t -> bool + + val parse_z : Z.t -> (t, string) result + + val unparse_to_z : t -> Z.t + end + + type state = private {id : Id.t option; diff : diff; memo_size : Memo_size.t} + + (** + Returns a [state] with fields filled accordingly. + [id] should only be used by [extract_lazy_storage_updates]. + *) + val empty_state : ?id:Id.t -> memo_size:Memo_size.t -> unit -> state + + type transaction = Sapling.UTXO.transaction + + val transaction_encoding : transaction Data_encoding.t + + val transaction_get_memo_size : transaction -> Memo_size.t option + + (** + Tries to fetch a state from the storage. + *) + val state_from_id : context -> Id.t -> (state * context) tzresult Lwt.t + + val rpc_arg : Id.t RPC_arg.t + + type root = Sapling.Hash.t + + val root_encoding : root Data_encoding.t + + (* Function exposed as RPC. Returns the root and a diff of a state starting + from an optional offset which is zero by default. *) + val get_diff : + context -> + Id.t -> + ?offset_commitment:Int64.t -> + ?offset_nullifier:Int64.t -> + unit -> + (root * diff) tzresult Lwt.t + + val verify_update : + context -> + state -> + transaction -> + string -> + (context * (Int64.t * state) option) tzresult Lwt.t + + type alloc = {memo_size : Memo_size.t} + + type updates = diff + + val transaction_in_memory_size : transaction -> Cache_memory_helpers.sint + + val diff_in_memory_size : diff -> Cache_memory_helpers.sint +end + +module Lazy_storage : sig + module Kind : sig + type ('id, 'alloc, 'updates) t = + | Big_map : (Big_map.Id.t, Big_map.alloc, Big_map.updates) t + | Sapling_state : (Sapling.Id.t, Sapling.alloc, Sapling.updates) t + end + + module IdSet : sig + type t + + type 'acc fold_f = {f : 'i 'a 'u. ('i, 'a, 'u) Kind.t -> 'i -> 'acc -> 'acc} + + val empty : t + + val mem : ('i, 'a, 'u) Kind.t -> 'i -> t -> bool + + val add : ('i, 'a, 'u) Kind.t -> 'i -> t -> t + + val diff : t -> t -> t + + val fold : ('i, 'a, 'u) Kind.t -> ('i -> 'acc -> 'acc) -> t -> 'acc -> 'acc + + val fold_all : 'acc fold_f -> t -> 'acc -> 'acc + end + + type ('id, 'alloc) init = Existing | Copy of {src : 'id} | Alloc of 'alloc + + type ('id, 'alloc, 'updates) diff = + | Remove + | Update of {init : ('id, 'alloc) init; updates : 'updates} + + type diffs_item + + val make : ('i, 'a, 'u) Kind.t -> 'i -> ('i, 'a, 'u) diff -> diffs_item + + type diffs = diffs_item list + + val encoding : diffs Data_encoding.t + + val diffs_in_memory_size : diffs -> Cache_memory_helpers.nodes_and_size + + val legacy_big_map_diff_encoding : diffs Data_encoding.t + + val cleanup_temporaries : context -> context Lwt.t + + val apply : t -> diffs -> (t * Z.t) tzresult Lwt.t +end + +module Contract : sig + include BASIC_DATA + + type contract = t + + val in_memory_size : t -> Cache_memory_helpers.sint + + val rpc_arg : contract RPC_arg.arg + + val to_b58check : contract -> string + + val of_b58check : string -> contract tzresult + + val implicit_contract : public_key_hash -> contract + + val is_implicit : contract -> public_key_hash option + + val exists : context -> contract -> bool tzresult Lwt.t + + val must_exist : context -> contract -> unit tzresult Lwt.t + + val allocated : context -> contract -> bool tzresult Lwt.t + + val must_be_allocated : context -> contract -> unit tzresult Lwt.t + + val list : context -> contract list Lwt.t + + val get_manager_key : context -> public_key_hash -> public_key tzresult Lwt.t + + val is_manager_key_revealed : + context -> public_key_hash -> bool tzresult Lwt.t + + val reveal_manager_key : + context -> public_key_hash -> public_key -> context tzresult Lwt.t + + val get_script_code : + context -> contract -> (context * Script.lazy_expr option) tzresult Lwt.t + + val get_script : + context -> contract -> (context * Script.t option) tzresult Lwt.t + + val get_storage : + context -> contract -> (context * Script.expr option) tzresult Lwt.t + + val get_counter : context -> public_key_hash -> Z.t tzresult Lwt.t + + val get_balance : context -> contract -> Tez.t tzresult Lwt.t + + val get_balance_carbonated : + context -> contract -> (context * Tez.t) tzresult Lwt.t + + val init_origination_nonce : context -> Operation_hash.t -> context + + val unset_origination_nonce : context -> context + + val fresh_contract_from_current_nonce : context -> (context * t) tzresult + + val originated_from_current_nonce : + since:context -> until:context -> contract list tzresult Lwt.t + + module Legacy_big_map_diff : sig + type item = private + | Update of { + big_map : Z.t; + diff_key : Script.expr; + diff_key_hash : Script_expr_hash.t; + diff_value : Script.expr option; + } + | Clear of Z.t + | Copy of {src : Z.t; dst : Z.t} + | Alloc of { + big_map : Z.t; + key_type : Script.expr; + value_type : Script.expr; + } + + type t = private item list + + val of_lazy_storage_diff : Lazy_storage.diffs -> t + end + + val originate : + context -> + contract -> + balance:Tez.t -> + script:Script.t * Lazy_storage.diffs option -> + delegate:public_key_hash option -> + context tzresult Lwt.t + + type error += Balance_too_low of contract * Tez.t * Tez.t + + val spend : context -> contract -> Tez.t -> context tzresult Lwt.t + + val credit : context -> contract -> Tez.t -> context tzresult Lwt.t + + val update_script_storage : + context -> + contract -> + Script.expr -> + Lazy_storage.diffs option -> + context tzresult Lwt.t + + val used_storage_space : context -> t -> Z.t tzresult Lwt.t + + val increment_counter : context -> public_key_hash -> context tzresult Lwt.t + + val check_counter_increment : + context -> public_key_hash -> Z.t -> unit tzresult Lwt.t + + (**/**) + + (* Only for testing *) + type origination_nonce + + val initial_origination_nonce : Operation_hash.t -> origination_nonce + + val originated_contract : origination_nonce -> contract +end + +module Receipt : sig + type balance = + | Contract of Contract.t + | Rewards of Signature.Public_key_hash.t * Cycle.t + | Fees of Signature.Public_key_hash.t * Cycle.t + | Deposits of Signature.Public_key_hash.t * Cycle.t + + type balance_update = Debited of Tez.t | Credited of Tez.t + + type update_origin = Block_application | Protocol_migration | Subsidy + + type balance_updates = (balance * balance_update * update_origin) list + + val balance_updates_encoding : balance_updates Data_encoding.t + + val cleanup_balance_updates : balance_updates -> balance_updates +end + +module Delegate : sig + val get : context -> Contract.t -> public_key_hash option tzresult Lwt.t + + val set : + context -> Contract.t -> public_key_hash option -> context tzresult Lwt.t + + val fold : + context -> init:'a -> f:(public_key_hash -> 'a -> 'a Lwt.t) -> 'a Lwt.t + + val list : context -> public_key_hash list Lwt.t + + val check_delegate : context -> public_key_hash -> unit tzresult Lwt.t + + val freeze_deposit : + context -> public_key_hash -> Tez.t -> context tzresult Lwt.t + + val freeze_rewards : + context -> public_key_hash -> Tez.t -> context tzresult Lwt.t + + val freeze_fees : + context -> public_key_hash -> Tez.t -> context tzresult Lwt.t + + val cycle_end : + context -> + Cycle.t -> + Nonce.unrevealed list -> + (context * Receipt.balance_updates * Signature.Public_key_hash.t list) + tzresult + Lwt.t + + type frozen_balance = {deposit : Tez.t; fees : Tez.t; rewards : Tez.t} + + val punish : + context -> + public_key_hash -> + Cycle.t -> + (context * frozen_balance) tzresult Lwt.t + + val full_balance : context -> public_key_hash -> Tez.t tzresult Lwt.t + + val has_frozen_balance : + context -> public_key_hash -> Cycle.t -> bool tzresult Lwt.t + + val frozen_balance : context -> public_key_hash -> Tez.t tzresult Lwt.t + + val frozen_balance_encoding : frozen_balance Data_encoding.t + + val frozen_balance_by_cycle_encoding : + frozen_balance Cycle.Map.t Data_encoding.t + + val frozen_balance_by_cycle : + context -> Signature.Public_key_hash.t -> frozen_balance Cycle.Map.t Lwt.t + + val staking_balance : + context -> Signature.Public_key_hash.t -> Tez.t tzresult Lwt.t + + val delegated_contracts : + context -> Signature.Public_key_hash.t -> Contract.t list Lwt.t + + val delegated_balance : + context -> Signature.Public_key_hash.t -> Tez.t tzresult Lwt.t + + val deactivated : + context -> Signature.Public_key_hash.t -> bool tzresult Lwt.t + + val grace_period : + context -> Signature.Public_key_hash.t -> Cycle.t tzresult Lwt.t +end + +module Voting_period : sig + type kind = Proposal | Exploration | Cooldown | Promotion | Adoption + + val kind_encoding : kind Data_encoding.encoding + + val pp_kind : Format.formatter -> kind -> unit + + (* This type should be abstract *) + type voting_period = private { + index : int32; + kind : kind; + start_position : int32; + } + + type t = voting_period + + include BASIC_DATA with type t := t + + val encoding : voting_period Data_encoding.t + + val pp : Format.formatter -> voting_period -> unit + + val reset : context -> context tzresult Lwt.t + + val succ : context -> context tzresult Lwt.t + + val get_current : context -> voting_period tzresult Lwt.t + + val get_current_kind : context -> kind tzresult Lwt.t + + val is_last_block : context -> bool tzresult Lwt.t + + type info = {voting_period : t; position : int32; remaining : int32} + + val info_encoding : info Data_encoding.t + + val pp_info : Format.formatter -> info -> unit + + val get_rpc_current_info : context -> info tzresult Lwt.t + + val get_rpc_succ_info : context -> info tzresult Lwt.t +end + +module Vote : sig + type proposal = Protocol_hash.t + + val record_proposal : + context -> Protocol_hash.t -> public_key_hash -> context tzresult Lwt.t + + val get_proposals : context -> int32 Protocol_hash.Map.t tzresult Lwt.t + + val clear_proposals : context -> context Lwt.t + + val recorded_proposal_count_for_delegate : + context -> public_key_hash -> int tzresult Lwt.t + + val listings_encoding : + (Signature.Public_key_hash.t * int32) list Data_encoding.t + + val update_listings : context -> context tzresult Lwt.t + + val listing_size : context -> int32 tzresult Lwt.t + + val in_listings : context -> public_key_hash -> bool Lwt.t + + val get_listings : context -> (public_key_hash * int32) list Lwt.t + + type ballot = Yay | Nay | Pass + + val get_voting_power_free : + context -> Signature.Public_key_hash.t -> int32 tzresult Lwt.t + + val get_voting_power : + context -> Signature.Public_key_hash.t -> (context * int32) tzresult Lwt.t + + val get_total_voting_power_free : context -> int32 tzresult Lwt.t + + val get_total_voting_power : context -> (context * int32) tzresult Lwt.t + + val ballot_encoding : ballot Data_encoding.t + + type ballots = {yay : int32; nay : int32; pass : int32} + + val ballots_encoding : ballots Data_encoding.t + + val has_recorded_ballot : context -> public_key_hash -> bool Lwt.t + + val record_ballot : + context -> public_key_hash -> ballot -> context tzresult Lwt.t + + val get_ballots : context -> ballots tzresult Lwt.t + + val get_ballot_list : + context -> (Signature.Public_key_hash.t * ballot) list Lwt.t + + val clear_ballots : context -> context Lwt.t + + val get_current_quorum : context -> int32 tzresult Lwt.t + + val get_participation_ema : context -> int32 tzresult Lwt.t + + val set_participation_ema : context -> int32 -> context tzresult Lwt.t + + val get_current_proposal : context -> proposal tzresult Lwt.t + + val find_current_proposal : context -> proposal option tzresult Lwt.t + + val init_current_proposal : context -> proposal -> context tzresult Lwt.t + + val clear_current_proposal : context -> context tzresult Lwt.t +end + +module Block_header : sig + type contents = { + priority : int; + seed_nonce_hash : Nonce_hash.t option; + proof_of_work_nonce : bytes; + liquidity_baking_escape_vote : bool; + } + + type protocol_data = {contents : contents; signature : Signature.t} + + type t = {shell : Block_header.shell_header; protocol_data : protocol_data} + + type block_header = t + + type raw = Block_header.t + + type shell_header = Block_header.shell_header + + val raw : block_header -> raw + + val hash : block_header -> Block_hash.t + + val hash_raw : raw -> Block_hash.t + + val encoding : block_header Data_encoding.encoding + + val raw_encoding : raw Data_encoding.t + + val contents_encoding : contents Data_encoding.t + + val unsigned_encoding : (shell_header * contents) Data_encoding.t + + val protocol_data_encoding : protocol_data Data_encoding.encoding + + val shell_header_encoding : shell_header Data_encoding.encoding + + (** The maximum size of block headers in bytes *) + val max_header_length : int +end + +module Kind : sig + type seed_nonce_revelation = Seed_nonce_revelation_kind + + type endorsement_with_slot = Endorsement_with_slot_kind + + type double_endorsement_evidence = Double_endorsement_evidence_kind + + type double_baking_evidence = Double_baking_evidence_kind + + type activate_account = Activate_account_kind + + type endorsement = Endorsement_kind + + type proposals = Proposals_kind + + type ballot = Ballot_kind + + type reveal = Reveal_kind + + type transaction = Transaction_kind + + type origination = Origination_kind + + type delegation = Delegation_kind + + type failing_noop = Failing_noop_kind + + type register_global_constant = Register_global_constant_kind + + type 'a manager = + | Reveal_manager_kind : reveal manager + | Transaction_manager_kind : transaction manager + | Origination_manager_kind : origination manager + | Delegation_manager_kind : delegation manager + | Register_global_constant_manager_kind : register_global_constant manager +end + +type 'kind operation = { + shell : Operation.shell_header; + protocol_data : 'kind protocol_data; +} + +and 'kind protocol_data = { + contents : 'kind contents_list; + signature : Signature.t option; +} + +and _ contents_list = + | Single : 'kind contents -> 'kind contents_list + | Cons : + 'kind Kind.manager contents * 'rest Kind.manager contents_list + -> ('kind * 'rest) Kind.manager contents_list + +and _ contents = + | Endorsement : {level : Raw_level.t} -> Kind.endorsement contents + | Seed_nonce_revelation : { + level : Raw_level.t; + nonce : Nonce.t; + } + -> Kind.seed_nonce_revelation contents + | Endorsement_with_slot : { + endorsement : Kind.endorsement operation; + slot : int; + } + -> Kind.endorsement_with_slot contents + | Double_endorsement_evidence : { + op1 : Kind.endorsement operation; + op2 : Kind.endorsement operation; + slot : int; + } + -> Kind.double_endorsement_evidence contents + | Double_baking_evidence : { + bh1 : Block_header.t; + bh2 : Block_header.t; + } + -> Kind.double_baking_evidence contents + | Activate_account : { + id : Ed25519.Public_key_hash.t; + activation_code : Blinded_public_key_hash.activation_code; + } + -> Kind.activate_account contents + | Proposals : { + source : Signature.Public_key_hash.t; + period : int32; + proposals : Protocol_hash.t list; + } + -> Kind.proposals contents + | Ballot : { + source : Signature.Public_key_hash.t; + period : int32; + proposal : Protocol_hash.t; + ballot : Vote.ballot; + } + -> Kind.ballot contents + | Failing_noop : string -> Kind.failing_noop contents + | Manager_operation : { + source : Signature.Public_key_hash.t; + fee : Tez.tez; + counter : counter; + operation : 'kind manager_operation; + gas_limit : Gas.Arith.integral; + storage_limit : Z.t; + } + -> 'kind Kind.manager contents + +and _ manager_operation = + | Reveal : Signature.Public_key.t -> Kind.reveal manager_operation + | Transaction : { + amount : Tez.tez; + parameters : Script.lazy_expr; + entrypoint : string; + destination : Contract.contract; + } + -> Kind.transaction manager_operation + | Origination : { + delegate : Signature.Public_key_hash.t option; + script : Script.t; + credit : Tez.tez; + preorigination : Contract.t option; + } + -> Kind.origination manager_operation + | Delegation : + Signature.Public_key_hash.t option + -> Kind.delegation manager_operation + | Register_global_constant : { + value : Script.lazy_expr; + } + -> Kind.register_global_constant manager_operation + +and counter = Z.t + +type 'kind internal_operation = { + source : Contract.contract; + operation : 'kind manager_operation; + nonce : int; +} + +type packed_manager_operation = + | Manager : 'kind manager_operation -> packed_manager_operation + +type packed_contents = Contents : 'kind contents -> packed_contents + +type packed_contents_list = + | Contents_list : 'kind contents_list -> packed_contents_list + +type packed_protocol_data = + | Operation_data : 'kind protocol_data -> packed_protocol_data + +type packed_operation = { + shell : Operation.shell_header; + protocol_data : packed_protocol_data; +} + +type packed_internal_operation = + | Internal_operation : 'kind internal_operation -> packed_internal_operation + +val manager_kind : 'kind manager_operation -> 'kind Kind.manager + +module Fees : sig + val origination_burn : context -> (context * Tez.t) tzresult + + val cost_of_bytes : context -> Z.t -> Tez.t tzresult + + val record_paid_storage_space : + context -> Contract.t -> (context * Z.t * Z.t * Tez.t) tzresult Lwt.t + + val record_paid_storage_space_subsidy : + context -> Contract.t -> (context * Z.t * Z.t) tzresult Lwt.t + + val record_global_constant_storage_space : context -> Z.t -> context * Z.t + + val start_counting_storage_fees : context -> context + + val burn_storage_fees : + context -> storage_limit:Z.t -> payer:Contract.t -> context tzresult Lwt.t + + type error += Cannot_pay_storage_fee (* `Temporary *) + + type error += Operation_quota_exceeded (* `Temporary *) + + type error += Storage_limit_too_high (* `Permanent *) + + val check_storage_limit : context -> storage_limit:Z.t -> unit tzresult +end + +module Operation : sig + type nonrec 'kind contents = 'kind contents + + type nonrec packed_contents = packed_contents + + val contents_encoding : packed_contents Data_encoding.t + + type nonrec 'kind protocol_data = 'kind protocol_data + + type nonrec packed_protocol_data = packed_protocol_data + + val protocol_data_encoding : packed_protocol_data Data_encoding.t + + val unsigned_encoding : + (Operation.shell_header * packed_contents_list) Data_encoding.t + + type raw = Operation.t = {shell : Operation.shell_header; proto : bytes} + + val raw_encoding : raw Data_encoding.t + + val contents_list_encoding : packed_contents_list Data_encoding.t + + type 'kind t = 'kind operation = { + shell : Operation.shell_header; + protocol_data : 'kind protocol_data; + } + + type nonrec packed = packed_operation + + val encoding : packed Data_encoding.t + + val raw : _ operation -> raw + + val hash : _ operation -> Operation_hash.t + + val hash_raw : raw -> Operation_hash.t + + val hash_packed : packed_operation -> Operation_hash.t + + val acceptable_passes : packed_operation -> int list + + type error += Missing_signature (* `Permanent *) + + type error += Invalid_signature (* `Permanent *) + + val check_signature : public_key -> Chain_id.t -> _ operation -> unit tzresult + + val internal_operation_encoding : packed_internal_operation Data_encoding.t + + val packed_internal_operation_in_memory_size : + packed_internal_operation -> Cache_memory_helpers.nodes_and_size + + val pack : 'kind operation -> packed_operation + + type ('a, 'b) eq = Eq : ('a, 'a) eq + + val equal : 'a operation -> 'b operation -> ('a, 'b) eq option + + module Encoding : sig + type 'b case = + | Case : { + tag : int; + name : string; + encoding : 'a Data_encoding.t; + select : packed_contents -> 'b contents option; + proj : 'b contents -> 'a; + inj : 'a -> 'b contents; + } + -> 'b case + + val endorsement_case : Kind.endorsement case + + val seed_nonce_revelation_case : Kind.seed_nonce_revelation case + + val endorsement_with_slot_case : Kind.endorsement_with_slot case + + val double_endorsement_evidence_case : Kind.double_endorsement_evidence case + + val double_baking_evidence_case : Kind.double_baking_evidence case + + val activate_account_case : Kind.activate_account case + + val proposals_case : Kind.proposals case + + val ballot_case : Kind.ballot case + + val failing_noop_case : Kind.failing_noop case + + val reveal_case : Kind.reveal Kind.manager case + + val transaction_case : Kind.transaction Kind.manager case + + val origination_case : Kind.origination Kind.manager case + + val delegation_case : Kind.delegation Kind.manager case + + val register_global_constant_case : + Kind.register_global_constant Kind.manager case + + module Manager_operations : sig + type 'b case = + | MCase : { + tag : int; + name : string; + encoding : 'a Data_encoding.t; + select : packed_manager_operation -> 'kind manager_operation option; + proj : 'kind manager_operation -> 'a; + inj : 'a -> 'kind manager_operation; + } + -> 'kind case + + val reveal_case : Kind.reveal case + + val transaction_case : Kind.transaction case + + val origination_case : Kind.origination case + + val delegation_case : Kind.delegation case + + val register_global_constant_case : Kind.register_global_constant case + end + end + + val of_list : packed_contents list -> packed_contents_list tzresult + + val to_list : packed_contents_list -> packed_contents list +end + +module Roll : sig + type t = private int32 + + type roll = t + + val encoding : roll Data_encoding.t + + val snapshot_rolls : context -> context tzresult Lwt.t + + val cycle_end : context -> Cycle.t -> context tzresult Lwt.t + + val baking_rights_owner : + context -> Level.t -> priority:int -> public_key tzresult Lwt.t + + val endorsement_rights_owner : + context -> Level.t -> slot:int -> public_key tzresult Lwt.t + + val delegate_pubkey : context -> public_key_hash -> public_key tzresult Lwt.t + + val count_rolls : context -> Signature.Public_key_hash.t -> int tzresult Lwt.t + + val get_change : + context -> Signature.Public_key_hash.t -> Tez.t tzresult Lwt.t +end + +module Commitment : sig + type t = { + blinded_public_key_hash : Blinded_public_key_hash.t; + amount : Tez.tez; + } + + val encoding : t Data_encoding.t + + val find : context -> Blinded_public_key_hash.t -> Tez.t option tzresult Lwt.t + + val remove_existing : + context -> Blinded_public_key_hash.t -> context tzresult Lwt.t +end + +module Bootstrap : sig + val cycle_end : context -> Cycle.t -> context tzresult Lwt.t +end + +module Global : sig + val get_block_priority : context -> int tzresult Lwt.t + + val set_block_priority : context -> int -> context tzresult Lwt.t +end + +val max_operations_ttl : int + +module Migration : sig + type origination_result = { + balance_updates : Receipt.balance_updates; + originated_contracts : Contract.t list; + storage_size : Z.t; + paid_storage_size_diff : Z.t; + } +end + +(** Create an [Alpha_context.t] from an untyped context (first block in the chain only). *) +val prepare_first_block : + Context.t -> + typecheck: + (context -> + Script.t -> + ((Script.t * Lazy_storage.diffs option) * context) tzresult Lwt.t) -> + level:Int32.t -> + timestamp:Time.t -> + fitness:Fitness.t -> + context tzresult Lwt.t + +(** Create an [Alpha_context.t] from an untyped context. *) +val prepare : + Context.t -> + level:Int32.t -> + predecessor_timestamp:Time.t -> + timestamp:Time.t -> + fitness:Fitness.t -> + (context * Receipt.balance_updates * Migration.origination_result list) + tzresult + Lwt.t + +(** Finalize an {{!t} [Alpha_context.t]}, producing a [validation_result]. + *) +val finalize : ?commit_message:string -> context -> Updater.validation_result + +val activate : context -> Protocol_hash.t -> context Lwt.t + +val record_endorsement : context -> Signature.Public_key_hash.t -> context + +val allowed_endorsements : + context -> + (Signature.Public_key.t * int list * bool) Signature.Public_key_hash.Map.t + +val init_endorsements : + context -> + (Signature.Public_key.t * int list * bool) Signature.Public_key_hash.Map.t -> + context + +val included_endorsements : context -> int + +val reset_internal_nonce : context -> context + +val fresh_internal_nonce : context -> (context * int) tzresult + +val record_internal_nonce : context -> int -> context + +val internal_nonce_already_recorded : context -> int -> bool + +val add_fees : context -> Tez.t -> context tzresult + +val add_rewards : context -> Tez.t -> context tzresult + +val get_fees : context -> Tez.t + +val get_rewards : context -> Tez.t + +val description : context Storage_description.t + +module Parameters : sig + type bootstrap_account = { + public_key_hash : public_key_hash; + public_key : public_key option; + amount : Tez.t; + } + + type bootstrap_contract = { + delegate : public_key_hash; + amount : Tez.t; + script : Script.t; + } + + type t = { + bootstrap_accounts : bootstrap_account list; + bootstrap_contracts : bootstrap_contract list; + commitments : Commitment.t list; + constants : Constants.parametric; + security_deposit_ramp_up_cycles : int option; + no_reward_cycles : int option; + } + + val encoding : t Data_encoding.t +end + +module Liquidity_baking : sig + val get_cpmm_address : context -> Contract.t tzresult Lwt.t + + type escape_ema = Int32.t + + val on_subsidy_allowed : + context -> + escape_vote:bool -> + (context -> Contract.t -> (context * 'a list) tzresult Lwt.t) -> + (context * 'a list * escape_ema) tzresult Lwt.t +end diff --git a/src/proto_011_PtHangzH/lib_protocol/alpha_services.ml b/src/proto_011_PtHangzH/lib_protocol/alpha_services.ml new file mode 100644 index 000000000000..b3b6a5183478 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/alpha_services.ml @@ -0,0 +1,194 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +let custom_root = RPC_path.open_root + +module Seed = struct + module S = struct + open Data_encoding + + let seed = + RPC_service.post_service + ~description:"Seed of the cycle to which the block belongs." + ~query:RPC_query.empty + ~input:empty + ~output:Seed.seed_encoding + RPC_path.(custom_root / "context" / "seed") + end + + let () = + let open Services_registration in + register0 ~chunked:false S.seed (fun ctxt () () -> + let l = Level.current ctxt in + Seed.for_cycle ctxt l.cycle) + + let get ctxt block = RPC_context.make_call0 S.seed ctxt block () () +end + +module Nonce = struct + type info = Revealed of Nonce.t | Missing of Nonce_hash.t | Forgotten + + let info_encoding = + let open Data_encoding in + union + [ + case + (Tag 0) + ~title:"Revealed" + (obj1 (req "nonce" Nonce.encoding)) + (function Revealed nonce -> Some nonce | _ -> None) + (fun nonce -> Revealed nonce); + case + (Tag 1) + ~title:"Missing" + (obj1 (req "hash" Nonce_hash.encoding)) + (function Missing nonce -> Some nonce | _ -> None) + (fun nonce -> Missing nonce); + case + (Tag 2) + ~title:"Forgotten" + empty + (function Forgotten -> Some () | _ -> None) + (fun () -> Forgotten); + ] + + module S = struct + let get = + RPC_service.get_service + ~description:"Info about the nonce of a previous block." + ~query:RPC_query.empty + ~output:info_encoding + RPC_path.(custom_root / "context" / "nonces" /: Raw_level.rpc_arg) + end + + let register () = + let open Services_registration in + register1 ~chunked:false S.get (fun ctxt raw_level () () -> + let level = Level.from_raw ctxt raw_level in + Nonce.get ctxt level >|= function + | Ok (Revealed nonce) -> ok (Revealed nonce) + | Ok (Unrevealed {nonce_hash; _}) -> ok (Missing nonce_hash) + | Error _ -> ok Forgotten) + + let get ctxt block level = RPC_context.make_call1 S.get ctxt block level () () +end + +module Contract = Contract_services +module Constants = Constants_services +module Delegate = Delegate_services +module Voting = Voting_services +module Sapling = Sapling_services + +module Liquidity_baking = struct + module S = struct + let get_cpmm_address = + RPC_service.get_service + ~description:"Liquidity baking CPMM address" + ~query:RPC_query.empty + ~output:Alpha_context.Contract.encoding + RPC_path.(custom_root / "context" / "liquidity_baking" / "cpmm_address") + end + + let register () = + let open Services_registration in + register0 ~chunked:false S.get_cpmm_address (fun ctxt () () -> + Alpha_context.Liquidity_baking.get_cpmm_address ctxt) + + let get_cpmm_address ctxt block = + RPC_context.make_call0 S.get_cpmm_address ctxt block () () +end + +module Cache = struct + module S = struct + let cached_contracts = + RPC_service.get_service + ~description:"Return the list of cached contracts" + ~query:RPC_query.empty + ~output: + Data_encoding.(list @@ tup2 Alpha_context.Contract.encoding int31) + RPC_path.(custom_root / "context" / "cache" / "contracts" / "all") + + let contract_cache_size = + RPC_service.get_service + ~description:"Return the size of the contract cache" + ~query:RPC_query.empty + ~output:Data_encoding.int31 + RPC_path.(custom_root / "context" / "cache" / "contracts" / "size") + + let contract_cache_size_limit = + RPC_service.get_service + ~description:"Return the size limit of the contract cache" + ~query:RPC_query.empty + ~output:Data_encoding.int31 + RPC_path.( + custom_root / "context" / "cache" / "contracts" / "size_limit") + + let contract_rank = + RPC_service.post_service + ~description: + "Return the number of cached contracts older than the provided \ + contract" + ~query:RPC_query.empty + ~input:Alpha_context.Contract.encoding + ~output:Data_encoding.(option int31) + RPC_path.(custom_root / "context" / "cache" / "contract_rank") + end + + let register () = + let open Services_registration in + register0 ~chunked:true S.cached_contracts (fun ctxt () () -> + Script_cache.entries ctxt |> Lwt.return) ; + register0 ~chunked:false S.contract_cache_size (fun ctxt () () -> + Script_cache.size ctxt |> return) ; + register0 ~chunked:false S.contract_cache_size_limit (fun ctxt () () -> + Script_cache.size_limit ctxt |> return) ; + register0 ~chunked:false S.contract_rank (fun ctxt () contract -> + Script_cache.contract_rank ctxt contract |> return) + + let cached_contracts ctxt block = + RPC_context.make_call0 S.cached_contracts ctxt block () () + + let contract_cache_size ctxt block = + RPC_context.make_call0 S.contract_cache_size ctxt block () () + + let contract_cache_size_limit ctxt block = + RPC_context.make_call0 S.contract_cache_size_limit ctxt block () () + + let contract_rank ctxt block contract = + RPC_context.make_call0 S.contract_rank ctxt block () contract +end + +let register () = + Contract.register () ; + Constants.register () ; + Delegate.register () ; + Nonce.register () ; + Voting.register () ; + Sapling.register () ; + Liquidity_baking.register () ; + Cache.register () diff --git a/src/proto_011_PtHangzH/lib_protocol/alpha_services.mli b/src/proto_011_PtHangzH/lib_protocol/alpha_services.mli new file mode 100644 index 000000000000..b32cb71dfe0a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/alpha_services.mli @@ -0,0 +1,81 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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 declares Protocol RPC services. + + Protocol RPC services are read-only, and support querying the state of the + ledger (including information such as existing contracts, delegation, + voting, and so on), at a given block height. + + This is a mostly internal module used from [rpc_services] in [Main]. + *) + +open Alpha_context + +module Seed : sig + val get : 'a #RPC_context.simple -> 'a -> Seed.seed shell_tzresult Lwt.t +end + +module Nonce : sig + type info = Revealed of Nonce.t | Missing of Nonce_hash.t | Forgotten + + val get : + 'a #RPC_context.simple -> 'a -> Raw_level.t -> info shell_tzresult Lwt.t +end + +module Contract = Contract_services +module Constants = Constants_services +module Delegate = Delegate_services +module Voting = Voting_services +module Sapling = Sapling_services + +module Liquidity_baking : sig + val get_cpmm_address : + 'a #RPC_context.simple -> + 'a -> + Alpha_context.Contract.t shell_tzresult Lwt.t +end + +module Cache : sig + val cached_contracts : + 'a #RPC_context.simple -> + 'a -> + (Alpha_context.Contract.t * int) list shell_tzresult Lwt.t + + val contract_cache_size : + 'a #RPC_context.simple -> 'a -> int shell_tzresult Lwt.t + + val contract_cache_size_limit : + 'a #RPC_context.simple -> 'a -> int shell_tzresult Lwt.t + + val contract_rank : + 'a #RPC_context.simple -> + 'a -> + Alpha_context.Contract.t -> + int option shell_tzresult Lwt.t +end + +val register : unit -> unit diff --git a/src/proto_011_PtHangzH/lib_protocol/amendment.ml b/src/proto_011_PtHangzH/lib_protocol/amendment.ml new file mode 100644 index 000000000000..cbb18079fcae --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/amendment.ml @@ -0,0 +1,264 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +(** Returns the proposal submitted by the most delegates. + Returns None in case of a tie, if proposal quorum is below required + minimum or if there are no proposals. *) +let select_winning_proposal ctxt = + Vote.get_proposals ctxt >>=? fun proposals -> + let merge proposal vote winners = + match winners with + | None -> Some ([proposal], vote) + | Some (winners, winners_vote) as previous -> + if Compare.Int32.(vote = winners_vote) then + Some (proposal :: winners, winners_vote) + else if Compare.Int32.(vote > winners_vote) then Some ([proposal], vote) + else previous + in + match Protocol_hash.Map.fold merge proposals None with + | Some ([proposal], vote) -> + Vote.listing_size ctxt >>=? fun max_vote -> + let min_proposal_quorum = Constants.min_proposal_quorum ctxt in + let min_vote_to_pass = + Int32.div (Int32.mul min_proposal_quorum max_vote) 100_00l + in + if Compare.Int32.(vote >= min_vote_to_pass) then return_some proposal + else return_none + | _ -> return_none + +(* in case of a tie, let's do nothing. *) + +(** A proposal is approved if it has supermajority and the participation reaches + the current quorum. + Supermajority means the yays are more 8/10 of casted votes. + The participation is the ratio of all received votes, including passes, with + respect to the number of possible votes. + The participation EMA (exponential moving average) uses the last + participation EMA and the current participation./ + The expected quorum is calculated using the last participation EMA, capped + by the min/max quorum protocol constants. *) +let approval_and_participation_ema (ballots : Vote.ballots) ~maximum_vote + ~participation_ema ~expected_quorum = + (* Note overflows: considering a maximum of 8e8 tokens, with roll size as + small as 1e3, there is a maximum of 8e5 rolls and thus votes. + In 'participation' an Int64 is used because in the worst case 'all_votes is + 8e5 and after the multiplication is 8e9, making it potentially overflow a + signed Int32 which is 2e9. *) + let casted_votes = Int32.add ballots.yay ballots.nay in + let all_votes = Int32.add casted_votes ballots.pass in + let supermajority = Int32.div (Int32.mul 8l casted_votes) 10l in + let participation = + (* in centile of percentage *) + Int64.( + to_int32 (div (mul (of_int32 all_votes) 100_00L) (of_int32 maximum_vote))) + in + let approval = + Compare.Int32.( + participation >= expected_quorum && ballots.yay >= supermajority) + in + let new_participation_ema = + Int32.(div (add (mul 8l participation_ema) (mul 2l participation)) 10l) + in + (approval, new_participation_ema) + +let get_approval_and_update_participation_ema ctxt = + Vote.get_ballots ctxt >>=? fun ballots -> + Vote.listing_size ctxt >>=? fun maximum_vote -> + Vote.get_participation_ema ctxt >>=? fun participation_ema -> + Vote.get_current_quorum ctxt >>=? fun expected_quorum -> + Vote.clear_ballots ctxt >>= fun ctxt -> + let (approval, new_participation_ema) = + approval_and_participation_ema + ballots + ~maximum_vote + ~participation_ema + ~expected_quorum + in + Vote.set_participation_ema ctxt new_participation_ema >|=? fun ctxt -> + (ctxt, approval) + +(** Implements the state machine of the amendment procedure. Note that + [update_listings], that computes the vote weight of each delegate, is run at + the end of each voting period. This state-machine prepare the voting_period + for the next block. *) +let start_new_voting_period ctxt = + Voting_period.get_current_kind ctxt >>=? fun kind -> + (match kind with + | Proposal -> ( + select_winning_proposal ctxt >>=? fun proposal -> + Vote.clear_proposals ctxt >>= fun ctxt -> + match proposal with + | None -> Voting_period.reset ctxt + | Some proposal -> + Vote.init_current_proposal ctxt proposal >>=? Voting_period.succ) + | Exploration -> + get_approval_and_update_participation_ema ctxt + >>=? fun (ctxt, approved) -> + if approved then Voting_period.succ ctxt + else + Vote.clear_current_proposal ctxt >>=? fun ctxt -> + Voting_period.reset ctxt + | Cooldown -> Voting_period.succ ctxt + | Promotion -> + get_approval_and_update_participation_ema ctxt + >>=? fun (ctxt, approved) -> + if approved then Voting_period.succ ctxt + else Vote.clear_current_proposal ctxt >>=? Voting_period.reset + | Adoption -> + Vote.get_current_proposal ctxt >>=? fun proposal -> + activate ctxt proposal >>= fun ctxt -> + Vote.clear_current_proposal ctxt >>=? Voting_period.reset) + >>=? fun ctxt -> Vote.update_listings ctxt + +type error += + | (* `Branch *) + Invalid_proposal + | Unexpected_proposal + | Unauthorized_proposal + | Too_many_proposals + | Empty_proposal + | Unexpected_ballot + | Unauthorized_ballot + +let () = + let open Data_encoding in + (* Invalid proposal *) + register_error_kind + `Branch + ~id:"invalid_proposal" + ~title:"Invalid proposal" + ~description:"Ballot provided for a proposal that is not the current one." + ~pp:(fun ppf () -> Format.fprintf ppf "Invalid proposal") + empty + (function Invalid_proposal -> Some () | _ -> None) + (fun () -> Invalid_proposal) ; + (* Unexpected proposal *) + register_error_kind + `Branch + ~id:"unexpected_proposal" + ~title:"Unexpected proposal" + ~description:"Proposal recorded outside of a proposal period." + ~pp:(fun ppf () -> Format.fprintf ppf "Unexpected proposal") + empty + (function Unexpected_proposal -> Some () | _ -> None) + (fun () -> Unexpected_proposal) ; + (* Unauthorized proposal *) + register_error_kind + `Branch + ~id:"unauthorized_proposal" + ~title:"Unauthorized proposal" + ~description: + "The delegate provided for the proposal is not in the voting listings." + ~pp:(fun ppf () -> Format.fprintf ppf "Unauthorized proposal") + empty + (function Unauthorized_proposal -> Some () | _ -> None) + (fun () -> Unauthorized_proposal) ; + (* Unexpected ballot *) + register_error_kind + `Branch + ~id:"unexpected_ballot" + ~title:"Unexpected ballot" + ~description:"Ballot recorded outside of a voting period." + ~pp:(fun ppf () -> Format.fprintf ppf "Unexpected ballot") + empty + (function Unexpected_ballot -> Some () | _ -> None) + (fun () -> Unexpected_ballot) ; + (* Unauthorized ballot *) + register_error_kind + `Branch + ~id:"unauthorized_ballot" + ~title:"Unauthorized ballot" + ~description: + "The delegate provided for the ballot is not in the voting listings." + ~pp:(fun ppf () -> Format.fprintf ppf "Unauthorized ballot") + empty + (function Unauthorized_ballot -> Some () | _ -> None) + (fun () -> Unauthorized_ballot) ; + (* Too many proposals *) + register_error_kind + `Branch + ~id:"too_many_proposals" + ~title:"Too many proposals" + ~description:"The delegate reached the maximum number of allowed proposals." + ~pp:(fun ppf () -> Format.fprintf ppf "Too many proposals") + empty + (function Too_many_proposals -> Some () | _ -> None) + (fun () -> Too_many_proposals) ; + (* Empty proposal *) + register_error_kind + `Branch + ~id:"empty_proposal" + ~title:"Empty proposal" + ~description:"Proposal lists cannot be empty." + ~pp:(fun ppf () -> Format.fprintf ppf "Empty proposal") + empty + (function Empty_proposal -> Some () | _ -> None) + (fun () -> Empty_proposal) + +let record_proposals ctxt delegate proposals = + (match proposals with [] -> error Empty_proposal | _ :: _ -> ok_unit) + >>?= fun () -> + Voting_period.get_current_kind ctxt >>=? function + | Proposal -> + Vote.in_listings ctxt delegate >>= fun in_listings -> + if in_listings then ( + Vote.recorded_proposal_count_for_delegate ctxt delegate + >>=? fun count -> + assert (Compare.Int.(Constants.max_proposals_per_delegate >= count)) ; + error_when + Compare.Int.( + List.compare_length_with + proposals + (Constants.max_proposals_per_delegate - count) + > 0) + Too_many_proposals + >>?= fun () -> + List.fold_left_es + (fun ctxt proposal -> Vote.record_proposal ctxt proposal delegate) + ctxt + proposals) + else fail Unauthorized_proposal + | Exploration | Cooldown | Promotion | Adoption -> fail Unexpected_proposal + +let record_ballot ctxt delegate proposal ballot = + Voting_period.get_current_kind ctxt >>=? function + | Exploration | Promotion -> + Vote.get_current_proposal ctxt >>=? fun current_proposal -> + error_unless + (Protocol_hash.equal proposal current_proposal) + Invalid_proposal + >>?= fun () -> + Vote.has_recorded_ballot ctxt delegate >>= fun has_ballot -> + error_when has_ballot Unauthorized_ballot >>?= fun () -> + Vote.in_listings ctxt delegate >>= fun in_listings -> + if in_listings then Vote.record_ballot ctxt delegate ballot + else fail Unauthorized_ballot + | Cooldown | Proposal | Adoption -> fail Unexpected_ballot + +let may_start_new_voting_period ctxt = + Voting_period.is_last_block ctxt >>=? fun is_last -> + if is_last then start_new_voting_period ctxt else return ctxt diff --git a/src/proto_011_PtHangzH/lib_protocol/amendment.mli b/src/proto_011_PtHangzH/lib_protocol/amendment.mli new file mode 100644 index 000000000000..200019bd03ea --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/amendment.mli @@ -0,0 +1,81 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Only delegates with at least one roll take part in the amendment + procedure. It works as follows: + + - Proposal period: delegates can submit protocol amendment + proposals using the proposal operation. At the end of a proposal + period, the proposal with most supporters is selected and we move + to an exploration period. If there are no proposals, or a tie + between proposals, a new proposal period starts. + + - Exploration period: delegates can cast votes to test or not the + winning proposal using the ballot operation. At the end of an + exploration period if participation reaches the quorum and the + proposal has a supermajority in favor, we proceed to a cooldown + period. Otherwise we go back to a proposal period. In any case, if + there is enough participation the quorum is updated. + + - Cooldown period: Nothing happens, this period is only a time gap + between exploration and promotion periods. At the end of a cooldown + period we move to a promotion period. + + - Promotion period: delegates can cast votes to promote or not the + proposal using the ballot operation. At the end of a promotion + period if participation reaches the quorum and the proposal has a + supermajority in favor, we move to an adoption period. Otherwise we + go back to a proposal period. In any case, if there is enough + participation the quorum is updated. + + - Adoption period: At the end of an adoption period, the proposal + is activated as the new protocol. *) + +open Alpha_context + +(** If at the end of a voting period, moves to the next one following + the state machine of the amendment procedure. *) +val may_start_new_voting_period : context -> context tzresult Lwt.t + +type error += + | Unexpected_proposal + | Unauthorized_proposal + | Too_many_proposals + | Empty_proposal + +(** Records a list of proposals for a delegate. + @raise Unexpected_proposal if [ctxt] is not in a proposal period. + @raise Unauthorized_proposal if [delegate] is not in the listing. *) +val record_proposals : + context -> public_key_hash -> Protocol_hash.t list -> context tzresult Lwt.t + +type error += Invalid_proposal | Unexpected_ballot | Unauthorized_ballot + +val record_ballot : + context -> + public_key_hash -> + Protocol_hash.t -> + Vote.ballot -> + context tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/apply.ml b/src/proto_011_PtHangzH/lib_protocol/apply.ml new file mode 100644 index 000000000000..ff7568a14b80 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/apply.ml @@ -0,0 +1,1720 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Tezos Protocol Implementation - Main Entry Points *) + +open Alpha_context + +type error += Wrong_voting_period of int32 * int32 + +(* `Temporary *) + +type error += Wrong_endorsement_predecessor of Block_hash.t * Block_hash.t + +(* `Temporary *) + +type error += Duplicate_endorsement of Signature.Public_key_hash.t + +(* `Branch *) + +type error += Invalid_endorsement_level + +type error += Invalid_endorsement_wrapper + +type error += Invalid_commitment of {expected : bool} + +type error += Internal_operation_replay of packed_internal_operation + +type error += Invalid_double_endorsement_evidence (* `Permanent *) + +type error += + | Inconsistent_double_endorsement_evidence of { + delegate1 : Signature.Public_key_hash.t; + delegate2 : Signature.Public_key_hash.t; + } + +(* `Permanent *) + +type error += Unwrapped_endorsement (* `Permanent *) + +type error += Unrequired_double_endorsement_evidence (* `Branch*) + +type error += + | Too_early_double_endorsement_evidence of { + level : Raw_level.t; + current : Raw_level.t; + } + +(* `Temporary *) + +type error += + | Outdated_double_endorsement_evidence of { + level : Raw_level.t; + last : Raw_level.t; + } + +(* `Permanent *) + +type error += + | Invalid_double_baking_evidence of { + hash1 : Block_hash.t; + level1 : Int32.t; + hash2 : Block_hash.t; + level2 : Int32.t; + } + +(* `Permanent *) + +type error += + | Inconsistent_double_baking_evidence of { + delegate1 : Signature.Public_key_hash.t; + delegate2 : Signature.Public_key_hash.t; + } + +(* `Permanent *) + +type error += Unrequired_double_baking_evidence (* `Branch*) + +type error += + | Too_early_double_baking_evidence of { + level : Raw_level.t; + current : Raw_level.t; + } + +(* `Temporary *) + +type error += + | Outdated_double_baking_evidence of {level : Raw_level.t; last : Raw_level.t} + +(* `Permanent *) + +type error += Invalid_activation of {pkh : Ed25519.Public_key_hash.t} + +type error += Multiple_revelation + +type error += Gas_quota_exceeded_init_deserialize (* Permanent *) + +type error += (* `Permanent *) Inconsistent_sources + +type error += (* `Permanent *) Failing_noop_error + +let () = + register_error_kind + `Temporary + ~id:"operation.wrong_endorsement_predecessor" + ~title:"Wrong endorsement predecessor" + ~description: + "Trying to include an endorsement in a block that is not the successor \ + of the endorsed one" + ~pp:(fun ppf (e, p) -> + Format.fprintf + ppf + "Wrong predecessor %a, expected %a" + Block_hash.pp + p + Block_hash.pp + e) + Data_encoding.( + obj2 + (req "expected" Block_hash.encoding) + (req "provided" Block_hash.encoding)) + (function Wrong_endorsement_predecessor (e, p) -> Some (e, p) | _ -> None) + (fun (e, p) -> Wrong_endorsement_predecessor (e, p)) ; + register_error_kind + `Temporary + ~id:"operation.wrong_voting_period" + ~title:"Wrong voting period" + ~description: + "Trying to include a proposal or ballot meant for another voting period" + ~pp:(fun ppf (e, p) -> + Format.fprintf ppf "Wrong voting period %ld, current is %ld" p e) + Data_encoding.( + obj2 (req "current_index" int32) (req "provided_index" int32)) + (function Wrong_voting_period (e, p) -> Some (e, p) | _ -> None) + (fun (e, p) -> Wrong_voting_period (e, p)) ; + register_error_kind + `Branch + ~id:"operation.duplicate_endorsement" + ~title:"Duplicate endorsement" + ~description:"Two endorsements received from same delegate" + ~pp:(fun ppf k -> + Format.fprintf + ppf + "Duplicate endorsement from delegate %a (possible replay attack)." + Signature.Public_key_hash.pp_short + k) + Data_encoding.(obj1 (req "delegate" Signature.Public_key_hash.encoding)) + (function Duplicate_endorsement k -> Some k | _ -> None) + (fun k -> Duplicate_endorsement k) ; + register_error_kind + `Temporary + ~id:"operation.invalid_endorsement_level" + ~title:"Unexpected level in endorsement" + ~description: + "The level of an endorsement is inconsistent with the provided block \ + hash." + ~pp:(fun ppf () -> Format.fprintf ppf "Unexpected level in endorsement.") + Data_encoding.unit + (function Invalid_endorsement_level -> Some () | _ -> None) + (fun () -> Invalid_endorsement_level) ; + register_error_kind + `Temporary + ~id:"operation.invalid_endorsement_wrapper" + ~title:"Unexpected wrapper in endorsement" + ~description: + "The wrapper of an endorsement is inconsistent with the endorsement it \ + wraps." + ~pp:(fun ppf () -> + Format.fprintf + ppf + "The endorsement wrapper announces a block hash different from its \ + wrapped endorsement, or bears a signature.") + Data_encoding.unit + (function Invalid_endorsement_wrapper -> Some () | _ -> None) + (fun () -> Invalid_endorsement_wrapper) ; + register_error_kind + `Temporary + ~id:"operation.unwrapped_endorsement" + ~title:"Unwrapped endorsement" + ~description: + "A legacy endorsement has been applied without its required slot-bearing \ + wrapper." + ~pp:(fun ppf () -> + Format.fprintf + ppf + "A legacy endorsement has been applied without its required \ + slot-bearing wrapper operation.") + Data_encoding.unit + (function Unwrapped_endorsement -> Some () | _ -> None) + (fun () -> Unwrapped_endorsement) ; + register_error_kind + `Permanent + ~id:"block.invalid_commitment" + ~title:"Invalid commitment in block header" + ~description:"The block header has invalid commitment." + ~pp:(fun ppf expected -> + if expected then + Format.fprintf ppf "Missing seed's nonce commitment in block header." + else + Format.fprintf ppf "Unexpected seed's nonce commitment in block header.") + Data_encoding.(obj1 (req "expected" bool)) + (function Invalid_commitment {expected} -> Some expected | _ -> None) + (fun expected -> Invalid_commitment {expected}) ; + register_error_kind + `Permanent + ~id:"internal_operation_replay" + ~title:"Internal operation replay" + ~description:"An internal operation was emitted twice by a script" + ~pp:(fun ppf (Internal_operation {nonce; _}) -> + Format.fprintf + ppf + "Internal operation %d was emitted twice by a script" + nonce) + Operation.internal_operation_encoding + (function Internal_operation_replay op -> Some op | _ -> None) + (fun op -> Internal_operation_replay op) ; + register_error_kind + `Permanent + ~id:"block.invalid_double_endorsement_evidence" + ~title:"Invalid double endorsement evidence" + ~description:"A double-endorsement evidence is malformed" + ~pp:(fun ppf () -> + Format.fprintf ppf "Malformed double-endorsement evidence") + Data_encoding.empty + (function Invalid_double_endorsement_evidence -> Some () | _ -> None) + (fun () -> Invalid_double_endorsement_evidence) ; + register_error_kind + `Permanent + ~id:"block.inconsistent_double_endorsement_evidence" + ~title:"Inconsistent double endorsement evidence" + ~description: + "A double-endorsement evidence is inconsistent (two distinct delegates)" + ~pp:(fun ppf (delegate1, delegate2) -> + Format.fprintf + ppf + "Inconsistent double-endorsement evidence (distinct delegate: %a and \ + %a)" + Signature.Public_key_hash.pp_short + delegate1 + Signature.Public_key_hash.pp_short + delegate2) + Data_encoding.( + obj2 + (req "delegate1" Signature.Public_key_hash.encoding) + (req "delegate2" Signature.Public_key_hash.encoding)) + (function + | Inconsistent_double_endorsement_evidence {delegate1; delegate2} -> + Some (delegate1, delegate2) + | _ -> None) + (fun (delegate1, delegate2) -> + Inconsistent_double_endorsement_evidence {delegate1; delegate2}) ; + register_error_kind + `Branch + ~id:"block.unrequired_double_endorsement_evidence" + ~title:"Unrequired double endorsement evidence" + ~description:"A double-endorsement evidence is unrequired" + ~pp:(fun ppf () -> + Format.fprintf + ppf + "A valid double-endorsement operation cannot be applied: the \ + associated delegate has previously been denounced in this cycle.") + Data_encoding.empty + (function Unrequired_double_endorsement_evidence -> Some () | _ -> None) + (fun () -> Unrequired_double_endorsement_evidence) ; + register_error_kind + `Temporary + ~id:"block.too_early_double_endorsement_evidence" + ~title:"Too early double endorsement evidence" + ~description:"A double-endorsement evidence is in the future" + ~pp:(fun ppf (level, current) -> + Format.fprintf + ppf + "A double-endorsement evidence is in the future (current level: %a, \ + endorsement level: %a)" + Raw_level.pp + current + Raw_level.pp + level) + Data_encoding.( + obj2 (req "level" Raw_level.encoding) (req "current" Raw_level.encoding)) + (function + | Too_early_double_endorsement_evidence {level; current} -> + Some (level, current) + | _ -> None) + (fun (level, current) -> + Too_early_double_endorsement_evidence {level; current}) ; + register_error_kind + `Permanent + ~id:"block.outdated_double_endorsement_evidence" + ~title:"Outdated double endorsement evidence" + ~description:"A double-endorsement evidence is outdated." + ~pp:(fun ppf (level, last) -> + Format.fprintf + ppf + "A double-endorsement evidence is outdated (last acceptable level: \ + %a, endorsement level: %a)" + Raw_level.pp + last + Raw_level.pp + level) + Data_encoding.( + obj2 (req "level" Raw_level.encoding) (req "last" Raw_level.encoding)) + (function + | Outdated_double_endorsement_evidence {level; last} -> Some (level, last) + | _ -> None) + (fun (level, last) -> Outdated_double_endorsement_evidence {level; last}) ; + register_error_kind + `Permanent + ~id:"block.invalid_double_baking_evidence" + ~title:"Invalid double baking evidence" + ~description: + "A double-baking evidence is inconsistent (two distinct level)" + ~pp:(fun ppf (hash1, level1, hash2, level2) -> + Format.fprintf + ppf + "Invalid double-baking evidence (hash: %a and %a, levels: %ld and %ld)" + Block_hash.pp + hash1 + Block_hash.pp + hash2 + level1 + level2) + Data_encoding.( + obj4 + (req "hash1" Block_hash.encoding) + (req "level1" int32) + (req "hash2" Block_hash.encoding) + (req "level2" int32)) + (function + | Invalid_double_baking_evidence {hash1; level1; hash2; level2} -> + Some (hash1, level1, hash2, level2) + | _ -> None) + (fun (hash1, level1, hash2, level2) -> + Invalid_double_baking_evidence {hash1; level1; hash2; level2}) ; + register_error_kind + `Permanent + ~id:"block.inconsistent_double_baking_evidence" + ~title:"Inconsistent double baking evidence" + ~description: + "A double-baking evidence is inconsistent (two distinct delegates)" + ~pp:(fun ppf (delegate1, delegate2) -> + Format.fprintf + ppf + "Inconsistent double-baking evidence (distinct delegate: %a and %a)" + Signature.Public_key_hash.pp_short + delegate1 + Signature.Public_key_hash.pp_short + delegate2) + Data_encoding.( + obj2 + (req "delegate1" Signature.Public_key_hash.encoding) + (req "delegate2" Signature.Public_key_hash.encoding)) + (function + | Inconsistent_double_baking_evidence {delegate1; delegate2} -> + Some (delegate1, delegate2) + | _ -> None) + (fun (delegate1, delegate2) -> + Inconsistent_double_baking_evidence {delegate1; delegate2}) ; + register_error_kind + `Branch + ~id:"block.unrequired_double_baking_evidence" + ~title:"Unrequired double baking evidence" + ~description:"A double-baking evidence is unrequired" + ~pp:(fun ppf () -> + Format.fprintf + ppf + "A valid double-baking operation cannot be applied: the associated \ + delegate has previously been denounced in this cycle.") + Data_encoding.empty + (function Unrequired_double_baking_evidence -> Some () | _ -> None) + (fun () -> Unrequired_double_baking_evidence) ; + register_error_kind + `Temporary + ~id:"block.too_early_double_baking_evidence" + ~title:"Too early double baking evidence" + ~description:"A double-baking evidence is in the future" + ~pp:(fun ppf (level, current) -> + Format.fprintf + ppf + "A double-baking evidence is in the future (current level: %a, baking \ + level: %a)" + Raw_level.pp + current + Raw_level.pp + level) + Data_encoding.( + obj2 (req "level" Raw_level.encoding) (req "current" Raw_level.encoding)) + (function + | Too_early_double_baking_evidence {level; current} -> + Some (level, current) + | _ -> None) + (fun (level, current) -> Too_early_double_baking_evidence {level; current}) ; + register_error_kind + `Permanent + ~id:"block.outdated_double_baking_evidence" + ~title:"Outdated double baking evidence" + ~description:"A double-baking evidence is outdated." + ~pp:(fun ppf (level, last) -> + Format.fprintf + ppf + "A double-baking evidence is outdated (last acceptable level: %a, \ + baking level: %a)" + Raw_level.pp + last + Raw_level.pp + level) + Data_encoding.( + obj2 (req "level" Raw_level.encoding) (req "last" Raw_level.encoding)) + (function + | Outdated_double_baking_evidence {level; last} -> Some (level, last) + | _ -> None) + (fun (level, last) -> Outdated_double_baking_evidence {level; last}) ; + register_error_kind + `Permanent + ~id:"operation.invalid_activation" + ~title:"Invalid activation" + ~description: + "The given key and secret do not correspond to any existing preallocated \ + contract" + ~pp:(fun ppf pkh -> + Format.fprintf + ppf + "Invalid activation. The public key %a does not match any commitment." + Ed25519.Public_key_hash.pp + pkh) + Data_encoding.(obj1 (req "pkh" Ed25519.Public_key_hash.encoding)) + (function Invalid_activation {pkh} -> Some pkh | _ -> None) + (fun pkh -> Invalid_activation {pkh}) ; + register_error_kind + `Permanent + ~id:"block.multiple_revelation" + ~title:"Multiple revelations were included in a manager operation" + ~description: + "A manager operation should not contain more than one revelation" + ~pp:(fun ppf () -> + Format.fprintf + ppf + "Multiple revelations were included in a manager operation") + Data_encoding.empty + (function Multiple_revelation -> Some () | _ -> None) + (fun () -> Multiple_revelation) ; + register_error_kind + `Permanent + ~id:"gas_exhausted.init_deserialize" + ~title:"Not enough gas for initial deserialization of script expressions" + ~description: + "Gas limit was not high enough to deserialize the transaction parameters \ + or origination script code or initial storage, making the operation \ + impossible to parse within the provided gas bounds." + Data_encoding.empty + (function Gas_quota_exceeded_init_deserialize -> Some () | _ -> None) + (fun () -> Gas_quota_exceeded_init_deserialize) ; + register_error_kind + `Permanent + ~id:"operation.inconsistent_sources" + ~title:"Inconsistent sources in operation pack" + ~description: + "The operation pack includes operations from different sources." + ~pp:(fun ppf () -> + Format.pp_print_string + ppf + "The operation pack includes operations from different sources.") + Data_encoding.empty + (function Inconsistent_sources -> Some () | _ -> None) + (fun () -> Inconsistent_sources) ; + register_error_kind + `Permanent + ~id:"operation.failing_noop" + ~title:"Failing_noop operation are not executed by the protocol" + ~description: + "The failing_noop operation is an operation that is not and never will \ + be executed by the protocol." + ~pp:(fun ppf () -> + Format.fprintf + ppf + "The failing_noop operation cannot be executed by the protocol") + Data_encoding.empty + (function Failing_noop_error -> Some () | _ -> None) + (fun () -> Failing_noop_error) + +open Apply_results + +let cache_layout = Constants_repr.cache_layout + +(** + + Retrieving the source code of a contract from its address is costly + because it requires I/Os. For this reason, we put the corresponding + Micheline expression in the cache. + + Elaborating a Micheline node into the well-typed script abstract + syntax tree is also a costly operation. The result of this operation + is cached as well. + +*) + +let apply_manager_operation_content : + type kind. + Alpha_context.t -> + Script_ir_translator.unparsing_mode -> + payer:Contract.t -> + source:Contract.t -> + chain_id:Chain_id.t -> + internal:bool -> + kind manager_operation -> + (context + * kind successful_manager_operation_result + * packed_internal_operation list) + tzresult + Lwt.t = + fun ctxt mode ~payer ~source ~chain_id ~internal operation -> + let before_operation = + (* This context is not used for backtracking. Only to compute + gas consumption and originations for the operation result. *) + ctxt + in + Contract.must_exist ctxt source >>=? fun () -> + Gas.consume ctxt Michelson_v1_gas.Cost_of.manager_operation >>?= fun ctxt -> + match operation with + | Reveal _ -> + return + (* No-op: action already performed by `precheck_manager_contents`. *) + ( ctxt, + (Reveal_result + {consumed_gas = Gas.consumed ~since:before_operation ~until:ctxt} + : kind successful_manager_operation_result), + [] ) + | Transaction {amount; parameters; destination; entrypoint} -> ( + Script.force_decode_in_context ctxt parameters + (* [note]: for toplevel ops, cost is nil since the lazy value has + already been forced at precheck. Otherwise fail early if not + enough gas for complete deserialization cost *) + >>?= + fun (parameter, ctxt) -> + Contract.spend ctxt source amount >>=? fun ctxt -> + (match Contract.is_implicit destination with + | None -> return (ctxt, [], false) + | Some _ -> ( + Contract.allocated ctxt destination >>=? function + | true -> return (ctxt, [], false) + | false -> + Lwt.return + ( Fees.origination_burn ctxt >|? fun (ctxt, origination_burn) -> + ( ctxt, + [ + Receipt. + ( Contract payer, + Debited origination_burn, + Block_application ); + ], + true ) ))) + >>=? fun (ctxt, maybe_burn_balance_update, allocated_destination_contract) + -> + Contract.credit ctxt destination amount >>=? fun ctxt -> + Script_cache.find ctxt destination >>=? fun (ctxt, cache_key, script) -> + match script with + | None -> + Lwt.return + ( ( (match entrypoint with + | "default" -> ok_unit + | entrypoint -> + error (Script_tc_errors.No_such_entrypoint entrypoint)) + >>? fun () -> + match Micheline.root parameter with + | Prim (_, D_Unit, [], _) -> + (* Allow [Unit] parameter to non-scripted contracts. *) + ok ctxt + | _ -> + error + (Script_interpreter.Bad_contract_parameter destination) ) + >|? fun ctxt -> + let result = + Transaction_result + { + storage = None; + lazy_storage_diff = None; + balance_updates = + Receipt.( + cleanup_balance_updates + [ + (Contract source, Debited amount, Block_application); + ( Contract destination, + Credited amount, + Block_application ); + ] + @ maybe_burn_balance_update); + originated_contracts = []; + consumed_gas = + Gas.consumed ~since:before_operation ~until:ctxt; + storage_size = Z.zero; + paid_storage_size_diff = Z.zero; + allocated_destination_contract; + } + in + (ctxt, result, []) ) + | Some (script, script_ir) -> + let step_constants = + let open Script_interpreter in + {source; payer; self = destination; amount; chain_id} + in + Script_interpreter.execute + ctxt + ~cached_script:(Some script_ir) + mode + step_constants + ~script + ~parameter + ~entrypoint + ~internal + >>=? fun ( {ctxt; storage; lazy_storage_diff; operations}, + (updated_cached_script, updated_size) ) -> + Contract.update_script_storage + ctxt + destination + storage + lazy_storage_diff + >>=? fun ctxt -> + Fees.record_paid_storage_space ctxt destination + >>=? fun (ctxt, new_size, paid_storage_size_diff, fees) -> + Contract.originated_from_current_nonce + ~since:before_operation + ~until:ctxt + >>=? fun originated_contracts -> + Lwt.return + ( Script_cache.update + ctxt + cache_key + ( {script with storage = Script.lazy_expr storage}, + updated_cached_script ) + updated_size + >|? fun ctxt -> + let result = + Transaction_result + { + storage = Some storage; + lazy_storage_diff; + balance_updates = + Receipt.cleanup_balance_updates + [ + (Contract payer, Debited fees, Block_application); + (Contract source, Debited amount, Block_application); + ( Contract destination, + Credited amount, + Block_application ); + ]; + originated_contracts; + consumed_gas = + Gas.consumed ~since:before_operation ~until:ctxt; + storage_size = new_size; + paid_storage_size_diff; + allocated_destination_contract; + } + in + (ctxt, result, operations) )) + | Origination {delegate; script; preorigination; credit} -> + Script.force_decode_in_context ctxt script.storage + (* see [note] *) + >>?= fun (_unparsed_storage, ctxt) -> + Script.force_decode_in_context ctxt script.code + (* see [note] *) + >>?= fun (unparsed_code, ctxt) -> + Script_ir_translator.parse_script + ctxt + ~legacy:false + ~allow_forged_in_storage:internal + script + >>=? fun (Ex_script parsed_script, ctxt) -> + let views_result = + Script_ir_translator.typecheck_views + ctxt + ~legacy:false + parsed_script.storage_type + parsed_script.views + in + trace + (Script_tc_errors.Ill_typed_contract (unparsed_code, [])) + views_result + >>=? fun ctxt -> + Script_ir_translator.collect_lazy_storage + ctxt + parsed_script.storage_type + parsed_script.storage + >>?= fun (to_duplicate, ctxt) -> + let to_update = Script_ir_translator.no_lazy_storage_id in + Script_ir_translator.extract_lazy_storage_diff + ctxt + Optimized + parsed_script.storage_type + parsed_script.storage + ~to_duplicate + ~to_update + ~temporary:false + >>=? fun (storage, lazy_storage_diff, ctxt) -> + Script_ir_translator.unparse_data + ctxt + Optimized + parsed_script.storage_type + storage + >>=? fun (storage, ctxt) -> + let storage = Script.lazy_expr (Micheline.strip_locations storage) in + let script = {script with storage} in + Contract.spend ctxt source credit >>=? fun ctxt -> + (match preorigination with + | Some contract -> + assert internal ; + (* The preorigination field is only used to early return + the address of an originated contract in Michelson. + It cannot come from the outside. *) + ok (ctxt, contract) + | None -> Contract.fresh_contract_from_current_nonce ctxt) + >>?= fun (ctxt, contract) -> + Contract.originate + ctxt + contract + ~delegate + ~balance:credit + ~script:(script, lazy_storage_diff) + >>=? fun ctxt -> + Fees.origination_burn ctxt >>?= fun (ctxt, origination_burn) -> + Fees.record_paid_storage_space ctxt contract + >|=? fun (ctxt, size, paid_storage_size_diff, fees) -> + let result = + Origination_result + { + lazy_storage_diff; + balance_updates = + Receipt.cleanup_balance_updates + [ + (Contract payer, Debited fees, Block_application); + (Contract payer, Debited origination_burn, Block_application); + (Contract source, Debited credit, Block_application); + (Contract contract, Credited credit, Block_application); + ]; + originated_contracts = [contract]; + consumed_gas = Gas.consumed ~since:before_operation ~until:ctxt; + storage_size = size; + paid_storage_size_diff; + } + in + (ctxt, result, []) + | Delegation delegate -> + Delegate.set ctxt source delegate >|=? fun ctxt -> + ( ctxt, + Delegation_result + {consumed_gas = Gas.consumed ~since:before_operation ~until:ctxt}, + [] ) + | Register_global_constant {value} -> + (* Decode the value and consume gas appropriately *) + Script.force_decode_in_context ctxt value >>?= fun (expr, ctxt) -> + (* Set the key to the value in storage. *) + Global_constants_storage.register ctxt expr + >>=? fun (ctxt, address, size) -> + (* The burn and the reporting of the burn are calculated differently. + + [Fees.record_global_constant_storage_space] does the actual burn + based on the size of the constant registered, and this causes a + change in account balance. + + On the other hand, the receipt is calculated + with the help of [Fees.cost_of_bytes], and is included in block metadata + and the client output. The receipt is also used during simulation, + letting the client automatically set an appropriate storage limit. *) + let (ctxt, paid_size) = + Fees.record_global_constant_storage_space ctxt size + in + Fees.cost_of_bytes ctxt paid_size >>?= fun fees -> + let result = + Register_global_constant_result + { + balance_updates = + Receipt.cleanup_balance_updates + [(Contract payer, Debited fees, Block_application)]; + consumed_gas = Gas.consumed ~since:before_operation ~until:ctxt; + size_of_constant = paid_size; + global_address = address; + } + in + return (ctxt, result, []) + +type success_or_failure = Success of context | Failure + +let apply_internal_manager_operations ctxt mode ~payer ~chain_id ops = + let[@coq_struct "ctxt"] rec apply ctxt applied worklist = + match worklist with + | [] -> Lwt.return (Success ctxt, List.rev applied) + | Internal_operation ({source; operation; nonce} as op) :: rest -> ( + (if internal_nonce_already_recorded ctxt nonce then + fail (Internal_operation_replay (Internal_operation op)) + else + let ctxt = record_internal_nonce ctxt nonce in + apply_manager_operation_content + ctxt + mode + ~source + ~payer + ~chain_id + ~internal:true + operation) + >>= function + | Error errors -> + let result = + Internal_operation_result + (op, Failed (manager_kind op.operation, errors)) + in + let skipped = + List.rev_map + (fun (Internal_operation op) -> + Internal_operation_result + (op, Skipped (manager_kind op.operation))) + rest + in + Lwt.return (Failure, List.rev (skipped @ result :: applied)) + | Ok (ctxt, result, emitted) -> + apply + ctxt + (Internal_operation_result (op, Applied result) :: applied) + (emitted @ rest)) + in + apply ctxt [] ops + +let precheck_manager_contents (type kind) ctxt (op : kind Kind.manager contents) + : context tzresult Lwt.t = + let[@coq_match_with_default] (Manager_operation + { + source; + fee; + counter; + operation; + gas_limit; + storage_limit; + }) = + op + in + Gas.consume_limit_in_block ctxt gas_limit >>?= fun ctxt -> + let ctxt = Gas.set_limit ctxt gas_limit in + Fees.check_storage_limit ctxt ~storage_limit >>?= fun () -> + Contract.must_be_allocated ctxt (Contract.implicit_contract source) + >>=? fun () -> + Contract.check_counter_increment ctxt source counter >>=? fun () -> + (match operation with + | Reveal pk -> Contract.reveal_manager_key ctxt source pk + | Transaction {parameters; _} -> + Lwt.return + @@ record_trace Gas_quota_exceeded_init_deserialize + @@ (* Fail early if not enough gas for complete deserialization cost *) + ( Script.force_decode_in_context ctxt parameters >|? fun (_arg, ctxt) -> + ctxt ) + | Origination {script; _} -> + Lwt.return + @@ record_trace Gas_quota_exceeded_init_deserialize + @@ (* Fail early if not enough gas for complete deserialization cost *) + ( Script.force_decode_in_context ctxt script.code >>? fun (_code, ctxt) -> + Script.force_decode_in_context ctxt script.storage + >|? fun (_storage, ctxt) -> ctxt ) + | Register_global_constant {value} -> + Lwt.return + @@ record_trace Gas_quota_exceeded_init_deserialize + @@ (Script.force_decode_in_context ctxt value >|? fun (_, ctxt) -> ctxt) + | _ -> return ctxt) + >>=? fun ctxt -> + Contract.increment_counter ctxt source >>=? fun ctxt -> + Contract.spend ctxt (Contract.implicit_contract source) fee >>=? fun ctxt -> + Lwt.return (add_fees ctxt fee) + +let apply_manager_contents (type kind) ctxt mode chain_id + (op : kind Kind.manager contents) : + (success_or_failure + * kind manager_operation_result + * packed_internal_operation_result list) + Lwt.t = + let[@coq_match_with_default] (Manager_operation + { + source; + operation; + gas_limit; + storage_limit; + _; + }) = + op + in + (* We do not expose the internal scaling to the users. Instead, we multiply + the specified gas limit by the internal scaling. *) + let ctxt = Gas.set_limit ctxt gas_limit in + let ctxt = Fees.start_counting_storage_fees ctxt in + let source = Contract.implicit_contract source in + apply_manager_operation_content + ctxt + mode + ~source + ~payer:source + ~internal:false + ~chain_id + operation + >>= function + | Ok (ctxt, operation_results, internal_operations) -> ( + apply_internal_manager_operations + ctxt + mode + ~payer:source + ~chain_id + internal_operations + >>= function + | (Success ctxt, internal_operations_results) -> ( + Fees.burn_storage_fees ctxt ~storage_limit ~payer:source >|= function + | Ok ctxt -> + ( Success ctxt, + Applied operation_results, + internal_operations_results ) + | Error errors -> + ( Failure, + Backtracked (operation_results, Some errors), + internal_operations_results )) + | (Failure, internal_operations_results) -> + Lwt.return + (Failure, Applied operation_results, internal_operations_results)) + | Error errors -> + Lwt.return (Failure, Failed (manager_kind operation, errors), []) + +let skipped_operation_result : + type kind. kind manager_operation -> kind manager_operation_result = + function + | operation -> ( + match operation with + | Reveal _ -> + Applied + (Reveal_result {consumed_gas = Gas.Arith.zero} + : kind successful_manager_operation_result) + | _ -> Skipped (manager_kind operation)) + +let rec mark_skipped : + type kind. + baker:Signature.Public_key_hash.t -> + Level.t -> + kind Kind.manager contents_list -> + kind Kind.manager contents_result_list = + fun ~baker level -> function[@coq_match_with_default] + | Single (Manager_operation {source; fee; operation; _}) -> + let source = Contract.implicit_contract source in + Single_result + (Manager_operation_result + { + balance_updates = + Receipt.cleanup_balance_updates + [ + (Contract source, Debited fee, Block_application); + (Fees (baker, level.cycle), Credited fee, Block_application); + ]; + operation_result = skipped_operation_result operation; + internal_operation_results = []; + }) + | Cons (Manager_operation {source; fee; operation; _}, rest) -> + let source = Contract.implicit_contract source in + Cons_result + ( Manager_operation_result + { + balance_updates = + Receipt.cleanup_balance_updates + [ + (Contract source, Debited fee, Block_application); + (Fees (baker, level.cycle), Credited fee, Block_application); + ]; + operation_result = skipped_operation_result operation; + internal_operation_results = []; + }, + mark_skipped ~baker level rest ) + +let rec precheck_manager_contents_list : + type kind. + Alpha_context.t -> kind Kind.manager contents_list -> context tzresult Lwt.t + = + fun ctxt contents_list -> + match[@coq_match_with_default] contents_list with + | Single (Manager_operation _ as op) -> precheck_manager_contents ctxt op + | Cons ((Manager_operation _ as op), rest) -> + precheck_manager_contents ctxt op >>=? fun ctxt -> + precheck_manager_contents_list ctxt rest + +let check_manager_signature ctxt chain_id (op : _ Kind.manager contents_list) + raw_operation = + (* Currently, the [op] only contains one signature, so + all operations are required to be from the same manager. This may + change in the future, allowing several managers to group-sign a + sequence of transactions. *) + let check_same_manager (source, source_key) manager = + match manager with + | None -> + (* Consistency already checked by + [reveal_manager_key] in [precheck_manager_contents]. *) + ok (source, source_key) + | Some (manager, manager_key) -> + if Signature.Public_key_hash.equal source manager then + ok (source, Option.either manager_key source_key) + else error Inconsistent_sources + in + let rec find_source : + type kind. + kind Kind.manager contents_list -> + (Signature.public_key_hash * Signature.public_key option) option -> + (Signature.public_key_hash * Signature.public_key option) tzresult = + fun contents_list manager -> + let source (type kind) = function[@coq_match_with_default] + | (Manager_operation {source; operation = Reveal key; _} : + kind Kind.manager contents) -> + (source, Some key) + | Manager_operation {source; _} -> (source, None) + in + match contents_list with + | Single op -> check_same_manager (source op) manager + | Cons (op, rest) -> + check_same_manager (source op) manager >>? fun manager -> + find_source rest (Some manager) + in + find_source op None >>?= fun (source, source_key) -> + (match source_key with + | Some key -> return key + | None -> Contract.get_manager_key ctxt source) + >>=? fun public_key -> + Lwt.return (Operation.check_signature public_key chain_id raw_operation) + +let rec apply_manager_contents_list_rec : + type kind. + Alpha_context.t -> + Script_ir_translator.unparsing_mode -> + public_key_hash -> + Chain_id.t -> + kind Kind.manager contents_list -> + (success_or_failure * kind Kind.manager contents_result_list) Lwt.t = + fun ctxt mode baker chain_id contents_list -> + let level = Level.current ctxt in + match[@coq_match_with_default] contents_list with + | Single (Manager_operation {source; fee; _} as op) -> + let source = Contract.implicit_contract source in + apply_manager_contents ctxt mode chain_id op + >|= fun (ctxt_result, operation_result, internal_operation_results) -> + let result = + Manager_operation_result + { + balance_updates = + Receipt.cleanup_balance_updates + [ + (Contract source, Debited fee, Block_application); + (Fees (baker, level.cycle), Credited fee, Block_application); + ]; + operation_result; + internal_operation_results; + } + in + (ctxt_result, Single_result result) + | Cons ((Manager_operation {source; fee; _} as op), rest) -> ( + let source = Contract.implicit_contract source in + apply_manager_contents ctxt mode chain_id op >>= function + | (Failure, operation_result, internal_operation_results) -> + let result = + Manager_operation_result + { + balance_updates = + Receipt.cleanup_balance_updates + [ + (Contract source, Debited fee, Block_application); + ( Fees (baker, level.cycle), + Credited fee, + Block_application ); + ]; + operation_result; + internal_operation_results; + } + in + Lwt.return + (Failure, Cons_result (result, mark_skipped ~baker level rest)) + | (Success ctxt, operation_result, internal_operation_results) -> + let result = + Manager_operation_result + { + balance_updates = + Receipt.cleanup_balance_updates + [ + (Contract source, Debited fee, Block_application); + ( Fees (baker, level.cycle), + Credited fee, + Block_application ); + ]; + operation_result; + internal_operation_results; + } + in + apply_manager_contents_list_rec ctxt mode baker chain_id rest + >|= fun (ctxt_result, results) -> + (ctxt_result, Cons_result (result, results))) + +let mark_backtracked results = + let rec mark_contents_list : + type kind. + kind Kind.manager contents_result_list -> + kind Kind.manager contents_result_list = function + | Single_result (Manager_operation_result op) -> + Single_result + (Manager_operation_result + { + balance_updates = op.balance_updates; + operation_result = + mark_manager_operation_result op.operation_result; + internal_operation_results = + List.map + mark_internal_operation_results + op.internal_operation_results; + }) + | Cons_result (Manager_operation_result op, rest) -> + Cons_result + ( Manager_operation_result + { + balance_updates = op.balance_updates; + operation_result = + mark_manager_operation_result op.operation_result; + internal_operation_results = + List.map + mark_internal_operation_results + op.internal_operation_results; + }, + mark_contents_list rest ) + and mark_internal_operation_results (Internal_operation_result (kind, result)) + = + Internal_operation_result (kind, mark_manager_operation_result result) + and mark_manager_operation_result : + type kind. kind manager_operation_result -> kind manager_operation_result + = function + | (Failed _ | Skipped _ | Backtracked _) as result -> result + | Applied (Reveal_result _) as result -> result + | Applied result -> Backtracked (result, None) + in + mark_contents_list results + [@@coq_axiom_with_reason "non-top-level mutual recursion"] + +let apply_manager_contents_list ctxt mode baker chain_id contents_list = + apply_manager_contents_list_rec ctxt mode baker chain_id contents_list + >>= fun (ctxt_result, results) -> + match ctxt_result with + | Failure -> Lwt.return (ctxt (* backtracked *), mark_backtracked results) + | Success ctxt -> + Lazy_storage.cleanup_temporaries ctxt >|= fun ctxt -> (ctxt, results) + +let apply_contents_list (type kind) ctxt chain_id mode pred_block baker + (operation : kind operation) (contents_list : kind contents_list) : + (context * kind contents_result_list) tzresult Lwt.t = + match[@coq_match_with_default] contents_list with + | Single + (Endorsement_with_slot + { + endorsement = + { + shell = {branch}; + protocol_data = {contents = Single (Endorsement {level}); _}; + } as unslotted; + slot; + }) -> + if + (match operation.protocol_data.signature with + | None -> false + | Some _ -> true) + || not (Block_hash.equal operation.shell.branch branch) + then fail Invalid_endorsement_wrapper + else + let operation = unslotted (* shadow the slot box *) in + let block = operation.shell.branch in + Baking.check_endorsement_right ctxt chain_id operation ~slot + >>=? fun delegate -> + error_unless + (Block_hash.equal block pred_block) + (Wrong_endorsement_predecessor (pred_block, block)) + >>?= fun () -> + let current_level = Level.current ctxt in + error_unless + Raw_level.(succ level = current_level.level) + Invalid_endorsement_level + >>?= fun () -> + Baking.check_endorsement_slots_at_current_level ctxt ~slot delegate + >>=? fun (slots, used) -> + if used then fail (Duplicate_endorsement delegate) + else + let ctxt = record_endorsement ctxt delegate in + let gap = List.length slots in + Tez.(Constants.endorsement_security_deposit ctxt *? Int64.of_int gap) + >>?= fun deposit -> + Delegate.freeze_deposit ctxt delegate deposit >>=? fun ctxt -> + Global.get_block_priority ctxt >>=? fun block_priority -> + Baking.endorsing_reward ctxt ~block_priority gap >>?= fun reward -> + Delegate.freeze_rewards ctxt delegate reward >|=? fun ctxt -> + ( ctxt, + Single_result + (Endorsement_with_slot_result + (Endorsement_result + { + balance_updates = + Receipt.cleanup_balance_updates + [ + ( Contract (Contract.implicit_contract delegate), + Debited deposit, + Block_application ); + ( Deposits (delegate, current_level.cycle), + Credited deposit, + Block_application ); + ( Rewards (delegate, current_level.cycle), + Credited reward, + Block_application ); + ]; + delegate; + slots; + })) ) + | Single (Endorsement _) -> fail Unwrapped_endorsement + | Single (Seed_nonce_revelation {level; nonce}) -> + let level = Level.from_raw ctxt level in + Nonce.reveal ctxt level nonce >>=? fun ctxt -> + let seed_nonce_revelation_tip = + Constants.seed_nonce_revelation_tip ctxt + in + Lwt.return + ( add_rewards ctxt seed_nonce_revelation_tip >|? fun ctxt -> + ( ctxt, + Single_result + (Seed_nonce_revelation_result + [ + ( Rewards (baker, (Level.current ctxt).cycle), + Credited seed_nonce_revelation_tip, + Block_application ); + ]) ) ) + | Single (Double_endorsement_evidence {op1; op2; slot}) -> ( + match (op1.protocol_data.contents, op2.protocol_data.contents) with + | (Single (Endorsement e1), Single (Endorsement e2)) + when Raw_level.(e1.level = e2.level) + && not (Block_hash.equal op1.shell.branch op2.shell.branch) -> + let level = Level.from_raw ctxt e1.level in + let oldest_level = Level.last_allowed_fork_level ctxt in + fail_unless + Level.(level < Level.current ctxt) + (Too_early_double_endorsement_evidence + {level = level.level; current = (Level.current ctxt).level}) + >>=? fun () -> + fail_unless + Raw_level.(oldest_level <= level.level) + (Outdated_double_endorsement_evidence + {level = level.level; last = oldest_level}) + >>=? fun () -> + Baking.check_endorsement_right ctxt chain_id op1 ~slot + >>=? fun delegate1 -> + Baking.check_endorsement_right ctxt chain_id op2 ~slot + >>=? fun delegate2 -> + fail_unless + (Signature.Public_key_hash.equal delegate1 delegate2) + (Inconsistent_double_endorsement_evidence {delegate1; delegate2}) + >>=? fun () -> + Delegate.has_frozen_balance ctxt delegate1 level.cycle + >>=? fun valid -> + fail_unless valid Unrequired_double_endorsement_evidence + >>=? fun () -> + Delegate.punish ctxt delegate1 level.cycle >>=? fun (ctxt, balance) -> + Lwt.return Tez.(balance.deposit +? balance.fees) >>=? fun burned -> + let reward = + match Tez.(burned /? 2L) with Ok v -> v | Error _ -> Tez.zero + in + add_rewards ctxt reward >>?= fun ctxt -> + let current_cycle = (Level.current ctxt).cycle in + return + ( ctxt, + Single_result + (Double_endorsement_evidence_result + (Receipt.cleanup_balance_updates + [ + ( Deposits (delegate1, level.cycle), + Debited balance.deposit, + Block_application ); + ( Fees (delegate1, level.cycle), + Debited balance.fees, + Block_application ); + ( Rewards (delegate1, level.cycle), + Debited balance.rewards, + Block_application ); + ( Rewards (baker, current_cycle), + Credited reward, + Block_application ); + ])) ) + | (_, _) -> fail Invalid_double_endorsement_evidence) + | Single (Double_baking_evidence {bh1; bh2}) -> + let hash1 = Block_header.hash bh1 in + let hash2 = Block_header.hash bh2 in + fail_unless + (Compare.Int32.(bh1.shell.level = bh2.shell.level) + && not (Block_hash.equal hash1 hash2)) + (Invalid_double_baking_evidence + {hash1; level1 = bh1.shell.level; hash2; level2 = bh2.shell.level}) + >>=? fun () -> + Lwt.return (Raw_level.of_int32 bh1.shell.level) >>=? fun raw_level -> + let oldest_level = Level.last_allowed_fork_level ctxt in + fail_unless + Raw_level.(raw_level < (Level.current ctxt).level) + (Too_early_double_baking_evidence + {level = raw_level; current = (Level.current ctxt).level}) + >>=? fun () -> + fail_unless + Raw_level.(oldest_level <= raw_level) + (Outdated_double_baking_evidence + {level = raw_level; last = oldest_level}) + >>=? fun () -> + let level = Level.from_raw ctxt raw_level in + Roll.baking_rights_owner + ctxt + level + ~priority:bh1.protocol_data.contents.priority + >>=? fun delegate1 -> + Baking.check_signature bh1 chain_id delegate1 >>=? fun () -> + Roll.baking_rights_owner + ctxt + level + ~priority:bh2.protocol_data.contents.priority + >>=? fun delegate2 -> + Baking.check_signature bh2 chain_id delegate2 >>=? fun () -> + fail_unless + (Signature.Public_key.equal delegate1 delegate2) + (Inconsistent_double_baking_evidence + { + delegate1 = Signature.Public_key.hash delegate1; + delegate2 = Signature.Public_key.hash delegate2; + }) + >>=? fun () -> + let delegate = Signature.Public_key.hash delegate1 in + Delegate.has_frozen_balance ctxt delegate level.cycle >>=? fun valid -> + fail_unless valid Unrequired_double_baking_evidence >>=? fun () -> + Delegate.punish ctxt delegate level.cycle >>=? fun (ctxt, balance) -> + Tez.(balance.deposit +? balance.fees) >>?= fun burned -> + let reward = + match Tez.(burned /? 2L) with Ok v -> v | Error _ -> Tez.zero + in + Lwt.return + ( add_rewards ctxt reward >|? fun ctxt -> + let current_cycle = (Level.current ctxt).cycle in + ( ctxt, + Single_result + (Double_baking_evidence_result + (Receipt.cleanup_balance_updates + [ + ( Deposits (delegate, level.cycle), + Debited balance.deposit, + Block_application ); + ( Fees (delegate, level.cycle), + Debited balance.fees, + Block_application ); + ( Rewards (delegate, level.cycle), + Debited balance.rewards, + Block_application ); + ( Rewards (baker, current_cycle), + Credited reward, + Block_application ); + ])) ) ) + | Single (Activate_account {id = pkh; activation_code}) -> ( + let blinded_pkh = + Blinded_public_key_hash.of_ed25519_pkh activation_code pkh + in + Commitment.find ctxt blinded_pkh >>=? function + | None -> fail (Invalid_activation {pkh}) + | Some amount -> + Commitment.remove_existing ctxt blinded_pkh >>=? fun ctxt -> + let contract = Contract.implicit_contract (Signature.Ed25519 pkh) in + Contract.(credit ctxt contract amount) >|=? fun ctxt -> + ( ctxt, + Single_result + (Activate_account_result + [(Contract contract, Credited amount, Block_application)]) )) + | Single (Proposals {source; period; proposals}) -> + Roll.delegate_pubkey ctxt source >>=? fun delegate -> + Operation.check_signature delegate chain_id operation >>?= fun () -> + Voting_period.get_current ctxt >>=? fun {index = current_period; _} -> + error_unless + Compare.Int32.(current_period = period) + (Wrong_voting_period (current_period, period)) + >>?= fun () -> + Amendment.record_proposals ctxt source proposals >|=? fun ctxt -> + (ctxt, Single_result Proposals_result) + | Single (Ballot {source; period; proposal; ballot}) -> + Roll.delegate_pubkey ctxt source >>=? fun delegate -> + Operation.check_signature delegate chain_id operation >>?= fun () -> + Voting_period.get_current ctxt >>=? fun {index = current_period; _} -> + error_unless + Compare.Int32.(current_period = period) + (Wrong_voting_period (current_period, period)) + >>?= fun () -> + Amendment.record_ballot ctxt source proposal ballot >|=? fun ctxt -> + (ctxt, Single_result Ballot_result) + | Single (Failing_noop _) -> + (* Failing_noop _ always fails *) + fail Failing_noop_error + | Single (Manager_operation _) as op -> + precheck_manager_contents_list ctxt op >>=? fun ctxt -> + check_manager_signature ctxt chain_id op operation >>=? fun () -> + apply_manager_contents_list ctxt mode baker chain_id op >|= ok + | Cons (Manager_operation _, _) as op -> + precheck_manager_contents_list ctxt op >>=? fun ctxt -> + check_manager_signature ctxt chain_id op operation >>=? fun () -> + apply_manager_contents_list ctxt mode baker chain_id op >|= ok + +let apply_operation ctxt chain_id mode pred_block baker hash operation = + let ctxt = Contract.init_origination_nonce ctxt hash in + apply_contents_list + ctxt + chain_id + mode + pred_block + baker + operation + operation.protocol_data.contents + >|=? fun (ctxt, result) -> + let ctxt = Gas.set_unlimited ctxt in + let ctxt = Contract.unset_origination_nonce ctxt in + (ctxt, {contents = result}) + +let may_start_new_cycle ctxt = + match Level.dawn_of_a_new_cycle ctxt with + | None -> return (ctxt, [], []) + | Some last_cycle -> + Seed.cycle_end ctxt last_cycle >>=? fun (ctxt, unrevealed) -> + Roll.cycle_end ctxt last_cycle >>=? fun ctxt -> + Delegate.cycle_end ctxt last_cycle unrevealed + >>=? fun (ctxt, update_balances, deactivated) -> + Bootstrap.cycle_end ctxt last_cycle >|=? fun ctxt -> + (ctxt, update_balances, deactivated) + +let endorsement_rights_of_pred_level ctxt = + match Level.pred ctxt (Level.current ctxt) with + | None -> assert false (* genesis *) + | Some pred_level -> Baking.endorsement_rights ctxt pred_level + +let apply_liquidity_baking_subsidy ctxt ~escape_vote = + Liquidity_baking.on_subsidy_allowed + ctxt + ~escape_vote + (fun ctxt liquidity_baking_cpmm_contract -> + let ctxt = + (* We set a gas limit of 1/20th the block limit, which is ~10x actual usage here in Granada. Gas consumed is reported in the Transaction receipt, but not counted towards the block limit. The gas limit is reset to unlimited at the end of this function.*) + Gas.set_limit + ctxt + (Gas.Arith.integral_exn + (Z.div + (Gas.Arith.integral_to_z + (Constants.hard_gas_limit_per_block ctxt)) + (Z.of_int 20))) + in + let backtracking_ctxt = ctxt in + (let liquidity_baking_subsidy = Constants.liquidity_baking_subsidy ctxt in + (* credit liquidity baking subsidy to CPMM contract *) + Contract.credit + ctxt + liquidity_baking_cpmm_contract + liquidity_baking_subsidy + >>=? fun ctxt -> + Script_cache.find ctxt liquidity_baking_cpmm_contract + >>=? fun (ctxt, cache_key, script) -> + match script with + | None -> fail (Script_tc_errors.No_such_entrypoint "default") + | Some (script, script_ir) -> ( + let step_constants = + let open Script_interpreter in + (* Using dummy values for source, payer, and chain_id + since they are not used within the CPMM default + entrypoint. *) + { + source = liquidity_baking_cpmm_contract; + payer = liquidity_baking_cpmm_contract; + self = liquidity_baking_cpmm_contract; + amount = liquidity_baking_subsidy; + chain_id = Chain_id.zero; + } + in + let parameter = + Micheline.strip_locations + Michelson_v1_primitives.(Prim (0, D_Unit, [], [])) + in + (* + Call CPPM default entrypoint with parameter Unit. + This is necessary for the CPMM's xtz_pool in storage to + increase since it cannot use BALANCE due to a transfer attack. + + Mimicks a transaction. + + There is no: + - storage burn (extra storage is free) + - fees (the operation is mandatory) + *) + Script_interpreter.execute + ctxt + Optimized + step_constants + ~script + ~parameter + ~cached_script:(Some script_ir) + ~entrypoint:"default" + ~internal:false + >>=? fun ( {ctxt; storage; lazy_storage_diff; operations}, + (updated_cached_script, updated_size) ) -> + match operations with + | _ :: _ -> + (* No internal operations are expected here. Something bad may be happening. *) + return (backtracking_ctxt, []) + | [] -> + (* update CPMM storage *) + Contract.update_script_storage + ctxt + liquidity_baking_cpmm_contract + storage + lazy_storage_diff + >>=? fun ctxt -> + Fees.record_paid_storage_space_subsidy + ctxt + liquidity_baking_cpmm_contract + >>=? fun (ctxt, new_size, paid_storage_size_diff) -> + let balance_updates = + [ + Receipt. + ( Contract liquidity_baking_cpmm_contract, + Credited liquidity_baking_subsidy, + Subsidy ); + ] + in + let consumed_gas = + Gas.consumed ~since:backtracking_ctxt ~until:ctxt + in + Script_cache.update + ctxt + cache_key + ( {script with storage = Script.lazy_expr storage}, + updated_cached_script ) + updated_size + >>?= fun ctxt -> + let result = + Transaction_result + { + storage = Some storage; + lazy_storage_diff; + balance_updates; + (* At this point in application the origination nonce has not been initialized so it's not possible to originate new contracts. We've checked above that none were originated. *) + originated_contracts = []; + consumed_gas; + storage_size = new_size; + paid_storage_size_diff; + allocated_destination_contract = false; + } + in + let ctxt = Gas.set_unlimited ctxt in + return (ctxt, [Successful_manager_result result]))) + >|= function + | Ok (ctxt, results) -> Ok (ctxt, results) + | Error _ -> + (* Do not fail if something bad happens during CPMM contract call. *) + let ctxt = Gas.set_unlimited backtracking_ctxt in + Ok (ctxt, [])) + +let begin_full_construction ctxt pred_timestamp protocol_data = + let priority = protocol_data.Block_header.priority in + Global.set_block_priority ctxt priority >>=? fun ctxt -> + Baking.check_timestamp ctxt ~priority pred_timestamp >>?= fun () -> + let level = Level.current ctxt in + Roll.baking_rights_owner ctxt level ~priority >>=? fun delegate_pk -> + let ctxt = Fitness.increase ctxt in + endorsement_rights_of_pred_level ctxt >>=? fun rights -> + let ctxt = init_endorsements ctxt rights in + let escape_vote = protocol_data.liquidity_baking_escape_vote in + apply_liquidity_baking_subsidy ctxt ~escape_vote + >|=? fun ( ctxt, + liquidity_baking_operations_results, + liquidity_baking_escape_ema ) -> + ( ctxt, + protocol_data, + delegate_pk, + liquidity_baking_operations_results, + liquidity_baking_escape_ema ) + +let begin_partial_construction ctxt ~escape_vote = + let ctxt = Fitness.increase ctxt in + endorsement_rights_of_pred_level ctxt >>=? fun rights -> + let ctxt = init_endorsements ctxt rights in + apply_liquidity_baking_subsidy ctxt ~escape_vote + +let begin_application ctxt chain_id block_header pred_timestamp = + let priority = block_header.Block_header.protocol_data.contents.priority in + Global.set_block_priority ctxt priority >>=? fun ctxt -> + Baking.check_timestamp ctxt ~priority pred_timestamp >>?= fun () -> + Baking.check_proof_of_work_stamp ctxt block_header >>?= fun () -> + Baking.check_fitness_gap ctxt block_header >>?= fun () -> + let current_level = Level.current ctxt in + Roll.baking_rights_owner ctxt current_level ~priority >>=? fun delegate_pk -> + Baking.check_signature block_header chain_id delegate_pk >>=? fun () -> + let has_commitment = + Option.is_some block_header.protocol_data.contents.seed_nonce_hash + in + error_unless + Compare.Bool.(has_commitment = current_level.expected_commitment) + (Invalid_commitment {expected = current_level.expected_commitment}) + >>?= fun () -> + let ctxt = Fitness.increase ctxt in + endorsement_rights_of_pred_level ctxt >>=? fun rights -> + let ctxt = init_endorsements ctxt rights in + let escape_vote = + block_header.Block_header.protocol_data.contents + .liquidity_baking_escape_vote + in + apply_liquidity_baking_subsidy ctxt ~escape_vote + >|=? fun ( ctxt, + liquidity_baking_operations_results, + liquidity_baking_escape_ema ) -> + ( ctxt, + delegate_pk, + liquidity_baking_operations_results, + liquidity_baking_escape_ema ) + +let check_minimal_valid_time ctxt ~priority ~endorsing_power = + let predecessor_timestamp = Timestamp.predecessor ctxt in + Baking.minimal_valid_time + (Constants.parametric ctxt) + ~priority + ~endorsing_power + ~predecessor_timestamp + >>? fun minimum -> + let timestamp = Timestamp.current ctxt in + error_unless + Compare.Int64.(Time.to_seconds timestamp >= Time.to_seconds minimum) + (Baking.Timestamp_too_early + { + minimal_time = minimum; + provided_time = timestamp; + priority; + endorsing_power_opt = Some endorsing_power; + }) + +let finalize_application ctxt protocol_data delegate migration_balance_updates + liquidity_baking_escape_ema implicit_operations_results = + let included_endorsements = included_endorsements ctxt in + check_minimal_valid_time + ctxt + ~priority:protocol_data.Block_header.priority + ~endorsing_power:included_endorsements + >>?= fun () -> + let deposit = Constants.block_security_deposit ctxt in + Delegate.freeze_deposit ctxt delegate deposit >>=? fun ctxt -> + Baking.baking_reward + ctxt + ~block_priority:protocol_data.priority + ~included_endorsements + >>?= fun reward -> + add_rewards ctxt reward >>?= fun ctxt -> + (* end of level (from this point nothing should fail) *) + let fees = Alpha_context.get_fees ctxt in + Delegate.freeze_fees ctxt delegate fees >>=? fun ctxt -> + let rewards = Alpha_context.get_rewards ctxt in + Delegate.freeze_rewards ctxt delegate rewards >>=? fun ctxt -> + (match protocol_data.Block_header.seed_nonce_hash with + | None -> return ctxt + | Some nonce_hash -> + Nonce.record_hash ctxt {nonce_hash; delegate; rewards; fees}) + >>=? fun ctxt -> + (* end of cycle *) + (if Level.may_snapshot_rolls ctxt then Roll.snapshot_rolls ctxt + else return ctxt) + >>=? fun ctxt -> + may_start_new_cycle ctxt >>=? fun (ctxt, balance_updates, deactivated) -> + Amendment.may_start_new_voting_period ctxt >>=? fun ctxt -> + let cycle = (Level.current ctxt).cycle in + let balance_updates = + Receipt.( + cleanup_balance_updates + (migration_balance_updates + @ [ + ( Contract (Contract.implicit_contract delegate), + Debited deposit, + Block_application ); + (Deposits (delegate, cycle), Credited deposit, Block_application); + (Rewards (delegate, cycle), Credited reward, Block_application); + ] + @ balance_updates)) + in + let consumed_gas = + Gas.Arith.sub + (Gas.Arith.fp @@ Constants.hard_gas_limit_per_block ctxt) + (Gas.block_level ctxt) + in + Voting_period.get_rpc_current_info ctxt >|=? fun voting_period_info -> + let level_info = Level.current ctxt in + let receipt = + Apply_results. + { + baker = delegate; + level_info; + voting_period_info; + nonce_hash = protocol_data.seed_nonce_hash; + consumed_gas; + deactivated; + balance_updates; + liquidity_baking_escape_ema; + implicit_operations_results; + } + in + (ctxt, receipt) + +let value_of_key ctxt k = Alpha_context.Cache.Admin.value_of_key ctxt k diff --git a/src/proto_011_PtHangzH/lib_protocol/apply.mli b/src/proto_011_PtHangzH/lib_protocol/apply.mli new file mode 100644 index 000000000000..a242f25bd8ea --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/apply.mli @@ -0,0 +1,182 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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 supports advancing the ledger state by applying [operation]s. + + Each operation application takes and returns an [Alpha_context.t], representing + the old and new state, respectively. + + The [Main] module provides wrappers for the functionality in this module, + satisfying the Protocol signature. + *) + +open Alpha_context +open Apply_results + +type error += Wrong_endorsement_predecessor of Block_hash.t * Block_hash.t + +type error += Duplicate_endorsement of Signature.Public_key_hash.t + +type error += Invalid_endorsement_level + +type error += Unwrapped_endorsement + +type error += Invalid_commitment of {expected : bool} + +type error += Internal_operation_replay of packed_internal_operation + +type error += Invalid_double_endorsement_evidence + +type error += + | Inconsistent_double_endorsement_evidence of { + delegate1 : Signature.Public_key_hash.t; + delegate2 : Signature.Public_key_hash.t; + } + +type error += + | Too_early_double_endorsement_evidence of { + level : Raw_level.t; + current : Raw_level.t; + } + +type error += + | Outdated_double_endorsement_evidence of { + level : Raw_level.t; + last : Raw_level.t; + } + +type error += + | Invalid_double_baking_evidence of { + hash1 : Block_hash.t; + level1 : Int32.t; + hash2 : Block_hash.t; + level2 : Int32.t; + } + +type error += + | Inconsistent_double_baking_evidence of { + delegate1 : Signature.Public_key_hash.t; + delegate2 : Signature.Public_key_hash.t; + } + +type error += + | Too_early_double_baking_evidence of { + level : Raw_level.t; + current : Raw_level.t; + } + +type error += + | Outdated_double_baking_evidence of {level : Raw_level.t; last : Raw_level.t} + +type error += Invalid_activation of {pkh : Ed25519.Public_key_hash.t} + +type error += Gas_quota_exceeded_init_deserialize + +type error += Inconsistent_sources + +type error += (* `Permanent *) Failing_noop_error + +val begin_partial_construction : + t -> + escape_vote:bool -> + (t + * packed_successful_manager_operation_result list + * Liquidity_baking.escape_ema) + tzresult + Lwt.t + +val begin_full_construction : + t -> + Time.t -> + Block_header.contents -> + (t + * Block_header.contents + * public_key + * packed_successful_manager_operation_result list + * Liquidity_baking.escape_ema) + tzresult + Lwt.t + +val begin_application : + t -> + Chain_id.t -> + Block_header.t -> + Time.t -> + (t + * public_key + * packed_successful_manager_operation_result list + * Liquidity_baking.escape_ema) + tzresult + Lwt.t + +val apply_operation : + t -> + Chain_id.t -> + Script_ir_translator.unparsing_mode -> + Block_hash.t -> + public_key_hash -> + Operation_list_hash.elt -> + 'a operation -> + (t * 'a operation_metadata, error trace) result Lwt.t + +val finalize_application : + t -> + Block_header.contents -> + public_key_hash -> + Receipt.balance_updates -> + Liquidity_baking.escape_ema -> + packed_successful_manager_operation_result list -> + (t * block_metadata, error trace) result Lwt.t + +val apply_manager_contents_list : + t -> + Script_ir_translator.unparsing_mode -> + public_key_hash -> + Chain_id.t -> + 'a Kind.manager contents_list -> + (t * 'a Kind.manager contents_result_list) Lwt.t + +val apply_contents_list : + t -> + Chain_id.t -> + Script_ir_translator.unparsing_mode -> + Block_hash.t -> + public_key_hash -> + 'kind operation -> + 'kind contents_list -> + (t * 'kind contents_result_list) tzresult Lwt.t + +val check_minimal_valid_time : + t -> priority:int -> endorsing_power:int -> (unit, error trace) result + +(** [value_of_key ctxt k] builds a value identified by key [k] + so that it can be put into the cache. *) +val value_of_key : t -> Context.Cache.key -> Context.Cache.value tzresult Lwt.t + +(** [cache_layout] describes how the caches needed by the protocol. + The length of the list defines the number of caches while each + element of this list corresponds to the size limit of each cache. *) +val cache_layout : int list diff --git a/src/proto_011_PtHangzH/lib_protocol/apply_results.ml b/src/proto_011_PtHangzH/lib_protocol/apply_results.ml new file mode 100644 index 000000000000..efb188f96f79 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/apply_results.ml @@ -0,0 +1,1345 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Data_encoding + +let error_encoding = + def + "error" + ~description: + "The full list of RPC errors would be too long to include.\n\ + It is available at RPC `/errors` (GET).\n\ + Errors specific to protocol Alpha have an id that starts with \ + `proto.alpha`." + @@ splitted + ~json: + (conv + (fun err -> + Data_encoding.Json.construct Error_monad.error_encoding err) + (fun json -> + Data_encoding.Json.destruct Error_monad.error_encoding json) + json) + ~binary:Error_monad.error_encoding + +let trace_encoding = make_trace_encoding error_encoding + +type _ successful_manager_operation_result = + | Reveal_result : { + consumed_gas : Gas.Arith.fp; + } + -> Kind.reveal successful_manager_operation_result + | Transaction_result : { + storage : Script.expr option; + lazy_storage_diff : Lazy_storage.diffs option; + balance_updates : Receipt.balance_updates; + originated_contracts : Contract.t list; + consumed_gas : Gas.Arith.fp; + storage_size : Z.t; + paid_storage_size_diff : Z.t; + allocated_destination_contract : bool; + } + -> Kind.transaction successful_manager_operation_result + | Origination_result : { + lazy_storage_diff : Lazy_storage.diffs option; + balance_updates : Receipt.balance_updates; + originated_contracts : Contract.t list; + consumed_gas : Gas.Arith.fp; + storage_size : Z.t; + paid_storage_size_diff : Z.t; + } + -> Kind.origination successful_manager_operation_result + | Delegation_result : { + consumed_gas : Gas.Arith.fp; + } + -> Kind.delegation successful_manager_operation_result + | Register_global_constant_result : { + balance_updates : Receipt.balance_updates; + consumed_gas : Gas.Arith.fp; + size_of_constant : Z.t; + global_address : Script_expr_hash.t; + } + -> Kind.register_global_constant successful_manager_operation_result + +let migration_origination_result_to_successful_manager_operation_result + ({ + balance_updates; + originated_contracts; + storage_size; + paid_storage_size_diff; + } : + Migration.origination_result) = + Origination_result + { + lazy_storage_diff = None; + balance_updates; + originated_contracts; + consumed_gas = Gas.Arith.zero; + storage_size; + paid_storage_size_diff; + } + +type packed_successful_manager_operation_result = + | Successful_manager_result : + 'kind successful_manager_operation_result + -> packed_successful_manager_operation_result + +let pack_migration_operation_results results = + List.map + (fun el -> + Successful_manager_result + (migration_origination_result_to_successful_manager_operation_result el)) + results + +type 'kind manager_operation_result = + | Applied of 'kind successful_manager_operation_result + | Backtracked of + 'kind successful_manager_operation_result * error trace option + | Failed : 'kind Kind.manager * error trace -> 'kind manager_operation_result + | Skipped : 'kind Kind.manager -> 'kind manager_operation_result +[@@coq_force_gadt] + +type packed_internal_operation_result = + | Internal_operation_result : + 'kind internal_operation * 'kind manager_operation_result + -> packed_internal_operation_result + +module Manager_result = struct + type 'kind case = + | MCase : { + op_case : 'kind Operation.Encoding.Manager_operations.case; + encoding : 'a Data_encoding.t; + kind : 'kind Kind.manager; + iselect : + packed_internal_operation_result -> + ('kind internal_operation * 'kind manager_operation_result) option; + select : + packed_successful_manager_operation_result -> + 'kind successful_manager_operation_result option; + proj : 'kind successful_manager_operation_result -> 'a; + inj : 'a -> 'kind successful_manager_operation_result; + t : 'kind manager_operation_result Data_encoding.t; + } + -> 'kind case + + let make ~op_case ~encoding ~kind ~iselect ~select ~proj ~inj = + let (Operation.Encoding.Manager_operations.MCase {name; _}) = op_case in + let t = + def (Format.asprintf "operation.alpha.operation_result.%s" name) + @@ union + ~tag_size:`Uint8 + [ + case + (Tag 0) + ~title:"Applied" + (merge_objs (obj1 (req "status" (constant "applied"))) encoding) + (fun o -> + match o with + | Skipped _ | Failed _ | Backtracked _ -> None + | Applied o -> ( + match select (Successful_manager_result o) with + | None -> None + | Some o -> Some ((), proj o))) + (fun ((), x) -> Applied (inj x)); + case + (Tag 1) + ~title:"Failed" + (obj2 + (req "status" (constant "failed")) + (req "errors" trace_encoding)) + (function Failed (_, errs) -> Some ((), errs) | _ -> None) + (fun ((), errs) -> Failed (kind, errs)); + case + (Tag 2) + ~title:"Skipped" + (obj1 (req "status" (constant "skipped"))) + (function Skipped _ -> Some () | _ -> None) + (fun () -> Skipped kind); + case + (Tag 3) + ~title:"Backtracked" + (merge_objs + (obj2 + (req "status" (constant "backtracked")) + (opt "errors" trace_encoding)) + encoding) + (fun o -> + match o with + | Skipped _ | Failed _ | Applied _ -> None + | Backtracked (o, errs) -> ( + match select (Successful_manager_result o) with + | None -> None + | Some o -> Some (((), errs), proj o))) + (fun (((), errs), x) -> Backtracked (inj x, errs)); + ] + in + MCase {op_case; encoding; kind; iselect; select; proj; inj; t} + + let[@coq_axiom_with_reason "gadt"] reveal_case = + make + ~op_case:Operation.Encoding.Manager_operations.reveal_case + ~encoding: + Data_encoding.( + obj2 + (dft "consumed_gas" Gas.Arith.n_integral_encoding Gas.Arith.zero) + (dft "consumed_milligas" Gas.Arith.n_fp_encoding Gas.Arith.zero)) + ~iselect:(function + | Internal_operation_result (({operation = Reveal _; _} as op), res) -> + Some (op, res) + | _ -> None) + ~select:(function + | Successful_manager_result (Reveal_result _ as op) -> Some op + | _ -> None) + ~kind:Kind.Reveal_manager_kind + ~proj:(function + | Reveal_result {consumed_gas} -> + (Gas.Arith.ceil consumed_gas, consumed_gas)) + ~inj:(fun (consumed_gas, consumed_milligas) -> + assert (Gas.Arith.(equal (ceil consumed_milligas) consumed_gas)) ; + Reveal_result {consumed_gas = consumed_milligas}) + + let[@coq_axiom_with_reason "gadt"] transaction_case = + make + ~op_case:Operation.Encoding.Manager_operations.transaction_case + ~encoding: + (obj10 + (opt "storage" Script.expr_encoding) + (opt + (* The field [big_map_diff] is deprecated since 008, use [lazy_storage_diff] instead. + Is it kept here for a transition period, for tool like indexers to update. + TODO(009): remove it. *) + "big_map_diff" + Lazy_storage.legacy_big_map_diff_encoding) + (dft "balance_updates" Receipt.balance_updates_encoding []) + (dft "originated_contracts" (list Contract.encoding) []) + (dft "consumed_gas" Gas.Arith.n_integral_encoding Gas.Arith.zero) + (dft "consumed_milligas" Gas.Arith.n_fp_encoding Gas.Arith.zero) + (dft "storage_size" z Z.zero) + (dft "paid_storage_size_diff" z Z.zero) + (dft "allocated_destination_contract" bool false) + (opt "lazy_storage_diff" Lazy_storage.encoding)) + ~iselect:(function + | Internal_operation_result (({operation = Transaction _; _} as op), res) + -> + Some (op, res) + | _ -> None) + ~select:(function + | Successful_manager_result (Transaction_result _ as op) -> Some op + | _ -> None) + ~kind:Kind.Transaction_manager_kind + ~proj:(function + | Transaction_result + { + storage; + lazy_storage_diff; + balance_updates; + originated_contracts; + consumed_gas; + storage_size; + paid_storage_size_diff; + allocated_destination_contract; + } -> + ( storage, + lazy_storage_diff, + balance_updates, + originated_contracts, + Gas.Arith.ceil consumed_gas, + consumed_gas, + storage_size, + paid_storage_size_diff, + allocated_destination_contract, + lazy_storage_diff )) + ~inj: + (fun ( storage, + legacy_lazy_storage_diff, + balance_updates, + originated_contracts, + consumed_gas, + consumed_milligas, + storage_size, + paid_storage_size_diff, + allocated_destination_contract, + lazy_storage_diff ) -> + assert (Gas.Arith.(equal (ceil consumed_milligas) consumed_gas)) ; + let lazy_storage_diff = + Option.either lazy_storage_diff legacy_lazy_storage_diff + in + Transaction_result + { + storage; + lazy_storage_diff; + balance_updates; + originated_contracts; + consumed_gas = consumed_milligas; + storage_size; + paid_storage_size_diff; + allocated_destination_contract; + }) + + let[@coq_axiom_with_reason "gadt"] origination_case = + make + ~op_case:Operation.Encoding.Manager_operations.origination_case + ~encoding: + (obj8 + (opt + (* The field [big_map_diff] is deprecated since 008, use [lazy_storage_diff] instead. + Is it kept here for a transition period, for tool like indexers to update. + TODO(009): remove it. *) + "big_map_diff" + Lazy_storage.legacy_big_map_diff_encoding) + (dft "balance_updates" Receipt.balance_updates_encoding []) + (dft "originated_contracts" (list Contract.encoding) []) + (dft "consumed_gas" Gas.Arith.n_integral_encoding Gas.Arith.zero) + (dft "consumed_milligas" Gas.Arith.n_fp_encoding Gas.Arith.zero) + (dft "storage_size" z Z.zero) + (dft "paid_storage_size_diff" z Z.zero) + (opt "lazy_storage_diff" Lazy_storage.encoding)) + ~iselect:(function + | Internal_operation_result (({operation = Origination _; _} as op), res) + -> + Some (op, res) + | _ -> None) + ~select:(function + | Successful_manager_result (Origination_result _ as op) -> Some op + | _ -> None) + ~proj:(function + | Origination_result + { + lazy_storage_diff; + balance_updates; + originated_contracts; + consumed_gas; + storage_size; + paid_storage_size_diff; + } -> + ( lazy_storage_diff, + balance_updates, + originated_contracts, + Gas.Arith.ceil consumed_gas, + consumed_gas, + storage_size, + paid_storage_size_diff, + lazy_storage_diff )) + ~kind:Kind.Origination_manager_kind + ~inj: + (fun ( legacy_lazy_storage_diff, + balance_updates, + originated_contracts, + consumed_gas, + consumed_milligas, + storage_size, + paid_storage_size_diff, + lazy_storage_diff ) -> + assert (Gas.Arith.(equal (ceil consumed_milligas) consumed_gas)) ; + let lazy_storage_diff = + Option.either lazy_storage_diff legacy_lazy_storage_diff + in + Origination_result + { + lazy_storage_diff; + balance_updates; + originated_contracts; + consumed_gas = consumed_milligas; + storage_size; + paid_storage_size_diff; + }) + + let[@coq_axiom_with_reason "gadt"] register_global_constant_case = + make + ~op_case: + Operation.Encoding.Manager_operations.register_global_constant_case + ~encoding: + (obj4 + (req "balance_updates" Receipt.balance_updates_encoding) + (req "consumed_gas" Gas.Arith.n_integral_encoding) + (req "storage_size" z) + (req "global_address" Script_expr_hash.encoding)) + ~iselect:(function + | Internal_operation_result + (({operation = Register_global_constant _; _} as op), res) -> + Some (op, res) + | _ -> None) + ~select:(function + | Successful_manager_result (Register_global_constant_result _ as op) -> + Some op + | _ -> None) + ~proj:(function + | Register_global_constant_result + {balance_updates; consumed_gas; size_of_constant; global_address} -> + (balance_updates, consumed_gas, size_of_constant, global_address)) + ~kind:Kind.Register_global_constant_manager_kind + ~inj: + (fun (balance_updates, consumed_gas, size_of_constant, global_address) -> + Register_global_constant_result + {balance_updates; consumed_gas; size_of_constant; global_address}) + + let delegation_case = + make + ~op_case:Operation.Encoding.Manager_operations.delegation_case + ~encoding: + Data_encoding.( + obj2 + (dft "consumed_gas" Gas.Arith.n_integral_encoding Gas.Arith.zero) + (dft "consumed_milligas" Gas.Arith.n_fp_encoding Gas.Arith.zero)) + ~iselect:(function + | Internal_operation_result (({operation = Delegation _; _} as op), res) + -> + Some (op, res) + | _ -> None) + ~select:(function + | Successful_manager_result (Delegation_result _ as op) -> Some op + | _ -> None) + ~kind:Kind.Delegation_manager_kind + ~proj:(function[@coq_match_with_default] + | Delegation_result {consumed_gas} -> + (Gas.Arith.ceil consumed_gas, consumed_gas)) + ~inj:(fun (consumed_gas, consumed_milligas) -> + assert (Gas.Arith.(equal (ceil consumed_milligas) consumed_gas)) ; + Delegation_result {consumed_gas = consumed_milligas}) +end + +let internal_operation_result_encoding : + packed_internal_operation_result Data_encoding.t = + let make (type kind) + (Manager_result.MCase res_case : kind Manager_result.case) = + let (Operation.Encoding.Manager_operations.MCase op_case) = + res_case.op_case + in + case + (Tag op_case.tag) + ~title:op_case.name + (merge_objs + (obj3 + (req "kind" (constant op_case.name)) + (req "source" Contract.encoding) + (req "nonce" uint16)) + (merge_objs op_case.encoding (obj1 (req "result" res_case.t)))) + (fun op -> + match res_case.iselect op with + | Some (op, res) -> + Some (((), op.source, op.nonce), (op_case.proj op.operation, res)) + | None -> None) + (fun (((), source, nonce), (op, res)) -> + let op = {source; operation = op_case.inj op; nonce} in + Internal_operation_result (op, res)) + in + def "operation.alpha.internal_operation_result" + @@ union + [ + make Manager_result.reveal_case; + make Manager_result.transaction_case; + make Manager_result.origination_case; + make Manager_result.delegation_case; + make Manager_result.register_global_constant_case; + ] + +let successful_manager_operation_result_encoding : + packed_successful_manager_operation_result Data_encoding.t = + let make (type kind) + (Manager_result.MCase res_case : kind Manager_result.case) = + let (Operation.Encoding.Manager_operations.MCase op_case) = + res_case.op_case + in + case + (Tag op_case.tag) + ~title:op_case.name + (merge_objs (obj1 (req "kind" (constant op_case.name))) res_case.encoding) + (fun res -> + match res_case.select res with + | Some res -> Some ((), res_case.proj res) + | None -> None) + (fun ((), res) -> Successful_manager_result (res_case.inj res)) + in + def "operation.alpha.successful_manager_operation_result" + @@ union + [ + make Manager_result.reveal_case; + make Manager_result.transaction_case; + make Manager_result.origination_case; + make Manager_result.delegation_case; + ] + +type 'kind contents_result = + | Endorsement_result : { + balance_updates : Receipt.balance_updates; + delegate : Signature.Public_key_hash.t; + slots : int list; + } + -> Kind.endorsement contents_result + | Seed_nonce_revelation_result : + Receipt.balance_updates + -> Kind.seed_nonce_revelation contents_result + | Endorsement_with_slot_result : + Kind.endorsement contents_result + -> Kind.endorsement_with_slot contents_result + | Double_endorsement_evidence_result : + Receipt.balance_updates + -> Kind.double_endorsement_evidence contents_result + | Double_baking_evidence_result : + Receipt.balance_updates + -> Kind.double_baking_evidence contents_result + | Activate_account_result : + Receipt.balance_updates + -> Kind.activate_account contents_result + | Proposals_result : Kind.proposals contents_result + | Ballot_result : Kind.ballot contents_result + | Manager_operation_result : { + balance_updates : Receipt.balance_updates; + operation_result : 'kind manager_operation_result; + internal_operation_results : packed_internal_operation_result list; + } + -> 'kind Kind.manager contents_result + +type packed_contents_result = + | Contents_result : 'kind contents_result -> packed_contents_result + +type packed_contents_and_result = + | Contents_and_result : + 'kind Operation.contents * 'kind contents_result + -> packed_contents_and_result + +type ('a, 'b) eq = Eq : ('a, 'a) eq [@@coq_force_gadt] + +let equal_manager_kind : + type a b. a Kind.manager -> b Kind.manager -> (a, b) eq option = + fun ka kb -> + match (ka, kb) with + | (Kind.Reveal_manager_kind, Kind.Reveal_manager_kind) -> Some Eq + | (Kind.Reveal_manager_kind, _) -> None + | (Kind.Transaction_manager_kind, Kind.Transaction_manager_kind) -> Some Eq + | (Kind.Transaction_manager_kind, _) -> None + | (Kind.Origination_manager_kind, Kind.Origination_manager_kind) -> Some Eq + | (Kind.Origination_manager_kind, _) -> None + | (Kind.Delegation_manager_kind, Kind.Delegation_manager_kind) -> Some Eq + | (Kind.Delegation_manager_kind, _) -> None + | ( Kind.Register_global_constant_manager_kind, + Kind.Register_global_constant_manager_kind ) -> + Some Eq + | (Kind.Register_global_constant_manager_kind, _) -> None + +module Encoding = struct + type 'kind case = + | Case : { + op_case : 'kind Operation.Encoding.case; + encoding : 'a Data_encoding.t; + select : packed_contents_result -> 'kind contents_result option; + mselect : + packed_contents_and_result -> + ('kind contents * 'kind contents_result) option; + proj : 'kind contents_result -> 'a; + inj : 'a -> 'kind contents_result; + } + -> 'kind case + + let tagged_case tag name args proj inj = + let open Data_encoding in + case + tag + ~title:(String.capitalize_ascii name) + (merge_objs (obj1 (req "kind" (constant name))) args) + (fun x -> match proj x with None -> None | Some x -> Some ((), x)) + (fun ((), x) -> inj x) + + let[@coq_axiom_with_reason "gadt"] endorsement_case = + Case + { + op_case = Operation.Encoding.endorsement_case; + encoding = + obj3 + (req "balance_updates" Receipt.balance_updates_encoding) + (req "delegate" Signature.Public_key_hash.encoding) + (req "slots" (list uint16)); + select = + (function + | Contents_result (Endorsement_result _ as op) -> Some op | _ -> None); + mselect = + (function + | Contents_and_result ((Endorsement _ as op), res) -> Some (op, res) + | _ -> None); + proj = + (function + | Endorsement_result {balance_updates; delegate; slots} -> + (balance_updates, delegate, slots)); + inj = + (fun (balance_updates, delegate, slots) -> + Endorsement_result {balance_updates; delegate; slots}); + } + + let[@coq_axiom_with_reason "gadt"] seed_nonce_revelation_case = + Case + { + op_case = Operation.Encoding.seed_nonce_revelation_case; + encoding = obj1 (req "balance_updates" Receipt.balance_updates_encoding); + select = + (function + | Contents_result (Seed_nonce_revelation_result _ as op) -> Some op + | _ -> None); + mselect = + (function + | Contents_and_result ((Seed_nonce_revelation _ as op), res) -> + Some (op, res) + | _ -> None); + proj = (fun (Seed_nonce_revelation_result bus) -> bus); + inj = (fun bus -> Seed_nonce_revelation_result bus); + } + + let[@coq_axiom_with_reason "gadt"] endorsement_with_slot_case = + Case + { + op_case = Operation.Encoding.endorsement_with_slot_case; + encoding = + obj3 + (req "balance_updates" Receipt.balance_updates_encoding) + (req "delegate" Signature.Public_key_hash.encoding) + (req "slots" (list uint16)); + select = + (function + | Contents_result (Endorsement_with_slot_result _ as op) -> Some op + | _ -> None); + mselect = + (function + | Contents_and_result ((Endorsement_with_slot _ as op), res) -> + Some (op, res) + | _ -> None); + proj = + (function + | Endorsement_with_slot_result + (Endorsement_result {balance_updates; delegate; slots}) -> + (balance_updates, delegate, slots)); + inj = + (fun (balance_updates, delegate, slots) -> + Endorsement_with_slot_result + (Endorsement_result {balance_updates; delegate; slots})); + } + + let[@coq_axiom_with_reason "gadt"] double_endorsement_evidence_case = + Case + { + op_case = Operation.Encoding.double_endorsement_evidence_case; + encoding = obj1 (req "balance_updates" Receipt.balance_updates_encoding); + select = + (function + | Contents_result (Double_endorsement_evidence_result _ as op) -> + Some op + | _ -> None); + mselect = + (function + | Contents_and_result ((Double_endorsement_evidence _ as op), res) -> + Some (op, res) + | _ -> None); + proj = (fun (Double_endorsement_evidence_result bus) -> bus); + inj = (fun bus -> Double_endorsement_evidence_result bus); + } + + let[@coq_axiom_with_reason "gadt"] double_baking_evidence_case = + Case + { + op_case = Operation.Encoding.double_baking_evidence_case; + encoding = obj1 (req "balance_updates" Receipt.balance_updates_encoding); + select = + (function + | Contents_result (Double_baking_evidence_result _ as op) -> Some op + | _ -> None); + mselect = + (function + | Contents_and_result ((Double_baking_evidence _ as op), res) -> + Some (op, res) + | _ -> None); + proj = (fun (Double_baking_evidence_result bus) -> bus); + inj = (fun bus -> Double_baking_evidence_result bus); + } + + let[@coq_axiom_with_reason "gadt"] activate_account_case = + Case + { + op_case = Operation.Encoding.activate_account_case; + encoding = obj1 (req "balance_updates" Receipt.balance_updates_encoding); + select = + (function + | Contents_result (Activate_account_result _ as op) -> Some op + | _ -> None); + mselect = + (function + | Contents_and_result ((Activate_account _ as op), res) -> + Some (op, res) + | _ -> None); + proj = (fun (Activate_account_result bus) -> bus); + inj = (fun bus -> Activate_account_result bus); + } + + let[@coq_axiom_with_reason "gadt"] proposals_case = + Case + { + op_case = Operation.Encoding.proposals_case; + encoding = Data_encoding.empty; + select = + (function + | Contents_result (Proposals_result as op) -> Some op | _ -> None); + mselect = + (function + | Contents_and_result ((Proposals _ as op), res) -> Some (op, res) + | _ -> None); + proj = (fun Proposals_result -> ()); + inj = (fun () -> Proposals_result); + } + + let[@coq_axiom_with_reason "gadt"] ballot_case = + Case + { + op_case = Operation.Encoding.ballot_case; + encoding = Data_encoding.empty; + select = + (function + | Contents_result (Ballot_result as op) -> Some op | _ -> None); + mselect = + (function + | Contents_and_result ((Ballot _ as op), res) -> Some (op, res) + | _ -> None); + proj = (fun Ballot_result -> ()); + inj = (fun () -> Ballot_result); + } + + let[@coq_axiom_with_reason "gadt"] make_manager_case (type kind) + (Operation.Encoding.Case op_case : + kind Kind.manager Operation.Encoding.case) + (Manager_result.MCase res_case : kind Manager_result.case) mselect = + Case + { + op_case = Operation.Encoding.Case op_case; + encoding = + obj3 + (req "balance_updates" Receipt.balance_updates_encoding) + (req "operation_result" res_case.t) + (dft + "internal_operation_results" + (list internal_operation_result_encoding) + []); + select = + (function + | Contents_result + (Manager_operation_result + ({operation_result = Applied res; _} as op)) -> ( + match res_case.select (Successful_manager_result res) with + | Some res -> + Some + (Manager_operation_result + {op with operation_result = Applied res}) + | None -> None) + | Contents_result + (Manager_operation_result + ({operation_result = Backtracked (res, errs); _} as op)) -> ( + match res_case.select (Successful_manager_result res) with + | Some res -> + Some + (Manager_operation_result + {op with operation_result = Backtracked (res, errs)}) + | None -> None) + | Contents_result + (Manager_operation_result + ({operation_result = Skipped kind; _} as op)) -> ( + match equal_manager_kind kind res_case.kind with + | None -> None + | Some Eq -> + Some + (Manager_operation_result + {op with operation_result = Skipped kind})) + | Contents_result + (Manager_operation_result + ({operation_result = Failed (kind, errs); _} as op)) -> ( + match equal_manager_kind kind res_case.kind with + | None -> None + | Some Eq -> + Some + (Manager_operation_result + {op with operation_result = Failed (kind, errs)})) + | Contents_result Ballot_result -> None + | Contents_result (Endorsement_result _) -> None + | Contents_result (Seed_nonce_revelation_result _) -> None + | Contents_result (Endorsement_with_slot_result _) -> None + | Contents_result (Double_endorsement_evidence_result _) -> None + | Contents_result (Double_baking_evidence_result _) -> None + | Contents_result (Activate_account_result _) -> None + | Contents_result Proposals_result -> None); + mselect; + proj = + (fun (Manager_operation_result + { + balance_updates = bus; + operation_result = r; + internal_operation_results = rs; + }) -> + (bus, r, rs)); + inj = + (fun (bus, r, rs) -> + Manager_operation_result + { + balance_updates = bus; + operation_result = r; + internal_operation_results = rs; + }); + } + + let[@coq_axiom_with_reason "gadt"] reveal_case = + make_manager_case + Operation.Encoding.reveal_case + Manager_result.reveal_case + (function + | Contents_and_result + ((Manager_operation {operation = Reveal _; _} as op), res) -> + Some (op, res) + | _ -> None) + + let[@coq_axiom_with_reason "gadt"] transaction_case = + make_manager_case + Operation.Encoding.transaction_case + Manager_result.transaction_case + (function + | Contents_and_result + ((Manager_operation {operation = Transaction _; _} as op), res) -> + Some (op, res) + | _ -> None) + + let[@coq_axiom_with_reason "gadt"] origination_case = + make_manager_case + Operation.Encoding.origination_case + Manager_result.origination_case + (function + | Contents_and_result + ((Manager_operation {operation = Origination _; _} as op), res) -> + Some (op, res) + | _ -> None) + + let[@coq_axiom_with_reason "gadt"] delegation_case = + make_manager_case + Operation.Encoding.delegation_case + Manager_result.delegation_case + (function + | Contents_and_result + ((Manager_operation {operation = Delegation _; _} as op), res) -> + Some (op, res) + | _ -> None) + + let[@coq_axiom_with_reason "gadt"] register_global_constant_case = + make_manager_case + Operation.Encoding.register_global_constant_case + Manager_result.register_global_constant_case + (function + | Contents_and_result + ( (Manager_operation {operation = Register_global_constant _; _} as + op), + res ) -> + Some (op, res) + | _ -> None) +end + +let contents_result_encoding = + let open Encoding in + let make + (Case + { + op_case = Operation.Encoding.Case {tag; name; _}; + encoding; + mselect = _; + select; + proj; + inj; + }) = + let proj x = match select x with None -> None | Some x -> Some (proj x) in + let inj x = Contents_result (inj x) in + tagged_case (Tag tag) name encoding proj inj + in + def "operation.alpha.contents_result" + @@ union + [ + make endorsement_case; + make seed_nonce_revelation_case; + make endorsement_with_slot_case; + make double_endorsement_evidence_case; + make double_baking_evidence_case; + make activate_account_case; + make proposals_case; + make ballot_case; + make reveal_case; + make transaction_case; + make origination_case; + make delegation_case; + make register_global_constant_case; + ] + +let contents_and_result_encoding = + let open Encoding in + let make + (Case + { + op_case = Operation.Encoding.Case {tag; name; encoding; proj; inj; _}; + mselect; + encoding = meta_encoding; + proj = meta_proj; + inj = meta_inj; + _; + }) = + let proj c = + match mselect c with + | Some (op, res) -> Some (proj op, meta_proj res) + | _ -> None + in + let inj (op, res) = Contents_and_result (inj op, meta_inj res) in + let encoding = merge_objs encoding (obj1 (req "metadata" meta_encoding)) in + tagged_case (Tag tag) name encoding proj inj + in + def "operation.alpha.operation_contents_and_result" + @@ union + [ + make endorsement_case; + make seed_nonce_revelation_case; + make endorsement_with_slot_case; + make double_endorsement_evidence_case; + make double_baking_evidence_case; + make activate_account_case; + make proposals_case; + make ballot_case; + make reveal_case; + make transaction_case; + make origination_case; + make delegation_case; + make register_global_constant_case; + ] + +type 'kind contents_result_list = + | Single_result : 'kind contents_result -> 'kind contents_result_list + | Cons_result : + 'kind Kind.manager contents_result + * 'rest Kind.manager contents_result_list + -> ('kind * 'rest) Kind.manager contents_result_list + +type packed_contents_result_list = + | Contents_result_list : + 'kind contents_result_list + -> packed_contents_result_list + +let contents_result_list_encoding = + let rec to_list = function + | Contents_result_list (Single_result o) -> [Contents_result o] + | Contents_result_list (Cons_result (o, os)) -> + Contents_result o :: to_list (Contents_result_list os) + in + let rec of_list = function + | [] -> Error "cannot decode empty operation result" + | [Contents_result o] -> Ok (Contents_result_list (Single_result o)) + | Contents_result o :: os -> ( + of_list os >>? fun (Contents_result_list os) -> + match (o, os) with + | ( Manager_operation_result _, + Single_result (Manager_operation_result _) ) -> + Ok (Contents_result_list (Cons_result (o, os))) + | (Manager_operation_result _, Cons_result _) -> + Ok (Contents_result_list (Cons_result (o, os))) + | _ -> Error "cannot decode ill-formed operation result") + in + def "operation.alpha.contents_list_result" + @@ conv_with_guard to_list of_list (list contents_result_encoding) + +type 'kind contents_and_result_list = + | Single_and_result : + 'kind Alpha_context.contents * 'kind contents_result + -> 'kind contents_and_result_list + | Cons_and_result : + 'kind Kind.manager Alpha_context.contents + * 'kind Kind.manager contents_result + * 'rest Kind.manager contents_and_result_list + -> ('kind * 'rest) Kind.manager contents_and_result_list + +type packed_contents_and_result_list = + | Contents_and_result_list : + 'kind contents_and_result_list + -> packed_contents_and_result_list + +let contents_and_result_list_encoding = + let rec to_list = function + | Contents_and_result_list (Single_and_result (op, res)) -> + [Contents_and_result (op, res)] + | Contents_and_result_list (Cons_and_result (op, res, rest)) -> + Contents_and_result (op, res) :: to_list (Contents_and_result_list rest) + in + let rec of_list = function + | [] -> Error "cannot decode empty combined operation result" + | [Contents_and_result (op, res)] -> + Ok (Contents_and_result_list (Single_and_result (op, res))) + | Contents_and_result (op, res) :: rest -> ( + of_list rest >>? fun (Contents_and_result_list rest) -> + match (op, rest) with + | (Manager_operation _, Single_and_result (Manager_operation _, _)) -> + Ok (Contents_and_result_list (Cons_and_result (op, res, rest))) + | (Manager_operation _, Cons_and_result (_, _, _)) -> + Ok (Contents_and_result_list (Cons_and_result (op, res, rest))) + | _ -> Error "cannot decode ill-formed combined operation result") + in + conv_with_guard to_list of_list (Variable.list contents_and_result_encoding) + +type 'kind operation_metadata = {contents : 'kind contents_result_list} + +type packed_operation_metadata = + | Operation_metadata : 'kind operation_metadata -> packed_operation_metadata + | No_operation_metadata : packed_operation_metadata + +let operation_metadata_encoding = + def "operation.alpha.result" + @@ union + [ + case + (Tag 0) + ~title:"Operation_metadata" + contents_result_list_encoding + (function + | Operation_metadata {contents} -> + Some (Contents_result_list contents) + | _ -> None) + (fun (Contents_result_list contents) -> + Operation_metadata {contents}); + case + (Tag 1) + ~title:"No_operation_metadata" + empty + (function No_operation_metadata -> Some () | _ -> None) + (fun () -> No_operation_metadata); + ] + +let kind_equal : + type kind kind2. + kind contents -> kind2 contents_result -> (kind, kind2) eq option = + fun op res -> + match (op, res) with + | (Endorsement _, Endorsement_result _) -> Some Eq + | (Endorsement _, _) -> None + | (Seed_nonce_revelation _, Seed_nonce_revelation_result _) -> Some Eq + | (Seed_nonce_revelation _, _) -> None + | (Endorsement_with_slot _, Endorsement_with_slot_result _) -> Some Eq + | (Endorsement_with_slot _, _) -> None + | (Double_endorsement_evidence _, Double_endorsement_evidence_result _) -> + Some Eq + | (Double_endorsement_evidence _, _) -> None + | (Double_baking_evidence _, Double_baking_evidence_result _) -> Some Eq + | (Double_baking_evidence _, _) -> None + | (Activate_account _, Activate_account_result _) -> Some Eq + | (Activate_account _, _) -> None + | (Proposals _, Proposals_result) -> Some Eq + | (Proposals _, _) -> None + | (Ballot _, Ballot_result) -> Some Eq + | (Ballot _, _) -> None + | (Failing_noop _, _) -> + (* the Failing_noop operation always fails and can't have result *) + None + | ( Manager_operation {operation = Reveal _; _}, + Manager_operation_result {operation_result = Applied (Reveal_result _); _} + ) -> + Some Eq + | ( Manager_operation {operation = Reveal _; _}, + Manager_operation_result + {operation_result = Backtracked (Reveal_result _, _); _} ) -> + Some Eq + | ( Manager_operation {operation = Reveal _; _}, + Manager_operation_result + { + operation_result = Failed (Alpha_context.Kind.Reveal_manager_kind, _); + _; + } ) -> + Some Eq + | ( Manager_operation {operation = Reveal _; _}, + Manager_operation_result + {operation_result = Skipped Alpha_context.Kind.Reveal_manager_kind; _} + ) -> + Some Eq + | (Manager_operation {operation = Reveal _; _}, _) -> None + | ( Manager_operation {operation = Transaction _; _}, + Manager_operation_result + {operation_result = Applied (Transaction_result _); _} ) -> + Some Eq + | ( Manager_operation {operation = Transaction _; _}, + Manager_operation_result + {operation_result = Backtracked (Transaction_result _, _); _} ) -> + Some Eq + | ( Manager_operation {operation = Transaction _; _}, + Manager_operation_result + { + operation_result = + Failed (Alpha_context.Kind.Transaction_manager_kind, _); + _; + } ) -> + Some Eq + | ( Manager_operation {operation = Transaction _; _}, + Manager_operation_result + { + operation_result = Skipped Alpha_context.Kind.Transaction_manager_kind; + _; + } ) -> + Some Eq + | (Manager_operation {operation = Transaction _; _}, _) -> None + | ( Manager_operation {operation = Origination _; _}, + Manager_operation_result + {operation_result = Applied (Origination_result _); _} ) -> + Some Eq + | ( Manager_operation {operation = Origination _; _}, + Manager_operation_result + {operation_result = Backtracked (Origination_result _, _); _} ) -> + Some Eq + | ( Manager_operation {operation = Origination _; _}, + Manager_operation_result + { + operation_result = + Failed (Alpha_context.Kind.Origination_manager_kind, _); + _; + } ) -> + Some Eq + | ( Manager_operation {operation = Origination _; _}, + Manager_operation_result + { + operation_result = Skipped Alpha_context.Kind.Origination_manager_kind; + _; + } ) -> + Some Eq + | (Manager_operation {operation = Origination _; _}, _) -> None + | ( Manager_operation {operation = Delegation _; _}, + Manager_operation_result + {operation_result = Applied (Delegation_result _); _} ) -> + Some Eq + | ( Manager_operation {operation = Delegation _; _}, + Manager_operation_result + {operation_result = Backtracked (Delegation_result _, _); _} ) -> + Some Eq + | ( Manager_operation {operation = Delegation _; _}, + Manager_operation_result + { + operation_result = + Failed (Alpha_context.Kind.Delegation_manager_kind, _); + _; + } ) -> + Some Eq + | ( Manager_operation {operation = Delegation _; _}, + Manager_operation_result + { + operation_result = Skipped Alpha_context.Kind.Delegation_manager_kind; + _; + } ) -> + Some Eq + | (Manager_operation {operation = Delegation _; _}, _) -> None + | ( Manager_operation {operation = Register_global_constant _; _}, + Manager_operation_result + {operation_result = Applied (Register_global_constant_result _); _} ) -> + Some Eq + | ( Manager_operation {operation = Register_global_constant _; _}, + Manager_operation_result + { + operation_result = Backtracked (Register_global_constant_result _, _); + _; + } ) -> + Some Eq + | ( Manager_operation {operation = Register_global_constant _; _}, + Manager_operation_result + { + operation_result = + Failed (Alpha_context.Kind.Register_global_constant_manager_kind, _); + _; + } ) -> + Some Eq + | ( Manager_operation {operation = Register_global_constant _; _}, + Manager_operation_result + { + operation_result = + Skipped Alpha_context.Kind.Register_global_constant_manager_kind; + _; + } ) -> + Some Eq + | (Manager_operation {operation = Register_global_constant _; _}, _) -> None + +let rec kind_equal_list : + type kind kind2. + kind contents_list -> kind2 contents_result_list -> (kind, kind2) eq option + = + fun contents res -> + match (contents, res) with + | (Single op, Single_result res) -> ( + match kind_equal op res with None -> None | Some Eq -> Some Eq) + | (Cons (op, ops), Cons_result (res, ress)) -> ( + match kind_equal op res with + | None -> None + | Some Eq -> ( + match kind_equal_list ops ress with + | None -> None + | Some Eq -> Some Eq)) + | _ -> None + +let[@coq_axiom_with_reason "gadt"] rec pack_contents_list : + type kind. + kind contents_list -> + kind contents_result_list -> + kind contents_and_result_list = + fun contents res -> + match (contents, res) with + | (Single op, Single_result res) -> Single_and_result (op, res) + | (Cons (op, ops), Cons_result (res, ress)) -> + Cons_and_result (op, res, pack_contents_list ops ress) + | ( Single (Manager_operation _), + Cons_result (Manager_operation_result _, Single_result _) ) -> + . + | ( Cons (_, _), + Single_result (Manager_operation_result {operation_result = Failed _; _}) + ) -> + . + | ( Cons (_, _), + Single_result (Manager_operation_result {operation_result = Skipped _; _}) + ) -> + . + | ( Cons (_, _), + Single_result (Manager_operation_result {operation_result = Applied _; _}) + ) -> + . + | ( Cons (_, _), + Single_result + (Manager_operation_result {operation_result = Backtracked _; _}) ) -> + . + | (Single _, Cons_result _) -> . + +let rec unpack_contents_list : + type kind. + kind contents_and_result_list -> + kind contents_list * kind contents_result_list = function + | Single_and_result (op, res) -> (Single op, Single_result res) + | Cons_and_result (op, res, rest) -> + let (ops, ress) = unpack_contents_list rest in + (Cons (op, ops), Cons_result (res, ress)) + +let rec to_list = function + | Contents_result_list (Single_result o) -> [Contents_result o] + | Contents_result_list (Cons_result (o, os)) -> + Contents_result o :: to_list (Contents_result_list os) + +let operation_data_and_metadata_encoding = + def "operation.alpha.operation_with_metadata" + @@ union + [ + case + (Tag 0) + ~title:"Operation_with_metadata" + (obj2 + (req "contents" (dynamic_size contents_and_result_list_encoding)) + (opt "signature" Signature.encoding)) + (function + | (Operation_data _, No_operation_metadata) -> None + | (Operation_data op, Operation_metadata res) -> ( + match kind_equal_list op.contents res.contents with + | None -> + Pervasives.failwith + "cannot decode inconsistent combined operation result" + | Some Eq -> + Some + ( Contents_and_result_list + (pack_contents_list op.contents res.contents), + op.signature ))) + (fun (Contents_and_result_list contents, signature) -> + let (op_contents, res_contents) = unpack_contents_list contents in + ( Operation_data {contents = op_contents; signature}, + Operation_metadata {contents = res_contents} )); + case + (Tag 1) + ~title:"Operation_without_metadata" + (obj2 + (req "contents" (dynamic_size Operation.contents_list_encoding)) + (opt "signature" Signature.encoding)) + (function + | (Operation_data op, No_operation_metadata) -> + Some (Contents_list op.contents, op.signature) + | (Operation_data _, Operation_metadata _) -> None) + (fun (Contents_list contents, signature) -> + (Operation_data {contents; signature}, No_operation_metadata)); + ] + +type block_metadata = { + baker : Signature.Public_key_hash.t; + level_info : Level.t; + voting_period_info : Voting_period.info; + nonce_hash : Nonce_hash.t option; + consumed_gas : Gas.Arith.fp; + deactivated : Signature.Public_key_hash.t list; + balance_updates : Receipt.balance_updates; + liquidity_baking_escape_ema : Liquidity_baking.escape_ema; + implicit_operations_results : packed_successful_manager_operation_result list; +} + +let block_metadata_encoding = + let open Data_encoding in + def "block_header.alpha.metadata" + @@ conv + (fun { + baker; + level_info; + voting_period_info; + nonce_hash; + consumed_gas; + deactivated; + balance_updates; + liquidity_baking_escape_ema; + implicit_operations_results; + } -> + ( baker, + level_info, + voting_period_info, + nonce_hash, + consumed_gas, + deactivated, + balance_updates, + liquidity_baking_escape_ema, + implicit_operations_results )) + (fun ( baker, + level_info, + voting_period_info, + nonce_hash, + consumed_gas, + deactivated, + balance_updates, + liquidity_baking_escape_ema, + implicit_operations_results ) -> + { + baker; + level_info; + voting_period_info; + nonce_hash; + consumed_gas; + deactivated; + balance_updates; + liquidity_baking_escape_ema; + implicit_operations_results; + }) + (obj9 + (req "baker" Signature.Public_key_hash.encoding) + (req "level_info" Level.encoding) + (req "voting_period_info" Voting_period.info_encoding) + (req "nonce_hash" (option Nonce_hash.encoding)) + (req "consumed_gas" Gas.Arith.n_fp_encoding) + (req "deactivated" (list Signature.Public_key_hash.encoding)) + (req "balance_updates" Receipt.balance_updates_encoding) + (req "liquidity_baking_escape_ema" int32) + (req + "implicit_operations_results" + (list successful_manager_operation_result_encoding))) diff --git a/src/proto_011_PtHangzH/lib_protocol/apply_results.mli b/src/proto_011_PtHangzH/lib_protocol/apply_results.mli new file mode 100644 index 000000000000..cf0026c3e3dc --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/apply_results.mli @@ -0,0 +1,220 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Types representing results of applying an operation. + + These are used internally by [Apply], and can be used for experimenting + with protocol updates, by clients to print out a summary of the + operation at pre-injection simulation and at confirmation time, + and by block explorers. + *) + +open Alpha_context + +(** Result of applying a {!Operation.t}. Follows the same structure. *) +type 'kind operation_metadata = {contents : 'kind contents_result_list} + +and packed_operation_metadata = + | Operation_metadata : 'kind operation_metadata -> packed_operation_metadata + | No_operation_metadata : packed_operation_metadata + +(** Result of applying a {!Operation.contents_list}. Follows the same structure. *) +and 'kind contents_result_list = + | Single_result : 'kind contents_result -> 'kind contents_result_list + | Cons_result : + 'kind Kind.manager contents_result + * 'rest Kind.manager contents_result_list + -> ('kind * 'rest) Kind.manager contents_result_list + +and packed_contents_result_list = + | Contents_result_list : + 'kind contents_result_list + -> packed_contents_result_list + +(** Result of applying an {!Operation.contents}. Follows the same structure. *) +and 'kind contents_result = + | Endorsement_result : { + balance_updates : Receipt.balance_updates; + delegate : Signature.Public_key_hash.t; + slots : int list; + } + -> Kind.endorsement contents_result + | Seed_nonce_revelation_result : + Receipt.balance_updates + -> Kind.seed_nonce_revelation contents_result + | Endorsement_with_slot_result : + Kind.endorsement contents_result + -> Kind.endorsement_with_slot contents_result + | Double_endorsement_evidence_result : + Receipt.balance_updates + -> Kind.double_endorsement_evidence contents_result + | Double_baking_evidence_result : + Receipt.balance_updates + -> Kind.double_baking_evidence contents_result + | Activate_account_result : + Receipt.balance_updates + -> Kind.activate_account contents_result + | Proposals_result : Kind.proposals contents_result + | Ballot_result : Kind.ballot contents_result + | Manager_operation_result : { + balance_updates : Receipt.balance_updates; + operation_result : 'kind manager_operation_result; + internal_operation_results : packed_internal_operation_result list; + } + -> 'kind Kind.manager contents_result + +and packed_contents_result = + | Contents_result : 'kind contents_result -> packed_contents_result + +(** The result of an operation in the queue. [Skipped] ones should + always be at the tail, and after a single [Failed]. *) +and 'kind manager_operation_result = + | Applied of 'kind successful_manager_operation_result + | Backtracked of + 'kind successful_manager_operation_result * error trace option + | Failed : 'kind Kind.manager * error trace -> 'kind manager_operation_result + | Skipped : 'kind Kind.manager -> 'kind manager_operation_result +[@@coq_force_gadt] + +(** Result of applying a {!manager_operation_content}, either internal + or external. *) +and _ successful_manager_operation_result = + | Reveal_result : { + consumed_gas : Gas.Arith.fp; + } + -> Kind.reveal successful_manager_operation_result + | Transaction_result : { + storage : Script.expr option; + lazy_storage_diff : Lazy_storage.diffs option; + balance_updates : Receipt.balance_updates; + originated_contracts : Contract.t list; + consumed_gas : Gas.Arith.fp; + storage_size : Z.t; + paid_storage_size_diff : Z.t; + allocated_destination_contract : bool; + } + -> Kind.transaction successful_manager_operation_result + | Origination_result : { + lazy_storage_diff : Lazy_storage.diffs option; + balance_updates : Receipt.balance_updates; + originated_contracts : Contract.t list; + consumed_gas : Gas.Arith.fp; + storage_size : Z.t; + paid_storage_size_diff : Z.t; + } + -> Kind.origination successful_manager_operation_result + | Delegation_result : { + consumed_gas : Gas.Arith.fp; + } + -> Kind.delegation successful_manager_operation_result + | Register_global_constant_result : { + (* The manager submitting the operation must pay + the cost of storage for the registered value. + We include the balance update here. *) + balance_updates : Receipt.balance_updates; + (* Gas consumed while validating and storing the registered + value. *) + consumed_gas : Gas.Arith.fp; + (* The size of the registered value in bytes. + Currently, this is simply the number of bytes in the binary + serialization of the Micheline value. *) + size_of_constant : Z.t; + (* The address of the newly registered value, being + the hash of its binary serialization. This could be + calulated on demand but we include it here in the + receipt for flexibility in the future. *) + global_address : Script_expr_hash.t; + } + -> Kind.register_global_constant successful_manager_operation_result + +and packed_successful_manager_operation_result = + | Successful_manager_result : + 'kind successful_manager_operation_result + -> packed_successful_manager_operation_result + +and packed_internal_operation_result = + | Internal_operation_result : + 'kind internal_operation * 'kind manager_operation_result + -> packed_internal_operation_result + +val pack_migration_operation_results : + Migration.origination_result list -> + packed_successful_manager_operation_result list + +(** Serializer for {!packed_operation_result}. *) +val operation_metadata_encoding : packed_operation_metadata Data_encoding.t + +val operation_data_and_metadata_encoding : + (Operation.packed_protocol_data * packed_operation_metadata) Data_encoding.t + +type 'kind contents_and_result_list = + | Single_and_result : + 'kind Alpha_context.contents * 'kind contents_result + -> 'kind contents_and_result_list + | Cons_and_result : + 'kind Kind.manager Alpha_context.contents + * 'kind Kind.manager contents_result + * 'rest Kind.manager contents_and_result_list + -> ('kind * 'rest) Kind.manager contents_and_result_list + +type packed_contents_and_result_list = + | Contents_and_result_list : + 'kind contents_and_result_list + -> packed_contents_and_result_list + +val contents_and_result_list_encoding : + packed_contents_and_result_list Data_encoding.t + +val pack_contents_list : + 'kind contents_list -> + 'kind contents_result_list -> + 'kind contents_and_result_list + +val unpack_contents_list : + 'kind contents_and_result_list -> + 'kind contents_list * 'kind contents_result_list + +val to_list : packed_contents_result_list -> packed_contents_result list + +type ('a, 'b) eq = Eq : ('a, 'a) eq + +val kind_equal_list : + 'kind contents_list -> + 'kind2 contents_result_list -> + ('kind, 'kind2) eq option + +type block_metadata = { + baker : Signature.Public_key_hash.t; + level_info : Level.t; + voting_period_info : Voting_period.info; + nonce_hash : Nonce_hash.t option; + consumed_gas : Gas.Arith.fp; + deactivated : Signature.Public_key_hash.t list; + balance_updates : Receipt.balance_updates; + liquidity_baking_escape_ema : Liquidity_baking.escape_ema; + implicit_operations_results : packed_successful_manager_operation_result list; +} + +val block_metadata_encoding : block_metadata Data_encoding.encoding diff --git a/src/proto_011_PtHangzH/lib_protocol/baking.ml b/src/proto_011_PtHangzH/lib_protocol/baking.ml new file mode 100644 index 000000000000..2e6b6c6532e2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/baking.ml @@ -0,0 +1,467 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Misc + +type error += Invalid_fitness_gap of int64 * int64 (* `Permanent *) + +type error += + | Timestamp_too_early of { + minimal_time : Timestamp.t; + provided_time : Timestamp.t; + priority : int; + endorsing_power_opt : int option; + } + +(* `Permanent *) + +type error += Unexpected_endorsement (* `Permanent *) + +type error += Invalid_endorsement_slot of int (* `Permanent *) + +type error += Unexpected_endorsement_slot of int (* `Permanent *) + +type error += + | Invalid_block_signature of Block_hash.t * Signature.Public_key_hash.t + +(* `Permanent *) + +type error += Invalid_signature (* `Permanent *) + +type error += Invalid_stamp (* `Permanent *) + +let () = + register_error_kind + `Permanent + ~id:"baking.timestamp_too_early" + ~title:"Block forged too early" + ~description:"The block timestamp is before the minimal valid one." + ~pp:(fun ppf (minimal_time, provided_time, priority, endorsing_power) -> + let message_regarding_endorsements = + match endorsing_power with + | None -> "" + | Some power -> Format.asprintf " and endorsing power %d" power + in + Format.fprintf + ppf + "Block forged too early: %a is before the minimal time %a for priority \ + %d%s)" + Time.pp_hum + provided_time + Time.pp_hum + minimal_time + priority + message_regarding_endorsements) + Data_encoding.( + obj4 + (req "minimal_time" Time.encoding) + (req "provided_time" Time.encoding) + (req "priority" int31) + (opt "endorsing_power" int31)) + (function + | Timestamp_too_early + {minimal_time; provided_time; priority; endorsing_power_opt} -> + Some (minimal_time, provided_time, priority, endorsing_power_opt) + | _ -> None) + (fun (minimal_time, provided_time, priority, endorsing_power_opt) -> + Timestamp_too_early + {minimal_time; provided_time; priority; endorsing_power_opt}) ; + register_error_kind + `Permanent + ~id:"baking.invalid_fitness_gap" + ~title:"Invalid fitness gap" + ~description:"The gap of fitness is out of bounds" + ~pp:(fun ppf (m, g) -> + Format.fprintf ppf "The gap of fitness %Ld is not between 0 and %Ld" g m) + Data_encoding.(obj2 (req "maximum" int64) (req "provided" int64)) + (function Invalid_fitness_gap (m, g) -> Some (m, g) | _ -> None) + (fun (m, g) -> Invalid_fitness_gap (m, g)) ; + register_error_kind + `Permanent + ~id:"baking.invalid_block_signature" + ~title:"Invalid block signature" + ~description:"A block was not signed with the expected private key." + ~pp:(fun ppf (block, pkh) -> + Format.fprintf + ppf + "Invalid signature for block %a. Expected: %a." + Block_hash.pp_short + block + Signature.Public_key_hash.pp_short + pkh) + Data_encoding.( + obj2 + (req "block" Block_hash.encoding) + (req "expected" Signature.Public_key_hash.encoding)) + (function + | Invalid_block_signature (block, pkh) -> Some (block, pkh) | _ -> None) + (fun (block, pkh) -> Invalid_block_signature (block, pkh)) ; + register_error_kind + `Permanent + ~id:"baking.invalid_signature" + ~title:"Invalid block signature" + ~description:"The block's signature is invalid" + ~pp:(fun ppf () -> Format.fprintf ppf "Invalid block signature") + Data_encoding.empty + (function Invalid_signature -> Some () | _ -> None) + (fun () -> Invalid_signature) ; + register_error_kind + `Permanent + ~id:"baking.insufficient_proof_of_work" + ~title:"Insufficient block proof-of-work stamp" + ~description:"The block's proof-of-work stamp is insufficient" + ~pp:(fun ppf () -> Format.fprintf ppf "Insufficient proof-of-work stamp") + Data_encoding.empty + (function Invalid_stamp -> Some () | _ -> None) + (fun () -> Invalid_stamp) ; + register_error_kind + `Permanent + ~id:"baking.unexpected_endorsement" + ~title:"Endorsement from unexpected delegate" + ~description: + "The operation is signed by a delegate without endorsement rights." + ~pp:(fun ppf () -> + Format.fprintf + ppf + "The endorsement is signed by a delegate without endorsement rights.") + Data_encoding.unit + (function Unexpected_endorsement -> Some () | _ -> None) + (fun () -> Unexpected_endorsement) ; + register_error_kind + `Permanent + ~id:"baking.invalid_endorsement_slot" + ~title:"Endorsement slot out of range" + ~description:"The endorsement slot provided is negative or too high." + ~pp:(fun ppf v -> + Format.fprintf + ppf + "Endorsement slot %d provided is negative or too high." + v) + Data_encoding.(obj1 (req "slot" uint16)) + (function Invalid_endorsement_slot v -> Some v | _ -> None) + (fun v -> Invalid_endorsement_slot v) ; + register_error_kind + `Permanent + ~id:"baking.unexpected_endorsement_slot" + ~title:"Endorsement slot not the smallest possible" + ~description:"The endorsement slot provided is not the smallest possible." + ~pp:(fun ppf v -> + Format.fprintf + ppf + "Endorsement slot %d provided is not the smallest possible." + v) + Data_encoding.(obj1 (req "slot" uint16)) + (function Unexpected_endorsement_slot v -> Some v | _ -> None) + (fun v -> Unexpected_endorsement_slot v) + +(* The function implements the fast-path case in [minimal_time]. (See + [minimal_valid_time] for the definition of the fast-path.) *) +let minimal_time_fastpath_case minimal_block_delay pred_timestamp = + Timestamp.(pred_timestamp +? minimal_block_delay) + +(* The function implements the slow-path case in [minimal_time]. (See + [minimal_valid_time] for the definition of the slow-path.) *) +let minimal_time_slowpath_case time_between_blocks priority pred_timestamp = + let[@coq_struct "durations"] rec cumsum_time_between_blocks acc durations p = + if Compare.Int32.( <= ) p 0l then ok acc + else + match durations with + | [] -> cumsum_time_between_blocks acc [Period.one_minute] p + | [last] -> Period.mult p last >>? fun period -> Timestamp.(acc +? period) + | first :: durations -> + Timestamp.(acc +? first) >>? fun acc -> + let p = Int32.pred p in + cumsum_time_between_blocks acc durations p + in + cumsum_time_between_blocks + pred_timestamp + time_between_blocks + (Int32.succ priority) + +let minimal_time constants ~priority pred_timestamp = + let priority = Int32.of_int priority in + if Compare.Int32.(priority = 0l) then + minimal_time_fastpath_case + constants.Constants.minimal_block_delay + pred_timestamp + else + minimal_time_slowpath_case + constants.time_between_blocks + priority + pred_timestamp + +let earlier_predecessor_timestamp ctxt level = + let current = Level.current ctxt in + let current_timestamp = Timestamp.current ctxt in + let gap = Level.diff level current in + let step = Constants.minimal_block_delay ctxt in + if Compare.Int32.(gap < 1l) then + failwith "Baking.earlier_block_timestamp: past block." + else + Period.mult (Int32.pred gap) step >>? fun delay -> + Timestamp.(current_timestamp +? delay) + +let check_timestamp c ~priority pred_timestamp = + minimal_time (Constants.parametric c) ~priority pred_timestamp + >>? fun minimal_time -> + let timestamp = Timestamp.current c in + record_trace + (Timestamp_too_early + { + minimal_time; + provided_time = timestamp; + priority; + endorsing_power_opt = None; + }) + Timestamp.(timestamp -? minimal_time) + >>? fun _block_delay -> ok () + +type error += Incorrect_priority (* `Permanent *) + +type error += Incorrect_number_of_endorsements (* `Permanent *) + +let () = + register_error_kind + `Permanent + ~id:"incorrect_priority" + ~title:"Incorrect priority" + ~description:"Block priority must be non-negative." + ~pp:(fun ppf () -> + Format.fprintf ppf "The block priority must be non-negative.") + Data_encoding.unit + (function Incorrect_priority -> Some () | _ -> None) + (fun () -> Incorrect_priority) + +let () = + let description = + "The number of endorsements must be non-negative and at most the \ + endorsers_per_block constant." + in + register_error_kind + `Permanent + ~id:"incorrect_number_of_endorsements" + ~title:"Incorrect number of endorsements" + ~description + ~pp:(fun ppf () -> Format.fprintf ppf "%s" description) + Data_encoding.unit + (function Incorrect_number_of_endorsements -> Some () | _ -> None) + (fun () -> Incorrect_number_of_endorsements) + +let rec reward_for_priority reward_per_prio prio = + match reward_per_prio with + | [] -> + (* Empty reward list in parameters means no rewards *) + Tez.zero + | [last] -> last + | first :: rest -> + if Compare.Int.(prio <= 0) then first + else reward_for_priority rest (pred prio) + +let baking_reward ctxt ~block_priority ~included_endorsements = + error_unless Compare.Int.(block_priority >= 0) Incorrect_priority + >>? fun () -> + error_unless + Compare.Int.( + included_endorsements >= 0 + && included_endorsements <= Constants.endorsers_per_block ctxt) + Incorrect_number_of_endorsements + >>? fun () -> + let reward_per_endorsement = + reward_for_priority + (Constants.baking_reward_per_endorsement ctxt) + block_priority + in + Tez.(reward_per_endorsement *? Int64.of_int included_endorsements) + +let endorsing_reward ctxt ~block_priority num_slots = + error_unless Compare.Int.(block_priority >= 0) Incorrect_priority + >>? fun () -> + let reward_per_endorsement = + reward_for_priority (Constants.endorsement_reward ctxt) block_priority + in + Tez.(reward_per_endorsement *? Int64.of_int num_slots) + +let baking_priorities c level = + let rec f priority = + Roll.baking_rights_owner c level ~priority >|=? fun delegate -> + LCons (delegate, fun () -> f (succ priority)) + in + f 0 + +let endorsement_rights ctxt level = + List.fold_right_es + (fun slot acc -> + Roll.endorsement_rights_owner ctxt level ~slot >|=? fun pk -> + let pkh = Signature.Public_key.hash pk in + let right = + match Signature.Public_key_hash.Map.find pkh acc with + | None -> (pk, [slot], false) + | Some (pk, slots, used) -> (pk, slot :: slots, used) + in + Signature.Public_key_hash.Map.add pkh right acc) + (0 --> (Constants.endorsers_per_block ctxt - 1)) + Signature.Public_key_hash.Map.empty + +let[@coq_axiom_with_reason "gadt"] check_endorsement_right ctxt chain_id ~slot + (op : Kind.endorsement Operation.t) = + if + Compare.Int.(slot < 0 (* should not happen because of binary format *)) + || Compare.Int.(slot >= Constants.endorsers_per_block ctxt) + then fail (Invalid_endorsement_slot slot) + else + let (Single (Endorsement {level; _})) = op.protocol_data.contents in + Roll.endorsement_rights_owner ctxt (Level.from_raw ctxt level) ~slot + >>=? fun pk -> + let pkh = Signature.Public_key.hash pk in + match Operation.check_signature pk chain_id op with + | Error _ -> fail Unexpected_endorsement + | Ok () -> return pkh + +let check_endorsement_slots_at_current_level ctxt ~slot pkh = + let endorsements = Alpha_context.allowed_endorsements ctxt in + match Signature.Public_key_hash.Map.find pkh endorsements with + | None -> fail Unexpected_endorsement (* unexpected *) + | Some (_pk, (top_slot :: _ as slots), v) -> + error_unless + Compare.Int.(slot = top_slot) + (Unexpected_endorsement_slot slot) + >>?= fun () -> return (slots, v) + | Some (_pk, [], _) -> fail (Unexpected_endorsement_slot slot) + +let select_delegate delegate delegate_list max_priority = + let rec loop acc l n = + if Compare.Int.(n >= max_priority) then return (List.rev acc) + else + let (LCons (pk, t)) = l in + let acc = + if + Signature.Public_key_hash.equal + delegate + (Signature.Public_key.hash pk) + then n :: acc + else acc + in + t () >>=? fun t -> loop acc t (succ n) + in + loop [] delegate_list 0 + +let first_baking_priorities ctxt ?(max_priority = 32) delegate level = + baking_priorities ctxt level >>=? fun delegate_list -> + select_delegate delegate delegate_list max_priority + +let check_hash hash stamp_threshold = + let bytes = Block_hash.to_bytes hash in + let word = TzEndian.get_int64 bytes 0 in + Compare.Uint64.(word <= stamp_threshold) + +let check_header_proof_of_work_stamp shell contents stamp_threshold = + let hash = + Block_header.hash + {shell; protocol_data = {contents; signature = Signature.zero}} + in + check_hash hash stamp_threshold + +let check_proof_of_work_stamp ctxt block = + let proof_of_work_threshold = Constants.proof_of_work_threshold ctxt in + if + check_header_proof_of_work_stamp + block.Block_header.shell + block.protocol_data.contents + proof_of_work_threshold + then ok_unit + else error Invalid_stamp + +let check_signature block chain_id key = + let check_signature key + {Block_header.shell; protocol_data = {contents; signature}} = + let unsigned_header = + Data_encoding.Binary.to_bytes_exn + Block_header.unsigned_encoding + (shell, contents) + in + Signature.check + ~watermark:(Block_header chain_id) + key + signature + unsigned_header + in + if check_signature key block then return_unit + else + fail + (Invalid_block_signature + (Block_header.hash block, Signature.Public_key.hash key)) + +let max_fitness_gap _ctxt = 1L + +let check_fitness_gap ctxt (block : Block_header.t) = + let current_fitness = Fitness.current ctxt in + Fitness.to_int64 block.shell.fitness >>? fun announced_fitness -> + let gap = Int64.sub announced_fitness current_fitness in + if Compare.Int64.(gap <= 0L || max_fitness_gap ctxt < gap) then + error (Invalid_fitness_gap (max_fitness_gap ctxt, gap)) + else ok_unit + +(* The minimal threshold on the endorsing power for the fast-path case + is 60% of the maximal endorsing power. *) +let fastpath_endorsing_power_threshold maximal_endorsing_power = + 3 * maximal_endorsing_power / 5 + +(* This function computes the minimal time at which a block is + valid. It distinguishes between the "fast-path" case, when the + priority is 0 and the endorsing power is at least 60% of the + maximal endorsing power, and the "slow-path" case, when this + condition is not satisfied. *) +let minimal_valid_time constants ~priority ~endorsing_power + ~predecessor_timestamp = + if + Compare.Int.(priority = 0) + && Compare.Int.( + endorsing_power + >= fastpath_endorsing_power_threshold + constants.Constants.endorsers_per_block) + then + minimal_time_fastpath_case + constants.minimal_block_delay + predecessor_timestamp + else + minimal_time_slowpath_case + constants.time_between_blocks + (Int32.of_int priority) + predecessor_timestamp + >>? fun minimal_time -> + let delay_per_missing_endorsement = + constants.Constants.delay_per_missing_endorsement + in + let missing_endorsements = + let minimal_required_endorsements = + constants.Constants.initial_endorsers + in + Compare.Int.max 0 (minimal_required_endorsements - endorsing_power) + in + Period.mult + (Int32.of_int missing_endorsements) + delay_per_missing_endorsement + >|? fun delay -> Time.add minimal_time (Period.to_seconds delay) diff --git a/src/proto_011_PtHangzH/lib_protocol/baking.mli b/src/proto_011_PtHangzH/lib_protocol/baking.mli new file mode 100644 index 000000000000..a44c35c7bb92 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/baking.mli @@ -0,0 +1,165 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Misc + +type error += Invalid_fitness_gap of int64 * int64 (* `Permanent *) + +type error += + | Timestamp_too_early of { + minimal_time : Timestamp.t; + provided_time : Timestamp.t; + priority : int; + endorsing_power_opt : int option; + } + +(* `Permanent *) + +type error += + | Invalid_block_signature of Block_hash.t * Signature.Public_key_hash.t + +(* `Permanent *) + +type error += Unexpected_endorsement (* `Permanent *) + +type error += Invalid_endorsement_slot of int (* `Permanent *) + +type error += Unexpected_endorsement_slot of int (* `Permanent *) + +type error += Invalid_signature (* `Permanent *) + +type error += Invalid_stamp (* `Permanent *) + +(** [minimal_time ctxt priority pred_block_time] returns the minimal + time, given the predecessor block timestamp [pred_block_time], + after which a baker with priority [priority] is allowed to bake in + principle, that is, assuming the block will contain enough + endorsements. *) +val minimal_time : + Constants.parametric -> priority:int -> Time.t -> Time.t tzresult + +(** [check_timestamp ctxt priority pred_timestamp] verifies that + the timestamp is coherent with the announced baking slot. *) +val check_timestamp : context -> priority:int -> Time.t -> unit tzresult + +(** For a given level computes who has the right to + include an endorsement in the next block. + The result can be stored in Alpha_context.allowed_endorsements *) +val endorsement_rights : + context -> + Level.t -> + (public_key * int list * bool) Signature.Public_key_hash.Map.t tzresult Lwt.t + +(** Check that the operation was signed by the delegate allowed to + endorse at the given slot and at the level specified by the + endorsement. Returns the delegate. *) +val check_endorsement_right : + context -> + Chain_id.t -> + slot:int -> + Kind.endorsement Operation.t -> + public_key_hash tzresult Lwt.t + +(** Check that, at current level, the given slot is the smallest among + the delegate's slots. Returns all the slots of the delegate and "if + the slot has been used already" *) +val check_endorsement_slots_at_current_level : + context -> slot:int -> public_key_hash -> (int list * bool) tzresult Lwt.t + +(** Returns the baking reward calculated w.r.t a given priority [p] and a + number [e] of included endorsements *) +val baking_reward : + context -> block_priority:int -> included_endorsements:int -> Tez.t tzresult + +(** Returns the endorsing reward calculated w.r.t a given priority. *) +val endorsing_reward : context -> block_priority:int -> int -> Tez.t tzresult + +(** [baking_priorities ctxt level] is the lazy list of contract's + public key hashes that are allowed to bake for [level]. *) +val baking_priorities : context -> Level.t -> public_key lazy_list + +(** [first_baking_priorities ctxt ?max_priority contract_hash level] + is a list of priorities of max [?max_priority] elements, where the + delegate of [contract_hash] is allowed to bake for [level]. If + [?max_priority] is [None], a sensible number of priorities is + returned. *) +val first_baking_priorities : + context -> + ?max_priority:int -> + public_key_hash -> + Level.t -> + int list tzresult Lwt.t + +(** [check_signature ctxt chain_id block id] check if the block is + signed with the given key, and belongs to the given [chain_id] *) +val check_signature : + Block_header.t -> Chain_id.t -> public_key -> unit tzresult Lwt.t + +(** Checks if the header that would be built from the given components + is valid for the given difficulty. The signature is not passed as it + is does not impact the proof-of-work stamp. The stamp is checked on + the hash of a block header whose signature has been zeroed-out. *) +val check_header_proof_of_work_stamp : + Block_header.shell_header -> Block_header.contents -> int64 -> bool + +(** verify if the proof of work stamp is valid *) +val check_proof_of_work_stamp : context -> Block_header.t -> unit tzresult + +(** check if the gap between the fitness of the current context + and the given block is within the protocol parameters *) +val check_fitness_gap : context -> Block_header.t -> unit tzresult + +val earlier_predecessor_timestamp : context -> Level.t -> Timestamp.t tzresult + +(** Since Emmy+ + + A block is valid only if its timestamp has a minimal delay with + respect to the previous block's timestamp, and this minimal delay + depends not only on the block's priority but also on the number of + endorsement operations included in the block. + + In Emmy+, blocks' fitness increases by one unit with each level. + + In this way, Emmy+ simplifies the optimal baking strategy: The + bakers used to have to choose whether to wait for more endorsements + to include in their block, or to publish the block immediately, + without waiting. The incentive for including more endorsements was + to increase the fitness and win against unknown blocks. However, + when a block was produced too late in the priority period, there + was the risk that the block did not reach endorsers before the + block of next priority. In Emmy+, the baker does not need to take + such a decision, because the baker cannot publish a block too + early. *) + +(** Given a block priority and a number of endorsement slots (given by + the `endorsing_power` argument), it returns the minimum time at + which the next block can be baked. *) +val minimal_valid_time : + Constants.parametric -> + priority:int -> + endorsing_power:int -> + predecessor_timestamp:Time.t -> + Time.t tzresult diff --git a/src/proto_011_PtHangzH/lib_protocol/blinded_public_key_hash.ml b/src/proto_011_PtHangzH/lib_protocol/blinded_public_key_hash.ml new file mode 100644 index 000000000000..e88c982e6ccd --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/blinded_public_key_hash.ml @@ -0,0 +1,60 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module H = + Blake2B.Make + (Base58) + (struct + let name = "Blinded public key hash" + + let title = "A blinded public key hash" + + let b58check_prefix = "\001\002\049\223" + + let size = Some Ed25519.Public_key_hash.size + end) + +module Index = struct + include H + include Path_encoding.Make_hex (H) +end + +include H + +let () = Base58.check_encoded_prefix b58check_encoding "btz1" 37 + +let of_ed25519_pkh activation_code pkh = + hash_bytes ~key:activation_code [Ed25519.Public_key_hash.to_bytes pkh] + +type activation_code = bytes + +let activation_code_size = Ed25519.Public_key_hash.size + +let activation_code_encoding = Data_encoding.Fixed.bytes activation_code_size + +let activation_code_of_hex h = + if Compare.Int.(String.length h <> activation_code_size * 2) then + invalid_arg "Blinded_public_key_hash.activation_code_of_hex" ; + Hex.to_bytes (`Hex h) diff --git a/src/proto_011_PtHangzH/lib_protocol/blinded_public_key_hash.mli b/src/proto_011_PtHangzH/lib_protocol/blinded_public_key_hash.mli new file mode 100644 index 000000000000..1940cf779bc1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/blinded_public_key_hash.mli @@ -0,0 +1,45 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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 handles hashes of implicit contract addresses used for + commitments in the origin block. + + This module is needed because for legal reasons, when the blockchain is + activated, the btz1 addresses of participants to the fundraising are not + listed directly but instead their hashes are listed, together with their + balances. Thus, the listed accounts can be activated and credited in the + activation block. *) + +include S.HASH + +type activation_code + +val activation_code_encoding : activation_code Data_encoding.t + +val of_ed25519_pkh : activation_code -> Ed25519.Public_key_hash.t -> t + +val activation_code_of_hex : string -> activation_code + +module Index : Storage_description.INDEX with type t = t diff --git a/src/proto_011_PtHangzH/lib_protocol/block_header_repr.ml b/src/proto_011_PtHangzH/lib_protocol/block_header_repr.ml new file mode 100644 index 000000000000..0ea116c6da8e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/block_header_repr.ml @@ -0,0 +1,149 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Block header *) + +type contents = { + priority : int; + seed_nonce_hash : Nonce_hash.t option; + proof_of_work_nonce : bytes; + liquidity_baking_escape_vote : bool; +} + +type protocol_data = {contents : contents; signature : Signature.t} + +type t = {shell : Block_header.shell_header; protocol_data : protocol_data} + +type block_header = t + +type raw = Block_header.t + +type shell_header = Block_header.shell_header + +let raw_encoding = Block_header.encoding + +let shell_header_encoding = Block_header.shell_header_encoding + +let contents_encoding = + let open Data_encoding in + def "block_header.alpha.unsigned_contents" + @@ conv + (fun { + priority; + seed_nonce_hash; + proof_of_work_nonce; + liquidity_baking_escape_vote; + } -> + ( priority, + proof_of_work_nonce, + seed_nonce_hash, + liquidity_baking_escape_vote )) + (fun ( priority, + proof_of_work_nonce, + seed_nonce_hash, + liquidity_baking_escape_vote ) -> + { + priority; + seed_nonce_hash; + proof_of_work_nonce; + liquidity_baking_escape_vote; + }) + (obj4 + (req "priority" uint16) + (req + "proof_of_work_nonce" + (Fixed.bytes Constants_repr.proof_of_work_nonce_size)) + (opt "seed_nonce_hash" Nonce_hash.encoding) + (req "liquidity_baking_escape_vote" Data_encoding.bool)) + +let protocol_data_encoding = + let open Data_encoding in + def "block_header.alpha.signed_contents" + @@ conv + (fun {contents; signature} -> (contents, signature)) + (fun (contents, signature) -> {contents; signature}) + (merge_objs + contents_encoding + (obj1 (req "signature" Signature.encoding))) + +let raw {shell; protocol_data} = + let protocol_data = + Data_encoding.Binary.to_bytes_exn protocol_data_encoding protocol_data + in + {Block_header.shell; protocol_data} + +let unsigned_encoding = + let open Data_encoding in + merge_objs Block_header.shell_header_encoding contents_encoding + +let encoding = + let open Data_encoding in + def "block_header.alpha.full_header" + @@ conv + (fun {shell; protocol_data} -> (shell, protocol_data)) + (fun (shell, protocol_data) -> {shell; protocol_data}) + (merge_objs Block_header.shell_header_encoding protocol_data_encoding) + +(** Constants *) + +let max_header_length = + let fake_shell = + { + Block_header.level = 0l; + proto_level = 0; + predecessor = Block_hash.zero; + timestamp = Time.of_seconds 0L; + validation_passes = 0; + operations_hash = Operation_list_list_hash.zero; + fitness = Fitness_repr.from_int64 0L; + context = Context_hash.zero; + } + and fake_contents = + { + priority = 0; + proof_of_work_nonce = + Bytes.make Constants_repr.proof_of_work_nonce_size '0'; + seed_nonce_hash = Some Nonce_hash.zero; + liquidity_baking_escape_vote = false; + } + in + Data_encoding.Binary.length + encoding + { + shell = fake_shell; + protocol_data = {contents = fake_contents; signature = Signature.zero}; + } + +(** Header parsing entry point *) + +let hash_raw = Block_header.hash + +let hash {shell; protocol_data} = + Block_header.hash + { + shell; + protocol_data = + Data_encoding.Binary.to_bytes_exn protocol_data_encoding protocol_data; + } diff --git a/src/proto_011_PtHangzH/lib_protocol/block_header_repr.mli b/src/proto_011_PtHangzH/lib_protocol/block_header_repr.mli new file mode 100644 index 000000000000..42e8113ec902 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/block_header_repr.mli @@ -0,0 +1,65 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Representation of block headers. *) + +type contents = { + priority : int; + seed_nonce_hash : Nonce_hash.t option; + proof_of_work_nonce : bytes; + liquidity_baking_escape_vote : bool; + (* set by baker to vote in favor of permanently disabling liquidity baking *) +} + +type protocol_data = {contents : contents; signature : Signature.t} + +type t = {shell : Block_header.shell_header; protocol_data : protocol_data} + +type block_header = t + +type raw = Block_header.t + +type shell_header = Block_header.shell_header + +val raw : block_header -> raw + +val encoding : block_header Data_encoding.encoding + +val raw_encoding : raw Data_encoding.t + +val contents_encoding : contents Data_encoding.t + +val unsigned_encoding : (Block_header.shell_header * contents) Data_encoding.t + +val protocol_data_encoding : protocol_data Data_encoding.encoding + +val shell_header_encoding : shell_header Data_encoding.encoding + +(** The maximum size of block headers in bytes *) +val max_header_length : int + +val hash : block_header -> Block_hash.t + +val hash_raw : raw -> Block_hash.t diff --git a/src/proto_011_PtHangzH/lib_protocol/bootstrap_storage.ml b/src/proto_011_PtHangzH/lib_protocol/bootstrap_storage.ml new file mode 100644 index 000000000000..a6e316842f75 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/bootstrap_storage.ml @@ -0,0 +1,131 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Misc + +let init_account ctxt + ({public_key_hash; public_key; amount} : Parameters_repr.bootstrap_account) + = + let contract = Contract_repr.implicit_contract public_key_hash in + Contract_storage.credit ctxt contract amount >>=? fun ctxt -> + match public_key with + | Some public_key -> + Contract_storage.reveal_manager_key ctxt public_key_hash public_key + >>=? fun ctxt -> Delegate_storage.set ctxt contract (Some public_key_hash) + | None -> return ctxt + +let init_contract ~typecheck ctxt + ({delegate; amount; script} : Parameters_repr.bootstrap_contract) = + Contract_storage.fresh_contract_from_current_nonce ctxt + >>?= fun (ctxt, contract) -> + typecheck ctxt script >>=? fun (script, ctxt) -> + Contract_storage.raw_originate + ctxt + contract + ~balance:amount + ~prepaid_bootstrap_storage:true + ~script + ~delegate:(Some delegate) + +let init ctxt ~typecheck ?ramp_up_cycles ?no_reward_cycles accounts contracts = + let nonce = Operation_hash.hash_string ["Un festival de GADT."] in + let ctxt = Raw_context.init_origination_nonce ctxt nonce in + List.fold_left_es init_account ctxt accounts >>=? fun ctxt -> + List.fold_left_es (init_contract ~typecheck) ctxt contracts >>=? fun ctxt -> + (match no_reward_cycles with + | None -> return ctxt + | Some cycles -> + (* Store pending ramp ups. *) + let constants = Raw_context.constants ctxt in + (* Start without rewards *) + Raw_context.patch_constants ctxt (fun c -> + { + c with + baking_reward_per_endorsement = [Tez_repr.zero]; + endorsement_reward = [Tez_repr.zero]; + }) + >>= fun ctxt -> + (* Store the final reward. *) + Storage.Ramp_up.Rewards.init + ctxt + (Cycle_repr.of_int32_exn (Int32.of_int cycles)) + (constants.baking_reward_per_endorsement, constants.endorsement_reward)) + >>=? fun ctxt -> + match ramp_up_cycles with + | None -> return ctxt + | Some cycles -> + (* Store pending ramp ups. *) + let constants = Raw_context.constants ctxt in + Tez_repr.(constants.block_security_deposit /? Int64.of_int cycles) + >>?= fun block_step -> + Tez_repr.(constants.endorsement_security_deposit /? Int64.of_int cycles) + >>?= fun endorsement_step -> + (* Start without security_deposit *) + Raw_context.patch_constants ctxt (fun c -> + { + c with + block_security_deposit = Tez_repr.zero; + endorsement_security_deposit = Tez_repr.zero; + }) + >>= fun ctxt -> + List.fold_left_es + (fun ctxt cycle -> + Tez_repr.(block_step *? Int64.of_int cycle) + >>?= fun block_security_deposit -> + Tez_repr.(endorsement_step *? Int64.of_int cycle) + >>?= fun endorsement_security_deposit -> + let cycle = Cycle_repr.of_int32_exn (Int32.of_int cycle) in + Storage.Ramp_up.Security_deposits.init + ctxt + cycle + (block_security_deposit, endorsement_security_deposit)) + ctxt + (1 --> (cycles - 1)) + >>=? fun ctxt -> + (* Store the final security deposits. *) + Storage.Ramp_up.Security_deposits.init + ctxt + (Cycle_repr.of_int32_exn (Int32.of_int cycles)) + ( constants.block_security_deposit, + constants.endorsement_security_deposit ) + +let cycle_end ctxt last_cycle = + let next_cycle = Cycle_repr.succ last_cycle in + (Storage.Ramp_up.Rewards.find ctxt next_cycle >>=? function + | None -> return ctxt + | Some (baking_reward_per_endorsement, endorsement_reward) -> + Storage.Ramp_up.Rewards.remove_existing ctxt next_cycle >>=? fun ctxt -> + Raw_context.patch_constants ctxt (fun c -> + {c with baking_reward_per_endorsement; endorsement_reward}) + >|= ok) + >>=? fun ctxt -> + Storage.Ramp_up.Security_deposits.find ctxt next_cycle >>=? function + | None -> return ctxt + | Some (block_security_deposit, endorsement_security_deposit) -> + Storage.Ramp_up.Security_deposits.remove_existing ctxt next_cycle + >>=? fun ctxt -> + Raw_context.patch_constants ctxt (fun c -> + {c with block_security_deposit; endorsement_security_deposit}) + >|= ok diff --git a/src/proto_011_PtHangzH/lib_protocol/bootstrap_storage.mli b/src/proto_011_PtHangzH/lib_protocol/bootstrap_storage.mli new file mode 100644 index 000000000000..37ef6787ed65 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/bootstrap_storage.mli @@ -0,0 +1,39 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val init : + Raw_context.t -> + typecheck: + (Raw_context.t -> + Script_repr.t -> + ((Script_repr.t * Lazy_storage_diff.diffs option) * Raw_context.t) tzresult + Lwt.t) -> + ?ramp_up_cycles:int -> + ?no_reward_cycles:int -> + Parameters_repr.bootstrap_account list -> + Parameters_repr.bootstrap_contract list -> + Raw_context.t tzresult Lwt.t + +val cycle_end : Raw_context.t -> Cycle_repr.t -> Raw_context.t tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/cache_costs.ml b/src/proto_011_PtHangzH/lib_protocol/cache_costs.ml new file mode 100644 index 000000000000..8514df2c4550 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/cache_costs.ml @@ -0,0 +1,52 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module S = Saturation_repr + +(* Computed by typing the contract + "{parameter unit; storage unit; code FAILWITH}" + and evaluating + [(8 * Obj.reachable_words (Obj.repr typed_script))] + where [typed_script] is of type [ex_script] *) +let minimal_size_of_typed_contract_in_bytes = 688 + +let approximate_cardinal bytes = + S.safe_int (bytes / minimal_size_of_typed_contract_in_bytes) + +let log2 x = S.safe_int (1 + S.numbits x) + +let cache_update_constant = S.safe_int 600 + +let cache_update_coeff = S.safe_int 57 + +(* Cost of calling [Environment_cache.update]. *) +let cache_update ~cache_size_in_bytes = + let approx_card = approximate_cardinal cache_size_in_bytes in + Gas_limit_repr.atomic_step_cost + S.(add cache_update_constant (mul cache_update_coeff (log2 approx_card))) + +(* Cost of calling [Environment_cache.find]. + This overapproximates [cache_find] slightly. *) +let cache_find = cache_update diff --git a/src/proto_011_PtHangzH/lib_protocol/cache_costs.mli b/src/proto_011_PtHangzH/lib_protocol/cache_costs.mli new file mode 100644 index 000000000000..61910350f3a0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/cache_costs.mli @@ -0,0 +1,32 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Costs function for cache accesses. *) + +(** Cost of calling [Cache.update]. *) +val cache_update : cache_size_in_bytes:int -> Gas_limit_repr.cost + +(** Cost of calling [Cache.find]. *) +val cache_find : cache_size_in_bytes:int -> Gas_limit_repr.cost diff --git a/src/proto_011_PtHangzH/lib_protocol/cache_memory_helpers.ml b/src/proto_011_PtHangzH/lib_protocol/cache_memory_helpers.ml new file mode 100644 index 000000000000..83bdeb348494 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/cache_memory_helpers.ml @@ -0,0 +1,168 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** The [Nodes] module is used to count the number of computation steps + performed when evaluating the size of the in-memory graph corresponding + to an OCaml value. + + In first approximation, the value of type [Nodes.t] threaded through + {!expr_size} below and through the module {!Script_typed_ir_size} + is meant to match the number of recursive calls in the [traverse] + functions of {!Script_typed_ir} and in that of {!node_size}. + + The assumption is that there's a bounded amount of work performed between + two such recursive calls, hence that the total work is bounded above + by something proportional to the [Nodes.t] accumulator. + + Computations on values of type [Nodes.t] do not overflow, as they + are bounded above by the number of nodes traversed when computing + an OCaml value. + *) +module Nodes : sig + type t = private int + + val zero : t + + val one : t [@@ocaml.warning "-32"] + + val succ : t -> t + + val add : t -> t -> t + + val to_int : t -> int +end = struct + type t = int + + let zero = 0 + + let one = 1 + + let succ x = x + 1 + + let add x y = x + y + + let to_int x = x +end + +(** {2 Helpers to deal with computing the in-memory size of values} *) + +type sint = Saturation_repr.may_saturate Saturation_repr.t + +type nodes_and_size = Nodes.t * sint + +let ( !! ) = Saturation_repr.safe_int + +let ( +! ) = Saturation_repr.add + +let ( +? ) s x = Saturation_repr.add s !!x + +let ( *? ) s x = Saturation_repr.mul s !!x + +let ( /? ) s x = Saturation_repr.ediv s !!x + +let ( ++ ) (n1, s1) (n2, s2) = (Nodes.add n1 n2, s1 +! s2) + +let zero = (Nodes.zero, !!0) + +let word_size = !!8 + +let header_size = word_size + +let int64_size = header_size +! (word_size *? 2) + +let h1w = header_size +! word_size + +let h2w = header_size +! (word_size *? 2) + +let h3w = header_size +! (word_size *? 3) + +let h4w = header_size +! (word_size *? 4) + +let h5w = header_size +! (word_size *? 5) + +let hh3w = (word_size *? 3) +! (header_size *? 2) + +let hh6w = (word_size *? 6) +! (header_size *? 2) + +let hh8w = (word_size *? 8) +! (header_size *? 2) + +let z_size z = + let numbits = Z.numbits z in + if Compare.Int.(numbits <= 62) then !!0 else (word_size *? Z.size z) +? 32 + +let string_size_gen len = header_size +? (len + (8 - (len mod 8))) + +let bytes_size b = string_size_gen (Bytes.length b) + +let string_size s = string_size_gen (String.length s) + +let ret_adding (nodes, size) added = (nodes, size +! added) + +let ret_succ_adding (nodes, size) added = (Nodes.succ nodes, size +! added) + +let ret_succ (nodes, size) = (Nodes.succ nodes, size) + +let option_size some x = + let some x = h1w +! some x in + Option.fold ~none:!!0 ~some x + +let option_size_vec some x = + let some x = ret_adding (some x) h1w in + Option.fold ~none:zero ~some x + +let list_cell_size elt_size = + header_size +! word_size +! word_size +! elt_size + [@@ocaml.inline always] + +let list_fold_size elt_size list = + List.fold_left + (fun accu elt -> ret_succ_adding (accu ++ elt_size elt) h2w) + zero + list + +let boxed_tup2 x y = + header_size +! word_size +! word_size +! x +! y + [@@ocaml.inline always] + +let node_size = + let open Micheline in + let annotation_size a = + List.fold_left + (fun accu s -> ret_succ_adding accu (h2w +! string_size s)) + zero + a + in + let internal_node_size = function + | Int (_, z) -> (Nodes.one, h2w +! z_size z) + | String (_, s) -> (Nodes.one, h2w +! string_size s) + | Bytes (_, s) -> (Nodes.one, h2w +! bytes_size s) + | Prim (_, _, _, a) -> ret_succ_adding (annotation_size a) h4w + | Seq (_, _) -> (Nodes.one, h2w) + in + fun node -> + Script_repr.fold node zero @@ fun accu node -> + accu ++ internal_node_size node + +let expr_size expr = node_size (Micheline.root expr) diff --git a/src/proto_011_PtHangzH/lib_protocol/commitment_repr.ml b/src/proto_011_PtHangzH/lib_protocol/commitment_repr.ml new file mode 100644 index 000000000000..38f114120c35 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/commitment_repr.ml @@ -0,0 +1,36 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type t = { + blinded_public_key_hash : Blinded_public_key_hash.t; + amount : Tez_repr.t; +} + +let encoding = + let open Data_encoding in + conv + (fun {blinded_public_key_hash; amount} -> (blinded_public_key_hash, amount)) + (fun (blinded_public_key_hash, amount) -> {blinded_public_key_hash; amount}) + (tup2 Blinded_public_key_hash.encoding Tez_repr.encoding) diff --git a/src/proto_011_PtHangzH/lib_protocol/commitment_repr.mli b/src/proto_011_PtHangzH/lib_protocol/commitment_repr.mli new file mode 100644 index 000000000000..edca4134d844 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/commitment_repr.mli @@ -0,0 +1,31 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type t = { + blinded_public_key_hash : Blinded_public_key_hash.t; + amount : Tez_repr.t; +} + +val encoding : t Data_encoding.t diff --git a/src/proto_011_PtHangzH/lib_protocol/commitment_storage.ml b/src/proto_011_PtHangzH/lib_protocol/commitment_storage.ml new file mode 100644 index 000000000000..7c380af034ba --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/commitment_storage.ml @@ -0,0 +1,34 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let find = Storage.Commitments.find + +let remove_existing = Storage.Commitments.remove_existing + +let init ctxt commitments = + let init_commitment ctxt Commitment_repr.{blinded_public_key_hash; amount} = + Storage.Commitments.init ctxt blinded_public_key_hash amount + in + List.fold_left_es init_commitment ctxt commitments diff --git a/src/proto_011_PtHangzH/lib_protocol/commitment_storage.mli b/src/proto_011_PtHangzH/lib_protocol/commitment_storage.mli new file mode 100644 index 000000000000..d7604f0e9ec8 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/commitment_storage.mli @@ -0,0 +1,33 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val init : + Raw_context.t -> Commitment_repr.t list -> Raw_context.t tzresult Lwt.t + +val find : + Raw_context.t -> Blinded_public_key_hash.t -> Tez_repr.t option tzresult Lwt.t + +val remove_existing : + Raw_context.t -> Blinded_public_key_hash.t -> Raw_context.t tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/constants_repr.ml b/src/proto_011_PtHangzH/lib_protocol/constants_repr.ml new file mode 100644 index 000000000000..5ee4a1be93e1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/constants_repr.ml @@ -0,0 +1,499 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let version_number_004 = "\000" + +let version_number = "\001" + +let proof_of_work_nonce_size = 8 + +let nonce_length = 32 + +let max_anon_ops_per_block = 132 + +let max_proposals_per_delegate = 20 + +let max_operation_data_length = 32 * 1024 (* 32kB *) + +let max_micheline_node_count = 50_000 + +let max_micheline_bytes_limit = 50_000 + +let max_allowed_global_constant_depth = 10_000 + +(* In this version of the protocol, there is a single cache for + contract source code and storage. Its size has been chosen + not too exceed 100 000 000 bytes. *) +let cache_layout = [100_000_000] + +(* In previous versions of the protocol, this + [michelson_maximum_type_size] limit was set to 1000 but + the contract input types (pair ) + were not checked. Both components, and + where however checked hence it was possible to build + types as big as 2001. *) +let michelson_maximum_type_size = 2001 + +type fixed = { + proof_of_work_nonce_size : int; + nonce_length : int; + max_anon_ops_per_block : int; + max_operation_data_length : int; + max_proposals_per_delegate : int; + max_micheline_node_count : int; + max_micheline_bytes_limit : int; + max_allowed_global_constant_depth : int; +} + +let fixed_encoding = + let open Data_encoding in + conv + (fun c -> + ( c.proof_of_work_nonce_size, + c.nonce_length, + c.max_anon_ops_per_block, + c.max_operation_data_length, + c.max_proposals_per_delegate, + c.max_micheline_node_count, + c.max_micheline_bytes_limit, + c.max_allowed_global_constant_depth )) + (fun ( proof_of_work_nonce_size, + nonce_length, + max_anon_ops_per_block, + max_operation_data_length, + max_proposals_per_delegate, + max_micheline_node_count, + max_micheline_bytes_limit, + max_allowed_global_constant_depth ) -> + { + proof_of_work_nonce_size; + nonce_length; + max_anon_ops_per_block; + max_operation_data_length; + max_proposals_per_delegate; + max_micheline_node_count; + max_micheline_bytes_limit; + max_allowed_global_constant_depth; + }) + (obj8 + (req "proof_of_work_nonce_size" uint8) + (req "nonce_length" uint8) + (req "max_anon_ops_per_block" uint8) + (req "max_operation_data_length" int31) + (req "max_proposals_per_delegate" uint8) + (req "max_micheline_node_count" int31) + (req "max_micheline_bytes_limit" int31) + (req "max_allowed_global_constants_depth" int31)) + +let fixed = + { + proof_of_work_nonce_size; + nonce_length; + max_anon_ops_per_block; + max_operation_data_length; + max_proposals_per_delegate; + max_micheline_node_count; + max_micheline_bytes_limit; + max_allowed_global_constant_depth; + } + +(* The encoded representation of this type is stored in the context as + bytes. Changing the encoding, or the value of these constants from + the previous protocol may break the context migration, or (even + worse) yield an incorrect context after migration. + + If you change this encoding, you should ensure that there is a + proper migration of the constants during context migration. *) +type parametric = { + preserved_cycles : int; + blocks_per_cycle : int32; + blocks_per_commitment : int32; + blocks_per_roll_snapshot : int32; + blocks_per_voting_period : int32; + time_between_blocks : Period_repr.t list; + minimal_block_delay : Period_repr.t; + endorsers_per_block : int; + hard_gas_limit_per_operation : Gas_limit_repr.Arith.integral; + hard_gas_limit_per_block : Gas_limit_repr.Arith.integral; + proof_of_work_threshold : int64; + tokens_per_roll : Tez_repr.t; + seed_nonce_revelation_tip : Tez_repr.t; + origination_size : int; + block_security_deposit : Tez_repr.t; + endorsement_security_deposit : Tez_repr.t; + baking_reward_per_endorsement : Tez_repr.t list; + endorsement_reward : Tez_repr.t list; + cost_per_byte : Tez_repr.t; + hard_storage_limit_per_operation : Z.t; + quorum_min : int32; + quorum_max : int32; + min_proposal_quorum : int32; + initial_endorsers : int; + delay_per_missing_endorsement : Period_repr.t; + liquidity_baking_subsidy : Tez_repr.t; + liquidity_baking_sunset_level : int32; + liquidity_baking_escape_ema_threshold : int32; +} + +let parametric_encoding = + let open Data_encoding in + conv + (fun c -> + ( ( c.preserved_cycles, + c.blocks_per_cycle, + c.blocks_per_commitment, + c.blocks_per_roll_snapshot, + c.blocks_per_voting_period, + c.time_between_blocks, + c.endorsers_per_block, + c.hard_gas_limit_per_operation, + c.hard_gas_limit_per_block, + c.proof_of_work_threshold ), + ( ( c.tokens_per_roll, + c.seed_nonce_revelation_tip, + c.origination_size, + c.block_security_deposit, + c.endorsement_security_deposit, + c.baking_reward_per_endorsement, + c.endorsement_reward, + c.cost_per_byte, + c.hard_storage_limit_per_operation ), + ( c.quorum_min, + c.quorum_max, + c.min_proposal_quorum, + c.initial_endorsers, + c.delay_per_missing_endorsement, + c.minimal_block_delay, + c.liquidity_baking_subsidy, + c.liquidity_baking_sunset_level, + c.liquidity_baking_escape_ema_threshold ) ) )) + (fun ( ( preserved_cycles, + blocks_per_cycle, + blocks_per_commitment, + blocks_per_roll_snapshot, + blocks_per_voting_period, + time_between_blocks, + endorsers_per_block, + hard_gas_limit_per_operation, + hard_gas_limit_per_block, + proof_of_work_threshold ), + ( ( tokens_per_roll, + seed_nonce_revelation_tip, + origination_size, + block_security_deposit, + endorsement_security_deposit, + baking_reward_per_endorsement, + endorsement_reward, + cost_per_byte, + hard_storage_limit_per_operation ), + ( quorum_min, + quorum_max, + min_proposal_quorum, + initial_endorsers, + delay_per_missing_endorsement, + minimal_block_delay, + liquidity_baking_subsidy, + liquidity_baking_sunset_level, + liquidity_baking_escape_ema_threshold ) ) ) -> + { + preserved_cycles; + blocks_per_cycle; + blocks_per_commitment; + blocks_per_roll_snapshot; + blocks_per_voting_period; + time_between_blocks; + endorsers_per_block; + hard_gas_limit_per_operation; + hard_gas_limit_per_block; + proof_of_work_threshold; + tokens_per_roll; + seed_nonce_revelation_tip; + origination_size; + block_security_deposit; + endorsement_security_deposit; + baking_reward_per_endorsement; + endorsement_reward; + cost_per_byte; + hard_storage_limit_per_operation; + quorum_min; + quorum_max; + min_proposal_quorum; + initial_endorsers; + delay_per_missing_endorsement; + minimal_block_delay; + liquidity_baking_subsidy; + liquidity_baking_sunset_level; + liquidity_baking_escape_ema_threshold; + }) + (merge_objs + (obj10 + (req "preserved_cycles" uint8) + (req "blocks_per_cycle" int32) + (req "blocks_per_commitment" int32) + (req "blocks_per_roll_snapshot" int32) + (req "blocks_per_voting_period" int32) + (req "time_between_blocks" (list Period_repr.encoding)) + (req "endorsers_per_block" uint16) + (req + "hard_gas_limit_per_operation" + Gas_limit_repr.Arith.z_integral_encoding) + (req + "hard_gas_limit_per_block" + Gas_limit_repr.Arith.z_integral_encoding) + (req "proof_of_work_threshold" int64)) + (merge_objs + (obj9 + (req "tokens_per_roll" Tez_repr.encoding) + (req "seed_nonce_revelation_tip" Tez_repr.encoding) + (req "origination_size" int31) + (req "block_security_deposit" Tez_repr.encoding) + (req "endorsement_security_deposit" Tez_repr.encoding) + (req "baking_reward_per_endorsement" (list Tez_repr.encoding)) + (req "endorsement_reward" (list Tez_repr.encoding)) + (req "cost_per_byte" Tez_repr.encoding) + (req "hard_storage_limit_per_operation" z)) + (obj9 + (req "quorum_min" int32) + (req "quorum_max" int32) + (req "min_proposal_quorum" int32) + (req "initial_endorsers" uint16) + (req "delay_per_missing_endorsement" Period_repr.encoding) + (req "minimal_block_delay" Period_repr.encoding) + (req "liquidity_baking_subsidy" Tez_repr.encoding) + (req "liquidity_baking_sunset_level" int32) + (req "liquidity_baking_escape_ema_threshold" int32)))) + +type t = {fixed : fixed; parametric : parametric} + +let encoding = + let open Data_encoding in + conv + (fun {fixed; parametric} -> (fixed, parametric)) + (fun (fixed, parametric) -> {fixed; parametric}) + (merge_objs fixed_encoding parametric_encoding) + +type error += Invalid_protocol_constants of string (* `Permanent *) + +let () = + register_error_kind + `Permanent + ~id:"constants.invalid_protocol_constants" + ~title:"Invalid protocol constants" + ~description:"The provided protocol constants are not coherent." + ~pp:(fun ppf reason -> + Format.fprintf ppf "Invalid protocol constants: %s" reason) + Data_encoding.(obj1 (req "reason" string)) + (function Invalid_protocol_constants reason -> Some reason | _ -> None) + (fun reason -> Invalid_protocol_constants reason) + +let check_constants constants = + let min_time_between_blocks = + match constants.time_between_blocks with + | first_time_between_blocks :: _ -> first_time_between_blocks + | [] -> + (* this constant is used in the Baking module *) + Period_repr.one_minute + in + error_unless + Compare.Int64.( + Period_repr.to_seconds min_time_between_blocks + >= Period_repr.to_seconds constants.minimal_block_delay) + (Invalid_protocol_constants + (Format.asprintf + "minimal_block_delay value (%Ld) should be smaller than \ + time_between_blocks[0] value (%Ld)" + (Period_repr.to_seconds constants.minimal_block_delay) + (Period_repr.to_seconds min_time_between_blocks))) + >>? fun () -> + error_unless + Compare.Int.(constants.endorsers_per_block >= constants.initial_endorsers) + (Invalid_protocol_constants + "initial_endorsers should be smaller than endorsers_per_block") + +module Proto_previous = struct + type parametric = { + preserved_cycles : int; + blocks_per_cycle : int32; + blocks_per_commitment : int32; + blocks_per_roll_snapshot : int32; + blocks_per_voting_period : int32; + time_between_blocks : Period_repr.t list; + minimal_block_delay : Period_repr.t; + endorsers_per_block : int; + hard_gas_limit_per_operation : Gas_limit_repr.Arith.integral; + hard_gas_limit_per_block : Gas_limit_repr.Arith.integral; + proof_of_work_threshold : int64; + tokens_per_roll : Tez_repr.t; + michelson_maximum_type_size : int; + seed_nonce_revelation_tip : Tez_repr.t; + origination_size : int; + block_security_deposit : Tez_repr.t; + endorsement_security_deposit : Tez_repr.t; + baking_reward_per_endorsement : Tez_repr.t list; + endorsement_reward : Tez_repr.t list; + cost_per_byte : Tez_repr.t; + hard_storage_limit_per_operation : Z.t; + quorum_min : int32; + quorum_max : int32; + min_proposal_quorum : int32; + initial_endorsers : int; + delay_per_missing_endorsement : Period_repr.t; + liquidity_baking_subsidy : Tez_repr.t; + liquidity_baking_sunset_level : int32; + liquidity_baking_escape_ema_threshold : int32; + } + + let parametric_encoding = + let open Data_encoding in + conv + (fun c -> + ( ( c.preserved_cycles, + c.blocks_per_cycle, + c.blocks_per_commitment, + c.blocks_per_roll_snapshot, + c.blocks_per_voting_period, + c.time_between_blocks, + c.endorsers_per_block, + c.hard_gas_limit_per_operation, + c.hard_gas_limit_per_block, + c.proof_of_work_threshold ), + ( ( c.tokens_per_roll, + c.michelson_maximum_type_size, + c.seed_nonce_revelation_tip, + c.origination_size, + c.block_security_deposit, + c.endorsement_security_deposit, + c.baking_reward_per_endorsement, + c.endorsement_reward, + c.cost_per_byte, + c.hard_storage_limit_per_operation ), + ( c.quorum_min, + c.quorum_max, + c.min_proposal_quorum, + c.initial_endorsers, + c.delay_per_missing_endorsement, + c.minimal_block_delay, + c.liquidity_baking_subsidy, + c.liquidity_baking_sunset_level, + c.liquidity_baking_escape_ema_threshold ) ) )) + (fun ( ( preserved_cycles, + blocks_per_cycle, + blocks_per_commitment, + blocks_per_roll_snapshot, + blocks_per_voting_period, + time_between_blocks, + endorsers_per_block, + hard_gas_limit_per_operation, + hard_gas_limit_per_block, + proof_of_work_threshold ), + ( ( tokens_per_roll, + michelson_maximum_type_size, + seed_nonce_revelation_tip, + origination_size, + block_security_deposit, + endorsement_security_deposit, + baking_reward_per_endorsement, + endorsement_reward, + cost_per_byte, + hard_storage_limit_per_operation ), + ( quorum_min, + quorum_max, + min_proposal_quorum, + initial_endorsers, + delay_per_missing_endorsement, + minimal_block_delay, + liquidity_baking_subsidy, + liquidity_baking_sunset_level, + liquidity_baking_escape_ema_threshold ) ) ) -> + { + preserved_cycles; + blocks_per_cycle; + blocks_per_commitment; + blocks_per_roll_snapshot; + blocks_per_voting_period; + time_between_blocks; + endorsers_per_block; + hard_gas_limit_per_operation; + hard_gas_limit_per_block; + proof_of_work_threshold; + tokens_per_roll; + michelson_maximum_type_size; + seed_nonce_revelation_tip; + origination_size; + block_security_deposit; + endorsement_security_deposit; + baking_reward_per_endorsement; + endorsement_reward; + cost_per_byte; + hard_storage_limit_per_operation; + quorum_min; + quorum_max; + min_proposal_quorum; + initial_endorsers; + delay_per_missing_endorsement; + minimal_block_delay; + liquidity_baking_subsidy; + liquidity_baking_sunset_level; + liquidity_baking_escape_ema_threshold; + }) + (merge_objs + (obj10 + (req "preserved_cycles" uint8) + (req "blocks_per_cycle" int32) + (req "blocks_per_commitment" int32) + (req "blocks_per_roll_snapshot" int32) + (req "blocks_per_voting_period" int32) + (req "time_between_blocks" (list Period_repr.encoding)) + (req "endorsers_per_block" uint16) + (req + "hard_gas_limit_per_operation" + Gas_limit_repr.Arith.z_integral_encoding) + (req + "hard_gas_limit_per_block" + Gas_limit_repr.Arith.z_integral_encoding) + (req "proof_of_work_threshold" int64)) + (merge_objs + (obj10 + (req "tokens_per_roll" Tez_repr.encoding) + (req "michelson_maximum_type_size" uint16) + (req "seed_nonce_revelation_tip" Tez_repr.encoding) + (req "origination_size" int31) + (req "block_security_deposit" Tez_repr.encoding) + (req "endorsement_security_deposit" Tez_repr.encoding) + (req "baking_reward_per_endorsement" (list Tez_repr.encoding)) + (req "endorsement_reward" (list Tez_repr.encoding)) + (req "cost_per_byte" Tez_repr.encoding) + (req "hard_storage_limit_per_operation" z)) + (obj9 + (req "quorum_min" int32) + (req "quorum_max" int32) + (req "min_proposal_quorum" int32) + (req "initial_endorsers" uint16) + (req "delay_per_missing_endorsement" Period_repr.encoding) + (req "minimal_block_delay" Period_repr.encoding) + (req "liquidity_baking_subsidy" Tez_repr.encoding) + (req "liquidity_baking_sunset_level" int32) + (req "liquidity_baking_escape_ema_threshold" int32)))) +end diff --git a/src/proto_011_PtHangzH/lib_protocol/constants_repr.mli b/src/proto_011_PtHangzH/lib_protocol/constants_repr.mli new file mode 100644 index 000000000000..8c359a02feb1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/constants_repr.mli @@ -0,0 +1,166 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val version_number_004 : string + +val version_number : string + +val proof_of_work_nonce_size : int + +val nonce_length : int + +val max_anon_ops_per_block : int + +val max_proposals_per_delegate : int + +val max_operation_data_length : int + +(** A global size limit on the size of Micheline expressions + after expansion. + + We want to prevent constants from being + used to create huge values that could potentially do damage + if ever printed or sent over the network. We arrived at this + number by finding the largest possible contract in terms of + number of nodes. The number of nodes is constrained by the + current "max_operation_data_length" (32768) to be ~10,000 ( + see "largest_flat_contract.tz" in the tezt suite for the largest + contract with constants that can be originated). As a first + approximation, we set the node size limit to 5 times this amount. *) +val max_micheline_node_count : int + +(** Same as [max_micheline_node_count] but for limiting the combined + bytes of the strings, ints and bytes in a expanded Micheline + expression. *) +val max_micheline_bytes_limit : int + +(** Represents the maximum depth of an expression stored + in the table after all references to other constants have + (recursively) been expanded, where depth refers to the + nesting of [Prim] and/or [Seq] nodes. + + The size was chosen arbitrarily to match the typechecker + in [Script_ir_translator]. *) +val max_allowed_global_constant_depth : int + +(** Each protocol defines the number of subcaches and their respective + limit size using [cache_layout]. *) +val cache_layout : int list + +val michelson_maximum_type_size : int + +type fixed = { + proof_of_work_nonce_size : int; + nonce_length : int; + max_anon_ops_per_block : int; + max_operation_data_length : int; + max_proposals_per_delegate : int; + max_micheline_node_count : int; + max_micheline_bytes_limit : int; + max_allowed_global_constant_depth : int; +} + +val fixed_encoding : fixed Data_encoding.encoding + +val fixed : fixed + +type parametric = { + preserved_cycles : int; + blocks_per_cycle : int32; + blocks_per_commitment : int32; + blocks_per_roll_snapshot : int32; + blocks_per_voting_period : int32; + time_between_blocks : Period_repr.t list; + minimal_block_delay : Period_repr.t; + endorsers_per_block : int; + hard_gas_limit_per_operation : Gas_limit_repr.Arith.integral; + hard_gas_limit_per_block : Gas_limit_repr.Arith.integral; + proof_of_work_threshold : int64; + tokens_per_roll : Tez_repr.t; + seed_nonce_revelation_tip : Tez_repr.t; + origination_size : int; + block_security_deposit : Tez_repr.t; + endorsement_security_deposit : Tez_repr.t; + baking_reward_per_endorsement : Tez_repr.t list; + endorsement_reward : Tez_repr.t list; + cost_per_byte : Tez_repr.t; + hard_storage_limit_per_operation : Z.t; + (* in seconds *) + quorum_min : int32; + quorum_max : int32; + min_proposal_quorum : int32; + initial_endorsers : int; + delay_per_missing_endorsement : Period_repr.t; + liquidity_baking_subsidy : Tez_repr.t; + liquidity_baking_sunset_level : int32; + liquidity_baking_escape_ema_threshold : int32; +} + +val parametric_encoding : parametric Data_encoding.encoding + +type t = {fixed : fixed; parametric : parametric} + +val encoding : t Data_encoding.encoding + +(** performs some consistency on the protocol parameters *) +val check_constants : parametric -> unit tzresult + +module Proto_previous : sig + type parametric = { + preserved_cycles : int; + blocks_per_cycle : int32; + blocks_per_commitment : int32; + blocks_per_roll_snapshot : int32; + blocks_per_voting_period : int32; + time_between_blocks : Period_repr.t list; + minimal_block_delay : Period_repr.t; + endorsers_per_block : int; + hard_gas_limit_per_operation : Gas_limit_repr.Arith.integral; + hard_gas_limit_per_block : Gas_limit_repr.Arith.integral; + proof_of_work_threshold : int64; + tokens_per_roll : Tez_repr.t; + michelson_maximum_type_size : int; + seed_nonce_revelation_tip : Tez_repr.t; + origination_size : int; + block_security_deposit : Tez_repr.t; + endorsement_security_deposit : Tez_repr.t; + baking_reward_per_endorsement : Tez_repr.t list; + endorsement_reward : Tez_repr.t list; + cost_per_byte : Tez_repr.t; + hard_storage_limit_per_operation : Z.t; + (* in seconds *) + quorum_min : int32; + quorum_max : int32; + min_proposal_quorum : int32; + initial_endorsers : int; + delay_per_missing_endorsement : Period_repr.t; + liquidity_baking_subsidy : Tez_repr.t; + liquidity_baking_sunset_level : int32; + liquidity_baking_escape_ema_threshold : int32; + } + + val parametric_encoding : parametric Data_encoding.encoding +end diff --git a/src/proto_011_PtHangzH/lib_protocol/constants_services.ml b/src/proto_011_PtHangzH/lib_protocol/constants_services.ml new file mode 100644 index 000000000000..d5cced885855 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/constants_services.ml @@ -0,0 +1,60 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +let custom_root = + (RPC_path.(open_root / "context" / "constants") + : RPC_context.t RPC_path.context) + +module S = struct + open Data_encoding + + let errors = + RPC_service.get_service + ~description:"Schema for all the RPC errors from this protocol version" + ~query:RPC_query.empty + ~output:json_schema + RPC_path.(custom_root / "errors") + + let all = + RPC_service.get_service + ~description:"All constants" + ~query:RPC_query.empty + ~output:Alpha_context.Constants.encoding + custom_root +end + +let register () = + let open Services_registration in + register0_noctxt ~chunked:true S.errors (fun () () -> + return Data_encoding.Json.(schema error_encoding)) ; + register0 ~chunked:false S.all (fun ctxt () () -> + let open Constants in + return {fixed; parametric = parametric ctxt}) + +let errors ctxt block = RPC_context.make_call0 S.errors ctxt block () () + +let all ctxt block = RPC_context.make_call0 S.all ctxt block () () diff --git a/src/proto_011_PtHangzH/lib_protocol/constants_services.mli b/src/proto_011_PtHangzH/lib_protocol/constants_services.mli new file mode 100644 index 000000000000..4ebdfc3557d2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/constants_services.mli @@ -0,0 +1,34 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +val errors : + 'a #RPC_context.simple -> 'a -> Data_encoding.json_schema shell_tzresult Lwt.t + +(** Returns all the constants of the protocol *) +val all : 'a #RPC_context.simple -> 'a -> Constants.t shell_tzresult Lwt.t + +val register : unit -> unit diff --git a/src/proto_011_PtHangzH/lib_protocol/constants_storage.ml b/src/proto_011_PtHangzH/lib_protocol/constants_storage.ml new file mode 100644 index 000000000000..745eb5538bac --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/constants_storage.ml @@ -0,0 +1,138 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let preserved_cycles c = + let constants = Raw_context.constants c in + constants.preserved_cycles + +let blocks_per_cycle c = + let constants = Raw_context.constants c in + constants.blocks_per_cycle + +let blocks_per_commitment c = + let constants = Raw_context.constants c in + constants.blocks_per_commitment + +let blocks_per_roll_snapshot c = + let constants = Raw_context.constants c in + constants.blocks_per_roll_snapshot + +let blocks_per_voting_period c = + let constants = Raw_context.constants c in + constants.blocks_per_voting_period + +let time_between_blocks c = + let constants = Raw_context.constants c in + constants.time_between_blocks + +let minimal_block_delay c = + let constants = Raw_context.constants c in + constants.minimal_block_delay + +let endorsers_per_block c = + let constants = Raw_context.constants c in + constants.endorsers_per_block + +let initial_endorsers c = + let constants = Raw_context.constants c in + constants.initial_endorsers + +let delay_per_missing_endorsement c = + let constants = Raw_context.constants c in + constants.delay_per_missing_endorsement + +let hard_gas_limit_per_operation c = + let constants = Raw_context.constants c in + constants.hard_gas_limit_per_operation + +let hard_gas_limit_per_block c = + let constants = Raw_context.constants c in + constants.hard_gas_limit_per_block + +let cost_per_byte c = + let constants = Raw_context.constants c in + constants.cost_per_byte + +let hard_storage_limit_per_operation c = + let constants = Raw_context.constants c in + constants.hard_storage_limit_per_operation + +let proof_of_work_threshold c = + let constants = Raw_context.constants c in + constants.proof_of_work_threshold + +let tokens_per_roll c = + let constants = Raw_context.constants c in + constants.tokens_per_roll + +let seed_nonce_revelation_tip c = + let constants = Raw_context.constants c in + constants.seed_nonce_revelation_tip + +let origination_size c = + let constants = Raw_context.constants c in + constants.origination_size + +let block_security_deposit c = + let constants = Raw_context.constants c in + constants.block_security_deposit + +let endorsement_security_deposit c = + let constants = Raw_context.constants c in + constants.endorsement_security_deposit + +let baking_reward_per_endorsement c = + let constants = Raw_context.constants c in + constants.baking_reward_per_endorsement + +let endorsement_reward c = + let constants = Raw_context.constants c in + constants.endorsement_reward + +let quorum_min c = + let constants = Raw_context.constants c in + constants.quorum_min + +let quorum_max c = + let constants = Raw_context.constants c in + constants.quorum_max + +let min_proposal_quorum c = + let constants = Raw_context.constants c in + constants.min_proposal_quorum + +let liquidity_baking_subsidy c = + let constants = Raw_context.constants c in + constants.liquidity_baking_subsidy + +let liquidity_baking_sunset_level c = + let constants = Raw_context.constants c in + constants.liquidity_baking_sunset_level + +let liquidity_baking_escape_ema_threshold c = + let constants = Raw_context.constants c in + constants.liquidity_baking_escape_ema_threshold + +let parametric c = Raw_context.constants c diff --git a/src/proto_011_PtHangzH/lib_protocol/constants_storage.mli b/src/proto_011_PtHangzH/lib_protocol/constants_storage.mli new file mode 100644 index 000000000000..c01f1c3660d8 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/constants_storage.mli @@ -0,0 +1,84 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val preserved_cycles : Raw_context.t -> int + +val blocks_per_cycle : Raw_context.t -> int32 + +val blocks_per_commitment : Raw_context.t -> int32 + +val blocks_per_roll_snapshot : Raw_context.t -> int32 + +val blocks_per_voting_period : Raw_context.t -> int32 + +val time_between_blocks : Raw_context.t -> Period_repr.t list + +val minimal_block_delay : Raw_context.t -> Period_repr.t + +val endorsers_per_block : Raw_context.t -> int + +val initial_endorsers : Raw_context.t -> int + +val delay_per_missing_endorsement : Raw_context.t -> Period_repr.t + +val hard_gas_limit_per_operation : + Raw_context.t -> Gas_limit_repr.Arith.integral + +val hard_gas_limit_per_block : Raw_context.t -> Gas_limit_repr.Arith.integral + +val cost_per_byte : Raw_context.t -> Tez_repr.t + +val hard_storage_limit_per_operation : Raw_context.t -> Z.t + +val proof_of_work_threshold : Raw_context.t -> int64 + +val tokens_per_roll : Raw_context.t -> Tez_repr.t + +val seed_nonce_revelation_tip : Raw_context.t -> Tez_repr.t + +val origination_size : Raw_context.t -> int + +val block_security_deposit : Raw_context.t -> Tez_repr.t + +val endorsement_security_deposit : Raw_context.t -> Tez_repr.t + +val baking_reward_per_endorsement : Raw_context.t -> Tez_repr.t list + +val endorsement_reward : Raw_context.t -> Tez_repr.t list + +val quorum_min : Raw_context.t -> int32 + +val quorum_max : Raw_context.t -> int32 + +val min_proposal_quorum : Raw_context.t -> int32 + +val liquidity_baking_subsidy : Raw_context.t -> Tez_repr.t + +val liquidity_baking_sunset_level : Raw_context.t -> int32 + +val liquidity_baking_escape_ema_threshold : Raw_context.t -> int32 + +val parametric : Raw_context.t -> Constants_repr.parametric diff --git a/src/proto_011_PtHangzH/lib_protocol/contract_hash.ml b/src/proto_011_PtHangzH/lib_protocol/contract_hash.ml new file mode 100644 index 000000000000..c232a80278df --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contract_hash.ml @@ -0,0 +1,45 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* 20 *) +let contract_hash = "\002\090\121" (* KT1(36) *) + +module H = + Blake2B.Make + (Base58) + (struct + let name = "Contract_hash" + + let title = "A contract ID" + + let b58check_prefix = contract_hash + + let size = Some 20 + end) + +include H +include Path_encoding.Make_hex (H) + +let () = Base58.check_encoded_prefix b58check_encoding "KT1" 36 diff --git a/src/proto_011_PtHangzH/lib_protocol/contract_hash.mli b/src/proto_011_PtHangzH/lib_protocol/contract_hash.mli new file mode 100644 index 000000000000..1cbc424150af --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contract_hash.mli @@ -0,0 +1,29 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** A specialized Blake2B implementation for hashing contract identifiers. *) + +include S.HASH diff --git a/src/proto_011_PtHangzH/lib_protocol/contract_repr.ml b/src/proto_011_PtHangzH/lib_protocol/contract_repr.ml new file mode 100644 index 000000000000..07b78e0fd888 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contract_repr.ml @@ -0,0 +1,213 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type t = + | Implicit of Signature.Public_key_hash.t + | Originated of Contract_hash.t + +include Compare.Make (struct + type nonrec t = t + + let compare l1 l2 = + match (l1, l2) with + | (Implicit pkh1, Implicit pkh2) -> + Signature.Public_key_hash.compare pkh1 pkh2 + | (Originated h1, Originated h2) -> Contract_hash.compare h1 h2 + | (Implicit _, Originated _) -> -1 + | (Originated _, Implicit _) -> 1 +end) + +type contract = t + +let blake2b_hash_size = + let open Cache_memory_helpers in + header_size +! word_size +! string_size_gen 20 + +let public_key_hash_in_memory_size = + let open Cache_memory_helpers in + header_size +! word_size +! blake2b_hash_size + +let in_memory_size = + let open Cache_memory_helpers in + function + | Implicit _ -> header_size +! word_size +! public_key_hash_in_memory_size + | Originated _ -> header_size +! word_size +! blake2b_hash_size + +type error += Invalid_contract_notation of string (* `Permanent *) + +let to_b58check = function + | Implicit pbk -> Signature.Public_key_hash.to_b58check pbk + | Originated h -> Contract_hash.to_b58check h + +let of_b58check s = + match Base58.decode s with + | Some data -> ( + match data with + | Ed25519.Public_key_hash.Data h -> ok (Implicit (Signature.Ed25519 h)) + | Secp256k1.Public_key_hash.Data h -> + ok (Implicit (Signature.Secp256k1 h)) + | P256.Public_key_hash.Data h -> ok (Implicit (Signature.P256 h)) + | Contract_hash.Data h -> ok (Originated h) + | _ -> error (Invalid_contract_notation s)) + | None -> error (Invalid_contract_notation s) + +let pp ppf = function + | Implicit pbk -> Signature.Public_key_hash.pp ppf pbk + | Originated h -> Contract_hash.pp ppf h + +let pp_short ppf = function + | Implicit pbk -> Signature.Public_key_hash.pp_short ppf pbk + | Originated h -> Contract_hash.pp_short ppf h + +let encoding = + let open Data_encoding in + def + "contract_id" + ~title:"A contract handle" + ~description: + "A contract notation as given to an RPC or inside scripts. Can be a \ + base58 implicit contract hash or a base58 originated contract hash." + @@ splitted + ~binary: + (union + ~tag_size:`Uint8 + [ + case + (Tag 0) + ~title:"Implicit" + Signature.Public_key_hash.encoding + (function Implicit k -> Some k | _ -> None) + (fun k -> Implicit k); + case + (Tag 1) + (Fixed.add_padding Contract_hash.encoding 1) + ~title:"Originated" + (function Originated k -> Some k | _ -> None) + (fun k -> Originated k); + ]) + ~json: + (conv + to_b58check + (fun s -> + match of_b58check s with + | Ok s -> s + | Error _ -> Json.cannot_destruct "Invalid contract notation.") + string) + +let () = + let open Data_encoding in + register_error_kind + `Permanent + ~id:"contract.invalid_contract_notation" + ~title:"Invalid contract notation" + ~pp:(fun ppf x -> Format.fprintf ppf "Invalid contract notation %S" x) + ~description: + "A malformed contract notation was given to an RPC or in a script." + (obj1 (req "notation" string)) + (function Invalid_contract_notation loc -> Some loc | _ -> None) + (fun loc -> Invalid_contract_notation loc) + +let implicit_contract id = Implicit id + +let is_implicit = function Implicit m -> Some m | Originated _ -> None + +let is_originated = function Implicit _ -> None | Originated h -> Some h + +type origination_nonce = { + operation_hash : Operation_hash.t; + origination_index : int32; +} + +let origination_nonce_encoding = + let open Data_encoding in + conv + (fun {operation_hash; origination_index} -> + (operation_hash, origination_index)) + (fun (operation_hash, origination_index) -> + {operation_hash; origination_index}) + @@ obj2 (req "operation" Operation_hash.encoding) (dft "index" int32 0l) + +let originated_contract nonce = + let data = + Data_encoding.Binary.to_bytes_exn origination_nonce_encoding nonce + in + Originated (Contract_hash.hash_bytes [data]) + +let originated_contracts + ~since:{origination_index = first; operation_hash = first_hash} + ~until: + ({origination_index = last; operation_hash = last_hash} as + origination_nonce) = + assert (Operation_hash.equal first_hash last_hash) ; + let[@coq_struct "origination_index"] rec contracts acc origination_index = + if Compare.Int32.(origination_index < first) then acc + else + let origination_nonce = {origination_nonce with origination_index} in + let acc = originated_contract origination_nonce :: acc in + contracts acc (Int32.pred origination_index) + in + contracts [] (Int32.pred last) + +let initial_origination_nonce operation_hash = + {operation_hash; origination_index = 0l} + +let incr_origination_nonce nonce = + let origination_index = Int32.succ nonce.origination_index in + {nonce with origination_index} + +let rpc_arg = + let construct = to_b58check in + let destruct hash = + Result.map_error (fun _ -> "Cannot parse contract id") (of_b58check hash) + in + RPC_arg.make + ~descr:"A contract identifier encoded in b58check." + ~name:"contract_id" + ~construct + ~destruct + () + +module Index = struct + type t = contract + + let path_length = 1 + + let to_path c l = + let raw_key = Data_encoding.Binary.to_bytes_exn encoding c in + let (`Hex key) = Hex.of_bytes raw_key in + key :: l + + let of_path = function + | [key] -> + let raw_key = Hex.to_bytes (`Hex key) in + Data_encoding.Binary.of_bytes_opt encoding raw_key + | _ -> None + + let rpc_arg = rpc_arg + + let encoding = encoding + + let compare = compare +end diff --git a/src/proto_011_PtHangzH/lib_protocol/contract_repr.mli b/src/proto_011_PtHangzH/lib_protocol/contract_repr.mli new file mode 100644 index 000000000000..803275062627 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contract_repr.mli @@ -0,0 +1,99 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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 defines identifiers for two basic types of contracts. It also + specifies how to compute originated contract's hash from origination + nonce. *) + +(** A contract is simply an account on the blockchain ledger. There are two + types of contracts: + - implicit contracts represent accounts of users of the blockchain; + - originated are special accounts with a Michelson script attached to + them. Every time a transaction is sent to an originated account, its + associated script is run in order to trigger some action in response. + + An implicit account is identified by the hash of the public key which was + used to create it. The owner of the corresponding private key is the + holder of the account. An originated contract's hash is derived from its + origination nonce (see below). *) +type t = private + | Implicit of Signature.Public_key_hash.t + | Originated of Contract_hash.t + +type contract = t + +include Compare.S with type t := contract + +val public_key_hash_in_memory_size : Cache_memory_helpers.sint + +val in_memory_size : t -> Cache_memory_helpers.sint + +(** {2 Implicit contracts} *) + +val implicit_contract : Signature.Public_key_hash.t -> contract + +val is_implicit : contract -> Signature.Public_key_hash.t option + +(** {2 Originated contracts} *) + +(** Originated contracts handles are crafted from the hash of the + operation that triggered their origination (and nothing else). + As a single operation can trigger several originations, the + corresponding handles are forged from a deterministic sequence of + nonces, initialized with the hash of the operation. *) +type origination_nonce + +val originated_contract : origination_nonce -> contract + +val originated_contracts : + since:origination_nonce -> until:origination_nonce -> contract list + +val initial_origination_nonce : Operation_hash.t -> origination_nonce + +val incr_origination_nonce : origination_nonce -> origination_nonce + +val is_originated : contract -> Contract_hash.t option + +(** {2 Human readable notation} *) + +type error += Invalid_contract_notation of string (* `Permanent *) + +val to_b58check : contract -> string + +val of_b58check : string -> contract tzresult + +val pp : Format.formatter -> contract -> unit + +val pp_short : Format.formatter -> contract -> unit + +(** {2 Serializers} *) + +val encoding : contract Data_encoding.t + +val origination_nonce_encoding : origination_nonce Data_encoding.t + +val rpc_arg : contract RPC_arg.arg + +module Index : Storage_description.INDEX with type t = t diff --git a/src/proto_011_PtHangzH/lib_protocol/contract_services.ml b/src/proto_011_PtHangzH/lib_protocol/contract_services.ml new file mode 100644 index 000000000000..c037693609be --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contract_services.ml @@ -0,0 +1,516 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +let custom_root = + (RPC_path.(open_root / "context" / "contracts") + : RPC_context.t RPC_path.context) + +let big_map_root = + (RPC_path.(open_root / "context" / "big_maps") + : RPC_context.t RPC_path.context) + +type info = { + balance : Tez.t; + delegate : public_key_hash option; + counter : counter option; + script : Script.t option; +} + +let info_encoding = + let open Data_encoding in + conv + (fun {balance; delegate; script; counter} -> + (balance, delegate, script, counter)) + (fun (balance, delegate, script, counter) -> + {balance; delegate; script; counter}) + @@ obj4 + (req "balance" Tez.encoding) + (opt "delegate" Signature.Public_key_hash.encoding) + (opt "script" Script.encoding) + (opt "counter" n) + +module S = struct + open Data_encoding + + let balance = + RPC_service.get_service + ~description:"Access the balance of a contract." + ~query:RPC_query.empty + ~output:Tez.encoding + RPC_path.(custom_root /: Contract.rpc_arg / "balance") + + let manager_key = + RPC_service.get_service + ~description:"Access the manager of a contract." + ~query:RPC_query.empty + ~output:(option Signature.Public_key.encoding) + RPC_path.(custom_root /: Contract.rpc_arg / "manager_key") + + let delegate = + RPC_service.get_service + ~description:"Access the delegate of a contract, if any." + ~query:RPC_query.empty + ~output:Signature.Public_key_hash.encoding + RPC_path.(custom_root /: Contract.rpc_arg / "delegate") + + let counter = + RPC_service.get_service + ~description:"Access the counter of a contract, if any." + ~query:RPC_query.empty + ~output:z + RPC_path.(custom_root /: Contract.rpc_arg / "counter") + + let script = + RPC_service.get_service + ~description:"Access the code and data of the contract." + ~query:RPC_query.empty + ~output:Script.encoding + RPC_path.(custom_root /: Contract.rpc_arg / "script") + + let storage = + RPC_service.get_service + ~description:"Access the data of the contract." + ~query:RPC_query.empty + ~output:Script.expr_encoding + RPC_path.(custom_root /: Contract.rpc_arg / "storage") + + let entrypoint_type = + RPC_service.get_service + ~description:"Return the type of the given entrypoint of the contract" + ~query:RPC_query.empty + ~output:Script.expr_encoding + RPC_path.( + custom_root /: Contract.rpc_arg / "entrypoints" /: RPC_arg.string) + + let list_entrypoints = + RPC_service.get_service + ~description:"Return the list of entrypoints of the contract" + ~query:RPC_query.empty + ~output: + (obj2 + (dft + "unreachable" + (Data_encoding.list + (obj1 + (req + "path" + (Data_encoding.list + Michelson_v1_primitives.prim_encoding)))) + []) + (req "entrypoints" (assoc Script.expr_encoding))) + RPC_path.(custom_root /: Contract.rpc_arg / "entrypoints") + + let contract_big_map_get_opt = + RPC_service.post_service + ~description: + "Access the value associated with a key in a big map of the contract \ + (deprecated)." + ~query:RPC_query.empty + ~input: + (obj2 + (req "key" Script.expr_encoding) + (req "type" Script.expr_encoding)) + ~output:(option Script.expr_encoding) + RPC_path.(custom_root /: Contract.rpc_arg / "big_map_get") + + let big_map_get = + RPC_service.get_service + ~description:"Access the value associated with a key in a big map." + ~query:RPC_query.empty + ~output:Script.expr_encoding + RPC_path.(big_map_root /: Big_map.Id.rpc_arg /: Script_expr_hash.rpc_arg) + + type big_map_get_all_query = {offset : int option; length : int option} + + let rpc_arg_uint : int RPC_arg.t = + let int_of_string s = + int_of_string_opt s + |> Option.to_result + ~none:(Format.sprintf "Cannot parse integer value %s" s) + >>? fun i -> + if Compare.Int.(i < 0) then + Error (Format.sprintf "Negative integer: %d" i) + else Ok i + in + RPC_arg.make + ~name:"uint" + ~descr:"A non-negative integer (greater than or equal to 0)." + ~destruct:int_of_string + ~construct:string_of_int + () + + let big_map_get_all_query : big_map_get_all_query RPC_query.t = + let open RPC_query in + query (fun offset length -> {offset; length}) + |+ opt_field + ~descr: + "Skip the first [offset] values. Useful in combination with \ + [length] for pagination." + "offset" + rpc_arg_uint + (fun t -> t.offset) + |+ opt_field + ~descr: + "Only retrieve [length] values. Useful in combination with [offset] \ + for pagination." + "length" + rpc_arg_uint + (fun t -> t.length) + |> seal + + let big_map_get_all = + RPC_service.get_service + ~description: + "Get the (optionally paginated) list of values in a big map. Order of \ + values is unspecified, but is guaranteed to be consistent." + ~query:big_map_get_all_query + ~output:(list Script.expr_encoding) + RPC_path.(big_map_root /: Big_map.Id.rpc_arg) + + let info = + RPC_service.get_service + ~description:"Access the complete status of a contract." + ~query:RPC_query.empty + ~output:info_encoding + RPC_path.(custom_root /: Contract.rpc_arg) + + let list = + RPC_service.get_service + ~description: + "All existing contracts (including non-empty default contracts)." + ~query:RPC_query.empty + ~output:(list Contract.encoding) + custom_root + + module Sapling = struct + (* + Sapling: these RPCs are like Sapling RPCs (sapling_services.ml) + specialized for contracts containing a single sapling state. + *) + + let single_sapling_get_id ctxt contract_id = + Contract.get_script ctxt contract_id >>=? fun (ctxt, script) -> + match script with + | None -> return (None, ctxt) + | Some script -> + let ctxt = Gas.set_unlimited ctxt in + Script_ir_translator.parse_script + ctxt + ~legacy:true + ~allow_forged_in_storage:true + script + >|= fun tzresult -> + tzresult >>? fun (Ex_script script, ctxt) -> + Script_ir_translator.get_single_sapling_state + ctxt + script.storage_type + script.storage + + let make_service + Sapling_services.S.Args.{name; description; query; output; f} = + let name = "single_sapling_" ^ name in + let path = RPC_path.(custom_root /: Contract.rpc_arg / name) in + let service = RPC_service.get_service ~description ~query ~output path in + ( service, + fun ctxt contract_id q () -> + single_sapling_get_id ctxt contract_id >>=? fun (sapling_id, ctxt) -> + Option.map_es (fun sapling_id -> f ctxt sapling_id q) sapling_id ) + + let get_diff = make_service Sapling_services.S.Args.get_diff + + let register () = + let reg chunked (service, f) = + Services_registration.opt_register1 ~chunked service f + in + reg false get_diff + + let mk_call1 (service, _f) ctxt block id q = + RPC_context.make_call1 service ctxt block id q () + end +end + +let[@coq_axiom_with_reason "gadt"] register () = + let open Services_registration in + register0 ~chunked:true S.list (fun ctxt () () -> Contract.list ctxt >|= ok) ; + let register_field ~chunked s f = + opt_register1 ~chunked s (fun ctxt contract () () -> + Contract.exists ctxt contract >>=? function + | true -> f ctxt contract >|=? Option.some + | false -> return_none) + in + let register_opt_field ~chunked s f = + opt_register1 ~chunked s (fun ctxt contract () () -> + Contract.exists ctxt contract >>=? function + | true -> f ctxt contract + | false -> return_none) + in + let do_big_map_get ctxt id key = + let open Script_ir_translator in + let ctxt = Gas.set_unlimited ctxt in + Big_map.exists ctxt id >>=? fun (ctxt, types) -> + match types with + | None -> return_none + | Some (_, value_type) -> ( + parse_big_map_value_ty ctxt ~legacy:true (Micheline.root value_type) + >>?= fun (Ex_ty value_type, ctxt) -> + Big_map.get_opt ctxt id key >>=? fun (_ctxt, value) -> + match value with + | None -> return_none + | Some value -> + parse_data + ctxt + ~legacy:true + ~allow_forged:true + value_type + (Micheline.root value) + >>=? fun (value, ctxt) -> + unparse_data ctxt Readable value_type value + >|=? fun (value, _ctxt) -> Some (Micheline.strip_locations value)) + in + let do_big_map_get_all ?offset ?length ctxt id = + let open Script_ir_translator in + let ctxt = Gas.set_unlimited ctxt in + Big_map.exists ctxt id >>=? fun (ctxt, types) -> + match types with + | None -> raise Not_found + | Some (_, value_type) -> + parse_big_map_value_ty ctxt ~legacy:true (Micheline.root value_type) + >>?= fun (Ex_ty value_type, ctxt) -> + Big_map.list_values ?offset ?length ctxt id >>=? fun (ctxt, values) -> + List.fold_left_s + (fun acc value -> + acc >>?= fun (ctxt, rev_values) -> + parse_data + ctxt + ~legacy:true + ~allow_forged:true + value_type + (Micheline.root value) + >>=? fun (value, ctxt) -> + unparse_data ctxt Readable value_type value + >|=? fun (value, ctxt) -> + (ctxt, Micheline.strip_locations value :: rev_values)) + (Ok (ctxt, [])) + values + >|=? fun (_ctxt, rev_values) -> List.rev rev_values + in + register_field ~chunked:false S.balance Contract.get_balance ; + opt_register1 ~chunked:false S.manager_key (fun ctxt contract () () -> + match Contract.is_implicit contract with + | None -> return_none + | Some mgr -> ( + Contract.is_manager_key_revealed ctxt mgr >>=? function + | false -> return_some None + | true -> + Contract.get_manager_key ctxt mgr >|=? fun key -> Some (Some key))) ; + register_opt_field ~chunked:false S.delegate Delegate.get ; + opt_register1 ~chunked:false S.counter (fun ctxt contract () () -> + match Contract.is_implicit contract with + | None -> return_none + | Some mgr -> + Contract.get_counter ctxt mgr >|=? fun counter -> Some counter) ; + register_opt_field ~chunked:true S.script (fun c v -> + Contract.get_script c v >|=? fun (_, v) -> v) ; + register_opt_field ~chunked:true S.storage (fun ctxt contract -> + Contract.get_script ctxt contract >>=? fun (ctxt, script) -> + match script with + | None -> return_none + | Some script -> + let ctxt = Gas.set_unlimited ctxt in + let open Script_ir_translator in + parse_script ctxt ~legacy:true ~allow_forged_in_storage:true script + >>=? fun (Ex_script script, ctxt) -> + unparse_script ctxt Readable script >>=? fun (script, ctxt) -> + Script.force_decode_in_context ctxt script.storage + >>?= fun (storage, _ctxt) -> return_some storage) ; + opt_register2 ~chunked:true S.entrypoint_type (fun ctxt v entrypoint () () -> + Contract.get_script_code ctxt v >>=? fun (_, expr) -> + match expr with + | None -> return_none + | Some expr -> + let ctxt = Gas.set_unlimited ctxt in + let legacy = true in + let open Script_ir_translator in + Lwt.return + ( Script.force_decode_in_context ctxt expr >>? fun (expr, _) -> + ( parse_toplevel ctxt ~legacy expr + >>? fun ({arg_type; root_name; _}, ctxt) -> + parse_parameter_ty ctxt ~legacy arg_type + >>? fun (Ex_ty arg_type, _) -> + Script_ir_translator.find_entrypoint + ~root_name + arg_type + entrypoint ) + |> function + | Ok (_f, Ex_ty ty) -> + unparse_ty ctxt ty >|? fun (ty_node, _) -> + Some (Micheline.strip_locations ty_node) + | Error _ -> ok_none )) ; + opt_register1 ~chunked:true S.list_entrypoints (fun ctxt v () () -> + Contract.get_script_code ctxt v >>=? fun (_, expr) -> + match expr with + | None -> return_none + | Some expr -> + let ctxt = Gas.set_unlimited ctxt in + let legacy = true in + let open Script_ir_translator in + Lwt.return + ( Script.force_decode_in_context ctxt expr >>? fun (expr, _) -> + ( parse_toplevel ctxt ~legacy expr + >>? fun ({arg_type; root_name; _}, ctxt) -> + parse_parameter_ty ctxt ~legacy arg_type + >>? fun (Ex_ty arg_type, _) -> + Script_ir_translator.list_entrypoints ~root_name arg_type ctxt + ) + >|? fun (unreachable_entrypoint, map) -> + Some + ( unreachable_entrypoint, + Entrypoints_map.fold + (fun entry (_, ty) acc -> + (entry, Micheline.strip_locations ty) :: acc) + map + [] ) )) ; + opt_register1 + ~chunked:true + S.contract_big_map_get_opt + (fun ctxt contract () (key, key_type) -> + Contract.get_script ctxt contract >>=? fun (ctxt, script) -> + let key_type_node = Micheline.root key_type in + Script_ir_translator.parse_comparable_ty ctxt key_type_node + >>?= fun (Ex_comparable_ty key_type, ctxt) -> + Script_ir_translator.parse_comparable_data + ctxt + key_type + (Micheline.root key) + >>=? fun (key, ctxt) -> + Script_ir_translator.hash_comparable_data ctxt key_type key + >>=? fun (key, ctxt) -> + match script with + | None -> return_none + | Some script -> ( + let ctxt = Gas.set_unlimited ctxt in + let open Script_ir_translator in + parse_script ctxt ~legacy:true ~allow_forged_in_storage:true script + >>=? fun (Ex_script script, ctxt) -> + Script_ir_translator.collect_lazy_storage + ctxt + script.storage_type + script.storage + >>?= fun (ids, _ctxt) -> + match Script_ir_translator.list_of_big_map_ids ids with + | [] | _ :: _ :: _ -> return_some None + | [id] -> do_big_map_get ctxt id key >|=? Option.some)) ; + opt_register2 ~chunked:true S.big_map_get (fun ctxt id key () () -> + do_big_map_get ctxt id key) ; + register1 ~chunked:true S.big_map_get_all (fun ctxt id {offset; length} () -> + do_big_map_get_all ?offset ?length ctxt id) ; + register_field ~chunked:false S.info (fun ctxt contract -> + Contract.get_balance ctxt contract >>=? fun balance -> + Delegate.get ctxt contract >>=? fun delegate -> + (match Contract.is_implicit contract with + | Some manager -> + Contract.get_counter ctxt manager >>=? fun counter -> + return_some counter + | None -> return_none) + >>=? fun counter -> + Contract.get_script ctxt contract >>=? fun (ctxt, script) -> + (match script with + | None -> return (None, ctxt) + | Some script -> + let ctxt = Gas.set_unlimited ctxt in + let open Script_ir_translator in + parse_script ctxt ~legacy:true ~allow_forged_in_storage:true script + >>=? fun (Ex_script script, ctxt) -> + unparse_script ctxt Readable script >|=? fun (script, ctxt) -> + (Some script, ctxt)) + >|=? fun (script, _ctxt) -> {balance; delegate; script; counter}) ; + S.Sapling.register () + +let list ctxt block = RPC_context.make_call0 S.list ctxt block () () + +let info ctxt block contract = + RPC_context.make_call1 S.info ctxt block contract () () + +let balance ctxt block contract = + RPC_context.make_call1 S.balance ctxt block contract () () + +let manager_key ctxt block mgr = + RPC_context.make_call1 + S.manager_key + ctxt + block + (Contract.implicit_contract mgr) + () + () + +let delegate ctxt block contract = + RPC_context.make_call1 S.delegate ctxt block contract () () + +let delegate_opt ctxt block contract = + RPC_context.make_opt_call1 S.delegate ctxt block contract () () + +let counter ctxt block mgr = + RPC_context.make_call1 + S.counter + ctxt + block + (Contract.implicit_contract mgr) + () + () + +let script ctxt block contract = + RPC_context.make_call1 S.script ctxt block contract () () + +let script_opt ctxt block contract = + RPC_context.make_opt_call1 S.script ctxt block contract () () + +let storage ctxt block contract = + RPC_context.make_call1 S.storage ctxt block contract () () + +let entrypoint_type ctxt block contract entrypoint = + RPC_context.make_call2 S.entrypoint_type ctxt block contract entrypoint () () + +let list_entrypoints ctxt block contract = + RPC_context.make_call1 S.list_entrypoints ctxt block contract () () + +let storage_opt ctxt block contract = + RPC_context.make_opt_call1 S.storage ctxt block contract () () + +let big_map_get ctxt block id key = + RPC_context.make_call2 S.big_map_get ctxt block id key () () + +let contract_big_map_get_opt ctxt block contract key = + RPC_context.make_call1 S.contract_big_map_get_opt ctxt block contract () key + +let single_sapling_get_diff ctxt block id ?offset_commitment ?offset_nullifier + () = + S.Sapling.(mk_call1 get_diff) + ctxt + block + id + Sapling_services.{offset_commitment; offset_nullifier} diff --git a/src/proto_011_PtHangzH/lib_protocol/contract_services.mli b/src/proto_011_PtHangzH/lib_protocol/contract_services.mli new file mode 100644 index 000000000000..458dfbe4d617 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contract_services.mli @@ -0,0 +1,126 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +val list : 'a #RPC_context.simple -> 'a -> Contract.t list shell_tzresult Lwt.t + +type info = { + balance : Tez.t; + delegate : public_key_hash option; + counter : counter option; + script : Script.t option; +} + +val info_encoding : info Data_encoding.t + +val info : + 'a #RPC_context.simple -> 'a -> Contract.t -> info shell_tzresult Lwt.t + +val balance : + 'a #RPC_context.simple -> 'a -> Contract.t -> Tez.t shell_tzresult Lwt.t + +val manager_key : + 'a #RPC_context.simple -> + 'a -> + public_key_hash -> + public_key option shell_tzresult Lwt.t + +val delegate : + 'a #RPC_context.simple -> + 'a -> + Contract.t -> + public_key_hash shell_tzresult Lwt.t + +val delegate_opt : + 'a #RPC_context.simple -> + 'a -> + Contract.t -> + public_key_hash option shell_tzresult Lwt.t + +val counter : + 'a #RPC_context.simple -> + 'a -> + public_key_hash -> + counter shell_tzresult Lwt.t + +val script : + 'a #RPC_context.simple -> 'a -> Contract.t -> Script.t shell_tzresult Lwt.t + +val script_opt : + 'a #RPC_context.simple -> + 'a -> + Contract.t -> + Script.t option shell_tzresult Lwt.t + +val storage : + 'a #RPC_context.simple -> 'a -> Contract.t -> Script.expr shell_tzresult Lwt.t + +val entrypoint_type : + 'a #RPC_context.simple -> + 'a -> + Contract.t -> + string -> + Script.expr shell_tzresult Lwt.t + +val list_entrypoints : + 'a #RPC_context.simple -> + 'a -> + Contract.t -> + (Michelson_v1_primitives.prim list list * (string * Script.expr) list) + shell_tzresult + Lwt.t + +val storage_opt : + 'a #RPC_context.simple -> + 'a -> + Contract.t -> + Script.expr option shell_tzresult Lwt.t + +val big_map_get : + 'a #RPC_context.simple -> + 'a -> + Big_map.Id.t -> + Script_expr_hash.t -> + Script.expr shell_tzresult Lwt.t + +val contract_big_map_get_opt : + 'a #RPC_context.simple -> + 'a -> + Contract.t -> + Script.expr * Script.expr -> + Script.expr option shell_tzresult Lwt.t + +val single_sapling_get_diff : + 'a #RPC_context.simple -> + 'a -> + Contract.t -> + ?offset_commitment:int64 -> + ?offset_nullifier:int64 -> + unit -> + (Sapling.root * Sapling.diff) shell_tzresult Lwt.t + +val register : unit -> unit diff --git a/src/proto_011_PtHangzH/lib_protocol/contract_storage.ml b/src/proto_011_PtHangzH/lib_protocol/contract_storage.ml new file mode 100644 index 000000000000..d683a8fd66fb --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contract_storage.ml @@ -0,0 +1,744 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += + | Balance_too_low of Contract_repr.contract * Tez_repr.t * Tez_repr.t + | (* `Temporary *) + Counter_in_the_past of Contract_repr.contract * Z.t * Z.t + | (* `Branch *) + Counter_in_the_future of Contract_repr.contract * Z.t * Z.t + | (* `Temporary *) + Unspendable_contract of Contract_repr.contract + | (* `Permanent *) + Non_existing_contract of Contract_repr.contract + | (* `Temporary *) + Empty_implicit_contract of Signature.Public_key_hash.t + | (* `Temporary *) + Empty_implicit_delegated_contract of + Signature.Public_key_hash.t + | (* `Temporary *) + Empty_transaction of Contract_repr.t (* `Temporary *) + | Inconsistent_hash of + Signature.Public_key.t + * Signature.Public_key_hash.t + * Signature.Public_key_hash.t + | (* `Permanent *) + Inconsistent_public_key of + Signature.Public_key.t * Signature.Public_key.t + | (* `Permanent *) + Failure of string (* `Permanent *) + | Previously_revealed_key of Contract_repr.t (* `Permanent *) + | Unrevealed_manager_key of Contract_repr.t + +(* `Permanent *) + +let () = + register_error_kind + `Permanent + ~id:"contract.unspendable_contract" + ~title:"Unspendable contract" + ~description: + "An operation tried to spend tokens from an unspendable contract" + ~pp:(fun ppf c -> + Format.fprintf + ppf + "The tokens of contract %a can only be spent by its script" + Contract_repr.pp + c) + Data_encoding.(obj1 (req "contract" Contract_repr.encoding)) + (function Unspendable_contract c -> Some c | _ -> None) + (fun c -> Unspendable_contract c) ; + register_error_kind + `Temporary + ~id:"contract.balance_too_low" + ~title:"Balance too low" + ~description:"An operation tried to spend more tokens than the contract has" + ~pp:(fun ppf (c, b, a) -> + Format.fprintf + ppf + "Balance of contract %a too low (%a) to spend %a" + Contract_repr.pp + c + Tez_repr.pp + b + Tez_repr.pp + a) + Data_encoding.( + obj3 + (req "contract" Contract_repr.encoding) + (req "balance" Tez_repr.encoding) + (req "amount" Tez_repr.encoding)) + (function Balance_too_low (c, b, a) -> Some (c, b, a) | _ -> None) + (fun (c, b, a) -> Balance_too_low (c, b, a)) ; + register_error_kind + `Temporary + ~id:"contract.counter_in_the_future" + ~title:"Invalid counter (not yet reached) in a manager operation" + ~description:"An operation assumed a contract counter in the future" + ~pp:(fun ppf (contract, exp, found) -> + Format.fprintf + ppf + "Counter %a not yet reached for contract %a (expected %a)" + Z.pp_print + found + Contract_repr.pp + contract + Z.pp_print + exp) + Data_encoding.( + obj3 + (req "contract" Contract_repr.encoding) + (req "expected" z) + (req "found" z)) + (function Counter_in_the_future (c, x, y) -> Some (c, x, y) | _ -> None) + (fun (c, x, y) -> Counter_in_the_future (c, x, y)) ; + register_error_kind + `Branch + ~id:"contract.counter_in_the_past" + ~title:"Invalid counter (already used) in a manager operation" + ~description:"An operation assumed a contract counter in the past" + ~pp:(fun ppf (contract, exp, found) -> + Format.fprintf + ppf + "Counter %a already used for contract %a (expected %a)" + Z.pp_print + found + Contract_repr.pp + contract + Z.pp_print + exp) + Data_encoding.( + obj3 + (req "contract" Contract_repr.encoding) + (req "expected" z) + (req "found" z)) + (function Counter_in_the_past (c, x, y) -> Some (c, x, y) | _ -> None) + (fun (c, x, y) -> Counter_in_the_past (c, x, y)) ; + register_error_kind + `Temporary + ~id:"contract.non_existing_contract" + ~title:"Non existing contract" + ~description: + "A contract handle is not present in the context (either it never was or \ + it has been destroyed)" + ~pp:(fun ppf contract -> + Format.fprintf ppf "Contract %a does not exist" Contract_repr.pp contract) + Data_encoding.(obj1 (req "contract" Contract_repr.encoding)) + (function Non_existing_contract c -> Some c | _ -> None) + (fun c -> Non_existing_contract c) ; + register_error_kind + `Permanent + ~id:"contract.manager.inconsistent_hash" + ~title:"Inconsistent public key hash" + ~description: + "A revealed manager public key is inconsistent with the announced hash" + ~pp:(fun ppf (k, eh, ph) -> + Format.fprintf + ppf + "The hash of the manager public key %s is not %a as announced but %a" + (Signature.Public_key.to_b58check k) + Signature.Public_key_hash.pp + ph + Signature.Public_key_hash.pp + eh) + Data_encoding.( + obj3 + (req "public_key" Signature.Public_key.encoding) + (req "expected_hash" Signature.Public_key_hash.encoding) + (req "provided_hash" Signature.Public_key_hash.encoding)) + (function Inconsistent_hash (k, eh, ph) -> Some (k, eh, ph) | _ -> None) + (fun (k, eh, ph) -> Inconsistent_hash (k, eh, ph)) ; + register_error_kind + `Permanent + ~id:"contract.manager.inconsistent_public_key" + ~title:"Inconsistent public key" + ~description: + "A provided manager public key is different with the public key stored \ + in the contract" + ~pp:(fun ppf (eh, ph) -> + Format.fprintf + ppf + "Expected manager public key %s but %s was provided" + (Signature.Public_key.to_b58check ph) + (Signature.Public_key.to_b58check eh)) + Data_encoding.( + obj2 + (req "public_key" Signature.Public_key.encoding) + (req "expected_public_key" Signature.Public_key.encoding)) + (function Inconsistent_public_key (eh, ph) -> Some (eh, ph) | _ -> None) + (fun (eh, ph) -> Inconsistent_public_key (eh, ph)) ; + register_error_kind + `Permanent + ~id:"contract.failure" + ~title:"Contract storage failure" + ~description:"Unexpected contract storage error" + ~pp:(fun ppf s -> Format.fprintf ppf "Contract_storage.Failure %S" s) + Data_encoding.(obj1 (req "message" string)) + (function Failure s -> Some s | _ -> None) + (fun s -> Failure s) ; + register_error_kind + `Branch + ~id:"contract.unrevealed_key" + ~title:"Manager operation precedes key revelation" + ~description: + "One tried to apply a manager operation without revealing the manager \ + public key" + ~pp:(fun ppf s -> + Format.fprintf + ppf + "Unrevealed manager key for contract %a." + Contract_repr.pp + s) + Data_encoding.(obj1 (req "contract" Contract_repr.encoding)) + (function Unrevealed_manager_key s -> Some s | _ -> None) + (fun s -> Unrevealed_manager_key s) ; + register_error_kind + `Branch + ~id:"contract.previously_revealed_key" + ~title:"Manager operation already revealed" + ~description:"One tried to revealed twice a manager public key" + ~pp:(fun ppf s -> + Format.fprintf + ppf + "Previously revealed manager key for contract %a." + Contract_repr.pp + s) + Data_encoding.(obj1 (req "contract" Contract_repr.encoding)) + (function Previously_revealed_key s -> Some s | _ -> None) + (fun s -> Previously_revealed_key s) ; + register_error_kind + `Branch + ~id:"implicit.empty_implicit_contract" + ~title:"Empty implicit contract" + ~description: + "No manager operations are allowed on an empty implicit contract." + ~pp:(fun ppf implicit -> + Format.fprintf + ppf + "Empty implicit contract (%a)" + Signature.Public_key_hash.pp + implicit) + Data_encoding.(obj1 (req "implicit" Signature.Public_key_hash.encoding)) + (function Empty_implicit_contract c -> Some c | _ -> None) + (fun c -> Empty_implicit_contract c) ; + register_error_kind + `Branch + ~id:"implicit.empty_implicit_delegated_contract" + ~title:"Empty implicit delegated contract" + ~description:"Emptying an implicit delegated account is not allowed." + ~pp:(fun ppf implicit -> + Format.fprintf + ppf + "Emptying implicit delegated contract (%a)" + Signature.Public_key_hash.pp + implicit) + Data_encoding.(obj1 (req "implicit" Signature.Public_key_hash.encoding)) + (function Empty_implicit_delegated_contract c -> Some c | _ -> None) + (fun c -> Empty_implicit_delegated_contract c) ; + register_error_kind + `Branch + ~id:"contract.empty_transaction" + ~title:"Empty transaction" + ~description:"Forbidden to credit 0ꜩ to a contract without code." + ~pp:(fun ppf contract -> + Format.fprintf + ppf + "Transaction of 0ꜩ towards a contract without code are forbidden \ + (%a)." + Contract_repr.pp + contract) + Data_encoding.(obj1 (req "contract" Contract_repr.encoding)) + (function Empty_transaction c -> Some c | _ -> None) + (fun c -> Empty_transaction c) + +let failwith msg = fail (Failure msg) + +module Legacy_big_map_diff = struct + (* + Big_map_diff receipt as it was represented in 006 and earlier. + It is kept here for now for backward compatibility of tools. *) + + type item = + | Update of { + big_map : Z.t; + diff_key : Script_repr.expr; + diff_key_hash : Script_expr_hash.t; + diff_value : Script_repr.expr option; + } + | Clear of Z.t + | Copy of {src : Z.t; dst : Z.t} + | Alloc of { + big_map : Z.t; + key_type : Script_repr.expr; + value_type : Script_repr.expr; + } + + type t = item list + + let item_encoding = + let open Data_encoding in + union + [ + case + (Tag 0) + ~title:"update" + (obj5 + (req "action" (constant "update")) + (req "big_map" z) + (req "key_hash" Script_expr_hash.encoding) + (req "key" Script_repr.expr_encoding) + (opt "value" Script_repr.expr_encoding)) + (function + | Update {big_map; diff_key_hash; diff_key; diff_value} -> + Some ((), big_map, diff_key_hash, diff_key, diff_value) + | _ -> None) + (fun ((), big_map, diff_key_hash, diff_key, diff_value) -> + Update {big_map; diff_key_hash; diff_key; diff_value}); + case + (Tag 1) + ~title:"remove" + (obj2 (req "action" (constant "remove")) (req "big_map" z)) + (function Clear big_map -> Some ((), big_map) | _ -> None) + (fun ((), big_map) -> Clear big_map); + case + (Tag 2) + ~title:"copy" + (obj3 + (req "action" (constant "copy")) + (req "source_big_map" z) + (req "destination_big_map" z)) + (function Copy {src; dst} -> Some ((), src, dst) | _ -> None) + (fun ((), src, dst) -> Copy {src; dst}); + case + (Tag 3) + ~title:"alloc" + (obj4 + (req "action" (constant "alloc")) + (req "big_map" z) + (req "key_type" Script_repr.expr_encoding) + (req "value_type" Script_repr.expr_encoding)) + (function + | Alloc {big_map; key_type; value_type} -> + Some ((), big_map, key_type, value_type) + | _ -> None) + (fun ((), big_map, key_type, value_type) -> + Alloc {big_map; key_type; value_type}); + ] + + let encoding = Data_encoding.list item_encoding + + let to_lazy_storage_diff legacy_diffs = + let rev_head (diffs : (_ * (_, _, _) Lazy_storage_diff.diff) list) = + match diffs with + | [] -> [] + | (_, Remove) :: _ -> diffs + | (id, Update {init; updates}) :: rest -> + (id, Update {init; updates = List.rev updates}) :: rest + in + (* Invariant: + Updates are collected one by one, in reverse order, on the head diff + item. So only and exactly the head diff item has its updates reversed. + *) + List.fold_left + (fun (new_diff : (_ * (_, _, _) Lazy_storage_diff.diff) list) item -> + match item with + | Clear id -> (id, Lazy_storage_diff.Remove) :: rev_head new_diff + | Copy {src; dst} -> + let src = + Lazy_storage_kind.Big_map.Id + .of_legacy_USE_ONLY_IN_Legacy_big_map_diff + src + in + (dst, Lazy_storage_diff.Update {init = Copy {src}; updates = []}) + :: rev_head new_diff + | Alloc {big_map; key_type; value_type} -> + ( big_map, + Lazy_storage_diff.( + Update + { + init = Alloc Lazy_storage_kind.Big_map.{key_type; value_type}; + updates = []; + }) ) + :: rev_head new_diff + | Update + { + big_map; + diff_key = key; + diff_key_hash = key_hash; + diff_value = value; + } -> ( + match new_diff with + | (id, diff) :: rest when Compare.Z.(id = big_map) -> + let diff = + match diff with + | Remove -> assert false + | Update {init; updates} -> + let updates = + Lazy_storage_kind.Big_map.{key; key_hash; value} + :: updates + in + Lazy_storage_diff.Update {init; updates} + in + (id, diff) :: rest + | new_diff -> + let updates = + [Lazy_storage_kind.Big_map.{key; key_hash; value}] + in + (big_map, Update {init = Existing; updates}) + :: rev_head new_diff)) + [] + legacy_diffs + |> rev_head + |> List.rev_map (fun (id, diff) -> + let id = + Lazy_storage_kind.Big_map.Id + .of_legacy_USE_ONLY_IN_Legacy_big_map_diff + id + in + Lazy_storage_diff.make Lazy_storage_kind.Big_map id diff) + + let of_lazy_storage_diff diffs = + List.fold_left + (fun legacy_diffs (Lazy_storage_diff.Item (kind, id, diff)) -> + let diffs = + match kind with + | Lazy_storage_kind.Big_map -> ( + let id = + Lazy_storage_kind.Big_map.Id + .to_legacy_USE_ONLY_IN_Legacy_big_map_diff + id + in + match diff with + | Remove -> [Clear id] + | Update {init; updates} -> ( + let updates = + List.rev_map + (fun {Lazy_storage_kind.Big_map.key; key_hash; value} -> + Update + { + big_map = id; + diff_key = key; + diff_key_hash = key_hash; + diff_value = value; + }) + updates + in + match init with + | Existing -> updates + | Copy {src} -> + let src = + Lazy_storage_kind.Big_map.Id + .to_legacy_USE_ONLY_IN_Legacy_big_map_diff + src + in + Copy {src; dst = id} :: updates + | Alloc {key_type; value_type} -> + Alloc {big_map = id; key_type; value_type} :: updates)) + | _ -> (* Not a Big_map *) [] + in + diffs :: legacy_diffs) + [] + diffs + |> List.rev |> List.flatten + [@@coq_axiom_with_reason "gadt"] +end + +let update_script_lazy_storage c = function + | None -> return (c, Z.zero) + | Some diffs -> Lazy_storage_diff.apply c diffs + +let create_base c ?(prepaid_bootstrap_storage = false) + (* Free space for bootstrap contracts *) + contract ~balance ~manager ~delegate ?script () = + (match Contract_repr.is_implicit contract with + | None -> return c + | Some _ -> + Storage.Contract.Global_counter.get c >>=? fun counter -> + Storage.Contract.Counter.init c contract counter) + >>=? fun c -> + Storage.Contract.Balance.init c contract balance >>=? fun c -> + (match manager with + | Some manager -> + Storage.Contract.Manager.init c contract (Manager_repr.Hash manager) + | None -> return c) + >>=? fun c -> + (match delegate with + | None -> return c + | Some delegate -> Delegate_storage.init c contract delegate) + >>=? fun c -> + match script with + | Some ({Script_repr.code; storage}, lazy_storage_diff) -> + Storage.Contract.Code.init c contract code >>=? fun (c, code_size) -> + Storage.Contract.Storage.init c contract storage + >>=? fun (c, storage_size) -> + update_script_lazy_storage c lazy_storage_diff + >>=? fun (c, lazy_storage_size) -> + let total_size = + Z.add + (Z.add (Z.of_int code_size) (Z.of_int storage_size)) + lazy_storage_size + in + assert (Compare.Z.(total_size >= Z.zero)) ; + let prepaid_bootstrap_storage = + if prepaid_bootstrap_storage then total_size else Z.zero + in + Storage.Contract.Paid_storage_space.init + c + contract + prepaid_bootstrap_storage + >>=? fun c -> + Storage.Contract.Used_storage_space.init c contract total_size + | None -> return c + +let raw_originate c ?prepaid_bootstrap_storage contract ~balance ~script + ~delegate = + create_base + c + ?prepaid_bootstrap_storage + contract + ~balance + ~manager:None + ~delegate + ~script + () + +let create_implicit c manager ~balance = + create_base + c + (Contract_repr.implicit_contract manager) + ~balance + ~manager:(Some manager) + ?script:None + ~delegate:None + () + +let delete c contract = + match Contract_repr.is_implicit contract with + | None -> + (* For non implicit contract Big_map should be cleared *) + failwith "Non implicit contracts cannot be removed" + | Some _ -> + Delegate_storage.remove c contract >>=? fun c -> + Storage.Contract.Balance.remove_existing c contract >>=? fun c -> + Storage.Contract.Manager.remove_existing c contract >>=? fun c -> + Storage.Contract.Counter.remove_existing c contract >>=? fun c -> + Storage.Contract.Code.remove c contract >>=? fun (c, _, _) -> + Storage.Contract.Storage.remove c contract >>=? fun (c, _, _) -> + Storage.Contract.Paid_storage_space.remove c contract >>= fun c -> + Storage.Contract.Used_storage_space.remove c contract >|= ok + +let allocated c contract = + Storage.Contract.Balance.find c contract >>=? function + | None -> return_false + | Some _ -> return_true + +let exists c contract = + match Contract_repr.is_implicit contract with + | Some _ -> return_true + | None -> allocated c contract + +let must_exist c contract = + exists c contract >>=? function + | true -> return_unit + | false -> fail (Non_existing_contract contract) + +let must_be_allocated c contract = + allocated c contract >>=? function + | true -> return_unit + | false -> ( + match Contract_repr.is_implicit contract with + | Some pkh -> fail (Empty_implicit_contract pkh) + | None -> fail (Non_existing_contract contract)) + +let list c = Storage.Contract.list c + +let fresh_contract_from_current_nonce c = + Raw_context.increment_origination_nonce c >|? fun (c, nonce) -> + (c, Contract_repr.originated_contract nonce) + +let originated_from_current_nonce ~since:ctxt_since ~until:ctxt_until = + Raw_context.get_origination_nonce ctxt_since >>?= fun since -> + Raw_context.get_origination_nonce ctxt_until >>?= fun until -> + List.filter_es + (fun contract -> exists ctxt_until contract) + (Contract_repr.originated_contracts ~since ~until) + +let check_counter_increment c manager counter = + let contract = Contract_repr.implicit_contract manager in + Storage.Contract.Counter.get c contract >>=? fun contract_counter -> + let expected = Z.succ contract_counter in + if Compare.Z.(expected = counter) then return_unit + else if Compare.Z.(expected > counter) then + fail (Counter_in_the_past (contract, expected, counter)) + else fail (Counter_in_the_future (contract, expected, counter)) + +let increment_counter c manager = + let contract = Contract_repr.implicit_contract manager in + Storage.Contract.Global_counter.get c >>=? fun global_counter -> + Storage.Contract.Global_counter.update c (Z.succ global_counter) >>=? fun c -> + Storage.Contract.Counter.get c contract >>=? fun contract_counter -> + Storage.Contract.Counter.update c contract (Z.succ contract_counter) + +let get_script_code c contract = Storage.Contract.Code.find c contract + +let get_script c contract = + Storage.Contract.Code.find c contract >>=? fun (c, code) -> + Storage.Contract.Storage.find c contract >>=? fun (c, storage) -> + match (code, storage) with + | (None, None) -> return (c, None) + | (Some code, Some storage) -> return (c, Some {Script_repr.code; storage}) + | (None, Some _) | (Some _, None) -> failwith "get_script" + +let get_storage ctxt contract = + Storage.Contract.Storage.find ctxt contract >>=? function + | (ctxt, None) -> return (ctxt, None) + | (ctxt, Some storage) -> + Raw_context.consume_gas ctxt (Script_repr.force_decode_cost storage) + >>?= fun ctxt -> + Script_repr.force_decode storage >>?= fun storage -> + return (ctxt, Some storage) + +let get_counter c manager = + let contract = Contract_repr.implicit_contract manager in + Storage.Contract.Counter.find c contract >>=? function + | None -> ( + match Contract_repr.is_implicit contract with + | Some _ -> Storage.Contract.Global_counter.get c + | None -> failwith "get_counter") + | Some v -> return v + +let get_manager_key c manager = + let contract = Contract_repr.implicit_contract manager in + Storage.Contract.Manager.find c contract >>=? function + | None -> failwith "get_manager_key" + | Some (Manager_repr.Hash _) -> fail (Unrevealed_manager_key contract) + | Some (Manager_repr.Public_key v) -> return v + +let is_manager_key_revealed c manager = + let contract = Contract_repr.implicit_contract manager in + Storage.Contract.Manager.find c contract >>=? function + | None -> return_false + | Some (Manager_repr.Hash _) -> return_false + | Some (Manager_repr.Public_key _) -> return_true + +let reveal_manager_key c manager public_key = + let contract = Contract_repr.implicit_contract manager in + Storage.Contract.Manager.get c contract >>=? function + | Public_key _ -> fail (Previously_revealed_key contract) + | Hash v -> + let actual_hash = Signature.Public_key.hash public_key in + if Signature.Public_key_hash.equal actual_hash v then + let v = Manager_repr.Public_key public_key in + Storage.Contract.Manager.update c contract v + else fail (Inconsistent_hash (public_key, v, actual_hash)) + +let get_balance c contract = + Storage.Contract.Balance.find c contract >>=? function + | None -> ( + match Contract_repr.is_implicit contract with + | Some _ -> return Tez_repr.zero + | None -> failwith "get_balance") + | Some v -> return v + +let get_balance_carbonated c contract = + (* Reading an int64 from /contracts/index//balance *) + Raw_context.consume_gas + c + (Storage_costs.read_access ~path_length:4 ~read_bytes:8) + >>?= fun c -> + get_balance c contract >>=? fun balance -> return (c, balance) + +let update_script_storage c contract storage lazy_storage_diff = + let storage = Script_repr.lazy_expr storage in + update_script_lazy_storage c lazy_storage_diff + >>=? fun (c, lazy_storage_size_diff) -> + Storage.Contract.Storage.update c contract storage >>=? fun (c, size_diff) -> + Storage.Contract.Used_storage_space.get c contract >>=? fun previous_size -> + let new_size = + Z.add previous_size (Z.add lazy_storage_size_diff (Z.of_int size_diff)) + in + Storage.Contract.Used_storage_space.update c contract new_size + +let spend c contract amount = + Storage.Contract.Balance.get c contract >>=? fun balance -> + match Tez_repr.(balance -? amount) with + | Error _ -> fail (Balance_too_low (contract, balance, amount)) + | Ok new_balance -> ( + Storage.Contract.Balance.update c contract new_balance >>=? fun c -> + Roll_storage.Contract.remove_amount c contract amount >>=? fun c -> + if Tez_repr.(new_balance > Tez_repr.zero) then return c + else + match Contract_repr.is_implicit contract with + | None -> return c (* Never delete originated contracts *) + | Some pkh -> ( + Delegate_storage.get c contract >>=? function + | Some pkh' -> + if Signature.Public_key_hash.equal pkh pkh' then return c + else + (* Delegated implicit accounts cannot be emptied *) + fail (Empty_implicit_delegated_contract pkh) + | None -> + (* Delete empty implicit contract *) + delete c contract)) + +let credit c contract amount = + (if Tez_repr.(amount <> Tez_repr.zero) then return_unit + else + error_unless + (Option.is_some (Contract_repr.is_originated contract)) + (Empty_transaction contract) + >>?= fun () -> must_exist c contract) + >>=? fun () -> + Storage.Contract.Balance.find c contract >>=? function + | None -> ( + match Contract_repr.is_implicit contract with + | None -> fail (Non_existing_contract contract) + | Some manager -> create_implicit c manager ~balance:amount) + | Some balance -> + Tez_repr.(amount +? balance) >>?= fun balance -> + Storage.Contract.Balance.update c contract balance >>=? fun c -> + Roll_storage.Contract.add_amount c contract amount + +let init c = + Storage.Contract.Global_counter.init c Z.zero >>=? fun c -> + Lazy_storage_diff.init c + +let used_storage_space c contract = + Storage.Contract.Used_storage_space.find c contract + >|=? Option.value ~default:Z.zero + +let paid_storage_space c contract = + Storage.Contract.Paid_storage_space.find c contract + >|=? Option.value ~default:Z.zero + +let set_paid_storage_space_and_return_fees_to_pay c contract new_storage_space = + Storage.Contract.Paid_storage_space.get c contract + >>=? fun already_paid_space -> + if Compare.Z.(already_paid_space >= new_storage_space) then return (Z.zero, c) + else + let to_pay = Z.sub new_storage_space already_paid_space in + Storage.Contract.Paid_storage_space.update c contract new_storage_space + >|=? fun c -> (to_pay, c) diff --git a/src/proto_011_PtHangzH/lib_protocol/contract_storage.mli b/src/proto_011_PtHangzH/lib_protocol/contract_storage.mli new file mode 100644 index 000000000000..290eb227aa72 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contract_storage.mli @@ -0,0 +1,185 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += + | Balance_too_low of Contract_repr.contract * Tez_repr.t * Tez_repr.t + | (* `Temporary *) + Counter_in_the_past of Contract_repr.contract * Z.t * Z.t + | (* `Branch *) + Counter_in_the_future of Contract_repr.contract * Z.t * Z.t + | (* `Temporary *) + Unspendable_contract of Contract_repr.contract + | (* `Permanent *) + Non_existing_contract of Contract_repr.contract + | (* `Temporary *) + Empty_implicit_contract of Signature.Public_key_hash.t + | (* `Temporary *) + Empty_implicit_delegated_contract of + Signature.Public_key_hash.t + | (* `Temporary *) + Empty_transaction of Contract_repr.t (* `Temporary *) + | Inconsistent_hash of + Signature.Public_key.t + * Signature.Public_key_hash.t + * Signature.Public_key_hash.t + | (* `Permanent *) + Inconsistent_public_key of + Signature.Public_key.t * Signature.Public_key.t + | (* `Permanent *) + Failure of string (* `Permanent *) + | Previously_revealed_key of Contract_repr.t (* `Permanent *) + | Unrevealed_manager_key of Contract_repr.t + +(* `Permanent *) + +val exists : Raw_context.t -> Contract_repr.t -> bool tzresult Lwt.t + +(** [must_exist ctxt contract] fails with the [Non_existing_contract] error if + [exists ctxt contract] returns [false]. Even though this function is + gas-free, it is always called in a context where some gas consumption is + guaranteed whenever necessary. The first context is that of a transfer + operation, and in that case the base cost of a manager operation + ([Micheclson_v1_gas.Cost_of.manager_operation]) is consumed. The second + context is that of an activation operation, and in that case no gas needs to + be consumed since that operation is not a manager operation. *) +val must_exist : Raw_context.t -> Contract_repr.t -> unit tzresult Lwt.t + +val allocated : Raw_context.t -> Contract_repr.t -> bool tzresult Lwt.t + +val must_be_allocated : Raw_context.t -> Contract_repr.t -> unit tzresult Lwt.t + +val list : Raw_context.t -> Contract_repr.t list Lwt.t + +val check_counter_increment : + Raw_context.t -> Signature.Public_key_hash.t -> Z.t -> unit tzresult Lwt.t + +val increment_counter : + Raw_context.t -> Signature.Public_key_hash.t -> Raw_context.t tzresult Lwt.t + +val get_manager_key : + Raw_context.t -> + Signature.Public_key_hash.t -> + Signature.Public_key.t tzresult Lwt.t + +val is_manager_key_revealed : + Raw_context.t -> Signature.Public_key_hash.t -> bool tzresult Lwt.t + +val reveal_manager_key : + Raw_context.t -> + Signature.Public_key_hash.t -> + Signature.Public_key.t -> + Raw_context.t tzresult Lwt.t + +val get_balance : Raw_context.t -> Contract_repr.t -> Tez_repr.t tzresult Lwt.t + +val get_balance_carbonated : + Raw_context.t -> + Contract_repr.t -> + (Raw_context.t * Tez_repr.t) tzresult Lwt.t + +val get_counter : + Raw_context.t -> Signature.Public_key_hash.t -> Z.t tzresult Lwt.t + +val get_script_code : + Raw_context.t -> + Contract_repr.t -> + (Raw_context.t * Script_repr.lazy_expr option) tzresult Lwt.t + +val get_script : + Raw_context.t -> + Contract_repr.t -> + (Raw_context.t * Script_repr.t option) tzresult Lwt.t + +val get_storage : + Raw_context.t -> + Contract_repr.t -> + (Raw_context.t * Script_repr.expr option) tzresult Lwt.t + +module Legacy_big_map_diff : sig + type item = private + | Update of { + big_map : Z.t; + diff_key : Script_repr.expr; + diff_key_hash : Script_expr_hash.t; + diff_value : Script_repr.expr option; + } + | Clear of Z.t + | Copy of {src : Z.t; dst : Z.t} + | Alloc of { + big_map : Z.t; + key_type : Script_repr.expr; + value_type : Script_repr.expr; + } + + type t = item list + + val encoding : t Data_encoding.t + + val to_lazy_storage_diff : t -> Lazy_storage_diff.diffs + + val of_lazy_storage_diff : Lazy_storage_diff.diffs -> t +end + +val update_script_storage : + Raw_context.t -> + Contract_repr.t -> + Script_repr.expr -> + Lazy_storage_diff.diffs option -> + Raw_context.t tzresult Lwt.t + +val credit : + Raw_context.t -> Contract_repr.t -> Tez_repr.t -> Raw_context.t tzresult Lwt.t + +val spend : + Raw_context.t -> Contract_repr.t -> Tez_repr.t -> Raw_context.t tzresult Lwt.t + +val raw_originate : + Raw_context.t -> + ?prepaid_bootstrap_storage:bool -> + Contract_repr.t -> + balance:Tez_repr.t -> + script:Script_repr.t * Lazy_storage_diff.diffs option -> + delegate:Signature.Public_key_hash.t option -> + Raw_context.t tzresult Lwt.t + +val fresh_contract_from_current_nonce : + Raw_context.t -> (Raw_context.t * Contract_repr.t) tzresult + +val originated_from_current_nonce : + since:Raw_context.t -> + until:Raw_context.t -> + Contract_repr.t list tzresult Lwt.t + +val init : Raw_context.t -> Raw_context.t tzresult Lwt.t + +val used_storage_space : Raw_context.t -> Contract_repr.t -> Z.t tzresult Lwt.t + +val paid_storage_space : Raw_context.t -> Contract_repr.t -> Z.t tzresult Lwt.t + +val set_paid_storage_space_and_return_fees_to_pay : + Raw_context.t -> + Contract_repr.t -> + Z.t -> + (Z.t * Raw_context.t) tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/contracts/cpmm.bin b/src/proto_011_PtHangzH/lib_protocol/contracts/cpmm.bin new file mode 100644 index 000000000000..c4e455868ecb --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contracts/cpmm.bin @@ -0,0 +1 @@ +0x02000011c405000764076407640865046e00000006256f776e6572076504620000000d256d696e4c71744d696e7465640765046200000013256d6178546f6b656e734465706f7369746564046b0000000925646561646c696e650000000d256164644c6971756964697479046c000000082564656661756c7407640865046e0000000325746f076504620000000a256c71744275726e65640765046a00000010256d696e58747a57697468647261776e0765046200000013256d696e546f6b656e7357697468647261776e046b0000000925646561646c696e65000000102572656d6f76654c69717569646974790865046e00000015256f7574707574446578746572436f6e74726163740765046200000010256d696e546f6b656e73426f756768740765046e0000000325746f076504620000000b25746f6b656e73536f6c64046b0000000925646561646c696e650000000d25746f6b656e546f546f6b656e07640865046e0000000325746f076504620000000b25746f6b656e73536f6c640765046a0000000d256d696e58747a426f75676874046b0000000925646561646c696e650000000b25746f6b656e546f58747a0865046e0000000325746f0765046200000010256d696e546f6b656e73426f75676874046b0000000925646561646c696e650000000b2578747a546f546f6b656e0501076504620000000a25746f6b656e506f6f6c0765046a000000082578747a506f6f6c0765046200000009256c7174546f74616c0765046e0000000d25746f6b656e41646472657373046e0000000b256c71744164647265737305020200000f7203210317034c0316072e02000009d1072e020000035a072e020000032603210317034c0316034c03210317034c0316034c03210317034c0316034c034003190328072c020000000c05200004074303620003032702000002ea0743036a000105700004032105710005031703160322072f0200000013074303680100000008444956206279203003270200000000031603130743036a0001034c0322072f02000000130743036801000000084449562062792030032702000000000316034c0321057100020570000603210571000703170317031605700002032105710003033a0322072f020000001307430368010000000844495620627920300327020000000003160570000205700006032105710007031605700003033a0322072f020000001307430368010000000844495620627920300327020000002a03210317034c03160743036200000570000203190325072c02000000000200000008074303620001031205700002034c0321057100020319032a072c020000000c05200005074303620004032702000001b60571000203210571000303190337072c020000000c0520000407430362000503270200000190057000030321057100040317031703170570000203210571000305700005032105710006031703170316031203420570000403210571000503170316034205700004032105710005031603420317034c032105710002057000050321057100060316031203420321031703170313057000060317031603120342034c03160342034c03490354034203480342034c032105710002034c03210317034c0316034c03210317034c031605700003031703170317031606550765036e0765036e036200000009257472616e73666572072f0200000008074303620000032702000000000743036a000005700003057000030342057000030342034d05700002033005700003034205700002032105710003034c03210317034c031605700002031703170317031706550765045b00000009257175616e74697479046e00000007257461726765740000000b256d696e744f724275726e072f020000000807430362000c032702000000000743036a000005700002057000030342034d05700002053d036d05700002031b05700002031b0342020000002803200321031703170313057000020321057100030317031603120342034c03160342053d036d0342020000066b072e020000038d03210317034c0316034c03210317034c0316034c03210317034c0316034c03210317034c0316034c034003190328072c020000000c05200005074303620003032702000003470743036a000003130319032a072c020000000c0520000507430362000a03270200000323057000040321057100050317031703160743036a000105700006032105710007031703160322072f0200000013074303680100000008444956206279203003270200000000031605700004032105710005033a0322072f020000001307430368010000000844495620627920300327020000000003160743036a0001034c033a0570000503210571000603170317031605700006032105710007031605700005032105710006033a0322072f02000000130743036801000000084449562062792030032702000000000316057000030570000203210571000303190337072c020000000c0520000607430362000b0327020000022e05700002034c03210571000203190337072c020000000c0520000507430362000d032702000002060570000203210571000305700005032105710006031703170316034b0356072f020000000807430362000e03270200000000034c032105710002057000060321057100070316034b0356072f020000000807430362000f03270200000000057000040743035b0000034b0348034205700006032105710007034c03210317034c031605700002031703170317031706550765045b00000009257175616e74697479046e00000007257461726765740000000b256d696e744f724275726e072f020000000807430362000c032702000000000743036a000005700002057000030342034d0570000305700005032105710006034203490354034205700006032105710007034c03210317034c0316034c03210317034c031605700003031703170317031606550765036e0765036e036200000009257472616e73666572072f0200000008074303620000032702000000000743036a000005700003057000030342057000030342034d05700004032105710005057000060555036c072f020000000807430362000903270200000000034c0743036c030b034d0570000603210571000703170317057000060570000703210571000803170316034b034205700006031603420321031703170317057000060342034c032105710002031703160342034c031603420317057000040342053d036d05700002031b05700002031b05700002031b034202000002d203210317034c0316034c03210317034c0316034c03210317034c0316034c03210317034c03160570000406550765046e0000000325746f0765046200000010256d696e546f6b656e73426f75676874046b0000000925646561646c696e650000000b2578747a546f546f6b656e072f020000000807430362001f032702000000000743036a000003130319032a072c020000000c0520000607430362000a0327020000022d05700002032105710003034003190328072c020000000c05200006074303620003032702000002050743036200a70f05700002032105710003033a0743036200a80f057000070321057100080316033a031205700006032105710007031703160743036200a70f05700004032105710005033a033a0322072f020000001307430368010000000844495620627920300327020000000003160743036200a80f0743036200a70f05700002032105710003033a0322072f02000000130743036801000000084449562062792030032702000000000316057000070321057100080317057000040321057100050570000903210571000a031603120342032103170317057000030321057100040570000a03170316034b0342034c031603420570000403490354034203480342034c032105710002034c03210317034c0316034c03210317034c031605700003031703170317031606550765036e0765036e036200000009257472616e73666572072f0200000008074303620000032702000000000743036a000005700003057000030342057000030342034d057000040570000303210571000405700006057000080342057000070342034d0570000305700004034b0743036e0100000024747a314b65326837734464616b484a5168385758345a3337326475314b4368736b7379550555036c072f020000000807430362000903270200000000034c0743036c030b034d05700003053d036d05700002031b05700002031b05700002031b0342020000058d072e02000002cc03210317034c0316034c03210317034c0316034c03210317034c0316034c034003190328072c020000000c05200004074303620003032702000002900743036a000003130319032a072c020000000c0520000407430362000a0327020000026c0743036200a70f05700002032105710003033a0743036200a80f057000050321057100060316033a03120743036a000105700005032105710006031703160322072f020000001307430368010000000844495620627920300327020000000003160743036200a70f05700004032105710005033a033a0322072f020000001307430368010000000844495620627920300327020000000003160743036a0001034c033a0743036200a80f0743036200a70f05700002032105710003033a0322072f0200000013074303680100000008444956206279203003270200000000031605700002034c03210571000203190337072c020000000a032007430362000803270200000000057000020321057100030349035403420348034205700005032105710006034c03210317034c0316034c03210317034c031605700003031703170317031606550765036e0765036e036200000009257472616e73666572072f0200000008074303620000032702000000000743036a000005700003057000030342057000030342034d034c032105710002057000050555036c072f020000000807430362000903270200000000034c0743036c030b034d0570000503210571000603170570000505700006032105710007031603120342032103170317057000050321057100060570000703170316034b0342034c031603420570000305700004034b0743036e0100000024747a314b65326837734464616b484a5168385758345a3337326475314b4368736b7379550555036c072f020000000807430362000903270200000000034c0743036c030b034d034c053d036d05700002031b05700002031b05700002031b034202000002b503210317034c0316034c03210317034c0316034c034003190328072c020000000c05200003074303620003032702000002830743036a000105700003032105710004031703160322072f0200000013074303680100000008444956206279203003270200000000031603130743036a0001034c0322072f020000001307430368010000000844495620627920300327020000000003160743036200a80f0743036200a70f05700002032105710003033a0322072f02000000130743036801000000084449562062792030032702000000000316032105700002034b03110743036200a70f05700002032105710003033a0743036200a80f05700004033a03120570000503210571000603160743036200a70f05700004032105710005033a033a0322072f0200000013074303680100000008444956206279203003270200000000031605700003034c03210571000203190337072c020000000a0320074303620012032702000000000321057000050321057100060316034b0356072f02000000080743036200130327020000000005700005032105710006031703170743036a000105700005033a05700006032105710007031703160312034205700005031603420317034c0342034c057000030342034903540342034c032105710002034c03210317034c0316034c03210317034c031605700003031703170317031606550765036e0765036e036200000009257472616e73666572072f0200000008074303620000032702000000000743036a000005700003057000030342057000030342034d0743036a000105700003033a0743036e0100000024747a314b65326837734464616b484a5168385758345a3337326475314b4368736b7379550555036c072f020000000807430362000903270200000000034c0743036c030b034d05700002053d036d05700002031b05700002031b0342 diff --git a/src/proto_011_PtHangzH/lib_protocol/contracts/cpmm.mligo b/src/proto_011_PtHangzH/lib_protocol/contracts/cpmm.mligo new file mode 100644 index 000000000000..37213e25a216 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contracts/cpmm.mligo @@ -0,0 +1,388 @@ +// ============================================================================= +// Entrypoints +// ============================================================================= + +type add_liquidity = + [@layout:comb] + { owner : address ; + minLqtMinted : nat ; + maxTokensDeposited : nat ; + deadline : timestamp ; + } + +type remove_liquidity = + [@layout:comb] + { [@annot:to] to_ : address ; // recipient of the liquidity redemption + lqtBurned : nat ; // amount of lqt owned by sender to burn + minXtzWithdrawn : tez ; // minimum amount of tez to withdraw + minTokensWithdrawn : nat ; // minimum amount of tokens to whitdw + deadline : timestamp ; // the time before which the request must be completed + } + +type xtz_to_token = + [@layout:comb] + { [@annot:to] to_ : address ; + minTokensBought : nat ; + deadline : timestamp ; + } + +type token_to_xtz = + [@layout:comb] + { [@annot:to] to_ : address ; + tokensSold : nat ; + minXtzBought : tez ; + deadline : timestamp ; + } + +type token_to_token = + [@layout:comb] + { outputDexterContract : address ; + minTokensBought : nat ; + [@annot:to] to_ : address ; + tokensSold : nat ; + deadline : timestamp ; + } + +type entrypoint = +| AddLiquidity of add_liquidity +| RemoveLiquidity of remove_liquidity +| XtzToToken of xtz_to_token +| TokenToXtz of token_to_xtz +| Default of unit +| TokenToToken of token_to_token + + +// ============================================================================= +// Storage +// ============================================================================= + +type storage = + [@layout:comb] + { tokenPool : nat ; + xtzPool : tez ; + lqtTotal : nat ; + tokenAddress : address ; + lqtAddress : address ; + } + +// ============================================================================= +// Type Synonyms +// ============================================================================= + +type result = operation list * storage + +// FA1.2 +type token_contract_transfer = address * (address * nat) +type get_balance = address * (nat contract) + +// custom entrypoint for LQT FA1.2 +type mintOrBurn = + [@layout:comb] + { quantity : int ; + target : address } + +// ============================================================================= +// Error codes +// ============================================================================= + +[@inline] let error_TOKEN_CONTRACT_MUST_HAVE_A_TRANSFER_ENTRYPOINT = 0n +(* 1n *) +[@inline] let error_SELF_IS_UPDATING_TOKEN_POOL_MUST_BE_FALSE = 2n +[@inline] let error_THE_CURRENT_TIME_MUST_BE_LESS_THAN_THE_DEADLINE = 3n +[@inline] let error_MAX_TOKENS_DEPOSITED_MUST_BE_GREATER_THAN_OR_EQUAL_TO_TOKENS_DEPOSITED = 4n +[@inline] let error_LQT_MINTED_MUST_BE_GREATER_THAN_MIN_LQT_MINTED = 5n +(* 6n *) +(* 7n *) +[@inline] let error_XTZ_BOUGHT_MUST_BE_GREATER_THAN_OR_EQUAL_TO_MIN_XTZ_BOUGHT = 8n +[@inline] let error_INVALID_TO_ADDRESS = 9n +[@inline] let error_AMOUNT_MUST_BE_ZERO = 10n +[@inline] let error_THE_AMOUNT_OF_XTZ_WITHDRAWN_MUST_BE_GREATER_THAN_OR_EQUAL_TO_MIN_XTZ_WITHDRAWN = 11n +[@inline] let error_LQT_CONTRACT_MUST_HAVE_A_MINT_OR_BURN_ENTRYPOINT = 12n +[@inline] let error_THE_AMOUNT_OF_TOKENS_WITHDRAWN_MUST_BE_GREATER_THAN_OR_EQUAL_TO_MIN_TOKENS_WITHDRAWN = 13n +[@inline] let error_CANNOT_BURN_MORE_THAN_THE_TOTAL_AMOUNT_OF_LQT = 14n +[@inline] let error_TOKEN_POOL_MINUS_TOKENS_WITHDRAWN_IS_NEGATIVE = 15n +(* 16n *) +(* 17n *) +[@inline] let error_TOKENS_BOUGHT_MUST_BE_GREATER_THAN_OR_EQUAL_TO_MIN_TOKENS_BOUGHT = 18n +[@inline] let error_TOKEN_POOL_MINUS_TOKENS_BOUGHT_IS_NEGATIVE = 19n +[@inline] let error_ONLY_MANAGER_CAN_SET_BAKER = 20n +[@inline] let error_ONLY_MANAGER_CAN_SET_MANAGER = 21n +[@inline] let error_BAKER_PERMANENTLY_FROZEN = 22n +[@inline] let error_ONLY_MANAGER_CAN_SET_LQT_ADRESS = 23n +[@inline] let error_LQT_ADDRESS_ALREADY_SET = 24n +[@inline] let error_CALL_NOT_FROM_AN_IMPLICIT_ACCOUNT = 25n +(* 26n *) +(* 27n *) +#if FA2 +[@inline] let error_INVALID_FA2_TOKEN_CONTRACT_MISSING_BALANCE_OF = 28n +#else +[@inline] let error_INVALID_FA12_TOKEN_CONTRACT_MISSING_GETBALANCE = 28n +#endif +[@inline] let error_THIS_ENTRYPOINT_MAY_ONLY_BE_CALLED_BY_GETBALANCE_OF_TOKENADDRESS = 29n +(* 30n *) +[@inline] let error_INVALID_INTERMEDIATE_CONTRACT = 31n +[@inline] let error_INVALID_FA2_BALANCE_RESPONSE = 32n +[@inline] let error_UNEXPECTED_REENTRANCE_IN_UPDATE_TOKEN_POOL = 33n + + +// ============================================================================= +// Functions +// ============================================================================= + +[@inline] +let fee = 999n + +[@inline] let null_address = ("tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU" : address) + +(* this is slightly inefficient to inline, but, nice to have a clean stack for + the entrypoints for the Coq verification *) +[@inline] +let mutez_to_natural (a: tez) : nat = a / 1mutez + +[@inline] +let natural_to_mutez (a: nat): tez = a * 1mutez + +[@inline] +let is_a_nat (i : int) : nat option = Michelson.is_nat i + +let ceildiv (numerator : nat) (denominator : nat) : nat = + match (ediv numerator denominator) with + | None -> (failwith("DIV by 0") : nat) + | Some v -> let (q, r) = v in if r = 0n then q else q + 1n + +[@inline] +let mint_or_burn (storage : storage) (target : address) (quantity : int) : operation = + let lqt_admin : mintOrBurn contract = + match (Tezos.get_entrypoint_opt "%mintOrBurn" storage.lqtAddress : mintOrBurn contract option) with + | None -> (failwith error_LQT_CONTRACT_MUST_HAVE_A_MINT_OR_BURN_ENTRYPOINT : mintOrBurn contract) + | Some contract -> contract in + Tezos.transaction {quantity = quantity ; target = target} 0mutez lqt_admin + +[@inline] +let token_transfer (storage : storage) (from : address) (to_ : address) (token_amount : nat) : operation = + let token_contract: token_contract_transfer contract = + match (Tezos.get_entrypoint_opt "%transfer" storage.tokenAddress : token_contract_transfer contract option) with + | None -> (failwith error_TOKEN_CONTRACT_MUST_HAVE_A_TRANSFER_ENTRYPOINT : token_contract_transfer contract) + | Some contract -> contract in + Tezos.transaction (from, (to_, token_amount)) 0mutez token_contract + +[@inline] +let xtz_transfer (to_ : address) (amount_ : tez) : operation = + let to_contract : unit contract = + match (Tezos.get_contract_opt to_ : unit contract option) with + | None -> (failwith error_INVALID_TO_ADDRESS : unit contract) + | Some c -> c in + Tezos.transaction () amount_ to_contract + +// ============================================================================= +// Entrypoint Functions +// ============================================================================= + +// We assume the contract is originated with at least one liquidity +// provider set up already, so lqtTotal, xtzPool and tokenPool will +// always be positive after the initial setup, unless all liquidity is +// removed, at which point the contract is considered dead and stops working +// properly. (To prevent this, at least one address should keep at least a +// small amount of liquidity in the contract forever.) + +let add_liquidity (param : add_liquidity) (storage: storage) : result = + let { owner = owner ; + minLqtMinted = minLqtMinted ; + maxTokensDeposited = maxTokensDeposited ; + deadline = deadline } = param in + + if Tezos.now >= deadline then + (failwith error_THE_CURRENT_TIME_MUST_BE_LESS_THAN_THE_DEADLINE : result) + else + // the contract is initialized, use the existing exchange rate + // mints nothing if the contract has been emptied, but that's OK + let xtzPool : nat = mutez_to_natural storage.xtzPool in + let nat_amount : nat = mutez_to_natural Tezos.amount in + let lqt_minted : nat = nat_amount * storage.lqtTotal / xtzPool in + let tokens_deposited : nat = ceildiv (nat_amount * storage.tokenPool) xtzPool in + + if tokens_deposited > maxTokensDeposited then + (failwith error_MAX_TOKENS_DEPOSITED_MUST_BE_GREATER_THAN_OR_EQUAL_TO_TOKENS_DEPOSITED : result) + else if lqt_minted < minLqtMinted then + (failwith error_LQT_MINTED_MUST_BE_GREATER_THAN_MIN_LQT_MINTED : result) + else + let storage = {storage with + lqtTotal = storage.lqtTotal + lqt_minted ; + tokenPool = storage.tokenPool + tokens_deposited ; + xtzPool = storage.xtzPool + Tezos.amount} in + + // send tokens from sender to exchange + let op_token = token_transfer storage Tezos.sender Tezos.self_address tokens_deposited in + // mint lqt tokens for them + let op_lqt = mint_or_burn storage owner (int lqt_minted) in + ([op_token; op_lqt], storage) + +let remove_liquidity (param : remove_liquidity) (storage : storage) : result = + let { to_ = to_ ; + lqtBurned = lqtBurned ; + minXtzWithdrawn = minXtzWithdrawn ; + minTokensWithdrawn = minTokensWithdrawn ; + deadline = deadline } = param in + + if Tezos.now >= deadline then + (failwith error_THE_CURRENT_TIME_MUST_BE_LESS_THAN_THE_DEADLINE : result) + else if Tezos.amount > 0mutez then + (failwith error_AMOUNT_MUST_BE_ZERO : result) + else begin + let xtz_withdrawn : tez = natural_to_mutez ((lqtBurned * (mutez_to_natural storage.xtzPool)) / storage.lqtTotal) in + let tokens_withdrawn : nat = lqtBurned * storage.tokenPool / storage.lqtTotal in + + // Check that minimum withdrawal conditions are met + if xtz_withdrawn < minXtzWithdrawn then + (failwith error_THE_AMOUNT_OF_XTZ_WITHDRAWN_MUST_BE_GREATER_THAN_OR_EQUAL_TO_MIN_XTZ_WITHDRAWN : result) + else if tokens_withdrawn < minTokensWithdrawn then + (failwith error_THE_AMOUNT_OF_TOKENS_WITHDRAWN_MUST_BE_GREATER_THAN_OR_EQUAL_TO_MIN_TOKENS_WITHDRAWN : result) + // Proceed to form the operations and update the storage + else begin + // calculate lqtTotal, convert int to nat + let new_lqtTotal = match (is_a_nat ( storage.lqtTotal - lqtBurned)) with + // This check should be unecessary, the fa12 logic normally takes care of it + | None -> (failwith error_CANNOT_BURN_MORE_THAN_THE_TOTAL_AMOUNT_OF_LQT : nat) + | Some n -> n in + // Calculate tokenPool, convert int to nat + let new_tokenPool = match is_a_nat (storage.tokenPool - tokens_withdrawn) with + | None -> (failwith error_TOKEN_POOL_MINUS_TOKENS_WITHDRAWN_IS_NEGATIVE : nat) + | Some n -> n in + + let op_lqt = mint_or_burn storage Tezos.sender (0 - lqtBurned) in + let op_token = token_transfer storage Tezos.self_address to_ tokens_withdrawn in + let op_xtz = xtz_transfer to_ xtz_withdrawn in + let storage = {storage with xtzPool = storage.xtzPool - xtz_withdrawn ; lqtTotal = new_lqtTotal ; tokenPool = new_tokenPool} in + ([op_lqt; op_token; op_xtz], storage) + end + end + + +let xtz_to_token (param : xtz_to_token) (storage : storage) = + let { to_ = to_ ; + minTokensBought = minTokensBought ; + deadline = deadline } = param in + + if Tezos.now >= deadline then + (failwith error_THE_CURRENT_TIME_MUST_BE_LESS_THAN_THE_DEADLINE : result) + else begin + // we don't check that xtzPool > 0, because that is impossible + // unless all liquidity has been removed + let xtzPool = mutez_to_natural storage.xtzPool in + let nat_amount = mutez_to_natural Tezos.amount in + + let amount_net_burn = (nat_amount * 999n) / 1000n in + let burn_amount = abs (nat_amount - amount_net_burn) in + + let tokens_bought = + (let bought = (amount_net_burn * fee * storage.tokenPool) / (xtzPool * 1000n + (amount_net_burn * fee)) in + if bought < minTokensBought then + (failwith error_TOKENS_BOUGHT_MUST_BE_GREATER_THAN_OR_EQUAL_TO_MIN_TOKENS_BOUGHT : nat) + else + bought) + in + let new_tokenPool = (match is_nat (storage.tokenPool - tokens_bought) with + | None -> (failwith error_TOKEN_POOL_MINUS_TOKENS_BOUGHT_IS_NEGATIVE : nat) + | Some difference -> difference) in + + // update xtzPool + let storage = {storage with + xtzPool = storage.xtzPool + (natural_to_mutez amount_net_burn); + tokenPool = new_tokenPool } in + // send tokens_withdrawn to to address + // if tokens_bought is greater than storage.tokenPool, this will fail + let op = token_transfer storage Tezos.self_address to_ tokens_bought in + let op_burn = xtz_transfer null_address (natural_to_mutez burn_amount) in + ([ op ; op_burn], storage) + end + + +let token_to_xtz (param : token_to_xtz) (storage : storage) = + let { to_ = to_ ; + tokensSold = tokensSold ; + minXtzBought = minXtzBought ; + deadline = deadline } = param in + + if Tezos.now >= deadline then + (failwith error_THE_CURRENT_TIME_MUST_BE_LESS_THAN_THE_DEADLINE : result) + else if Tezos.amount > 0mutez then + (failwith error_AMOUNT_MUST_BE_ZERO : result) + else + // we don't check that tokenPool > 0, because that is impossible + // unless all liquidity has been removed + let xtz_bought = natural_to_mutez (((tokensSold * fee * (mutez_to_natural storage.xtzPool)) / (storage.tokenPool * 1000n + (tokensSold * fee)))) in + + let xtz_bought_net_burn = + let bought = (xtz_bought * 999n) / 1000n in + if bought < minXtzBought then (failwith error_XTZ_BOUGHT_MUST_BE_GREATER_THAN_OR_EQUAL_TO_MIN_XTZ_BOUGHT : tez) else bought in + + let op_token = token_transfer storage Tezos.sender Tezos.self_address tokensSold in + let op_tez = xtz_transfer to_ xtz_bought_net_burn in + let storage = {storage with tokenPool = storage.tokenPool + tokensSold ; + xtzPool = storage.xtzPool - xtz_bought } in + + let burn_amount = xtz_bought - xtz_bought_net_burn in + let op_burn = xtz_transfer null_address burn_amount in + ([op_token ; op_tez; op_burn], storage) + +// entrypoint to allow depositing funds +let default_ (storage : storage) : result = + // update xtzPool + let storage = {storage with xtzPool = storage.xtzPool + Tezos.amount } in + (([] : operation list), storage) + +let token_to_token (param : token_to_token) (storage : storage) : result = + let { outputDexterContract = outputDexterContract ; + minTokensBought = minTokensBought ; + to_ = to_ ; + tokensSold = tokensSold ; + deadline = deadline } = param in + + let outputDexterContract_contract: xtz_to_token contract = + (match (Tezos.get_entrypoint_opt "%xtzToToken" outputDexterContract : xtz_to_token contract option) with + | None -> (failwith error_INVALID_INTERMEDIATE_CONTRACT : xtz_to_token contract) + | Some c -> c) in + + if Tezos.amount > 0mutez then + (failwith error_AMOUNT_MUST_BE_ZERO : result) + else if Tezos.now >= deadline then + (failwith error_THE_CURRENT_TIME_MUST_BE_LESS_THAN_THE_DEADLINE : result) + else + // we don't check that tokenPool > 0, because that is impossible unless all liquidity has been removed + let xtz_bought = (tokensSold * fee * storage.xtzPool) / (storage.tokenPool * 1000n + (tokensSold * fee)) in + + let xtz_bought_net_burn = (xtz_bought * 999n) / 1000n in + + let storage = {storage with + tokenPool = storage.tokenPool + tokensSold ; + xtzPool = storage.xtzPool - xtz_bought } in + + let op1 = token_transfer storage Tezos.sender Tezos.self_address tokensSold in + let op2 = + Tezos.transaction + {to_ = to_; minTokensBought = minTokensBought; deadline = deadline} + xtz_bought_net_burn + outputDexterContract_contract in + + let burn_amount = xtz_bought - xtz_bought_net_burn in + let op_burn = xtz_transfer null_address burn_amount in + ([op1 ; op2; op_burn], storage) + +// ============================================================================= +// Main +// ============================================================================= + +let main ((entrypoint, storage) : entrypoint * storage) : result = + match entrypoint with + | AddLiquidity param -> + add_liquidity param storage + | RemoveLiquidity param -> + remove_liquidity param storage + | Default -> + default_ storage + | XtzToToken param -> + xtz_to_token param storage + | TokenToXtz param -> + token_to_xtz param storage + | TokenToToken param -> + token_to_token param storage \ No newline at end of file diff --git a/src/proto_011_PtHangzH/lib_protocol/contracts/cpmm.tz b/src/proto_011_PtHangzH/lib_protocol/contracts/cpmm.tz new file mode 100644 index 000000000000..15a0819c52e8 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contracts/cpmm.tz @@ -0,0 +1,929 @@ +{ parameter + (or (or (or (pair %addLiquidity + (address %owner) + (pair (nat %minLqtMinted) (pair (nat %maxTokensDeposited) (timestamp %deadline)))) + (unit %default)) + (or (pair %removeLiquidity + (address %to) + (pair (nat %lqtBurned) + (pair (mutez %minXtzWithdrawn) (pair (nat %minTokensWithdrawn) (timestamp %deadline))))) + (pair %tokenToToken + (address %outputDexterContract) + (pair (nat %minTokensBought) + (pair (address %to) (pair (nat %tokensSold) (timestamp %deadline))))))) + (or (pair %tokenToXtz + (address %to) + (pair (nat %tokensSold) (pair (mutez %minXtzBought) (timestamp %deadline)))) + (pair %xtzToToken (address %to) (pair (nat %minTokensBought) (timestamp %deadline))))) ; + storage + (pair (nat %tokenPool) + (pair (mutez %xtzPool) + (pair (nat %lqtTotal) (pair (address %tokenAddress) (address %lqtAddress))))) ; + code { DUP ; + CDR ; + SWAP ; + CAR ; + IF_LEFT + { IF_LEFT + { IF_LEFT + { DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + NOW ; + COMPARE ; + GE ; + IF { DROP 4 ; PUSH nat 3 ; FAILWITH } + { PUSH mutez 1 ; + DIG 4 ; + DUP ; + DUG 5 ; + CDR ; + CAR ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + AMOUNT ; + PUSH mutez 1 ; + SWAP ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + SWAP ; + DUP ; + DUG 2 ; + DIG 6 ; + DUP ; + DUG 7 ; + CDR ; + CDR ; + CAR ; + DIG 2 ; + DUP ; + DUG 3 ; + MUL ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + DIG 2 ; + DIG 6 ; + DUP ; + DUG 7 ; + CAR ; + DIG 3 ; + MUL ; + EDIV ; + IF_NONE + { PUSH string "DIV by 0" ; FAILWITH } + { DUP ; + CDR ; + SWAP ; + CAR ; + PUSH nat 0 ; + DIG 2 ; + COMPARE ; + EQ ; + IF {} { PUSH nat 1 ; ADD } } ; + DIG 2 ; + SWAP ; + DUP ; + DUG 2 ; + COMPARE ; + GT ; + IF { DROP 5 ; PUSH nat 4 ; FAILWITH } + { DUG 2 ; + DUP ; + DUG 3 ; + COMPARE ; + LT ; + IF { DROP 4 ; PUSH nat 5 ; FAILWITH } + { DIG 3 ; + DUP ; + DUG 4 ; + CDR ; + CDR ; + CDR ; + DIG 2 ; + DUP ; + DUG 3 ; + DIG 5 ; + DUP ; + DUG 6 ; + CDR ; + CDR ; + CAR ; + ADD ; + PAIR ; + DIG 4 ; + DUP ; + DUG 5 ; + CDR ; + CAR ; + PAIR ; + DIG 4 ; + DUP ; + DUG 5 ; + CAR ; + PAIR ; + CDR ; + SWAP ; + DUP ; + DUG 2 ; + DIG 5 ; + DUP ; + DUG 6 ; + CAR ; + ADD ; + PAIR ; + DUP ; + CDR ; + CDR ; + AMOUNT ; + DIG 6 ; + CDR ; + CAR ; + ADD ; + PAIR ; + SWAP ; + CAR ; + PAIR ; + SWAP ; + SELF ; + ADDRESS ; + PAIR ; + SENDER ; + PAIR ; + SWAP ; + DUP ; + DUG 2 ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + DIG 3 ; + CDR ; + CDR ; + CDR ; + CAR ; + CONTRACT %transfer (pair address (pair address nat)) ; + IF_NONE { PUSH nat 0 ; FAILWITH } {} ; + PUSH mutez 0 ; + DIG 3 ; + DIG 3 ; + PAIR ; + DIG 3 ; + PAIR ; + TRANSFER_TOKENS ; + DIG 2 ; + INT ; + DIG 3 ; + PAIR ; + DIG 2 ; + DUP ; + DUG 3 ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + DIG 2 ; + CDR ; + CDR ; + CDR ; + CDR ; + CONTRACT %mintOrBurn (pair (int %quantity) (address %target)) ; + IF_NONE { PUSH nat 12 ; FAILWITH } {} ; + PUSH mutez 0 ; + DIG 2 ; + DIG 3 ; + PAIR ; + TRANSFER_TOKENS ; + DIG 2 ; + NIL operation ; + DIG 2 ; + CONS ; + DIG 2 ; + CONS ; + PAIR } } } } + { DROP ; + DUP ; + CDR ; + CDR ; + AMOUNT ; + DIG 2 ; + DUP ; + DUG 3 ; + CDR ; + CAR ; + ADD ; + PAIR ; + SWAP ; + CAR ; + PAIR ; + NIL operation ; + PAIR } } + { IF_LEFT + { DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + NOW ; + COMPARE ; + GE ; + IF { DROP 5 ; PUSH nat 3 ; FAILWITH } + { PUSH mutez 0 ; + AMOUNT ; + COMPARE ; + GT ; + IF { DROP 5 ; PUSH nat 10 ; FAILWITH } + { DIG 4 ; + DUP ; + DUG 5 ; + CDR ; + CDR ; + CAR ; + PUSH mutez 1 ; + DIG 6 ; + DUP ; + DUG 7 ; + CDR ; + CAR ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + DIG 4 ; + DUP ; + DUG 5 ; + MUL ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + PUSH mutez 1 ; + SWAP ; + MUL ; + DIG 5 ; + DUP ; + DUG 6 ; + CDR ; + CDR ; + CAR ; + DIG 6 ; + DUP ; + DUG 7 ; + CAR ; + DIG 5 ; + DUP ; + DUG 6 ; + MUL ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + DIG 3 ; + DIG 2 ; + DUP ; + DUG 3 ; + COMPARE ; + LT ; + IF { DROP 6 ; PUSH nat 11 ; FAILWITH } + { DIG 2 ; + SWAP ; + DUP ; + DUG 2 ; + COMPARE ; + LT ; + IF { DROP 5 ; PUSH nat 13 ; FAILWITH } + { DIG 2 ; + DUP ; + DUG 3 ; + DIG 5 ; + DUP ; + DUG 6 ; + CDR ; + CDR ; + CAR ; + SUB ; + ISNAT ; + IF_NONE { PUSH nat 14 ; FAILWITH } {} ; + SWAP ; + DUP ; + DUG 2 ; + DIG 6 ; + DUP ; + DUG 7 ; + CAR ; + SUB ; + ISNAT ; + IF_NONE { PUSH nat 15 ; FAILWITH } {} ; + DIG 4 ; + PUSH int 0 ; + SUB ; + SENDER ; + PAIR ; + DIG 6 ; + DUP ; + DUG 7 ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + DIG 2 ; + CDR ; + CDR ; + CDR ; + CDR ; + CONTRACT %mintOrBurn (pair (int %quantity) (address %target)) ; + IF_NONE { PUSH nat 12 ; FAILWITH } {} ; + PUSH mutez 0 ; + DIG 2 ; + DIG 3 ; + PAIR ; + TRANSFER_TOKENS ; + DIG 3 ; + DIG 5 ; + DUP ; + DUG 6 ; + PAIR ; + SELF ; + ADDRESS ; + PAIR ; + DIG 6 ; + DUP ; + DUG 7 ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + DIG 3 ; + CDR ; + CDR ; + CDR ; + CAR ; + CONTRACT %transfer (pair address (pair address nat)) ; + IF_NONE { PUSH nat 0 ; FAILWITH } {} ; + PUSH mutez 0 ; + DIG 3 ; + DIG 3 ; + PAIR ; + DIG 3 ; + PAIR ; + TRANSFER_TOKENS ; + DIG 4 ; + DUP ; + DUG 5 ; + DIG 6 ; + CONTRACT unit ; + IF_NONE { PUSH nat 9 ; FAILWITH } {} ; + SWAP ; + PUSH unit Unit ; + TRANSFER_TOKENS ; + DIG 6 ; + DUP ; + DUG 7 ; + CDR ; + CDR ; + DIG 6 ; + DIG 7 ; + DUP ; + DUG 8 ; + CDR ; + CAR ; + SUB ; + PAIR ; + DIG 6 ; + CAR ; + PAIR ; + DUP ; + CDR ; + CDR ; + CDR ; + DIG 6 ; + PAIR ; + SWAP ; + DUP ; + DUG 2 ; + CDR ; + CAR ; + PAIR ; + SWAP ; + CAR ; + PAIR ; + CDR ; + DIG 4 ; + PAIR ; + NIL operation ; + DIG 2 ; + CONS ; + DIG 2 ; + CONS ; + DIG 2 ; + CONS ; + PAIR } } } } } + { DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + DIG 4 ; + CONTRACT %xtzToToken + (pair (address %to) (pair (nat %minTokensBought) (timestamp %deadline))) ; + IF_NONE { PUSH nat 31 ; FAILWITH } {} ; + PUSH mutez 0 ; + AMOUNT ; + COMPARE ; + GT ; + IF { DROP 6 ; PUSH nat 10 ; FAILWITH } + { DIG 2 ; + DUP ; + DUG 3 ; + NOW ; + COMPARE ; + GE ; + IF { DROP 6 ; PUSH nat 3 ; FAILWITH } + { PUSH nat 999 ; + DIG 2 ; + DUP ; + DUG 3 ; + MUL ; + PUSH nat 1000 ; + DIG 7 ; + DUP ; + DUG 8 ; + CAR ; + MUL ; + ADD ; + DIG 6 ; + DUP ; + DUG 7 ; + CDR ; + CAR ; + PUSH nat 999 ; + DIG 4 ; + DUP ; + DUG 5 ; + MUL ; + MUL ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + PUSH nat 1000 ; + PUSH nat 999 ; + DIG 2 ; + DUP ; + DUG 3 ; + MUL ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + DIG 7 ; + DUP ; + DUG 8 ; + CDR ; + DIG 4 ; + DUP ; + DUG 5 ; + DIG 9 ; + DUP ; + DUG 10 ; + CAR ; + ADD ; + PAIR ; + DUP ; + CDR ; + CDR ; + DIG 3 ; + DUP ; + DUG 4 ; + DIG 10 ; + CDR ; + CAR ; + SUB ; + PAIR ; + SWAP ; + CAR ; + PAIR ; + DIG 4 ; + SELF ; + ADDRESS ; + PAIR ; + SENDER ; + PAIR ; + SWAP ; + DUP ; + DUG 2 ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + DIG 3 ; + CDR ; + CDR ; + CDR ; + CAR ; + CONTRACT %transfer (pair address (pair address nat)) ; + IF_NONE { PUSH nat 0 ; FAILWITH } {} ; + PUSH mutez 0 ; + DIG 3 ; + DIG 3 ; + PAIR ; + DIG 3 ; + PAIR ; + TRANSFER_TOKENS ; + DIG 4 ; + DIG 3 ; + DUP ; + DUG 4 ; + DIG 6 ; + DIG 8 ; + PAIR ; + DIG 7 ; + PAIR ; + TRANSFER_TOKENS ; + DIG 3 ; + DIG 4 ; + SUB ; + PUSH address "tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU" ; + CONTRACT unit ; + IF_NONE { PUSH nat 9 ; FAILWITH } {} ; + SWAP ; + PUSH unit Unit ; + TRANSFER_TOKENS ; + DIG 3 ; + NIL operation ; + DIG 2 ; + CONS ; + DIG 2 ; + CONS ; + DIG 2 ; + CONS ; + PAIR } } } } } + { IF_LEFT + { DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + NOW ; + COMPARE ; + GE ; + IF { DROP 4 ; PUSH nat 3 ; FAILWITH } + { PUSH mutez 0 ; + AMOUNT ; + COMPARE ; + GT ; + IF { DROP 4 ; PUSH nat 10 ; FAILWITH } + { PUSH nat 999 ; + DIG 2 ; + DUP ; + DUG 3 ; + MUL ; + PUSH nat 1000 ; + DIG 5 ; + DUP ; + DUG 6 ; + CAR ; + MUL ; + ADD ; + PUSH mutez 1 ; + DIG 5 ; + DUP ; + DUG 6 ; + CDR ; + CAR ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + PUSH nat 999 ; + DIG 4 ; + DUP ; + DUG 5 ; + MUL ; + MUL ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + PUSH mutez 1 ; + SWAP ; + MUL ; + PUSH nat 1000 ; + PUSH nat 999 ; + DIG 2 ; + DUP ; + DUG 3 ; + MUL ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + DIG 2 ; + SWAP ; + DUP ; + DUG 2 ; + COMPARE ; + LT ; + IF { DROP ; PUSH nat 8 ; FAILWITH } {} ; + DIG 2 ; + DUP ; + DUG 3 ; + SELF ; + ADDRESS ; + PAIR ; + SENDER ; + PAIR ; + DIG 5 ; + DUP ; + DUG 6 ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + DIG 3 ; + CDR ; + CDR ; + CDR ; + CAR ; + CONTRACT %transfer (pair address (pair address nat)) ; + IF_NONE { PUSH nat 0 ; FAILWITH } {} ; + PUSH mutez 0 ; + DIG 3 ; + DIG 3 ; + PAIR ; + DIG 3 ; + PAIR ; + TRANSFER_TOKENS ; + SWAP ; + DUP ; + DUG 2 ; + DIG 5 ; + CONTRACT unit ; + IF_NONE { PUSH nat 9 ; FAILWITH } {} ; + SWAP ; + PUSH unit Unit ; + TRANSFER_TOKENS ; + DIG 5 ; + DUP ; + DUG 6 ; + CDR ; + DIG 5 ; + DIG 6 ; + DUP ; + DUG 7 ; + CAR ; + ADD ; + PAIR ; + DUP ; + CDR ; + CDR ; + DIG 5 ; + DUP ; + DUG 6 ; + DIG 7 ; + CDR ; + CAR ; + SUB ; + PAIR ; + SWAP ; + CAR ; + PAIR ; + DIG 3 ; + DIG 4 ; + SUB ; + PUSH address "tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU" ; + CONTRACT unit ; + IF_NONE { PUSH nat 9 ; FAILWITH } {} ; + SWAP ; + PUSH unit Unit ; + TRANSFER_TOKENS ; + SWAP ; + NIL operation ; + DIG 2 ; + CONS ; + DIG 2 ; + CONS ; + DIG 2 ; + CONS ; + PAIR } } } + { DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + NOW ; + COMPARE ; + GE ; + IF { DROP 3 ; PUSH nat 3 ; FAILWITH } + { PUSH mutez 1 ; + DIG 3 ; + DUP ; + DUG 4 ; + CDR ; + CAR ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + AMOUNT ; + PUSH mutez 1 ; + SWAP ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + PUSH nat 1000 ; + PUSH nat 999 ; + DIG 2 ; + DUP ; + DUG 3 ; + MUL ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + DUP ; + DIG 2 ; + SUB ; + ABS ; + PUSH nat 999 ; + DIG 2 ; + DUP ; + DUG 3 ; + MUL ; + PUSH nat 1000 ; + DIG 4 ; + MUL ; + ADD ; + DIG 5 ; + DUP ; + DUG 6 ; + CAR ; + PUSH nat 999 ; + DIG 4 ; + DUP ; + DUG 5 ; + MUL ; + MUL ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR ; + DIG 3 ; + SWAP ; + DUP ; + DUG 2 ; + COMPARE ; + LT ; + IF { DROP ; PUSH nat 18 ; FAILWITH } {} ; + DUP ; + DIG 5 ; + DUP ; + DUG 6 ; + CAR ; + SUB ; + ISNAT ; + IF_NONE { PUSH nat 19 ; FAILWITH } {} ; + DIG 5 ; + DUP ; + DUG 6 ; + CDR ; + CDR ; + PUSH mutez 1 ; + DIG 5 ; + MUL ; + DIG 6 ; + DUP ; + DUG 7 ; + CDR ; + CAR ; + ADD ; + PAIR ; + DIG 5 ; + CAR ; + PAIR ; + CDR ; + SWAP ; + PAIR ; + SWAP ; + DIG 3 ; + PAIR ; + SELF ; + ADDRESS ; + PAIR ; + SWAP ; + DUP ; + DUG 2 ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + SWAP ; + DUP ; + CDR ; + SWAP ; + CAR ; + DIG 3 ; + CDR ; + CDR ; + CDR ; + CAR ; + CONTRACT %transfer (pair address (pair address nat)) ; + IF_NONE { PUSH nat 0 ; FAILWITH } {} ; + PUSH mutez 0 ; + DIG 3 ; + DIG 3 ; + PAIR ; + DIG 3 ; + PAIR ; + TRANSFER_TOKENS ; + PUSH mutez 1 ; + DIG 3 ; + MUL ; + PUSH address "tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU" ; + CONTRACT unit ; + IF_NONE { PUSH nat 9 ; FAILWITH } {} ; + SWAP ; + PUSH unit Unit ; + TRANSFER_TOKENS ; + DIG 2 ; + NIL operation ; + DIG 2 ; + CONS ; + DIG 2 ; + CONS ; + PAIR } } } } } + diff --git a/src/proto_011_PtHangzH/lib_protocol/contracts/lqt.bin b/src/proto_011_PtHangzH/lib_protocol/contracts/lqt.bin new file mode 100644 index 000000000000..4fa01f58526f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contracts/lqt.bin @@ -0,0 +1 @@ +0x020000070005000764076407640865046e00000008257370656e6465720462000000062576616c75650000000825617070726f766508650865046e00000006256f776e6572046e00000008257370656e646572000000082572657175657374065a0362000000092563616c6c6261636b0000000d25676574416c6c6f77616e636507640865046e00000006256f776e6572065a0362000000092563616c6c6261636b0000000b2567657442616c616e63650865046c000000082572657175657374065a0362000000092563616c6c6261636b0000000f25676574546f74616c537570706c7907640865045b00000009257175616e74697479046e00000007257461726765740000000b256d696e744f724275726e0865046e000000052566726f6d0765046e0000000325746f0462000000062576616c756500000009257472616e73666572050107650861036e03620000000725746f6b656e73076508610765046e00000006256f776e6572046e00000008257370656e64657203620000000b25616c6c6f77616e6365730765046e000000062561646d696e04620000000d25746f74616c5f737570706c7905020200000552032103170743036a000003130319033c072c020000001607430368010000000b446f6e7453656e6454657a03270200000000034c0316072e02000001b2072e0200000132072e02000000e2034c03210571000203170316034c0321057100020316034803420743036200000570000303210571000403170319032a07430362000005700003032105710004057000030321057100040329072f020000000607430362000002000000000319032a0314072c0200000020074303680100000015556e73616665416c6c6f77616e63654368616e676503270200000000057000030321057100040317031705700002057000030317074303620000034c03210571000203190325072c02000000060320053e0362020000000203460570000303500342034c03160342053d036d03420200000044034c032105700002053d036d034c03210571000203170743036a000005700004031703160570000403160329072f02000000060743036200000200000000034d031b03420200000074072e0200000042034c032105700002053d036d034c03210571000203170743036a00000570000403160570000403160329072f02000000060743036200000200000000034d031b03420200000026034c032105700002053d036d034c03170743036a000005700003031703170317034d031b0342020000035e072e020000013c034c03210571000203170317031603480319033c072c02000000140743036801000000094f6e6c7941646d696e03270200000000032103160570000203210571000303160570000203210571000303170329072f0200000006074303620000020000000003120356072f020000003607430368010000002b43616e6e6f74206275726e206d6f7265207468616e207468652074617267657427732062616c616e63652e03270200000000034c032105710002031605700003032105710004031703170317031203110570000303210571000403170570000403160743036200000570000403210571000503190325072c020000000a057000030320053e03620200000006057000030346057000040317035003420321057100020317031703160342034c032105710002031703160342034c03160342053d036d03420200000216034c03210571000203170316057000020321057100030316057000020321057100030316034803190325072c0200000002034c02000000a903480570000303210571000403160342057000030321057100040317031705700003032105710004057000020321057100030329072f02000000060743036200000200000000034b0356072f020000001d0743036801000000124e6f74456e6f756768416c6c6f77616e636503270200000000057000030743036200000570000203210571000303190325072c0200000008034c0320053e03620200000004034c03460570000203500570000203210571000303170317057000020321057100030570000403210571000503160329072f02000000060743036200000200000000034b0356072f020000001b0743036801000000104e6f74456e6f75676842616c616e636503270200000000057000020743036200000570000203210571000303190325072c0200000008034c0320053e03620200000004034c034605700003032105710004031603500570000203210571000303170317034c03210571000205700004032105710005031703160329072f020000000607430362000002000000000312034c0743036200000570000203210571000303190325072c0200000008034c0320053e03620200000004034c034605700003031703160350057000020317034c0342032103170317057000020342034c03160342053d036d0342 diff --git a/src/proto_011_PtHangzH/lib_protocol/contracts/lqt.mligo b/src/proto_011_PtHangzH/lib_protocol/contracts/lqt.mligo new file mode 100644 index 000000000000..7c2fa5012d1e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contracts/lqt.mligo @@ -0,0 +1,164 @@ +type transfer = + [@layout:comb] + { [@annot:from] address_from : address; + [@annot:to] address_to : address; + value : nat } + +type approve = + [@layout:comb] + { spender : address; + value : nat } + +type mintOrBurn = + [@layout:comb] + { quantity : int ; + target : address } + +type allowance_key = + [@layout:comb] + { owner : address; + spender : address } + +type getAllowance = + [@layout:comb] + { request : allowance_key; + callback : nat contract } + +type getBalance = + [@layout:comb] + { owner : address; + callback : nat contract } + +type getTotalSupply = + [@layout:comb] + { request : unit ; + callback : nat contract } + +type tokens = (address, nat) big_map +type allowances = (allowance_key, nat) big_map + +type storage = + [@layout:comb] + { tokens : tokens; + allowances : allowances; + admin : address; + total_supply : nat; + } + +type parameter = + | Transfer of transfer + | Approve of approve + | MintOrBurn of mintOrBurn + | GetAllowance of getAllowance + | GetBalance of getBalance + | GetTotalSupply of getTotalSupply + +type result = operation list * storage + +[@inline] +let maybe (n : nat) : nat option = + if n = 0n + then (None : nat option) + else Some n + +let transfer (param : transfer) (storage : storage) : result = + let allowances = storage.allowances in + let tokens = storage.tokens in + let allowances = + if Tezos.sender = param.address_from + then allowances + else + let allowance_key = { owner = param.address_from ; spender = Tezos.sender } in + let authorized_value = + match Big_map.find_opt allowance_key allowances with + | Some value -> value + | None -> 0n in + let authorized_value = + match is_nat (authorized_value - param.value) with + | None -> (failwith "NotEnoughAllowance" : nat) + | Some authorized_value -> authorized_value in + Big_map.update allowance_key (maybe authorized_value) allowances in + let tokens = + let from_balance = + match Big_map.find_opt param.address_from tokens with + | Some value -> value + | None -> 0n in + let from_balance = + match is_nat (from_balance - param.value) with + | None -> (failwith "NotEnoughBalance" : nat) + | Some from_balance -> from_balance in + Big_map.update param.address_from (maybe from_balance) tokens in + let tokens = + let to_balance = + match Big_map.find_opt param.address_to tokens with + | Some value -> value + | None -> 0n in + let to_balance = to_balance + param.value in + Big_map.update param.address_to (maybe to_balance) tokens in + (([] : operation list), { storage with tokens = tokens; allowances = allowances }) + +let approve (param : approve) (storage : storage) : result = + let allowances = storage.allowances in + let allowance_key = { owner = Tezos.sender ; spender = param.spender } in + let previous_value = + match Big_map.find_opt allowance_key allowances with + | Some value -> value + | None -> 0n in + begin + if previous_value > 0n && param.value > 0n + then (failwith "UnsafeAllowanceChange") + else (); + let allowances = Big_map.update allowance_key (maybe param.value) allowances in + (([] : operation list), { storage with allowances = allowances }) + end + +let mintOrBurn (param : mintOrBurn) (storage : storage) : result = + begin + if Tezos.sender <> storage.admin + then failwith "OnlyAdmin" + else (); + let tokens = storage.tokens in + let old_balance = + match Big_map.find_opt param.target tokens with + | None -> 0n + | Some bal -> bal in + let new_balance = + match is_nat (old_balance + param.quantity) with + | None -> (failwith "Cannot burn more than the target's balance." : nat) + | Some bal -> bal in + let tokens = Big_map.update param.target (maybe new_balance) storage.tokens in + let total_supply = abs (storage.total_supply + param.quantity) in + (([] : operation list), { storage with tokens = tokens ; total_supply = total_supply }) + end + +let getAllowance (param : getAllowance) (storage : storage) : operation list = + let value = + match Big_map.find_opt param.request storage.allowances with + | Some value -> value + | None -> 0n in + [Tezos.transaction value 0mutez param.callback] + +let getBalance (param : getBalance) (storage : storage) : operation list = + let value = + match Big_map.find_opt param.owner storage.tokens with + | Some value -> value + | None -> 0n in + [Tezos.transaction value 0mutez param.callback] + +let getTotalSupply (param : getTotalSupply) (storage : storage) : operation list = + let total = storage.total_supply in + [Tezos.transaction total 0mutez param.callback] + +let main (param, storage : parameter * storage) : result = + begin + if Tezos.amount <> 0mutez + then failwith "DontSendTez" + else (); + match param with + | Transfer param -> transfer param storage + | Approve param -> approve param storage + | MintOrBurn param -> mintOrBurn param storage + | GetAllowance param -> (getAllowance param storage, storage) + | GetBalance param -> (getBalance param storage, storage) + | GetTotalSupply param -> (getTotalSupply param storage, storage) + end diff --git a/src/proto_011_PtHangzH/lib_protocol/contracts/lqt.tz b/src/proto_011_PtHangzH/lib_protocol/contracts/lqt.tz new file mode 100644 index 000000000000..d0f5f45fd05f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/contracts/lqt.tz @@ -0,0 +1,327 @@ +{ parameter + (or (or (or (pair %approve (address %spender) (nat %value)) + (pair %getAllowance + (pair %request (address %owner) (address %spender)) + (contract %callback nat))) + (or (pair %getBalance (address %owner) (contract %callback nat)) + (pair %getTotalSupply (unit %request) (contract %callback nat)))) + (or (pair %mintOrBurn (int %quantity) (address %target)) + (pair %transfer (address %from) (pair (address %to) (nat %value))))) ; + storage + (pair (big_map %tokens address nat) + (pair (big_map %allowances (pair (address %owner) (address %spender)) nat) + (pair (address %admin) (nat %total_supply)))) ; + code { DUP ; + CDR ; + PUSH mutez 0 ; + AMOUNT ; + COMPARE ; + NEQ ; + IF { PUSH string "DontSendTez" ; FAILWITH } {} ; + SWAP ; + CAR ; + IF_LEFT + { IF_LEFT + { IF_LEFT + { SWAP ; + DUP ; + DUG 2 ; + CDR ; + CAR ; + SWAP ; + DUP ; + DUG 2 ; + CAR ; + SENDER ; + PAIR ; + PUSH nat 0 ; + DIG 3 ; + DUP ; + DUG 4 ; + CDR ; + COMPARE ; + GT ; + PUSH nat 0 ; + DIG 3 ; + DUP ; + DUG 4 ; + DIG 3 ; + DUP ; + DUG 4 ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + COMPARE ; + GT ; + AND ; + IF { PUSH string "UnsafeAllowanceChange" ; FAILWITH } {} ; + DIG 3 ; + DUP ; + DUG 4 ; + CDR ; + CDR ; + DIG 2 ; + DIG 3 ; + CDR ; + PUSH nat 0 ; + SWAP ; + DUP ; + DUG 2 ; + COMPARE ; + EQ ; + IF { DROP ; NONE nat } { SOME } ; + DIG 3 ; + UPDATE ; + PAIR ; + SWAP ; + CAR ; + PAIR ; + NIL operation ; + PAIR } + { SWAP ; + DUP ; + DIG 2 ; + NIL operation ; + SWAP ; + DUP ; + DUG 2 ; + CDR ; + PUSH mutez 0 ; + DIG 4 ; + CDR ; + CAR ; + DIG 4 ; + CAR ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + TRANSFER_TOKENS ; + CONS ; + PAIR } } + { IF_LEFT + { SWAP ; + DUP ; + DIG 2 ; + NIL operation ; + SWAP ; + DUP ; + DUG 2 ; + CDR ; + PUSH mutez 0 ; + DIG 4 ; + CAR ; + DIG 4 ; + CAR ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + TRANSFER_TOKENS ; + CONS ; + PAIR } + { SWAP ; + DUP ; + DIG 2 ; + NIL operation ; + SWAP ; + CDR ; + PUSH mutez 0 ; + DIG 3 ; + CDR ; + CDR ; + CDR ; + TRANSFER_TOKENS ; + CONS ; + PAIR } } } + { IF_LEFT + { SWAP ; + DUP ; + DUG 2 ; + CDR ; + CDR ; + CAR ; + SENDER ; + COMPARE ; + NEQ ; + IF { PUSH string "OnlyAdmin" ; FAILWITH } {} ; + DUP ; + CAR ; + DIG 2 ; + DUP ; + DUG 3 ; + CAR ; + DIG 2 ; + DUP ; + DUG 3 ; + CDR ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + ADD ; + ISNAT ; + IF_NONE + { PUSH string "Cannot burn more than the target's balance." ; FAILWITH } + {} ; + SWAP ; + DUP ; + DUG 2 ; + CAR ; + DIG 3 ; + DUP ; + DUG 4 ; + CDR ; + CDR ; + CDR ; + ADD ; + ABS ; + DIG 3 ; + DUP ; + DUG 4 ; + CDR ; + DIG 4 ; + CAR ; + PUSH nat 0 ; + DIG 4 ; + DUP ; + DUG 5 ; + COMPARE ; + EQ ; + IF { DIG 3 ; DROP ; NONE nat } { DIG 3 ; SOME } ; + DIG 4 ; + CDR ; + UPDATE ; + PAIR ; + DUP ; + DUG 2 ; + CDR ; + CDR ; + CAR ; + PAIR ; + SWAP ; + DUP ; + DUG 2 ; + CDR ; + CAR ; + PAIR ; + SWAP ; + CAR ; + PAIR ; + NIL operation ; + PAIR } + { SWAP ; + DUP ; + DUG 2 ; + CDR ; + CAR ; + DIG 2 ; + DUP ; + DUG 3 ; + CAR ; + DIG 2 ; + DUP ; + DUG 3 ; + CAR ; + SENDER ; + COMPARE ; + EQ ; + IF { SWAP } + { SENDER ; + DIG 3 ; + DUP ; + DUG 4 ; + CAR ; + PAIR ; + DIG 3 ; + DUP ; + DUG 4 ; + CDR ; + CDR ; + DIG 3 ; + DUP ; + DUG 4 ; + DIG 2 ; + DUP ; + DUG 3 ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + SUB ; + ISNAT ; + IF_NONE { PUSH string "NotEnoughAllowance" ; FAILWITH } {} ; + DIG 3 ; + PUSH nat 0 ; + DIG 2 ; + DUP ; + DUG 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE nat } { SWAP ; SOME } ; + DIG 2 ; + UPDATE } ; + DIG 2 ; + DUP ; + DUG 3 ; + CDR ; + CDR ; + DIG 2 ; + DUP ; + DUG 3 ; + DIG 4 ; + DUP ; + DUG 5 ; + CAR ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + SUB ; + ISNAT ; + IF_NONE { PUSH string "NotEnoughBalance" ; FAILWITH } {} ; + DIG 2 ; + PUSH nat 0 ; + DIG 2 ; + DUP ; + DUG 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE nat } { SWAP ; SOME } ; + DIG 3 ; + DUP ; + DUG 4 ; + CAR ; + UPDATE ; + DIG 2 ; + DUP ; + DUG 3 ; + CDR ; + CDR ; + SWAP ; + DUP ; + DUG 2 ; + DIG 4 ; + DUP ; + DUG 5 ; + CDR ; + CAR ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + ADD ; + SWAP ; + PUSH nat 0 ; + DIG 2 ; + DUP ; + DUG 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE nat } { SWAP ; SOME } ; + DIG 3 ; + CDR ; + CAR ; + UPDATE ; + DIG 2 ; + CDR ; + SWAP ; + PAIR ; + DUP ; + CDR ; + CDR ; + DIG 2 ; + PAIR ; + SWAP ; + CAR ; + PAIR ; + NIL operation ; + PAIR } } } } + diff --git a/src/proto_011_PtHangzH/lib_protocol/coq-of-ocaml/README.md b/src/proto_011_PtHangzH/lib_protocol/coq-of-ocaml/README.md new file mode 100644 index 000000000000..dc8bbda5de5e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/coq-of-ocaml/README.md @@ -0,0 +1,11 @@ +# coq-of-ocaml + +In this folder we put the files relevant to the compilation of the protocol to +Coq using [coq-of-ocaml](https://clarus.github.io/coq-of-ocaml/). The code of +the protocol is annotated with `[@coq_...]` OCaml attributes. These attributes +are here to help the compilation to Coq. We document them on: +https://clarus.github.io/coq-of-ocaml/docs/attributes + +* `config.json` This file describes the configuration parameters for + coq-of-ocaml in the CI. For more information, see the + [documentation](https://clarus.github.io/coq-of-ocaml/docs/configuration). diff --git a/src/proto_011_PtHangzH/lib_protocol/coq-of-ocaml/config.json b/src/proto_011_PtHangzH/lib_protocol/coq-of-ocaml/config.json new file mode 100644 index 000000000000..a46e516495e1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/coq-of-ocaml/config.json @@ -0,0 +1,250 @@ +{ + "alias_barrier_modules": [ + "Tezos_protocol_environment_alpha__Environment" + ], + "constant_warning": false, + "constructor_map": [ + ["public_key_hash", "Ed25519", "Ed25519Hash"], + ["public_key_hash", "P256", "P256Hash"], + ["public_key_hash", "Secp256k1", "Secp256k1Hash"] + ], + "error_category_blacklist": [ + "side_effect" + ], + "error_filename_blacklist": [ + ], + "error_message_blacklist": [ + "Unbound module Tezos_protocol_011_PtHangzH_functor", + "The placeholders `_` in types are not handled", + "No type known for the following variants: `Ge, `Lt, `Eq, `Le, `Gt", + "No type known for the following variants: `Eq, `Ge, `Gt, `Le, `Lt", + "No type known for the following variants: `Eq", + "Constructor of the variant `Eq unknown", + "No type known for the following variants: `Tree, `Value", + "Constructor of the variant `Tree unknown", + "Constructor of the variant `Value unknown", + "Anonymous definition of signatures is not handled", + "A variable name instead of a pattern was expected", + "We only support extensible types in patterns at the head", + "This kind of signature is not handled", + "Tezos_raw_protocol_011_PtHangzH.Raw_context_intf.T" + ], + "escape_value": [ + "a", + "acc", + "alloc", + "b", + "baking_rights_query", + "case", + "cons", + "context", + "descr", + "diff", + "elt", + "endorsing_rights_query", + "eq", + "error", + "field", + "fixed", + "fp", + "frozen_balance", + "gas_counter_status", + "handler", + "has_big_map", + "has_lazy_storage", + "hash", + "info", + "init", + "integral", + "internal_gas", + "json", + "json_schema", + "judgement", + "key", + "kind", + "l", + "lazy_expr", + "level_query", + "list_query", + "may_saturate", + "mul_safe", + "namespace", + "nonce", + "query", + "p", + "parametric", + "r", + "raw", + "seed", + "sequence", + "snapshot", + "stack", + "storage", + "storage_error", + "t", + "tc_context", + "toplevel", + "trace", + "type_logger" + ], + "first_class_module_path_blacklist": [ + "Tezos_raw_protocol_011_PtHangzH", + "Tezos_protocol_environment_alpha.Environment", + "Tezos_protocol_environment_alpha.Environment.Sapling" + ], + "first_class_module_signature_blacklist": [ + "Tezos_sapling__Core_sig.T_encoding", + "Tezos_protocol_environment_alpha__Environment.Map.OrderedType", + "Tezos_protocol_environment_alpha__Environment.Set.OrderedType", + "Tezos_raw_protocol_011_PtHangzH__Raw_context.T", + "Environment_context.TREE" + ], + "merge_returns": [ + ["return=", "return?", "return=?"] + ], + "merge_types": [ + ["M=", "M?", "M=?"] + ], + "monadic_lets": [ + ["Error_monad.op_gtgteq", "let="], + ["Error_monad.op_gtgteqquestion", "let=?"], + ["Error_monad.op_gtgtquestion", "let?"] + ], + "monadic_let_returns": [ + ["Error_monad.op_gtpipeeq", "let=", "return="], + ["Error_monad.op_gtpipeeqquestion", "let=?", "return=?"], + ["Error_monad.op_gtpipequestion", "let?", "return?"] + ], + "monadic_returns": [ + ["Lwt.__return", "return="], + ["Error_monad.__return", "return=?"], + ["Error_monad.ok", "return?"] + ], + "monadic_return_lets": [ + ["Error_monad.op_gtgtquestioneq", "return=", "let=?"] + ], + "operator_infix": [ + ["Compare.Int.(Compare.S.op_eq)", "=i"], + ["Compare.Int.(Compare.S.op_ltgt)", "<>i"], + ["Compare.Int.(Compare.S.op_lteq)", "<=i"], + ["Compare.Int.(Compare.S.op_lt)", "=i"], + ["Compare.Int.(Compare.S.op_gt)", ">i"], + + ["Compare.Int32.(Compare.S.op_eq)", "=i32"], + ["Compare.Int32.(Compare.S.op_ltgt)", "<>i32"], + ["Compare.Int32.(Compare.S.op_lteq)", "<=i32"], + ["Compare.Int32.(Compare.S.op_lt)", "=i32"], + ["Compare.Int32.(Compare.S.op_gt)", ">i32"], + + ["Compare.Int64.(Compare.S.op_eq)", "=i64"], + ["Compare.Int64.(Compare.S.op_ltgt)", "<>i64"], + ["Compare.Int64.(Compare.S.op_lteq)", "<=i64"], + ["Compare.Int64.(Compare.S.op_lt)", "=i64"], + ["Compare.Int64.(Compare.S.op_gt)", ">i64"], + + ["Compare.Z.(Compare.S.op_eq)", "=Z"], + ["Compare.Z.(Compare.S.op_ltgt)", "<>Z"], + ["Compare.Z.(Compare.S.op_lteq)", "<=Z"], + ["Compare.Z.(Compare.S.op_lt)", "=Z"], + ["Compare.Z.(Compare.S.op_gt)", ">Z"], + + ["Int32.add", "+i32"], + ["Int32.sub", "-i32"], + ["Int32.mul", "*i32"], + ["Int32.div", "/i32"], + + ["Int64.add", "+i64"], + ["Int64.sub", "-i64"], + ["Int64.mul", "*i64"], + ["Int64.div", "/i64"], + + ["Pervasives.op_andand", "&&"], + ["Pervasives.op_pipepipe", "||"], + + ["Pervasives.op_plus", "+i"], + ["Pervasives.op_minus", "-i"], + ["Pervasives.op_star", "*i"], + ["Pervasives.op_div", "/i"], + + ["Z.add", "+Z"], + ["Z.sub", "-Z"], + ["Z.mul", "*Z"], + ["Z.div", "/Z"], + + ["Z_syntax.op_plus", "+Z"], + ["Z_syntax.op_star", "*Z"] + ], + "renaming_rules": [ + ["Error_monad.tzresult", "M?"], + ["Lwt.t", "M="], + ["Failure", "Failure"] + ], + "renaming_type_constructor": [ + ["Compare.Char.(Compare.S.t)", "ascii"], + ["Compare.Int.(Compare.S.t)", "int"], + ["Compare.Int32.(Compare.S.t)", "int32"], + ["Compare.Int64.(Compare.S.t)", "int64"], + ["Compare.String.(Compare.S.t)", "string"], + ["Compare.Z.(Compare.S.t)", "Z.t"] + ], + "require": [ + ["Tezos_raw_protocol_011_PtHangzH", "TezosOfOCaml.Proto_alpha"] + ], + "require_import": [ + ["Tezos_protocol_environment_alpha", "TezosOfOCaml.Proto_alpha"] + ], + "require_long_ident": [ + ["Storage_description", "TezosOfOCaml.Proto_alpha"] + ], + "require_mli": [ + ], + "variant_constructors": [ + ["Dir", "Context.Dir"], + ["Key", "Context.Key"], + ["Uint16", "Data_encoding.Uint16"], + ["Uint8", "Data_encoding.Uint8"], + ["Hex", "Hex.Hex"], + ["Branch", "Error_monad.Branch"], + ["Permanent", "Error_monad.Permanent"], + ["Temporary", "Error_monad.Temporary"] + ], + "variant_types": [ + ["Dir", "Context.key_or_dir"], + ["Key", "Context.key_or_dir"] + ], + "without_guard_checking": [ + "apply.ml", + "apply_results.ml", + "baking.ml", + "contract_repr.ml", + "delegate_services.ml", + "fixed_point_repr.ml", + "helpers_services.ml", + "lazy_storage_kind.ml", + "legacy_script_support_repr.ml", + "level_storage.ml", + "michelson_v1_gas.ml", + "michelson_v1_primitives.ml", + "misc.ml", + "operation_repr.ml", + "raw_context.ml", + "roll_storage.ml", + "sapling_storage.ml", + "script_interpreter.ml", + "script_ir_annot.ml", + "script_ir_translator.ml", + "script_repr.ml", + "seed_repr.ml", + "storage_description.ml", + "storage_functors.ml", + "tez_repr.ml" + ], + "without_positivity_checking": [ + "misc.ml", + "storage_description.ml" + ] +} diff --git a/src/proto_011_PtHangzH/lib_protocol/cycle_repr.ml b/src/proto_011_PtHangzH/lib_protocol/cycle_repr.ml new file mode 100644 index 000000000000..3cf65623c33a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/cycle_repr.ml @@ -0,0 +1,87 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type t = int32 + +type cycle = t + +let encoding = Data_encoding.int32 + +let rpc_arg = + let construct = Int32.to_string in + let destruct str = + Int32.of_string_opt str |> Option.to_result ~none:"Cannot parse cycle" + in + RPC_arg.make + ~descr:"A cycle integer" + ~name:"block_cycle" + ~construct + ~destruct + () + +let pp ppf cycle = Format.fprintf ppf "%ld" cycle + +include (Compare.Int32 : Compare.S with type t := t) + +module Map = Map.Make (Compare.Int32) + +let root = 0l + +let succ = Int32.succ + +let pred = function 0l -> None | i -> Some (Int32.pred i) + +let add c i = + assert (Compare.Int.(i >= 0)) ; + Int32.add c (Int32.of_int i) + +let sub c i = + assert (Compare.Int.(i >= 0)) ; + let r = Int32.sub c (Int32.of_int i) in + if Compare.Int32.(r < 0l) then None else Some r + +let diff = Int32.sub + +let to_int32 i = i + +let of_int32_exn l = + if Compare.Int32.(l >= 0l) then l else invalid_arg "Level_repr.Cycle.of_int32" + +module Index = struct + type t = cycle + + let path_length = 1 + + let to_path c l = Int32.to_string (to_int32 c) :: l + + let of_path = function [s] -> Int32.of_string_opt s | _ -> None + + let rpc_arg = rpc_arg + + let encoding = encoding + + let compare = compare +end diff --git a/src/proto_011_PtHangzH/lib_protocol/cycle_repr.mli b/src/proto_011_PtHangzH/lib_protocol/cycle_repr.mli new file mode 100644 index 000000000000..ad91fbd60447 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/cycle_repr.mli @@ -0,0 +1,56 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type t + +type cycle = t + +include Compare.S with type t := t + +val encoding : cycle Data_encoding.t + +val rpc_arg : cycle RPC_arg.arg + +val pp : Format.formatter -> cycle -> unit + +val root : cycle + +val pred : cycle -> cycle option + +val add : cycle -> int -> cycle + +val sub : cycle -> int -> cycle option + +val succ : cycle -> cycle + +val diff : cycle -> cycle -> int32 + +val to_int32 : cycle -> int32 + +val of_int32_exn : int32 -> cycle + +module Map : Map.S with type key = cycle + +module Index : Storage_description.INDEX with type t = cycle diff --git a/src/proto_011_PtHangzH/lib_protocol/delegate_services.ml b/src/proto_011_PtHangzH/lib_protocol/delegate_services.ml new file mode 100644 index 000000000000..b5bfbcc16f05 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/delegate_services.ml @@ -0,0 +1,390 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +type error += Balance_rpc_non_delegate of public_key_hash + +let () = + register_error_kind + `Temporary + ~id:"delegate_service.balance_rpc_on_non_delegate" + ~title:"Balance request for an unregistered delegate" + ~description:"The account whose balance was requested is not a delegate." + ~pp:(fun ppf pkh -> + Format.fprintf + ppf + "The implicit account (%a) whose balance was requested is not a \ + registered delegate. To get the balance of this account you can use \ + the ../context/contracts/%a/balance RPC." + Signature.Public_key_hash.pp + pkh + Signature.Public_key_hash.pp + pkh) + Data_encoding.(obj1 (req "pkh" Signature.Public_key_hash.encoding)) + (function Balance_rpc_non_delegate pkh -> Some pkh | _ -> None) + (fun pkh -> Balance_rpc_non_delegate pkh) + +type info = { + balance : Tez.t; + frozen_balance : Tez.t; + frozen_balance_by_cycle : Delegate.frozen_balance Cycle.Map.t; + staking_balance : Tez.t; + delegated_contracts : Contract.t list; + delegated_balance : Tez.t; + deactivated : bool; + grace_period : Cycle.t; + voting_power : int32; +} + +let info_encoding = + let open Data_encoding in + conv + (fun { + balance; + frozen_balance; + frozen_balance_by_cycle; + staking_balance; + delegated_contracts; + delegated_balance; + deactivated; + grace_period; + voting_power; + } -> + ( balance, + frozen_balance, + frozen_balance_by_cycle, + staking_balance, + delegated_contracts, + delegated_balance, + deactivated, + grace_period, + voting_power )) + (fun ( balance, + frozen_balance, + frozen_balance_by_cycle, + staking_balance, + delegated_contracts, + delegated_balance, + deactivated, + grace_period, + voting_power ) -> + { + balance; + frozen_balance; + frozen_balance_by_cycle; + staking_balance; + delegated_contracts; + delegated_balance; + deactivated; + grace_period; + voting_power; + }) + (obj9 + (req "balance" Tez.encoding) + (req "frozen_balance" Tez.encoding) + (req "frozen_balance_by_cycle" Delegate.frozen_balance_by_cycle_encoding) + (req "staking_balance" Tez.encoding) + (req "delegated_contracts" (list Contract.encoding)) + (req "delegated_balance" Tez.encoding) + (req "deactivated" bool) + (req "grace_period" Cycle.encoding) + (req "voting_power" int32)) + +module S = struct + let raw_path = RPC_path.(open_root / "context" / "delegates") + + open Data_encoding + + type list_query = {active : bool; inactive : bool} + + let list_query : list_query RPC_query.t = + let open RPC_query in + query (fun active inactive -> {active; inactive}) + |+ flag "active" (fun t -> t.active) + |+ flag "inactive" (fun t -> t.inactive) + |> seal + + let list_delegate = + RPC_service.get_service + ~description:"Lists all registered delegates." + ~query:list_query + ~output:(list Signature.Public_key_hash.encoding) + raw_path + + let path = RPC_path.(raw_path /: Signature.Public_key_hash.rpc_arg) + + let info = + RPC_service.get_service + ~description:"Everything about a delegate." + ~query:RPC_query.empty + ~output:info_encoding + path + + let balance = + RPC_service.get_service + ~description: + "Returns the full balance of a given delegate, including the frozen \ + balances." + ~query:RPC_query.empty + ~output:Tez.encoding + RPC_path.(path / "balance") + + let frozen_balance = + RPC_service.get_service + ~description: + "Returns the total frozen balances of a given delegate, this includes \ + the frozen deposits, rewards and fees." + ~query:RPC_query.empty + ~output:Tez.encoding + RPC_path.(path / "frozen_balance") + + let frozen_balance_by_cycle = + RPC_service.get_service + ~description: + "Returns the frozen balances of a given delegate, indexed by the cycle \ + by which it will be unfrozen" + ~query:RPC_query.empty + ~output:Delegate.frozen_balance_by_cycle_encoding + RPC_path.(path / "frozen_balance_by_cycle") + + let staking_balance = + RPC_service.get_service + ~description: + "Returns the total amount of tokens delegated to a given delegate. \ + This includes the balances of all the contracts that delegate to it, \ + but also the balance of the delegate itself and its frozen fees and \ + deposits. The rewards do not count in the delegated balance until \ + they are unfrozen." + ~query:RPC_query.empty + ~output:Tez.encoding + RPC_path.(path / "staking_balance") + + let delegated_contracts = + RPC_service.get_service + ~description: + "Returns the list of contracts that delegate to a given delegate." + ~query:RPC_query.empty + ~output:(list Contract.encoding) + RPC_path.(path / "delegated_contracts") + + let delegated_balance = + RPC_service.get_service + ~description: + "Returns the balances of all the contracts that delegate to a given \ + delegate. This excludes the delegate's own balance and its frozen \ + balances." + ~query:RPC_query.empty + ~output:Tez.encoding + RPC_path.(path / "delegated_balance") + + let deactivated = + RPC_service.get_service + ~description: + "Tells whether the delegate is currently tagged as deactivated or not." + ~query:RPC_query.empty + ~output:bool + RPC_path.(path / "deactivated") + + let grace_period = + RPC_service.get_service + ~description: + "Returns the cycle by the end of which the delegate might be \ + deactivated if she fails to execute any delegate action. A \ + deactivated delegate might be reactivated (without loosing any rolls) \ + by simply re-registering as a delegate. For deactivated delegates, \ + this value contains the cycle by which they were deactivated." + ~query:RPC_query.empty + ~output:Cycle.encoding + RPC_path.(path / "grace_period") + + let voting_power = + RPC_service.get_service + ~description: + "The number of rolls in the vote listings for a given delegate" + ~query:RPC_query.empty + ~output:Data_encoding.int32 + RPC_path.(path / "voting_power") +end + +let delegate_register () = + let open Services_registration in + register0 ~chunked:true S.list_delegate (fun ctxt q () -> + Delegate.list ctxt >>= fun delegates -> + match q with + | {active = true; inactive = false} -> + List.filter_es + (fun pkh -> Delegate.deactivated ctxt pkh >|=? not) + delegates + | {active = false; inactive = true} -> + List.filter_es (fun pkh -> Delegate.deactivated ctxt pkh) delegates + | _ -> return delegates) ; + register1 ~chunked:false S.info (fun ctxt pkh () () -> + Delegate.check_delegate ctxt pkh >>=? fun () -> + Delegate.full_balance ctxt pkh >>=? fun balance -> + Delegate.frozen_balance ctxt pkh >>=? fun frozen_balance -> + Delegate.frozen_balance_by_cycle ctxt pkh + >>= fun frozen_balance_by_cycle -> + Delegate.staking_balance ctxt pkh >>=? fun staking_balance -> + Delegate.delegated_contracts ctxt pkh >>= fun delegated_contracts -> + Delegate.delegated_balance ctxt pkh >>=? fun delegated_balance -> + Delegate.deactivated ctxt pkh >>=? fun deactivated -> + Delegate.grace_period ctxt pkh >>=? fun grace_period -> + Vote.get_voting_power_free ctxt pkh >|=? fun voting_power -> + { + balance; + frozen_balance; + frozen_balance_by_cycle; + staking_balance; + delegated_contracts; + delegated_balance; + deactivated; + grace_period; + voting_power; + }) ; + register1 ~chunked:false S.balance (fun ctxt pkh () () -> + trace (Balance_rpc_non_delegate pkh) (Delegate.check_delegate ctxt pkh) + >>=? fun () -> Delegate.full_balance ctxt pkh) ; + register1 ~chunked:false S.frozen_balance (fun ctxt pkh () () -> + Delegate.check_delegate ctxt pkh >>=? fun () -> + Delegate.frozen_balance ctxt pkh) ; + register1 ~chunked:true S.frozen_balance_by_cycle (fun ctxt pkh () () -> + Delegate.check_delegate ctxt pkh >>=? fun () -> + Delegate.frozen_balance_by_cycle ctxt pkh >|= ok) ; + register1 ~chunked:false S.staking_balance (fun ctxt pkh () () -> + Delegate.check_delegate ctxt pkh >>=? fun () -> + Delegate.staking_balance ctxt pkh) ; + register1 ~chunked:true S.delegated_contracts (fun ctxt pkh () () -> + Delegate.check_delegate ctxt pkh >>=? fun () -> + Delegate.delegated_contracts ctxt pkh >|= ok) ; + register1 ~chunked:false S.delegated_balance (fun ctxt pkh () () -> + Delegate.check_delegate ctxt pkh >>=? fun () -> + Delegate.delegated_balance ctxt pkh) ; + register1 ~chunked:false S.deactivated (fun ctxt pkh () () -> + Delegate.check_delegate ctxt pkh >>=? fun () -> + Delegate.deactivated ctxt pkh) ; + register1 ~chunked:false S.grace_period (fun ctxt pkh () () -> + Delegate.check_delegate ctxt pkh >>=? fun () -> + Delegate.grace_period ctxt pkh) ; + register1 ~chunked:false S.voting_power (fun ctxt pkh () () -> + Delegate.check_delegate ctxt pkh >>=? fun () -> + Vote.get_voting_power_free ctxt pkh) + +let list ctxt block ?(active = true) ?(inactive = false) () = + RPC_context.make_call0 S.list_delegate ctxt block {active; inactive} () + +let info ctxt block pkh = RPC_context.make_call1 S.info ctxt block pkh () () + +let balance ctxt block pkh = + RPC_context.make_call1 S.balance ctxt block pkh () () + +let frozen_balance ctxt block pkh = + RPC_context.make_call1 S.frozen_balance ctxt block pkh () () + +let frozen_balance_by_cycle ctxt block pkh = + RPC_context.make_call1 S.frozen_balance_by_cycle ctxt block pkh () () + +let staking_balance ctxt block pkh = + RPC_context.make_call1 S.staking_balance ctxt block pkh () () + +let delegated_contracts ctxt block pkh = + RPC_context.make_call1 S.delegated_contracts ctxt block pkh () () + +let delegated_balance ctxt block pkh = + RPC_context.make_call1 S.delegated_balance ctxt block pkh () () + +let deactivated ctxt block pkh = + RPC_context.make_call1 S.deactivated ctxt block pkh () () + +let grace_period ctxt block pkh = + RPC_context.make_call1 S.grace_period ctxt block pkh () () + +let voting_power ctxt block pkh = + RPC_context.make_call1 S.voting_power ctxt block pkh () () + +module Minimal_valid_time = struct + let minimal_valid_time ctxt ~priority ~endorsing_power ~predecessor_timestamp + = + Baking.minimal_valid_time + (Constants.parametric ctxt) + ~priority + ~endorsing_power + ~predecessor_timestamp + + module S = struct + type t = {priority : int; endorsing_power : int} + + let minimal_valid_time_query = + let open RPC_query in + query (fun priority endorsing_power -> {priority; endorsing_power}) + |+ field "priority" RPC_arg.int 0 (fun t -> t.priority) + |+ field "endorsing_power" RPC_arg.int 0 (fun t -> t.endorsing_power) + |> seal + + let minimal_valid_time = + RPC_service.get_service + ~description: + "Minimal valid time for a block given a priority and an endorsing \ + power." + ~query:minimal_valid_time_query + ~output:Time.encoding + RPC_path.(open_root / "minimal_valid_time") + end + + let register () = + let open Services_registration in + register0 + ~chunked:false + S.minimal_valid_time + (fun ctxt {priority; endorsing_power} () -> + let predecessor_timestamp = Timestamp.predecessor ctxt in + Lwt.return + @@ minimal_valid_time + ctxt + ~priority + ~endorsing_power + ~predecessor_timestamp) + + let get ctxt block priority endorsing_power = + RPC_context.make_call0 + S.minimal_valid_time + ctxt + block + {priority; endorsing_power} + () +end + +let register () = + delegate_register () ; + Minimal_valid_time.register () + +let minimal_valid_time ctxt priority endorsing_power predecessor_timestamp = + Minimal_valid_time.minimal_valid_time + ctxt + ~priority + ~endorsing_power + ~predecessor_timestamp diff --git a/src/proto_011_PtHangzH/lib_protocol/delegate_services.mli b/src/proto_011_PtHangzH/lib_protocol/delegate_services.mli new file mode 100644 index 000000000000..939ec94968ad --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/delegate_services.mli @@ -0,0 +1,117 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +val list : + 'a #RPC_context.simple -> + 'a -> + ?active:bool -> + ?inactive:bool -> + unit -> + Signature.Public_key_hash.t list shell_tzresult Lwt.t + +type info = { + balance : Tez.t; + frozen_balance : Tez.t; + frozen_balance_by_cycle : Delegate.frozen_balance Cycle.Map.t; + staking_balance : Tez.t; + delegated_contracts : Contract.t list; + delegated_balance : Tez.t; + deactivated : bool; + grace_period : Cycle.t; + voting_power : int32; +} + +val info_encoding : info Data_encoding.t + +val info : + 'a #RPC_context.simple -> + 'a -> + Signature.Public_key_hash.t -> + info shell_tzresult Lwt.t + +val balance : + 'a #RPC_context.simple -> + 'a -> + Signature.Public_key_hash.t -> + Tez.t shell_tzresult Lwt.t + +val frozen_balance : + 'a #RPC_context.simple -> + 'a -> + Signature.Public_key_hash.t -> + Tez.t shell_tzresult Lwt.t + +val frozen_balance_by_cycle : + 'a #RPC_context.simple -> + 'a -> + Signature.Public_key_hash.t -> + Delegate.frozen_balance Cycle.Map.t shell_tzresult Lwt.t + +val staking_balance : + 'a #RPC_context.simple -> + 'a -> + Signature.Public_key_hash.t -> + Tez.t shell_tzresult Lwt.t + +val delegated_contracts : + 'a #RPC_context.simple -> + 'a -> + Signature.Public_key_hash.t -> + Contract.t list shell_tzresult Lwt.t + +val delegated_balance : + 'a #RPC_context.simple -> + 'a -> + Signature.Public_key_hash.t -> + Tez.t shell_tzresult Lwt.t + +val deactivated : + 'a #RPC_context.simple -> + 'a -> + Signature.Public_key_hash.t -> + bool shell_tzresult Lwt.t + +val grace_period : + 'a #RPC_context.simple -> + 'a -> + Signature.Public_key_hash.t -> + Cycle.t shell_tzresult Lwt.t + +val voting_power : + 'a #RPC_context.simple -> 'a -> public_key_hash -> int32 shell_tzresult Lwt.t + +module Minimal_valid_time : sig + val get : + 'a #RPC_context.simple -> 'a -> int -> int -> Time.t shell_tzresult Lwt.t +end + +(* temporary export for deprecated unit test *) +val minimal_valid_time : + Alpha_context.t -> int -> int -> Time.t -> Time.t tzresult + +val register : unit -> unit diff --git a/src/proto_011_PtHangzH/lib_protocol/delegate_storage.ml b/src/proto_011_PtHangzH/lib_protocol/delegate_storage.ml new file mode 100644 index 000000000000..0cfb1f0a9225 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/delegate_storage.ml @@ -0,0 +1,568 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type frozen_balance = { + deposit : Tez_repr.t; + fees : Tez_repr.t; + rewards : Tez_repr.t; +} + +let frozen_balance_encoding = + let open Data_encoding in + conv + (fun {deposit; fees; rewards} -> (deposit, fees, rewards)) + (fun (deposit, fees, rewards) -> {deposit; fees; rewards}) + (obj3 + (req "deposits" Tez_repr.encoding) + (req "fees" Tez_repr.encoding) + (req "rewards" Tez_repr.encoding)) + +type error += + | No_deletion of Signature.Public_key_hash.t (* `Permanent *) + | Active_delegate (* `Temporary *) + | Current_delegate (* `Temporary *) + | Empty_delegate_account of Signature.Public_key_hash.t (* `Temporary *) + | Balance_too_low_for_deposit of { + (* `Temporary *) + delegate : Signature.Public_key_hash.t; + deposit : Tez_repr.t; + balance : Tez_repr.t; + } + | Not_registered of Signature.Public_key_hash.t +(* `Temporary *) + +let () = + register_error_kind + `Permanent + ~id:"delegate.no_deletion" + ~title:"Forbidden delegate deletion" + ~description:"Tried to unregister a delegate" + ~pp:(fun ppf delegate -> + Format.fprintf + ppf + "Delegate deletion is forbidden (%a)" + Signature.Public_key_hash.pp + delegate) + Data_encoding.(obj1 (req "delegate" Signature.Public_key_hash.encoding)) + (function No_deletion c -> Some c | _ -> None) + (fun c -> No_deletion c) ; + register_error_kind + `Temporary + ~id:"delegate.already_active" + ~title:"Delegate already active" + ~description:"Useless delegate reactivation" + ~pp:(fun ppf () -> + Format.fprintf ppf "The delegate is still active, no need to refresh it") + Data_encoding.empty + (function Active_delegate -> Some () | _ -> None) + (fun () -> Active_delegate) ; + register_error_kind + `Temporary + ~id:"delegate.unchanged" + ~title:"Unchanged delegated" + ~description:"Contract already delegated to the given delegate" + ~pp:(fun ppf () -> + Format.fprintf + ppf + "The contract is already delegated to the same delegate") + Data_encoding.empty + (function Current_delegate -> Some () | _ -> None) + (fun () -> Current_delegate) ; + register_error_kind + `Permanent + ~id:"delegate.empty_delegate_account" + ~title:"Empty delegate account" + ~description:"Cannot register a delegate when its implicit account is empty" + ~pp:(fun ppf delegate -> + Format.fprintf + ppf + "Delegate registration is forbidden when the delegate\n\ + \ implicit account is empty (%a)" + Signature.Public_key_hash.pp + delegate) + Data_encoding.(obj1 (req "delegate" Signature.Public_key_hash.encoding)) + (function Empty_delegate_account c -> Some c | _ -> None) + (fun c -> Empty_delegate_account c) ; + register_error_kind + `Temporary + ~id:"delegate.balance_too_low_for_deposit" + ~title:"Balance too low for deposit" + ~description:"Cannot freeze deposit when the balance is too low" + ~pp:(fun ppf (delegate, balance, deposit) -> + Format.fprintf + ppf + "Delegate %a has a too low balance (%a) to deposit %a" + Signature.Public_key_hash.pp + delegate + Tez_repr.pp + balance + Tez_repr.pp + deposit) + Data_encoding.( + obj3 + (req "delegate" Signature.Public_key_hash.encoding) + (req "balance" Tez_repr.encoding) + (req "deposit" Tez_repr.encoding)) + (function + | Balance_too_low_for_deposit {delegate; balance; deposit} -> + Some (delegate, balance, deposit) + | _ -> None) + (fun (delegate, balance, deposit) -> + Balance_too_low_for_deposit {delegate; balance; deposit}) ; + register_error_kind + `Temporary + ~id:"delegate.not_registered" + ~title:"Not a registered delegate" + ~description: + "The provided public key hash is not the address of a registered \ + delegate." + ~pp:(fun ppf pkh -> + Format.fprintf + ppf + "The provided public key hash (%a) is not the address of a registered \ + delegate. If you own this account and want to register it as a \ + delegate, use a delegation operation to delegate the account to \ + itself." + Signature.Public_key_hash.pp + pkh) + Data_encoding.(obj1 (req "pkh" Signature.Public_key_hash.encoding)) + (function Not_registered pkh -> Some pkh | _ -> None) + (fun pkh -> Not_registered pkh) + +let link c contract delegate = + Storage.Contract.Balance.get c contract >>=? fun balance -> + Roll_storage.Delegate.add_amount c delegate balance >>=? fun c -> + Storage.Contract.Delegated.add + (c, Contract_repr.implicit_contract delegate) + contract + >|= ok + +let unlink c contract = + Storage.Contract.Balance.get c contract >>=? fun balance -> + Storage.Contract.Delegate.find c contract >>=? function + | None -> return c + | Some delegate -> + (* Removes the balance of the contract from the delegate *) + Roll_storage.Delegate.remove_amount c delegate balance >>=? fun c -> + Storage.Contract.Delegated.remove + (c, Contract_repr.implicit_contract delegate) + contract + >|= ok + +let known c delegate = + Storage.Contract.Manager.find c (Contract_repr.implicit_contract delegate) + >>=? function + | None | Some (Manager_repr.Hash _) -> return_false + | Some (Manager_repr.Public_key _) -> return_true + +(* A delegate is registered if its "implicit account" delegates to itself. *) +let registered c delegate = + Storage.Contract.Delegate.find c (Contract_repr.implicit_contract delegate) + >|=? function + | Some current_delegate -> + Signature.Public_key_hash.equal delegate current_delegate + | None -> false + +let init ctxt contract delegate = + known ctxt delegate >>=? fun known_delegate -> + error_unless known_delegate (Roll_storage.Unregistered_delegate delegate) + >>?= fun () -> + registered ctxt delegate >>=? fun is_registered -> + error_unless is_registered (Roll_storage.Unregistered_delegate delegate) + >>?= fun () -> + Storage.Contract.Delegate.init ctxt contract delegate >>=? fun ctxt -> + link ctxt contract delegate + +let get = Roll_storage.get_contract_delegate + +let set c contract delegate = + match delegate with + | None -> ( + let delete () = + unlink c contract >>=? fun c -> + Storage.Contract.Delegate.remove c contract >|= ok + in + match Contract_repr.is_implicit contract with + | Some pkh -> + (* check if contract is a registered delegate *) + registered c pkh >>=? fun is_registered -> + if is_registered then fail (No_deletion pkh) else delete () + | None -> delete ()) + | Some delegate -> + known c delegate >>=? fun known_delegate -> + registered c delegate >>=? fun registered_delegate -> + let self_delegation = + match Contract_repr.is_implicit contract with + | Some pkh -> Signature.Public_key_hash.equal pkh delegate + | None -> false + in + if (not known_delegate) || not (registered_delegate || self_delegation) + then fail (Roll_storage.Unregistered_delegate delegate) + else + (Storage.Contract.Delegate.find c contract >>=? function + | Some current_delegate + when Signature.Public_key_hash.equal delegate current_delegate -> + if self_delegation then + Roll_storage.Delegate.is_inactive c delegate >>=? function + | true -> return_unit + | false -> fail Active_delegate + else fail Current_delegate + | None | Some _ -> return_unit) + >>=? fun () -> + (* check if contract is a registered delegate *) + (match Contract_repr.is_implicit contract with + | Some pkh -> + registered c pkh >>=? fun is_registered -> + (* allow self-delegation to re-activate *) + if (not self_delegation) && is_registered then + fail (No_deletion pkh) + else return_unit + | None -> return_unit) + >>=? fun () -> + Storage.Contract.Balance.mem c contract >>= fun exists -> + error_when + (self_delegation && not exists) + (Empty_delegate_account delegate) + >>?= fun () -> + unlink c contract >>=? fun c -> + Storage.Contract.Delegate.add c contract delegate >>= fun c -> + link c contract delegate >>=? fun c -> + if self_delegation then + Storage.Delegates.add c delegate >>= fun c -> + Roll_storage.Delegate.set_active c delegate + else return c + +let remove ctxt contract = unlink ctxt contract + +let delegated_contracts ctxt delegate = + let contract = Contract_repr.implicit_contract delegate in + Storage.Contract.Delegated.elements (ctxt, contract) + +let get_frozen_deposit ctxt contract cycle = + Storage.Contract.Frozen_deposits.find (ctxt, contract) cycle + >|=? Option.value ~default:Tez_repr.zero + +let credit_frozen_deposit ctxt delegate cycle amount = + let contract = Contract_repr.implicit_contract delegate in + get_frozen_deposit ctxt contract cycle >>=? fun old_amount -> + Tez_repr.(old_amount +? amount) >>?= fun new_amount -> + Storage.Contract.Frozen_deposits.add (ctxt, contract) cycle new_amount + >>= fun ctxt -> + Storage.Delegates_with_frozen_balance.add (ctxt, cycle) delegate >|= ok + +let freeze_deposit ctxt delegate amount = + let ({Level_repr.cycle; _} : Level_repr.t) = Level_storage.current ctxt in + Roll_storage.Delegate.set_active ctxt delegate >>=? fun ctxt -> + let contract = Contract_repr.implicit_contract delegate in + Storage.Contract.Balance.get ctxt contract >>=? fun balance -> + record_trace + (Balance_too_low_for_deposit {delegate; deposit = amount; balance}) + Tez_repr.(balance -? amount) + >>?= fun new_balance -> + Storage.Contract.Balance.update ctxt contract new_balance >>=? fun ctxt -> + credit_frozen_deposit ctxt delegate cycle amount + +let get_frozen_fees ctxt contract cycle = + Storage.Contract.Frozen_fees.find (ctxt, contract) cycle + >|=? Option.value ~default:Tez_repr.zero + +let credit_frozen_fees ctxt delegate cycle amount = + let contract = Contract_repr.implicit_contract delegate in + get_frozen_fees ctxt contract cycle >>=? fun old_amount -> + Tez_repr.(old_amount +? amount) >>?= fun new_amount -> + Storage.Contract.Frozen_fees.add (ctxt, contract) cycle new_amount + >>= fun ctxt -> + Storage.Delegates_with_frozen_balance.add (ctxt, cycle) delegate >|= ok + +let freeze_fees ctxt delegate amount = + let ({Level_repr.cycle; _} : Level_repr.t) = Level_storage.current ctxt in + Roll_storage.Delegate.add_amount ctxt delegate amount >>=? fun ctxt -> + credit_frozen_fees ctxt delegate cycle amount + +let burn_fees ctxt delegate cycle prescribed_amount = + let contract = Contract_repr.implicit_contract delegate in + get_frozen_fees ctxt contract cycle >>=? fun old_amount -> + (match Tez_repr.(old_amount -? prescribed_amount) with + | Ok new_amount -> + Roll_storage.Delegate.remove_amount ctxt delegate prescribed_amount + >|=? fun ctxt -> (new_amount, prescribed_amount, ctxt) + | Error _ -> + Roll_storage.Delegate.remove_amount ctxt delegate old_amount + >|=? fun ctxt -> (Tez_repr.zero, old_amount, ctxt)) + >>=? fun (new_amount, burned_amount, ctxt) -> + Storage.Contract.Frozen_fees.add (ctxt, contract) cycle new_amount + >|= fun ctxt -> ok (ctxt, burned_amount) + +let get_frozen_rewards ctxt contract cycle = + Storage.Contract.Frozen_rewards.find (ctxt, contract) cycle + >|=? Option.value ~default:Tez_repr.zero + +let credit_frozen_rewards ctxt delegate cycle amount = + let contract = Contract_repr.implicit_contract delegate in + get_frozen_rewards ctxt contract cycle >>=? fun old_amount -> + Tez_repr.(old_amount +? amount) >>?= fun new_amount -> + Storage.Contract.Frozen_rewards.add (ctxt, contract) cycle new_amount + >>= fun ctxt -> + Storage.Delegates_with_frozen_balance.add (ctxt, cycle) delegate >|= ok + +let freeze_rewards ctxt delegate amount = + let ({Level_repr.cycle; _} : Level_repr.t) = Level_storage.current ctxt in + credit_frozen_rewards ctxt delegate cycle amount + +let burn_rewards ctxt delegate cycle prescribed_amount = + let contract = Contract_repr.implicit_contract delegate in + get_frozen_rewards ctxt contract cycle >>=? fun old_amount -> + let (new_amount, burned_amount) = + match Tez_repr.(old_amount -? prescribed_amount) with + | Error _ -> (Tez_repr.zero, old_amount) + | Ok new_amount -> (new_amount, prescribed_amount) + in + Storage.Contract.Frozen_rewards.add (ctxt, contract) cycle new_amount + >|= fun ctxt -> ok (ctxt, burned_amount) + +let unfreeze ctxt delegate cycle = + let contract = Contract_repr.implicit_contract delegate in + get_frozen_deposit ctxt contract cycle >>=? fun deposit -> + get_frozen_fees ctxt contract cycle >>=? fun fees -> + get_frozen_rewards ctxt contract cycle >>=? fun rewards -> + Storage.Contract.Balance.get ctxt contract >>=? fun balance -> + Tez_repr.(deposit +? fees) >>?= fun unfrozen_amount -> + Tez_repr.(unfrozen_amount +? rewards) >>?= fun unfrozen_amount -> + Tez_repr.(balance +? unfrozen_amount) >>?= fun balance -> + Storage.Contract.Balance.update ctxt contract balance >>=? fun ctxt -> + Roll_storage.Delegate.add_amount ctxt delegate rewards >>=? fun ctxt -> + Storage.Contract.Frozen_deposits.remove (ctxt, contract) cycle >>= fun ctxt -> + Storage.Contract.Frozen_fees.remove (ctxt, contract) cycle >>= fun ctxt -> + Storage.Contract.Frozen_rewards.remove (ctxt, contract) cycle >|= fun ctxt -> + ok + ( ctxt, + Receipt_repr.cleanup_balance_updates + [ + (Deposits (delegate, cycle), Debited deposit, Block_application); + (Fees (delegate, cycle), Debited fees, Block_application); + (Rewards (delegate, cycle), Debited rewards, Block_application); + ( Contract (Contract_repr.implicit_contract delegate), + Credited unfrozen_amount, + Block_application ); + ] ) + +let cycle_end ctxt last_cycle unrevealed = + let preserved = Constants_storage.preserved_cycles ctxt in + (match Cycle_repr.pred last_cycle with + | None -> return (ctxt, []) + | Some revealed_cycle -> + List.fold_left_es + (fun (ctxt, balance_updates) (u : Nonce_storage.unrevealed) -> + burn_fees ctxt u.delegate revealed_cycle u.fees + >>=? fun (ctxt, burned_fees) -> + burn_rewards ctxt u.delegate revealed_cycle u.rewards + >|=? fun (ctxt, burned_rewards) -> + let bus = + Receipt_repr. + [ + ( Fees (u.delegate, revealed_cycle), + Debited burned_fees, + Block_application ); + ( Rewards (u.delegate, revealed_cycle), + Debited burned_rewards, + Block_application ); + ] + in + (ctxt, bus @ balance_updates)) + (ctxt, []) + unrevealed) + >>=? fun (ctxt, balance_updates) -> + match Cycle_repr.sub last_cycle preserved with + | None -> return (ctxt, balance_updates, []) + | Some unfrozen_cycle -> + Storage.Delegates_with_frozen_balance.fold + (ctxt, unfrozen_cycle) + ~init:(Ok (ctxt, balance_updates)) + ~f:(fun delegate acc -> + acc >>?= fun (ctxt, bus) -> + unfreeze ctxt delegate unfrozen_cycle + >|=? fun (ctxt, balance_updates) -> (ctxt, balance_updates @ bus)) + >>=? fun (ctxt, balance_updates) -> + Storage.Delegates_with_frozen_balance.clear (ctxt, unfrozen_cycle) + >>= fun ctxt -> + Storage.Active_delegates_with_rolls.fold + ctxt + ~init:(Ok (ctxt, [])) + ~f:(fun delegate acc -> + acc >>?= fun (ctxt, deactivated) -> + Storage.Contract.Delegate_desactivation.get + ctxt + (Contract_repr.implicit_contract delegate) + >>=? fun cycle -> + if Cycle_repr.(cycle <= last_cycle) then + Roll_storage.Delegate.set_inactive ctxt delegate >|=? fun ctxt -> + (ctxt, delegate :: deactivated) + else return (ctxt, deactivated)) + >|=? fun (ctxt, deactivated) -> (ctxt, balance_updates, deactivated) + +let punish ctxt delegate cycle = + let contract = Contract_repr.implicit_contract delegate in + get_frozen_deposit ctxt contract cycle >>=? fun deposit -> + get_frozen_fees ctxt contract cycle >>=? fun fees -> + get_frozen_rewards ctxt contract cycle >>=? fun rewards -> + Roll_storage.Delegate.remove_amount ctxt delegate deposit >>=? fun ctxt -> + Roll_storage.Delegate.remove_amount ctxt delegate fees >>=? fun ctxt -> + (* Rewards are not accounted in the delegate's rolls yet... *) + Storage.Contract.Frozen_deposits.remove (ctxt, contract) cycle >>= fun ctxt -> + Storage.Contract.Frozen_fees.remove (ctxt, contract) cycle >>= fun ctxt -> + Storage.Contract.Frozen_rewards.remove (ctxt, contract) cycle >|= fun ctxt -> + ok (ctxt, {deposit; fees; rewards}) + +let has_frozen_balance ctxt delegate cycle = + let contract = Contract_repr.implicit_contract delegate in + get_frozen_deposit ctxt contract cycle >>=? fun deposit -> + if Tez_repr.(deposit <> zero) then return_true + else + get_frozen_fees ctxt contract cycle >>=? fun fees -> + if Tez_repr.(fees <> zero) then return_true + else + get_frozen_rewards ctxt contract cycle >|=? fun rewards -> + Tez_repr.(rewards <> zero) + +let frozen_balance_by_cycle_encoding = + let open Data_encoding in + conv + Cycle_repr.Map.bindings + (List.fold_left + (fun m (c, b) -> Cycle_repr.Map.add c b m) + Cycle_repr.Map.empty) + (list + (merge_objs + (obj1 (req "cycle" Cycle_repr.encoding)) + frozen_balance_encoding)) + +let empty_frozen_balance = + {deposit = Tez_repr.zero; fees = Tez_repr.zero; rewards = Tez_repr.zero} + +let frozen_balance_by_cycle ctxt delegate = + let contract = Contract_repr.implicit_contract delegate in + let map = Cycle_repr.Map.empty in + Storage.Contract.Frozen_deposits.fold + (ctxt, contract) + ~init:map + ~f:(fun cycle amount map -> + Lwt.return + (Cycle_repr.Map.add + cycle + {empty_frozen_balance with deposit = amount} + map)) + >>= fun map -> + Storage.Contract.Frozen_fees.fold + (ctxt, contract) + ~init:map + ~f:(fun cycle amount map -> + let balance = + match Cycle_repr.Map.find cycle map with + | None -> empty_frozen_balance + | Some balance -> balance + in + Lwt.return (Cycle_repr.Map.add cycle {balance with fees = amount} map)) + >>= fun map -> + Storage.Contract.Frozen_rewards.fold + (ctxt, contract) + ~init:map + ~f:(fun cycle amount map -> + let balance = + match Cycle_repr.Map.find cycle map with + | None -> empty_frozen_balance + | Some balance -> balance + in + Lwt.return (Cycle_repr.Map.add cycle {balance with rewards = amount} map)) + +let frozen_balance ctxt delegate = + let contract = Contract_repr.implicit_contract delegate in + let balance = Ok Tez_repr.zero in + Storage.Contract.Frozen_deposits.fold + (ctxt, contract) + ~init:balance + ~f:(fun _cycle amount acc -> + Lwt.return (acc >>? fun acc -> Tez_repr.(acc +? amount))) + >>= fun balance -> + Storage.Contract.Frozen_fees.fold + (ctxt, contract) + ~init:balance + ~f:(fun _cycle amount acc -> + Lwt.return (acc >>? fun acc -> Tez_repr.(acc +? amount))) + >>= fun balance -> + Storage.Contract.Frozen_rewards.fold + (ctxt, contract) + ~init:balance + ~f:(fun _cycle amount acc -> + Lwt.return (acc >>? fun acc -> Tez_repr.(acc +? amount))) + +let full_balance ctxt delegate = + let contract = Contract_repr.implicit_contract delegate in + frozen_balance ctxt delegate >>=? fun frozen_balance -> + Storage.Contract.Balance.get ctxt contract >>=? fun balance -> + Lwt.return Tez_repr.(frozen_balance +? balance) + +let deactivated = Roll_storage.Delegate.is_inactive + +let grace_period ctxt delegate = + let contract = Contract_repr.implicit_contract delegate in + Storage.Contract.Delegate_desactivation.get ctxt contract + +let staking_balance ctxt delegate = + let token_per_rolls = Constants_storage.tokens_per_roll ctxt in + Roll_storage.count_rolls ctxt delegate >>=? fun rolls -> + Roll_storage.get_change ctxt delegate >>=? fun change -> + Lwt.return + ( Tez_repr.(token_per_rolls *? Int64.of_int rolls) >>? fun balance -> + Tez_repr.(balance +? change) ) + +let delegated_balance ctxt delegate = + let contract = Contract_repr.implicit_contract delegate in + staking_balance ctxt delegate >>=? fun staking_balance -> + Storage.Contract.Balance.get ctxt contract >>= fun self_staking_balance -> + Storage.Contract.Frozen_deposits.fold + (ctxt, contract) + ~init:self_staking_balance + ~f:(fun _cycle amount acc -> + Lwt.return (acc >>? fun acc -> Tez_repr.(acc +? amount))) + >>= fun self_staking_balance -> + Storage.Contract.Frozen_fees.fold + (ctxt, contract) + ~init:self_staking_balance + ~f:(fun _cycle amount acc -> + Lwt.return (acc >>? fun acc -> Tez_repr.(acc +? amount))) + >>=? fun self_staking_balance -> + Lwt.return Tez_repr.(staking_balance -? self_staking_balance) + +let fold = Storage.Delegates.fold + +let list = Storage.Delegates.elements + +(* The fact that this succeeds iff [registered ctxt pkh] returns true is an + invariant of the [set] function. *) +let check_delegate ctxt pkh = + Storage.Delegates.mem ctxt pkh >>= function + | true -> return_unit + | false -> fail (Not_registered pkh) diff --git a/src/proto_011_PtHangzH/lib_protocol/delegate_storage.mli b/src/proto_011_PtHangzH/lib_protocol/delegate_storage.mli new file mode 100644 index 000000000000..3a7ee9fbe123 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/delegate_storage.mli @@ -0,0 +1,181 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type frozen_balance = { + deposit : Tez_repr.t; + fees : Tez_repr.t; + rewards : Tez_repr.t; +} + +(** Allow to register a delegate when creating an account. *) +val init : + Raw_context.t -> + Contract_repr.t -> + Signature.Public_key_hash.t -> + Raw_context.t tzresult Lwt.t + +(** Cleanup delegation when deleting a contract. *) +val remove : Raw_context.t -> Contract_repr.t -> Raw_context.t tzresult Lwt.t + +(** Reading the current delegate of a contract. *) +val get : + Raw_context.t -> + Contract_repr.t -> + Signature.Public_key_hash.t option tzresult Lwt.t + +val registered : + Raw_context.t -> Signature.Public_key_hash.t -> bool tzresult Lwt.t + +(** Updating the delegate of a contract. + + When calling this function on an "implicit contract" and setting + the delegate to the contract manager registers it as a delegate. One + cannot unregister a delegate for now. The associate contract is now + 'undeletable'. *) +val set : + Raw_context.t -> + Contract_repr.t -> + Signature.Public_key_hash.t option -> + Raw_context.t tzresult Lwt.t + +type error += + | No_deletion of Signature.Public_key_hash.t (* `Permanent *) + | Active_delegate (* `Temporary *) + | Current_delegate (* `Temporary *) + | Empty_delegate_account of Signature.Public_key_hash.t (* `Temporary *) + | Balance_too_low_for_deposit of { + delegate : Signature.Public_key_hash.t; + deposit : Tez_repr.t; + balance : Tez_repr.t; + } + +(* `Temporary *) + +(** Check that a given implicit account is a registered delegate. *) +val check_delegate : + Raw_context.t -> Signature.Public_key_hash.t -> unit tzresult Lwt.t + +(** Iterate on all registered delegates. *) +val fold : + Raw_context.t -> + init:'a -> + f:(Signature.Public_key_hash.t -> 'a -> 'a Lwt.t) -> + 'a Lwt.t + +(** List all registered delegates. *) +val list : Raw_context.t -> Signature.Public_key_hash.t list Lwt.t + +(** Various functions to 'freeze' tokens. A frozen 'deposit' keeps its + associated rolls. When frozen, 'fees' may trigger new rolls + allocation. Rewards won't trigger new rolls allocation until + unfrozen. *) +val freeze_deposit : + Raw_context.t -> + Signature.Public_key_hash.t -> + Tez_repr.t -> + Raw_context.t tzresult Lwt.t + +val freeze_fees : + Raw_context.t -> + Signature.Public_key_hash.t -> + Tez_repr.t -> + Raw_context.t tzresult Lwt.t + +val freeze_rewards : + Raw_context.t -> + Signature.Public_key_hash.t -> + Tez_repr.t -> + Raw_context.t tzresult Lwt.t + +(** Trigger the context maintenance at the end of cycle 'n', i.e.: + unfreeze deposit/fees/rewards from 'n - preserved_cycle' ; punish the + provided unrevealed seeds (typically seed from cycle 'n - 1'). + Returns a list of account with the amount that was unfrozen for each + and the list of deactivated delegates. *) +val cycle_end : + Raw_context.t -> + Cycle_repr.t -> + Nonce_storage.unrevealed list -> + (Raw_context.t + * Receipt_repr.balance_updates + * Signature.Public_key_hash.t list) + tzresult + Lwt.t + +(** Burn all then frozen deposit/fees/rewards for a delegate at a given + cycle. Returns the burned amounts. *) +val punish : + Raw_context.t -> + Signature.Public_key_hash.t -> + Cycle_repr.t -> + (Raw_context.t * frozen_balance) tzresult Lwt.t + +(** Has the given key some frozen tokens in its implicit contract? *) +val has_frozen_balance : + Raw_context.t -> + Signature.Public_key_hash.t -> + Cycle_repr.t -> + bool tzresult Lwt.t + +(** Returns the amount of frozen deposit, fees and rewards associated + to a given delegate. *) +val frozen_balance : + Raw_context.t -> Signature.Public_key_hash.t -> Tez_repr.t tzresult Lwt.t + +val frozen_balance_encoding : frozen_balance Data_encoding.t + +val frozen_balance_by_cycle_encoding : + frozen_balance Cycle_repr.Map.t Data_encoding.t + +(** Returns the amount of frozen deposit, fees and rewards associated + to a given delegate, indexed by the cycle by which at the end the + balance will be unfrozen. *) +val frozen_balance_by_cycle : + Raw_context.t -> + Signature.Public_key_hash.t -> + frozen_balance Cycle_repr.Map.t Lwt.t + +(** Returns the full 'balance' of the implicit contract associated to + a given key, i.e. the sum of the spendable balance and of the + frozen balance. *) +val full_balance : + Raw_context.t -> Signature.Public_key_hash.t -> Tez_repr.t tzresult Lwt.t + +val staking_balance : + Raw_context.t -> Signature.Public_key_hash.t -> Tez_repr.t tzresult Lwt.t + +(** Returns the list of contracts (implicit or originated) that delegated towards a given delegate *) +val delegated_contracts : + Raw_context.t -> Signature.Public_key_hash.t -> Contract_repr.t list Lwt.t + +val delegated_balance : + Raw_context.t -> Signature.Public_key_hash.t -> Tez_repr.t tzresult Lwt.t + +val deactivated : + Raw_context.t -> Signature.Public_key_hash.t -> bool tzresult Lwt.t + +val grace_period : + Raw_context.t -> Signature.Public_key_hash.t -> Cycle_repr.t tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/dune b/src/proto_011_PtHangzH/lib_protocol/dune new file mode 120000 index 000000000000..8b081aeedbd3 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/dune @@ -0,0 +1 @@ +../../lib_protocol_compiler/dune_protocol.v1 \ No newline at end of file diff --git a/src/proto_011_PtHangzH/lib_protocol/dune-project b/src/proto_011_PtHangzH/lib_protocol/dune-project new file mode 100644 index 000000000000..50582bef8969 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(formatting (enabled_for ocaml)) +(name tezos-embedded-protocol-011-PtHangzH) diff --git a/src/proto_011_PtHangzH/lib_protocol/dune.inc b/src/proto_011_PtHangzH/lib_protocol/dune.inc new file mode 100644 index 000000000000..5a7c637f0b4d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/dune.inc @@ -0,0 +1,621 @@ + + +; +; /!\ /!\ Do not modify this file /!\ /!\ +; +; but the original template in `tezos-protocol-compiler` +; + +; generated from src/lib_protocol_compiler/dune_protocol.template.v1 + +; This template is intended for protocols written after the Tezos +; project start using OCaml 4.12. +; +; template.v1 was introduced when we bumped the version of our OCaml +; dependency to 4.12. This change to a newer OCaml version introduced +; new warnings that need to be ignored in the protocols written before +; the update (see dune_protocol.template.v0). + +(rule + (targets environment.ml) + (action + (write-file %{targets} + "module Name = struct let name = \"011-PtHangzH\" end +include Tezos_protocol_environment.MakeV3(Name)() +module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end +"))) + +(rule + (targets registerer.ml) + (deps + misc.mli misc.ml + path_encoding.mli path_encoding.ml + storage_description.mli storage_description.ml + state_hash.mli state_hash.ml + nonce_hash.mli nonce_hash.ml + script_expr_hash.mli script_expr_hash.ml + contract_hash.mli contract_hash.ml + blinded_public_key_hash.mli blinded_public_key_hash.ml + tez_repr.mli tez_repr.ml + period_repr.mli period_repr.ml + time_repr.mli time_repr.ml + fixed_point_repr.mli fixed_point_repr.ml + saturation_repr.mli saturation_repr.ml + gas_limit_repr.mli gas_limit_repr.ml + constants_repr.mli constants_repr.ml + fitness_repr.mli fitness_repr.ml + raw_level_repr.mli raw_level_repr.ml + cycle_repr.mli cycle_repr.ml + level_repr.mli level_repr.ml + seed_repr.mli seed_repr.ml + voting_period_repr.mli voting_period_repr.ml + script_string_repr.mli script_string_repr.ml + script_int_repr.mli script_int_repr.ml + script_timestamp_repr.mli script_timestamp_repr.ml + michelson_v1_primitives.mli michelson_v1_primitives.ml + script_repr.mli script_repr.ml + cache_memory_helpers.ml + contract_repr.mli contract_repr.ml + roll_repr.mli roll_repr.ml + vote_repr.mli vote_repr.ml + block_header_repr.mli block_header_repr.ml + operation_repr.mli operation_repr.ml + manager_repr.mli manager_repr.ml + commitment_repr.mli commitment_repr.ml + parameters_repr.mli parameters_repr.ml + sapling_repr.ml + lazy_storage_kind.mli lazy_storage_kind.ml + receipt_repr.mli receipt_repr.ml + migration_repr.mli migration_repr.ml + raw_context_intf.ml + raw_context.mli raw_context.ml + storage_costs.mli storage_costs.ml + storage_sigs.ml + storage_functors.mli storage_functors.ml + storage.mli storage.ml + constants_storage.mli constants_storage.ml + level_storage.mli level_storage.ml + nonce_storage.mli nonce_storage.ml + seed_storage.mli seed_storage.ml + roll_storage.mli roll_storage.ml + delegate_storage.mli delegate_storage.ml + sapling_storage.ml + lazy_storage_diff.mli lazy_storage_diff.ml + contract_storage.mli contract_storage.ml + bootstrap_storage.mli bootstrap_storage.ml + fitness_storage.mli fitness_storage.ml + voting_period_storage.mli voting_period_storage.ml + vote_storage.mli vote_storage.ml + commitment_storage.mli commitment_storage.ml + fees_storage.mli fees_storage.ml + liquidity_baking_repr.mli liquidity_baking_repr.ml + liquidity_baking_cpmm.ml + liquidity_baking_lqt.ml + liquidity_baking_migration.mli liquidity_baking_migration.ml + init_storage.mli init_storage.ml + sapling_validator.ml + global_constants_costs.mli global_constants_costs.ml + global_constants_storage.mli global_constants_storage.ml + cache_costs.mli cache_costs.ml + alpha_context.mli alpha_context.ml + script_tc_errors.ml + script_typed_ir.mli script_typed_ir.ml + script_typed_ir_size.mli script_typed_ir_size.ml + script_typed_ir_size_costs.mli script_typed_ir_size_costs.ml + michelson_v1_gas.mli michelson_v1_gas.ml + script_ir_annot.mli script_ir_annot.ml + script_list.mli script_list.ml + script_comparable.mli script_comparable.ml + script_set.mli script_set.ml + script_map.mli script_map.ml + script_ir_translator.mli script_ir_translator.ml + script_cache.mli script_cache.ml + script_tc_errors_registration.mli script_tc_errors_registration.ml + script_interpreter_defs.ml + script_interpreter.mli script_interpreter.ml + baking.mli baking.ml + amendment.mli amendment.ml + apply_results.mli apply_results.ml + apply.mli apply.ml + services_registration.mli services_registration.ml + constants_services.mli constants_services.ml + sapling_services.ml + contract_services.mli contract_services.ml + delegate_services.mli delegate_services.ml + voting_services.mli voting_services.ml + alpha_services.mli alpha_services.ml + main.mli main.ml + (:src_dir TEZOS_PROTOCOL)) + (action + (with-stdout-to %{targets} + (chdir %{workspace_root} (run %{bin:tezos-embedded-protocol-packer} "%{src_dir}" "011_PtHangzH"))))) + +(rule + (targets functor.ml) + (deps + misc.mli misc.ml + path_encoding.mli path_encoding.ml + storage_description.mli storage_description.ml + state_hash.mli state_hash.ml + nonce_hash.mli nonce_hash.ml + script_expr_hash.mli script_expr_hash.ml + contract_hash.mli contract_hash.ml + blinded_public_key_hash.mli blinded_public_key_hash.ml + tez_repr.mli tez_repr.ml + period_repr.mli period_repr.ml + time_repr.mli time_repr.ml + fixed_point_repr.mli fixed_point_repr.ml + saturation_repr.mli saturation_repr.ml + gas_limit_repr.mli gas_limit_repr.ml + constants_repr.mli constants_repr.ml + fitness_repr.mli fitness_repr.ml + raw_level_repr.mli raw_level_repr.ml + cycle_repr.mli cycle_repr.ml + level_repr.mli level_repr.ml + seed_repr.mli seed_repr.ml + voting_period_repr.mli voting_period_repr.ml + script_string_repr.mli script_string_repr.ml + script_int_repr.mli script_int_repr.ml + script_timestamp_repr.mli script_timestamp_repr.ml + michelson_v1_primitives.mli michelson_v1_primitives.ml + script_repr.mli script_repr.ml + cache_memory_helpers.ml + contract_repr.mli contract_repr.ml + roll_repr.mli roll_repr.ml + vote_repr.mli vote_repr.ml + block_header_repr.mli block_header_repr.ml + operation_repr.mli operation_repr.ml + manager_repr.mli manager_repr.ml + commitment_repr.mli commitment_repr.ml + parameters_repr.mli parameters_repr.ml + sapling_repr.ml + lazy_storage_kind.mli lazy_storage_kind.ml + receipt_repr.mli receipt_repr.ml + migration_repr.mli migration_repr.ml + raw_context_intf.ml + raw_context.mli raw_context.ml + storage_costs.mli storage_costs.ml + storage_sigs.ml + storage_functors.mli storage_functors.ml + storage.mli storage.ml + constants_storage.mli constants_storage.ml + level_storage.mli level_storage.ml + nonce_storage.mli nonce_storage.ml + seed_storage.mli seed_storage.ml + roll_storage.mli roll_storage.ml + delegate_storage.mli delegate_storage.ml + sapling_storage.ml + lazy_storage_diff.mli lazy_storage_diff.ml + contract_storage.mli contract_storage.ml + bootstrap_storage.mli bootstrap_storage.ml + fitness_storage.mli fitness_storage.ml + voting_period_storage.mli voting_period_storage.ml + vote_storage.mli vote_storage.ml + commitment_storage.mli commitment_storage.ml + fees_storage.mli fees_storage.ml + liquidity_baking_repr.mli liquidity_baking_repr.ml + liquidity_baking_cpmm.ml + liquidity_baking_lqt.ml + liquidity_baking_migration.mli liquidity_baking_migration.ml + init_storage.mli init_storage.ml + sapling_validator.ml + global_constants_costs.mli global_constants_costs.ml + global_constants_storage.mli global_constants_storage.ml + cache_costs.mli cache_costs.ml + alpha_context.mli alpha_context.ml + script_tc_errors.ml + script_typed_ir.mli script_typed_ir.ml + script_typed_ir_size.mli script_typed_ir_size.ml + script_typed_ir_size_costs.mli script_typed_ir_size_costs.ml + michelson_v1_gas.mli michelson_v1_gas.ml + script_ir_annot.mli script_ir_annot.ml + script_list.mli script_list.ml + script_comparable.mli script_comparable.ml + script_set.mli script_set.ml + script_map.mli script_map.ml + script_ir_translator.mli script_ir_translator.ml + script_cache.mli script_cache.ml + script_tc_errors_registration.mli script_tc_errors_registration.ml + script_interpreter_defs.ml + script_interpreter.mli script_interpreter.ml + baking.mli baking.ml + amendment.mli amendment.ml + apply_results.mli apply_results.ml + apply.mli apply.ml + services_registration.mli services_registration.ml + constants_services.mli constants_services.ml + sapling_services.ml + contract_services.mli contract_services.ml + delegate_services.mli delegate_services.ml + voting_services.mli voting_services.ml + alpha_services.mli alpha_services.ml + main.mli main.ml + (:src_dir TEZOS_PROTOCOL)) + (action (with-stdout-to %{targets} + (chdir %{workspace_root} + (run %{bin:tezos-protocol-compiler.tezos-protocol-packer} %{src_dir}))))) + +(rule + (targets protocol.ml) + (deps + misc.mli misc.ml + path_encoding.mli path_encoding.ml + storage_description.mli storage_description.ml + state_hash.mli state_hash.ml + nonce_hash.mli nonce_hash.ml + script_expr_hash.mli script_expr_hash.ml + contract_hash.mli contract_hash.ml + blinded_public_key_hash.mli blinded_public_key_hash.ml + tez_repr.mli tez_repr.ml + period_repr.mli period_repr.ml + time_repr.mli time_repr.ml + fixed_point_repr.mli fixed_point_repr.ml + saturation_repr.mli saturation_repr.ml + gas_limit_repr.mli gas_limit_repr.ml + constants_repr.mli constants_repr.ml + fitness_repr.mli fitness_repr.ml + raw_level_repr.mli raw_level_repr.ml + cycle_repr.mli cycle_repr.ml + level_repr.mli level_repr.ml + seed_repr.mli seed_repr.ml + voting_period_repr.mli voting_period_repr.ml + script_string_repr.mli script_string_repr.ml + script_int_repr.mli script_int_repr.ml + script_timestamp_repr.mli script_timestamp_repr.ml + michelson_v1_primitives.mli michelson_v1_primitives.ml + script_repr.mli script_repr.ml + cache_memory_helpers.ml + contract_repr.mli contract_repr.ml + roll_repr.mli roll_repr.ml + vote_repr.mli vote_repr.ml + block_header_repr.mli block_header_repr.ml + operation_repr.mli operation_repr.ml + manager_repr.mli manager_repr.ml + commitment_repr.mli commitment_repr.ml + parameters_repr.mli parameters_repr.ml + sapling_repr.ml + lazy_storage_kind.mli lazy_storage_kind.ml + receipt_repr.mli receipt_repr.ml + migration_repr.mli migration_repr.ml + raw_context_intf.ml + raw_context.mli raw_context.ml + storage_costs.mli storage_costs.ml + storage_sigs.ml + storage_functors.mli storage_functors.ml + storage.mli storage.ml + constants_storage.mli constants_storage.ml + level_storage.mli level_storage.ml + nonce_storage.mli nonce_storage.ml + seed_storage.mli seed_storage.ml + roll_storage.mli roll_storage.ml + delegate_storage.mli delegate_storage.ml + sapling_storage.ml + lazy_storage_diff.mli lazy_storage_diff.ml + contract_storage.mli contract_storage.ml + bootstrap_storage.mli bootstrap_storage.ml + fitness_storage.mli fitness_storage.ml + voting_period_storage.mli voting_period_storage.ml + vote_storage.mli vote_storage.ml + commitment_storage.mli commitment_storage.ml + fees_storage.mli fees_storage.ml + liquidity_baking_repr.mli liquidity_baking_repr.ml + liquidity_baking_cpmm.ml + liquidity_baking_lqt.ml + liquidity_baking_migration.mli liquidity_baking_migration.ml + init_storage.mli init_storage.ml + sapling_validator.ml + global_constants_costs.mli global_constants_costs.ml + global_constants_storage.mli global_constants_storage.ml + cache_costs.mli cache_costs.ml + alpha_context.mli alpha_context.ml + script_tc_errors.ml + script_typed_ir.mli script_typed_ir.ml + script_typed_ir_size.mli script_typed_ir_size.ml + script_typed_ir_size_costs.mli script_typed_ir_size_costs.ml + michelson_v1_gas.mli michelson_v1_gas.ml + script_ir_annot.mli script_ir_annot.ml + script_list.mli script_list.ml + script_comparable.mli script_comparable.ml + script_set.mli script_set.ml + script_map.mli script_map.ml + script_ir_translator.mli script_ir_translator.ml + script_cache.mli script_cache.ml + script_tc_errors_registration.mli script_tc_errors_registration.ml + script_interpreter_defs.ml + script_interpreter.mli script_interpreter.ml + baking.mli baking.ml + amendment.mli amendment.ml + apply_results.mli apply_results.ml + apply.mli apply.ml + services_registration.mli services_registration.ml + constants_services.mli constants_services.ml + sapling_services.ml + contract_services.mli contract_services.ml + delegate_services.mli delegate_services.ml + voting_services.mli voting_services.ml + alpha_services.mli alpha_services.ml + main.mli main.ml) + (action + (write-file %{targets} + "module Environment = Tezos_protocol_environment_011_PtHangzH.Environment +let hash = Tezos_crypto.Protocol_hash.of_b58check_exn \"PtHangzHogokSuiMHemCuowEavgYTP8J5qQ9fQS793MHYFpCY3r\" +let name = Environment.Name.name +include Tezos_raw_protocol_011_PtHangzH +include Tezos_raw_protocol_011_PtHangzH.Main +"))) + +(library + (name tezos_protocol_environment_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-protocol-011-PtHangzH.environment) + (library_flags (:standard -linkall)) + (libraries tezos-protocol-environment) + (modules Environment)) + +(library + (name tezos_raw_protocol_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-protocol-011-PtHangzH.raw) + (libraries tezos_protocol_environment_011_PtHangzH) + (library_flags (:standard -linkall)) + (flags (:standard -nopervasives -nostdlib + -w +a-4-40..42-44-45-48 + -warn-error +a + -open Tezos_protocol_environment_011_PtHangzH__Environment + -open Pervasives + -open Error_monad)) + (modules + Misc + Path_encoding + Storage_description + State_hash + Nonce_hash + Script_expr_hash + Contract_hash + Blinded_public_key_hash + Tez_repr + Period_repr + Time_repr + Fixed_point_repr + Saturation_repr + Gas_limit_repr + Constants_repr + Fitness_repr + Raw_level_repr + Cycle_repr + Level_repr + Seed_repr + Voting_period_repr + Script_string_repr + Script_int_repr + Script_timestamp_repr + Michelson_v1_primitives + Script_repr + Cache_memory_helpers + Contract_repr + Roll_repr + Vote_repr + Block_header_repr + Operation_repr + Manager_repr + Commitment_repr + Parameters_repr + Sapling_repr + Lazy_storage_kind + Receipt_repr + Migration_repr + Raw_context_intf + Raw_context + Storage_costs + Storage_sigs + Storage_functors + Storage + Constants_storage + Level_storage + Nonce_storage + Seed_storage + Roll_storage + Delegate_storage + Sapling_storage + Lazy_storage_diff + Contract_storage + Bootstrap_storage + Fitness_storage + Voting_period_storage + Vote_storage + Commitment_storage + Fees_storage + Liquidity_baking_repr + Liquidity_baking_cpmm + Liquidity_baking_lqt + Liquidity_baking_migration + Init_storage + Sapling_validator + Global_constants_costs + Global_constants_storage + Cache_costs + Alpha_context + Script_tc_errors + Script_typed_ir + Script_typed_ir_size + Script_typed_ir_size_costs + Michelson_v1_gas + Script_ir_annot + Script_list + Script_comparable + Script_set + Script_map + Script_ir_translator + Script_cache + Script_tc_errors_registration + Script_interpreter_defs + Script_interpreter + Baking + Amendment + Apply_results + Apply + Services_registration + Constants_services + Sapling_services + Contract_services + Delegate_services + Voting_services + Alpha_services + Main)) + +(install + (section lib) + (package tezos-protocol-011-PtHangzH) + (files (TEZOS_PROTOCOL as raw/TEZOS_PROTOCOL))) + +(library + (name tezos_protocol_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-protocol-011-PtHangzH) + (libraries + tezos-protocol-environment + tezos-protocol-environment-sigs + tezos_raw_protocol_011_PtHangzH) + (flags -w "+a-4-40..42-44-45-48" + -warn-error "+a" + -nopervasives) + (modules Protocol)) + +(library + (name tezos_protocol_011_PtHangzH_functor) + (instrumentation (backend bisect_ppx)) + (public_name tezos-protocol-functor-011-PtHangzH) + (libraries + tezos-protocol-environment + tezos-protocol-environment-sigs + tezos-protocol-011-PtHangzH.raw) + (flags -w "+a-4-40..42-44-45-48" + -warn-error "+a" + -nopervasives) + (modules Functor)) + +(library + (name tezos_embedded_protocol_011_PtHangzH) + (instrumentation (backend bisect_ppx)) + (public_name tezos-embedded-protocol-011-PtHangzH) + (library_flags (:standard -linkall)) + (libraries tezos-protocol-011-PtHangzH + tezos-protocol-updater + tezos-protocol-environment) + (flags (:standard -w +a-4-40..42-44-45-48 + -warn-error +a)) + (modules Registerer)) + +(rule + (alias runtest_compile_protocol) + (deps + misc.mli misc.ml + path_encoding.mli path_encoding.ml + storage_description.mli storage_description.ml + state_hash.mli state_hash.ml + nonce_hash.mli nonce_hash.ml + script_expr_hash.mli script_expr_hash.ml + contract_hash.mli contract_hash.ml + blinded_public_key_hash.mli blinded_public_key_hash.ml + tez_repr.mli tez_repr.ml + period_repr.mli period_repr.ml + time_repr.mli time_repr.ml + fixed_point_repr.mli fixed_point_repr.ml + saturation_repr.mli saturation_repr.ml + gas_limit_repr.mli gas_limit_repr.ml + constants_repr.mli constants_repr.ml + fitness_repr.mli fitness_repr.ml + raw_level_repr.mli raw_level_repr.ml + cycle_repr.mli cycle_repr.ml + level_repr.mli level_repr.ml + seed_repr.mli seed_repr.ml + voting_period_repr.mli voting_period_repr.ml + script_string_repr.mli script_string_repr.ml + script_int_repr.mli script_int_repr.ml + script_timestamp_repr.mli script_timestamp_repr.ml + michelson_v1_primitives.mli michelson_v1_primitives.ml + script_repr.mli script_repr.ml + cache_memory_helpers.ml + contract_repr.mli contract_repr.ml + roll_repr.mli roll_repr.ml + vote_repr.mli vote_repr.ml + block_header_repr.mli block_header_repr.ml + operation_repr.mli operation_repr.ml + manager_repr.mli manager_repr.ml + commitment_repr.mli commitment_repr.ml + parameters_repr.mli parameters_repr.ml + sapling_repr.ml + lazy_storage_kind.mli lazy_storage_kind.ml + receipt_repr.mli receipt_repr.ml + migration_repr.mli migration_repr.ml + raw_context_intf.ml + raw_context.mli raw_context.ml + storage_costs.mli storage_costs.ml + storage_sigs.ml + storage_functors.mli storage_functors.ml + storage.mli storage.ml + constants_storage.mli constants_storage.ml + level_storage.mli level_storage.ml + nonce_storage.mli nonce_storage.ml + seed_storage.mli seed_storage.ml + roll_storage.mli roll_storage.ml + delegate_storage.mli delegate_storage.ml + sapling_storage.ml + lazy_storage_diff.mli lazy_storage_diff.ml + contract_storage.mli contract_storage.ml + bootstrap_storage.mli bootstrap_storage.ml + fitness_storage.mli fitness_storage.ml + voting_period_storage.mli voting_period_storage.ml + vote_storage.mli vote_storage.ml + commitment_storage.mli commitment_storage.ml + fees_storage.mli fees_storage.ml + liquidity_baking_repr.mli liquidity_baking_repr.ml + liquidity_baking_cpmm.ml + liquidity_baking_lqt.ml + liquidity_baking_migration.mli liquidity_baking_migration.ml + init_storage.mli init_storage.ml + sapling_validator.ml + global_constants_costs.mli global_constants_costs.ml + global_constants_storage.mli global_constants_storage.ml + cache_costs.mli cache_costs.ml + alpha_context.mli alpha_context.ml + script_tc_errors.ml + script_typed_ir.mli script_typed_ir.ml + script_typed_ir_size.mli script_typed_ir_size.ml + script_typed_ir_size_costs.mli script_typed_ir_size_costs.ml + michelson_v1_gas.mli michelson_v1_gas.ml + script_ir_annot.mli script_ir_annot.ml + script_list.mli script_list.ml + script_comparable.mli script_comparable.ml + script_set.mli script_set.ml + script_map.mli script_map.ml + script_ir_translator.mli script_ir_translator.ml + script_cache.mli script_cache.ml + script_tc_errors_registration.mli script_tc_errors_registration.ml + script_interpreter_defs.ml + script_interpreter.mli script_interpreter.ml + baking.mli baking.ml + amendment.mli amendment.ml + apply_results.mli apply_results.ml + apply.mli apply.ml + services_registration.mli services_registration.ml + constants_services.mli constants_services.ml + sapling_services.ml + contract_services.mli contract_services.ml + delegate_services.mli delegate_services.ml + voting_services.mli voting_services.ml + alpha_services.mli alpha_services.ml + main.mli main.ml + (:src_dir TEZOS_PROTOCOL)) + (action (run %{bin:tezos-protocol-compiler} .))) + +(rule + (alias runtest_sandbox) + (deps .tezos_protocol_011_PtHangzH.objs/native/tezos_protocol_011_PtHangzH.cmx) + (action (progn))) + +(rule + (alias runtest) + (package tezos-protocol-011-PtHangzH) + (deps (alias runtest_sandbox)) + (action (progn))) diff --git a/src/proto_011_PtHangzH/lib_protocol/fees_storage.ml b/src/proto_011_PtHangzH/lib_protocol/fees_storage.ml new file mode 100644 index 000000000000..4a0cbf19e9a9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/fees_storage.ml @@ -0,0 +1,139 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += Cannot_pay_storage_fee (* `Temporary *) + +type error += Operation_quota_exceeded (* `Temporary *) + +type error += Storage_limit_too_high (* `Permanent *) + +let () = + let open Data_encoding in + register_error_kind + `Temporary + ~id:"contract.cannot_pay_storage_fee" + ~title:"Cannot pay storage fee" + ~description:"The storage fee is higher than the contract balance" + ~pp:(fun ppf () -> Format.fprintf ppf "Cannot pay storage storage fee") + Data_encoding.empty + (function Cannot_pay_storage_fee -> Some () | _ -> None) + (fun () -> Cannot_pay_storage_fee) ; + register_error_kind + `Temporary + ~id:"storage_exhausted.operation" + ~title:"Storage quota exceeded for the operation" + ~description: + "A script or one of its callee wrote more bytes than the operation said \ + it would" + Data_encoding.empty + (function Operation_quota_exceeded -> Some () | _ -> None) + (fun () -> Operation_quota_exceeded) ; + register_error_kind + `Permanent + ~id:"storage_limit_too_high" + ~title:"Storage limit out of protocol hard bounds" + ~description:"A transaction tried to exceed the hard limit on storage" + empty + (function Storage_limit_too_high -> Some () | _ -> None) + (fun () -> Storage_limit_too_high) + +let origination_burn c = + let origination_size = Constants_storage.origination_size c in + let cost_per_byte = Constants_storage.cost_per_byte c in + (* the origination burn, measured in bytes *) + Tez_repr.(cost_per_byte *? Int64.of_int origination_size) + >|? fun to_be_paid -> + (Raw_context.update_allocated_contracts_count c, to_be_paid) + +let start_counting_storage_fees c = Raw_context.init_storage_space_to_pay c + +(* TODO: https://gitlab.com/tezos/tezos/-/issues/1615 + Refactor other functions in module to use this one. + + This function was added when adding the table + of globals feature. In principle other parts of this module + could be refactored to use this function. *) +let cost_of_bytes c n = + let cost_per_byte = Constants_storage.cost_per_byte c in + Tez_repr.(cost_per_byte *? Z.to_int64 n) + +let record_paid_storage_space c contract = + Contract_storage.used_storage_space c contract >>=? fun size -> + Contract_storage.set_paid_storage_space_and_return_fees_to_pay c contract size + >>=? fun (to_be_paid, c) -> + let c = Raw_context.update_storage_space_to_pay c to_be_paid in + let cost_per_byte = Constants_storage.cost_per_byte c in + Lwt.return + ( Tez_repr.(cost_per_byte *? Z.to_int64 to_be_paid) >|? fun to_burn -> + (c, size, to_be_paid, to_burn) ) + +let record_global_constant_storage_space context size = + (* Following the precedent of big_map, a key in the + global table of constants costs 65 bytes (see + [Lazy_storage_diff.Big_map.bytes_size_for_big_map_key])*) + let cost_of_key = Z.of_int 65 in + let to_be_paid = Z.add size cost_of_key in + (Raw_context.update_storage_space_to_pay context to_be_paid, to_be_paid) + +let record_paid_storage_space_subsidy c contract = + let c = start_counting_storage_fees c in + record_paid_storage_space c contract >>=? fun (c, size, to_be_paid, _) -> + let (c, _, _) = Raw_context.clear_storage_space_to_pay c in + return (c, size, to_be_paid) + +let burn_storage_fees c ~storage_limit ~payer = + let origination_size = Constants_storage.origination_size c in + let (c, storage_space_to_pay, allocated_contracts) = + Raw_context.clear_storage_space_to_pay c + in + let storage_space_for_allocated_contracts = + Z.mul (Z.of_int allocated_contracts) (Z.of_int origination_size) + in + let consumed = + Z.add storage_space_to_pay storage_space_for_allocated_contracts + in + let remaining = Z.sub storage_limit consumed in + if Compare.Z.(remaining < Z.zero) then fail Operation_quota_exceeded + else + let cost_per_byte = Constants_storage.cost_per_byte c in + Tez_repr.(cost_per_byte *? Z.to_int64 consumed) >>?= fun to_burn -> + (* Burning the fees... *) + if Tez_repr.(to_burn = Tez_repr.zero) then + (* If the payer was was deleted by transferring all its balance, and no space was used, + burning zero would fail *) + return c + else + trace + Cannot_pay_storage_fee + ( Contract_storage.must_exist c payer >>=? fun () -> + Contract_storage.spend c payer to_burn ) + +let check_storage_limit c ~storage_limit = + if + Compare.Z.( + storage_limit > (Raw_context.constants c).hard_storage_limit_per_operation) + || Compare.Z.(storage_limit < Z.zero) + then error Storage_limit_too_high + else ok_unit diff --git a/src/proto_011_PtHangzH/lib_protocol/fees_storage.mli b/src/proto_011_PtHangzH/lib_protocol/fees_storage.mli new file mode 100644 index 000000000000..a2d61b0083ca --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/fees_storage.mli @@ -0,0 +1,67 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += Cannot_pay_storage_fee (* `Temporary *) + +type error += Operation_quota_exceeded (* `Temporary *) + +type error += Storage_limit_too_high (* `Permanent *) + +(** Does not burn, only adds the burn to storage space to be paid *) +val origination_burn : Raw_context.t -> (Raw_context.t * Tez_repr.t) tzresult + +(** [cost_of_bytes ctxt n] calculates the cost of storing n + bytes in the key-value store. *) +val cost_of_bytes : Raw_context.t -> Z.t -> Tez_repr.t tzresult + +(** The returned Tez quantity is for logging purpose only *) +val record_paid_storage_space : + Raw_context.t -> + Contract_repr.t -> + (Raw_context.t * Z.t * Z.t * Tez_repr.t) tzresult Lwt.t + +(** [record_global_constant_storage_space ctxt size] records + paid storage space for registering a new global constant. + Cost is in bytes + 65 additional bytes for the key + hash of the expression. Returns new context and the cost. +*) +val record_global_constant_storage_space : + Raw_context.t -> Z.t -> Raw_context.t * Z.t + +(** Record paid storage space for contract without burn. + For use only in subsidies. + Will fail if storage_space_to_pay has been initialized.*) +val record_paid_storage_space_subsidy : + Raw_context.t -> Contract_repr.t -> (Raw_context.t * Z.t * Z.t) tzresult Lwt.t + +val check_storage_limit : Raw_context.t -> storage_limit:Z.t -> unit tzresult + +val start_counting_storage_fees : Raw_context.t -> Raw_context.t + +val burn_storage_fees : + Raw_context.t -> + storage_limit:Z.t -> + payer:Contract_repr.t -> + Raw_context.t tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/fitness_repr.ml b/src/proto_011_PtHangzH/lib_protocol/fitness_repr.ml new file mode 100644 index 000000000000..36b4bd2ce847 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/fitness_repr.ml @@ -0,0 +1,61 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += Invalid_fitness (* `Permanent *) + +let () = + register_error_kind + `Permanent + ~id:"invalid_fitness" + ~title:"Invalid fitness" + ~description:"Fitness representation should be exactly 8 bytes long." + ~pp:(fun ppf () -> Format.fprintf ppf "Invalid fitness") + Data_encoding.empty + (function Invalid_fitness -> Some () | _ -> None) + (fun () -> Invalid_fitness) + +let int64_to_bytes i = + let b = Bytes.make 8 '0' in + TzEndian.set_int64 b 0 i ; + b + +let int64_of_bytes b = + if Compare.Int.(Bytes.length b <> 8) then error Invalid_fitness + else ok (TzEndian.get_int64 b 0) + +let from_int64 fitness = + [Bytes.of_string Constants_repr.version_number; int64_to_bytes fitness] + +let to_int64 = function + | [version; fitness] + when Compare.String.( + Bytes.to_string version = Constants_repr.version_number) -> + int64_of_bytes fitness + | [version; _fitness (* ignored since higher version takes priority *)] + when Compare.String.( + Bytes.to_string version = Constants_repr.version_number_004) -> + ok 0L + | [] -> ok 0L + | _ -> error Invalid_fitness diff --git a/src/proto_011_PtHangzH/lib_protocol/fitness_repr.mli b/src/proto_011_PtHangzH/lib_protocol/fitness_repr.mli new file mode 100644 index 000000000000..1636fae707e9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/fitness_repr.mli @@ -0,0 +1,29 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val from_int64 : int64 -> bytes list + +val to_int64 : bytes list -> (int64, error trace) result diff --git a/src/proto_011_PtHangzH/lib_protocol/fitness_storage.ml b/src/proto_011_PtHangzH/lib_protocol/fitness_storage.ml new file mode 100644 index 000000000000..26d1478fc1fd --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/fitness_storage.ml @@ -0,0 +1,30 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let current = Raw_context.current_fitness + +let increase ctxt = + let fitness = current ctxt in + Raw_context.set_current_fitness ctxt (Int64.succ fitness) diff --git a/src/proto_011_PtHangzH/lib_protocol/fitness_storage.mli b/src/proto_011_PtHangzH/lib_protocol/fitness_storage.mli new file mode 100644 index 000000000000..c9844d2c9b1f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/fitness_storage.mli @@ -0,0 +1,29 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val current : Raw_context.t -> Int64.t + +val increase : Raw_context.t -> Raw_context.t diff --git a/src/proto_011_PtHangzH/lib_protocol/fixed_point_repr.ml b/src/proto_011_PtHangzH/lib_protocol/fixed_point_repr.ml new file mode 100644 index 000000000000..531fd045f453 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/fixed_point_repr.ml @@ -0,0 +1,94 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type fp_tag (* Tag for fixed point computations *) + +type integral_tag (* Tag for integral computations *) + +module type Safe = sig + type 'a t [@@coq_phantom] + + type fp = fp_tag t + + type integral = integral_tag t + + val integral_exn : Z.t -> integral + + val integral_of_int_exn : int -> integral + + val integral_to_z : integral -> Z.t + + val zero : 'a t + + val add : 'a t -> 'a t -> 'a t + + val sub : 'a t -> 'a t -> 'a t + + val ceil : fp -> integral + + val floor : fp -> integral + + val fp : 'a t -> fp + + val ( = ) : 'a t -> 'b t -> bool + + val ( <> ) : 'a t -> 'b t -> bool + + val ( < ) : 'a t -> 'b t -> bool + + val ( <= ) : 'a t -> 'b t -> bool + + val ( >= ) : 'a t -> 'b t -> bool + + val ( > ) : 'a t -> 'b t -> bool + + val compare : 'a t -> 'b t -> int + + val equal : 'a t -> 'b t -> bool + + val max : 'a t -> 'a t -> 'a t + + val min : 'a t -> 'a t -> 'a t + + val pp : Format.formatter -> 'a t -> unit + + val pp_integral : Format.formatter -> integral -> unit + + val n_fp_encoding : fp Data_encoding.t + + val n_integral_encoding : integral Data_encoding.t + + val z_fp_encoding : fp Data_encoding.t + + val z_integral_encoding : integral Data_encoding.t +end + +module type Full = sig + type 'a t [@@coq_phantom] + + include Safe with type 'a t := 'a t + + val unsafe_fp : Z.t -> fp +end diff --git a/src/proto_011_PtHangzH/lib_protocol/fixed_point_repr.mli b/src/proto_011_PtHangzH/lib_protocol/fixed_point_repr.mli new file mode 100644 index 000000000000..a9dee73a6f6e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/fixed_point_repr.mli @@ -0,0 +1,105 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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 defines a standard signature for modules providing fixed-point + arithmetic. *) + +type fp_tag (* Tag for fixed point computations *) + +type integral_tag (* Tag for integral computations *) + +(** A signature for modules implementing a fixed-point arithmetic. + + Fixed-point types come in two flavours: + - integral (marked with [integral_tag]), behaving like integers; + - fp (marked with [fp_tag]), allowing for fractions. + + Such numbers represent standard arithmetic, rounding (converting fp + flavour to integral one) and comparisons (which can work across flavours). *) +module type Safe = sig + type 'a t [@@coq_phantom] + + type fp = fp_tag t + + type integral = integral_tag t + + val integral_exn : Z.t -> integral + + val integral_of_int_exn : int -> integral + + val integral_to_z : integral -> Z.t + + val zero : 'a t + + val add : 'a t -> 'a t -> 'a t + + val sub : 'a t -> 'a t -> 'a t + + val ceil : fp -> integral + + val floor : fp -> integral + + val fp : 'a t -> fp + + val ( = ) : 'a t -> 'b t -> bool + + val ( <> ) : 'a t -> 'b t -> bool + + val ( < ) : 'a t -> 'b t -> bool + + val ( <= ) : 'a t -> 'b t -> bool + + val ( >= ) : 'a t -> 'b t -> bool + + val ( > ) : 'a t -> 'b t -> bool + + val compare : 'a t -> 'b t -> int + + val equal : 'a t -> 'b t -> bool + + val max : 'a t -> 'a t -> 'a t + + val min : 'a t -> 'a t -> 'a t + + val pp : Format.formatter -> 'a t -> unit + + val pp_integral : Format.formatter -> integral -> unit + + val n_fp_encoding : fp Data_encoding.t + + val n_integral_encoding : integral Data_encoding.t + + val z_fp_encoding : fp Data_encoding.t + + val z_integral_encoding : integral Data_encoding.t +end + +module type Full = sig + type 'a t [@@coq_phantom] + + include Safe with type 'a t := 'a t + + val unsafe_fp : Z.t -> fp +end diff --git a/src/proto_011_PtHangzH/lib_protocol/gas_limit_repr.ml b/src/proto_011_PtHangzH/lib_protocol/gas_limit_repr.ml new file mode 100644 index 000000000000..b613533863e7 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/gas_limit_repr.ml @@ -0,0 +1,210 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let decimals = 3 + +type fp_tag + +type integral_tag + +module S = Saturation_repr + +(* 1 gas unit *) +let scaling_factor = S.mul_safe_of_int_exn 1000 + +module Arith = struct + type 'a t = S.may_saturate S.t + + type fp = fp_tag t + + type integral = integral_tag t + + let scaling_factor = scaling_factor + + let sub = S.sub + + let add = S.add + + let zero = S.zero + + let min = S.min + + let max = S.max + + let compare = S.compare + + let ( < ) = S.( < ) + + let ( <> ) = S.( <> ) + + let ( > ) = S.( > ) + + let ( <= ) = S.( <= ) + + let ( >= ) = S.( >= ) + + let ( = ) = S.( = ) + + let equal = S.equal + + let of_int_opt = S.of_int_opt + + let fatally_saturated_int i = + failwith (string_of_int i ^ " should not be saturated.") + + let fatally_saturated_z z = + failwith (Z.to_string z ^ " should not be saturated.") + + let integral_of_int_exn i = + S.( + match of_int_opt i with + | None -> fatally_saturated_int i + | Some i' -> + let r = scale_fast scaling_factor i' in + if r = saturated then fatally_saturated_int i else r) + + let integral_exn z = + match Z.to_int z with + | i -> integral_of_int_exn i + | exception Z.Overflow -> fatally_saturated_z z + + let integral_to_z (i : integral) : Z.t = S.(to_z (ediv i scaling_factor)) + + let ceil x = + let r = S.erem x scaling_factor in + if r = zero then x else add x (sub scaling_factor r) + + let floor x = sub x (S.erem x scaling_factor) + + let fp x = x + + let pp fmtr fp = + let q = S.(ediv fp scaling_factor |> to_int) in + let r = S.(erem fp scaling_factor |> to_int) in + if Compare.Int.(r = 0) then Format.fprintf fmtr "%d" q + else Format.fprintf fmtr "%d.%0*d" q decimals r + + let pp_integral = pp + + let n_fp_encoding : fp Data_encoding.t = S.n_encoding + + let z_fp_encoding : fp Data_encoding.t = S.z_encoding + + let n_integral_encoding : integral Data_encoding.t = + Data_encoding.conv integral_to_z integral_exn Data_encoding.n + + let z_integral_encoding : integral Data_encoding.t = + Data_encoding.conv integral_to_z integral_exn Data_encoding.z + + let unsafe_fp x = + match of_int_opt (Z.to_int x) with + | Some int -> int + | None -> fatally_saturated_z x + + let sub_opt = S.sub_opt +end + +type t = Unaccounted | Limited of {remaining : Arith.fp} + +type cost = S.may_saturate S.t + +let encoding = + let open Data_encoding in + union + [ + case + (Tag 0) + ~title:"Limited" + Arith.z_fp_encoding + (function Limited {remaining} -> Some remaining | _ -> None) + (fun remaining -> Limited {remaining}); + case + (Tag 1) + ~title:"Unaccounted" + (constant "unaccounted") + (function Unaccounted -> Some () | _ -> None) + (fun () -> Unaccounted); + ] + +let pp ppf = function + | Unaccounted -> Format.fprintf ppf "unaccounted" + | Limited {remaining} -> + Format.fprintf ppf "%a units remaining" Arith.pp remaining + +let cost_encoding = S.z_encoding + +let pp_cost fmt z = S.pp fmt z + +(* 2 units of gas *) +let allocation_weight = + S.(mul_fast scaling_factor (S.mul_safe_of_int_exn 2)) |> S.mul_safe_exn + +let step_weight = scaling_factor + +(* 100 units of gas *) +let read_base_weight = + S.(mul_fast scaling_factor (S.mul_safe_of_int_exn 100)) |> S.mul_safe_exn + +(* 160 units of gas *) +let write_base_weight = + S.(mul_fast scaling_factor (S.mul_safe_of_int_exn 160)) |> S.mul_safe_exn + +(* 10 units of gas *) +let byte_read_weight = + S.(mul_fast scaling_factor (S.mul_safe_of_int_exn 10)) |> S.mul_safe_exn + +(* 15 units of gas *) +let byte_written_weight = + S.(mul_fast scaling_factor (S.mul_safe_of_int_exn 15)) |> S.mul_safe_exn + +let cost_to_milligas (cost : cost) : Arith.fp = cost + +let raw_consume gas_counter cost = + let gas = cost_to_milligas cost in + Arith.sub_opt gas_counter gas + +let alloc_cost n = + S.scale_fast allocation_weight S.(add n (S.mul_safe_of_int_exn 1)) + +let alloc_bytes_cost n = alloc_cost (S.safe_int ((n + 7) / 8)) + +let atomic_step_cost : 'a S.t -> cost = S.may_saturate + +let step_cost n = S.scale_fast step_weight n + +let free = S.zero + +let read_bytes_cost n = + S.add read_base_weight (S.scale_fast byte_read_weight (S.safe_int n)) + +let write_bytes_cost n = + S.add write_base_weight (S.scale_fast byte_written_weight (S.safe_int n)) + +let ( +@ ) x y = S.add x y + +let ( *@ ) x y = S.mul x y + +let alloc_mbytes_cost n = + alloc_cost (S.mul_safe_of_int_exn 12) +@ alloc_bytes_cost n diff --git a/src/proto_011_PtHangzH/lib_protocol/gas_limit_repr.mli b/src/proto_011_PtHangzH/lib_protocol/gas_limit_repr.mli new file mode 100644 index 000000000000..3b87007d6ee7 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/gas_limit_repr.mli @@ -0,0 +1,110 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Internal representation of the gas limit available to the node baking a new + block. It should be proportional to the time and energy required to perform a + computation. + + This protects the bakers from performing exceedingly costly computations + while baking and also allows them to select cheaper-to-compute operations to + include in their blocks, as their reward for baking a block is not directly + related to the resources consumed by the machine performing the operation. + + It can be [Unaccounted] (unlimited) or [Limited] to some fixed-point value + (see [Fixed_point_repr] for the details). The value is represented with 3 + decimal places of precision. + + All computations on gas are performed in saturation arithmetic (see + [Saturation_repr]) bounded between [0] and [2 ^ 62 - 1]*) + +module Arith : + Fixed_point_repr.Full + with type 'a t = Saturation_repr.may_saturate Saturation_repr.t +[@@coq_plain_module] + +type t = Unaccounted | Limited of {remaining : Arith.fp} + +val encoding : t Data_encoding.encoding + +val pp : Format.formatter -> t -> unit + +(** Represents a gas cost of an operation. The gas model is constructed such + that the cost of each operation is roughly proportional to the time required + to perform the operation. If the gas cost of an operation exceeds the + available limit, such an operation is rejected. This is especially meant to + protect bakers against DoS attacks. *) +type cost = Saturation_repr.may_saturate Saturation_repr.t + +val cost_encoding : cost Data_encoding.encoding + +val pp_cost : Format.formatter -> cost -> unit + +(** Subtracts the cost from the current limit. Returns [None] if the limit + would fall below [0]. *) +val raw_consume : Arith.fp -> cost -> Arith.fp option + +(** The cost of free operation is [0]. *) +val free : cost + +(** [atomic_step_cost x] corresponds to [x] milliunit of gas. *) +val atomic_step_cost : _ Saturation_repr.t -> cost + +(** [step_cost x] corresponds to [x] units of gas. *) +val step_cost : _ Saturation_repr.t -> cost + +(** Cost of allocating qwords of storage. + + [alloc_cost n] estimates the cost of allocating [n] qwords of storage. *) +val alloc_cost : _ Saturation_repr.t -> cost + +(** Cost of allocating bytes in the storage. + + [alloc_bytes_cost b] estimates the cost of allocating [b] bytes of + storage. *) +val alloc_bytes_cost : int -> cost + +(** Cost of allocating bytes in the storage. + + [alloc_mbytes_cost b] estimates the cost of allocating [b] bytes of + storage and the cost of a header to describe these bytes. *) +val alloc_mbytes_cost : int -> cost + +(** Cost of reading the storage. + + [read_bytes_const n] estimates the cost of reading [n] bytes of storage. *) +val read_bytes_cost : int -> cost + +(** Cost of writing to storage. + + [write_bytes_const n] estimates the cost of writing [n] bytes to the + storage. *) +val write_bytes_cost : int -> cost + +(** Multiply a cost by a factor. Both arguments are saturated arithmetic values, + so no negative numbers are involved. *) +val ( *@ ) : _ Saturation_repr.t -> cost -> cost + +(** Add two costs together. *) +val ( +@ ) : cost -> cost -> cost diff --git a/src/proto_011_PtHangzH/lib_protocol/global_constants_costs.ml b/src/proto_011_PtHangzH/lib_protocol/global_constants_costs.ml new file mode 100644 index 000000000000..61bbab15e6b3 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/global_constants_costs.ml @@ -0,0 +1,47 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module S = Saturation_repr + +let log2 x = S.safe_int (1 + S.numbits x) + +let ( + ) = S.add + +let ( lsr ) = S.shift_right + +(* Approximating 200 + 1.266960 * number of bytes *) +let expr_to_address_in_context_cost bytes = + let v0 = Bytes.length bytes |> S.safe_int in + S.safe_int 200 + (v0 + (v0 lsr 2)) |> Gas_limit_repr.atomic_step_cost + +let expand_constants_branch_cost = + Gas_limit_repr.atomic_step_cost @@ S.safe_int 4095 + +(* Approximating 100 + 4.639474 * n*log(n) *) +let expand_no_constants_branch_cost node = + let v0 = Script_repr.micheline_nodes node |> S.safe_int in + let v0 = S.mul v0 (log2 v0) in + S.safe_int 100 + S.mul (S.safe_int 4) v0 + (v0 lsr 1) + (v0 lsr 3) + |> Gas_limit_repr.atomic_step_cost diff --git a/src/proto_011_PtHangzH/lib_protocol/global_constants_costs.mli b/src/proto_011_PtHangzH/lib_protocol/global_constants_costs.mli new file mode 100644 index 000000000000..9f24e8b34d39 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/global_constants_costs.mli @@ -0,0 +1,34 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Costs function for the global table of constants. *) + +(** Cost of calling [Global_constats_storage.expr_to_address_in_context]. *) +val expr_to_address_in_context_cost : bytes -> Gas_limit_repr.cost + +(** Step costs for [Global_constats_storage.expand_node]. *) +val expand_constants_branch_cost : Gas_limit_repr.cost + +val expand_no_constants_branch_cost : Script_repr.node -> Gas_limit_repr.cost diff --git a/src/proto_011_PtHangzH/lib_protocol/global_constants_storage.ml b/src/proto_011_PtHangzH/lib_protocol/global_constants_storage.ml new file mode 100644 index 000000000000..0db6ec9a48cc --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/global_constants_storage.ml @@ -0,0 +1,270 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) +open Micheline +open Michelson_v1_primitives + +(* + + See [expand] for an example. + + TODO: https://gitlab.com/tezos/tezos/-/issues/1609 + Move function to lib_micheline. + + On our next opportunity to update the environment, we + should move this function to lib_micheline. + +*) +let bottom_up_fold_cps initial_accumulator node initial_k f = + let rec traverse_node accu node k = + f accu node @@ fun accu node -> + match node with + | String _ | Int _ | Bytes _ -> k accu node + | Prim (loc, prim, args, annot) -> + (traverse_nodes [@ocaml.tailcall]) accu args @@ fun accu args -> + f accu (Prim (loc, prim, args, annot)) k + | Seq (loc, elts) -> + (traverse_nodes [@ocaml.tailcall]) accu elts @@ fun accu elts -> + f accu (Seq (loc, elts)) k + and traverse_nodes accu nodes k = + match nodes with + | [] -> k accu [] + | node :: nodes -> + (traverse_node [@ocaml.tailcall]) accu node @@ fun accu node -> + (traverse_nodes [@ocaml.tailcall]) accu nodes @@ fun accu nodes -> + k accu (node :: nodes) + in + traverse_node initial_accumulator node initial_k + [@@coq_axiom_with_reason "local mutually recursive definition not handled"] + +module Gas_costs = Global_constants_costs +module Expr_hash_map = Map.Make (Script_expr_hash) + +type error += Expression_too_deep + +type error += Expression_already_registered + +type error += Badly_formed_constant_expression + +type error += Nonexistent_global + +type error += Expression_too_large + +let () = + let description = + "Attempted to register an expression that, after fully expanding all \ + referenced global constants, would result in too many levels of nesting." + in + register_error_kind + `Branch + ~id:"Expression_too_deep" + ~title:"Expression too deep" + ~description + ~pp:(fun ppf () -> Format.fprintf ppf "%s" description) + Data_encoding.empty + (function Expression_too_deep -> Some () | _ -> None) + (fun () -> Expression_too_deep) ; + let description = + "Attempted to register an expression as global constant that has already \ + been registered." + in + register_error_kind + `Branch + ~id:"Expression_already_registered" + ~title:"Expression already registered" + ~description + ~pp:(fun ppf () -> Format.fprintf ppf "%s" description) + Data_encoding.empty + (function Expression_already_registered -> Some () | _ -> None) + (fun () -> Expression_already_registered) ; + let description = + "Found a badly formed constant expression. The 'constant' primitive must \ + always be followed by a string of the hash of the expression it points \ + to." + in + register_error_kind + `Branch + ~id:"Badly_formed_constant_expression" + ~title:"Badly formed constant expression" + ~description + ~pp:(fun ppf () -> Format.fprintf ppf "%s" description) + Data_encoding.empty + (function Badly_formed_constant_expression -> Some () | _ -> None) + (fun () -> Badly_formed_constant_expression) ; + let description = + "No registered global was found at the given hash in storage." + in + register_error_kind + `Branch + ~id:"Nonexistent_global" + ~title:"Tried to look up nonexistent global" + ~description + ~pp:(fun ppf () -> Format.fprintf ppf "%s" description) + Data_encoding.empty + (function Nonexistent_global -> Some () | _ -> None) + (fun () -> Nonexistent_global) ; + let description = + "Encountered an expression that, after expanding all constants, is larger \ + than the expression size limit." + in + register_error_kind + `Branch + ~id:"Expression_too_large" + ~title:"Expression too large" + ~description + ~pp:(fun ppf () -> Format.fprintf ppf "%s" description) + Data_encoding.empty + (function Expression_too_large -> Some () | _ -> None) + (fun () -> Expression_too_large) + +let get context hash = + Storage.Global_constants.Map.find context hash >>=? fun (context, value) -> + match value with + | None -> fail Nonexistent_global + | Some value -> return (context, value) + +let expr_to_address_in_context context expr = + let lexpr = Script_repr.lazy_expr expr in + Raw_context.consume_gas context @@ Script_repr.force_bytes_cost lexpr + >>? fun context -> + Script_repr.force_bytes lexpr >>? fun b -> + Raw_context.consume_gas context @@ Gas_costs.expr_to_address_in_context_cost b + >|? fun context -> (context, Script_expr_hash.hash_bytes [b]) + +let node_too_large node = + let node_size = Script_repr.Micheline_size.of_node node in + let nodes = Saturation_repr.to_int node_size.nodes in + let string_bytes = Saturation_repr.to_int node_size.string_bytes in + let z_bytes = Saturation_repr.to_int node_size.z_bytes in + Compare.Int.( + nodes > Constants_repr.max_micheline_node_count + || string_bytes + z_bytes > Constants_repr.max_micheline_bytes_limit) + +let expand_node context node = + (* We charge for traversing the top-level node at the beginning. + Inside the loop, we charge for traversing each new constant + that gets expanded. *) + Raw_context.consume_gas + context + (Gas_costs.expand_no_constants_branch_cost node) + >>?= fun context -> + bottom_up_fold_cps + (* We carry a Boolean representing whether we + had to do any expansions or not. *) + (context, Expr_hash_map.empty, false) + node + (fun (context, _, did_expansion) node -> + return (context, node, did_expansion)) + (fun (context, map, did_expansion) node k -> + match node with + | Prim (_, H_constant, args, annot) -> ( + (* Charge for validating the b58check hash. *) + Raw_context.consume_gas context Gas_costs.expand_constants_branch_cost + >>?= fun context -> + match (args, annot) with + (* A constant Prim should always have a single String argument, + being a properly formatted hash. *) + | ([String (_, address)], []) -> ( + match Script_expr_hash.of_b58check_opt address with + | None -> fail Badly_formed_constant_expression + | Some hash -> ( + match Expr_hash_map.find hash map with + | Some node -> + (* Charge traversing the newly retrieved node *) + Raw_context.consume_gas + context + (Gas_costs.expand_no_constants_branch_cost node) + >>?= fun context -> k (context, map, true) node + | None -> + get context hash >>=? fun (context, expr) -> + (* Charge traversing the newly retrieved node *) + let node = root expr in + Raw_context.consume_gas + context + (Gas_costs.expand_no_constants_branch_cost node) + >>?= fun context -> + k (context, Expr_hash_map.add hash node map, true) node)) + | _ -> fail Badly_formed_constant_expression) + | Int _ | String _ | Bytes _ | Prim _ | Seq _ -> + k (context, map, did_expansion) node) + >>=? fun (context, node, did_expansion) -> + if did_expansion then + (* Gas charged during expansion is at least proportional to the size of the + resulting node so the execution time of [node_too_large] is already + covered. *) + if node_too_large node then fail Expression_too_large + else return (context, node) + else return (context, node) + +let expand context expr = + expand_node context (root expr) >|=? fun (context, node) -> + (context, strip_locations node) + +(** Computes the maximum depth of a Micheline node. Fails + with [Expression_too_deep] if greater than + [max_allowed_global_constant_depth].*) +let check_depth node = + let rec advance node depth k = + if Compare.Int.(depth > Constants_repr.max_allowed_global_constant_depth) + then error Expression_too_deep + else + match node with + | Int _ | String _ | Bytes _ | Prim (_, _, [], _) | Seq (_, []) -> + (k [@tailcall]) (depth + 1) + | Prim (_, _, hd :: tl, _) | Seq (_, hd :: tl) -> + (advance [@tailcall]) hd (depth + 1) (fun dhd -> + (advance [@tailcall]) + (* Because [depth] doesn't care about the content + of the expression, we can safely throw away information + about primitives and replace them with the [Seq] constructor.*) + (Seq (-1, tl)) + depth + (fun dtl -> (k [@tailcall]) (Compare.Int.max dhd dtl))) + in + advance node 0 (fun x -> Ok x) + +let register context value = + (* To calculate the total depth, we first expand all constants + in the expression. This may fail with [Expression_too_large]. + + Though the stored expression is the unexpanded version. + *) + expand_node context (root value) >>=? fun (context, node) -> + (* We do not need to carbonate [check_depth]. [expand_node] and + [Storage.Global_constants.Map.init] are already carbonated + with gas at least proportional to the size of the expanded node + and the computation cost of [check_depth] is of the same order. *) + check_depth node >>?= fun (_depth : int) -> + expr_to_address_in_context context value >>?= fun (context, key) -> + trace Expression_already_registered + @@ Storage.Global_constants.Map.init context key value + >|=? fun (context, size) -> (context, key, Z.of_int size) + +module Internal_for_tests = struct + let node_too_large = node_too_large + + let bottom_up_fold_cps = bottom_up_fold_cps + + let expr_to_address_in_context = expr_to_address_in_context +end diff --git a/src/proto_011_PtHangzH/lib_protocol/global_constants_storage.mli b/src/proto_011_PtHangzH/lib_protocol/global_constants_storage.mli new file mode 100644 index 000000000000..6c4116c15568 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/global_constants_storage.mli @@ -0,0 +1,150 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* *) +(* 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 represents access to a global table of constant + Micheline values. Users may register a Micheline value in the + table, paying the cost of storage. Once stored, contracts source code may + reference this value by its hash. + + Note: the table does not typecheck the values stored in it. + Instead, any place that uses constants must first call [expand] + before typechecking the code. This decision was made to make it as + easy as possible for users to register values to the table, and also + to allow maximum flexibility in the use of constants for different + parts of a Michelson script (code, types, data, etc.). *) + +type error += Expression_too_deep + +type error += Expression_already_registered + +(** A constant is the prim of the literal characters "constant". + A constant must have a single argument, being a string with a + well formed hash of a Micheline expression (i.e generated by + [Script_expr_hash.to_b58check]). *) +type error += Badly_formed_constant_expression + +type error += Nonexistent_global + +(** [get context hash] retrieves the Micheline value with the given hash. + + Fails with [Nonexistent_global] if no value is found at the given hash. + + Fails with [Storage_error Corrupted_data] if the deserialisation fails. + + Consumes [Gas_repr.read_bytes_cost ]. *) +val get : + Raw_context.t -> + Script_expr_hash.t -> + (Raw_context.t * Script_repr.expr) tzresult Lwt.t + +(** [register context value] registers a constant in the global table of constants, + returning the hash and storage bytes consumed. + + Does not type-check the Micheline code being registered, allow potentially + ill-typed Michelson values to be stored in the table (see note at top of module). + + The constant is stored unexpanded, but it is temporarily expanded at registration + time only to check the expanded version respects the following limits. + This also ensures there are no cyclic dependencies between constants. + + Fails with [Expression_too_deep] if, after fully expanding all constants, + the expression would have a depth greater than [Constant_repr.max_allowed_global_constant_depth]. + + Fails with [Badly_formed_constant_expression] if constants are not + well-formed (see declaration of [Badly_formed_constant_expression]) or with + [Nonexistent_global] if a referenced constant does not exist in the table. + + Consumes serialization cost. + Consumes [Gas_repr.write_bytes_cost ] where size is the number + of bytes in the binary serialization provided by [Script_repr.expr_encoding]. *) +val register : + Raw_context.t -> + Script_repr.expr -> + (Raw_context.t * Script_expr_hash.t * Z.t) tzresult Lwt.t + +(** [expand context expr] replaces every constant in the + given Michelson expression with its value stored in the global table. + + The expansion is applied recursively so that the returned expression + contains no constant. + + Fails with [Badly_formed_constant_expression] if constants are not + well-formed (see declaration of [Badly_formed_constant_expression]) or + with [Nonexistent_global] if a referenced constant does not exist in + the table. *) +val expand : + Raw_context.t -> + Script_repr.expr -> + (Raw_context.t * Script_repr.expr) tzresult Lwt.t + +module Internal_for_tests : sig + (** [node_too_large node] returns true if: + - The number of sub-nodes in the [node] + exceeds [Global_constants_storage.node_size_limit]. + - The sum of the bytes in String, Int, + and Bytes sub-nodes of [node] exceeds + [Global_constants_storage.bytes_size_limit]. + + Otherwise returns false. *) + val node_too_large : Script_repr.node -> bool + + (** [bottom_up_fold_cps initial_accumulator node initial_k f] + folds [node] and all its sub-nodes if any, starting from + [initial_accumulator], using an initial continuation [initial_k]. + At each node, [f] is called to transform the continuation [k] into + the next one. This explicit manipulation of the continuation + is typically useful to short-circuit. + + Notice that a common source of bug is to forget to properly call the + continuation in `f`. + + See [Global_constants_storage.expand] for an example. + + TODO: https://gitlab.com/tezos/tezos/-/issues/1609 + Move function to lib_micheline. + + On our next opportunity to update the environment, we + should move this function to lib_micheline. + *) + val bottom_up_fold_cps : + 'accumulator -> + Script_repr.node -> + ('accumulator -> Script_repr.node -> 'return) -> + ('accumulator -> + Script_repr.node -> + ('accumulator -> Script_repr.node -> 'return) -> + 'return) -> + 'return + + (* [expr_to_address_in_context context expr] converts [expr] + into a unique hash represented by a [Script_expr_hash.t]. + + Consumes gas corresponding to the cost of converting [expr] + to bytes and hashing the bytes. *) + val expr_to_address_in_context : + Raw_context.t -> + Script_repr.expr -> + (Raw_context.t * Script_expr_hash.t) tzresult +end diff --git a/src/proto_011_PtHangzH/lib_protocol/init_storage.ml b/src/proto_011_PtHangzH/lib_protocol/init_storage.ml new file mode 100644 index 000000000000..78dd830f91bb --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/init_storage.ml @@ -0,0 +1,311 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* Copyright (c) 2021 DaiLambda, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let log fmt = Logging.log Notice fmt + +(* Remove me after protocol H *) +module Flatten_storage_for_H = struct + (* /tree_abs_key/key/*/*/*/*/* + => /tree_abs_key/key/rename( */*/*/*/* ) + *) + let flatten ~tree ~key ~depth ~rename ~init = + Raw_context.Tree.fold + tree + key + ~depth:(`Eq depth) + ~init + ~f:(fun old_key tree dst_tree -> + let new_key = rename old_key in + Raw_context.Tree.add_tree dst_tree new_key tree) + >>= fun dst_tree -> + (* rm -rf $index_key + mv $tmp_index_key $index_key *) + Raw_context.Tree.add_tree tree key dst_tree + + (* /abs_key/*(depth')/mid_key/*(depth) + => /abs_key/*(depth')/mid_key/rename( *(depth) ) + *) + let fold_flatten ctxt abs_key depth' mid_key ~depth ~rename = + Raw_context.fold + ~depth:(`Eq depth') + ctxt + abs_key + ~init:ctxt + ~f:(fun key tree ctxt -> + (* tree at /abs_key/*(depth') *) + flatten + ~tree + ~key:mid_key + ~depth + ~rename + ~init:(Raw_context.Tree.empty ctxt) + >>= fun tree -> Raw_context.add_tree ctxt (abs_key @ key) tree) + + let flatten_storage ctxt = + log + "flattening the context storage: this operation may take several minutes" ; + let rec drop n xs = + match (n, xs) with + | (0, _) -> xs + | (_, []) -> assert false + | (_, _ :: xs) -> drop (n - 1) xs + in + let rename_blake2b = function + | n1 :: n2 :: n3 :: n4 :: n5 :: n6 :: rest -> + String.concat "" [n1; n2; n3; n4; n5; n6] :: rest + | _ -> assert false + in + let rename_public_key_hash = function + | (("ed25519" | "secp256k1" | "p256") as k) + :: n1 :: n2 :: n3 :: n4 :: n5 :: n6 :: rest -> + k :: String.concat "" [n1; n2; n3; n4; n5; n6] :: rest + | _ -> assert false + in + (* /contracts/index/xx/xx/xx/xx/xx/xx/yyyyyyyyyy + => /contracts/index/yyyyyyyyyy + *) + fold_flatten ctxt ["contracts"; "index"] 0 [] ~depth:7 ~rename:(drop 6) + >>= fun ctxt -> + (* *) + (* /contracts/index/yyyyyyyyyy/delegated/xx/xx/xx/xx/xx/xx/zzzzzzzzzz + => /contracts/index/yyyyyyyyyy/delegated/zzzzzzzzzz + *) + fold_flatten + ctxt + ["contracts"; "index"] + 1 + ["delegated"] + ~depth:7 + ~rename:(drop 6) + >>= fun ctxt -> + (* *) + (* /big_maps/index/xx/xx/xx/xx/xx/xx/n + => /big_maps/index/n + *) + fold_flatten ctxt ["big_maps"; "index"] 0 [] ~depth:7 ~rename:(drop 6) + >>= fun ctxt -> + (* *) + (* /big_maps/index/n/contents/yy/yy/yy/yy/yy/yyyyyyyy + => /big_maps/index/n/contents/yyyyyyyyyyyyyyyyyy + *) + fold_flatten + ctxt + ["big_maps"; "index"] + 1 + ["contents"] + ~depth:6 + ~rename:rename_blake2b + >>= fun ctxt -> + (* *) + (* /rolls/index/x/y/n + => /rolls/index/n + *) + fold_flatten ctxt ["rolls"; "index"] 0 [] ~depth:3 ~rename:(drop 2) + >>= fun ctxt -> + (* *) + (* /rolls/owner/current/x/y/n + => /rolls/owner/current/n + *) + fold_flatten + ctxt + ["rolls"; "owner"; "current"] + 0 + [] + ~depth:3 + ~rename:(drop 2) + >>= fun ctxt -> + (* *) + (* /rolls/owner/snapshot/n1/n2/x/y/n3 + => /rolls/owner/snapshot/n1/n2/n3 + *) + fold_flatten + ctxt + ["rolls"; "owner"; "snapshot"] + 2 + [] + ~depth:3 + ~rename:(drop 2) + >>= fun ctxt -> + (* *) + (* /commitments/xx/xx/xx/xx/xx/xxxxxx + => /commitments/xxxxxxxxxxxxxxxx + *) + fold_flatten ctxt ["commitments"] 0 [] ~depth:6 ~rename:rename_blake2b + >>= fun ctxt -> + (* *) + (* /votes/listings/kk/xx/xx/xx/xx/xx/xx/xxxxxxxx + => /votes/listings/kk/xxxxxxxxxxxxxxxxxx + *) + fold_flatten + ctxt + ["votes"; "listings"] + 0 + [] + ~depth:7 + ~rename:rename_public_key_hash + >>= fun ctxt -> + (* *) + (* /votes/ballots/kk/xx/xx/xx/xx/xx/xx/xxxxxxxx + => /votes/ballots/KK/xxxxxxxxxxxxxxxxxxxx + *) + fold_flatten + ctxt + ["votes"; "ballots"] + 0 + [] + ~depth:7 + ~rename:rename_public_key_hash + >>= fun ctxt -> + (* *) + (* /votes/proposals_count/kk/xx/xx/xx/xx/xx/xx/xxxxxxxx + => /votes/proposals_count/kk/xxxxxxxxxxxxxxxxxxxx + *) + fold_flatten + ctxt + ["votes"; "proposals_count"] + 0 + [] + ~depth:7 + ~rename:rename_public_key_hash + >>= fun ctxt -> + (* *) + (* /votes/proposals/xx/xx/xx/xx/xx/xx/xxxxxxxx + => /votes/proposals/xxxxxxxxxxxxxxxxxxxx + *) + fold_flatten + ctxt + ["votes"; "proposals"] + 0 + [] + ~depth:6 + ~rename:rename_blake2b + >>= fun ctxt -> + (* *) + (* /votes/proposals/yyyyyyyyyyyyyyyyyyyy/kk/xx/xx/xx/xx/xx/xx/xxxxxxxx + => /votes/proposals/yyyyyyyyyyyyyyyyyyyy/KK/xxxxxxxxxxxxxxxxxxxx + *) + fold_flatten + ctxt + ["votes"; "proposals"] + 1 + [] + ~depth:7 + ~rename:rename_public_key_hash + >>= fun ctxt -> + (* *) + (* /delegates/kk/xx/xx/xx/xx/xx/xx/xxxxxxxx + => /delegates/KK/xxxxxxxxxxxxxxxxxxxx + *) + fold_flatten ctxt ["delegates"] 0 [] ~depth:7 ~rename:rename_public_key_hash + >>= fun ctxt -> + (* *) + (* /active_delegates_with_rolls/kk/xx/xx/xx/xx/xx/xx/xxxxxxxx + => /active_delegates_with_rolls/KK/xxxxxxxxxxxxxxxxxxxx + *) + fold_flatten + ctxt + ["active_delegates_with_rolls"] + 0 + [] + ~depth:7 + ~rename:rename_public_key_hash + >>= fun ctxt -> + (* *) + (* /delegates_with_frozen_balance/n/kk/xx/xx/xx/xx/xx/xx/xxxxxxxx + => /delegates_with_frozen_balance/n/KK/xxxxxxxxxxxxxxxxxxxx + *) + fold_flatten + ctxt + ["delegates_with_frozen_balance"] + 1 + [] + ~depth:7 + ~rename:rename_public_key_hash + >|= fun ctxt -> + log "context storage flattening completed" ; + ctxt +end + +(* + To add invoices, you can use a helper function like this one: + + (** Invoice a contract at a given address with a given amount. Returns the + updated context and a balance update receipt (singleton list). The address + must be a valid base58 hash, otherwise this is no-op and returns an empty + receipts list. + + Do not fail if something goes wrong. + *) + let invoice_contract ctxt ~address ~amount_mutez = + match Tez_repr.of_mutez amount_mutez with + | None -> + Lwt.return (ctxt, []) + | Some amount -> ( + Contract_repr.of_b58check address + >>?= (fun recipient -> + Contract_storage.credit ctxt recipient amount + >|=? fun ctxt -> + ( ctxt, + Receipt_repr. + [(Contract recipient, Credited amount, Protocol_migration)] )) + >|= function Ok res -> res | Error _ -> (ctxt, []) ) +*) + +let prepare_first_block ctxt ~typecheck ~level ~timestamp ~fitness = + Raw_context.prepare_first_block ~level ~timestamp ~fitness ctxt + >>=? fun (previous_protocol, ctxt) -> + match previous_protocol with + | Genesis param -> + (* This is the genesis protocol: initialise the state *) + Commitment_storage.init ctxt param.commitments >>=? fun ctxt -> + Roll_storage.init ctxt >>=? fun ctxt -> + Seed_storage.init ctxt >>=? fun ctxt -> + Contract_storage.init ctxt >>=? fun ctxt -> + Bootstrap_storage.init + ctxt + ~typecheck + ?ramp_up_cycles:param.security_deposit_ramp_up_cycles + ?no_reward_cycles:param.no_reward_cycles + param.bootstrap_accounts + param.bootstrap_contracts + >>=? fun ctxt -> + Roll_storage.init_first_cycles ctxt >>=? fun ctxt -> + Vote_storage.init + ctxt + ~start_position:(Level_storage.current ctxt).level_position + >>=? fun ctxt -> + Storage.Block_priority.init ctxt 0 >>=? fun ctxt -> + Vote_storage.update_listings ctxt >>=? fun ctxt -> + (* Must be called after other originations since it unsets the origination nonce.*) + Liquidity_baking_migration.init ctxt ~typecheck + >>=? fun (ctxt, operation_results) -> + Storage.Pending_migration.Operation_results.init ctxt operation_results + | Granada_010 -> Flatten_storage_for_H.flatten_storage ctxt >>= return + +let prepare ctxt ~level ~predecessor_timestamp ~timestamp ~fitness = + Raw_context.prepare ~level ~predecessor_timestamp ~timestamp ~fitness ctxt + >>=? fun ctxt -> Storage.Pending_migration.remove ctxt diff --git a/src/proto_011_PtHangzH/lib_protocol/init_storage.mli b/src/proto_011_PtHangzH/lib_protocol/init_storage.mli new file mode 100644 index 000000000000..262f7ab97bb5 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/init_storage.mli @@ -0,0 +1,57 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Functions to setup storage. Used by [Alpha_context.prepare]. + + If you have defined a new type of storage, you should add relevant + setups here. + *) + +(* This is the genesis protocol: initialise the state *) +val prepare_first_block : + Context.t -> + typecheck: + (Raw_context.t -> + Script_repr.t -> + ((Script_repr.t * Lazy_storage_diff.diffs option) * Raw_context.t) + Error_monad.tzresult + Lwt.t) -> + level:int32 -> + timestamp:Time.t -> + fitness:Fitness.t -> + (Raw_context.t, Error_monad.error Error_monad.trace) Pervasives.result Lwt.t + +val prepare : + Context.t -> + level:Int32.t -> + predecessor_timestamp:Time.t -> + timestamp:Time.t -> + fitness:Fitness.t -> + (Raw_context.t + * Receipt_repr.balance_updates + * Migration_repr.origination_result list) + Error_monad.tzresult + Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/lazy_storage_diff.ml b/src/proto_011_PtHangzH/lib_protocol/lazy_storage_diff.ml new file mode 100644 index 000000000000..9a7030c35741 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/lazy_storage_diff.ml @@ -0,0 +1,439 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module type Next = sig + type id + + val init : Raw_context.t -> Raw_context.t tzresult Lwt.t + + val incr : Raw_context.t -> (Raw_context.t * id) tzresult Lwt.t +end + +module type Total_bytes = sig + type id + + val init : Raw_context.t -> id -> Z.t -> Raw_context.t tzresult Lwt.t + + val get : Raw_context.t -> id -> Z.t tzresult Lwt.t + + val update : Raw_context.t -> id -> Z.t -> Raw_context.t tzresult Lwt.t +end + +(** Operations to be defined on a lazy storage type. *) +module type OPS = sig + module Id : Lazy_storage_kind.ID + + type alloc + + type updates + + val title : string + + val alloc_encoding : alloc Data_encoding.t + + val updates_encoding : updates Data_encoding.t + + val alloc_in_memory_size : alloc -> Cache_memory_helpers.nodes_and_size + + val updates_in_memory_size : updates -> Cache_memory_helpers.nodes_and_size + + val bytes_size_for_empty : Z.t + + val alloc : Raw_context.t -> id:Id.t -> alloc -> Raw_context.t tzresult Lwt.t + + val apply_updates : + Raw_context.t -> id:Id.t -> updates -> (Raw_context.t * Z.t) tzresult Lwt.t + + module Next : Next with type id := Id.t + + module Total_bytes : Total_bytes with type id := Id.t + + (** Deep copy. *) + val copy : + Raw_context.t -> from:Id.t -> to_:Id.t -> Raw_context.t tzresult Lwt.t + + (** Deep deletion. *) + val remove : Raw_context.t -> Id.t -> Raw_context.t Lwt.t +end + +module Big_map = struct + include Lazy_storage_kind.Big_map + + let alloc_in_memory_size {key_type; value_type} = + let open Cache_memory_helpers in + ret_adding + (expr_size key_type ++ expr_size value_type) + (header_size +! (word_size *? 2)) + + let updates_in_memory_size updates = + let open Cache_memory_helpers in + let update_size {key; key_hash = _; value} = + ret_adding + (expr_size key ++ option_size_vec expr_size value) + (header_size +! (word_size *? 3) +? Script_expr_hash.size) + in + list_fold_size update_size updates + + let bytes_size_for_big_map_key = 65 + + let bytes_size_for_empty = + let bytes_size_for_big_map = 33 in + Z.of_int bytes_size_for_big_map + + let alloc ctxt ~id {key_type; value_type} = + (* Annotations are erased to allow sharing on [Copy]. The types from the + contract code are used, these ones are only used to make sure they are + compatible during transmissions between contracts, and only need to be + compatible, annotations notwithstanding. *) + let key_type = + Micheline.strip_locations + (Script_repr.strip_annotations (Micheline.root key_type)) + in + let value_type = + Micheline.strip_locations + (Script_repr.strip_annotations (Micheline.root value_type)) + in + Storage.Big_map.Key_type.init ctxt id key_type >>=? fun ctxt -> + Storage.Big_map.Value_type.init ctxt id value_type + + let apply_update ctxt ~id + { + key = _key_is_shown_only_on_the_receipt_in_print_big_map_diff; + key_hash; + value; + } = + match value with + | None -> + Storage.Big_map.Contents.remove (ctxt, id) key_hash + >|=? fun (ctxt, freed, existed) -> + let freed = + if existed then freed + bytes_size_for_big_map_key else freed + in + (ctxt, Z.of_int ~-freed) + | Some v -> + Storage.Big_map.Contents.add (ctxt, id) key_hash v + >|=? fun (ctxt, size_diff, existed) -> + let size_diff = + if existed then size_diff else size_diff + bytes_size_for_big_map_key + in + (ctxt, Z.of_int size_diff) + + let apply_updates ctxt ~id updates = + List.fold_left_es + (fun (ctxt, size) update -> + apply_update ctxt ~id update >|=? fun (ctxt, added_size) -> + (ctxt, Z.add size added_size)) + (ctxt, Z.zero) + updates + + include Storage.Big_map +end + +type ('id, 'alloc, 'updates) ops = + (module OPS + with type Id.t = 'id + and type alloc = 'alloc + and type updates = 'updates) + +module Sapling_state = struct + include Lazy_storage_kind.Sapling_state + + let alloc_in_memory_size {memo_size = (_ : int)} = + let open Cache_memory_helpers in + (Nodes.zero, header_size +! word_size) + + let updates_in_memory_size update = + (Cache_memory_helpers.Nodes.zero, Sapling_repr.diff_in_memory_size update) + + let bytes_size_for_empty = Z.of_int 33 + + let alloc ctxt ~id {memo_size} = Sapling_storage.init ctxt id ~memo_size + + let apply_updates ctxt ~id updates = + Sapling_storage.apply_diff ctxt id updates + + include Storage.Sapling +end + +(* + To add a new lazy storage kind here, you only need to create a module similar + to [Big_map] above and add a case to [get_ops] below. +*) + +let get_ops : type i a u. (i, a, u) Lazy_storage_kind.t -> (i, a, u) ops = + function + | Big_map -> (module Big_map) + | Sapling_state -> (module Sapling_state) + [@@coq_axiom_with_reason "gadt"] + +type ('id, 'alloc) init = Existing | Copy of {src : 'id} | Alloc of 'alloc + +type ('id, 'alloc, 'updates) diff = + | Remove + | Update of {init : ('id, 'alloc) init; updates : 'updates} + +let diff_encoding : type i a u. (i, a, u) ops -> (i, a, u) diff Data_encoding.t + = + fun (module OPS) -> + let open Data_encoding in + union + [ + case + (Tag 0) + ~title:"update" + (obj2 + (req "action" (constant "update")) + (req "updates" OPS.updates_encoding)) + (function + | Update {init = Existing; updates} -> Some ((), updates) | _ -> None) + (fun ((), updates) -> Update {init = Existing; updates}); + case + (Tag 1) + ~title:"remove" + (obj1 (req "action" (constant "remove"))) + (function Remove -> Some () | _ -> None) + (fun () -> Remove); + case + (Tag 2) + ~title:"copy" + (obj3 + (req "action" (constant "copy")) + (req "source" OPS.Id.encoding) + (req "updates" OPS.updates_encoding)) + (function + | Update {init = Copy {src}; updates} -> Some ((), src, updates) + | _ -> None) + (fun ((), src, updates) -> Update {init = Copy {src}; updates}); + case + (Tag 3) + ~title:"alloc" + (merge_objs + (obj2 + (req "action" (constant "alloc")) + (req "updates" OPS.updates_encoding)) + OPS.alloc_encoding) + (function + | Update {init = Alloc alloc; updates} -> Some (((), updates), alloc) + | _ -> None) + (fun (((), updates), alloc) -> Update {init = Alloc alloc; updates}); + ] + +let init_size : + type i a u. + (i, a, u) ops -> (i, a) init -> Cache_memory_helpers.nodes_and_size = + fun (module OPS) init -> + let open Cache_memory_helpers in + match init with + | Existing -> zero + | Copy {src = _id_is_a_Z_fitting_in_an_int_for_a_long_time} -> + (Nodes.zero, header_size +! word_size) + | Alloc alloc -> + ret_adding (OPS.alloc_in_memory_size alloc) (header_size +! word_size) + +let updates_size : + type i a u. (i, a, u) ops -> u -> Cache_memory_helpers.nodes_and_size = + fun (module OPS) updates -> OPS.updates_in_memory_size updates + +let diff_in_memory_size kind diff = + let open Cache_memory_helpers in + match diff with + | Remove -> zero + | Update {init; updates} -> + let ops = get_ops kind in + ret_adding (init_size ops init ++ updates_size ops updates) h2w + +(** + [apply_updates ctxt ops ~id init] applies the updates [updates] on lazy + storage [id] on storage context [ctxt] using operations [ops] and returns the + updated storage context and the added size in bytes (may be negative). +*) +let apply_updates : + type i a u. + Raw_context.t -> + (i, a, u) ops -> + id:i -> + u -> + (Raw_context.t * Z.t) tzresult Lwt.t = + fun ctxt (module OPS) ~id updates -> + OPS.apply_updates ctxt ~id updates >>=? fun (ctxt, updates_size) -> + if Z.(equal updates_size zero) then return (ctxt, updates_size) + else + OPS.Total_bytes.get ctxt id >>=? fun size -> + OPS.Total_bytes.update ctxt id (Z.add size updates_size) >|=? fun ctxt -> + (ctxt, updates_size) + +(** + [apply_init ctxt ops ~id init] applies the initialization [init] on lazy + storage [id] on storage context [ctxt] using operations [ops] and returns the + updated storage context and the added size in bytes (may be negative). + + If [id] represents a temporary lazy storage, the added size may be wrong. +*) +let apply_init : + type i a u. + Raw_context.t -> + (i, a, u) ops -> + id:i -> + (i, a) init -> + (Raw_context.t * Z.t) tzresult Lwt.t = + fun ctxt (module OPS) ~id init -> + match init with + | Existing -> return (ctxt, Z.zero) + | Copy {src} -> + OPS.copy ctxt ~from:src ~to_:id >>=? fun ctxt -> + if OPS.Id.is_temp id then return (ctxt, Z.zero) + else + OPS.Total_bytes.get ctxt src >>=? fun copy_size -> + return (ctxt, Z.add copy_size OPS.bytes_size_for_empty) + | Alloc alloc -> + OPS.Total_bytes.init ctxt id Z.zero >>=? fun ctxt -> + OPS.alloc ctxt ~id alloc >>=? fun ctxt -> + return (ctxt, OPS.bytes_size_for_empty) + +(** + [apply_diff ctxt ops ~id diff] applies the diff [diff] on lazy storage [id] + on storage context [ctxt] using operations [ops] and returns the updated + storage context and the added size in bytes (may be negative). + + If [id] represents a temporary lazy storage, the added size may be wrong. +*) +let apply_diff : + type i a u. + Raw_context.t -> + (i, a, u) ops -> + id:i -> + (i, a, u) diff -> + (Raw_context.t * Z.t) tzresult Lwt.t = + fun ctxt ((module OPS) as ops) ~id diff -> + match diff with + | Remove -> + if OPS.Id.is_temp id then + OPS.remove ctxt id >|= fun ctxt -> ok (ctxt, Z.zero) + else + OPS.Total_bytes.get ctxt id >>=? fun size -> + OPS.remove ctxt id >>= fun ctxt -> + return (ctxt, Z.neg (Z.add size OPS.bytes_size_for_empty)) + | Update {init; updates} -> + apply_init ctxt ops ~id init >>=? fun (ctxt, init_size) -> + apply_updates ctxt ops ~id updates >>=? fun (ctxt, updates_size) -> + return (ctxt, Z.add init_size updates_size) + +type diffs_item = + | Item : + ('i, 'a, 'u) Lazy_storage_kind.t * 'i * ('i, 'a, 'u) diff + -> diffs_item + +let make : + type i a u. + (i, a, u) Lazy_storage_kind.t -> i -> (i, a, u) diff -> diffs_item = + fun k id diff -> Item (k, id, diff) + +let item_encoding = + let open Data_encoding in + union + @@ List.map + (fun (tag, Lazy_storage_kind.Ex_Kind k) -> + let ops = get_ops k in + let (module OPS) = ops in + let title = OPS.title in + case + (Tag tag) + ~title + (obj3 + (req "kind" (constant title)) + (req "id" OPS.Id.encoding) + (req "diff" (diff_encoding ops))) + (fun (Item (kind, id, diff)) -> + match Lazy_storage_kind.equal k kind with + | Eq -> Some ((), id, diff) + | Neq -> None) + (fun ((), id, diff) -> Item (k, id, diff))) + Lazy_storage_kind.all + [@@coq_axiom_with_reason "gadt"] + +let item_in_memory_size + (Item + ( kind + (* kinds are constant tags *), + _id_is_a_Z_fitting_in_an_int_for_a_long_time, + diff )) = + let open Cache_memory_helpers in + ret_adding (diff_in_memory_size kind diff) h3w + +type diffs = diffs_item list + +let diffs_in_memory_size diffs = + Cache_memory_helpers.list_fold_size item_in_memory_size diffs + +let encoding = + let open Data_encoding in + def "lazy_storage_diff" @@ list item_encoding + +let apply ctxt diffs = + List.fold_left_es + (fun (ctxt, total_size) (Item (k, id, diff)) -> + let ops = get_ops k in + apply_diff ctxt ops ~id diff >|=? fun (ctxt, added_size) -> + let (module OPS) = ops in + ( ctxt, + if OPS.Id.is_temp id then total_size else Z.add total_size added_size )) + (ctxt, Z.zero) + diffs + +let fresh : + type i a u. + (i, a, u) Lazy_storage_kind.t -> + temporary:bool -> + Raw_context.t -> + (Raw_context.t * i) tzresult Lwt.t = + fun kind ~temporary ctxt -> + if temporary then + return + (Raw_context.fold_map_temporary_lazy_storage_ids ctxt (fun temp_ids -> + Lazy_storage_kind.Temp_ids.fresh kind temp_ids)) + else + let (module OPS) = get_ops kind in + OPS.Next.incr ctxt + [@@coq_axiom_with_reason "gadt"] + +let init ctxt = + List.fold_left_es + (fun ctxt (_tag, Lazy_storage_kind.Ex_Kind k) -> + let (module OPS) = get_ops k in + OPS.Next.init ctxt) + ctxt + Lazy_storage_kind.all + [@@coq_axiom_with_reason "gadt"] + +let cleanup_temporaries ctxt = + Raw_context.map_temporary_lazy_storage_ids_s ctxt (fun temp_ids -> + List.fold_left_s + (fun ctxt (_tag, Lazy_storage_kind.Ex_Kind k) -> + let (module OPS) = get_ops k in + Lazy_storage_kind.Temp_ids.fold_s k OPS.remove temp_ids ctxt) + ctxt + Lazy_storage_kind.all + >|= fun ctxt -> (ctxt, Lazy_storage_kind.Temp_ids.init)) + [@@coq_axiom_with_reason "gadt"] diff --git a/src/proto_011_PtHangzH/lib_protocol/lazy_storage_diff.mli b/src/proto_011_PtHangzH/lib_protocol/lazy_storage_diff.mli new file mode 100644 index 000000000000..17637213d75b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/lazy_storage_diff.mli @@ -0,0 +1,71 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** + See [Lazy_storage_kind] for an introduction on lazy storage. + + This module defines operations on lazy storage types and diffs. +*) + +type ('id, 'alloc) init = Existing | Copy of {src : 'id} | Alloc of 'alloc + +type ('id, 'alloc, 'updates) diff = + | Remove + | Update of {init : ('id, 'alloc) init; updates : 'updates} + +(* Exposing this type is needed only for legacy big map diff. *) +type diffs_item = private + | Item : + ('i, 'a, 'u) Lazy_storage_kind.t * 'i * ('i, 'a, 'u) diff + -> diffs_item + +val make : + ('i, 'a, 'u) Lazy_storage_kind.t -> 'i -> ('i, 'a, 'u) diff -> diffs_item + +type diffs = diffs_item list + +val diffs_in_memory_size : diffs -> Cache_memory_helpers.nodes_and_size + +val encoding : diffs Data_encoding.t + +(** + The returned [Z.t] is the size added by the application of the diffs. +*) +val apply : Raw_context.t -> diffs -> (Raw_context.t * Z.t) tzresult Lwt.t + +val fresh : + ('id, _, _) Lazy_storage_kind.t -> + temporary:bool -> + Raw_context.t -> + (Raw_context.t * 'id) tzresult Lwt.t + +(** + Initializes the storage for all lazy storage kind. + This is useful for genesis only. + Protocol updates need to initialize new lazy storage kinds. +*) +val init : Raw_context.t -> Raw_context.t tzresult Lwt.t + +val cleanup_temporaries : Raw_context.t -> Raw_context.t Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/lazy_storage_kind.ml b/src/proto_011_PtHangzH/lib_protocol/lazy_storage_kind.ml new file mode 100644 index 000000000000..799e55e047f7 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/lazy_storage_kind.ml @@ -0,0 +1,325 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module type TEMP_ID = sig + type t + + val equal : t -> t -> bool + + val init : t + + val next : t -> t +end + +module type ID = sig + type t + + val compare : t -> t -> int + + val encoding : t Data_encoding.t + + val rpc_arg : t RPC_arg.arg + + val init : t + + (** In the protocol, to be used in parse_data only *) + val parse_z : Z.t -> t + + (** In the protocol, to be used in unparse_data only *) + val unparse_to_z : t -> Z.t + + val next : t -> t + + val is_temp : t -> bool + + val of_legacy_USE_ONLY_IN_Legacy_big_map_diff : Z.t -> t + + val to_legacy_USE_ONLY_IN_Legacy_big_map_diff : t -> Z.t + + include Path_encoding.S with type t := t +end + +module type Title = sig + val title : string +end + +module type TitleWithId = sig + val title : string + + module Id : ID + + module Temp_id : TEMP_ID with type t = private Id.t + + module IdSet : Set.S with type elt = Id.t +end + +module MakeId (Title : Title) : TitleWithId = struct + let title = Title.title + + let title_words = String.map (function '_' -> ' ' | c -> c) title + + let rpc_arg_error = Format.sprintf "Cannot parse %s id" title_words + + let description = Format.sprintf "A %s identifier" title_words + + let name = title ^ "_id" + + let encoding_title = String.capitalize_ascii title_words ^ " identifier" + + module Id = struct + type t = Z.t + + let compare = Z.compare + + let encoding = + Data_encoding.def name ~title:encoding_title ~description Data_encoding.z + + let rpc_arg = + let construct = Z.to_string in + let destruct hash = + Result.catch_f (fun () -> Z.of_string hash) (fun _ -> rpc_arg_error) + in + RPC_arg.make ~descr:description ~name ~construct ~destruct () + + let init = Z.zero + + let parse_z (z : Z.t) : t = z + + let unparse_to_z (z : t) : Z.t = z + + let next = Z.succ + + let of_legacy_USE_ONLY_IN_Legacy_big_map_diff (z : Z.t) : t = z + + let to_legacy_USE_ONLY_IN_Legacy_big_map_diff (z : t) : Z.t = z + + let is_temp z = Compare.Z.(z < Z.zero) + + let path_length = 1 + + let to_path z l = Z.to_string z :: l + + let of_path = function + | [] | _ :: _ :: _ -> None + | [z] -> Some (Z.of_string z) + end + + module Temp_id = struct + type t = Id.t + + let equal = Z.equal + + let init = Z.of_int ~-1 + + let next z = Z.sub z Z.one + end + + module IdSet = Set.Make (Id) +end + +module Big_map = struct + include MakeId (struct + let title = "big_map" + end) + + type alloc = {key_type : Script_repr.expr; value_type : Script_repr.expr} + + type update = { + key : Script_repr.expr; + (** The key is ignored by [apply_update] but is shown in the receipt, + as specified in [print_big_map_diff]. *) + key_hash : Script_expr_hash.t; + value : Script_repr.expr option; + } + + type updates = update list + + let alloc_encoding = + let open Data_encoding in + conv + (fun {key_type; value_type} -> (key_type, value_type)) + (fun (key_type, value_type) -> {key_type; value_type}) + (obj2 + (req "key_type" Script_repr.expr_encoding) + (req "value_type" Script_repr.expr_encoding)) + + let update_encoding = + let open Data_encoding in + conv + (fun {key_hash; key; value} -> (key_hash, key, value)) + (fun (key_hash, key, value) -> {key_hash; key; value}) + (obj3 + (req "key_hash" Script_expr_hash.encoding) + (req "key" Script_repr.expr_encoding) + (opt "value" Script_repr.expr_encoding)) + + let updates_encoding = Data_encoding.list update_encoding +end + +module Sapling_state = struct + include MakeId (struct + let title = "sapling_state" + end) + + type alloc = {memo_size : Sapling_repr.Memo_size.t} + + type updates = Sapling_repr.diff + + let alloc_encoding = + let open Data_encoding in + conv + (fun {memo_size} -> memo_size) + (fun memo_size -> {memo_size}) + (obj1 (req "memo_size" Sapling_repr.Memo_size.encoding)) + + let updates_encoding = Sapling_repr.diff_encoding +end + +(* + When adding cases to this type, grep for [new lazy storage kind] in the code + for locations to update. + It must be: + - the value [all] right below, + - modules [Temp_ids], [IdSet] below, + - the rest should be guided by type errors. +*) +type ('id, 'alloc, 'updates) t = + | Big_map : (Big_map.Id.t, Big_map.alloc, Big_map.updates) t + | Sapling_state + : (Sapling_state.Id.t, Sapling_state.alloc, Sapling_state.updates) t + +type ex = Ex_Kind : (_, _, _) t -> ex + +(* /!\ Don't forget to add new lazy storage kinds here. /!\ *) +let all = [(0, Ex_Kind Big_map); (1, Ex_Kind Sapling_state)] + +type (_, _) cmp = Eq : ('a, 'a) cmp | Neq + +let equal : + type i1 a1 u1 i2 a2 u2. + (i1, a1, u1) t -> (i2, a2, u2) t -> (i1 * a1 * u1, i2 * a2 * u2) cmp = + fun k1 k2 -> + match (k1, k2) with + | (Big_map, Big_map) -> Eq + | (Sapling_state, Sapling_state) -> Eq + | (Big_map, _) -> Neq + | (_, Big_map) -> Neq + +type ('i, 'a, 'u) kind = ('i, 'a, 'u) t + +module Temp_ids = struct + type t = { + big_map : Big_map.Temp_id.t; + sapling_state : Sapling_state.Temp_id.t; + } + + let init = + {big_map = Big_map.Temp_id.init; sapling_state = Sapling_state.Temp_id.init} + + let fresh : type i a u. (i, a, u) kind -> t -> t * i = + fun kind temp_ids -> + match kind with + | Big_map -> + let big_map = Big_map.Temp_id.next temp_ids.big_map in + ({temp_ids with big_map}, (temp_ids.big_map :> Big_map.Id.t)) + | Sapling_state -> + let sapling_state = Sapling_state.Temp_id.next temp_ids.sapling_state in + ( {temp_ids with sapling_state}, + (temp_ids.sapling_state :> Sapling_state.Id.t) ) + [@@coq_axiom_with_reason "gadt"] + + let fold_s : + type i a u. + (i, a, u) kind -> ('acc -> i -> 'acc Lwt.t) -> t -> 'acc -> 'acc Lwt.t = + fun kind f temp_ids acc -> + let helper (type j) (module Temp_id : TEMP_ID with type t = j) ~last f = + let rec aux acc id = + if Temp_id.equal id last then Lwt.return acc + else f acc id >>= fun acc -> aux acc (Temp_id.next id) + in + aux acc Temp_id.init + in + match kind with + | Big_map -> + helper + (module Big_map.Temp_id) + ~last:temp_ids.big_map + (fun acc temp_id -> f acc (temp_id :> i)) + | Sapling_state -> + helper + (module Sapling_state.Temp_id) + ~last:temp_ids.sapling_state + (fun acc temp_id -> f acc (temp_id :> i)) + [@@coq_axiom_with_reason "gadt"] +end + +module IdSet = struct + type t = {big_map : Big_map.IdSet.t; sapling_state : Sapling_state.IdSet.t} + + type 'acc fold_f = {f : 'i 'a 'u. ('i, 'a, 'u) kind -> 'i -> 'acc -> 'acc} + + let empty = + {big_map = Big_map.IdSet.empty; sapling_state = Sapling_state.IdSet.empty} + + let mem (type i a u) (kind : (i, a, u) kind) (id : i) set = + match (kind, set) with + | (Big_map, {big_map; _}) -> Big_map.IdSet.mem id big_map + | (Sapling_state, {sapling_state; _}) -> + Sapling_state.IdSet.mem id sapling_state + [@@coq_axiom_with_reason "gadt"] + + let add (type i a u) (kind : (i, a, u) kind) (id : i) set = + match (kind, set) with + | (Big_map, {big_map; _}) -> + let big_map = Big_map.IdSet.add id big_map in + {set with big_map} + | (Sapling_state, {sapling_state; _}) -> + let sapling_state = Sapling_state.IdSet.add id sapling_state in + {set with sapling_state} + [@@coq_axiom_with_reason "gadt"] + + let diff set1 set2 = + let big_map = Big_map.IdSet.diff set1.big_map set2.big_map in + let sapling_state = + Sapling_state.IdSet.diff set1.sapling_state set2.sapling_state + in + {big_map; sapling_state} + [@@coq_axiom_with_reason "gadt"] + + let fold (type i a u) (kind : (i, a, u) kind) (f : i -> 'acc -> 'acc) set + (acc : 'acc) = + match (kind, set) with + | (Big_map, {big_map; _}) -> Big_map.IdSet.fold f big_map acc + | (Sapling_state, {sapling_state; _}) -> + Sapling_state.IdSet.fold f sapling_state acc + [@@coq_axiom_with_reason "gadt"] + + let fold_all f set acc = + List.fold_left + (fun acc (_, Ex_Kind kind) -> fold kind (f.f kind) set acc) + acc + all + [@@coq_axiom_with_reason "gadt"] +end diff --git a/src/proto_011_PtHangzH/lib_protocol/lazy_storage_kind.mli b/src/proto_011_PtHangzH/lib_protocol/lazy_storage_kind.mli new file mode 100644 index 000000000000..eb23fb9545ad --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/lazy_storage_kind.mli @@ -0,0 +1,178 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** + Lazy_storage offers a unified interface for specific Michelson datatype that + behave somewhat lazily, because they are intended to be quite big. + Instead of serializing/deserializing the whole value to/from the storage, + only an identifier is used. The identifier acts like a pointer. + When using the value in a Michelson script, some part of it may be read from + the storage, and a lightweight diff is computed. + The diff is effectively applied to the storage at the end of the execution. + + This module defines the different kinds of lazy storages and their basic + properties. See also [Lazy_storage_diff]. + + Lazy storage types are: + - Big_map +*) + +(** + Lazy storage ids are kept as abstract as possible to avoid mixing them up. + + Behind the scene they are [Z.t]s but, within the protocol, only [parse_data]/ + [unparse_data] are allowed convert from/to it. + + Temporary ids may be used to pass values between contracts that won't be kept + longer than the lifetime of the operation. + Behind the scene, temporary ids are negative [Z.t]s. +*) +module type ID = sig + type t + + val compare : t -> t -> int + + val encoding : t Data_encoding.t + + val rpc_arg : t RPC_arg.arg + + (** Initial value for ids: zero. *) + val init : t + + (** In the protocol, to be used in parse_data only *) + val parse_z : Z.t -> t + + (** In the protocol, to be used in unparse_data only *) + val unparse_to_z : t -> Z.t + + val next : t -> t + + val is_temp : t -> bool + + (* To be removed once legacy big map diff is removed: *) + + val of_legacy_USE_ONLY_IN_Legacy_big_map_diff : Z.t -> t + + val to_legacy_USE_ONLY_IN_Legacy_big_map_diff : t -> Z.t + + (* To be used in storage: *) + + include Path_encoding.S with type t := t +end + +module Big_map : sig + val title : string + + module Id : ID + + type alloc = {key_type : Script_repr.expr; value_type : Script_repr.expr} + + type update = { + key : Script_repr.expr; + (** The key is ignored by [apply_update] but is shown in the receipt, + as specified in [print_big_map_diff]. *) + key_hash : Script_expr_hash.t; + value : Script_repr.expr option; + } + + type updates = update list + + val alloc_encoding : alloc Data_encoding.t + + val updates_encoding : updates Data_encoding.t +end + +module Sapling_state : sig + val title : string + + module Id : ID + + type alloc = {memo_size : Sapling_repr.Memo_size.t} + + type updates = Sapling_repr.diff + + val alloc_encoding : alloc Data_encoding.t + + val updates_encoding : updates Data_encoding.t +end + +(** + Kinds of lazy storage. + The GADT ensures operations are properly applied to the correct kind. + + ['id] the abstract type for the identifier of the kind. + ['alloc] is the type used to construct a new value. + ['updates] is the type used to update a value. +*) +type ('id, 'alloc, 'updates) t = + | Big_map : (Big_map.Id.t, Big_map.alloc, Big_map.updates) t + | Sapling_state + : (Sapling_state.Id.t, Sapling_state.alloc, Sapling_state.updates) t + +type ex = Ex_Kind : (_, _, _) t -> ex + +val all : (int * ex) list + +type (_, _) cmp = Eq : ('a, 'a) cmp | Neq + +val equal : + ('i1, 'a1, 'u1) t -> + ('i2, 'a2, 'u2) t -> + ('i1 * 'a1 * 'u1, 'i2 * 'a2 * 'u2) cmp + +type ('i, 'a, 'u) kind = ('i, 'a, 'u) t + +(** + Type to manage temporary ids. + Used only in the context. +*) +module Temp_ids : sig + type t + + val init : t + + val fresh : ('i, 'a, 'u) kind -> t -> t * 'i + + val fold_s : + ('i, 'a, 'u) kind -> ('acc -> 'i -> 'acc Lwt.t) -> t -> 'acc -> 'acc Lwt.t +end + +module IdSet : sig + type t + + type 'acc fold_f = {f : 'i 'a 'u. ('i, 'a, 'u) kind -> 'i -> 'acc -> 'acc} + + val empty : t + + val mem : ('i, 'a, 'u) kind -> 'i -> t -> bool + + val add : ('i, 'a, 'u) kind -> 'i -> t -> t + + val diff : t -> t -> t + + val fold : ('i, 'a, 'u) kind -> ('i -> 'acc -> 'acc) -> t -> 'acc -> 'acc + + val fold_all : 'acc fold_f -> t -> 'acc -> 'acc +end diff --git a/src/proto_011_PtHangzH/lib_protocol/level_repr.ml b/src/proto_011_PtHangzH/lib_protocol/level_repr.ml new file mode 100644 index 000000000000..17ec79b22c0f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/level_repr.ml @@ -0,0 +1,301 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type t = { + level : Raw_level_repr.t; + level_position : int32; + cycle : Cycle_repr.t; + cycle_position : int32; + expected_commitment : bool; +} + +include Compare.Make (struct + type nonrec t = t + + let compare {level = l1; _} {level = l2; _} = Raw_level_repr.compare l1 l2 +end) + +type level = t + +let pp ppf {level; _} = Raw_level_repr.pp ppf level + +let pp_full ppf l = + Format.fprintf + ppf + "%a.%ld (cycle %a.%ld)" + Raw_level_repr.pp + l.level + l.level_position + Cycle_repr.pp + l.cycle + l.cycle_position + +let encoding = + let open Data_encoding in + conv + (fun {level; level_position; cycle; cycle_position; expected_commitment} -> + (level, level_position, cycle, cycle_position, expected_commitment)) + (fun (level, level_position, cycle, cycle_position, expected_commitment) -> + {level; level_position; cycle; cycle_position; expected_commitment}) + (obj5 + (req + "level" + ~description: + "The level of the block relative to genesis. This is also the \ + Shell's notion of level" + Raw_level_repr.encoding) + (req + "level_position" + ~description: + "The level of the block relative to the block that starts protocol \ + alpha. This is specific to the protocol alpha. Other protocols \ + might or might not include a similar notion." + int32) + (req + "cycle" + ~description: + "The current cycle's number. Note that cycles are a \ + protocol-specific notion. As a result, the cycle number starts at \ + 0 with the first block of protocol alpha." + Cycle_repr.encoding) + (req + "cycle_position" + ~description: + "The current level of the block relative to the first block of the \ + current cycle." + int32) + (req + "expected_commitment" + ~description: + "Tells whether the baker of this block has to commit a seed nonce \ + hash." + bool)) + +let diff {level = l1; _} {level = l2; _} = + Int32.sub (Raw_level_repr.to_int32 l1) (Raw_level_repr.to_int32 l2) + +type cycle_era = { + first_level : Raw_level_repr.t; + first_cycle : Cycle_repr.t; + blocks_per_cycle : int32; + blocks_per_commitment : int32; +} + +type cycle_eras = cycle_era list + +type error += Invalid_cycle_eras + +let () = + register_error_kind + `Temporary + ~id:"level_repr.invalid_cycle_eras" + ~title:"Invalid cycle eras" + ~description: + "The cycles eras are not valid: empty list or non-decreasing first \ + levels or first cycles." + ~pp:(fun ppf () -> + Format.fprintf + ppf + "The cycles eras are not valid: empty list or non-decreasing first \ + levels or first cycles.") + Data_encoding.empty + (function Invalid_cycle_eras -> Some () | _ -> None) + (fun () -> Invalid_cycle_eras) + +let create_cycle_eras cycle_eras = + match cycle_eras with + | [] -> error Invalid_cycle_eras + | newest_era :: older_eras -> + let rec aux {first_level; first_cycle; _} older_eras = + match older_eras with + | ({ + first_level = first_level_of_previous_era; + first_cycle = first_cycle_of_previous_era; + _; + } as previous_era) + :: even_older_eras -> + if + Raw_level_repr.(first_level > first_level_of_previous_era) + && Cycle_repr.(first_cycle > first_cycle_of_previous_era) + then aux previous_era even_older_eras + else error Invalid_cycle_eras + | [] -> ok () + in + aux newest_era older_eras >>? fun () -> ok cycle_eras + +let cycle_era_encoding = + let open Data_encoding in + conv + (fun {first_level; first_cycle; blocks_per_cycle; blocks_per_commitment} -> + (first_level, first_cycle, blocks_per_cycle, blocks_per_commitment)) + (fun (first_level, first_cycle, blocks_per_cycle, blocks_per_commitment) -> + {first_level; first_cycle; blocks_per_cycle; blocks_per_commitment}) + (obj4 + (req + "first_level" + ~description:"The first level of a new cycle era." + Raw_level_repr.encoding) + (req + "first_cycle" + ~description:"The first cycle of a new cycle era." + Cycle_repr.encoding) + (req + "blocks_per_cycle" + ~description: + "The value of the blocks_per_cycle constant used during the cycle \ + era starting with first_level." + int32) + (req + "blocks_per_commitment" + ~description: + "The value of the blocks_per_commitment constant used during the \ + cycle era starting with first_level." + int32)) + +let cycle_eras_encoding = + Data_encoding.conv_with_guard + (fun eras -> eras) + (fun eras -> + match create_cycle_eras eras with + | Ok eras -> Ok eras + | Error _ -> Error "Invalid cycle eras") + (Data_encoding.list cycle_era_encoding) + +let current_era = function [] -> assert false | cycle_era :: _ -> cycle_era + +let root_level cycle_eras = + let first_era = List.last_opt cycle_eras in + let first_era = + match first_era with + | Some first_era -> first_era + | None -> + (* {!create_cycle_eras} fails if the list is empty. + {!cycle_eras_encoding} uses {!create_cycle_eras} and so fails on empty + lists too. *) + assert false + in + { + level = first_era.first_level; + level_position = 0l; + cycle = Cycle_repr.root; + cycle_position = 0l; + expected_commitment = false; + } + +(* This function returns the cycle era to which [level] belongs. *) +let era_of_level ~cycle_eras level = + let rec aux = function + | ({first_level; _} as era) :: previous_eras -> + if Raw_level_repr.(level >= first_level) then era else aux previous_eras + | [] -> assert false + in + aux cycle_eras + +(* This function returns the cycle era to which [cycle] belongs. *) +let era_of_cycle ~cycle_eras cycle = + let rec aux = function + | ({first_cycle; _} as era) :: previous_eras -> + if Cycle_repr.(cycle >= first_cycle) then era else aux previous_eras + | [] -> assert false + in + aux cycle_eras + +(* precondition: level belong to era *) +let level_from_raw_with_era era ~first_level_in_alpha_family level = + let {first_level; first_cycle; blocks_per_cycle; blocks_per_commitment} = + era + in + let level_position_in_era = Raw_level_repr.diff level first_level in + assert (Compare.Int32.(level_position_in_era >= 0l)) ; + let cycles_since_era_start = + Int32.div level_position_in_era blocks_per_cycle + in + let cycle = + Cycle_repr.add first_cycle (Int32.to_int cycles_since_era_start) + in + let cycle_position = Int32.rem level_position_in_era blocks_per_cycle in + let level_position = Raw_level_repr.diff level first_level_in_alpha_family in + let expected_commitment = + Compare.Int32.( + Int32.rem cycle_position blocks_per_commitment + = Int32.pred blocks_per_commitment) + in + {level; level_position; cycle; cycle_position; expected_commitment} + +let level_from_raw_aux ~cycle_eras level = + let first_level_in_alpha_family = + match List.rev cycle_eras with + | [] -> assert false + | {first_level; _} :: _ -> first_level + in + let era = era_of_level ~cycle_eras level in + level_from_raw_with_era era ~first_level_in_alpha_family level + +let from_raw ~cycle_eras l = level_from_raw_aux ~cycle_eras l + +type error += Negative_level_and_offset_sum of int32 * int32 + +let () = + register_error_kind + `Permanent + ~id:"negative_level_and_offset_sum" + ~title:"Negative sum of level and offset" + ~description:"Negative sum of level and offset" + ~pp:(fun ppf (level, offset) -> + Format.fprintf + ppf + "Sum of level : %ld and offset : %ld is negative" + level + offset) + Data_encoding.(obj2 (req "level" int32) (req "offset" int32)) + (function + | Negative_level_and_offset_sum (level, offset) -> Some (level, offset) + | _ -> None) + (fun (level, offset) -> Negative_level_and_offset_sum (level, offset)) + +let from_raw_with_offset ~cycle_eras ~offset l = + let res = Raw_level_repr.(of_int32 (Int32.add (to_int32 l) offset)) in + match res with + | Ok l -> Ok (level_from_raw_aux ~cycle_eras l) + | Error _ -> + error (Negative_level_and_offset_sum (Raw_level_repr.to_int32 l, offset)) + +let first_level_in_cycle_from_eras ~cycle_eras cycle = + let first_level_in_alpha_family = + match List.rev cycle_eras with + | [] -> assert false + | {first_level; _} :: _ -> first_level + in + let era = era_of_cycle ~cycle_eras cycle in + let cycle_position = Cycle_repr.diff cycle era.first_cycle in + let offset = Int32.mul era.blocks_per_cycle cycle_position in + let first_level_in_cycle = + Raw_level_repr.(of_int32_exn (Int32.add (to_int32 era.first_level) offset)) + in + level_from_raw_with_era era ~first_level_in_alpha_family first_level_in_cycle + +let last_of_cycle ~cycle_eras level = + let era = era_of_level ~cycle_eras level.level in + Compare.Int32.(Int32.succ level.cycle_position = era.blocks_per_cycle) diff --git a/src/proto_011_PtHangzH/lib_protocol/level_repr.mli b/src/proto_011_PtHangzH/lib_protocol/level_repr.mli new file mode 100644 index 000000000000..ebb061c62654 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/level_repr.mli @@ -0,0 +1,113 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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 defines the protocol representation of a level. Besides the "raw + level", which is the shell's notion of the level, this representation also + contains additional information, like the cycle the level belongs to. *) + +type t = private { + level : Raw_level_repr.t; + (** The level of the block relative to genesis. This + is also the Shell's notion of level. *) + level_position : int32; + (** The level of the block relative to the block that starts the + alpha family of protocols. *) + cycle : Cycle_repr.t; + (** The current cycle's number. Note that cycles are a protocol-specific + notion. As a result, the cycle number starts at 0 with the first block of + the first version of protocol alpha. *) + cycle_position : int32; + (** The current level of the block relative to the first block of the current + cycle. *) + expected_commitment : bool; +} + +type level = t + +include Compare.S with type t := level + +val encoding : level Data_encoding.t + +val pp : Format.formatter -> level -> unit + +val pp_full : Format.formatter -> level -> unit + +val diff : level -> level -> int32 + +(** A cycle era is a chunk of cycles having the same number of levels + per cycle and the same number of blocks per commitment. *) +type cycle_era = { + first_level : Raw_level_repr.t; (** The first level of a cycle era. *) + first_cycle : Cycle_repr.t; (** The first cycle of a cycle era. *) + blocks_per_cycle : int32; + (** The value of the blocks_per_cycle constant used during the cycle + era starting with first_level. *) + blocks_per_commitment : int32; + (** The value of the blocks_per_commitment constant used during the + cycle era starting with first_level. *) +} + +(** Stores the cycles eras of the Alpha family of protocols *) +type cycle_eras + +val cycle_eras_encoding : cycle_eras Data_encoding.t + +(** Preconditions on the input list of cycle eras: + - the list is not empty + - the first levels and the first cycles are decreasing, meaning that the + first era in the list is the current era, and the last era in the list + is the oldest era + Invariants: + - the first era therefore contains the same constants as in Constants + - the first level of an era is the first level of a cycle +*) +val create_cycle_eras : cycle_era list -> cycle_eras tzresult + +(** Returns the current era *) +val current_era : cycle_eras -> cycle_era + +(** Returns the first level of the oldest era *) +val root_level : cycle_eras -> level + +(** Returns the annotated level corresponding to a raw level *) +val from_raw : cycle_eras:cycle_eras -> Raw_level_repr.t -> level + +(** Returns the annotated level corresponding to a raw level and an + offset. A positive offset corresponds to a higher level. + Fails with [Negative_level_and_offset_sum] if the sum of the raw_level and the offset is negative. *) +val from_raw_with_offset : + cycle_eras:cycle_eras -> offset:int32 -> Raw_level_repr.t -> level tzresult + +(** Returns the first level of the given cycle. *) +val first_level_in_cycle_from_eras : + cycle_eras:cycle_eras -> Cycle_repr.t -> level + +(** Returns true if the given level is the last of a cycle. *) +val last_of_cycle : cycle_eras:cycle_eras -> level -> bool + +(**/**) + +(* exported for unit testing only *) +type error += Invalid_cycle_eras diff --git a/src/proto_011_PtHangzH/lib_protocol/level_storage.ml b/src/proto_011_PtHangzH/lib_protocol/level_storage.ml new file mode 100644 index 000000000000..de01a2f49d5b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/level_storage.ml @@ -0,0 +1,110 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Level_repr + +let from_raw c l = + let cycle_eras = Raw_context.cycle_eras c in + Level_repr.from_raw ~cycle_eras l + +let from_raw_with_offset c ~offset l : Level_repr.t tzresult = + let cycle_eras = Raw_context.cycle_eras c in + Level_repr.from_raw_with_offset ~cycle_eras ~offset l + +let root c = Raw_context.cycle_eras c |> Level_repr.root_level + +let succ c (l : Level_repr.t) = from_raw c (Raw_level_repr.succ l.level) + +let pred c (l : Level_repr.t) = + match Raw_level_repr.pred l.Level_repr.level with + | None -> None + | Some l -> Some (from_raw c l) + +let current ctxt = Raw_context.current_level ctxt + +let previous ctxt = + let l = current ctxt in + match pred ctxt l with + | None -> assert false (* We never validate the Genesis... *) + | Some p -> p + +let first_level_in_cycle ctxt cycle = + let cycle_eras = Raw_context.cycle_eras ctxt in + Level_repr.first_level_in_cycle_from_eras ~cycle_eras cycle + +let last_level_in_cycle ctxt c = + match pred ctxt (first_level_in_cycle ctxt (Cycle_repr.succ c)) with + | None -> assert false + | Some x -> x + +let levels_in_cycle ctxt cycle = + let first = first_level_in_cycle ctxt cycle in + let[@coq_struct "n"] rec loop (n : Level_repr.t) acc = + if Cycle_repr.(n.cycle = first.cycle) then loop (succ ctxt n) (n :: acc) + else acc + in + loop first [] + +let levels_in_current_cycle ctxt ?(offset = 0l) () = + let current_cycle = Cycle_repr.to_int32 (current ctxt).cycle in + let cycle = Int32.add current_cycle offset in + if Compare.Int32.(cycle < 0l) then [] + else + let cycle = Cycle_repr.of_int32_exn cycle in + levels_in_cycle ctxt cycle + +let levels_with_commitments_in_cycle ctxt c = + let first = first_level_in_cycle ctxt c in + let[@coq_struct "n"] rec loop (n : Level_repr.t) acc = + if Cycle_repr.(n.cycle = first.cycle) then + if n.expected_commitment then loop (succ ctxt n) (n :: acc) + else loop (succ ctxt n) acc + else acc + in + loop first [] + +let last_allowed_fork_level c = + let level = Raw_context.current_level c in + let preserved_cycles = Constants_storage.preserved_cycles c in + match Cycle_repr.sub level.cycle preserved_cycles with + | None -> Raw_level_repr.root + | Some cycle -> (first_level_in_cycle c cycle).level + +let last_of_a_cycle ctxt level = + let cycle_eras = Raw_context.cycle_eras ctxt in + Level_repr.last_of_cycle ~cycle_eras level + +let dawn_of_a_new_cycle ctxt = + let level = current ctxt in + if last_of_a_cycle ctxt level then Some level.cycle else None + +let may_snapshot_rolls ctxt = + let level = current ctxt in + let blocks_per_roll_snapshot = + Constants_storage.blocks_per_roll_snapshot ctxt + in + Compare.Int32.equal + (Int32.rem level.cycle_position blocks_per_roll_snapshot) + (Int32.pred blocks_per_roll_snapshot) diff --git a/src/proto_011_PtHangzH/lib_protocol/level_storage.mli b/src/proto_011_PtHangzH/lib_protocol/level_storage.mli new file mode 100644 index 000000000000..eb98ab267e8d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/level_storage.mli @@ -0,0 +1,63 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val current : Raw_context.t -> Level_repr.t + +val previous : Raw_context.t -> Level_repr.t + +val root : Raw_context.t -> Level_repr.t + +val from_raw : Raw_context.t -> Raw_level_repr.t -> Level_repr.t + +(** Fails with [Negative_level_and_offset_sum] if the sum of the raw_level and the offset is negative. *) +val from_raw_with_offset : + Raw_context.t -> offset:int32 -> Raw_level_repr.t -> Level_repr.t tzresult + +val pred : Raw_context.t -> Level_repr.t -> Level_repr.t option + +val succ : Raw_context.t -> Level_repr.t -> Level_repr.t + +val first_level_in_cycle : Raw_context.t -> Cycle_repr.t -> Level_repr.t + +val last_level_in_cycle : Raw_context.t -> Cycle_repr.t -> Level_repr.t + +val levels_in_cycle : Raw_context.t -> Cycle_repr.t -> Level_repr.t list + +val levels_in_current_cycle : + Raw_context.t -> ?offset:int32 -> unit -> Level_repr.t list + +val levels_with_commitments_in_cycle : + Raw_context.t -> Cycle_repr.t -> Level_repr.t list + +val last_allowed_fork_level : Raw_context.t -> Raw_level_repr.t + +(** Returns [Some cycle] if the current level represents the last + level of [cycle] and [None] if the level is not the last level of a + cycle. *) +val dawn_of_a_new_cycle : Raw_context.t -> Cycle_repr.t option + +(** Returns [true] if the rolls should be snapshot at the current + level. *) +val may_snapshot_rolls : Raw_context.t -> bool diff --git a/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_cpmm.ml b/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_cpmm.ml new file mode 100644 index 000000000000..65fa9c91dd08 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_cpmm.ml @@ -0,0 +1,11 @@ +let script_hex : Hex.t = + `Hex + "02000011c405000764076407640865046e00000006256f776e6572076504620000000d256d696e4c71744d696e7465640765046200000013256d6178546f6b656e734465706f7369746564046b0000000925646561646c696e650000000d256164644c6971756964697479046c000000082564656661756c7407640865046e0000000325746f076504620000000a256c71744275726e65640765046a00000010256d696e58747a57697468647261776e0765046200000013256d696e546f6b656e7357697468647261776e046b0000000925646561646c696e65000000102572656d6f76654c69717569646974790865046e00000015256f7574707574446578746572436f6e74726163740765046200000010256d696e546f6b656e73426f756768740765046e0000000325746f076504620000000b25746f6b656e73536f6c64046b0000000925646561646c696e650000000d25746f6b656e546f546f6b656e07640865046e0000000325746f076504620000000b25746f6b656e73536f6c640765046a0000000d256d696e58747a426f75676874046b0000000925646561646c696e650000000b25746f6b656e546f58747a0865046e0000000325746f0765046200000010256d696e546f6b656e73426f75676874046b0000000925646561646c696e650000000b2578747a546f546f6b656e0501076504620000000a25746f6b656e506f6f6c0765046a000000082578747a506f6f6c0765046200000009256c7174546f74616c0765046e0000000d25746f6b656e41646472657373046e0000000b256c71744164647265737305020200000f7203210317034c0316072e02000009d1072e020000035a072e020000032603210317034c0316034c03210317034c0316034c03210317034c0316034c034003190328072c020000000c05200004074303620003032702000002ea0743036a000105700004032105710005031703160322072f0200000013074303680100000008444956206279203003270200000000031603130743036a0001034c0322072f02000000130743036801000000084449562062792030032702000000000316034c0321057100020570000603210571000703170317031605700002032105710003033a0322072f020000001307430368010000000844495620627920300327020000000003160570000205700006032105710007031605700003033a0322072f020000001307430368010000000844495620627920300327020000002a03210317034c03160743036200000570000203190325072c02000000000200000008074303620001031205700002034c0321057100020319032a072c020000000c05200005074303620004032702000001b60571000203210571000303190337072c020000000c0520000407430362000503270200000190057000030321057100040317031703170570000203210571000305700005032105710006031703170316031203420570000403210571000503170316034205700004032105710005031603420317034c032105710002057000050321057100060316031203420321031703170313057000060317031603120342034c03160342034c03490354034203480342034c032105710002034c03210317034c0316034c03210317034c031605700003031703170317031606550765036e0765036e036200000009257472616e73666572072f0200000008074303620000032702000000000743036a000005700003057000030342057000030342034d05700002033005700003034205700002032105710003034c03210317034c031605700002031703170317031706550765045b00000009257175616e74697479046e00000007257461726765740000000b256d696e744f724275726e072f020000000807430362000c032702000000000743036a000005700002057000030342034d05700002053d036d05700002031b05700002031b0342020000002803200321031703170313057000020321057100030317031603120342034c03160342053d036d0342020000066b072e020000038d03210317034c0316034c03210317034c0316034c03210317034c0316034c03210317034c0316034c034003190328072c020000000c05200005074303620003032702000003470743036a000003130319032a072c020000000c0520000507430362000a03270200000323057000040321057100050317031703160743036a000105700006032105710007031703160322072f0200000013074303680100000008444956206279203003270200000000031605700004032105710005033a0322072f020000001307430368010000000844495620627920300327020000000003160743036a0001034c033a0570000503210571000603170317031605700006032105710007031605700005032105710006033a0322072f02000000130743036801000000084449562062792030032702000000000316057000030570000203210571000303190337072c020000000c0520000607430362000b0327020000022e05700002034c03210571000203190337072c020000000c0520000507430362000d032702000002060570000203210571000305700005032105710006031703170316034b0356072f020000000807430362000e03270200000000034c032105710002057000060321057100070316034b0356072f020000000807430362000f03270200000000057000040743035b0000034b0348034205700006032105710007034c03210317034c031605700002031703170317031706550765045b00000009257175616e74697479046e00000007257461726765740000000b256d696e744f724275726e072f020000000807430362000c032702000000000743036a000005700002057000030342034d0570000305700005032105710006034203490354034205700006032105710007034c03210317034c0316034c03210317034c031605700003031703170317031606550765036e0765036e036200000009257472616e73666572072f0200000008074303620000032702000000000743036a000005700003057000030342057000030342034d05700004032105710005057000060555036c072f020000000807430362000903270200000000034c0743036c030b034d0570000603210571000703170317057000060570000703210571000803170316034b034205700006031603420321031703170317057000060342034c032105710002031703160342034c031603420317057000040342053d036d05700002031b05700002031b05700002031b034202000002d203210317034c0316034c03210317034c0316034c03210317034c0316034c03210317034c03160570000406550765046e0000000325746f0765046200000010256d696e546f6b656e73426f75676874046b0000000925646561646c696e650000000b2578747a546f546f6b656e072f020000000807430362001f032702000000000743036a000003130319032a072c020000000c0520000607430362000a0327020000022d05700002032105710003034003190328072c020000000c05200006074303620003032702000002050743036200a70f05700002032105710003033a0743036200a80f057000070321057100080316033a031205700006032105710007031703160743036200a70f05700004032105710005033a033a0322072f020000001307430368010000000844495620627920300327020000000003160743036200a80f0743036200a70f05700002032105710003033a0322072f02000000130743036801000000084449562062792030032702000000000316057000070321057100080317057000040321057100050570000903210571000a031603120342032103170317057000030321057100040570000a03170316034b0342034c031603420570000403490354034203480342034c032105710002034c03210317034c0316034c03210317034c031605700003031703170317031606550765036e0765036e036200000009257472616e73666572072f0200000008074303620000032702000000000743036a000005700003057000030342057000030342034d057000040570000303210571000405700006057000080342057000070342034d0570000305700004034b0743036e0100000024747a314b65326837734464616b484a5168385758345a3337326475314b4368736b7379550555036c072f020000000807430362000903270200000000034c0743036c030b034d05700003053d036d05700002031b05700002031b05700002031b0342020000058d072e02000002cc03210317034c0316034c03210317034c0316034c03210317034c0316034c034003190328072c020000000c05200004074303620003032702000002900743036a000003130319032a072c020000000c0520000407430362000a0327020000026c0743036200a70f05700002032105710003033a0743036200a80f057000050321057100060316033a03120743036a000105700005032105710006031703160322072f020000001307430368010000000844495620627920300327020000000003160743036200a70f05700004032105710005033a033a0322072f020000001307430368010000000844495620627920300327020000000003160743036a0001034c033a0743036200a80f0743036200a70f05700002032105710003033a0322072f0200000013074303680100000008444956206279203003270200000000031605700002034c03210571000203190337072c020000000a032007430362000803270200000000057000020321057100030349035403420348034205700005032105710006034c03210317034c0316034c03210317034c031605700003031703170317031606550765036e0765036e036200000009257472616e73666572072f0200000008074303620000032702000000000743036a000005700003057000030342057000030342034d034c032105710002057000050555036c072f020000000807430362000903270200000000034c0743036c030b034d0570000503210571000603170570000505700006032105710007031603120342032103170317057000050321057100060570000703170316034b0342034c031603420570000305700004034b0743036e0100000024747a314b65326837734464616b484a5168385758345a3337326475314b4368736b7379550555036c072f020000000807430362000903270200000000034c0743036c030b034d034c053d036d05700002031b05700002031b05700002031b034202000002b503210317034c0316034c03210317034c0316034c034003190328072c020000000c05200003074303620003032702000002830743036a000105700003032105710004031703160322072f0200000013074303680100000008444956206279203003270200000000031603130743036a0001034c0322072f020000001307430368010000000844495620627920300327020000000003160743036200a80f0743036200a70f05700002032105710003033a0322072f02000000130743036801000000084449562062792030032702000000000316032105700002034b03110743036200a70f05700002032105710003033a0743036200a80f05700004033a03120570000503210571000603160743036200a70f05700004032105710005033a033a0322072f0200000013074303680100000008444956206279203003270200000000031605700003034c03210571000203190337072c020000000a0320074303620012032702000000000321057000050321057100060316034b0356072f02000000080743036200130327020000000005700005032105710006031703170743036a000105700005033a05700006032105710007031703160312034205700005031603420317034c0342034c057000030342034903540342034c032105710002034c03210317034c0316034c03210317034c031605700003031703170317031606550765036e0765036e036200000009257472616e73666572072f0200000008074303620000032702000000000743036a000005700003057000030342057000030342034d0743036a000105700003033a0743036e0100000024747a314b65326837734464616b484a5168385758345a3337326475314b4368736b7379550555036c072f020000000807430362000903270200000000034c0743036c030b034d05700002053d036d05700002031b05700002031b0342" + +let script_bytes : Bytes.t = Hex.to_bytes script_hex + +let script_opt : Script_repr.expr option = + Data_encoding.Binary.of_bytes_opt Script_repr.expr_encoding script_bytes + +let script : Script_repr.expr = + Option.value_f ~default:(fun () -> assert false) script_opt diff --git a/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_lqt.ml b/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_lqt.ml new file mode 100644 index 000000000000..edf0a5397d22 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_lqt.ml @@ -0,0 +1,11 @@ +let script_hex : Hex.t = + `Hex + "020000070005000764076407640865046e00000008257370656e6465720462000000062576616c75650000000825617070726f766508650865046e00000006256f776e6572046e00000008257370656e646572000000082572657175657374065a0362000000092563616c6c6261636b0000000d25676574416c6c6f77616e636507640865046e00000006256f776e6572065a0362000000092563616c6c6261636b0000000b2567657442616c616e63650865046c000000082572657175657374065a0362000000092563616c6c6261636b0000000f25676574546f74616c537570706c7907640865045b00000009257175616e74697479046e00000007257461726765740000000b256d696e744f724275726e0865046e000000052566726f6d0765046e0000000325746f0462000000062576616c756500000009257472616e73666572050107650861036e03620000000725746f6b656e73076508610765046e00000006256f776e6572046e00000008257370656e64657203620000000b25616c6c6f77616e6365730765046e000000062561646d696e04620000000d25746f74616c5f737570706c7905020200000552032103170743036a000003130319033c072c020000001607430368010000000b446f6e7453656e6454657a03270200000000034c0316072e02000001b2072e0200000132072e02000000e2034c03210571000203170316034c0321057100020316034803420743036200000570000303210571000403170319032a07430362000005700003032105710004057000030321057100040329072f020000000607430362000002000000000319032a0314072c0200000020074303680100000015556e73616665416c6c6f77616e63654368616e676503270200000000057000030321057100040317031705700002057000030317074303620000034c03210571000203190325072c02000000060320053e0362020000000203460570000303500342034c03160342053d036d03420200000044034c032105700002053d036d034c03210571000203170743036a000005700004031703160570000403160329072f02000000060743036200000200000000034d031b03420200000074072e0200000042034c032105700002053d036d034c03210571000203170743036a00000570000403160570000403160329072f02000000060743036200000200000000034d031b03420200000026034c032105700002053d036d034c03170743036a000005700003031703170317034d031b0342020000035e072e020000013c034c03210571000203170317031603480319033c072c02000000140743036801000000094f6e6c7941646d696e03270200000000032103160570000203210571000303160570000203210571000303170329072f0200000006074303620000020000000003120356072f020000003607430368010000002b43616e6e6f74206275726e206d6f7265207468616e207468652074617267657427732062616c616e63652e03270200000000034c032105710002031605700003032105710004031703170317031203110570000303210571000403170570000403160743036200000570000403210571000503190325072c020000000a057000030320053e03620200000006057000030346057000040317035003420321057100020317031703160342034c032105710002031703160342034c03160342053d036d03420200000216034c03210571000203170316057000020321057100030316057000020321057100030316034803190325072c0200000002034c02000000a903480570000303210571000403160342057000030321057100040317031705700003032105710004057000020321057100030329072f02000000060743036200000200000000034b0356072f020000001d0743036801000000124e6f74456e6f756768416c6c6f77616e636503270200000000057000030743036200000570000203210571000303190325072c0200000008034c0320053e03620200000004034c03460570000203500570000203210571000303170317057000020321057100030570000403210571000503160329072f02000000060743036200000200000000034b0356072f020000001b0743036801000000104e6f74456e6f75676842616c616e636503270200000000057000020743036200000570000203210571000303190325072c0200000008034c0320053e03620200000004034c034605700003032105710004031603500570000203210571000303170317034c03210571000205700004032105710005031703160329072f020000000607430362000002000000000312034c0743036200000570000203210571000303190325072c0200000008034c0320053e03620200000004034c034605700003031703160350057000020317034c0342032103170317057000020342034c03160342053d036d0342" + +let script_bytes : Bytes.t = Hex.to_bytes script_hex + +let script_opt : Script_repr.expr option = + Data_encoding.Binary.of_bytes_opt Script_repr.expr_encoding script_bytes + +let script : Script_repr.expr = + Option.value_f ~default:(fun () -> assert false) script_opt diff --git a/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_migration.ml b/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_migration.ml new file mode 100644 index 000000000000..aec13a095f49 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_migration.ml @@ -0,0 +1,217 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Tocqueville Group, Inc. *) +(* *) +(* 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 is used to originate contracts for liquidity baking during + protocol stitching: a CPMM (constant product market making) contract and a + liquidity token FA1.2 contract, with the storage of each containing the + other's address. + + The CPMM's storage contains a token address, which corresponds to tzBTC when + originated on mainnet and a reference FA1.2 contract when originated for + testing. + + The test FA1.2 contract uses the same script as the liquidity token. Its + manager is initialized to the first bootstrap account. Before originating it, + we make sure we are not on mainnet by both checking for the existence of the + tzBTC contract and that the level is sufficiently low. + + The Michelson and Ligo code, as well as Coq proofs, for the CPMM and + liquidity token contracts are available here: + https://gitlab.com/dexter2tz/dexter2tz/-/tree/liquidity_baking + + All contracts were generated from Ligo at revision + 4d10d07ca05abe0f8a5fb97d15267bf5d339d9f4 and converted to OCaml using + `tezos-client convert`. +*) + +open Michelson_v1_primitives +open Micheline + +let null_address = + Bytes.of_string + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + +let mainnet_tzBTC_address = "KT1PWx2mnDueood7fEmfbBDKx1D9BAnnXitn" + +(** If token_pool, xtz_pool, or lqt_total are ever zero the CPMM will be + permanently broken. Therefore, we initialize it with the null address + registered as a liquidity provider with 1 satoshi tzBTC and 100 mutez + (roughly the current exchange rate). *) +let cpmm_init_storage ~token_address ~lqt_address = + Script_repr.lazy_expr + (Micheline.strip_locations + (Prim + ( 0, + D_Pair, + [ + Int (1, Z.one); + Int (2, Z.of_int 100); + Int (3, Z.of_int 100); + String (4, token_address); + String (5, lqt_address); + ], + [] ))) + +let lqt_init_storage cpmm_address = + Script_repr.lazy_expr + (Micheline.strip_locations + (Prim + ( 0, + D_Pair, + [ + Seq + ( 1, + [ + Prim + ( 2, + D_Elt, + [Bytes (3, null_address); Int (4, Z.of_int 100)], + [] ); + ] ); + Seq (5, []); + String (6, cpmm_address); + Int (7, Z.of_int 100); + ], + [] ))) + +let test_fa12_init_storage manager = + Script_repr.lazy_expr + (Micheline.strip_locations + (Prim + ( 0, + D_Pair, + [ + Seq (1, []); + Seq (2, []); + String (3, manager); + Int (4, Z.of_int 10_000); + ], + [] ))) + +let originate ctxt address ~balance script = + Contract_storage.raw_originate ctxt address ~balance ~script ~delegate:None + >>=? fun ctxt -> + Fees_storage.record_paid_storage_space_subsidy ctxt address + >>=? fun (ctxt, size, paid_storage_size_diff) -> + let result : Migration_repr.origination_result = + { + balance_updates = + Receipt_repr.[(Contract address, Credited balance, Protocol_migration)]; + originated_contracts = [address]; + storage_size = size; + paid_storage_size_diff; + } + in + return (ctxt, result) + +let originate_test_fa12 ~typecheck ctxt admin = + Contract_storage.fresh_contract_from_current_nonce ctxt + >>?= fun (ctxt, fa12_address) -> + let script = + Script_repr. + { + code = Script_repr.lazy_expr Liquidity_baking_lqt.script; + storage = + test_fa12_init_storage (Signature.Public_key_hash.to_b58check admin); + } + in + typecheck ctxt script >>=? fun (script, ctxt) -> + originate ctxt fa12_address ~balance:(Tez_repr.of_mutez_exn 1_000_000L) script + >|=? fun (ctxt, origination_result) -> + (ctxt, fa12_address, [origination_result]) + +(* hardcoded from lib_parameters *) +let first_bootstrap_account = + Signature.Public_key.hash + (Signature.Public_key.of_b58check_exn + "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav") + +let check_tzBTC ~typecheck current_level ctxt f = + Contract_repr.of_b58check mainnet_tzBTC_address >>?= fun tzBTC -> + Contract_storage.exists ctxt tzBTC >>=? function + | true -> + (* If tzBTC exists, we're on mainnet and we use it as the token address in the CPMM. *) + f ctxt tzBTC [] + | false -> + (* If the tzBTC contract does not exist, we originate a test FA1.2 contract using the same script as the LQT. This is so that we can test the contracts after performing the same protocol migration that will be done on mainnet. + + First, we check current level is below mainnet level roughly around 010 injection so we do not accidentally originate the test token contract on mainnet. *) + if Compare.Int32.(current_level < 1_437_862l) then + originate_test_fa12 ~typecheck ctxt first_bootstrap_account + (* Token contract admin *) + >>=? fun (ctxt, token_address, token_result) -> + f ctxt token_address token_result + else + (* If we accidentally entered the tzBTC address incorrectly, but current level indicates this could be mainnet, we do not originate any contracts *) + return (ctxt, []) + +let init ctxt ~typecheck = + (* We use a custom origination nonce because it is unset when stitching from 009 *) + let nonce = Operation_hash.hash_string ["Drip, drip, drip."] in + let ctxt = Raw_context.init_origination_nonce ctxt nonce in + Storage.Liquidity_baking.Escape_ema.init ctxt 0l >>=? fun ctxt -> + let current_level = + Raw_level_repr.to_int32 (Level_storage.current ctxt).level + in + Contract_storage.fresh_contract_from_current_nonce ctxt + >>?= fun (ctxt, cpmm_address) -> + Contract_storage.fresh_contract_from_current_nonce ctxt + >>?= fun (ctxt, lqt_address) -> + Storage.Liquidity_baking.Cpmm_address.init ctxt cpmm_address >>=? fun ctxt -> + check_tzBTC + ~typecheck + current_level + ctxt + (fun ctxt token_address token_result -> + let cpmm_script = + Script_repr. + { + code = Script_repr.lazy_expr Liquidity_baking_cpmm.script; + storage = + cpmm_init_storage + ~token_address:(Contract_repr.to_b58check token_address) + ~lqt_address:(Contract_repr.to_b58check lqt_address); + } + in + typecheck ctxt cpmm_script >>=? fun (cpmm_script, ctxt) -> + let lqt_script = + Script_repr. + { + code = Script_repr.lazy_expr Liquidity_baking_lqt.script; + storage = lqt_init_storage (Contract_repr.to_b58check cpmm_address); + } + in + typecheck ctxt lqt_script >>=? fun (lqt_script, ctxt) -> + originate + ctxt + cpmm_address + ~balance:(Tez_repr.of_mutez_exn 100L) + cpmm_script + >>=? fun (ctxt, cpmm_result) -> + originate ctxt lqt_address ~balance:Tez_repr.zero lqt_script + >|=? fun (ctxt, lqt_result) -> + (* Unsets the origination nonce, which is okay because this is called after other originations in stitching. *) + let ctxt = Raw_context.unset_origination_nonce ctxt in + (ctxt, [cpmm_result; lqt_result] @ token_result)) diff --git a/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_migration.mli b/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_migration.mli new file mode 100644 index 000000000000..27059e493d50 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_migration.mli @@ -0,0 +1,33 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Tocqueville Group, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val init : + Raw_context.t -> + typecheck: + (Raw_context.t -> + Script_repr.t -> + ((Script_repr.t * Lazy_storage_diff.diffs option) * Raw_context.t) tzresult + Lwt.t) -> + (Raw_context.t * Migration_repr.origination_result list) tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_repr.ml b/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_repr.ml new file mode 100644 index 000000000000..2dc35196d273 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_repr.ml @@ -0,0 +1,71 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Tocqueville Group, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let get_cpmm_address = Storage.Liquidity_baking.Cpmm_address.get + +let get_escape_ema = Storage.Liquidity_baking.Escape_ema.get + +type escape_ema = Int32.t + +let on_cpmm_exists ctxt f = + get_cpmm_address ctxt >>=? fun cpmm_contract -> + Contract_storage.exists ctxt cpmm_contract >>=? function + | false -> + (* do nothing if the cpmm is not found *) + return (ctxt, []) + | true -> f ctxt cpmm_contract + +let on_below_sunset ctxt f = + let sunset_level = Constants_storage.liquidity_baking_sunset_level ctxt in + let level = Raw_level_repr.to_int32 (Level_storage.current ctxt).level in + if Compare.Int32.(level >= sunset_level) then return (ctxt, []) + else on_cpmm_exists ctxt f + +(* ema starts at zero + ema[n+1] = (1999 * ema[n] // 2000) + (1000 if escape_vote[n] else 0) + where escape_vote is protocol_data.contents.liquidity_baking_escape_vote *) +let update_escape_ema ctxt ~escape_vote = + get_escape_ema ctxt >>=? fun old_ema -> + (* if ema is over threshold, we don't update it because liquidity baking is permanently off *) + if + Compare.Int32.( + old_ema < Constants_storage.liquidity_baking_escape_ema_threshold ctxt) + then + let new_ema = + Int32.( + add (div (mul 1999l old_ema) 2000l) (if escape_vote then 1000l else 0l)) + in + Storage.Liquidity_baking.Escape_ema.update ctxt new_ema >|=? fun ctxt -> + (ctxt, new_ema, false) + else return (ctxt, old_ema, true) + +let on_subsidy_allowed ctxt ~escape_vote f = + update_escape_ema ctxt ~escape_vote + >>=? fun (ctxt, escape_ema, threshold_reached) -> + (* liquidity baking permanently shuts off if threshold is reached once *) + if threshold_reached then return (ctxt, [], escape_ema) + else + on_below_sunset ctxt f >|=? fun (ctxt, operation_results) -> + (ctxt, operation_results, escape_ema) diff --git a/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_repr.mli b/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_repr.mli new file mode 100644 index 000000000000..f631ec4ddf4a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/liquidity_baking_repr.mli @@ -0,0 +1,36 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Tocqueville Group, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val get_cpmm_address : Raw_context.t -> Contract_repr.t tzresult Lwt.t + +type escape_ema = Int32.t + +(** Checks if below EMA threshold (after updating), sunset level, and if CPMM + contract exists. *) +val on_subsidy_allowed : + Raw_context.t -> + escape_vote:bool -> + (Raw_context.t -> Contract_repr.t -> (Raw_context.t * 'a list) tzresult Lwt.t) -> + (Raw_context.t * 'a list * escape_ema) tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/main.ml b/src/proto_011_PtHangzH/lib_protocol/main.ml new file mode 100644 index 000000000000..d134876737f2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/main.ml @@ -0,0 +1,497 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Tezos Protocol Implementation - Protocol Signature Instance *) + +type block_header_data = Alpha_context.Block_header.protocol_data + +type block_header = Alpha_context.Block_header.t = { + shell : Block_header.shell_header; + protocol_data : block_header_data; +} + +let block_header_data_encoding = + Alpha_context.Block_header.protocol_data_encoding + +type block_header_metadata = Apply_results.block_metadata + +let block_header_metadata_encoding = Apply_results.block_metadata_encoding + +type operation_data = Alpha_context.packed_protocol_data = + | Operation_data : + 'kind Alpha_context.Operation.protocol_data + -> operation_data + +let operation_data_encoding = Alpha_context.Operation.protocol_data_encoding + +type operation_receipt = Apply_results.packed_operation_metadata = + | Operation_metadata : + 'kind Apply_results.operation_metadata + -> operation_receipt + | No_operation_metadata : operation_receipt + +let operation_receipt_encoding = Apply_results.operation_metadata_encoding + +let operation_data_and_receipt_encoding = + Apply_results.operation_data_and_metadata_encoding + +type operation = Alpha_context.packed_operation = { + shell : Operation.shell_header; + protocol_data : operation_data; +} + +let acceptable_passes = Alpha_context.Operation.acceptable_passes + +let max_block_length = Alpha_context.Block_header.max_header_length + +let max_operation_data_length = + Alpha_context.Constants.max_operation_data_length + +let validation_passes = + let open Alpha_context.Constants in + Updater. + [ + (* 2048 endorsements *) + {max_size = 2048 * 2048; max_op = Some 2048}; + (* 32k of voting operations *) + {max_size = 32 * 1024; max_op = None}; + (* revelations, wallet activations and denunciations *) + { + max_size = max_anon_ops_per_block * 1024; + max_op = Some max_anon_ops_per_block; + }; + (* 512kB *) + {max_size = 512 * 1024; max_op = None}; + ] + +let rpc_services = + Alpha_services.register () ; + Services_registration.get_rpc_services () + +type validation_mode = + | Application of { + block_header : Alpha_context.Block_header.t; + baker : Alpha_context.public_key_hash; + } + | Partial_application of { + block_header : Alpha_context.Block_header.t; + baker : Alpha_context.public_key_hash; + } + | Partial_construction of {predecessor : Block_hash.t} + | Full_construction of { + predecessor : Block_hash.t; + protocol_data : Alpha_context.Block_header.contents; + baker : Alpha_context.public_key_hash; + } + +type validation_state = { + mode : validation_mode; + chain_id : Chain_id.t; + ctxt : Alpha_context.t; + op_count : int; + migration_balance_updates : Alpha_context.Receipt.balance_updates; + liquidity_baking_escape_ema : Int32.t; + implicit_operations_results : + Apply_results.packed_successful_manager_operation_result list; +} + +let cache_layout = Apply.cache_layout + +let begin_partial_application ~chain_id ~ancestor_context:ctxt + ~predecessor_timestamp ~predecessor_fitness + (block_header : Alpha_context.Block_header.t) = + let level = block_header.shell.level in + let fitness = predecessor_fitness in + let timestamp = block_header.shell.timestamp in + Alpha_context.prepare ~level ~predecessor_timestamp ~timestamp ~fitness ctxt + >>=? fun (ctxt, migration_balance_updates, migration_operation_results) -> + Apply.begin_application ctxt chain_id block_header predecessor_timestamp + >|=? fun ( ctxt, + baker, + liquidity_baking_operations_results, + liquidity_baking_escape_ema ) -> + let mode = + Partial_application {block_header; baker = Signature.Public_key.hash baker} + in + { + mode; + chain_id; + ctxt; + op_count = 0; + migration_balance_updates; + liquidity_baking_escape_ema; + implicit_operations_results = + Apply_results.pack_migration_operation_results migration_operation_results + @ liquidity_baking_operations_results; + } + +let begin_application ~chain_id ~predecessor_context:ctxt ~predecessor_timestamp + ~predecessor_fitness (block_header : Alpha_context.Block_header.t) = + let level = block_header.shell.level in + let fitness = predecessor_fitness in + let timestamp = block_header.shell.timestamp in + Alpha_context.prepare ~level ~predecessor_timestamp ~timestamp ~fitness ctxt + >>=? fun (ctxt, migration_balance_updates, migration_operation_results) -> + Apply.begin_application ctxt chain_id block_header predecessor_timestamp + >|=? fun ( ctxt, + baker, + liquidity_baking_operations_results, + liquidity_baking_escape_ema ) -> + let mode = + Application {block_header; baker = Signature.Public_key.hash baker} + in + { + mode; + chain_id; + ctxt; + op_count = 0; + migration_balance_updates; + liquidity_baking_escape_ema; + implicit_operations_results = + Apply_results.pack_migration_operation_results migration_operation_results + @ liquidity_baking_operations_results; + } + +let begin_construction ~chain_id ~predecessor_context:ctxt + ~predecessor_timestamp ~predecessor_level:pred_level + ~predecessor_fitness:pred_fitness ~predecessor ~timestamp + ?(protocol_data : block_header_data option) () = + let level = Int32.succ pred_level in + let fitness = pred_fitness in + Alpha_context.prepare ~level ~predecessor_timestamp ~timestamp ~fitness ctxt + >>=? fun (ctxt, migration_balance_updates, migration_operation_results) -> + (match protocol_data with + | None -> + let escape_vote = false in + Apply.begin_partial_construction ctxt ~escape_vote + >|=? fun ( ctxt, + liquidity_baking_operations_results, + liquidity_baking_escape_ema ) -> + let mode = Partial_construction {predecessor} in + ( mode, + ctxt, + liquidity_baking_operations_results, + liquidity_baking_escape_ema ) + | Some proto_header -> + Apply.begin_full_construction + ctxt + predecessor_timestamp + proto_header.contents + >|=? fun ( ctxt, + protocol_data, + baker, + liquidity_baking_operations_results, + liquidity_baking_escape_ema ) -> + let mode = + let baker = Signature.Public_key.hash baker in + Full_construction {predecessor; baker; protocol_data} + in + ( mode, + ctxt, + liquidity_baking_operations_results, + liquidity_baking_escape_ema )) + >|=? fun ( mode, + ctxt, + liquidity_baking_operations_results, + liquidity_baking_escape_ema ) -> + { + mode; + chain_id; + ctxt; + op_count = 0; + migration_balance_updates; + liquidity_baking_escape_ema; + implicit_operations_results = + Apply_results.pack_migration_operation_results migration_operation_results + @ liquidity_baking_operations_results; + } + +let apply_operation ({mode; chain_id; ctxt; op_count; _} as data) + (operation : Alpha_context.packed_operation) = + match mode with + | Partial_application _ + when not + (List.exists + (Compare.Int.equal 0) + (Alpha_context.Operation.acceptable_passes operation)) -> + (* Multipass validation only considers operations in pass 0. *) + let op_count = op_count + 1 in + return ({data with ctxt; op_count}, No_operation_metadata) + | _ -> + let {shell; protocol_data = Operation_data protocol_data} = operation in + let operation : _ Alpha_context.operation = {shell; protocol_data} in + let (predecessor, baker) = + match mode with + | Partial_application + {block_header = {shell = {predecessor; _}; _}; baker} + | Application {block_header = {shell = {predecessor; _}; _}; baker} + | Full_construction {predecessor; baker; _} -> + (predecessor, baker) + | Partial_construction {predecessor} -> + (predecessor, Signature.Public_key_hash.zero) + in + Apply.apply_operation + ctxt + chain_id + Optimized + predecessor + baker + (Alpha_context.Operation.hash operation) + operation + >|=? fun (ctxt, result) -> + let op_count = op_count + 1 in + ({data with ctxt; op_count}, Operation_metadata result) + +let cache_nonce_from_block_header shell contents = + Block_hash.to_bytes + Alpha_context.Block_header.( + let shell = + Block_header. + { + shell with + context = Context_hash.zero; + fitness = []; + proto_level = 0; + level = 0l; + validation_passes = 0; + timestamp = Time.of_seconds 0L; + } + in + let contents = + { + contents with + proof_of_work_nonce = + Bytes.make Constants_repr.proof_of_work_nonce_size '0'; + } + in + let protocol_data = {signature = Signature.zero; contents} in + hash {shell; protocol_data}) + +type error += Missing_shell_header + +let () = + register_error_kind + `Permanent + ~id:"main.missing_shell_header" + ~title:"Missing shell_header during finalisation of a block" + ~description: + "During finalisation of a block header in Application mode or Full \ + construction mode, a shell header should be provided so that a cache \ + nonce can be computed." + ~pp:(fun ppf () -> + Format.fprintf + ppf + "No shell header provided during the finalisation of a block.") + Data_encoding.unit + (function Missing_shell_header -> Some () | _ -> None) + (fun () -> Missing_shell_header) + +let finalize_block + { + mode; + ctxt; + op_count; + migration_balance_updates; + liquidity_baking_escape_ema; + implicit_operations_results; + _; + } shell_header = + match mode with + | Partial_construction _ -> + Alpha_context.Voting_period.get_rpc_current_info ctxt + >|=? fun voting_period_info -> + let level_info = Alpha_context.Level.current ctxt in + let baker = Signature.Public_key_hash.zero in + let ctxt = Alpha_context.finalize ctxt in + ( ctxt, + Apply_results. + { + baker; + level_info; + voting_period_info; + nonce_hash = None; + consumed_gas = Alpha_context.Gas.Arith.zero; + deactivated = []; + balance_updates = migration_balance_updates; + liquidity_baking_escape_ema; + implicit_operations_results; + } ) + | Partial_application {block_header; baker} -> + let included_endorsements = Alpha_context.included_endorsements ctxt in + Apply.check_minimal_valid_time + ctxt + ~priority:block_header.protocol_data.contents.priority + ~endorsing_power:included_endorsements + >>?= fun () -> + Alpha_context.Voting_period.get_rpc_current_info ctxt + >|=? fun voting_period_info -> + let level_info = Alpha_context.Level.current ctxt in + let ctxt = Alpha_context.finalize ctxt in + ( ctxt, + Apply_results. + { + baker; + level_info; + voting_period_info; + nonce_hash = None; + consumed_gas = Alpha_context.Gas.Arith.zero; + deactivated = []; + balance_updates = migration_balance_updates; + liquidity_baking_escape_ema; + implicit_operations_results; + } ) + | Application + {baker; block_header = {protocol_data = {contents = protocol_data; _}; _}} + | Full_construction {protocol_data; baker; _} -> + Apply.finalize_application + ctxt + protocol_data + baker + migration_balance_updates + liquidity_baking_escape_ema + implicit_operations_results + >>=? fun (ctxt, receipt) -> + let level = Alpha_context.Level.current ctxt in + let priority = protocol_data.priority in + let raw_level = Alpha_context.Raw_level.to_int32 level.level in + let fitness = Alpha_context.Fitness.current ctxt in + let commit_message = + Format.asprintf + "lvl %ld, fit 1:%Ld, prio %d, %d ops" + raw_level + fitness + priority + op_count + in + Option.value_e + shell_header + ~error:(Error_monad.trace_of_error Missing_shell_header) + >>?= fun shell_header -> + let cache_nonce = + cache_nonce_from_block_header + {shell_header with fitness = Alpha_context.Fitness.from_int64 fitness} + protocol_data + in + Alpha_context.Cache.Admin.sync ctxt ~cache_nonce >>= fun ctxt -> + let ctxt = Alpha_context.finalize ~commit_message ctxt in + return (ctxt, receipt) + +let relative_position_within_block op1 op2 = + let open Alpha_context in + let (Operation_data op1) = op1.protocol_data in + let (Operation_data op2) = op2.protocol_data in + match[@coq_match_with_default] (op1.contents, op2.contents) with + | (Single (Endorsement _), Single (Endorsement _)) -> 0 + | (_, Single (Endorsement _)) -> 1 + | (Single (Endorsement _), _) -> -1 + | (Single (Seed_nonce_revelation _), Single (Seed_nonce_revelation _)) -> 0 + | (_, Single (Seed_nonce_revelation _)) -> 1 + | (Single (Seed_nonce_revelation _), _) -> -1 + | ( Single (Double_endorsement_evidence _), + Single (Double_endorsement_evidence _) ) -> + 0 + | (_, Single (Double_endorsement_evidence _)) -> 1 + | (Single (Double_endorsement_evidence _), _) -> -1 + | (Single (Endorsement_with_slot _), Single (Endorsement_with_slot _)) -> 0 + | (_, Single (Endorsement_with_slot _)) -> 1 + | (Single (Endorsement_with_slot _), _) -> -1 + | (Single (Double_baking_evidence _), Single (Double_baking_evidence _)) -> 0 + | (_, Single (Double_baking_evidence _)) -> 1 + | (Single (Double_baking_evidence _), _) -> -1 + | (Single (Activate_account _), Single (Activate_account _)) -> 0 + | (_, Single (Activate_account _)) -> 1 + | (Single (Activate_account _), _) -> -1 + | (Single (Proposals _), Single (Proposals _)) -> 0 + | (_, Single (Proposals _)) -> 1 + | (Single (Proposals _), _) -> -1 + | (Single (Ballot _), Single (Ballot _)) -> 0 + | (_, Single (Ballot _)) -> 1 + | (Single (Ballot _), _) -> -1 + | (Single (Failing_noop _), Single (Failing_noop _)) -> 0 + | (_, Single (Failing_noop _)) -> 1 + | (Single (Failing_noop _), _) -> -1 + (* Manager operations with smaller counter are pre-validated first. *) + | (Single (Manager_operation op1), Single (Manager_operation op2)) -> + Z.compare op1.counter op2.counter + | (Cons (Manager_operation op1, _), Single (Manager_operation op2)) -> + Z.compare op1.counter op2.counter + | (Single (Manager_operation op1), Cons (Manager_operation op2, _)) -> + Z.compare op1.counter op2.counter + | (Cons (Manager_operation op1, _), Cons (Manager_operation op2, _)) -> + Z.compare op1.counter op2.counter + +let init_context ctxt = + Context.Cache.set_cache_layout ctxt cache_layout >>= fun ctxt -> + Lwt.return @@ Context.Cache.clear ctxt + +let init ctxt block_header = + let level = block_header.Block_header.level in + let fitness = block_header.fitness in + let timestamp = block_header.timestamp in + let typecheck (ctxt : Alpha_context.context) (script : Alpha_context.Script.t) + = + let allow_forged_in_storage = + false + (* There should be no forged value in bootstrap contracts. *) + in + Script_ir_translator.parse_script + ctxt + ~legacy:false + ~allow_forged_in_storage + script + >>=? fun (Ex_script parsed_script, ctxt) -> + Script_ir_translator.extract_lazy_storage_diff + ctxt + Optimized + parsed_script.storage_type + parsed_script.storage + ~to_duplicate:Script_ir_translator.no_lazy_storage_id + ~to_update:Script_ir_translator.no_lazy_storage_id + ~temporary:false + >>=? fun (storage, lazy_storage_diff, ctxt) -> + Script_ir_translator.unparse_data + ctxt + Optimized + parsed_script.storage_type + storage + >|=? fun (storage, ctxt) -> + let storage = + Alpha_context.Script.lazy_expr (Micheline.strip_locations storage) + in + (({script with storage}, lazy_storage_diff), ctxt) + in + init_context ctxt >>= fun ctxt -> + Alpha_context.prepare_first_block ~typecheck ~level ~timestamp ~fitness ctxt + >>=? fun ctxt -> return (Alpha_context.finalize ctxt) + +let value_of_key ~chain_id:_ ~predecessor_context:ctxt ~predecessor_timestamp + ~predecessor_level:pred_level ~predecessor_fitness:pred_fitness + ~predecessor:_ ~timestamp = + let level = Int32.succ pred_level in + let fitness = pred_fitness in + Alpha_context.prepare ~level ~predecessor_timestamp ~timestamp ~fitness ctxt + >>=? fun (ctxt, _, _) -> return (Apply.value_of_key ctxt) + +(* Vanity nonce: 0105005008491999 *) diff --git a/src/proto_011_PtHangzH/lib_protocol/main.mli b/src/proto_011_PtHangzH/lib_protocol/main.mli new file mode 100644 index 000000000000..726b38668eb8 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/main.mli @@ -0,0 +1,87 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Tezos Protocol Implementation - Protocol Signature Instance + + This module is the entrypoint to the protocol for shells and other + embedders. This signature is an instance of + {{!Tezos_protocol_environment_sigs.V3.T.Updater.PROTOCOL} the + [Updater.PROTOCOL] signature} from the + {{:https://tezos.gitlab.io/shell/the_big_picture.html#the-economic-protocol-environment-and-compiler} + Protocol Environment}. + + Each Protocol depends on a version of the Protocol Environment. For the + currently developed protocol, this is normally the latest version. You can + see {{!Tezos_protocol_environment_sigs} the full list of versions here}. + + For details on how Protocol and Environment interact, see + {{:https://tezos.gitlab.io/shell/the_big_picture.html} this overview}. + *) + +type validation_mode = + | Application of { + block_header : Alpha_context.Block_header.t; + baker : Alpha_context.public_key_hash; + } + | Partial_application of { + block_header : Alpha_context.Block_header.t; + baker : Alpha_context.public_key_hash; + } + | Partial_construction of {predecessor : Block_hash.t} + | Full_construction of { + predecessor : Block_hash.t; + protocol_data : Alpha_context.Block_header.contents; + baker : Alpha_context.public_key_hash; + } + +type validation_state = { + mode : validation_mode; + chain_id : Chain_id.t; + ctxt : Alpha_context.t; + op_count : int; + migration_balance_updates : Alpha_context.Receipt.balance_updates; + liquidity_baking_escape_ema : Int32.t; + implicit_operations_results : + Apply_results.packed_successful_manager_operation_result list; +} + +type operation_data = Alpha_context.packed_protocol_data + +type operation = Alpha_context.packed_operation = { + shell : Operation.shell_header; + protocol_data : operation_data; +} + +val init_context : Context.t -> Context.t Lwt.t + +include + Updater.PROTOCOL + with type block_header_data = Alpha_context.Block_header.protocol_data + and type block_header_metadata = Apply_results.block_metadata + and type block_header = Alpha_context.Block_header.t + and type operation_data := operation_data + and type operation_receipt = Apply_results.packed_operation_metadata + and type operation := operation + and type validation_state := validation_state diff --git a/src/proto_011_PtHangzH/lib_protocol/manager_repr.ml b/src/proto_011_PtHangzH/lib_protocol/manager_repr.ml new file mode 100644 index 000000000000..b96a51401289 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/manager_repr.ml @@ -0,0 +1,52 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Tezos Protocol Implementation - Low level Repr. of Managers' keys *) + +type manager_key = + | Hash of Signature.Public_key_hash.t + | Public_key of Signature.Public_key.t + +type t = manager_key + +open Data_encoding + +let hash_case tag = + case + tag + ~title:"Public_key_hash" + Signature.Public_key_hash.encoding + (function Hash hash -> Some hash | _ -> None) + (fun hash -> Hash hash) + +let pubkey_case tag = + case + tag + ~title:"Public_key" + Signature.Public_key.encoding + (function Public_key hash -> Some hash | _ -> None) + (fun hash -> Public_key hash) + +let encoding = union [hash_case (Tag 0); pubkey_case (Tag 1)] diff --git a/src/proto_011_PtHangzH/lib_protocol/manager_repr.mli b/src/proto_011_PtHangzH/lib_protocol/manager_repr.mli new file mode 100644 index 000000000000..18ca236d71b1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/manager_repr.mli @@ -0,0 +1,38 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Tezos Protocol Implementation - Low level Repr. of Managers' keys *) + +(** The public key of the manager of a contract is reveled only after the + first operation. At Origination time, the manager provides only the hash + of its public key that is stored in the contract. When the public key + is actually revealed, the public key instead of the hash of the key *) +type manager_key = + | Hash of Signature.Public_key_hash.t + | Public_key of Signature.Public_key.t + +type t = manager_key + +val encoding : t Data_encoding.encoding diff --git a/src/proto_011_PtHangzH/lib_protocol/michelson_v1_gas.ml b/src/proto_011_PtHangzH/lib_protocol/michelson_v1_gas.ml new file mode 100644 index 000000000000..7135f7c8a5f6 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/michelson_v1_gas.ml @@ -0,0 +1,1820 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Gas +module S = Saturation_repr + +module Cost_of = struct + module S_syntax = struct + (* This is a good enough approximation. S.numbits 0 = 0 *) + let log2 x = S.safe_int (1 + S.numbits x) + + let ( + ) = S.add + + let ( * ) = S.mul + + let ( lsr ) = S.shift_right + end + + let z_bytes (z : Z.t) = + let bits = Z.numbits z in + (7 + bits) / 8 + + let int_bytes (z : 'a Script_int.num) = z_bytes (Script_int.to_zint z) + + let manager_operation = step_cost @@ S.safe_int 1_000 + + module Generated_costs = struct + (* Automatically generated costs functions. *) + + (* model N_IAbs_int *) + (* Approximating 0.065045 x term *) + let cost_N_IAbs_int size = S.safe_int (25 + (size lsr 4)) + + (* model N_IAdd_bls12_381_fr *) + let cost_N_IAdd_bls12_381_fr = S.safe_int 145 + + (* model N_IAdd_bls12_381_g1 *) + let cost_N_IAdd_bls12_381_g1 = S.safe_int 8_300 + + (* model N_IAdd_bls12_381_g2 *) + let cost_N_IAdd_bls12_381_g2 = S.safe_int 11_450 + + let cost_linear_op_int size1 size2 = + let open S_syntax in + let v0 = S.safe_int (Compare.Int.max size1 size2) in + S.safe_int 35 + ((v0 lsr 4) + (v0 lsr 7)) + + (* model N_IAdd_intint *) + (* Approximating 0.077989 x term *) + let cost_N_IAdd_intint = cost_linear_op_int + + (* model N_IAdd_intnat *) + (* Approximating 0.077997 x term *) + let cost_N_IAdd_intnat = cost_linear_op_int + + (* model N_IAdd_natint *) + (* Approximating 0.078154 x term *) + let cost_N_IAdd_natint = cost_linear_op_int + + (* model N_IAdd_natnat *) + (* Approximating 0.077807 x term *) + let cost_N_IAdd_natnat = cost_linear_op_int + + (* model N_IAdd_seconds_to_timestamp *) + (* Approximating 0.078056 x term *) + let cost_N_IAdd_seconds_to_timestamp = cost_linear_op_int + + (* model N_IAdd_tez *) + let cost_N_IAdd_tez = S.safe_int 25 + + (* model N_IAdd_timestamp_to_seconds *) + (* Approximating 0.077771 x term *) + let cost_N_IAdd_timestamp_to_seconds = cost_linear_op_int + + (* model N_IAddress *) + let cost_N_IAddress = S.safe_int 10 + + (* model N_IAmount *) + let cost_N_IAmount = S.safe_int 15 + + (* model N_IAnd *) + let cost_N_IAnd = S.safe_int 20 + + (* model N_IAnd_int_nat *) + (* Approximating 0.076804 x 2 x term *) + let cost_N_IAnd_int_nat size1 size2 = + let open S_syntax in + let v0 = S.safe_int (Compare.Int.min size1 size2) in + S.safe_int 35 + ((v0 lsr 3) + (v0 lsr 6)) + + (* model N_IAnd_nat *) + (* Approximating 0.076804 x term *) + let cost_N_IAnd_nat size1 size2 = + let open S_syntax in + let v0 = S.safe_int (Compare.Int.min size1 size2) in + S.safe_int 35 + ((v0 lsr 4) + (v0 lsr 7)) + + (* model N_IApply *) + let cost_N_IApply = S.safe_int 135 + + (* model N_IBlake2b *) + (* Approximating 1.120804 x term *) + let cost_N_IBlake2b size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 605 + v0 + (v0 lsr 3) + + (* model N_IBytes_size *) + let cost_N_IBytes_size = S.safe_int 15 + + (* model N_ICar *) + let cost_N_ICar = S.safe_int 10 + + (* model N_ICdr *) + let cost_N_ICdr = S.safe_int 10 + + (* model N_IChainId *) + let cost_N_IChainId = S.safe_int 15 + + (* model N_ICheck_signature_ed25519 *) + (* Approximating 1.123507 x term *) + let cost_N_ICheck_signature_ed25519 size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 242_950 + (v0 + (v0 lsr 3)) + + (* model N_ICheck_signature_p256 *) + (* Approximating 1.111539 x term *) + let cost_N_ICheck_signature_p256 size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 532_150 + (v0 + (v0 lsr 3)) + + (* model N_ICheck_signature_secp256k1 *) + (* Approximating 1.125404 x term *) + let cost_N_ICheck_signature_secp256k1 size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 49_700 + (v0 + (v0 lsr 3)) + + (* model N_IComb *) + (* Approximating 3.531001 x term *) + (* Note: size >= 2, so the cost is never 0 *) + let cost_N_IComb size = + let open S_syntax in + let v0 = S.safe_int size in + (S.safe_int 3 * v0) + (v0 lsr 1) + (v0 lsr 5) + + (* model N_IComb_get *) + (* Approximating 0.573180 x term *) + let cost_N_IComb_get size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 30 + (v0 lsr 1) + (v0 lsr 4) + + (* model N_IComb_set *) + (* Approximating 1.365745 x term *) + let cost_N_IComb_set size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 10 + (v0 + (v0 lsr 2) + (v0 lsr 3)) + + (* Model N_ICompare *) + (* Approximating 0.024413 x term *) + let cost_N_ICompare size1 size2 = + let open S_syntax in + let v0 = S.safe_int (Compare.Int.min size1 size2) in + S.safe_int 35 + ((v0 lsr 6) + (v0 lsr 7)) + + (* model N_IConcat_bytes_pair *) + (* Approximating 0.065017 x term *) + let cost_N_IConcat_bytes_pair size1 size2 = + let open S_syntax in + let v0 = S.safe_int size1 + S.safe_int size2 in + S.safe_int 65 + (v0 lsr 4) + + (* model N_IConcat_string_pair *) + (* Approximating 0.061402 x term *) + let cost_N_IConcat_string_pair size1 size2 = + let open S_syntax in + let v0 = S.safe_int size1 + S.safe_int size2 in + S.safe_int 65 + (v0 lsr 4) + + (* model N_ICons_list *) + let cost_N_ICons_list = S.safe_int 15 + + (* model N_ICons_none *) + let cost_N_ICons_none = S.safe_int 15 + + (* model N_ICons_pair *) + let cost_N_ICons_pair = S.safe_int 15 + + (* model N_ICons_some *) + let cost_N_ICons_some = S.safe_int 15 + + (* model N_IConst *) + let cost_N_IConst = S.safe_int 10 + + (* model N_IContract *) + let cost_N_IContract = S.safe_int 30 + + (* model N_ICreate_contract *) + let cost_N_ICreate_contract = S.safe_int 30 + + (* model N_IDiff_timestamps *) + (* Approximating 0.077922 x term *) + let cost_N_IDiff_timestamps = cost_linear_op_int + + (* model N_IDig *) + (* Approximating 6.750442 x term *) + let cost_N_IDig size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 20 + ((S.safe_int 6 * v0) + (v0 lsr 1) + (v0 lsr 2)) + + (* model N_IDip *) + let cost_N_IDip = S.safe_int 15 + + (* model N_IDipN *) + (* Approximating 1.708122 x term *) + let cost_N_IDipN size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 20 + (v0 + (v0 lsr 1) + (v0 lsr 3)) + + (* model N_IView *) + let cost_N_IView = S.safe_int 1370 + + (* model N_IDrop *) + let cost_N_IDrop = S.safe_int 10 + + (* model N_IDropN *) + (* Approximating 2.713108 x term *) + let cost_N_IDropN size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 20 + (S.safe_int 2 * v0) + (v0 lsr 1) + (v0 lsr 3) + + (* model N_IDug *) + (* Approximating 6.718396 x term *) + let cost_N_IDug size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 20 + ((S.safe_int 6 * v0) + (v0 lsr 1) + (v0 lsr 2)) + + (* model N_IDup *) + let cost_N_IDup = S.safe_int 10 + + (* model N_IDupN *) + (* Approximating 1.129785 x term *) + let cost_N_IDupN size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 20 + v0 + (v0 lsr 3) + + let cost_div_int size1 size2 = + let q = size1 - size2 in + if Compare.Int.(q < 0) then S.safe_int 110 + else + let open S_syntax in + let v0 = S.safe_int q * S.safe_int size2 in + S.safe_int 110 + (v0 lsr 10) + (v0 lsr 11) + (v0 lsr 13) + + (* model N_IEdiv_intint *) + (* Approximating 0.001591 x term *) + let cost_N_IEdiv_intint = cost_div_int + + (* model N_IEdiv_intnat *) + (* Approximating 0.001548 x term *) + let cost_N_IEdiv_intnat = cost_div_int + + (* model N_IEdiv_natint *) + (* Approximating 0.001535 x term *) + let cost_N_IEdiv_natint = cost_div_int + + (* model N_IEdiv_natnat *) + (* Approximating 0.001605 x term *) + let cost_N_IEdiv_natnat = cost_div_int + + (* model N_IEdiv_tez *) + let cost_N_IEdiv_tez = S.safe_int 65 + + (* model N_IEdiv_teznat *) + let cost_N_IEdiv_teznat = S.safe_int 70 + + (* model N_IEmpty_big_map *) + let cost_N_IEmpty_big_map = S.safe_int 15 + + (* model N_IEmpty_map *) + let cost_N_IEmpty_map = S.safe_int 155 + + (* model N_IEmpty_set *) + let cost_N_IEmpty_set = S.safe_int 155 + + (* model N_IEq *) + let cost_N_IEq = S.safe_int 15 + + (* model N_IExec *) + let cost_N_IExec = S.safe_int 15 + + (* model N_IFailwith *) + (* let cost_N_IFailwith = S.safe_int 105 *) + + (* model N_IGe *) + let cost_N_IGe = S.safe_int 15 + + (* model N_IGt *) + let cost_N_IGt = S.safe_int 15 + + (* model N_IHalt *) + let cost_N_IHalt = S.safe_int 15 + + (* model N_IHash_key *) + let cost_N_IHash_key = S.safe_int 655 + + (* model N_IIf *) + let cost_N_IIf = S.safe_int 10 + + (* model N_IIf_cons *) + let cost_N_IIf_cons = S.safe_int 10 + + (* model N_IIf_left *) + let cost_N_IIf_left = S.safe_int 10 + + (* model N_IIf_none *) + let cost_N_IIf_none = S.safe_int 10 + + (* model N_IImplicit_account *) + let cost_N_IImplicit_account = S.safe_int 10 + + (* model N_IInt_bls12_381_z_fr *) + let cost_N_IInt_bls12_381_z_fr = S.safe_int 40 + + (* model N_IInt_nat *) + let cost_N_IInt_nat = S.safe_int 15 + + (* model N_IIs_nat *) + let cost_N_IIs_nat = S.safe_int 15 + + (* model N_IKeccak *) + (* Approximating 32.7522064274 x term *) + let cost_N_IKeccak size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 5100 + ((S.safe_int 32 * v0) + (v0 lsr 1) + (v0 lsr 2)) + + (* model N_ILambda *) + let cost_N_ILambda = S.safe_int 10 + + (* model N_ILe *) + let cost_N_ILe = S.safe_int 15 + + (* model N_ILeft *) + let cost_N_ILeft = S.safe_int 15 + + (* model N_ILevel *) + let cost_N_ILevel = S.safe_int 25 + + (* model N_IList_iter *) + let cost_N_IList_iter _ = S.safe_int 50 + + (* model N_IList_map *) + let cost_N_IList_map _ = S.safe_int 45 + + (* model N_IList_size *) + let cost_N_IList_size = S.safe_int 15 + + (* model N_ILoop *) + let cost_N_ILoop = S.safe_int 10 + + (* model N_ILoop_left *) + let cost_N_ILoop_left = S.safe_int 10 + + (* model N_ILsl_nat *) + (* Approximating 0.115642 x term *) + let cost_N_ILsl_nat size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 35 + ((v0 lsr 4) + (v0 lsr 5) + (v0 lsr 6)) + + (* model N_ILsr_nat *) + (* Approximating 0.115565 x term *) + let cost_N_ILsr_nat size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 35 + ((v0 lsr 4) + (v0 lsr 5) + (v0 lsr 6)) + + (* model N_ILt *) + let cost_N_ILt = S.safe_int 15 + + (* model N_IMap_get *) + (* Approximating 0.048359 x term *) + let cost_N_IMap_get size1 size2 = + let open S_syntax in + let v0 = size1 * log2 size2 in + S.safe_int 80 + (v0 lsr 5) + (v0 lsr 6) + + (* model N_IMap_get_and_update *) + (* Approximating 0.145661 x term *) + let cost_N_IMap_get_and_update size1 size2 = + let open S_syntax in + let v0 = size1 * log2 size2 in + S.safe_int 165 + (v0 lsr 3) + (v0 lsr 6) + + (* model N_IMap_iter *) + (* Approximating 5.235173 x term *) + let cost_N_IMap_iter size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 60 + (S.safe_int 5 * v0) + (v0 lsr 2) + + (* model N_IMap_map *) + (* Approximating 7.46280485884 x term *) + let cost_N_IMap_map size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 180 + ((S.safe_int 7 * v0) + (v0 lsr 1)) + + (* model N_IMap_mem *) + (* Approximating 0.048446 x term *) + let cost_N_IMap_mem size1 size2 = + let open S_syntax in + let v0 = size1 * log2 size2 in + S.safe_int 80 + (v0 lsr 5) + (v0 lsr 6) + + (* model N_IMap_size *) + let cost_N_IMap_size = S.safe_int 15 + + (* model N_IMap_update *) + (* Approximating 0.097072 x term *) + let cost_N_IMap_update size1 size2 = + let open S_syntax in + let v0 = size1 * log2 size2 in + S.safe_int 100 + (v0 lsr 4) + (v0 lsr 5) + + (* model N_IMul_bls12_381_fr *) + let cost_N_IMul_bls12_381_fr = S.safe_int 170 + + (* model N_IMul_bls12_381_fr_z *) + (* Approximating 1.059386 x term *) + let cost_N_IMul_bls12_381_fr_z size1 = + let open S_syntax in + let v0 = S.safe_int size1 in + S.safe_int 270 + v0 + (v0 lsr 4) + + (* model N_IMul_bls12_381_g1 *) + let cost_N_IMul_bls12_381_g1 = S.safe_int 229_850 + + (* model N_IMul_bls12_381_g2 *) + let cost_N_IMul_bls12_381_g2 = S.safe_int 760_350 + + (* model N_IMul_bls12_381_z_fr *) + (* Approximating 1.068674 x term *) + let cost_N_IMul_bls12_381_z_fr size1 = + let open S_syntax in + let v0 = S.safe_int size1 in + S.safe_int 270 + v0 + (v0 lsr 4) + + let cost_mul size1 size2 = + let open S_syntax in + let a = S.add (S.safe_int size1) (S.safe_int size2) in + let v0 = a * log2 a in + S.safe_int 75 + (v0 lsr 1) + (v0 lsr 2) + (v0 lsr 4) + + (* model N_IMul_intint *) + (* Approximating 0.857296 x term *) + let cost_N_IMul_intint = cost_mul + + (* model N_IMul_intnat *) + (* Approximating 0.857931 x term *) + let cost_N_IMul_intnat = cost_mul + + (* model N_IMul_natint *) + (* Approximating 0.861823 x term *) + let cost_N_IMul_natint = cost_mul + + (* model N_IMul_natnat *) + (* Approximating 0.849870 x term *) + let cost_N_IMul_natnat = cost_mul + + (* model N_IMul_nattez *) + let cost_N_IMul_nattez = S.safe_int 100 + + (* model N_IMul_teznat *) + let cost_N_IMul_teznat = S.safe_int 100 + + (* model N_INeg_bls12_381_fr *) + let cost_N_INeg_bls12_381_fr = S.safe_int 120 + + (* model N_INeg_bls12_381_g1 *) + let cost_N_INeg_bls12_381_g1 = S.safe_int 290 + + (* model N_INeg_bls12_381_g2 *) + let cost_N_INeg_bls12_381_g2 = S.safe_int 555 + + (* model N_INeg_int *) + (* Approximating 0.065748 x term *) + let cost_N_INeg_int size = + let open S_syntax in + S.safe_int 25 + (S.safe_int size lsr 4) + + (* model N_INeg_nat *) + (* Approximating 0.066076 x term *) + let cost_N_INeg_nat size = + let open S_syntax in + S.safe_int 25 + (S.safe_int size lsr 4) + + (* model N_INeq *) + let cost_N_INeq = S.safe_int 15 + + (* model N_INil *) + let cost_N_INil = S.safe_int 15 + + (* model N_INot *) + let cost_N_INot = S.safe_int 10 + + (* model N_INot_int *) + (* Approximating 0.075541 x term *) + let cost_N_INot_int size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 25 + ((v0 lsr 4) + (v0 lsr 7)) + + (* model N_INot_nat *) + (* Approximating 0.074613 x term *) + let cost_N_INot_nat size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 25 + ((v0 lsr 4) + (v0 lsr 7)) + + (* model N_INow *) + let cost_N_INow = S.safe_int 25 + + (* model N_IOpen_chest *) + (* 612000 + chest * 19 + time * 19050 *) + let cost_N_IOpen_chest ~chest ~time = + let open S_syntax in + let v0 = S.safe_int chest in + let v1 = S.safe_int time in + S.safe_int 612_000 + (S.safe_int 19 * v0) + (S.safe_int 19050 * v1) + + (* model N_IOr *) + let cost_N_IOr = S.safe_int 15 + + (* model N_IOr_nat *) + (* Approximating 0.075758 x term *) + let cost_N_IOr_nat = cost_linear_op_int + + (* model N_IPairing_check_bls12_381 *) + let cost_N_IPairing_check_bls12_381 size = + S.add + (S.safe_int 1_396_550) + (S.mul (S.safe_int 456_475) (S.safe_int size)) + + (* model N_IRead_ticket *) + let cost_N_IRead_ticket = S.safe_int 15 + + (* model N_IRight *) + let cost_N_IRight = S.safe_int 15 + + (* model N_ISapling_empty_state *) + let cost_N_ISapling_empty_state = S.safe_int 15 + + (* model N_ISapling_verify_update *) + (* Approximating 1.27167 x term *) + (* Approximating 38.72115 x term *) + let cost_N_ISapling_verify_update size1 size2 = + let open S_syntax in + let v1 = S.safe_int size1 in + let v0 = S.safe_int size2 in + S.safe_int 84_050 + (v1 + (v1 lsr 2)) + (S.safe_int 39 * v0) + + (* model N_ISelf_address *) + let cost_N_ISelf_address = S.safe_int 15 + + (* model N_ISelf *) + let cost_N_ISelf = S.safe_int 15 + + (* model N_ISender *) + let cost_N_ISender = S.safe_int 15 + + (* model N_ISet_delegate *) + let cost_N_ISet_delegate = S.safe_int 40 + + (* model N_ISet_iter *) + (* Approximating 4.214099 x term *) + let cost_N_ISet_iter size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 60 + (S.safe_int 4 * v0) + (v0 lsr 2) + + (* model N_ISet_size *) + let cost_N_ISet_size = S.safe_int 15 + + (* model N_ISha256 *) + (* Approximating 4.763264 x term *) + let cost_N_ISha256 size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 460 + ((S.safe_int 4 * v0) + (v0 lsr 1) + (v0 lsr 2)) + + (* model N_ISha3 *) + (* Approximating 32.739046325 x term *) + let cost_N_ISha3 = cost_N_IKeccak + + (* model N_ISha512 *) + (* Approximating 3.074641 x term *) + let cost_N_ISha512 size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 535 + (S.safe_int 3 * v0) + + (* model N_ISlice_bytes *) + (* Approximating 0.065752 x term *) + let cost_N_ISlice_bytes size = + let open S_syntax in + S.safe_int 30 + (S.safe_int size lsr 4) + + (* model N_ISlice_string *) + (* Approximating 0.065688 x term *) + let cost_N_ISlice_string size = + let open S_syntax in + S.safe_int 30 + (S.safe_int size lsr 4) + + (* model N_ISource *) + let cost_N_ISource = S.safe_int 15 + + (* model N_ISplit_ticket *) + (* Approximating 0.132362 x term *) + let cost_N_ISplit_ticket size1 size2 = + let open S_syntax in + let v1 = S.safe_int (Compare.Int.max size1 size2) in + S.safe_int 70 + (v1 lsr 3) + + (* model N_IString_size *) + let cost_N_IString_size = S.safe_int 15 + + (* model N_ISub_int *) + (* Approximating 0.077849 x term *) + let cost_N_ISub_int = cost_linear_op_int + + (* model N_ISub_tez *) + let cost_N_ISub_tez = S.safe_int 25 + + (* model N_ISub_timestamp_seconds *) + (* Approximating 0.077794 x term *) + let cost_N_ISub_timestamp_seconds = cost_linear_op_int + + (* model N_ISwap *) + let cost_N_ISwap = S.safe_int 10 + + (* model N_ITicket *) + let cost_N_ITicket = S.safe_int 15 + + (* model N_ITotal_voting_power *) + let cost_N_ITotal_voting_power = S.safe_int 300 + + (* model N_ITransfer_tokens *) + let cost_N_ITransfer_tokens = S.safe_int 30 + + (* model N_IUncomb *) + (* Approximating 3.944710 x term *) + let cost_N_IUncomb size = + let open S_syntax in + let v0 = S.safe_int size in + S.safe_int 25 + (S.safe_int 4 * v0) + + (* model N_IUnpair *) + let cost_N_IUnpair = S.safe_int 10 + + (* model N_IVoting_power *) + let cost_N_IVoting_power = S.safe_int 400 + + (* model N_IXor *) + let cost_N_IXor = S.safe_int 20 + + (* model N_IXor_nat *) + (* Approximating 0.075601 x term *) + let cost_N_IXor_nat = cost_linear_op_int + + (* model N_KCons *) + let cost_N_KCons = S.safe_int 15 + + (* model N_KIter *) + let cost_N_KIter = S.safe_int 20 + + (* model N_KList_enter_body *) + (* Approximating 1.672196 x term *) + let cost_N_KList_enter_body xs size_ys = + match xs with + | [] -> + let open S_syntax in + let v0 = S.safe_int size_ys in + S.safe_int 40 + (v0 + (v0 lsr 1) + (v0 lsr 3)) + | _ :: _ -> S.safe_int 70 + + (* model N_KList_exit_body *) + let cost_N_KList_exit_body = S.safe_int 30 + + (* model N_KLoop_in *) + let cost_N_KLoop_in = S.safe_int 15 + + (* model N_KLoop_in_left *) + let cost_N_KLoop_in_left = S.safe_int 15 + + (* model N_KMap_enter_body *) + let cost_N_KMap_enter_body = S.safe_int 130 + + (* model N_KNil *) + let cost_N_KNil = S.safe_int 20 + + (* model N_KReturn *) + let cost_N_KReturn = S.safe_int 15 + + (* model N_KUndip *) + let cost_N_KUndip = S.safe_int 15 + + (* model DECODING_BLS_FR *) + let cost_DECODING_BLS_FR = S.safe_int 50 + + (* model DECODING_BLS_G1 *) + let cost_DECODING_BLS_G1 = S.safe_int 195_000 + + (* model DECODING_BLS_G2 *) + let cost_DECODING_BLS_G2 = S.safe_int 660_000 + + (* model B58CHECK_DECODING_CHAIN_ID *) + let cost_B58CHECK_DECODING_CHAIN_ID = S.safe_int 1_400 + + (* model B58CHECK_DECODING_PUBLIC_KEY_HASH_ed25519 *) + let cost_B58CHECK_DECODING_PUBLIC_KEY_HASH_ed25519 = S.safe_int 3_100 + + (* model B58CHECK_DECODING_PUBLIC_KEY_HASH_p256 *) + let cost_B58CHECK_DECODING_PUBLIC_KEY_HASH_p256 = S.safe_int 3_100 + + (* model B58CHECK_DECODING_PUBLIC_KEY_HASH_secp256k1 *) + let cost_B58CHECK_DECODING_PUBLIC_KEY_HASH_secp256k1 = S.safe_int 3_100 + + (* model B58CHECK_DECODING_PUBLIC_KEY_ed25519 *) + let cost_B58CHECK_DECODING_PUBLIC_KEY_ed25519 = S.safe_int 4_000 + + (* model B58CHECK_DECODING_PUBLIC_KEY_p256 *) + let cost_B58CHECK_DECODING_PUBLIC_KEY_p256 = S.safe_int 27_000 + + (* model B58CHECK_DECODING_PUBLIC_KEY_secp256k1 *) + let cost_B58CHECK_DECODING_PUBLIC_KEY_secp256k1 = S.safe_int 8_500 + + (* model B58CHECK_DECODING_SIGNATURE_ed25519 *) + let cost_B58CHECK_DECODING_SIGNATURE_ed25519 = S.safe_int 6_100 + + (* model B58CHECK_DECODING_SIGNATURE_p256 *) + let cost_B58CHECK_DECODING_SIGNATURE_p256 = S.safe_int 6_100 + + (* model B58CHECK_DECODING_SIGNATURE_secp256k1 *) + let cost_B58CHECK_DECODING_SIGNATURE_secp256k1 = S.safe_int 6_100 + + (* model ENCODING_BLS_FR *) + let cost_ENCODING_BLS_FR = S.safe_int 30 + + (* model ENCODING_BLS_G1 *) + let cost_ENCODING_BLS_G1 = S.safe_int 30 + + (* model ENCODING_BLS_G2 *) + let cost_ENCODING_BLS_G2 = S.safe_int 30 + + (* model B58CHECK_ENCODING_CHAIN_ID *) + let cost_B58CHECK_ENCODING_CHAIN_ID = S.safe_int 1_600 + + (* model B58CHECK_ENCODING_PUBLIC_KEY_HASH_ed25519 *) + let cost_B58CHECK_ENCODING_PUBLIC_KEY_HASH_ed25519 = S.safe_int 2_900 + + (* model B58CHECK_ENCODING_PUBLIC_KEY_HASH_p256 *) + let cost_B58CHECK_ENCODING_PUBLIC_KEY_HASH_p256 = S.safe_int 2_900 + + (* model B58CHECK_ENCODING_PUBLIC_KEY_HASH_secp256k1 *) + let cost_B58CHECK_ENCODING_PUBLIC_KEY_HASH_secp256k1 = S.safe_int 2_900 + + (* model B58CHECK_ENCODING_PUBLIC_KEY_ed25519 *) + let cost_B58CHECK_ENCODING_PUBLIC_KEY_ed25519 = S.safe_int 4_200 + + (* model B58CHECK_ENCODING_PUBLIC_KEY_p256 *) + let cost_B58CHECK_ENCODING_PUBLIC_KEY_p256 = S.safe_int 4_700 + + (* model B58CHECK_ENCODING_PUBLIC_KEY_secp256k1 *) + let cost_B58CHECK_ENCODING_PUBLIC_KEY_secp256k1 = S.safe_int 4_500 + + (* model B58CHECK_ENCODING_SIGNATURE_ed25519 *) + let cost_B58CHECK_ENCODING_SIGNATURE_ed25519 = S.safe_int 7_800 + + (* model B58CHECK_ENCODING_SIGNATURE_p256 *) + let cost_B58CHECK_ENCODING_SIGNATURE_p256 = S.safe_int 7_800 + + (* model B58CHECK_ENCODING_SIGNATURE_secp256k1 *) + let cost_B58CHECK_ENCODING_SIGNATURE_secp256k1 = S.safe_int 7_800 + + (* model DECODING_CHAIN_ID *) + let cost_DECODING_CHAIN_ID = S.safe_int 50 + + (* model DECODING_PUBLIC_KEY_HASH_ed25519 *) + let cost_DECODING_PUBLIC_KEY_HASH_ed25519 = S.safe_int 50 + + (* model DECODING_PUBLIC_KEY_HASH_p256 *) + let cost_DECODING_PUBLIC_KEY_HASH_p256 = S.safe_int 50 + + (* model DECODING_PUBLIC_KEY_HASH_secp256k1 *) + let cost_DECODING_PUBLIC_KEY_HASH_secp256k1 = S.safe_int 50 + + (* model DECODING_PUBLIC_KEY_ed25519 *) + let cost_DECODING_PUBLIC_KEY_ed25519 = S.safe_int 60 + + (* model DECODING_PUBLIC_KEY_p256 *) + let cost_DECODING_PUBLIC_KEY_p256 = S.safe_int 23_000 + + (* model DECODING_PUBLIC_KEY_secp256k1 *) + let cost_DECODING_PUBLIC_KEY_secp256k1 = S.safe_int 4_800 + + (* model DECODING_SIGNATURE_ed25519 *) + let cost_DECODING_SIGNATURE_ed25519 = S.safe_int 30 + + (* model DECODING_SIGNATURE_p256 *) + let cost_DECODING_SIGNATURE_p256 = S.safe_int 30 + + (* model DECODING_SIGNATURE_secp256k1 *) + let cost_DECODING_SIGNATURE_secp256k1 = S.safe_int 30 + + (* model DECODING_Chest_key *) + let cost_DECODING_Chest_key = S.safe_int 7200 + + (* model DECODING_Chest *) + (* Approximating 0.039349 x term *) + let cost_DECODING_Chest ~bytes = + let open S_syntax in + let v0 = S.safe_int bytes in + S.safe_int 7400 + (v0 lsr 5) + (v0 lsr 7) + + (* model ENCODING_CHAIN_ID *) + let cost_ENCODING_CHAIN_ID = S.safe_int 50 + + (* model ENCODING_PUBLIC_KEY_HASH_ed25519 *) + let cost_ENCODING_PUBLIC_KEY_HASH_ed25519 = S.safe_int 60 + + (* model ENCODING_PUBLIC_KEY_HASH_p256 *) + let cost_ENCODING_PUBLIC_KEY_HASH_p256 = S.safe_int 80 + + (* model ENCODING_PUBLIC_KEY_HASH_secp256k1 *) + let cost_ENCODING_PUBLIC_KEY_HASH_secp256k1 = S.safe_int 70 + + (* model ENCODING_PUBLIC_KEY_ed25519 *) + let cost_ENCODING_PUBLIC_KEY_ed25519 = S.safe_int 80 + + (* model ENCODING_PUBLIC_KEY_p256 *) + let cost_ENCODING_PUBLIC_KEY_p256 = S.safe_int 570 + + (* model ENCODING_PUBLIC_KEY_secp256k1 *) + let cost_ENCODING_PUBLIC_KEY_secp256k1 = S.safe_int 440 + + (* model ENCODING_SIGNATURE_ed25519 *) + let cost_ENCODING_SIGNATURE_ed25519 = S.safe_int 40 + + (* model ENCODING_SIGNATURE_p256 *) + let cost_ENCODING_SIGNATURE_p256 = S.safe_int 40 + + (* model ENCODING_SIGNATURE_secp256k1 *) + let cost_ENCODING_SIGNATURE_secp256k1 = S.safe_int 40 + + (* model ENCODING_Chest_key *) + let cost_ENCODING_Chest_key = S.safe_int 13500 + + (* model ENCODING_Chest *) + (* Approximating 0.120086 x term *) + let cost_ENCODING_Chest ~plaintext_size = + let open S_syntax in + let v0 = S.safe_int plaintext_size in + S.safe_int 16630 + (v0 lsr 3) + + (* model TIMESTAMP_READABLE_DECODING *) + let cost_TIMESTAMP_READABLE_DECODING = S.safe_int 120 + + (* model TIMESTAMP_READABLE_ENCODING *) + let cost_TIMESTAMP_READABLE_ENCODING = S.safe_int 800 + + (* model CHECK_PRINTABLE *) + let cost_CHECK_PRINTABLE size = + let open S_syntax in + S.safe_int 14 + (S.safe_int 10 * S.safe_int size) + + (* model MERGE_TYPES + This is the estimated cost of one iteration of merge_types, extracted + and copied manually from the parameter fit for the MERGE_TYPES benchmark + (the model is parametric on the size of the type, which we don't have + access to in O(1)). *) + let cost_MERGE_TYPES = S.safe_int 40 + + (* model TYPECHECKING_CODE + This is the cost of one iteration of parse_instr, extracted by hand from the + parameter fit for the TYPECHECKING_CODE benchmark. *) + let cost_TYPECHECKING_CODE = S.safe_int 220 + + (* model UNPARSING_CODE + This is the cost of one iteration of unparse_instr, extracted by hand from the + parameter fit for the UNPARSING_CODE benchmark. *) + let cost_UNPARSING_CODE = S.safe_int 115 + + (* model TYPECHECKING_DATA + This is the cost of one iteration of parse_data, extracted by hand from the + parameter fit for the TYPECHECKING_DATA benchmark. *) + let cost_TYPECHECKING_DATA = S.safe_int 100 + + (* model UNPARSING_DATA + This is the cost of one iteration of unparse_data, extracted by hand from the + parameter fit for the UNPARSING_DATA benchmark. *) + let cost_UNPARSING_DATA = S.safe_int 45 + + (* model PARSE_TYPE + This is the cost of one iteration of parse_ty, extracted by hand from the + parameter fit for the PARSE_TYPE benchmark. *) + let cost_PARSE_TYPE = S.safe_int 60 + + (* model UNPARSE_TYPE + This is the cost of one iteration of unparse_ty, extracted by hand from the + parameter fit for the UNPARSE_TYPE benchmark. *) + let cost_UNPARSE_TYPE = S.safe_int 20 + + (* TODO: benchmark *) + let cost_COMPARABLE_TY_OF_TY = S.safe_int 120 + + (* model SAPLING_TRANSACTION_ENCODING *) + let cost_SAPLING_TRANSACTION_ENCODING ~inputs ~outputs = + S.safe_int (1500 + (inputs * 160) + (outputs * 320)) + + (* model SAPLING_DIFF_ENCODING *) + let cost_SAPLING_DIFF_ENCODING ~nfs ~cms = + S.safe_int ((nfs * 22) + (cms * 215)) + end + + module Interpreter = struct + open Generated_costs + + let drop = atomic_step_cost cost_N_IDrop + + let dup = atomic_step_cost cost_N_IDup + + let swap = atomic_step_cost cost_N_ISwap + + let cons_some = atomic_step_cost cost_N_ICons_some + + let cons_none = atomic_step_cost cost_N_ICons_none + + let if_none = atomic_step_cost cost_N_IIf_none + + let cons_pair = atomic_step_cost cost_N_ICons_pair + + let unpair = atomic_step_cost cost_N_IUnpair + + let car = atomic_step_cost cost_N_ICar + + let cdr = atomic_step_cost cost_N_ICdr + + let cons_left = atomic_step_cost cost_N_ILeft + + let cons_right = atomic_step_cost cost_N_IRight + + let if_left = atomic_step_cost cost_N_IIf_left + + let cons_list = atomic_step_cost cost_N_ICons_list + + let nil = atomic_step_cost cost_N_INil + + let if_cons = atomic_step_cost cost_N_IIf_cons + + let list_map : 'a Script_typed_ir.boxed_list -> Gas.cost = + fun {length; _} -> atomic_step_cost (cost_N_IList_map length) + + let list_size = atomic_step_cost cost_N_IList_size + + let list_iter : 'a Script_typed_ir.boxed_list -> Gas.cost = + fun {length; _} -> atomic_step_cost (cost_N_IList_iter length) + + let empty_set = atomic_step_cost cost_N_IEmpty_set + + let set_iter (type a) ((module Box) : a Script_typed_ir.set) = + atomic_step_cost (cost_N_ISet_iter Box.size) + + let set_size = atomic_step_cost cost_N_ISet_size + + let empty_map = atomic_step_cost cost_N_IEmpty_map + + let map_map (type k v) ((module Box) : (k, v) Script_typed_ir.map) = + atomic_step_cost (cost_N_IMap_map (snd Box.boxed)) + + let map_iter (type k v) ((module Box) : (k, v) Script_typed_ir.map) = + atomic_step_cost (cost_N_IMap_iter (snd Box.boxed)) + + let map_size = atomic_step_cost cost_N_IMap_size + + let big_map_elt_size = S.safe_int Script_expr_hash.size + + let big_map_mem ({size; _} : _ Script_typed_ir.big_map_overlay) = + atomic_step_cost (cost_N_IMap_mem big_map_elt_size (S.safe_int size)) + + let big_map_get ({size; _} : _ Script_typed_ir.big_map_overlay) = + atomic_step_cost (cost_N_IMap_get big_map_elt_size (S.safe_int size)) + + let big_map_update ({size; _} : _ Script_typed_ir.big_map_overlay) = + atomic_step_cost (cost_N_IMap_update big_map_elt_size (S.safe_int size)) + + let big_map_get_and_update ({size; _} : _ Script_typed_ir.big_map_overlay) = + atomic_step_cost + (cost_N_IMap_get_and_update big_map_elt_size (S.safe_int size)) + + let add_seconds_timestamp : + 'a Script_int.num -> Script_timestamp.t -> Gas.cost = + fun seconds timestamp -> + let seconds_bytes = int_bytes seconds in + let timestamp_bytes = z_bytes (Script_timestamp.to_zint timestamp) in + atomic_step_cost + (cost_N_IAdd_seconds_to_timestamp seconds_bytes timestamp_bytes) + + let add_timestamp_seconds : + Script_timestamp.t -> 'a Script_int.num -> Gas.cost = + fun timestamp seconds -> + let seconds_bytes = int_bytes seconds in + let timestamp_bytes = z_bytes (Script_timestamp.to_zint timestamp) in + atomic_step_cost + (cost_N_IAdd_timestamp_to_seconds timestamp_bytes seconds_bytes) + + let sub_timestamp_seconds : + Script_timestamp.t -> 'a Script_int.num -> Gas.cost = + fun timestamp seconds -> + let seconds_bytes = int_bytes seconds in + let timestamp_bytes = z_bytes (Script_timestamp.to_zint timestamp) in + atomic_step_cost + (cost_N_ISub_timestamp_seconds timestamp_bytes seconds_bytes) + + let diff_timestamps t1 t2 = + let t1_bytes = z_bytes (Script_timestamp.to_zint t1) in + let t2_bytes = z_bytes (Script_timestamp.to_zint t2) in + atomic_step_cost (cost_N_IDiff_timestamps t1_bytes t2_bytes) + + let concat_string_pair s1 s2 = + atomic_step_cost + (cost_N_IConcat_string_pair + (Script_string.length s1) + (Script_string.length s2)) + + let slice_string s = + atomic_step_cost (cost_N_ISlice_string (Script_string.length s)) + + let string_size = atomic_step_cost cost_N_IString_size + + let concat_bytes_pair b1 b2 = + atomic_step_cost + (cost_N_IConcat_bytes_pair (Bytes.length b1) (Bytes.length b2)) + + let slice_bytes b = atomic_step_cost (cost_N_ISlice_bytes (Bytes.length b)) + + let bytes_size = atomic_step_cost cost_N_IBytes_size + + let add_tez = atomic_step_cost cost_N_IAdd_tez + + let sub_tez = atomic_step_cost cost_N_ISub_tez + + let mul_teznat = atomic_step_cost cost_N_IMul_teznat + + let mul_nattez = atomic_step_cost cost_N_IMul_nattez + + let bool_or = atomic_step_cost cost_N_IOr + + let bool_and = atomic_step_cost cost_N_IAnd + + let bool_xor = atomic_step_cost cost_N_IXor + + let bool_not = atomic_step_cost cost_N_INot + + let is_nat = atomic_step_cost cost_N_IIs_nat + + let abs_int i = atomic_step_cost (cost_N_IAbs_int (int_bytes i)) + + let int_nat = atomic_step_cost cost_N_IInt_nat + + let neg_int i = atomic_step_cost (cost_N_INeg_int (int_bytes i)) + + let neg_nat n = atomic_step_cost (cost_N_INeg_nat (int_bytes n)) + + let add_intint i1 i2 = + atomic_step_cost (cost_N_IAdd_intint (int_bytes i1) (int_bytes i2)) + + let add_intnat i1 i2 = + atomic_step_cost (cost_N_IAdd_intnat (int_bytes i1) (int_bytes i2)) + + let add_natint i1 i2 = + atomic_step_cost (cost_N_IAdd_natint (int_bytes i1) (int_bytes i2)) + + let add_natnat i1 i2 = + atomic_step_cost (cost_N_IAdd_natnat (int_bytes i1) (int_bytes i2)) + + let sub_int i1 i2 = + atomic_step_cost (cost_N_ISub_int (int_bytes i1) (int_bytes i2)) + + let mul_intint i1 i2 = + atomic_step_cost (cost_N_IMul_intint (int_bytes i1) (int_bytes i2)) + + let mul_intnat i1 i2 = + atomic_step_cost (cost_N_IMul_intnat (int_bytes i1) (int_bytes i2)) + + let mul_natint i1 i2 = + atomic_step_cost (cost_N_IMul_natint (int_bytes i1) (int_bytes i2)) + + let mul_natnat i1 i2 = + atomic_step_cost (cost_N_IMul_natnat (int_bytes i1) (int_bytes i2)) + + let ediv_teznat _tez _n = atomic_step_cost cost_N_IEdiv_teznat + + let ediv_tez = atomic_step_cost cost_N_IEdiv_tez + + let ediv_intint i1 i2 = + atomic_step_cost (cost_N_IEdiv_intint (int_bytes i1) (int_bytes i2)) + + let ediv_intnat i1 i2 = + atomic_step_cost (cost_N_IEdiv_intnat (int_bytes i1) (int_bytes i2)) + + let ediv_natint i1 i2 = + atomic_step_cost (cost_N_IEdiv_natint (int_bytes i1) (int_bytes i2)) + + let ediv_natnat i1 i2 = + atomic_step_cost (cost_N_IEdiv_natnat (int_bytes i1) (int_bytes i2)) + + let eq = atomic_step_cost cost_N_IEq + + let lsl_nat shifted = atomic_step_cost (cost_N_ILsl_nat (int_bytes shifted)) + + let lsr_nat shifted = atomic_step_cost (cost_N_ILsr_nat (int_bytes shifted)) + + let or_nat n1 n2 = + atomic_step_cost (cost_N_IOr_nat (int_bytes n1) (int_bytes n2)) + + let and_nat n1 n2 = + atomic_step_cost (cost_N_IAnd_nat (int_bytes n1) (int_bytes n2)) + + let and_int_nat n1 n2 = + atomic_step_cost (cost_N_IAnd_int_nat (int_bytes n1) (int_bytes n2)) + + let xor_nat n1 n2 = + atomic_step_cost (cost_N_IXor_nat (int_bytes n1) (int_bytes n2)) + + let not_int i = atomic_step_cost (cost_N_INot_int (int_bytes i)) + + let not_nat i = atomic_step_cost (cost_N_INot_nat (int_bytes i)) + + let if_ = atomic_step_cost cost_N_IIf + + let loop = atomic_step_cost cost_N_ILoop + + let loop_left = atomic_step_cost cost_N_ILoop_left + + let dip = atomic_step_cost cost_N_IDip + + let view = atomic_step_cost cost_N_IView + + let check_signature (pkey : Signature.public_key) b = + let cost = + match pkey with + | Ed25519 _ -> cost_N_ICheck_signature_ed25519 (Bytes.length b) + | Secp256k1 _ -> cost_N_ICheck_signature_secp256k1 (Bytes.length b) + | P256 _ -> cost_N_ICheck_signature_p256 (Bytes.length b) + in + atomic_step_cost cost + + let blake2b b = atomic_step_cost (cost_N_IBlake2b (Bytes.length b)) + + let sha256 b = atomic_step_cost (cost_N_ISha256 (Bytes.length b)) + + let sha512 b = atomic_step_cost (cost_N_ISha512 (Bytes.length b)) + + let dign n = atomic_step_cost (cost_N_IDig n) + + let dugn n = atomic_step_cost (cost_N_IDug n) + + let dipn n = atomic_step_cost (cost_N_IDipN n) + + let dropn n = atomic_step_cost (cost_N_IDropN n) + + let voting_power = atomic_step_cost cost_N_IVoting_power + + let total_voting_power = atomic_step_cost cost_N_ITotal_voting_power + + let keccak b = atomic_step_cost (cost_N_IKeccak (Bytes.length b)) + + let sha3 b = atomic_step_cost (cost_N_ISha3 (Bytes.length b)) + + let add_bls12_381_g1 = atomic_step_cost cost_N_IAdd_bls12_381_g1 + + let add_bls12_381_g2 = atomic_step_cost cost_N_IAdd_bls12_381_g2 + + let add_bls12_381_fr = atomic_step_cost cost_N_IAdd_bls12_381_fr + + let mul_bls12_381_g1 = atomic_step_cost cost_N_IMul_bls12_381_g1 + + let mul_bls12_381_g2 = atomic_step_cost cost_N_IMul_bls12_381_g2 + + let mul_bls12_381_fr = atomic_step_cost cost_N_IMul_bls12_381_fr + + let mul_bls12_381_fr_z z = + atomic_step_cost (cost_N_IMul_bls12_381_fr_z (int_bytes z)) + + let mul_bls12_381_z_fr z = + atomic_step_cost (cost_N_IMul_bls12_381_z_fr (int_bytes z)) + + let int_bls12_381_fr = atomic_step_cost cost_N_IInt_bls12_381_z_fr + + let neg_bls12_381_g1 = atomic_step_cost cost_N_INeg_bls12_381_g1 + + let neg_bls12_381_g2 = atomic_step_cost cost_N_INeg_bls12_381_g2 + + let neg_bls12_381_fr = atomic_step_cost cost_N_INeg_bls12_381_fr + + let neq = atomic_step_cost cost_N_INeq + + let pairing_check_bls12_381 (l : 'a Script_typed_ir.boxed_list) = + atomic_step_cost (cost_N_IPairing_check_bls12_381 l.length) + + let comb n = atomic_step_cost (cost_N_IComb n) + + let uncomb n = atomic_step_cost (cost_N_IUncomb n) + + let comb_get n = atomic_step_cost (cost_N_IComb_get n) + + let comb_set n = atomic_step_cost (cost_N_IComb_set n) + + let dupn n = atomic_step_cost (cost_N_IDupN n) + + let sapling_verify_update ~inputs ~outputs = + atomic_step_cost (cost_N_ISapling_verify_update inputs outputs) + + let sapling_empty_state = atomic_step_cost cost_N_ISapling_empty_state + + let halt = atomic_step_cost cost_N_IHalt + + let const = atomic_step_cost cost_N_IConst + + let empty_big_map = atomic_step_cost cost_N_IEmpty_big_map + + let lt = atomic_step_cost cost_N_ILt + + let le = atomic_step_cost cost_N_ILe + + let gt = atomic_step_cost cost_N_IGt + + let ge = atomic_step_cost cost_N_IGe + + let exec = atomic_step_cost cost_N_IExec + + let apply = atomic_step_cost cost_N_IApply + + let lambda = atomic_step_cost cost_N_ILambda + + let address = atomic_step_cost cost_N_IAddress + + let contract = atomic_step_cost cost_N_IContract + + let transfer_tokens = atomic_step_cost cost_N_ITransfer_tokens + + let implicit_account = atomic_step_cost cost_N_IImplicit_account + + let create_contract = atomic_step_cost cost_N_ICreate_contract + + let set_delegate = atomic_step_cost cost_N_ISet_delegate + + let level = atomic_step_cost cost_N_ILevel + + let now = atomic_step_cost cost_N_INow + + let source = atomic_step_cost cost_N_ISource + + let sender = atomic_step_cost cost_N_ISender + + let self = atomic_step_cost cost_N_ISelf + + let self_address = atomic_step_cost cost_N_ISelf_address + + let amount = atomic_step_cost cost_N_IAmount + + let chain_id = atomic_step_cost cost_N_IChainId + + let ticket = atomic_step_cost cost_N_ITicket + + let read_ticket = atomic_step_cost cost_N_IRead_ticket + + let hash_key _ = atomic_step_cost cost_N_IHash_key + + let split_ticket _ amount_a amount_b = + atomic_step_cost + (cost_N_ISplit_ticket (int_bytes amount_a) (int_bytes amount_b)) + + let open_chest ~chest ~time = + let plaintext = Timelock.get_plaintext_size chest in + let log_time = Z.log2 Z.(add one time) in + atomic_step_cost (cost_N_IOpen_chest ~chest:plaintext ~time:log_time) + + (* --------------------------------------------------------------------- *) + (* Semi-hand-crafted models *) + + let compare_unit = atomic_step_cost (S.safe_int 10) + + let compare_pair_tag = atomic_step_cost (S.safe_int 10) + + let compare_union_tag = atomic_step_cost (S.safe_int 10) + + let compare_option_tag = atomic_step_cost (S.safe_int 10) + + let compare_bool = atomic_step_cost (cost_N_ICompare 1 1) + + let compare_signature = atomic_step_cost (S.safe_int 92) + + let compare_string s1 s2 = + atomic_step_cost + (cost_N_ICompare (Script_string.length s1) (Script_string.length s2)) + + let compare_bytes b1 b2 = + atomic_step_cost (cost_N_ICompare (Bytes.length b1) (Bytes.length b2)) + + let compare_mutez = atomic_step_cost (cost_N_ICompare 8 8) + + let compare_int i1 i2 = + atomic_step_cost (cost_N_ICompare (int_bytes i1) (int_bytes i2)) + + let compare_nat n1 n2 = + atomic_step_cost (cost_N_ICompare (int_bytes n1) (int_bytes n2)) + + let compare_key_hash = + let sz = Signature.Public_key_hash.size in + atomic_step_cost (cost_N_ICompare sz sz) + + let compare_key = atomic_step_cost (S.safe_int 92) + + let compare_timestamp t1 t2 = + atomic_step_cost + (cost_N_ICompare + (z_bytes (Script_timestamp.to_zint t1)) + (z_bytes (Script_timestamp.to_zint t2))) + + (* Maximum size of an entrypoint in bytes *) + let entrypoint_size = 31 + + let compare_address = + let sz = Signature.Public_key_hash.size + entrypoint_size in + atomic_step_cost (cost_N_ICompare sz sz) + + let compare_chain_id = atomic_step_cost (S.safe_int 30) + + (* Defunctionalized CPS *) + type cont = + | Compare : 'a Script_typed_ir.comparable_ty * 'a * 'a * cont -> cont + | Return : cont + + let compare : type a. a Script_typed_ir.comparable_ty -> a -> a -> cost = + fun ty x y -> + let rec compare : + type a. + a Script_typed_ir.comparable_ty -> a -> a -> cost -> cont -> cost = + fun ty x y acc k -> + match ty with + | Unit_key _ -> (apply [@tailcall]) Gas.(acc +@ compare_unit) k + | Never_key _ -> ( match x with _ -> .) + | Bool_key _ -> (apply [@tailcall]) Gas.(acc +@ compare_bool) k + | String_key _ -> (apply [@tailcall]) Gas.(acc +@ compare_string x y) k + | Signature_key _ -> + (apply [@tailcall]) Gas.(acc +@ compare_signature) k + | Bytes_key _ -> (apply [@tailcall]) Gas.(acc +@ compare_bytes x y) k + | Mutez_key _ -> (apply [@tailcall]) Gas.(acc +@ compare_mutez) k + | Int_key _ -> (apply [@tailcall]) Gas.(acc +@ compare_int x y) k + | Nat_key _ -> (apply [@tailcall]) Gas.(acc +@ compare_nat x y) k + | Key_hash_key _ -> (apply [@tailcall]) Gas.(acc +@ compare_key_hash) k + | Key_key _ -> (apply [@tailcall]) Gas.(acc +@ compare_key) k + | Timestamp_key _ -> + (apply [@tailcall]) Gas.(acc +@ compare_timestamp x y) k + | Address_key _ -> (apply [@tailcall]) Gas.(acc +@ compare_address) k + | Chain_id_key _ -> (apply [@tailcall]) Gas.(acc +@ compare_chain_id) k + | Pair_key ((tl, _), (tr, _), _) -> + (* Reasonable over-approximation of the cost of lexicographic comparison. *) + let (xl, xr) = x in + let (yl, yr) = y in + (compare [@tailcall]) + tl + xl + yl + Gas.(acc +@ compare_pair_tag) + (Compare (tr, xr, yr, k)) + | Union_key ((tl, _), (tr, _), _) -> ( + match (x, y) with + | (L x, L y) -> + (compare [@tailcall]) tl x y Gas.(acc +@ compare_union_tag) k + | (L _, R _) -> (apply [@tailcall]) Gas.(acc +@ compare_union_tag) k + | (R _, L _) -> (apply [@tailcall]) Gas.(acc +@ compare_union_tag) k + | (R x, R y) -> + (compare [@tailcall]) tr x y Gas.(acc +@ compare_union_tag) k) + | Option_key (t, _) -> ( + match (x, y) with + | (None, None) -> + (apply [@tailcall]) Gas.(acc +@ compare_option_tag) k + | (None, Some _) -> + (apply [@tailcall]) Gas.(acc +@ compare_option_tag) k + | (Some _, None) -> + (apply [@tailcall]) Gas.(acc +@ compare_option_tag) k + | (Some x, Some y) -> + (compare [@tailcall]) t x y Gas.(acc +@ compare_option_tag) k) + and apply cost k = + match k with + | Compare (ty, x, y, k) -> (compare [@tailcall]) ty x y cost k + | Return -> cost + in + compare ty x y Gas.free Return + [@@coq_axiom_with_reason "non top-level mutually recursive function"] + + let view_mem (elt : Script_string.t) + (m : Script_typed_ir.view Script_typed_ir.SMap.t) = + let open S_syntax in + let per_elt_cost = + compare (Script_typed_ir.string_key ~annot:None) elt elt + in + let size = S.safe_int (Script_typed_ir.SMap.cardinal m) in + let intercept = atomic_step_cost (S.safe_int 80) in + Gas.(intercept +@ (log2 size *@ per_elt_cost)) + + let view_get = view_mem + + let view_update (elt : Script_string.t) + (m : Script_typed_ir.view Script_typed_ir.SMap.t) = + let open S_syntax in + let per_elt_cost = + compare (Script_typed_ir.string_key ~annot:None) elt elt + in + let size = S.safe_int (Script_typed_ir.SMap.cardinal m) in + let intercept = atomic_step_cost (S.safe_int 80) in + Gas.(intercept +@ (S.safe_int 2 * log2 size *@ per_elt_cost)) + + let set_mem (type a) (elt : a) ((module Box) : a Script_typed_ir.set) = + let open S_syntax in + let per_elt_cost = compare Box.elt_ty elt elt in + let size = S.safe_int Box.size in + let intercept = atomic_step_cost (S.safe_int 80) in + Gas.(intercept +@ (log2 size *@ per_elt_cost)) + + let set_update (type a) (elt : a) ((module Box) : a Script_typed_ir.set) = + let open S_syntax in + let per_elt_cost = compare Box.elt_ty elt elt in + let size = S.safe_int Box.size in + let intercept = atomic_step_cost (S.safe_int 80) in + (* The 2 factor reflects the update vs mem overhead as benchmarked + on non-structured data *) + Gas.(intercept +@ (S.safe_int 2 * log2 size *@ per_elt_cost)) + + let map_mem (type k v) (elt : k) ((module Box) : (k, v) Script_typed_ir.map) + = + let open S_syntax in + let per_elt_cost = compare Box.key_ty elt elt in + let size = S.safe_int (snd Box.boxed) in + let intercept = atomic_step_cost (S.safe_int 80) in + Gas.(intercept +@ (log2 size *@ per_elt_cost)) + + let map_get = map_mem + + let map_update (type k v) (elt : k) + ((module Box) : (k, v) Script_typed_ir.map) = + let open S_syntax in + let per_elt_cost = compare Box.key_ty elt elt in + let size = S.safe_int (snd Box.boxed) in + let intercept = atomic_step_cost (S.safe_int 80) in + (* The 2 factor reflects the update vs mem overhead as benchmarked + on non-structured data *) + Gas.(intercept +@ (S.safe_int 2 * log2 size *@ per_elt_cost)) + + let map_get_and_update (type k v) (elt : k) + ((module Box) : (k, v) Script_typed_ir.map) = + let open S_syntax in + let per_elt_cost = compare Box.key_ty elt elt in + let size = S.safe_int (snd Box.boxed) in + let intercept = atomic_step_cost (S.safe_int 80) in + (* The 3 factor reflects the update vs mem overhead as benchmarked + on non-structured data *) + Gas.(intercept +@ (S.safe_int 3 * log2 size *@ per_elt_cost)) + + let join_tickets : + 'a Script_typed_ir.comparable_ty -> + 'a Script_typed_ir.ticket -> + 'a Script_typed_ir.ticket -> + Gas.cost = + fun ty ticket_a ticket_b -> + let contents_comparison = + compare ty ticket_a.contents ticket_b.contents + in + Gas.( + contents_comparison +@ compare_address + +@ add_natnat ticket_a.amount ticket_b.amount) + + (* Continuations *) + module Control = struct + let nil = atomic_step_cost cost_N_KNil + + let cons = atomic_step_cost cost_N_KCons + + let return = atomic_step_cost cost_N_KReturn + + let undip = atomic_step_cost cost_N_KUndip + + let loop_in = atomic_step_cost cost_N_KLoop_in + + let loop_in_left = atomic_step_cost cost_N_KLoop_in_left + + let iter = atomic_step_cost cost_N_KIter + + let list_enter_body xs ys_len = + atomic_step_cost (cost_N_KList_enter_body xs ys_len) + + let list_exit_body = atomic_step_cost cost_N_KList_exit_body + + let map_enter_body = atomic_step_cost cost_N_KMap_enter_body + + let map_exit_body (type k v) (key : k) (map : (k, v) Script_typed_ir.map) + = + map_update key map + end + + (* --------------------------------------------------------------------- *) + (* Hand-crafted models *) + + (* The cost functions below where not benchmarked, a cost model was derived + from looking at similar instructions. *) + + (* Cost for Concat_string is paid in two steps: when entering the interpreter, + the user pays for the cost of computing the information necessary to compute + the actual gas (so it's meta-gas): indeed, one needs to run through the + list of strings to compute the total allocated cost. + [concat_string_precheck] corresponds to the meta-gas cost of this computation. + *) + let concat_string_precheck (l : 'a Script_typed_ir.boxed_list) = + (* we set the precheck to be slightly more expensive than cost_N_IList_iter *) + atomic_step_cost (S.mul (S.safe_int l.length) (S.safe_int 10)) + + (* This is the cost of allocating a string and blitting existing ones into it. *) + let concat_string total_bytes = + atomic_step_cost + S.(add (S.safe_int 100) (S.ediv total_bytes (S.safe_int 10))) + + (* Same story as Concat_string. *) + let concat_bytes total_bytes = + atomic_step_cost + S.(add (S.safe_int 100) (S.ediv total_bytes (S.safe_int 10))) + + (* Cost of access taken care of in Contract_storage.get_balance_carbonated *) + let balance = Gas.free + + (* Cost of Unpack pays two integer comparisons, and a Bytes slice *) + let unpack bytes = + let blen = Bytes.length bytes in + let open S_syntax in + atomic_step_cost (S.safe_int 100 + (S.safe_int blen lsr 3)) + + (* TODO benchmark *) + (* FIXME: imported from 006, needs proper benchmarks *) + let unpack_failed bytes = + (* We cannot instrument failed deserialization, + so we take worst case fees: a set of size 1 bytes values. *) + let blen = Bytes.length bytes in + let len = S.safe_int blen in + let d = Z.numbits (Z.of_int blen) in + (len *@ alloc_mbytes_cost 1) + +@ len + *@ (S.safe_int d *@ (alloc_cost (S.safe_int 3) +@ step_cost S.one)) + end + + module Typechecking = struct + open Generated_costs + + let public_key_optimized = + atomic_step_cost + @@ S.( + max + cost_DECODING_PUBLIC_KEY_ed25519 + (max + cost_DECODING_PUBLIC_KEY_secp256k1 + cost_DECODING_PUBLIC_KEY_p256)) + + let public_key_readable = + atomic_step_cost + @@ S.( + max + cost_B58CHECK_DECODING_PUBLIC_KEY_ed25519 + (max + cost_B58CHECK_DECODING_PUBLIC_KEY_secp256k1 + cost_B58CHECK_DECODING_PUBLIC_KEY_p256)) + + let key_hash_optimized = + atomic_step_cost + @@ S.( + max + cost_DECODING_PUBLIC_KEY_HASH_ed25519 + (max + cost_DECODING_PUBLIC_KEY_HASH_secp256k1 + cost_DECODING_PUBLIC_KEY_HASH_p256)) + + let key_hash_readable = + atomic_step_cost + @@ S.( + max + cost_B58CHECK_DECODING_PUBLIC_KEY_HASH_ed25519 + (max + cost_B58CHECK_DECODING_PUBLIC_KEY_HASH_secp256k1 + cost_B58CHECK_DECODING_PUBLIC_KEY_HASH_p256)) + + let signature_optimized = + atomic_step_cost + @@ S.( + max + cost_DECODING_SIGNATURE_ed25519 + (max + cost_DECODING_SIGNATURE_secp256k1 + cost_DECODING_SIGNATURE_p256)) + + let signature_readable = + atomic_step_cost + @@ S.( + max + cost_B58CHECK_DECODING_SIGNATURE_ed25519 + (max + cost_B58CHECK_DECODING_SIGNATURE_secp256k1 + cost_B58CHECK_DECODING_SIGNATURE_p256)) + + let chain_id_optimized = atomic_step_cost cost_DECODING_CHAIN_ID + + let chain_id_readable = atomic_step_cost cost_B58CHECK_DECODING_CHAIN_ID + + (* Reasonable approximation *) + let address_optimized = key_hash_optimized + + (* Reasonable approximation *) + let contract_optimized = key_hash_optimized + + (* Reasonable approximation *) + let contract_readable = key_hash_readable + + let bls12_381_g1 = atomic_step_cost cost_DECODING_BLS_G1 + + let bls12_381_g2 = atomic_step_cost cost_DECODING_BLS_G2 + + let bls12_381_fr = atomic_step_cost cost_DECODING_BLS_FR + + let check_printable s = + atomic_step_cost (cost_CHECK_PRINTABLE (String.length s)) + + let merge_cycle = atomic_step_cost cost_MERGE_TYPES + + let parse_type_cycle = atomic_step_cost cost_PARSE_TYPE + + let parse_instr_cycle = atomic_step_cost cost_TYPECHECKING_CODE + + let parse_data_cycle = atomic_step_cost cost_TYPECHECKING_DATA + + let comparable_ty_of_ty_cycle = atomic_step_cost cost_COMPARABLE_TY_OF_TY + + (* Cost of a cycle of checking that a type is dupable *) + (* TODO: bench *) + let check_dupable_cycle = atomic_step_cost cost_TYPECHECKING_DATA + + let bool = free + + let unit = free + + let timestamp_readable = atomic_step_cost cost_TIMESTAMP_READABLE_DECODING + + (* Reasonable estimate. *) + let contract = Gas.(S.safe_int 2 *@ public_key_readable) + + (* Balance stored at /contracts/index/hash/balance, on 64 bits *) + let contract_exists = + Gas.cost_of_repr @@ Storage_costs.read_access ~path_length:4 ~read_bytes:8 + + (* Constructing proof arguments consists in a decreasing loop in the result + monad, allocating at each step. We charge a reasonable overapproximation. *) + let proof_argument n = + atomic_step_cost (S.mul (S.safe_int n) (S.safe_int 50)) + + let chest_key = atomic_step_cost cost_DECODING_Chest_key + + let chest ~bytes = atomic_step_cost (cost_DECODING_Chest ~bytes) + end + + module Unparsing = struct + open Generated_costs + + let public_key_optimized = + atomic_step_cost + @@ S.( + max + cost_ENCODING_PUBLIC_KEY_ed25519 + (max + cost_ENCODING_PUBLIC_KEY_secp256k1 + cost_ENCODING_PUBLIC_KEY_p256)) + + let public_key_readable = + atomic_step_cost + @@ S.( + max + cost_B58CHECK_ENCODING_PUBLIC_KEY_ed25519 + (max + cost_B58CHECK_ENCODING_PUBLIC_KEY_secp256k1 + cost_B58CHECK_ENCODING_PUBLIC_KEY_p256)) + + let key_hash_optimized = + atomic_step_cost + @@ S.( + max + cost_ENCODING_PUBLIC_KEY_HASH_ed25519 + (max + cost_ENCODING_PUBLIC_KEY_HASH_secp256k1 + cost_ENCODING_PUBLIC_KEY_HASH_p256)) + + let key_hash_readable = + atomic_step_cost + @@ S.( + max + cost_B58CHECK_ENCODING_PUBLIC_KEY_HASH_ed25519 + (max + cost_B58CHECK_ENCODING_PUBLIC_KEY_HASH_secp256k1 + cost_B58CHECK_ENCODING_PUBLIC_KEY_HASH_p256)) + + let signature_optimized = + atomic_step_cost + @@ S.( + max + cost_ENCODING_SIGNATURE_ed25519 + (max + cost_ENCODING_SIGNATURE_secp256k1 + cost_ENCODING_SIGNATURE_p256)) + + let signature_readable = + atomic_step_cost + @@ S.( + max + cost_B58CHECK_ENCODING_SIGNATURE_ed25519 + (max + cost_B58CHECK_ENCODING_SIGNATURE_secp256k1 + cost_B58CHECK_ENCODING_SIGNATURE_p256)) + + let chain_id_optimized = atomic_step_cost cost_ENCODING_CHAIN_ID + + let chain_id_readable = atomic_step_cost cost_B58CHECK_ENCODING_CHAIN_ID + + let timestamp_readable = atomic_step_cost cost_TIMESTAMP_READABLE_ENCODING + + (* Reasonable approximation *) + let address_optimized = key_hash_optimized + + (* Reasonable approximation *) + let contract_optimized = key_hash_optimized + + (* Reasonable approximation *) + let contract_readable = key_hash_readable + + let bls12_381_g1 = atomic_step_cost cost_ENCODING_BLS_G1 + + let bls12_381_g2 = atomic_step_cost cost_ENCODING_BLS_G2 + + let bls12_381_fr = atomic_step_cost cost_ENCODING_BLS_FR + + let unparse_type_cycle = atomic_step_cost cost_UNPARSE_TYPE + + let unparse_instr_cycle = atomic_step_cost cost_UNPARSING_CODE + + let unparse_data_cycle = atomic_step_cost cost_UNPARSING_DATA + + let unit = Gas.free + + (* Reasonable estimate. *) + let contract = Gas.(S.safe_int 2 *@ public_key_readable) + + (* Reuse 006 costs. *) + let operation bytes = Script.bytes_node_cost bytes + + let sapling_transaction (t : Sapling.transaction) = + let inputs = List.length t.inputs in + let outputs = List.length t.outputs in + atomic_step_cost (cost_SAPLING_TRANSACTION_ENCODING ~inputs ~outputs) + + let sapling_diff (d : Sapling.diff) = + let nfs = List.length d.nullifiers in + let cms = List.length d.commitments_and_ciphertexts in + atomic_step_cost (cost_SAPLING_DIFF_ENCODING ~nfs ~cms) + + let chest_key = atomic_step_cost cost_ENCODING_Chest_key + + let chest ~plaintext_size = + atomic_step_cost (cost_ENCODING_Chest ~plaintext_size) + end +end diff --git a/src/proto_011_PtHangzH/lib_protocol/michelson_v1_gas.mli b/src/proto_011_PtHangzH/lib_protocol/michelson_v1_gas.mli new file mode 100644 index 000000000000..35a3810a26c1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/michelson_v1_gas.mli @@ -0,0 +1,543 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +module Cost_of : sig + val manager_operation : Gas.cost + + module Interpreter : sig + val drop : Gas.cost + + val dup : Gas.cost + + val swap : Gas.cost + + val cons_some : Gas.cost + + val cons_none : Gas.cost + + val if_none : Gas.cost + + val cons_pair : Gas.cost + + val unpair : Gas.cost + + val car : Gas.cost + + val cdr : Gas.cost + + val cons_left : Gas.cost + + val cons_right : Gas.cost + + val if_left : Gas.cost + + val cons_list : Gas.cost + + val nil : Gas.cost + + val if_cons : Gas.cost + + val list_map : 'a Script_typed_ir.boxed_list -> Gas.cost + + val list_size : Gas.cost + + val list_iter : 'a Script_typed_ir.boxed_list -> Gas.cost + + val empty_set : Gas.cost + + val set_iter : 'a Script_typed_ir.set -> Gas.cost + + val set_mem : 'a -> 'a Script_typed_ir.set -> Gas.cost + + val set_update : 'a -> 'a Script_typed_ir.set -> Gas.cost + + val set_size : Gas.cost + + val empty_map : Gas.cost + + val map_map : ('k, 'v) Script_typed_ir.map -> Gas.cost + + val map_iter : ('k, 'v) Script_typed_ir.map -> Gas.cost + + val map_mem : 'k -> ('k, 'v) Script_typed_ir.map -> Gas.cost + + val map_get : 'k -> ('k, 'v) Script_typed_ir.map -> Gas.cost + + val map_update : 'k -> ('k, 'v) Script_typed_ir.map -> Gas.cost + + val map_get_and_update : 'k -> ('k, 'v) Script_typed_ir.map -> Gas.cost + + val big_map_mem : (_, _) Script_typed_ir.big_map_overlay -> Gas.cost + + val big_map_get : (_, _) Script_typed_ir.big_map_overlay -> Gas.cost + + val big_map_update : (_, _) Script_typed_ir.big_map_overlay -> Gas.cost + + val big_map_get_and_update : + (_, _) Script_typed_ir.big_map_overlay -> Gas.cost + + val map_size : Gas.cost + + val add_seconds_timestamp : + 'a Script_int.num -> Script_timestamp.t -> Gas.cost + + val add_timestamp_seconds : + Script_timestamp.t -> 'a Script_int.num -> Gas.cost + + val sub_timestamp_seconds : + Script_timestamp.t -> 'a Script_int.num -> Gas.cost + + val diff_timestamps : Script_timestamp.t -> Script_timestamp.t -> Gas.cost + + val concat_string_pair : Script_string.t -> Script_string.t -> Gas.cost + + val slice_string : Script_string.t -> Gas.cost + + val string_size : Gas.cost + + val concat_bytes_pair : bytes -> bytes -> Gas.cost + + val slice_bytes : bytes -> Gas.cost + + val bytes_size : Gas.cost + + val add_tez : Gas.cost + + val sub_tez : Gas.cost + + val mul_teznat : Gas.cost + + val mul_nattez : Gas.cost + + val bool_or : Gas.cost + + val bool_and : Gas.cost + + val bool_xor : Gas.cost + + val bool_not : Gas.cost + + val is_nat : Gas.cost + + val abs_int : Alpha_context.Script_int.z Script_int.num -> Gas.cost + + val int_nat : Gas.cost + + val neg_int : Alpha_context.Script_int.z Script_int.num -> Gas.cost + + val neg_nat : Alpha_context.Script_int.n Script_int.num -> Gas.cost + + val add_intint : + Alpha_context.Script_int.z Script_int.num -> + Alpha_context.Script_int.z Script_int.num -> + Gas.cost + + val add_intnat : + Alpha_context.Script_int.z Script_int.num -> + Alpha_context.Script_int.n Script_int.num -> + Gas.cost + + val add_natint : + Alpha_context.Script_int.n Script_int.num -> + Alpha_context.Script_int.z Script_int.num -> + Gas.cost + + val add_natnat : + Alpha_context.Script_int.n Script_int.num -> + Alpha_context.Script_int.n Script_int.num -> + Gas.cost + + val sub_int : 'a Script_int.num -> 'b Script_int.num -> Gas.cost + + val mul_intint : + Alpha_context.Script_int.z Script_int.num -> + Alpha_context.Script_int.z Script_int.num -> + Gas.cost + + val mul_intnat : + Alpha_context.Script_int.z Script_int.num -> + Alpha_context.Script_int.n Script_int.num -> + Gas.cost + + val mul_natint : + Alpha_context.Script_int.n Script_int.num -> + Alpha_context.Script_int.z Script_int.num -> + Gas.cost + + val mul_natnat : + Alpha_context.Script_int.n Script_int.num -> + Alpha_context.Script_int.n Script_int.num -> + Gas.cost + + val ediv_teznat : 'a -> 'b Script_int.num -> Gas.cost + + val ediv_tez : Gas.cost + + val ediv_intint : + Alpha_context.Script_int.z Script_int.num -> + Alpha_context.Script_int.z Script_int.num -> + Gas.cost + + val ediv_intnat : + Alpha_context.Script_int.z Script_int.num -> + Alpha_context.Script_int.n Script_int.num -> + Gas.cost + + val ediv_natint : + Alpha_context.Script_int.n Script_int.num -> + Alpha_context.Script_int.z Script_int.num -> + Gas.cost + + val ediv_natnat : + Alpha_context.Script_int.n Script_int.num -> + Alpha_context.Script_int.n Script_int.num -> + Gas.cost + + val eq : Gas.cost + + val lsl_nat : 'a Script_int.num -> Gas.cost + + val lsr_nat : 'a Script_int.num -> Gas.cost + + val or_nat : 'a Script_int.num -> 'b Script_int.num -> Gas.cost + + val and_nat : 'a Script_int.num -> 'b Script_int.num -> Gas.cost + + val and_int_nat : + Alpha_context.Script_int.z Script_int.num -> + Alpha_context.Script_int.n Script_int.num -> + Gas.cost + + val xor_nat : 'a Script_int.num -> 'b Script_int.num -> Gas.cost + + val not_int : 'a Script_int.num -> Gas.cost + + val not_nat : 'a Script_int.num -> Gas.cost + + val if_ : Gas.cost + + val loop : Gas.cost + + val loop_left : Gas.cost + + val dip : Gas.cost + + val check_signature : Signature.public_key -> bytes -> Gas.cost + + val blake2b : bytes -> Gas.cost + + val sha256 : bytes -> Gas.cost + + val sha512 : bytes -> Gas.cost + + val dign : int -> Gas.cost + + val dugn : int -> Gas.cost + + val dipn : int -> Gas.cost + + val dropn : int -> Gas.cost + + val voting_power : Gas.cost + + val total_voting_power : Gas.cost + + val keccak : bytes -> Gas.cost + + val sha3 : bytes -> Gas.cost + + val add_bls12_381_g1 : Gas.cost + + val add_bls12_381_g2 : Gas.cost + + val add_bls12_381_fr : Gas.cost + + val mul_bls12_381_g1 : Gas.cost + + val mul_bls12_381_g2 : Gas.cost + + val mul_bls12_381_fr : Gas.cost + + val mul_bls12_381_fr_z : 'a Script_int.num -> Gas.cost + + val mul_bls12_381_z_fr : 'a Script_int.num -> Gas.cost + + val int_bls12_381_fr : Gas.cost + + val neg_bls12_381_g1 : Gas.cost + + val neg_bls12_381_g2 : Gas.cost + + val neg_bls12_381_fr : Gas.cost + + val neq : Gas.cost + + val pairing_check_bls12_381 : 'a Script_typed_ir.boxed_list -> Gas.cost + + val comb : int -> Gas.cost + + val uncomb : int -> Gas.cost + + val comb_get : int -> Gas.cost + + val comb_set : int -> Gas.cost + + val dupn : int -> Gas.cost + + val compare : 'a Script_typed_ir.comparable_ty -> 'a -> 'a -> Gas.cost + + val concat_string_precheck : 'a Script_typed_ir.boxed_list -> Gas.cost + + val concat_string : + Saturation_repr.may_saturate Saturation_repr.t -> Gas.cost + + val concat_bytes : + Saturation_repr.may_saturate Saturation_repr.t -> Gas.cost + + val halt : Gas.cost + + val const : Gas.cost + + val empty_big_map : Gas.cost + + val lt : Gas.cost + + val le : Gas.cost + + val gt : Gas.cost + + val ge : Gas.cost + + val exec : Gas.cost + + val apply : Gas.cost + + val lambda : Gas.cost + + val address : Gas.cost + + val contract : Gas.cost + + val view : Gas.cost + + val view_mem : + Script_string.t -> Script_typed_ir.view Script_typed_ir.SMap.t -> Gas.cost + + val view_get : + Script_string.t -> Script_typed_ir.view Script_typed_ir.SMap.t -> Gas.cost + + val view_update : + Script_string.t -> Script_typed_ir.view Script_typed_ir.SMap.t -> Gas.cost + + val transfer_tokens : Gas.cost + + val implicit_account : Gas.cost + + val create_contract : Gas.cost + + val set_delegate : Gas.cost + + val balance : Gas.cost + + val level : Gas.cost + + val now : Gas.cost + + val hash_key : Signature.Public_key.t -> Gas.cost + + val source : Gas.cost + + val sender : Gas.cost + + val self : Gas.cost + + val self_address : Gas.cost + + val amount : Gas.cost + + val chain_id : Gas.cost + + val unpack : bytes -> Gas.cost + + val unpack_failed : bytes -> Gas.cost + + val sapling_empty_state : Gas.cost + + val sapling_verify_update : inputs:int -> outputs:int -> Gas.cost + + val ticket : Gas.cost + + val read_ticket : Gas.cost + + val split_ticket : + 'a Script_int.num -> 'a Script_int.num -> 'a Script_int.num -> Gas.cost + + val join_tickets : + 'a Script_typed_ir.comparable_ty -> + 'a Script_typed_ir.ticket -> + 'a Script_typed_ir.ticket -> + Gas.cost + + val open_chest : chest:Timelock.chest -> time:Z.t -> Gas.cost + + module Control : sig + val nil : Gas.cost + + val cons : Gas.cost + + val return : Gas.cost + + val undip : Gas.cost + + val loop_in : Gas.cost + + val loop_in_left : Gas.cost + + val iter : Gas.cost + + val list_enter_body : 'a list -> int -> Gas.cost + + val list_exit_body : Gas.cost + + val map_enter_body : Gas.cost + + val map_exit_body : 'k -> ('k, 'v) Script_typed_ir.map -> Gas.cost + end + end + + module Typechecking : sig + val public_key_optimized : Gas.cost + + val public_key_readable : Gas.cost + + val key_hash_optimized : Gas.cost + + val key_hash_readable : Gas.cost + + val signature_optimized : Gas.cost + + val signature_readable : Gas.cost + + val chain_id_optimized : Gas.cost + + val chain_id_readable : Gas.cost + + val address_optimized : Gas.cost + + val contract_optimized : Gas.cost + + val contract_readable : Gas.cost + + val bls12_381_g1 : Gas.cost + + val bls12_381_g2 : Gas.cost + + val bls12_381_fr : Gas.cost + + val check_printable : string -> Gas.cost + + val merge_cycle : Gas.cost + + val parse_type_cycle : Gas.cost + + val parse_instr_cycle : Gas.cost + + val parse_data_cycle : Gas.cost + + val comparable_ty_of_ty_cycle : Gas.cost + + val check_dupable_cycle : Gas.cost + + val bool : Gas.cost + + val unit : Gas.cost + + val timestamp_readable : Gas.cost + + val contract : Gas.cost + + val contract_exists : Gas.cost + + val proof_argument : int -> Gas.cost + + val chest_key : Gas.cost + + val chest : bytes:int -> Gas.cost + end + + module Unparsing : sig + val public_key_optimized : Gas.cost + + val public_key_readable : Gas.cost + + val key_hash_optimized : Gas.cost + + val key_hash_readable : Gas.cost + + val signature_optimized : Gas.cost + + val signature_readable : Gas.cost + + val chain_id_optimized : Gas.cost + + val chain_id_readable : Gas.cost + + val timestamp_readable : Gas.cost + + val address_optimized : Gas.cost + + val contract_optimized : Gas.cost + + val contract_readable : Gas.cost + + val bls12_381_g1 : Gas.cost + + val bls12_381_g2 : Gas.cost + + val bls12_381_fr : Gas.cost + + val unparse_type_cycle : Gas.cost + + val unparse_instr_cycle : Gas.cost + + val unparse_data_cycle : Gas.cost + + val unit : Gas.cost + + val contract : Gas.cost + + val operation : bytes -> Gas.cost + + val sapling_transaction : Sapling.transaction -> Gas.cost + + val sapling_diff : Sapling.diff -> Gas.cost + + val chest_key : Gas.cost + + val chest : plaintext_size:int -> Gas.cost + end +end diff --git a/src/proto_011_PtHangzH/lib_protocol/michelson_v1_primitives.ml b/src/proto_011_PtHangzH/lib_protocol/michelson_v1_primitives.ml new file mode 100644 index 000000000000..5197d0a887af --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/michelson_v1_primitives.ml @@ -0,0 +1,794 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Micheline + +type error += Unknown_primitive_name of string + +type error += Invalid_case of string + +type error += + | Invalid_primitive_name of + string Micheline.canonical * Micheline.canonical_location + +type prim = + | K_parameter + | K_storage + | K_code + | K_view + | D_False + | D_Elt + | D_Left + | D_None + | D_Pair + | D_Right + | D_Some + | D_True + | D_Unit + | I_PACK + | I_UNPACK + | I_BLAKE2B + | I_SHA256 + | I_SHA512 + | I_ABS + | I_ADD + | I_AMOUNT + | I_AND + | I_BALANCE + | I_CAR + | I_CDR + | I_CHAIN_ID + | I_CHECK_SIGNATURE + | I_COMPARE + | I_CONCAT + | I_CONS + | I_CREATE_ACCOUNT + | I_CREATE_CONTRACT + | I_IMPLICIT_ACCOUNT + | I_DIP + | I_DROP + | I_DUP + | I_VIEW + | I_EDIV + | I_EMPTY_BIG_MAP + | I_EMPTY_MAP + | I_EMPTY_SET + | I_EQ + | I_EXEC + | I_APPLY + | I_FAILWITH + | I_GE + | I_GET + | I_GET_AND_UPDATE + | I_GT + | I_HASH_KEY + | I_IF + | I_IF_CONS + | I_IF_LEFT + | I_IF_NONE + | I_INT + | I_LAMBDA + | I_LE + | I_LEFT + | I_LEVEL + | I_LOOP + | I_LSL + | I_LSR + | I_LT + | I_MAP + | I_MEM + | I_MUL + | I_NEG + | I_NEQ + | I_NIL + | I_NONE + | I_NOT + | I_NOW + | I_OR + | I_PAIR + | I_UNPAIR + | I_PUSH + | I_RIGHT + | I_SIZE + | I_SOME + | I_SOURCE + | I_SENDER + | I_SELF + | I_SELF_ADDRESS + | I_SLICE + | I_STEPS_TO_QUOTA + | I_SUB + | I_SWAP + | I_TRANSFER_TOKENS + | I_SET_DELEGATE + | I_UNIT + | I_UPDATE + | I_XOR + | I_ITER + | I_LOOP_LEFT + | I_ADDRESS + | I_CONTRACT + | I_ISNAT + | I_CAST + | I_RENAME + | I_SAPLING_EMPTY_STATE + | I_SAPLING_VERIFY_UPDATE + | I_DIG + | I_DUG + | I_NEVER + | I_VOTING_POWER + | I_TOTAL_VOTING_POWER + | I_KECCAK + | I_SHA3 + | I_PAIRING_CHECK + | I_TICKET + | I_READ_TICKET + | I_SPLIT_TICKET + | I_JOIN_TICKETS + | I_OPEN_CHEST + | T_bool + | T_contract + | T_int + | T_key + | T_key_hash + | T_lambda + | T_list + | T_map + | T_big_map + | T_nat + | T_option + | T_or + | T_pair + | T_set + | T_signature + | T_string + | T_bytes + | T_mutez + | T_timestamp + | T_unit + | T_operation + | T_address + | T_sapling_transaction + | T_sapling_state + | T_chain_id + | T_never + | T_bls12_381_g1 + | T_bls12_381_g2 + | T_bls12_381_fr + | T_ticket + | T_chest_key + | T_chest + | H_constant + +(* Auxiliary types for error documentation. + All the prim constructor prefixes must match their namespace. *) +type namespace = + | (* prefix "T" *) Type_namespace + | (* prefix "D" *) Constant_namespace + | (* prefix "I" *) Instr_namespace + | (* prefix "K" *) Keyword_namespace + | (* prefix "H" *) Constant_hash_namespace + +let namespace = function + | K_code | K_view | K_parameter | K_storage -> Keyword_namespace + | D_Elt | D_False | D_Left | D_None | D_Pair | D_Right | D_Some | D_True + | D_Unit -> + Constant_namespace + | I_ABS | I_ADD | I_ADDRESS | I_AMOUNT | I_AND | I_APPLY | I_BALANCE + | I_BLAKE2B | I_CAR | I_CAST | I_CDR | I_CHAIN_ID | I_CHECK_SIGNATURE + | I_COMPARE | I_CONCAT | I_CONS | I_CONTRACT | I_CREATE_ACCOUNT + | I_CREATE_CONTRACT | I_DIG | I_DIP | I_DROP | I_DUG | I_DUP | I_VIEW | I_EDIV + | I_EMPTY_BIG_MAP | I_EMPTY_MAP | I_EMPTY_SET | I_EQ | I_EXEC | I_FAILWITH + | I_GE | I_GET | I_GET_AND_UPDATE | I_GT | I_HASH_KEY | I_IF | I_IF_CONS + | I_IF_LEFT | I_IF_NONE | I_IMPLICIT_ACCOUNT | I_INT | I_ISNAT | I_ITER + | I_JOIN_TICKETS | I_KECCAK | I_LAMBDA | I_LE | I_LEFT | I_LEVEL | I_LOOP + | I_LOOP_LEFT | I_LSL | I_LSR | I_LT | I_MAP | I_MEM | I_MUL | I_NEG | I_NEQ + | I_NEVER | I_NIL | I_NONE | I_NOT | I_NOW | I_OR | I_PACK | I_PAIR + | I_PAIRING_CHECK | I_PUSH | I_READ_TICKET | I_RENAME | I_RIGHT + | I_SAPLING_EMPTY_STATE | I_SAPLING_VERIFY_UPDATE | I_SELF | I_SELF_ADDRESS + | I_SENDER | I_SET_DELEGATE | I_SHA256 | I_SHA512 | I_SHA3 | I_SIZE | I_SLICE + | I_SOME | I_SOURCE | I_SPLIT_TICKET | I_STEPS_TO_QUOTA | I_SUB | I_SWAP + | I_TICKET | I_TOTAL_VOTING_POWER | I_TRANSFER_TOKENS | I_UNIT | I_UNPACK + | I_UNPAIR | I_UPDATE | I_VOTING_POWER | I_XOR | I_OPEN_CHEST -> + Instr_namespace + | T_address | T_big_map | T_bool | T_bytes | T_chain_id | T_contract | T_int + | T_key | T_key_hash | T_lambda | T_list | T_map | T_mutez | T_nat | T_never + | T_operation | T_option | T_or | T_pair | T_sapling_state + | T_sapling_transaction | T_set | T_signature | T_string | T_timestamp + | T_unit | T_bls12_381_fr | T_bls12_381_g1 | T_bls12_381_g2 | T_ticket + | T_chest_key | T_chest -> + Type_namespace + | H_constant -> Constant_hash_namespace + +let valid_case name = + let is_lower = function '_' | 'a' .. 'z' -> true | _ -> false in + let is_upper = function '_' | 'A' .. 'Z' -> true | _ -> false in + let[@coq_struct "a_value"] rec for_all a b f = + Compare.Int.(a > b) || (f a && for_all (a + 1) b f) + in + let len = String.length name in + Compare.Int.(len <> 0) + && Compare.Char.(name.[0] <> '_') + && ((is_upper name.[0] && for_all 1 (len - 1) (fun i -> is_upper name.[i])) + || (is_upper name.[0] && for_all 1 (len - 1) (fun i -> is_lower name.[i])) + || (is_lower name.[0] && for_all 1 (len - 1) (fun i -> is_lower name.[i])) + ) + +let string_of_prim = function + | K_parameter -> "parameter" + | K_storage -> "storage" + | K_code -> "code" + | K_view -> "view" + | D_False -> "False" + | D_Elt -> "Elt" + | D_Left -> "Left" + | D_None -> "None" + | D_Pair -> "Pair" + | D_Right -> "Right" + | D_Some -> "Some" + | D_True -> "True" + | D_Unit -> "Unit" + | I_PACK -> "PACK" + | I_UNPACK -> "UNPACK" + | I_BLAKE2B -> "BLAKE2B" + | I_SHA256 -> "SHA256" + | I_SHA512 -> "SHA512" + | I_ABS -> "ABS" + | I_ADD -> "ADD" + | I_AMOUNT -> "AMOUNT" + | I_AND -> "AND" + | I_BALANCE -> "BALANCE" + | I_CAR -> "CAR" + | I_CDR -> "CDR" + | I_CHAIN_ID -> "CHAIN_ID" + | I_CHECK_SIGNATURE -> "CHECK_SIGNATURE" + | I_COMPARE -> "COMPARE" + | I_CONCAT -> "CONCAT" + | I_CONS -> "CONS" + | I_CREATE_ACCOUNT -> "CREATE_ACCOUNT" + | I_CREATE_CONTRACT -> "CREATE_CONTRACT" + | I_IMPLICIT_ACCOUNT -> "IMPLICIT_ACCOUNT" + | I_DIP -> "DIP" + | I_DROP -> "DROP" + | I_DUP -> "DUP" + | I_EDIV -> "EDIV" + | I_EMPTY_BIG_MAP -> "EMPTY_BIG_MAP" + | I_EMPTY_MAP -> "EMPTY_MAP" + | I_EMPTY_SET -> "EMPTY_SET" + | I_EQ -> "EQ" + | I_EXEC -> "EXEC" + | I_APPLY -> "APPLY" + | I_FAILWITH -> "FAILWITH" + | I_GE -> "GE" + | I_GET -> "GET" + | I_GET_AND_UPDATE -> "GET_AND_UPDATE" + | I_GT -> "GT" + | I_HASH_KEY -> "HASH_KEY" + | I_IF -> "IF" + | I_IF_CONS -> "IF_CONS" + | I_IF_LEFT -> "IF_LEFT" + | I_IF_NONE -> "IF_NONE" + | I_INT -> "INT" + | I_LAMBDA -> "LAMBDA" + | I_LE -> "LE" + | I_LEFT -> "LEFT" + | I_LEVEL -> "LEVEL" + | I_LOOP -> "LOOP" + | I_LSL -> "LSL" + | I_LSR -> "LSR" + | I_LT -> "LT" + | I_MAP -> "MAP" + | I_MEM -> "MEM" + | I_MUL -> "MUL" + | I_NEG -> "NEG" + | I_NEQ -> "NEQ" + | I_NIL -> "NIL" + | I_NONE -> "NONE" + | I_NOT -> "NOT" + | I_NOW -> "NOW" + | I_OR -> "OR" + | I_PAIR -> "PAIR" + | I_PUSH -> "PUSH" + | I_RIGHT -> "RIGHT" + | I_SIZE -> "SIZE" + | I_SOME -> "SOME" + | I_SOURCE -> "SOURCE" + | I_SENDER -> "SENDER" + | I_SELF -> "SELF" + | I_SELF_ADDRESS -> "SELF_ADDRESS" + | I_SLICE -> "SLICE" + | I_STEPS_TO_QUOTA -> "STEPS_TO_QUOTA" + | I_SUB -> "SUB" + | I_SWAP -> "SWAP" + | I_TRANSFER_TOKENS -> "TRANSFER_TOKENS" + | I_SET_DELEGATE -> "SET_DELEGATE" + | I_UNIT -> "UNIT" + | I_UNPAIR -> "UNPAIR" + | I_UPDATE -> "UPDATE" + | I_XOR -> "XOR" + | I_ITER -> "ITER" + | I_LOOP_LEFT -> "LOOP_LEFT" + | I_ADDRESS -> "ADDRESS" + | I_CONTRACT -> "CONTRACT" + | I_ISNAT -> "ISNAT" + | I_CAST -> "CAST" + | I_RENAME -> "RENAME" + | I_SAPLING_EMPTY_STATE -> "SAPLING_EMPTY_STATE" + | I_SAPLING_VERIFY_UPDATE -> "SAPLING_VERIFY_UPDATE" + | I_DIG -> "DIG" + | I_DUG -> "DUG" + | I_NEVER -> "NEVER" + | I_VOTING_POWER -> "VOTING_POWER" + | I_TOTAL_VOTING_POWER -> "TOTAL_VOTING_POWER" + | I_KECCAK -> "KECCAK" + | I_SHA3 -> "SHA3" + | I_PAIRING_CHECK -> "PAIRING_CHECK" + | I_TICKET -> "TICKET" + | I_READ_TICKET -> "READ_TICKET" + | I_SPLIT_TICKET -> "SPLIT_TICKET" + | I_JOIN_TICKETS -> "JOIN_TICKETS" + | I_OPEN_CHEST -> "OPEN_CHEST" + | I_VIEW -> "VIEW" + | T_bool -> "bool" + | T_contract -> "contract" + | T_int -> "int" + | T_key -> "key" + | T_key_hash -> "key_hash" + | T_lambda -> "lambda" + | T_list -> "list" + | T_map -> "map" + | T_big_map -> "big_map" + | T_nat -> "nat" + | T_option -> "option" + | T_or -> "or" + | T_pair -> "pair" + | T_set -> "set" + | T_signature -> "signature" + | T_string -> "string" + | T_bytes -> "bytes" + | T_mutez -> "mutez" + | T_timestamp -> "timestamp" + | T_unit -> "unit" + | T_operation -> "operation" + | T_address -> "address" + | T_sapling_state -> "sapling_state" + | T_sapling_transaction -> "sapling_transaction" + | T_chain_id -> "chain_id" + | T_never -> "never" + | T_bls12_381_g1 -> "bls12_381_g1" + | T_bls12_381_g2 -> "bls12_381_g2" + | T_bls12_381_fr -> "bls12_381_fr" + | T_ticket -> "ticket" + | T_chest_key -> "chest_key" + | T_chest -> "chest" + | H_constant -> "constant" + +let prim_of_string = function + | "parameter" -> ok K_parameter + | "storage" -> ok K_storage + | "code" -> ok K_code + | "view" -> ok K_view + | "False" -> ok D_False + | "Elt" -> ok D_Elt + | "Left" -> ok D_Left + | "None" -> ok D_None + | "Pair" -> ok D_Pair + | "Right" -> ok D_Right + | "Some" -> ok D_Some + | "True" -> ok D_True + | "Unit" -> ok D_Unit + | "PACK" -> ok I_PACK + | "UNPACK" -> ok I_UNPACK + | "BLAKE2B" -> ok I_BLAKE2B + | "SHA256" -> ok I_SHA256 + | "SHA512" -> ok I_SHA512 + | "ABS" -> ok I_ABS + | "ADD" -> ok I_ADD + | "AMOUNT" -> ok I_AMOUNT + | "AND" -> ok I_AND + | "BALANCE" -> ok I_BALANCE + | "CAR" -> ok I_CAR + | "CDR" -> ok I_CDR + | "CHAIN_ID" -> ok I_CHAIN_ID + | "CHECK_SIGNATURE" -> ok I_CHECK_SIGNATURE + | "COMPARE" -> ok I_COMPARE + | "CONCAT" -> ok I_CONCAT + | "CONS" -> ok I_CONS + | "CREATE_ACCOUNT" -> ok I_CREATE_ACCOUNT + | "CREATE_CONTRACT" -> ok I_CREATE_CONTRACT + | "IMPLICIT_ACCOUNT" -> ok I_IMPLICIT_ACCOUNT + | "DIP" -> ok I_DIP + | "DROP" -> ok I_DROP + | "DUP" -> ok I_DUP + | "VIEW" -> ok I_VIEW + | "EDIV" -> ok I_EDIV + | "EMPTY_BIG_MAP" -> ok I_EMPTY_BIG_MAP + | "EMPTY_MAP" -> ok I_EMPTY_MAP + | "EMPTY_SET" -> ok I_EMPTY_SET + | "EQ" -> ok I_EQ + | "EXEC" -> ok I_EXEC + | "APPLY" -> ok I_APPLY + | "FAILWITH" -> ok I_FAILWITH + | "GE" -> ok I_GE + | "GET" -> ok I_GET + | "GET_AND_UPDATE" -> ok I_GET_AND_UPDATE + | "GT" -> ok I_GT + | "HASH_KEY" -> ok I_HASH_KEY + | "IF" -> ok I_IF + | "IF_CONS" -> ok I_IF_CONS + | "IF_LEFT" -> ok I_IF_LEFT + | "IF_NONE" -> ok I_IF_NONE + | "INT" -> ok I_INT + | "KECCAK" -> ok I_KECCAK + | "LAMBDA" -> ok I_LAMBDA + | "LE" -> ok I_LE + | "LEFT" -> ok I_LEFT + | "LEVEL" -> ok I_LEVEL + | "LOOP" -> ok I_LOOP + | "LSL" -> ok I_LSL + | "LSR" -> ok I_LSR + | "LT" -> ok I_LT + | "MAP" -> ok I_MAP + | "MEM" -> ok I_MEM + | "MUL" -> ok I_MUL + | "NEG" -> ok I_NEG + | "NEQ" -> ok I_NEQ + | "NIL" -> ok I_NIL + | "NONE" -> ok I_NONE + | "NOT" -> ok I_NOT + | "NOW" -> ok I_NOW + | "OR" -> ok I_OR + | "PAIR" -> ok I_PAIR + | "UNPAIR" -> ok I_UNPAIR + | "PAIRING_CHECK" -> ok I_PAIRING_CHECK + | "PUSH" -> ok I_PUSH + | "RIGHT" -> ok I_RIGHT + | "SHA3" -> ok I_SHA3 + | "SIZE" -> ok I_SIZE + | "SOME" -> ok I_SOME + | "SOURCE" -> ok I_SOURCE + | "SENDER" -> ok I_SENDER + | "SELF" -> ok I_SELF + | "SELF_ADDRESS" -> ok I_SELF_ADDRESS + | "SLICE" -> ok I_SLICE + | "STEPS_TO_QUOTA" -> ok I_STEPS_TO_QUOTA + | "SUB" -> ok I_SUB + | "SWAP" -> ok I_SWAP + | "TRANSFER_TOKENS" -> ok I_TRANSFER_TOKENS + | "SET_DELEGATE" -> ok I_SET_DELEGATE + | "UNIT" -> ok I_UNIT + | "UPDATE" -> ok I_UPDATE + | "XOR" -> ok I_XOR + | "ITER" -> ok I_ITER + | "LOOP_LEFT" -> ok I_LOOP_LEFT + | "ADDRESS" -> ok I_ADDRESS + | "CONTRACT" -> ok I_CONTRACT + | "ISNAT" -> ok I_ISNAT + | "CAST" -> ok I_CAST + | "RENAME" -> ok I_RENAME + | "SAPLING_EMPTY_STATE" -> ok I_SAPLING_EMPTY_STATE + | "SAPLING_VERIFY_UPDATE" -> ok I_SAPLING_VERIFY_UPDATE + | "DIG" -> ok I_DIG + | "DUG" -> ok I_DUG + | "NEVER" -> ok I_NEVER + | "VOTING_POWER" -> ok I_VOTING_POWER + | "TOTAL_VOTING_POWER" -> ok I_TOTAL_VOTING_POWER + | "TICKET" -> ok I_TICKET + | "READ_TICKET" -> ok I_READ_TICKET + | "SPLIT_TICKET" -> ok I_SPLIT_TICKET + | "JOIN_TICKETS" -> ok I_JOIN_TICKETS + | "OPEN_CHEST" -> ok I_OPEN_CHEST + | "bool" -> ok T_bool + | "contract" -> ok T_contract + | "int" -> ok T_int + | "key" -> ok T_key + | "key_hash" -> ok T_key_hash + | "lambda" -> ok T_lambda + | "list" -> ok T_list + | "map" -> ok T_map + | "big_map" -> ok T_big_map + | "nat" -> ok T_nat + | "option" -> ok T_option + | "or" -> ok T_or + | "pair" -> ok T_pair + | "set" -> ok T_set + | "signature" -> ok T_signature + | "string" -> ok T_string + | "bytes" -> ok T_bytes + | "mutez" -> ok T_mutez + | "timestamp" -> ok T_timestamp + | "unit" -> ok T_unit + | "operation" -> ok T_operation + | "address" -> ok T_address + | "sapling_state" -> ok T_sapling_state + | "sapling_transaction" -> ok T_sapling_transaction + | "chain_id" -> ok T_chain_id + | "never" -> ok T_never + | "bls12_381_g1" -> ok T_bls12_381_g1 + | "bls12_381_g2" -> ok T_bls12_381_g2 + | "bls12_381_fr" -> ok T_bls12_381_fr + | "ticket" -> ok T_ticket + | "chest_key" -> ok T_chest_key + | "chest" -> ok T_chest + | "constant" -> ok H_constant + | n -> + if valid_case n then error (Unknown_primitive_name n) + else error (Invalid_case n) + +let prims_of_strings expr = + let rec convert = function + | (Int _ | String _ | Bytes _) as expr -> ok expr + | Prim (loc, prim, args, annot) -> + Error_monad.record_trace + (Invalid_primitive_name (expr, loc)) + (prim_of_string prim) + >>? fun prim -> + List.map_e convert args >|? fun args -> Prim (0, prim, args, annot) + | Seq (_, args) -> List.map_e convert args >|? fun args -> Seq (0, args) + in + convert (root expr) >|? fun expr -> strip_locations expr + [@@coq_axiom_with_reason + "implicit type conversion for expr in the constant cases"] + +let strings_of_prims expr = + let rec convert = function + | (Int _ | String _ | Bytes _) as expr -> expr + | Prim (_, prim, args, annot) -> + let prim = string_of_prim prim in + let args = List.map convert args in + Prim (0, prim, args, annot) + | Seq (_, args) -> + let args = List.map convert args in + Seq (0, args) + in + strip_locations (convert (root expr)) + [@@coq_axiom_with_reason + "implicit type conversion for expr in the constant cases"] + +let prim_encoding = + let open Data_encoding in + def "michelson.v1.primitives" + @@ string_enum + (* Add the comment below every 10 lines *) + [ + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + ("parameter", K_parameter); + ("storage", K_storage); + ("code", K_code); + ("False", D_False); + ("Elt", D_Elt); + ("Left", D_Left); + ("None", D_None); + ("Pair", D_Pair); + ("Right", D_Right); + ("Some", D_Some); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + ("True", D_True); + ("Unit", D_Unit); + ("PACK", I_PACK); + ("UNPACK", I_UNPACK); + ("BLAKE2B", I_BLAKE2B); + ("SHA256", I_SHA256); + ("SHA512", I_SHA512); + ("ABS", I_ABS); + ("ADD", I_ADD); + ("AMOUNT", I_AMOUNT); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + ("AND", I_AND); + ("BALANCE", I_BALANCE); + ("CAR", I_CAR); + ("CDR", I_CDR); + ("CHECK_SIGNATURE", I_CHECK_SIGNATURE); + ("COMPARE", I_COMPARE); + ("CONCAT", I_CONCAT); + ("CONS", I_CONS); + ("CREATE_ACCOUNT", I_CREATE_ACCOUNT); + ("CREATE_CONTRACT", I_CREATE_CONTRACT); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + ("IMPLICIT_ACCOUNT", I_IMPLICIT_ACCOUNT); + ("DIP", I_DIP); + ("DROP", I_DROP); + ("DUP", I_DUP); + ("EDIV", I_EDIV); + ("EMPTY_MAP", I_EMPTY_MAP); + ("EMPTY_SET", I_EMPTY_SET); + ("EQ", I_EQ); + ("EXEC", I_EXEC); + ("FAILWITH", I_FAILWITH); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + ("GE", I_GE); + ("GET", I_GET); + ("GT", I_GT); + ("HASH_KEY", I_HASH_KEY); + ("IF", I_IF); + ("IF_CONS", I_IF_CONS); + ("IF_LEFT", I_IF_LEFT); + ("IF_NONE", I_IF_NONE); + ("INT", I_INT); + ("LAMBDA", I_LAMBDA); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + ("LE", I_LE); + ("LEFT", I_LEFT); + ("LOOP", I_LOOP); + ("LSL", I_LSL); + ("LSR", I_LSR); + ("LT", I_LT); + ("MAP", I_MAP); + ("MEM", I_MEM); + ("MUL", I_MUL); + ("NEG", I_NEG); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + ("NEQ", I_NEQ); + ("NIL", I_NIL); + ("NONE", I_NONE); + ("NOT", I_NOT); + ("NOW", I_NOW); + ("OR", I_OR); + ("PAIR", I_PAIR); + ("PUSH", I_PUSH); + ("RIGHT", I_RIGHT); + ("SIZE", I_SIZE); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + ("SOME", I_SOME); + ("SOURCE", I_SOURCE); + ("SENDER", I_SENDER); + ("SELF", I_SELF); + ("STEPS_TO_QUOTA", I_STEPS_TO_QUOTA); + ("SUB", I_SUB); + ("SWAP", I_SWAP); + ("TRANSFER_TOKENS", I_TRANSFER_TOKENS); + ("SET_DELEGATE", I_SET_DELEGATE); + ("UNIT", I_UNIT); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + ("UPDATE", I_UPDATE); + ("XOR", I_XOR); + ("ITER", I_ITER); + ("LOOP_LEFT", I_LOOP_LEFT); + ("ADDRESS", I_ADDRESS); + ("CONTRACT", I_CONTRACT); + ("ISNAT", I_ISNAT); + ("CAST", I_CAST); + ("RENAME", I_RENAME); + ("bool", T_bool); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + ("contract", T_contract); + ("int", T_int); + ("key", T_key); + ("key_hash", T_key_hash); + ("lambda", T_lambda); + ("list", T_list); + ("map", T_map); + ("big_map", T_big_map); + ("nat", T_nat); + ("option", T_option); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + ("or", T_or); + ("pair", T_pair); + ("set", T_set); + ("signature", T_signature); + ("string", T_string); + ("bytes", T_bytes); + ("mutez", T_mutez); + ("timestamp", T_timestamp); + ("unit", T_unit); + ("operation", T_operation); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + ("address", T_address); + (* Alpha_002 addition *) + ("SLICE", I_SLICE); + (* Alpha_005 addition *) + ("DIG", I_DIG); + ("DUG", I_DUG); + ("EMPTY_BIG_MAP", I_EMPTY_BIG_MAP); + ("APPLY", I_APPLY); + ("chain_id", T_chain_id); + ("CHAIN_ID", I_CHAIN_ID); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + (* Alpha_008 addition *) + ("LEVEL", I_LEVEL); + ("SELF_ADDRESS", I_SELF_ADDRESS); + ("never", T_never); + ("NEVER", I_NEVER); + ("UNPAIR", I_UNPAIR); + ("VOTING_POWER", I_VOTING_POWER); + ("TOTAL_VOTING_POWER", I_TOTAL_VOTING_POWER); + ("KECCAK", I_KECCAK); + ("SHA3", I_SHA3); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + (* Alpha_008 addition *) + ("PAIRING_CHECK", I_PAIRING_CHECK); + ("bls12_381_g1", T_bls12_381_g1); + ("bls12_381_g2", T_bls12_381_g2); + ("bls12_381_fr", T_bls12_381_fr); + ("sapling_state", T_sapling_state); + ("sapling_transaction", T_sapling_transaction); + ("SAPLING_EMPTY_STATE", I_SAPLING_EMPTY_STATE); + ("SAPLING_VERIFY_UPDATE", I_SAPLING_VERIFY_UPDATE); + ("ticket", T_ticket); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + (* Alpha_008 addition *) + ("TICKET", I_TICKET); + ("READ_TICKET", I_READ_TICKET); + ("SPLIT_TICKET", I_SPLIT_TICKET); + ("JOIN_TICKETS", I_JOIN_TICKETS); + ("GET_AND_UPDATE", I_GET_AND_UPDATE); + (* /!\ NEW INSTRUCTIONS MUST BE ADDED AT THE END OF THE STRING_ENUM, FOR BACKWARD COMPATIBILITY OF THE ENCODING. *) + (* Alpha_011 addition *) + ("chest", T_chest); + ("chest_key", T_chest_key); + ("OPEN_CHEST", I_OPEN_CHEST); + ("VIEW", I_VIEW); + ("view", K_view); + ("constant", H_constant); + (* New instructions must be added here, for backward compatibility of the encoding. *) + (* Keep the comment above at the end of the list *) + ] + +let () = + register_error_kind + `Permanent + ~id:"michelson_v1.unknown_primitive_name" + ~title:"Unknown primitive name" + ~description:"In a script or data expression, a primitive was unknown." + ~pp:(fun ppf n -> Format.fprintf ppf "Unknown primitive %s." n) + Data_encoding.(obj1 (req "wrong_primitive_name" string)) + (function Unknown_primitive_name got -> Some got | _ -> None) + (fun got -> Unknown_primitive_name got) ; + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_primitive_name_case" + ~title:"Invalid primitive name case" + ~description: + "In a script or data expression, a primitive name is neither uppercase, \ + lowercase or capitalized." + ~pp:(fun ppf n -> Format.fprintf ppf "Primitive %s has invalid case." n) + Data_encoding.(obj1 (req "wrong_primitive_name" string)) + (function Invalid_case name -> Some name | _ -> None) + (fun name -> Invalid_case name) ; + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_primitive_name" + ~title:"Invalid primitive name" + ~description: + "In a script or data expression, a primitive name is unknown or has a \ + wrong case." + ~pp:(fun ppf _ -> Format.fprintf ppf "Invalid primitive.") + Data_encoding.( + obj2 + (req + "expression" + (Micheline.canonical_encoding ~variant:"generic" string)) + (req "location" Micheline.canonical_location_encoding)) + (function + | Invalid_primitive_name (expr, loc) -> Some (expr, loc) | _ -> None) + (fun (expr, loc) -> Invalid_primitive_name (expr, loc)) + +let string_of_namespace = function + | Type_namespace -> "T" + | Constant_namespace -> "D" + | Instr_namespace -> "I" + | Keyword_namespace -> "K" + | Constant_hash_namespace -> "H" diff --git a/src/proto_011_PtHangzH/lib_protocol/michelson_v1_primitives.mli b/src/proto_011_PtHangzH/lib_protocol/michelson_v1_primitives.mli new file mode 100644 index 000000000000..acd82bf9634e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/michelson_v1_primitives.mli @@ -0,0 +1,220 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += (* `Permanent *) Unknown_primitive_name of string + +type error += (* `Permanent *) Invalid_case of string + +type error += + | (* `Permanent *) + Invalid_primitive_name of + string Micheline.canonical * Micheline.canonical_location + +(** Types of nodes in Michelson's AST. They fall into 4 categories: + - types (prefixed with [T_]); + - constants (prefixed with [D_]); + - instructions (prefixed with [I_]); + - keywords (prefixed with [K_]). *) +type prim = + | K_parameter + | K_storage + | K_code + | K_view + | D_False + | D_Elt + | D_Left + | D_None + | D_Pair + | D_Right + | D_Some + | D_True + | D_Unit + | I_PACK + | I_UNPACK + | I_BLAKE2B + | I_SHA256 + | I_SHA512 + | I_ABS + | I_ADD + | I_AMOUNT + | I_AND + | I_BALANCE + | I_CAR + | I_CDR + | I_CHAIN_ID + | I_CHECK_SIGNATURE + | I_COMPARE + | I_CONCAT + | I_CONS + | I_CREATE_ACCOUNT + | I_CREATE_CONTRACT + | I_IMPLICIT_ACCOUNT + | I_DIP + | I_DROP + | I_DUP + | I_VIEW + | I_EDIV + | I_EMPTY_BIG_MAP + | I_EMPTY_MAP + | I_EMPTY_SET + | I_EQ + | I_EXEC + | I_APPLY + | I_FAILWITH + | I_GE + | I_GET + | I_GET_AND_UPDATE + | I_GT + | I_HASH_KEY + | I_IF + | I_IF_CONS + | I_IF_LEFT + | I_IF_NONE + | I_INT + | I_LAMBDA + | I_LE + | I_LEFT + | I_LEVEL + | I_LOOP + | I_LSL + | I_LSR + | I_LT + | I_MAP + | I_MEM + | I_MUL + | I_NEG + | I_NEQ + | I_NIL + | I_NONE + | I_NOT + | I_NOW + | I_OR + | I_PAIR + | I_UNPAIR + | I_PUSH + | I_RIGHT + | I_SIZE + | I_SOME + | I_SOURCE + | I_SENDER + | I_SELF + | I_SELF_ADDRESS + | I_SLICE + | I_STEPS_TO_QUOTA + | I_SUB + | I_SWAP + | I_TRANSFER_TOKENS + | I_SET_DELEGATE + | I_UNIT + | I_UPDATE + | I_XOR + | I_ITER + | I_LOOP_LEFT + | I_ADDRESS + | I_CONTRACT + | I_ISNAT + | I_CAST + | I_RENAME + | I_SAPLING_EMPTY_STATE + | I_SAPLING_VERIFY_UPDATE + | I_DIG + | I_DUG + | I_NEVER + | I_VOTING_POWER + | I_TOTAL_VOTING_POWER + | I_KECCAK + | I_SHA3 + | I_PAIRING_CHECK + | I_TICKET + | I_READ_TICKET + | I_SPLIT_TICKET + | I_JOIN_TICKETS + | I_OPEN_CHEST + | T_bool + | T_contract + | T_int + | T_key + | T_key_hash + | T_lambda + | T_list + | T_map + | T_big_map + | T_nat + | T_option + | T_or + | T_pair + | T_set + | T_signature + | T_string + | T_bytes + | T_mutez + | T_timestamp + | T_unit + | T_operation + | T_address + | T_sapling_transaction + | T_sapling_state + | T_chain_id + | T_never + | T_bls12_381_g1 + | T_bls12_381_g2 + | T_bls12_381_fr + | T_ticket + | T_chest_key + | T_chest + (* See the interface of [Global_constants_storage]. *) + | H_constant + +(** Auxiliary types for error documentation. + All the prim constructor prefixes must match their namespace. *) + +type namespace = + | (* prefix "T" *) Type_namespace + | (* prefix "D" *) Constant_namespace + | (* prefix "I" *) Instr_namespace + | (* prefix "K" *) Keyword_namespace + (* The Constant Hash namespace is a singleton reserved + for the constant keyword. Unlike other primitives, + constants have no representation in the typed IR, + being fully expanded away before typechecking. *) + | (* prefix "H" *) Constant_hash_namespace + +val namespace : prim -> namespace + +val prim_encoding : prim Data_encoding.encoding + +val string_of_prim : prim -> string + +val prim_of_string : string -> prim tzresult + +val prims_of_strings : + string Micheline.canonical -> prim Micheline.canonical tzresult + +val strings_of_prims : prim Micheline.canonical -> string Micheline.canonical + +(** The string corresponds to the constructor prefix from the given namespace + (i.e. "T", "D", "I" or "K") *) +val string_of_namespace : namespace -> string diff --git a/src/proto_011_PtHangzH/lib_protocol/migration_repr.ml b/src/proto_011_PtHangzH/lib_protocol/migration_repr.ml new file mode 100644 index 000000000000..5d4d513caff1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/migration_repr.ml @@ -0,0 +1,62 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Tocqueville Group, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type origination_result = { + balance_updates : Receipt_repr.balance_updates; + originated_contracts : Contract_repr.t list; + storage_size : Z.t; + paid_storage_size_diff : Z.t; +} + +let origination_result_list_encoding = + let open Data_encoding in + def "operation.alpha.origination_result" + @@ list + (conv + (fun { + balance_updates; + originated_contracts; + storage_size; + paid_storage_size_diff; + } -> + ( balance_updates, + originated_contracts, + storage_size, + paid_storage_size_diff )) + (fun ( balance_updates, + originated_contracts, + storage_size, + paid_storage_size_diff ) -> + { + balance_updates; + originated_contracts; + storage_size; + paid_storage_size_diff; + }) + (obj4 + (dft "balance_updates" Receipt_repr.balance_updates_encoding []) + (dft "originated_contracts" (list Contract_repr.encoding) []) + (dft "storage_size" z Z.zero) + (dft "paid_storage_size_diff" z Z.zero))) diff --git a/src/proto_011_PtHangzH/lib_protocol/migration_repr.mli b/src/proto_011_PtHangzH/lib_protocol/migration_repr.mli new file mode 100644 index 000000000000..ea34cb1b7ee6 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/migration_repr.mli @@ -0,0 +1,39 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Tocqueville Group, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Dupe of `Kind.origination successful_manager_operation_result` for use + inside Alpha_context. Converted in Apply_results. + + Doesn't consume gas and omits lazy_storage_diff field since it would + require copying Script_ir_translator functions to work on Raw_context. + *) +type origination_result = { + balance_updates : Receipt_repr.balance_updates; + originated_contracts : Contract_repr.t list; + storage_size : Z.t; + paid_storage_size_diff : Z.t; +} + +val origination_result_list_encoding : origination_result list Data_encoding.t diff --git a/src/proto_011_PtHangzH/lib_protocol/misc.ml b/src/proto_011_PtHangzH/lib_protocol/misc.ml new file mode 100644 index 000000000000..6e3d49853380 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/misc.ml @@ -0,0 +1,86 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type 'a lazyt = unit -> 'a + +type 'a lazy_list_t = LCons of 'a * 'a lazy_list_t tzresult Lwt.t lazyt + +type 'a lazy_list = 'a lazy_list_t tzresult Lwt.t + +let[@coq_struct "i"] rec ( --> ) i j = + (* [i; i+1; ...; j] *) + if Compare.Int.(i > j) then [] else i :: (succ i --> j) + +let[@coq_struct "i"] rec ( ---> ) i j = + (* [i; i+1; ...; j] *) + if Compare.Int32.(i > j) then [] else i :: (Int32.succ i ---> j) + +let split delim ?(limit = max_int) path = + let l = String.length path in + let rec do_slashes acc limit i = + if Compare.Int.(i >= l) then List.rev acc + else if Compare.Char.(path.[i] = delim) then do_slashes acc limit (i + 1) + else do_split acc limit i + and do_split acc limit i = + if Compare.Int.(limit <= 0) then + if Compare.Int.(i = l) then List.rev acc + else List.rev (String.sub path i (l - i) :: acc) + else do_component acc (pred limit) i i + and do_component acc limit i j = + if Compare.Int.(j >= l) then + if Compare.Int.(i = j) then List.rev acc + else List.rev (String.sub path i (j - i) :: acc) + else if Compare.Char.(path.[j] = delim) then + do_slashes (String.sub path i (j - i) :: acc) limit j + else do_component acc limit i (j + 1) + in + if Compare.Int.(limit > 0) then do_slashes [] limit 0 else [path] + [@@coq_axiom_with_reason "non-top-level mutual recursion"] + +let pp_print_paragraph ppf description = + Format.fprintf + ppf + "@[%a@]" + Format.(pp_print_list ~pp_sep:pp_print_space pp_print_string) + (split ' ' description) + +let take n l = + let rec loop acc n xs = + if Compare.Int.(n <= 0) then Some (List.rev acc, xs) + else match xs with [] -> None | x :: xs -> loop (x :: acc) (n - 1) xs + in + loop [] n l + +let remove_prefix ~prefix s = + let x = String.length prefix in + let n = String.length s in + if Compare.Int.(n >= x) && Compare.String.(String.sub s 0 x = prefix) then + Some (String.sub s x (n - x)) + else None + +let rec remove_elem_from_list nb = function + | [] -> [] + | _ :: _ as l when Compare.Int.(nb <= 0) -> l + | _ :: tl -> remove_elem_from_list (nb - 1) tl diff --git a/src/proto_011_PtHangzH/lib_protocol/misc.mli b/src/proto_011_PtHangzH/lib_protocol/misc.mli new file mode 100644 index 000000000000..fb4e07dae4f0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/misc.mli @@ -0,0 +1,47 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** {2 Helper functions} *) + +type 'a lazyt = unit -> 'a + +type 'a lazy_list_t = LCons of 'a * 'a lazy_list_t tzresult Lwt.t lazyt + +type 'a lazy_list = 'a lazy_list_t tzresult Lwt.t + +(** Include bounds *) +val ( --> ) : int -> int -> int list + +val ( ---> ) : Int32.t -> Int32.t -> Int32.t list + +val pp_print_paragraph : Format.formatter -> string -> unit + +val take : int -> 'a list -> ('a list * 'a list) option + +(** Some (input with [prefix] removed), if string has [prefix], else [None] *) +val remove_prefix : prefix:string -> string -> string option + +(** [remove nb list] remove the first [nb] elements from the list [list]. *) +val remove_elem_from_list : int -> 'a list -> 'a list diff --git a/src/proto_011_PtHangzH/lib_protocol/nonce_hash.ml b/src/proto_011_PtHangzH/lib_protocol/nonce_hash.ml new file mode 100644 index 000000000000..10a3f7efe42b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/nonce_hash.ml @@ -0,0 +1,45 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* 32 *) +let nonce_hash = "\069\220\169" (* nce(53) *) + +module H = + Blake2B.Make + (Base58) + (struct + let name = "cycle_nonce" + + let title = "A nonce hash" + + let b58check_prefix = nonce_hash + + let size = None + end) + +include H +include Path_encoding.Make_hex (H) + +let () = Base58.check_encoded_prefix b58check_encoding "nce" 53 diff --git a/src/proto_011_PtHangzH/lib_protocol/nonce_hash.mli b/src/proto_011_PtHangzH/lib_protocol/nonce_hash.mli new file mode 100644 index 000000000000..aeeef12905bd --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/nonce_hash.mli @@ -0,0 +1,31 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** A specialized Blake2B implementation for hashing nonces. *) + +include S.HASH + +include Path_encoding.S with type t := t diff --git a/src/proto_011_PtHangzH/lib_protocol/nonce_storage.ml b/src/proto_011_PtHangzH/lib_protocol/nonce_storage.ml new file mode 100644 index 000000000000..22492366e545 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/nonce_storage.ml @@ -0,0 +1,127 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type t = Seed_repr.nonce + +type nonce = t + +let encoding = Seed_repr.nonce_encoding + +type error += + | Too_late_revelation + | Too_early_revelation + | Previously_revealed_nonce + | Inconsistent_nonce + +let () = + register_error_kind + `Branch + ~id:"nonce.too_late_revelation" + ~title:"Too late nonce revelation" + ~description:"Nonce revelation happens too late" + ~pp:(fun ppf () -> + Format.fprintf ppf "This nonce cannot be revealed anymore.") + Data_encoding.unit + (function Too_late_revelation -> Some () | _ -> None) + (fun () -> Too_late_revelation) ; + register_error_kind + `Temporary + ~id:"nonce.too_early_revelation" + ~title:"Too early nonce revelation" + ~description:"Nonce revelation happens before cycle end" + ~pp:(fun ppf () -> + Format.fprintf ppf "This nonce should not yet be revealed") + Data_encoding.unit + (function Too_early_revelation -> Some () | _ -> None) + (fun () -> Too_early_revelation) ; + register_error_kind + `Branch + ~id:"nonce.previously_revealed" + ~title:"Previously revealed nonce" + ~description:"Duplicated revelation for a nonce." + ~pp:(fun ppf () -> Format.fprintf ppf "This nonce was previously revealed") + Data_encoding.unit + (function Previously_revealed_nonce -> Some () | _ -> None) + (fun () -> Previously_revealed_nonce) ; + register_error_kind + `Branch + ~id:"nonce.inconsistent" + ~title:"Inconsistent nonce" + ~description: + "The provided nonce is inconsistent with the committed nonce hash." + ~pp:(fun ppf () -> + Format.fprintf + ppf + "This nonce revelation is invalid (inconsistent with the committed \ + hash)") + Data_encoding.unit + (function Inconsistent_nonce -> Some () | _ -> None) + (fun () -> Inconsistent_nonce) + +(* checks that the level of a revelation is not too early or too late wrt to the + current context and that a nonce has not been already revealed for that level *) +let get_unrevealed ctxt (level : Level_repr.t) = + let cur_level = Level_storage.current ctxt in + match Cycle_repr.pred cur_level.cycle with + | None -> fail Too_early_revelation (* no revelations during cycle 0 *) + | Some revealed_cycle -> ( + if Cycle_repr.(revealed_cycle < level.Level_repr.cycle) then + fail Too_early_revelation + else if Cycle_repr.(level.Level_repr.cycle < revealed_cycle) then + fail Too_late_revelation + else + Storage.Seed.Nonce.get ctxt level >>=? function + | Revealed _ -> fail Previously_revealed_nonce + | Unrevealed status -> return status) + +let record_hash ctxt unrevealed = + let level = Level_storage.current ctxt in + Storage.Seed.Nonce.init ctxt level (Unrevealed unrevealed) + +let reveal ctxt level nonce = + get_unrevealed ctxt level >>=? fun unrevealed -> + error_unless + (Seed_repr.check_hash nonce unrevealed.nonce_hash) + Inconsistent_nonce + >>?= fun () -> Storage.Seed.Nonce.update ctxt level (Revealed nonce) + +type unrevealed = Storage.Seed.unrevealed_nonce = { + nonce_hash : Nonce_hash.t; + delegate : Signature.Public_key_hash.t; + rewards : Tez_repr.t; + fees : Tez_repr.t; +} + +type status = Storage.Seed.nonce_status = + | Unrevealed of unrevealed + | Revealed of Seed_repr.nonce + +let get = Storage.Seed.Nonce.get + +let of_bytes = Seed_repr.make_nonce + +let hash = Seed_repr.hash + +let check_hash = Seed_repr.check_hash diff --git a/src/proto_011_PtHangzH/lib_protocol/nonce_storage.mli b/src/proto_011_PtHangzH/lib_protocol/nonce_storage.mli new file mode 100644 index 000000000000..8c36c888b7b7 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/nonce_storage.mli @@ -0,0 +1,58 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += + | Too_late_revelation + | Too_early_revelation + | Previously_revealed_nonce + | Inconsistent_nonce + +type t = Seed_repr.nonce + +type nonce = t + +val encoding : nonce Data_encoding.t + +type unrevealed = Storage.Seed.unrevealed_nonce = { + nonce_hash : Nonce_hash.t; + delegate : Signature.Public_key_hash.t; + rewards : Tez_repr.t; + fees : Tez_repr.t; +} + +type status = Unrevealed of unrevealed | Revealed of Seed_repr.nonce + +val get : Raw_context.t -> Level_repr.t -> status tzresult Lwt.t + +val record_hash : Raw_context.t -> unrevealed -> Raw_context.t tzresult Lwt.t + +val reveal : + Raw_context.t -> Level_repr.t -> nonce -> Raw_context.t tzresult Lwt.t + +val of_bytes : bytes -> nonce tzresult + +val hash : nonce -> Nonce_hash.t + +val check_hash : nonce -> Nonce_hash.t -> bool diff --git a/src/proto_011_PtHangzH/lib_protocol/operation_repr.ml b/src/proto_011_PtHangzH/lib_protocol/operation_repr.ml new file mode 100644 index 000000000000..ed496155628f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/operation_repr.ml @@ -0,0 +1,955 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Tezos Protocol Implementation - Low level Repr. of Operations *) + +module Kind = struct + type seed_nonce_revelation = Seed_nonce_revelation_kind + + type endorsement_with_slot = Endorsement_with_slot_kind + + type double_endorsement_evidence = Double_endorsement_evidence_kind + + type double_baking_evidence = Double_baking_evidence_kind + + type activate_account = Activate_account_kind + + type endorsement = Endorsement_kind + + type proposals = Proposals_kind + + type ballot = Ballot_kind + + type reveal = Reveal_kind + + type transaction = Transaction_kind + + type origination = Origination_kind + + type delegation = Delegation_kind + + type failing_noop = Failing_noop_kind + + type register_global_constant = Register_global_constant_kind + + type 'a manager = + | Reveal_manager_kind : reveal manager + | Transaction_manager_kind : transaction manager + | Origination_manager_kind : origination manager + | Delegation_manager_kind : delegation manager + | Register_global_constant_manager_kind : register_global_constant manager +end + +type raw = Operation.t = {shell : Operation.shell_header; proto : bytes} + +let raw_encoding = Operation.encoding + +type 'kind operation = { + shell : Operation.shell_header; + protocol_data : 'kind protocol_data; +} + +and 'kind protocol_data = { + contents : 'kind contents_list; + signature : Signature.t option; +} + +and _ contents_list = + | Single : 'kind contents -> 'kind contents_list + | Cons : + 'kind Kind.manager contents * 'rest Kind.manager contents_list + -> ('kind * 'rest) Kind.manager contents_list + +and _ contents = + | Endorsement : {level : Raw_level_repr.t} -> Kind.endorsement contents + | Seed_nonce_revelation : { + level : Raw_level_repr.t; + nonce : Seed_repr.nonce; + } + -> Kind.seed_nonce_revelation contents + | Endorsement_with_slot : { + endorsement : Kind.endorsement operation; + slot : int; + } + -> Kind.endorsement_with_slot contents + | Double_endorsement_evidence : { + op1 : Kind.endorsement operation; + op2 : Kind.endorsement operation; + slot : int; + } + -> Kind.double_endorsement_evidence contents + | Double_baking_evidence : { + bh1 : Block_header_repr.t; + bh2 : Block_header_repr.t; + } + -> Kind.double_baking_evidence contents + | Activate_account : { + id : Ed25519.Public_key_hash.t; + activation_code : Blinded_public_key_hash.activation_code; + } + -> Kind.activate_account contents + | Proposals : { + source : Signature.Public_key_hash.t; + period : int32; + proposals : Protocol_hash.t list; + } + -> Kind.proposals contents + | Ballot : { + source : Signature.Public_key_hash.t; + period : int32; + proposal : Protocol_hash.t; + ballot : Vote_repr.ballot; + } + -> Kind.ballot contents + | Failing_noop : string -> Kind.failing_noop contents + | Manager_operation : { + source : Signature.public_key_hash; + fee : Tez_repr.tez; + counter : counter; + operation : 'kind manager_operation; + gas_limit : Gas_limit_repr.Arith.integral; + storage_limit : Z.t; + } + -> 'kind Kind.manager contents + +and _ manager_operation = + | Reveal : Signature.Public_key.t -> Kind.reveal manager_operation + | Transaction : { + amount : Tez_repr.tez; + parameters : Script_repr.lazy_expr; + entrypoint : string; + destination : Contract_repr.contract; + } + -> Kind.transaction manager_operation + | Origination : { + delegate : Signature.Public_key_hash.t option; + script : Script_repr.t; + credit : Tez_repr.tez; + preorigination : Contract_repr.t option; + } + -> Kind.origination manager_operation + | Delegation : + Signature.Public_key_hash.t option + -> Kind.delegation manager_operation + | Register_global_constant : { + value : Script_repr.lazy_expr; + } + -> Kind.register_global_constant manager_operation + +and counter = Z.t + +let manager_kind : type kind. kind manager_operation -> kind Kind.manager = + function + | Reveal _ -> Kind.Reveal_manager_kind + | Transaction _ -> Kind.Transaction_manager_kind + | Origination _ -> Kind.Origination_manager_kind + | Delegation _ -> Kind.Delegation_manager_kind + | Register_global_constant _ -> Kind.Register_global_constant_manager_kind + +type 'kind internal_operation = { + source : Contract_repr.contract; + operation : 'kind manager_operation; + nonce : int; +} + +type packed_manager_operation = + | Manager : 'kind manager_operation -> packed_manager_operation + +type packed_contents = Contents : 'kind contents -> packed_contents + +type packed_contents_list = + | Contents_list : 'kind contents_list -> packed_contents_list + +type packed_protocol_data = + | Operation_data : 'kind protocol_data -> packed_protocol_data + +type packed_operation = { + shell : Operation.shell_header; + protocol_data : packed_protocol_data; +} + +let pack ({shell; protocol_data} : _ operation) : packed_operation = + {shell; protocol_data = Operation_data protocol_data} + +type packed_internal_operation = + | Internal_operation : 'kind internal_operation -> packed_internal_operation + +let rec to_list = function + | Contents_list (Single o) -> [Contents o] + | Contents_list (Cons (o, os)) -> Contents o :: to_list (Contents_list os) + +(* This first version of of_list has the type (_, string) result expected by + the conv_with_guard combinator of Data_encoding. For a more conventional + return type see [of_list] below. *) +let rec of_list_internal = function + | [] -> Error "Operation lists should not be empty." + | [Contents o] -> Ok (Contents_list (Single o)) + | Contents o :: os -> ( + of_list_internal os >>? fun (Contents_list os) -> + match (o, os) with + | (Manager_operation _, Single (Manager_operation _)) -> + Ok (Contents_list (Cons (o, os))) + | (Manager_operation _, Cons _) -> Ok (Contents_list (Cons (o, os))) + | _ -> + Error + "Operation list of length > 1 should only contains manager \ + operations.") + +type error += Contents_list_error of string (* `Permanent *) + +let of_list l = + match of_list_internal l with + | Ok contents -> Ok contents + | Error s -> error @@ Contents_list_error s + +module Encoding = struct + open Data_encoding + + let case tag name args proj inj = + case + tag + ~title:(String.capitalize_ascii name) + (merge_objs (obj1 (req "kind" (constant name))) args) + (fun x -> match proj x with None -> None | Some x -> Some ((), x)) + (fun ((), x) -> inj x) + + module Manager_operations = struct + type 'kind case = + | MCase : { + tag : int; + name : string; + encoding : 'a Data_encoding.t; + select : packed_manager_operation -> 'kind manager_operation option; + proj : 'kind manager_operation -> 'a; + inj : 'a -> 'kind manager_operation; + } + -> 'kind case + [@@coq_force_gadt] + + let[@coq_axiom_with_reason "gadt"] reveal_case = + MCase + { + tag = 0; + name = "reveal"; + encoding = obj1 (req "public_key" Signature.Public_key.encoding); + select = (function Manager (Reveal _ as op) -> Some op | _ -> None); + proj = (function Reveal pkh -> pkh); + inj = (fun pkh -> Reveal pkh); + } + + let entrypoint_encoding = + def + ~title:"entrypoint" + ~description:"Named entrypoint to a Michelson smart contract" + "entrypoint" + @@ + let builtin_case tag name = + Data_encoding.case + (Tag tag) + ~title:name + (constant name) + (fun n -> if Compare.String.(n = name) then Some () else None) + (fun () -> name) + in + union + [ + builtin_case 0 "default"; + builtin_case 1 "root"; + builtin_case 2 "do"; + builtin_case 3 "set_delegate"; + builtin_case 4 "remove_delegate"; + Data_encoding.case + (Tag 255) + ~title:"named" + (Bounded.string 31) + (fun s -> Some s) + (fun s -> s); + ] + + let[@coq_axiom_with_reason "gadt"] transaction_case = + MCase + { + tag = 1; + name = "transaction"; + encoding = + obj3 + (req "amount" Tez_repr.encoding) + (req "destination" Contract_repr.encoding) + (opt + "parameters" + (obj2 + (req "entrypoint" entrypoint_encoding) + (req "value" Script_repr.lazy_expr_encoding))); + select = + (function Manager (Transaction _ as op) -> Some op | _ -> None); + proj = + (function + | Transaction {amount; destination; parameters; entrypoint} -> + let parameters = + if + Script_repr.is_unit_parameter parameters + && Compare.String.(entrypoint = "default") + then None + else Some (entrypoint, parameters) + in + (amount, destination, parameters)); + inj = + (fun (amount, destination, parameters) -> + let (entrypoint, parameters) = + match parameters with + | None -> ("default", Script_repr.unit_parameter) + | Some (entrypoint, value) -> (entrypoint, value) + in + Transaction {amount; destination; parameters; entrypoint}); + } + + let[@coq_axiom_with_reason "gadt"] origination_case = + MCase + { + tag = 2; + name = "origination"; + encoding = + obj3 + (req "balance" Tez_repr.encoding) + (opt "delegate" Signature.Public_key_hash.encoding) + (req "script" Script_repr.encoding); + select = + (function Manager (Origination _ as op) -> Some op | _ -> None); + proj = + (function + | Origination + { + credit; + delegate; + script; + preorigination = + _ + (* the hash is only used internally + when originating from smart + contracts, don't serialize it *); + } -> + (credit, delegate, script)); + inj = + (fun (credit, delegate, script) -> + Origination {credit; delegate; script; preorigination = None}); + } + + let[@coq_axiom_with_reason "gadt"] delegation_case = + MCase + { + tag = 3; + name = "delegation"; + encoding = obj1 (opt "delegate" Signature.Public_key_hash.encoding); + select = + (function Manager (Delegation _ as op) -> Some op | _ -> None); + proj = (function Delegation key -> key); + inj = (fun key -> Delegation key); + } + + let[@coq_axiom_with_reason "gadt"] register_global_constant_case = + MCase + { + tag = 4; + name = "register_global_constant"; + encoding = obj1 (req "value" Script_repr.lazy_expr_encoding); + select = + (function + | Manager (Register_global_constant _ as op) -> Some op | _ -> None); + proj = (function Register_global_constant {value} -> value); + inj = (fun value -> Register_global_constant {value}); + } + + let encoding = + let make (MCase {tag; name; encoding; select; proj; inj}) = + case + (Tag tag) + name + encoding + (fun o -> + match select o with None -> None | Some o -> Some (proj o)) + (fun x -> Manager (inj x)) + in + union + ~tag_size:`Uint8 + [ + make reveal_case; + make transaction_case; + make origination_case; + make delegation_case; + make register_global_constant_case; + ] + end + + type 'b case = + | Case : { + tag : int; + name : string; + encoding : 'a Data_encoding.t; + select : packed_contents -> 'b contents option; + proj : 'b contents -> 'a; + inj : 'a -> 'b contents; + } + -> 'b case + + let endorsement_case = + Case + { + tag = 0; + name = "endorsement"; + encoding = obj1 (req "level" Raw_level_repr.encoding); + select = + (function Contents (Endorsement _ as op) -> Some op | _ -> None); + proj = (fun [@coq_match_with_default] (Endorsement {level}) -> level); + inj = (fun level -> Endorsement {level}); + } + + let[@coq_axiom_with_reason "gadt"] endorsement_encoding = + let make (Case {tag; name; encoding; select = _; proj; inj}) = + case (Tag tag) name encoding (fun o -> Some (proj o)) (fun x -> inj x) + in + let to_list : Kind.endorsement contents_list -> _ = fun (Single o) -> o in + let of_list : Kind.endorsement contents -> _ = fun o -> Single o in + def "inlined.endorsement" + @@ conv + (fun ({shell; protocol_data = {contents; signature}} : _ operation) -> + (shell, (contents, signature))) + (fun (shell, (contents, signature)) : _ operation -> + {shell; protocol_data = {contents; signature}}) + (merge_objs + Operation.shell_header_encoding + (obj2 + (req + "operations" + (conv to_list of_list + @@ def "inlined.endorsement.contents" + @@ union [make endorsement_case])) + (varopt "signature" Signature.encoding))) + + let[@coq_axiom_with_reason "gadt"] seed_nonce_revelation_case = + Case + { + tag = 1; + name = "seed_nonce_revelation"; + encoding = + obj2 + (req "level" Raw_level_repr.encoding) + (req "nonce" Seed_repr.nonce_encoding); + select = + (function + | Contents (Seed_nonce_revelation _ as op) -> Some op | _ -> None); + proj = (fun (Seed_nonce_revelation {level; nonce}) -> (level, nonce)); + inj = (fun (level, nonce) -> Seed_nonce_revelation {level; nonce}); + } + + let[@coq_axiom_with_reason "gadt"] endorsement_with_slot_case : + Kind.endorsement_with_slot case = + Case + { + tag = 10; + name = "endorsement_with_slot"; + encoding = + obj2 + (req "endorsement" (dynamic_size endorsement_encoding)) + (req "slot" uint16); + select = + (function + | Contents (Endorsement_with_slot _ as op) -> Some op | _ -> None); + proj = + (fun (Endorsement_with_slot {endorsement; slot}) -> + (endorsement, slot)); + inj = + (fun (endorsement, slot) -> Endorsement_with_slot {endorsement; slot}); + } + + let[@coq_axiom_with_reason "gadt"] double_endorsement_evidence_case : + Kind.double_endorsement_evidence case = + Case + { + tag = 2; + name = "double_endorsement_evidence"; + encoding = + obj3 + (req "op1" (dynamic_size endorsement_encoding)) + (req "op2" (dynamic_size endorsement_encoding)) + (req "slot" uint16); + select = + (function + | Contents (Double_endorsement_evidence _ as op) -> Some op + | _ -> None); + proj = + (fun (Double_endorsement_evidence {op1; op2; slot}) -> + (op1, op2, slot)); + inj = + (fun (op1, op2, slot) -> Double_endorsement_evidence {op1; op2; slot}); + } + + let[@coq_axiom_with_reason "gadt"] double_baking_evidence_case = + Case + { + tag = 3; + name = "double_baking_evidence"; + encoding = + obj2 + (req "bh1" (dynamic_size Block_header_repr.encoding)) + (req "bh2" (dynamic_size Block_header_repr.encoding)); + select = + (function + | Contents (Double_baking_evidence _ as op) -> Some op | _ -> None); + proj = (fun (Double_baking_evidence {bh1; bh2}) -> (bh1, bh2)); + inj = (fun (bh1, bh2) -> Double_baking_evidence {bh1; bh2}); + } + + let[@coq_axiom_with_reason "gadt"] activate_account_case = + Case + { + tag = 4; + name = "activate_account"; + encoding = + obj2 + (req "pkh" Ed25519.Public_key_hash.encoding) + (req "secret" Blinded_public_key_hash.activation_code_encoding); + select = + (function + | Contents (Activate_account _ as op) -> Some op | _ -> None); + proj = + (fun (Activate_account {id; activation_code}) -> + (id, activation_code)); + inj = + (fun (id, activation_code) -> Activate_account {id; activation_code}); + } + + let[@coq_axiom_with_reason "gadt"] proposals_case = + Case + { + tag = 5; + name = "proposals"; + encoding = + obj3 + (req "source" Signature.Public_key_hash.encoding) + (req "period" int32) + (req "proposals" (list Protocol_hash.encoding)); + select = + (function Contents (Proposals _ as op) -> Some op | _ -> None); + proj = + (fun (Proposals {source; period; proposals}) -> + (source, period, proposals)); + inj = + (fun (source, period, proposals) -> + Proposals {source; period; proposals}); + } + + let[@coq_axiom_with_reason "gadt"] ballot_case = + Case + { + tag = 6; + name = "ballot"; + encoding = + obj4 + (req "source" Signature.Public_key_hash.encoding) + (req "period" int32) + (req "proposal" Protocol_hash.encoding) + (req "ballot" Vote_repr.ballot_encoding); + select = (function Contents (Ballot _ as op) -> Some op | _ -> None); + proj = + (function + | Ballot {source; period; proposal; ballot} -> + (source, period, proposal, ballot)); + inj = + (fun (source, period, proposal, ballot) -> + Ballot {source; period; proposal; ballot}); + } + + let failing_noop_case = + Case + { + tag = 17; + name = "failing_noop"; + encoding = obj1 (req "arbitrary" Data_encoding.string); + select = + (function Contents (Failing_noop _ as op) -> Some op | _ -> None); + proj = + (function[@coq_match_with_default] Failing_noop message -> message); + inj = (function message -> Failing_noop message); + } + + let manager_encoding = + obj5 + (req "source" Signature.Public_key_hash.encoding) + (req "fee" Tez_repr.encoding) + (req "counter" (check_size 10 n)) + (req "gas_limit" (check_size 10 Gas_limit_repr.Arith.n_integral_encoding)) + (req "storage_limit" (check_size 10 n)) + + let extract : type kind. kind Kind.manager contents -> _ = + function[@coq_match_with_default] + | Manager_operation + {source; fee; counter; gas_limit; storage_limit; operation = _} -> + (source, fee, counter, gas_limit, storage_limit) + + let rebuild (source, fee, counter, gas_limit, storage_limit) operation = + Manager_operation + {source; fee; counter; gas_limit; storage_limit; operation} + + let[@coq_axiom_with_reason "gadt"] make_manager_case tag (type kind) + (Manager_operations.MCase mcase : kind Manager_operations.case) = + Case + { + tag; + name = mcase.name; + encoding = merge_objs manager_encoding mcase.encoding; + select = + (function + | Contents (Manager_operation ({operation; _} as op)) -> ( + match mcase.select (Manager operation) with + | None -> None + | Some operation -> Some (Manager_operation {op with operation})) + | _ -> None); + proj = + (function + | Manager_operation {operation; _} as op -> + (extract op, mcase.proj operation)); + inj = (fun (op, contents) -> rebuild op (mcase.inj contents)); + } + + let reveal_case = make_manager_case 107 Manager_operations.reveal_case + + let transaction_case = + make_manager_case 108 Manager_operations.transaction_case + + let origination_case = + make_manager_case 109 Manager_operations.origination_case + + let delegation_case = make_manager_case 110 Manager_operations.delegation_case + + let register_global_constant_case = + make_manager_case 111 Manager_operations.register_global_constant_case + + let contents_encoding = + let make (Case {tag; name; encoding; select; proj; inj}) = + case + (Tag tag) + name + encoding + (fun o -> match select o with None -> None | Some o -> Some (proj o)) + (fun x -> Contents (inj x)) + in + def "operation.alpha.contents" + @@ union + [ + make endorsement_case; + make seed_nonce_revelation_case; + make endorsement_with_slot_case; + make double_endorsement_evidence_case; + make double_baking_evidence_case; + make activate_account_case; + make proposals_case; + make ballot_case; + make reveal_case; + make transaction_case; + make origination_case; + make delegation_case; + make failing_noop_case; + make register_global_constant_case; + ] + + let contents_list_encoding = + conv_with_guard to_list of_list_internal (Variable.list contents_encoding) + + let optional_signature_encoding = + conv + (function Some s -> s | None -> Signature.zero) + (fun s -> if Signature.equal s Signature.zero then None else Some s) + Signature.encoding + + let protocol_data_encoding = + def "operation.alpha.contents_and_signature" + @@ conv + (fun (Operation_data {contents; signature}) -> + (Contents_list contents, signature)) + (fun (Contents_list contents, signature) -> + Operation_data {contents; signature}) + (obj2 + (req "contents" contents_list_encoding) + (req "signature" optional_signature_encoding)) + + let operation_encoding = + conv + (fun {shell; protocol_data} -> (shell, protocol_data)) + (fun (shell, protocol_data) -> {shell; protocol_data}) + (merge_objs Operation.shell_header_encoding protocol_data_encoding) + + let unsigned_operation_encoding = + def "operation.alpha.unsigned_operation" + @@ merge_objs + Operation.shell_header_encoding + (obj1 (req "contents" contents_list_encoding)) + + let internal_operation_encoding = + def "operation.alpha.internal_operation" + @@ conv + (fun (Internal_operation {source; operation; nonce}) -> + ((source, nonce), Manager operation)) + (fun ((source, nonce), Manager operation) -> + Internal_operation {source; operation; nonce}) + (merge_objs + (obj2 (req "source" Contract_repr.encoding) (req "nonce" uint16)) + Manager_operations.encoding) +end + +let encoding = Encoding.operation_encoding + +let contents_encoding = Encoding.contents_encoding + +let contents_list_encoding = Encoding.contents_list_encoding + +let protocol_data_encoding = Encoding.protocol_data_encoding + +let unsigned_operation_encoding = Encoding.unsigned_operation_encoding + +let internal_operation_encoding = Encoding.internal_operation_encoding + +let raw ({shell; protocol_data} : _ operation) = + let proto = + Data_encoding.Binary.to_bytes_exn + protocol_data_encoding + (Operation_data protocol_data) + in + {Operation.shell; proto} + +let acceptable_passes (op : packed_operation) = + let (Operation_data protocol_data) = op.protocol_data in + match protocol_data.contents with + | Single (Failing_noop _) -> [] + | Single (Endorsement _) -> [0] + | Single (Endorsement_with_slot _) -> [0] + | Single (Proposals _) -> [1] + | Single (Ballot _) -> [1] + | Single (Seed_nonce_revelation _) -> [2] + | Single (Double_endorsement_evidence _) -> [2] + | Single (Double_baking_evidence _) -> [2] + | Single (Activate_account _) -> [2] + | Single (Manager_operation _) -> [3] + | Cons _ -> [3] + +type error += Invalid_signature (* `Permanent *) + +type error += Missing_signature (* `Permanent *) + +let () = + register_error_kind + `Permanent + ~id:"operation.invalid_signature" + ~title:"Invalid operation signature" + ~description: + "The operation signature is ill-formed or has been made with the wrong \ + public key" + ~pp:(fun ppf () -> Format.fprintf ppf "The operation signature is invalid") + Data_encoding.unit + (function Invalid_signature -> Some () | _ -> None) + (fun () -> Invalid_signature) ; + register_error_kind + `Permanent + ~id:"operation.missing_signature" + ~title:"Missing operation signature" + ~description: + "The operation is of a kind that must be signed, but the signature is \ + missing" + ~pp:(fun ppf () -> Format.fprintf ppf "The operation requires a signature") + Data_encoding.unit + (function Missing_signature -> Some () | _ -> None) + (fun () -> Missing_signature) ; + register_error_kind + `Permanent + ~id:"operation.contents_list_error" + ~title:"Invalid list of operation contents." + ~description: + "An operation contents list has an unexpected shape; it should be either \ + a single operation or a non-empty list of manager operations" + ~pp:(fun ppf s -> + Format.fprintf + ppf + "An operation contents list has an unexpected shape: %s" + s) + Data_encoding.(obj1 (req "message" string)) + (function Contents_list_error s -> Some s | _ -> None) + (fun s -> Contents_list_error s) + +let check_signature (type kind) key chain_id + ({shell; protocol_data} : kind operation) = + let check ~watermark contents signature = + let unsigned_operation = + Data_encoding.Binary.to_bytes_exn + unsigned_operation_encoding + (shell, contents) + in + if Signature.check ~watermark key signature unsigned_operation then Ok () + else error Invalid_signature + in + match (protocol_data.contents, protocol_data.signature) with + | (Single _, None) -> error Missing_signature + | (Cons _, None) -> error Missing_signature + | ((Single (Endorsement _) as contents), Some signature) -> + check ~watermark:(Endorsement chain_id) (Contents_list contents) signature + | ((Single _ as contents), Some signature) -> + check ~watermark:Generic_operation (Contents_list contents) signature + | ((Cons _ as contents), Some signature) -> + check ~watermark:Generic_operation (Contents_list contents) signature + +let hash_raw = Operation.hash + +let hash (o : _ operation) = + let proto = + Data_encoding.Binary.to_bytes_exn + protocol_data_encoding + (Operation_data o.protocol_data) + in + Operation.hash {shell = o.shell; proto} + +let hash_packed (o : packed_operation) = + let proto = + Data_encoding.Binary.to_bytes_exn protocol_data_encoding o.protocol_data + in + Operation.hash {shell = o.shell; proto} + +type ('a, 'b) eq = Eq : ('a, 'a) eq [@@coq_force_gadt] + +let equal_manager_operation_kind : + type a b. a manager_operation -> b manager_operation -> (a, b) eq option = + fun op1 op2 -> + match (op1, op2) with + | (Reveal _, Reveal _) -> Some Eq + | (Reveal _, _) -> None + | (Transaction _, Transaction _) -> Some Eq + | (Transaction _, _) -> None + | (Origination _, Origination _) -> Some Eq + | (Origination _, _) -> None + | (Delegation _, Delegation _) -> Some Eq + | (Delegation _, _) -> None + | (Register_global_constant _, Register_global_constant _) -> Some Eq + | (Register_global_constant _, _) -> None + +let equal_contents_kind : type a b. a contents -> b contents -> (a, b) eq option + = + fun op1 op2 -> + match (op1, op2) with + | (Endorsement _, Endorsement _) -> Some Eq + | (Endorsement _, _) -> None + | (Seed_nonce_revelation _, Seed_nonce_revelation _) -> Some Eq + | (Seed_nonce_revelation _, _) -> None + | (Endorsement_with_slot _, Endorsement_with_slot _) -> Some Eq + | (Endorsement_with_slot _, _) -> None + | (Double_endorsement_evidence _, Double_endorsement_evidence _) -> Some Eq + | (Double_endorsement_evidence _, _) -> None + | (Double_baking_evidence _, Double_baking_evidence _) -> Some Eq + | (Double_baking_evidence _, _) -> None + | (Activate_account _, Activate_account _) -> Some Eq + | (Activate_account _, _) -> None + | (Proposals _, Proposals _) -> Some Eq + | (Proposals _, _) -> None + | (Ballot _, Ballot _) -> Some Eq + | (Ballot _, _) -> None + | (Failing_noop _, Failing_noop _) -> Some Eq + | (Failing_noop _, _) -> None + | (Manager_operation op1, Manager_operation op2) -> ( + match equal_manager_operation_kind op1.operation op2.operation with + | None -> None + | Some Eq -> Some Eq) + | (Manager_operation _, _) -> None + +let rec equal_contents_kind_list : + type a b. a contents_list -> b contents_list -> (a, b) eq option = + fun op1 op2 -> + match (op1, op2) with + | (Single op1, Single op2) -> equal_contents_kind op1 op2 + | (Single _, Cons _) -> None + | (Cons _, Single _) -> None + | (Cons (op1, ops1), Cons (op2, ops2)) -> ( + match equal_contents_kind op1 op2 with + | None -> None + | Some Eq -> ( + match equal_contents_kind_list ops1 ops2 with + | None -> None + | Some Eq -> Some Eq)) + +let equal : type a b. a operation -> b operation -> (a, b) eq option = + fun op1 op2 -> + if not (Operation_hash.equal (hash op1) (hash op2)) then None + else + equal_contents_kind_list + op1.protocol_data.contents + op2.protocol_data.contents + +open Cache_memory_helpers + +let script_lazy_expr_size (expr : Script_repr.lazy_expr) = + let fun_value expr = ret_adding (expr_size expr) word_size in + let fun_bytes bytes = (Nodes.zero, word_size +! bytes_size bytes) in + let fun_combine expr_size bytes_size = expr_size ++ bytes_size in + ret_adding + (Data_encoding.apply_lazy ~fun_value ~fun_bytes ~fun_combine expr) + header_size + +let script_repr_size ({code; storage} : Script_repr.t) = + ret_adding (script_lazy_expr_size code ++ script_lazy_expr_size storage) h2w + +let internal_manager_operation_size (type a) (op : a manager_operation) = + match op with + | Transaction {amount = _; parameters; entrypoint; destination} -> + ret_adding + (script_lazy_expr_size parameters) + (h4w +! int64_size + +! string_size_gen (String.length entrypoint) + +! Contract_repr.in_memory_size destination) + | Origination {delegate; script; credit = _; preorigination} -> + ret_adding + (script_repr_size script) + (h4w + +! option_size + (fun _ -> Contract_repr.public_key_hash_in_memory_size) + delegate + +! int64_size + +! option_size Contract_repr.in_memory_size preorigination) + | Delegation pkh_opt -> + ( Nodes.zero, + h1w + +! option_size + (fun _ -> Contract_repr.public_key_hash_in_memory_size) + pkh_opt ) + | Reveal _ -> + (* Reveals can't occur as internal operations *) + assert false + | Register_global_constant _ -> + (* Global constant registrations can't occur as internal operations *) + assert false + +let packed_internal_operation_in_memory_size : + packed_internal_operation -> nodes_and_size = function + | Internal_operation iop -> + let {source; operation; nonce = _} = iop in + let source_size = Contract_repr.in_memory_size source in + let nonce_size = word_size in + ret_adding + (internal_manager_operation_size operation) + (h2w +! source_size +! nonce_size) diff --git a/src/proto_011_PtHangzH/lib_protocol/operation_repr.mli b/src/proto_011_PtHangzH/lib_protocol/operation_repr.mli new file mode 100644 index 000000000000..6a727a84dab9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/operation_repr.mli @@ -0,0 +1,317 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Tezos Protocol Implementation - Low level Repr. of Operations + + Defines kinds of operations that can be performed on chain: + - endorsement (should now always be wrapped in endorsement_with_slot) + - endorsement_with_slot + - double endorsement evidence + - seed nonce revelation + - double baking evidence + - account activation + - proposal (see: [Voting_repr]) + - ballot (see: [Voting_repr]) + - failing noop + - manager operation (which in turn has several types): + - revelation + - transaction + - origination + - delegation + + Each of them can be encoded as raw bytes. Operations are distinguished at + type level using phantom type parameters. [packed_operation] type allows + for unifying them when required, for instance to put them on a single + list. *) + +module Kind : sig + type seed_nonce_revelation = Seed_nonce_revelation_kind + + type endorsement_with_slot = Endorsement_with_slot_kind + + type double_endorsement_evidence = Double_endorsement_evidence_kind + + type double_baking_evidence = Double_baking_evidence_kind + + type activate_account = Activate_account_kind + + type endorsement = Endorsement_kind + + type proposals = Proposals_kind + + type ballot = Ballot_kind + + type reveal = Reveal_kind + + type transaction = Transaction_kind + + type origination = Origination_kind + + type delegation = Delegation_kind + + type failing_noop = Failing_noop_kind + + type register_global_constant = Register_global_constant_kind + + type 'a manager = + | Reveal_manager_kind : reveal manager + | Transaction_manager_kind : transaction manager + | Origination_manager_kind : origination manager + | Delegation_manager_kind : delegation manager + | Register_global_constant_manager_kind : register_global_constant manager +end + +type raw = Operation.t = {shell : Operation.shell_header; proto : bytes} + +val raw_encoding : raw Data_encoding.t + +type 'kind operation = { + shell : Operation.shell_header; + protocol_data : 'kind protocol_data; +} + +and 'kind protocol_data = { + contents : 'kind contents_list; + signature : Signature.t option; +} + +and _ contents_list = + | Single : 'kind contents -> 'kind contents_list + | Cons : + 'kind Kind.manager contents * 'rest Kind.manager contents_list + -> ('kind * 'rest) Kind.manager contents_list + +and _ contents = + | Endorsement : {level : Raw_level_repr.t} -> Kind.endorsement contents + | Seed_nonce_revelation : { + level : Raw_level_repr.t; + nonce : Seed_repr.nonce; + } + -> Kind.seed_nonce_revelation contents + | Endorsement_with_slot : { + endorsement : Kind.endorsement operation; + slot : int; + } + -> Kind.endorsement_with_slot contents + | Double_endorsement_evidence : { + op1 : Kind.endorsement operation; + op2 : Kind.endorsement operation; + slot : int; + } + -> Kind.double_endorsement_evidence contents + | Double_baking_evidence : { + bh1 : Block_header_repr.t; + bh2 : Block_header_repr.t; + } + -> Kind.double_baking_evidence contents + | Activate_account : { + id : Ed25519.Public_key_hash.t; + activation_code : Blinded_public_key_hash.activation_code; + } + -> Kind.activate_account contents + | Proposals : { + source : Signature.Public_key_hash.t; + period : int32; + proposals : Protocol_hash.t list; + } + -> Kind.proposals contents + | Ballot : { + source : Signature.Public_key_hash.t; + period : int32; + proposal : Protocol_hash.t; + ballot : Vote_repr.ballot; + } + -> Kind.ballot contents + | Failing_noop : string -> Kind.failing_noop contents + | Manager_operation : { + source : Signature.Public_key_hash.t; + fee : Tez_repr.tez; + counter : counter; + operation : 'kind manager_operation; + gas_limit : Gas_limit_repr.Arith.integral; + storage_limit : Z.t; + } + -> 'kind Kind.manager contents + +and _ manager_operation = + | Reveal : Signature.Public_key.t -> Kind.reveal manager_operation + | Transaction : { + amount : Tez_repr.tez; + parameters : Script_repr.lazy_expr; + entrypoint : string; + destination : Contract_repr.contract; + } + -> Kind.transaction manager_operation + | Origination : { + delegate : Signature.Public_key_hash.t option; + script : Script_repr.t; + credit : Tez_repr.tez; + preorigination : Contract_repr.t option; + } + -> Kind.origination manager_operation + | Delegation : + Signature.Public_key_hash.t option + -> Kind.delegation manager_operation + | Register_global_constant : { + value : Script_repr.lazy_expr; + } + -> Kind.register_global_constant manager_operation + +and counter = Z.t + +type 'kind internal_operation = { + source : Contract_repr.contract; + operation : 'kind manager_operation; + nonce : int; +} + +type packed_manager_operation = + | Manager : 'kind manager_operation -> packed_manager_operation + +type packed_contents = Contents : 'kind contents -> packed_contents + +type packed_contents_list = + | Contents_list : 'kind contents_list -> packed_contents_list + +val of_list : packed_contents list -> packed_contents_list tzresult + +val to_list : packed_contents_list -> packed_contents list + +type packed_protocol_data = + | Operation_data : 'kind protocol_data -> packed_protocol_data + +type packed_operation = { + shell : Operation.shell_header; + protocol_data : packed_protocol_data; +} + +val pack : 'kind operation -> packed_operation + +type packed_internal_operation = + | Internal_operation : 'kind internal_operation -> packed_internal_operation + +val manager_kind : 'kind manager_operation -> 'kind Kind.manager + +val encoding : packed_operation Data_encoding.t + +val contents_encoding : packed_contents Data_encoding.t + +val contents_list_encoding : packed_contents_list Data_encoding.t + +val protocol_data_encoding : packed_protocol_data Data_encoding.t + +val unsigned_operation_encoding : + (Operation.shell_header * packed_contents_list) Data_encoding.t + +val raw : _ operation -> raw + +val hash_raw : raw -> Operation_hash.t + +val hash : _ operation -> Operation_hash.t + +val hash_packed : packed_operation -> Operation_hash.t + +val acceptable_passes : packed_operation -> int list + +type error += Missing_signature (* `Permanent *) + +type error += Invalid_signature (* `Permanent *) + +val check_signature : + Signature.Public_key.t -> Chain_id.t -> _ operation -> unit tzresult + +val internal_operation_encoding : packed_internal_operation Data_encoding.t + +type ('a, 'b) eq = Eq : ('a, 'a) eq + +val equal : 'a operation -> 'b operation -> ('a, 'b) eq option + +val packed_internal_operation_in_memory_size : + packed_internal_operation -> Cache_memory_helpers.nodes_and_size + +module Encoding : sig + type 'b case = + | Case : { + tag : int; + name : string; + encoding : 'a Data_encoding.t; + select : packed_contents -> 'b contents option; + proj : 'b contents -> 'a; + inj : 'a -> 'b contents; + } + -> 'b case + + val endorsement_case : Kind.endorsement case + + val seed_nonce_revelation_case : Kind.seed_nonce_revelation case + + val endorsement_with_slot_case : Kind.endorsement_with_slot case + + val double_endorsement_evidence_case : Kind.double_endorsement_evidence case + + val double_baking_evidence_case : Kind.double_baking_evidence case + + val activate_account_case : Kind.activate_account case + + val proposals_case : Kind.proposals case + + val ballot_case : Kind.ballot case + + val failing_noop_case : Kind.failing_noop case + + val reveal_case : Kind.reveal Kind.manager case + + val transaction_case : Kind.transaction Kind.manager case + + val origination_case : Kind.origination Kind.manager case + + val delegation_case : Kind.delegation Kind.manager case + + val register_global_constant_case : + Kind.register_global_constant Kind.manager case + + module Manager_operations : sig + type 'b case = + | MCase : { + tag : int; + name : string; + encoding : 'a Data_encoding.t; + select : packed_manager_operation -> 'kind manager_operation option; + proj : 'kind manager_operation -> 'a; + inj : 'a -> 'kind manager_operation; + } + -> 'kind case + + val reveal_case : Kind.reveal case + + val transaction_case : Kind.transaction case + + val origination_case : Kind.origination case + + val delegation_case : Kind.delegation case + + val register_global_constant_case : Kind.register_global_constant case + end +end diff --git a/src/proto_011_PtHangzH/lib_protocol/parameters_repr.ml b/src/proto_011_PtHangzH/lib_protocol/parameters_repr.ml new file mode 100644 index 000000000000..479639ae04f2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/parameters_repr.ml @@ -0,0 +1,131 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type bootstrap_account = { + public_key_hash : Signature.Public_key_hash.t; + public_key : Signature.Public_key.t option; + amount : Tez_repr.t; +} + +type bootstrap_contract = { + delegate : Signature.Public_key_hash.t; + amount : Tez_repr.t; + script : Script_repr.t; +} + +type t = { + bootstrap_accounts : bootstrap_account list; + bootstrap_contracts : bootstrap_contract list; + commitments : Commitment_repr.t list; + constants : Constants_repr.parametric; + security_deposit_ramp_up_cycles : int option; + no_reward_cycles : int option; +} + +let bootstrap_account_encoding = + let open Data_encoding in + union + [ + case + (Tag 0) + ~title:"Public_key_known" + (tup2 Signature.Public_key.encoding Tez_repr.encoding) + (function + | {public_key_hash; public_key = Some public_key; amount} -> + assert ( + Signature.Public_key_hash.equal + (Signature.Public_key.hash public_key) + public_key_hash) ; + Some (public_key, amount) + | {public_key = None; _} -> None) + (fun (public_key, amount) -> + { + public_key = Some public_key; + public_key_hash = Signature.Public_key.hash public_key; + amount; + }); + case + (Tag 1) + ~title:"Public_key_unknown" + (tup2 Signature.Public_key_hash.encoding Tez_repr.encoding) + (function + | {public_key_hash; public_key = None; amount} -> + Some (public_key_hash, amount) + | {public_key = Some _; _} -> None) + (fun (public_key_hash, amount) -> + {public_key = None; public_key_hash; amount}); + ] + +let bootstrap_contract_encoding = + let open Data_encoding in + conv + (fun {delegate; amount; script} -> (delegate, amount, script)) + (fun (delegate, amount, script) -> {delegate; amount; script}) + (obj3 + (req "delegate" Signature.Public_key_hash.encoding) + (req "amount" Tez_repr.encoding) + (req "script" Script_repr.encoding)) + +let encoding = + let open Data_encoding in + conv + (fun { + bootstrap_accounts; + bootstrap_contracts; + commitments; + constants; + security_deposit_ramp_up_cycles; + no_reward_cycles; + } -> + ( ( bootstrap_accounts, + bootstrap_contracts, + commitments, + security_deposit_ramp_up_cycles, + no_reward_cycles ), + constants )) + (fun ( ( bootstrap_accounts, + bootstrap_contracts, + commitments, + security_deposit_ramp_up_cycles, + no_reward_cycles ), + constants ) -> + { + bootstrap_accounts; + bootstrap_contracts; + commitments; + constants; + security_deposit_ramp_up_cycles; + no_reward_cycles; + }) + (merge_objs + (obj5 + (req "bootstrap_accounts" (list bootstrap_account_encoding)) + (dft "bootstrap_contracts" (list bootstrap_contract_encoding) []) + (dft "commitments" (list Commitment_repr.encoding) []) + (opt "security_deposit_ramp_up_cycles" int31) + (opt "no_reward_cycles" int31)) + Constants_repr.parametric_encoding) + +let check_params params = Constants_repr.check_constants params.constants diff --git a/src/proto_011_PtHangzH/lib_protocol/parameters_repr.mli b/src/proto_011_PtHangzH/lib_protocol/parameters_repr.mli new file mode 100644 index 000000000000..782748e9b44b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/parameters_repr.mli @@ -0,0 +1,56 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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 defines protocol parameters, i.e. constants regulating the + behaviour of the blockchain under the protocol. *) + +(** An implict contract (account) initially existing on a chain since genesis. *) +type bootstrap_account = { + public_key_hash : Signature.Public_key_hash.t; + public_key : Signature.Public_key.t option; + amount : Tez_repr.t; +} + +(** An originated contract initially existing on a chain since genesis. *) +type bootstrap_contract = { + delegate : Signature.Public_key_hash.t; + amount : Tez_repr.t; + script : Script_repr.t; +} + +(** Protocol parameters define some constants regulating behaviour of the + chain. *) +type t = { + bootstrap_accounts : bootstrap_account list; + bootstrap_contracts : bootstrap_contract list; + commitments : Commitment_repr.t list; + constants : Constants_repr.parametric; + security_deposit_ramp_up_cycles : int option; + no_reward_cycles : int option; +} + +val encoding : t Data_encoding.t + +val check_params : t -> unit tzresult diff --git a/src/proto_011_PtHangzH/lib_protocol/path_encoding.ml b/src/proto_011_PtHangzH/lib_protocol/path_encoding.ml new file mode 100644 index 000000000000..1b386c8d0a19 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/path_encoding.ml @@ -0,0 +1,57 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2021 DaiLambda, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module type S = sig + type t + + val to_path : t -> string list -> string list + + val of_path : string list -> t option + + val path_length : int +end + +module Make_hex (H : sig + type t + + val to_bytes : t -> bytes + + val of_bytes_opt : bytes -> t option +end) = +struct + let path_length = 1 + + let to_path t l = + let (`Hex key) = Hex.of_bytes (H.to_bytes t) in + key :: l + + let of_path = function + | [path] -> ( + match Hex.to_bytes (`Hex path) with + | bytes -> H.of_bytes_opt bytes + | exception _ -> None) + | _ -> None +end diff --git a/src/proto_011_PtHangzH/lib_protocol/path_encoding.mli b/src/proto_011_PtHangzH/lib_protocol/path_encoding.mli new file mode 100644 index 000000000000..7388fb52f6d2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/path_encoding.mli @@ -0,0 +1,48 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2021 DaiLambda, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module type S = sig + type t + + (** [to_path t postfix] returns the context path name for [t] + postfixed with [postfix] *) + val to_path : t -> string list -> string list + + (** [of_path path] parses [path] as a context path name for [t] *) + val of_path : string list -> t option + + (** Directory levels of the path encoding of [t] *) + val path_length : int +end + +(** Path encoding in hex: /[0-9a-f]{2}+/ *) +module Make_hex (H : sig + type t + + val to_bytes : t -> bytes + + val of_bytes_opt : bytes -> t option +end) : S with type t := H.t diff --git a/src/proto_011_PtHangzH/lib_protocol/period_repr.ml b/src/proto_011_PtHangzH/lib_protocol/period_repr.ml new file mode 100644 index 000000000000..89ef5b2f376b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/period_repr.ml @@ -0,0 +1,157 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* `Permanent *) +type error += Malformed_period | Invalid_arg | Period_overflow + +let () = + let open Data_encoding in + (* Malformed period *) + register_error_kind + `Permanent + ~id:"malformed_period" + ~title:"Malformed period" + ~description:"Period is negative." + ~pp:(fun ppf () -> Format.fprintf ppf "Malformed period") + empty + (function Malformed_period -> Some () | _ -> None) + (fun () -> Malformed_period) ; + (* Invalid arg *) + register_error_kind + `Permanent + ~id:"invalid_arg" + ~title:"Invalid arg" + ~description:"Negative multiple of periods are not allowed." + ~pp:(fun ppf () -> Format.fprintf ppf "Invalid arg") + empty + (function Invalid_arg -> Some () | _ -> None) + (fun () -> Invalid_arg) ; + let title = "Period overflow" in + register_error_kind + `Permanent + ~id:"period_overflow" + ~title + ~description:"Last operation generated an integer overflow." + ~pp:(fun ppf () -> Format.fprintf ppf "%s" title) + empty + (function Period_overflow -> Some () | _ -> None) + (fun () -> Period_overflow) + +module type INTERNAL = sig + type t = private int64 + + val create : int64 -> t option + + val zero : t + + val one : t + + val mult_ : t -> t -> t option + + val add_ : t -> t -> t option + + val encoding : t Data_encoding.t + + val rpc_arg : t RPC_arg.arg + + val pp : Format.formatter -> t -> unit + + include Compare.S with type t := t +end + +(* Internal module implementing natural numbers using int64. These are different + from usual (wrapping up) unsigned integers in that if one overflows the + representation bounds for int64 through [add] or [mul], a [None] value is + returned *) +module Internal : INTERNAL = struct + type t = Int64.t + + let encoding = Data_encoding.int64 + + let rpc_arg = RPC_arg.int64 + + let pp ppf v = Format.fprintf ppf "%Ld" v + + include (Compare.Int64 : Compare.S with type t := t) + + let zero = 0L + + let one = 1L + + let create t = if t >= zero then Some t else None + + (* The create function is not used in the [mul_] and [add_] below to not add + extra Some | None pattern matching to handle since the overflow checks are + generic and apply as well to negative as positive integers . + + To handle overflows, both [add_] and [mult_] return option types. [None] is + returned on detected overflow, [Some value] when everything went well. *) + let mult_ a b = + if a <> zero then + let res = Int64.mul a b in + if Int64.div res a <> b then None else Some res + else Some zero + + let add_ a b = + let res = Int64.add a b in + if res < a || res < b then None else Some res +end + +include Internal + +type period = Internal.t + +let to_seconds (t : Internal.t) = (t :> int64) + +let of_seconds secs = + match Internal.create secs with + | Some v -> ok v + | None -> error Malformed_period + +let of_seconds_exn t = + match Internal.create t with + | Some t -> t + | None -> invalid_arg "Period.of_seconds_exn" + +let mult i p = + match Internal.create (Int64.of_int32 i) with + | None -> error Invalid_arg + | Some iper -> ( + match Internal.mult_ iper p with + | None -> error Period_overflow + | Some res -> ok res) + +let add p1 p2 = + match Internal.add_ p1 p2 with + | None -> error Period_overflow + | Some res -> ok res + +let ( +? ) = add + +let one_second = Internal.one + +let one_minute = of_seconds_exn 60L + +let one_hour = of_seconds_exn 3600L diff --git a/src/proto_011_PtHangzH/lib_protocol/period_repr.mli b/src/proto_011_PtHangzH/lib_protocol/period_repr.mli new file mode 100644 index 000000000000..92f60493a57d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/period_repr.mli @@ -0,0 +1,73 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type t + +(** Represents a period of time as a non-negative integer. *) +type period = t + +include Compare.S with type t := t + +val encoding : period Data_encoding.t + +val rpc_arg : period RPC_arg.t + +val pp : Format.formatter -> period -> unit + +(** Returns the number of seconds contained in the period. *) +val to_seconds : period -> int64 + +(** Converts a number of seconds to a [period]. + + [of_second s] fails if [s] is not positive. *) +val of_seconds : int64 -> period tzresult + +(** Converts a number of seconds to [period]. + + [of_second s] fails if [s] is not positive. + It should only be used at toplevel for constants. *) +val of_seconds_exn : int64 -> period + +(** Safe addition of periods, guarded against overflow. *) +val add : period -> period -> period tzresult + +(** Alias for [add]. *) +val ( +? ) : period -> period -> period tzresult + +(** Safe multiplication by a positive integer. Guarded against overflow. *) +val mult : int32 -> period -> period tzresult + +val zero : period + +val one_second : period + +val one_minute : period + +val one_hour : period + +(** [compare x y] returns [0] if [x] is equal to [y], a negative + integer if [x] is shorter than [y], and a positive integer if [x] + is longer than [y]. *) +val compare : period -> period -> int diff --git a/src/proto_011_PtHangzH/lib_protocol/raw_context.ml b/src/proto_011_PtHangzH/lib_protocol/raw_context.ml new file mode 100644 index 000000000000..311f6d3d0c73 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/raw_context.ml @@ -0,0 +1,996 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module Int_set = Set.Make (Compare.Int) + +(* + + Gas levels maintenance + ======================= + + The context maintains two levels of gas, one corresponds to the gas + available for the current operation while the other is the gas + available for the current block. Both levels are maintained + independently: [consume_gas] only decreases the operation level, + and block level should be updated with [consume_gas_limit_in_block]. + + A layered context + ================= + + Updating the context [remaining_operation_gas] is a critical routine + called very frequently by the operations performed by the protocol. + On the contrary, other fields are less frequently updated. + + In a previous version of the context datatype definition, all + the fields were represented at the toplevel. To update the remaining + gas, we had to copy ~25 fields (that is 200 bytes). + + With the following layered representation, we only have to + copy 2 fields (16 bytes) during [remaining_operation_gas] update. + This has a significant impact on the Michelson runtime efficiency. + + Here are the fields on the [back] of the context: + + *) +type back = { + context : Context.t; + constants : Constants_repr.parametric; + cycle_eras : Level_repr.cycle_eras; + level : Level_repr.t; + predecessor_timestamp : Time.t; + timestamp : Time.t; + fitness : Int64.t; + included_endorsements : int; + allowed_endorsements : + (Signature.Public_key.t * int list * bool) Signature.Public_key_hash.Map.t; + fees : Tez_repr.t; + rewards : Tez_repr.t; + storage_space_to_pay : Z.t option; + allocated_contracts : int option; + origination_nonce : Contract_repr.origination_nonce option; + temporary_lazy_storage_ids : Lazy_storage_kind.Temp_ids.t; + internal_nonce : int; + internal_nonces_used : Int_set.t; + remaining_block_gas : Gas_limit_repr.Arith.fp; + unlimited_operation_gas : bool; +} + +(* + + The context is simply a record with two fields which + limits the cost of updating the [remaining_operation_gas]. + +*) +type t = {remaining_operation_gas : Gas_limit_repr.Arith.fp; back : back} + +type root = t + +(* + + Context fields accessors + ======================== + + To have the context related code more robust to evolutions, + we introduce accessors to get and to update the context + components. + +*) +let[@inline] context ctxt = ctxt.back.context + +let[@inline] current_level ctxt = ctxt.back.level + +let[@inline] storage_space_to_pay ctxt = ctxt.back.storage_space_to_pay + +let[@inline] predecessor_timestamp ctxt = ctxt.back.predecessor_timestamp + +let[@inline] current_timestamp ctxt = ctxt.back.timestamp + +let[@inline] current_fitness ctxt = ctxt.back.fitness + +let[@inline] cycle_eras ctxt = ctxt.back.cycle_eras + +let[@inline] constants ctxt = ctxt.back.constants + +let[@inline] recover ctxt = ctxt.back.context + +let[@inline] fees ctxt = ctxt.back.fees + +let[@inline] origination_nonce ctxt = ctxt.back.origination_nonce + +let[@inline] allowed_endorsements ctxt = ctxt.back.allowed_endorsements + +let[@inline] included_endorsements ctxt = ctxt.back.included_endorsements + +let[@inline] internal_nonce ctxt = ctxt.back.internal_nonce + +let[@inline] internal_nonces_used ctxt = ctxt.back.internal_nonces_used + +let[@inline] remaining_block_gas ctxt = ctxt.back.remaining_block_gas + +let[@inline] unlimited_operation_gas ctxt = ctxt.back.unlimited_operation_gas + +let[@inline] rewards ctxt = ctxt.back.rewards + +let[@inline] allocated_contracts ctxt = ctxt.back.allocated_contracts + +let[@inline] temporary_lazy_storage_ids ctxt = + ctxt.back.temporary_lazy_storage_ids + +let[@inline] remaining_operation_gas ctxt = ctxt.remaining_operation_gas + +let[@inline] update_remaining_operation_gas ctxt remaining_operation_gas = + {ctxt with remaining_operation_gas} + +let[@inline] update_back ctxt back = {ctxt with back} + +let[@inline] update_remaining_block_gas ctxt remaining_block_gas = + update_back ctxt {ctxt.back with remaining_block_gas} + +let[@inline] update_unlimited_operation_gas ctxt unlimited_operation_gas = + update_back ctxt {ctxt.back with unlimited_operation_gas} + +let[@inline] update_context ctxt context = + update_back ctxt {ctxt.back with context} + +let[@inline] update_constants ctxt constants = + update_back ctxt {ctxt.back with constants} + +let[@inline] update_fitness ctxt fitness = + update_back ctxt {ctxt.back with fitness} + +let[@inline] update_allowed_endorsements ctxt allowed_endorsements = + update_back ctxt {ctxt.back with allowed_endorsements} + +let[@inline] update_rewards ctxt rewards = + update_back ctxt {ctxt.back with rewards} + +let[@inline] raw_update_storage_space_to_pay ctxt storage_space_to_pay = + update_back ctxt {ctxt.back with storage_space_to_pay} + +let[@inline] update_allocated_contracts ctxt allocated_contracts = + update_back ctxt {ctxt.back with allocated_contracts} + +let[@inline] update_origination_nonce ctxt origination_nonce = + update_back ctxt {ctxt.back with origination_nonce} + +let[@inline] update_internal_nonce ctxt internal_nonce = + update_back ctxt {ctxt.back with internal_nonce} + +let[@inline] update_internal_nonces_used ctxt internal_nonces_used = + update_back ctxt {ctxt.back with internal_nonces_used} + +let[@inline] update_included_endorsements ctxt included_endorsements = + update_back ctxt {ctxt.back with included_endorsements} + +let[@inline] update_fees ctxt fees = update_back ctxt {ctxt.back with fees} + +let[@inline] update_temporary_lazy_storage_ids ctxt temporary_lazy_storage_ids = + update_back ctxt {ctxt.back with temporary_lazy_storage_ids} + +let record_endorsement ctxt k = + match Signature.Public_key_hash.Map.find k (allowed_endorsements ctxt) with + | None -> assert false + | Some (_, _, true) -> assert false (* right already used *) + | Some (d, s, false) -> + let ctxt = + update_included_endorsements + ctxt + (included_endorsements ctxt + List.length s) + in + update_allowed_endorsements + ctxt + (Signature.Public_key_hash.Map.add + k + (d, s, true) + (allowed_endorsements ctxt)) + +let init_endorsements ctxt allowed_endorsements' = + if Signature.Public_key_hash.Map.is_empty allowed_endorsements' then + assert false (* can't initialize to empty *) + else if Signature.Public_key_hash.Map.is_empty (allowed_endorsements ctxt) + then update_allowed_endorsements ctxt allowed_endorsements' + else assert false + +type error += Too_many_internal_operations (* `Permanent *) + +type error += Block_quota_exceeded (* `Temporary *) + +type error += Operation_quota_exceeded (* `Temporary *) + +let () = + let open Data_encoding in + register_error_kind + `Permanent + ~id:"too_many_internal_operations" + ~title:"Too many internal operations" + ~description: + "A transaction exceeded the hard limit of internal operations it can emit" + empty + (function Too_many_internal_operations -> Some () | _ -> None) + (fun () -> Too_many_internal_operations) ; + register_error_kind + `Temporary + ~id:"gas_exhausted.operation" + ~title:"Gas quota exceeded for the operation" + ~description: + "A script or one of its callee took more time than the operation said it \ + would" + empty + (function Operation_quota_exceeded -> Some () | _ -> None) + (fun () -> Operation_quota_exceeded) ; + register_error_kind + `Temporary + ~id:"gas_exhausted.block" + ~title:"Gas quota exceeded for the block" + ~description: + "The sum of gas consumed by all the operations in the block exceeds the \ + hard gas limit per block" + empty + (function Block_quota_exceeded -> Some () | _ -> None) + (fun () -> Block_quota_exceeded) + +let fresh_internal_nonce ctxt = + if Compare.Int.(internal_nonce ctxt >= 65_535) then + error Too_many_internal_operations + else + ok + (update_internal_nonce ctxt (internal_nonce ctxt + 1), internal_nonce ctxt) + +let reset_internal_nonce ctxt = + let ctxt = update_internal_nonce ctxt 0 in + update_internal_nonces_used ctxt Int_set.empty + +let record_internal_nonce ctxt k = + update_internal_nonces_used ctxt (Int_set.add k (internal_nonces_used ctxt)) + +let internal_nonce_already_recorded ctxt k = + Int_set.mem k (internal_nonces_used ctxt) + +let set_current_fitness ctxt fitness = update_fitness ctxt fitness + +let add_fees ctxt fees' = Tez_repr.(fees ctxt +? fees') >|? update_fees ctxt + +let add_rewards ctxt rewards' = + Tez_repr.(rewards ctxt +? rewards') >|? update_rewards ctxt + +let get_rewards = rewards + +let get_fees = fees + +type error += Undefined_operation_nonce (* `Permanent *) + +let () = + let open Data_encoding in + register_error_kind + `Permanent + ~id:"undefined_operation_nonce" + ~title:"Ill timed access to the origination nonce" + ~description: + "An origination was attempted out of the scope of a manager operation" + empty + (function Undefined_operation_nonce -> Some () | _ -> None) + (fun () -> Undefined_operation_nonce) + +let init_origination_nonce ctxt operation_hash = + let origination_nonce = + Some (Contract_repr.initial_origination_nonce operation_hash) + in + update_origination_nonce ctxt origination_nonce + +let increment_origination_nonce ctxt = + match origination_nonce ctxt with + | None -> error Undefined_operation_nonce + | Some cur_origination_nonce -> + let origination_nonce = + Some (Contract_repr.incr_origination_nonce cur_origination_nonce) + in + let ctxt = update_origination_nonce ctxt origination_nonce in + ok (ctxt, cur_origination_nonce) + +let get_origination_nonce ctxt = + match origination_nonce ctxt with + | None -> error Undefined_operation_nonce + | Some origination_nonce -> ok origination_nonce + +let unset_origination_nonce ctxt = update_origination_nonce ctxt None + +type error += Gas_limit_too_high (* `Permanent *) + +let () = + let open Data_encoding in + register_error_kind + `Permanent + ~id:"gas_limit_too_high" + ~title:"Gas limit out of protocol hard bounds" + ~description:"A transaction tried to exceed the hard limit on gas" + empty + (function Gas_limit_too_high -> Some () | _ -> None) + (fun () -> Gas_limit_too_high) + +let gas_level ctxt = + let open Gas_limit_repr in + if unlimited_operation_gas ctxt then Unaccounted + else Limited {remaining = remaining_operation_gas ctxt} + +let block_gas_level = remaining_block_gas + +let check_gas_limit_is_valid ctxt (remaining : 'a Gas_limit_repr.Arith.t) = + if + Gas_limit_repr.Arith.( + remaining > (constants ctxt).hard_gas_limit_per_operation + || remaining < zero) + then error Gas_limit_too_high + else ok_unit + +let consume_gas_limit_in_block ctxt (limit : 'a Gas_limit_repr.Arith.t) = + let open Gas_limit_repr in + check_gas_limit_is_valid ctxt limit >>? fun () -> + let block_gas = block_gas_level ctxt in + let limit = Arith.fp limit in + if Arith.(limit > block_gas) then error Block_quota_exceeded + else + let level = Arith.sub (block_gas_level ctxt) limit in + let ctxt = update_remaining_block_gas ctxt level in + Ok ctxt + +let set_gas_limit ctxt (remaining : 'a Gas_limit_repr.Arith.t) = + let open Gas_limit_repr in + let remaining_operation_gas = Arith.fp remaining in + let ctxt = update_unlimited_operation_gas ctxt false in + {ctxt with remaining_operation_gas} + +let set_gas_unlimited ctxt = update_unlimited_operation_gas ctxt true + +let gas_exhausted_error _ctxt = error Operation_quota_exceeded + +let consume_gas ctxt cost = + match Gas_limit_repr.raw_consume (remaining_operation_gas ctxt) cost with + | Some gas_counter -> Ok (update_remaining_operation_gas ctxt gas_counter) + | None -> + if unlimited_operation_gas ctxt then ok ctxt + else error Operation_quota_exceeded + +let check_enough_gas ctxt cost = consume_gas ctxt cost >>? fun _ -> ok_unit + +let gas_consumed ~since ~until = + match (gas_level since, gas_level until) with + | (Limited {remaining = before}, Limited {remaining = after}) -> + Gas_limit_repr.Arith.sub before after + | (_, _) -> Gas_limit_repr.Arith.zero + +let init_storage_space_to_pay ctxt = + match storage_space_to_pay ctxt with + | Some _ -> assert false + | None -> + let ctxt = raw_update_storage_space_to_pay ctxt (Some Z.zero) in + update_allocated_contracts ctxt (Some 0) + +let clear_storage_space_to_pay ctxt = + match (storage_space_to_pay ctxt, allocated_contracts ctxt) with + | (None, _) | (_, None) -> assert false + | (Some storage_space_to_pay, Some allocated_contracts) -> + let ctxt = raw_update_storage_space_to_pay ctxt None in + let ctxt = update_allocated_contracts ctxt None in + (ctxt, storage_space_to_pay, allocated_contracts) + +let update_storage_space_to_pay ctxt n = + match storage_space_to_pay ctxt with + | None -> assert false + | Some storage_space_to_pay -> + raw_update_storage_space_to_pay ctxt (Some (Z.add n storage_space_to_pay)) + +let update_allocated_contracts_count ctxt = + match allocated_contracts ctxt with + | None -> assert false + | Some allocated_contracts -> + update_allocated_contracts ctxt (Some (succ allocated_contracts)) + +type missing_key_kind = Get | Set | Del | Copy + +type storage_error = + | Incompatible_protocol_version of string + | Missing_key of string list * missing_key_kind + | Existing_key of string list + | Corrupted_data of string list + +let storage_error_encoding = + let open Data_encoding in + union + [ + case + (Tag 0) + ~title:"Incompatible_protocol_version" + (obj1 (req "incompatible_protocol_version" string)) + (function Incompatible_protocol_version arg -> Some arg | _ -> None) + (fun arg -> Incompatible_protocol_version arg); + case + (Tag 1) + ~title:"Missing_key" + (obj2 + (req "missing_key" (list string)) + (req + "function" + (string_enum + [("get", Get); ("set", Set); ("del", Del); ("copy", Copy)]))) + (function Missing_key (key, f) -> Some (key, f) | _ -> None) + (fun (key, f) -> Missing_key (key, f)); + case + (Tag 2) + ~title:"Existing_key" + (obj1 (req "existing_key" (list string))) + (function Existing_key key -> Some key | _ -> None) + (fun key -> Existing_key key); + case + (Tag 3) + ~title:"Corrupted_data" + (obj1 (req "corrupted_data" (list string))) + (function Corrupted_data key -> Some key | _ -> None) + (fun key -> Corrupted_data key); + ] + +let pp_storage_error ppf = function + | Incompatible_protocol_version version -> + Format.fprintf + ppf + "Found a context with an unexpected version '%s'." + version + | Missing_key (key, Get) -> + Format.fprintf ppf "Missing key '%s'." (String.concat "/" key) + | Missing_key (key, Set) -> + Format.fprintf + ppf + "Cannot set undefined key '%s'." + (String.concat "/" key) + | Missing_key (key, Del) -> + Format.fprintf + ppf + "Cannot delete undefined key '%s'." + (String.concat "/" key) + | Missing_key (key, Copy) -> + Format.fprintf + ppf + "Cannot copy undefined key '%s'." + (String.concat "/" key) + | Existing_key key -> + Format.fprintf + ppf + "Cannot initialize defined key '%s'." + (String.concat "/" key) + | Corrupted_data key -> + Format.fprintf + ppf + "Failed to parse the data at '%s'." + (String.concat "/" key) + +type error += Storage_error of storage_error + +let () = + register_error_kind + `Permanent + ~id:"context.storage_error" + ~title:"Storage error (fatal internal error)" + ~description: + "An error that should never happen unless something has been deleted or \ + corrupted in the database." + ~pp:(fun ppf err -> + Format.fprintf ppf "@[Storage error:@ %a@]" pp_storage_error err) + storage_error_encoding + (function Storage_error err -> Some err | _ -> None) + (fun err -> Storage_error err) + +let storage_error err = error (Storage_error err) + +(* Initialization *********************************************************) + +(* This key should always be populated for every version of the + protocol. It's absence meaning that the context is empty. *) +let version_key = ["version"] + +(* This value is set by the snapshot_alpha.sh script, don't change it. *) +let version_value = "hangzhou_011" + +let version = "v1" + +let cycle_eras_key = [version; "cycle_eras"] + +let constants_key = [version; "constants"] + +let protocol_param_key = ["protocol_parameters"] + +let get_cycle_eras ctxt = + Context.find ctxt cycle_eras_key >|= function + | None -> storage_error (Missing_key (cycle_eras_key, Get)) + | Some bytes -> ( + match + Data_encoding.Binary.of_bytes_opt Level_repr.cycle_eras_encoding bytes + with + | None -> storage_error (Corrupted_data cycle_eras_key) + | Some cycle_eras -> ok cycle_eras) + +let set_cycle_eras ctxt cycle_eras = + let bytes = + Data_encoding.Binary.to_bytes_exn Level_repr.cycle_eras_encoding cycle_eras + in + Context.add ctxt cycle_eras_key bytes >|= ok + +type error += Failed_to_parse_parameter of bytes + +type error += Failed_to_decode_parameter of Data_encoding.json * string + +let () = + register_error_kind + `Temporary + ~id:"context.failed_to_parse_parameter" + ~title:"Failed to parse parameter" + ~description:"The protocol parameters are not valid JSON." + ~pp:(fun ppf bytes -> + Format.fprintf + ppf + "@[Cannot parse the protocol parameter:@ %s@]" + (Bytes.to_string bytes)) + Data_encoding.(obj1 (req "contents" bytes)) + (function Failed_to_parse_parameter data -> Some data | _ -> None) + (fun data -> Failed_to_parse_parameter data) ; + register_error_kind + `Temporary + ~id:"context.failed_to_decode_parameter" + ~title:"Failed to decode parameter" + ~description:"Unexpected JSON object." + ~pp:(fun ppf (json, msg) -> + Format.fprintf + ppf + "@[Cannot decode the protocol parameter:@ %s@ %a@]" + msg + Data_encoding.Json.pp + json) + Data_encoding.(obj2 (req "contents" json) (req "error" string)) + (function + | Failed_to_decode_parameter (json, msg) -> Some (json, msg) | _ -> None) + (fun (json, msg) -> Failed_to_decode_parameter (json, msg)) + +let get_proto_param ctxt = + Context.find ctxt protocol_param_key >>= function + | None -> failwith "Missing protocol parameters." + | Some bytes -> ( + match Data_encoding.Binary.of_bytes_opt Data_encoding.json bytes with + | None -> fail (Failed_to_parse_parameter bytes) + | Some json -> ( + Context.remove ctxt protocol_param_key >|= fun ctxt -> + match Data_encoding.Json.destruct Parameters_repr.encoding json with + | exception (Data_encoding.Json.Cannot_destruct _ as exn) -> + Format.kasprintf + failwith + "Invalid protocol_parameters: %a %a" + (fun ppf -> Data_encoding.Json.print_error ppf) + exn + Data_encoding.Json.pp + json + | param -> + Parameters_repr.check_params param >>? fun () -> ok (param, ctxt)) + ) + +let add_constants ctxt constants = + let bytes = + Data_encoding.Binary.to_bytes_exn + Constants_repr.parametric_encoding + constants + in + Context.add ctxt constants_key bytes + +let get_constants ctxt = + Context.find ctxt constants_key >|= function + | None -> failwith "Internal error: cannot read constants in context." + | Some bytes -> ( + match + Data_encoding.Binary.of_bytes_opt + Constants_repr.parametric_encoding + bytes + with + | None -> failwith "Internal error: cannot parse constants in context." + | Some constants -> ok constants) + +let patch_constants ctxt f = + let constants = f (constants ctxt) in + add_constants (context ctxt) constants >|= fun context -> + let ctxt = update_context ctxt context in + update_constants ctxt constants + +let check_inited ctxt = + Context.find ctxt version_key >|= function + | None -> failwith "Internal error: un-initialized context." + | Some bytes -> + let s = Bytes.to_string bytes in + if Compare.String.(s = version_value) then ok_unit + else storage_error (Incompatible_protocol_version s) + +let check_cycle_eras (cycle_eras : Level_repr.cycle_eras) + (constants : Constants_repr.parametric) = + let current_era = Level_repr.current_era cycle_eras in + assert ( + Compare.Int32.(current_era.blocks_per_cycle = constants.blocks_per_cycle)) ; + assert ( + Compare.Int32.( + current_era.blocks_per_commitment = constants.blocks_per_commitment)) + +let prepare ~level ~predecessor_timestamp ~timestamp ~fitness ctxt = + Raw_level_repr.of_int32 level >>?= fun level -> + Fitness_repr.to_int64 fitness >>?= fun fitness -> + check_inited ctxt >>=? fun () -> + get_constants ctxt >>=? fun constants -> + get_cycle_eras ctxt >|=? fun cycle_eras -> + check_cycle_eras cycle_eras constants ; + let level = Level_repr.from_raw ~cycle_eras level in + { + remaining_operation_gas = Gas_limit_repr.Arith.zero; + back = + { + context = ctxt; + constants; + level; + predecessor_timestamp; + timestamp; + fitness; + cycle_eras; + allowed_endorsements = Signature.Public_key_hash.Map.empty; + included_endorsements = 0; + fees = Tez_repr.zero; + rewards = Tez_repr.zero; + storage_space_to_pay = None; + allocated_contracts = None; + origination_nonce = None; + temporary_lazy_storage_ids = Lazy_storage_kind.Temp_ids.init; + internal_nonce = 0; + internal_nonces_used = Int_set.empty; + remaining_block_gas = + Gas_limit_repr.Arith.fp + constants.Constants_repr.hard_gas_limit_per_block; + unlimited_operation_gas = true; + }; + } + +type previous_protocol = Genesis of Parameters_repr.t | Granada_010 + +let check_and_update_protocol_version ctxt = + (Context.find ctxt version_key >>= function + | None -> + failwith "Internal error: un-initialized context in check_first_block." + | Some bytes -> + let s = Bytes.to_string bytes in + if Compare.String.(s = version_value) then + failwith "Internal error: previously initialized context." + else if Compare.String.(s = "genesis") then + get_proto_param ctxt >|=? fun (param, ctxt) -> (Genesis param, ctxt) + else if Compare.String.(s = "granada_010") then return (Granada_010, ctxt) + else Lwt.return @@ storage_error (Incompatible_protocol_version s)) + >>=? fun (previous_proto, ctxt) -> + Context.add ctxt version_key (Bytes.of_string version_value) >|= fun ctxt -> + ok (previous_proto, ctxt) + +(* only for the migration *) +let[@warning "-32"] get_previous_protocol_constants ctxt = + Context.find ctxt constants_key >>= function + | None -> + failwith + "Internal error: cannot read previous protocol constants in context." + | Some bytes -> ( + match + Data_encoding.Binary.of_bytes_opt + Constants_repr.Proto_previous.parametric_encoding + bytes + with + | None -> + failwith + "Internal error: cannot parse previous protocol constants in \ + context." + | Some constants -> Lwt.return constants) + +(* You should ensure that if the type `Constant_repr.parametric` is + different from the previous protocol or the value of these + constants is modified, is changed from the previous protocol, then + you `propagate` these constants to the new protocol by writing them + onto the context via the function `add_constants` or + `patch_constants`. + + This migration can be achieved also implicitly by modifying the + encoding directly in a way which is compatible with the previous + protocol. However, by doing so, you do not change the value of + these constants inside the context. *) +let prepare_first_block ~level ~timestamp ~fitness ctxt = + check_and_update_protocol_version ctxt >>=? fun (previous_proto, ctxt) -> + (match previous_proto with + | Genesis param -> + Raw_level_repr.of_int32 level >>?= fun first_level -> + let cycle_era = + Level_repr. + { + first_level; + first_cycle = Cycle_repr.root; + blocks_per_cycle = param.constants.blocks_per_cycle; + blocks_per_commitment = param.constants.blocks_per_commitment; + } + in + Level_repr.create_cycle_eras [cycle_era] >>?= fun cycle_eras -> + set_cycle_eras ctxt cycle_eras >>=? fun ctxt -> + add_constants ctxt param.constants >|= ok + | Granada_010 -> + get_previous_protocol_constants ctxt >>= fun c -> + let constants = + (* removes michelson_maximum_type_size *) + Constants_repr. + { + minimal_block_delay = c.minimal_block_delay; + preserved_cycles = c.preserved_cycles; + blocks_per_cycle = c.blocks_per_cycle; + blocks_per_commitment = c.blocks_per_commitment; + blocks_per_roll_snapshot = c.blocks_per_roll_snapshot; + blocks_per_voting_period = c.blocks_per_voting_period; + time_between_blocks = c.time_between_blocks; + endorsers_per_block = c.endorsers_per_block; + hard_gas_limit_per_operation = c.hard_gas_limit_per_operation; + hard_gas_limit_per_block = c.hard_gas_limit_per_block; + proof_of_work_threshold = c.proof_of_work_threshold; + tokens_per_roll = c.tokens_per_roll; + seed_nonce_revelation_tip = c.seed_nonce_revelation_tip; + origination_size = c.origination_size; + block_security_deposit = c.block_security_deposit; + endorsement_security_deposit = c.endorsement_security_deposit; + baking_reward_per_endorsement = c.baking_reward_per_endorsement; + endorsement_reward = c.endorsement_reward; + hard_storage_limit_per_operation = + c.hard_storage_limit_per_operation; + cost_per_byte = c.cost_per_byte; + quorum_min = c.quorum_min; + quorum_max = c.quorum_max; + min_proposal_quorum = c.min_proposal_quorum; + initial_endorsers = c.initial_endorsers; + delay_per_missing_endorsement = c.delay_per_missing_endorsement; + liquidity_baking_subsidy = c.liquidity_baking_subsidy; + liquidity_baking_sunset_level = + (* preserve a lower level for testnets *) + (if Compare.Int32.(c.liquidity_baking_sunset_level = 2_032_928l) + then 2_244_609l + else c.liquidity_baking_sunset_level); + liquidity_baking_escape_ema_threshold = + c.liquidity_baking_escape_ema_threshold; + } + in + add_constants ctxt constants >>= fun ctxt -> return ctxt) + >>=? fun ctxt -> + prepare ctxt ~level ~predecessor_timestamp:timestamp ~timestamp ~fitness + >|=? fun ctxt -> (previous_proto, ctxt) + +let activate ctxt h = Updater.activate (context ctxt) h >|= update_context ctxt + +(* Generic context ********************************************************) + +type key = string list + +type value = bytes + +type tree = Context.tree + +module type T = + Raw_context_intf.T + with type root := root + and type key := key + and type value := value + and type tree := tree + +let mem ctxt k = Context.mem (context ctxt) k + +let mem_tree ctxt k = Context.mem_tree (context ctxt) k + +let get ctxt k = + Context.find (context ctxt) k >|= function + | None -> storage_error (Missing_key (k, Get)) + | Some v -> ok v + +let get_tree ctxt k = + Context.find_tree (context ctxt) k >|= function + | None -> storage_error (Missing_key (k, Get)) + | Some v -> ok v + +let find ctxt k = Context.find (context ctxt) k + +let find_tree ctxt k = Context.find_tree (context ctxt) k + +let add ctxt k v = Context.add (context ctxt) k v >|= update_context ctxt + +let add_tree ctxt k v = + Context.add_tree (context ctxt) k v >|= update_context ctxt + +let init ctxt k v = + Context.mem (context ctxt) k >>= function + | true -> Lwt.return @@ storage_error (Existing_key k) + | _ -> + Context.add (context ctxt) k v >|= fun context -> + ok (update_context ctxt context) + +let init_tree ctxt k v : _ tzresult Lwt.t = + Context.mem_tree (context ctxt) k >>= function + | true -> Lwt.return @@ storage_error (Existing_key k) + | _ -> + Context.add_tree (context ctxt) k v >|= fun context -> + ok (update_context ctxt context) + +let update ctxt k v = + Context.mem (context ctxt) k >>= function + | false -> Lwt.return @@ storage_error (Missing_key (k, Set)) + | _ -> + Context.add (context ctxt) k v >|= fun context -> + ok (update_context ctxt context) + +let update_tree ctxt k v = + Context.mem_tree (context ctxt) k >>= function + | false -> Lwt.return @@ storage_error (Missing_key (k, Set)) + | _ -> + Context.add_tree (context ctxt) k v >|= fun context -> + ok (update_context ctxt context) + +(* Verify that the key is present before deleting *) +let remove_existing ctxt k = + Context.mem (context ctxt) k >>= function + | false -> Lwt.return @@ storage_error (Missing_key (k, Del)) + | _ -> + Context.remove (context ctxt) k >|= fun context -> + ok (update_context ctxt context) + +(* Verify that the key is present before deleting *) +let remove_existing_tree ctxt k = + Context.mem_tree (context ctxt) k >>= function + | false -> Lwt.return @@ storage_error (Missing_key (k, Del)) + | _ -> + Context.remove (context ctxt) k >|= fun context -> + ok (update_context ctxt context) + +(* Do not verify before deleting *) +let remove ctxt k = Context.remove (context ctxt) k >|= update_context ctxt + +let add_or_remove ctxt k = function + | None -> remove ctxt k + | Some v -> add ctxt k v + +let add_or_remove_tree ctxt k = function + | None -> remove ctxt k + | Some v -> add_tree ctxt k v + +let list ctxt ?offset ?length k = Context.list (context ctxt) ?offset ?length k + +let fold ?depth ctxt k ~init ~f = Context.fold ?depth (context ctxt) k ~init ~f + +module Tree : + Raw_context_intf.TREE + with type t := t + and type key := key + and type value := value + and type tree := tree = struct + include Context.Tree + + let empty ctxt = Context.Tree.empty (context ctxt) + + let get t k = + find t k >|= function + | None -> storage_error (Missing_key (k, Get)) + | Some v -> ok v + + let get_tree t k = + find_tree t k >|= function + | None -> storage_error (Missing_key (k, Get)) + | Some v -> ok v + + let init t k v = + mem t k >>= function + | true -> Lwt.return @@ storage_error (Existing_key k) + | _ -> add t k v >|= ok + + let init_tree t k v = + mem_tree t k >>= function + | true -> Lwt.return @@ storage_error (Existing_key k) + | _ -> add_tree t k v >|= ok + + let update t k v = + mem t k >>= function + | false -> Lwt.return @@ storage_error (Missing_key (k, Set)) + | _ -> add t k v >|= ok + + let update_tree t k v = + mem_tree t k >>= function + | false -> Lwt.return @@ storage_error (Missing_key (k, Set)) + | _ -> add_tree t k v >|= ok + + (* Verify that the key is present before deleting *) + let remove_existing t k = + mem t k >>= function + | false -> Lwt.return @@ storage_error (Missing_key (k, Del)) + | _ -> remove t k >|= ok + + (* Verify that the key is present before deleting *) + let remove_existing_tree t k = + mem_tree t k >>= function + | false -> Lwt.return @@ storage_error (Missing_key (k, Del)) + | _ -> remove t k >|= ok + + let add_or_remove t k = function None -> remove t k | Some v -> add t k v + + let add_or_remove_tree t k = function + | None -> remove t k + | Some v -> add_tree t k v +end + +let project x = x + +let absolute_key _ k = k + +let description = Storage_description.create () + +let fold_map_temporary_lazy_storage_ids ctxt f = + f (temporary_lazy_storage_ids ctxt) |> fun (temporary_lazy_storage_ids, x) -> + (update_temporary_lazy_storage_ids ctxt temporary_lazy_storage_ids, x) + +let map_temporary_lazy_storage_ids_s ctxt f = + f (temporary_lazy_storage_ids ctxt) + >|= fun (ctxt, temporary_lazy_storage_ids) -> + update_temporary_lazy_storage_ids ctxt temporary_lazy_storage_ids + +module Cache = struct + type key = Context.Cache.key + + type value = Context.Cache.value = .. + + let key_of_identifier = Context.Cache.key_of_identifier + + let identifier_of_key = Context.Cache.identifier_of_key + + let pp fmt ctxt = Context.Cache.pp fmt (context ctxt) + + let find c k = Context.Cache.find (context c) k + + let set_cache_layout c layout = + Context.Cache.set_cache_layout (context c) layout >>= fun ctxt -> + Lwt.return (update_context c ctxt) + + let update c k v = Context.Cache.update (context c) k v |> update_context c + + let sync c ~cache_nonce = + Context.Cache.sync (context c) ~cache_nonce >>= fun ctxt -> + Lwt.return (update_context c ctxt) + + let clear c = Context.Cache.clear (context c) |> update_context c + + let list_keys c ~cache_index = + Context.Cache.list_keys (context c) ~cache_index + + let key_rank c key = Context.Cache.key_rank (context c) key + + let cache_size_limit c ~cache_index = + Context.Cache.cache_size_limit (context c) ~cache_index + + let cache_size c ~cache_index = + Context.Cache.cache_size (context c) ~cache_index + + let future_cache_expectation c ~time_in_blocks = + Context.Cache.future_cache_expectation (context c) ~time_in_blocks + |> update_context c +end diff --git a/src/proto_011_PtHangzH/lib_protocol/raw_context.mli b/src/proto_011_PtHangzH/lib_protocol/raw_context.mli new file mode 100644 index 000000000000..d7c6073ed0f9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/raw_context.mli @@ -0,0 +1,221 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** {1 Errors} *) + +type error += Too_many_internal_operations (* `Permanent *) + +type missing_key_kind = Get | Set | Del | Copy + +(** An internal storage error that should not happen *) +type storage_error = + | Incompatible_protocol_version of string + | Missing_key of string list * missing_key_kind + | Existing_key of string list + | Corrupted_data of string list + +type error += Storage_error of storage_error + +type error += Failed_to_parse_parameter of bytes + +type error += Failed_to_decode_parameter of Data_encoding.json * string + +val storage_error : storage_error -> 'a tzresult + +(** {1 Abstract Context} *) + +(** Abstract view of the context. + Includes a handle to the functional key-value database + ({!Context.t}) along with some in-memory values (gas, etc.). *) +type t + +type root = t + +(** Retrieves the state of the database and gives its abstract view. + It also returns wether this is the first block validated + with this version of the protocol. *) +val prepare : + level:Int32.t -> + predecessor_timestamp:Time.t -> + timestamp:Time.t -> + fitness:Fitness.t -> + Context.t -> + t tzresult Lwt.t + +type previous_protocol = Genesis of Parameters_repr.t | Granada_010 + +val prepare_first_block : + level:int32 -> + timestamp:Time.t -> + fitness:Fitness.t -> + Context.t -> + (previous_protocol * t) tzresult Lwt.t + +val activate : t -> Protocol_hash.t -> t Lwt.t + +(** Returns the state of the database resulting of operations on its + abstract view *) +val recover : t -> Context.t + +val current_level : t -> Level_repr.t + +val predecessor_timestamp : t -> Time.t + +val current_timestamp : t -> Time.t + +val current_fitness : t -> Int64.t + +val set_current_fitness : t -> Int64.t -> t + +val constants : t -> Constants_repr.parametric + +val patch_constants : + t -> (Constants_repr.parametric -> Constants_repr.parametric) -> t Lwt.t + +(** Retrieve the cycle eras. *) +val cycle_eras : t -> Level_repr.cycle_eras + +(** Increment the current block fee stash that will be credited to baker's + frozen_fees account at finalize_application *) +val add_fees : t -> Tez_repr.t -> t tzresult + +(** Increment the current block reward stash that will be credited to baker's + frozen_fees account at finalize_application *) +val add_rewards : t -> Tez_repr.t -> t tzresult + +val get_fees : t -> Tez_repr.t + +val get_rewards : t -> Tez_repr.t + +type error += Gas_limit_too_high (* `Permanent *) + +val check_gas_limit_is_valid : t -> 'a Gas_limit_repr.Arith.t -> unit tzresult + +val consume_gas_limit_in_block : t -> 'a Gas_limit_repr.Arith.t -> t tzresult + +val set_gas_limit : t -> 'a Gas_limit_repr.Arith.t -> t + +val set_gas_unlimited : t -> t + +val gas_level : t -> Gas_limit_repr.t + +val gas_consumed : since:t -> until:t -> Gas_limit_repr.Arith.fp + +val remaining_operation_gas : t -> Gas_limit_repr.Arith.fp + +val update_remaining_operation_gas : t -> Gas_limit_repr.Arith.fp -> t + +val gas_exhausted_error : t -> 'a tzresult + +val block_gas_level : t -> Gas_limit_repr.Arith.fp + +val storage_space_to_pay : t -> Z.t option + +val init_storage_space_to_pay : t -> t + +val update_storage_space_to_pay : t -> Z.t -> t + +val update_allocated_contracts_count : t -> t + +val clear_storage_space_to_pay : t -> t * Z.t * int + +type error += Undefined_operation_nonce (* `Permanent *) + +val init_origination_nonce : t -> Operation_hash.t -> t + +val get_origination_nonce : t -> Contract_repr.origination_nonce tzresult + +val increment_origination_nonce : + t -> (t * Contract_repr.origination_nonce) tzresult + +val unset_origination_nonce : t -> t + +(** {1 Generic accessors} *) + +type key = string list + +type value = bytes + +type tree + +module type T = + Raw_context_intf.T + with type root := root + and type key := key + and type value := value + and type tree := tree + +include T with type t := t + +(** Initialize the local nonce used for preventing a script to + duplicate an internal operation to replay it. *) +val reset_internal_nonce : t -> t + +(** Increments the internal operation nonce. *) +val fresh_internal_nonce : t -> (t * int) tzresult + +(** Mark an internal operation nonce as taken. *) +val record_internal_nonce : t -> int -> t + +(** Check is the internal operation nonce has been taken. *) +val internal_nonce_already_recorded : t -> int -> bool + +(** Returns a map where to each endorser's pkh is associated the list of its + endorsing slots (in increasing order) for a given level. *) +val allowed_endorsements : + t -> + (Signature.Public_key.t * int list * bool) Signature.Public_key_hash.Map.t + +(** Keep track of the number of endorsements that are included in a block *) +val included_endorsements : t -> int + +(** Initializes the map of allowed endorsements, this function must only be + called once. *) +val init_endorsements : + t -> + (Signature.Public_key.t * int list * bool) Signature.Public_key_hash.Map.t -> + t + +(** Marks an endorsement in the map as used. *) +val record_endorsement : t -> Signature.Public_key_hash.t -> t + +val fold_map_temporary_lazy_storage_ids : + t -> + (Lazy_storage_kind.Temp_ids.t -> Lazy_storage_kind.Temp_ids.t * 'res) -> + t * 'res + +val map_temporary_lazy_storage_ids_s : + t -> + (Lazy_storage_kind.Temp_ids.t -> (t * Lazy_storage_kind.Temp_ids.t) Lwt.t) -> + t Lwt.t + +module Cache : + Context.CACHE + with type t := t + and type size := int + and type index := int + and type identifier := string + and type key = Context.Cache.key + and type value = Context.Cache.value diff --git a/src/proto_011_PtHangzH/lib_protocol/raw_context_intf.ml b/src/proto_011_PtHangzH/lib_protocol/raw_context_intf.ml new file mode 100644 index 000000000000..c2e095ec9ea6 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/raw_context_intf.ml @@ -0,0 +1,259 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2018-2021 Tarides *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** All context manipulation functions. This signature is included + as-is for direct context accesses, and used in {!Storage_functors} + to provide restricted views to the context. *) + +module type VIEW = sig + (* Same as [Environment_context.VIEW] but with extra getters and + setters functions. *) + + (** The type for context handler. *) + type t + + (** The type for context trees. *) + type tree + + (** The type for context keys. *) + type key = string list + + (** The type for context values. *) + type value = bytes + + (** {2 Getters} *) + + (** [mem t k] is an Lwt promise that resolves to [true] iff [k] is bound + to a value in [t]. *) + val mem : t -> key -> bool Lwt.t + + (** [mem_tree t k] is like {!mem} but for trees. *) + val mem_tree : t -> key -> bool Lwt.t + + (** [get t k] is an Lwt promise that resolves to [Ok v] if [k] is + bound to the value [v] in [t] and {!Storage_Error Missing_key} + otherwise. *) + val get : t -> key -> value tzresult Lwt.t + + (** [get_tree] is like {!get} but for trees. *) + val get_tree : t -> key -> tree tzresult Lwt.t + + (** [find t k] is an Lwt promise that resolves to [Some v] if [k] is + bound to the value [v] in [t] and [None] otherwise. *) + val find : t -> key -> value option Lwt.t + + (** [find_tree t k] is like {!find} but for trees. *) + val find_tree : t -> key -> tree option Lwt.t + + (** [list t key] is the list of files and sub-nodes stored under [k] in [t]. + The result order is not specified but is stable. + + [offset] and [length] are used for pagination. *) + val list : + t -> ?offset:int -> ?length:int -> key -> (string * tree) list Lwt.t + + (** {2 Setters} *) + + (** [init t k v] is an Lwt promise that resolves to [Ok c] if: + + - [k] is unbound in [t]; + - [k] is bound to [v] in [c]; + - and [c] is similar to [t] otherwise. + + It is {!Storage_error Existing_key} if [k] is already bound in [t]. *) + val init : t -> key -> value -> t tzresult Lwt.t + + (** [init_tree] is like {!init} but for trees. *) + val init_tree : t -> key -> tree -> t tzresult Lwt.t + + (** [update t k v] is an Lwt promise that resolves to [Ok c] if: + + - [k] is bound in [t]; + - [k] is bound to [v] in [c]; + - and [c] is similar to [t] otherwise. + + It is {!Storage_error Missing_key} if [k] is not already bound in [t]. *) + val update : t -> key -> value -> t tzresult Lwt.t + + (** [update_tree] is like {!update} but for trees. *) + val update_tree : t -> key -> tree -> t tzresult Lwt.t + + (** [add t k v] is an Lwt promise that resolves to [c] such that: + + - [k] is bound to [v] in [c]; + - and [c] is similar to [t] otherwise. + + If [k] was already bound in [t] to a value that is physically equal + to [v], the result of the function is a promise that resolves to + [t]. Otherwise, the previous binding of [k] in [t] disappears. *) + val add : t -> key -> value -> t Lwt.t + + (** [add_tree] is like {!add} but for trees. *) + val add_tree : t -> key -> tree -> t Lwt.t + + (** [remove t k v] is an Lwt promise that resolves to [c] such that: + + - [k] is unbound in [c]; + - and [c] is similar to [t] otherwise. *) + val remove : t -> key -> t Lwt.t + + (** [remove_existing t k v] is an Lwt promise that resolves to [Ok c] if: + + - [k] is bound in [t] to a value; + - [k] is unbound in [c]; + - and [c] is similar to [t] otherwise.*) + val remove_existing : t -> key -> t tzresult Lwt.t + + (** [remove_existing_tree t k v] is an Lwt promise that reolves to [Ok c] if: + + - [k] is bound in [t] to a tree; + - [k] is unbound in [c]; + - and [c] is similar to [t] otherwise.*) + val remove_existing_tree : t -> key -> t tzresult Lwt.t + + (** [add_or_remove t k v] is: + + - [add t k x] if [v] is [Some x]; + - [remove t k] otherwise. *) + val add_or_remove : t -> key -> value option -> t Lwt.t + + (** [add_or_remove_tree t k v] is: + + - [add_tree t k x] if [v] is [Some x]; + - [remove t k] otherwise. *) + val add_or_remove_tree : t -> key -> tree option -> t Lwt.t + + (** {2 Folds} *) + + (** [fold ?depth t root ~init ~f] recursively folds over the trees + and values of [t]. The [f] callbacks are called with a key relative + to [root]. [f] is never called with an empty key for values; i.e., + folding over a value is a no-op. + + Elements are traversed in lexical order of keys. + + The depth is 0-indexed. If [depth] is set (by default it is not), then [f] + is only called when the conditions described by the parameter is true: + + - [Eq d] folds over nodes and contents of depth exactly [d]. + - [Lt d] folds over nodes and contents of depth strictly less than [d]. + - [Le d] folds over nodes and contents of depth less than or equal to [d]. + - [Gt d] folds over nodes and contents of depth strictly more than [d]. + - [Ge d] folds over nodes and contents of depth more than or equal to [d]. *) + val fold : + ?depth:[`Eq of int | `Le of int | `Lt of int | `Ge of int | `Gt of int] -> + t -> + key -> + init:'a -> + f:(key -> tree -> 'a -> 'a Lwt.t) -> + 'a Lwt.t +end + +module type TREE = sig + (** [Tree] provides immutable, in-memory partial mirror of the + context, with lazy reads and delayed writes. The trees are Merkle + trees that carry the same hash as the part of the context they + mirror. + + Trees are immutable and non-persistent (they disappear if the + host crash), held in memory for efficiency, where reads are done + lazily and writes are done only when needed, e.g. on + [Context.commit]. If a key is modified twice, only the last + value will be written to disk on commit. *) + + (** The type for context views. *) + type t + + (** The type for context trees. *) + type tree + + include VIEW with type t := tree and type tree := tree + + (** [empty _] is the empty tree. *) + val empty : t -> tree + + (** [is_empty t] is true iff [t] is [empty _]. *) + val is_empty : tree -> bool + + (** [kind t] is [t]'s kind. It's either a tree node or a leaf + value. *) + val kind : tree -> [`Value | `Tree] + + (** [to_value t] is [Some v] is [t] is a leaf tree and [None] otherwise. *) + val to_value : tree -> value option Lwt.t + + (** [hash t] is [t]'s Merkle hash. *) + val hash : tree -> Context_hash.t + + (** [equal x y] is true iff [x] and [y] have the same Merkle hash. *) + val equal : tree -> tree -> bool + + (** {2 Caches} *) + + (** [clear ?depth t] clears all caches in the tree [t] for subtrees with a + depth higher than [depth]. If [depth] is not set, all of the subtrees are + cleared. *) + val clear : ?depth:int -> tree -> unit +end + +module type T = sig + (** The type for root contexts. *) + type root + + include VIEW + + module Tree : + TREE + with type t := t + and type key := key + and type value := value + and type tree := tree + + (** Internally used in {!Storage_functors} to escape from a view. *) + val project : t -> root + + (** Internally used in {!Storage_functors} to retrieve a full key + from partial key relative a view. *) + val absolute_key : t -> key -> key + + (** Raised if block gas quota is exhausted during gas + consumption. *) + type error += Block_quota_exceeded + + (** Raised if operation gas quota is exhausted during gas + consumption. *) + type error += Operation_quota_exceeded + + (** Internally used in {!Storage_functors} to consume gas from + within a view. May raise {!Block_quota_exceeded} or + {!Operation_quota_exceeded}. *) + val consume_gas : t -> Gas_limit_repr.cost -> t tzresult + + (** Check if consume_gas will fail *) + val check_enough_gas : t -> Gas_limit_repr.cost -> unit tzresult + + val description : t Storage_description.t +end diff --git a/src/proto_011_PtHangzH/lib_protocol/raw_level_repr.ml b/src/proto_011_PtHangzH/lib_protocol/raw_level_repr.ml new file mode 100644 index 000000000000..c9fec65666c3 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/raw_level_repr.ml @@ -0,0 +1,99 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type t = int32 + +type raw_level = t + +include (Compare.Int32 : Compare.S with type t := t) + +let pp ppf level = Format.fprintf ppf "%ld" level + +let rpc_arg = + let construct raw_level = Int32.to_string raw_level in + let destruct str = + Int32.of_string_opt str |> Option.to_result ~none:"Cannot parse level" + in + RPC_arg.make + ~descr:"A level integer" + ~name:"block_level" + ~construct + ~destruct + () + +let root = 0l + +let succ = Int32.succ + +let pred l = if l = 0l then None else Some (Int32.pred l) + +let diff = Int32.sub + +let to_int32 l = l + +let of_int32_exn l = + if Compare.Int32.(l >= 0l) then l else invalid_arg "Level_repr.of_int32" + +let encoding = + Data_encoding.conv_with_guard + (fun i -> i) + (fun i -> try ok (of_int32_exn i) with Invalid_argument s -> Error s) + Data_encoding.int32 + +type error += Unexpected_level of Int32.t (* `Permanent *) + +let () = + register_error_kind + `Permanent + ~id:"unexpected_level" + ~title:"Unexpected level" + ~description:"Level must be non-negative." + ~pp:(fun ppf l -> + Format.fprintf + ppf + "The level is %s but should be non-negative." + (Int32.to_string l)) + Data_encoding.(obj1 (req "level" int32)) + (function Unexpected_level l -> Some l | _ -> None) + (fun l -> Unexpected_level l) + +let of_int32 l = + Error_monad.catch_f (fun () -> of_int32_exn l) (fun _ -> Unexpected_level l) + +module Index = struct + type t = raw_level + + let path_length = 1 + + let to_path level l = Int32.to_string level :: l + + let of_path = function [s] -> Int32.of_string_opt s | _ -> None + + let rpc_arg = rpc_arg + + let encoding = encoding + + let compare = compare +end diff --git a/src/proto_011_PtHangzH/lib_protocol/raw_level_repr.mli b/src/proto_011_PtHangzH/lib_protocol/raw_level_repr.mli new file mode 100644 index 000000000000..99b4cc8b632c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/raw_level_repr.mli @@ -0,0 +1,58 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** The shell's notion of a level: an integer indicating the number of blocks + since genesis: genesis is 0, all other blocks have increasing levels from + there. *) +type t + +type raw_level = t + +(** @raise Invalid_argument when the level to encode is not positive *) +val encoding : raw_level Data_encoding.t + +val rpc_arg : raw_level RPC_arg.arg + +val pp : Format.formatter -> raw_level -> unit + +include Compare.S with type t := raw_level + +val to_int32 : raw_level -> int32 + +(** @raise Invalid_argument when the level to encode is negative *) +val of_int32_exn : int32 -> raw_level + +(** Can trigger Unexpected_level error when the level to encode is negative *) +val of_int32 : int32 -> raw_level tzresult + +val diff : raw_level -> raw_level -> int32 + +val root : raw_level + +val succ : raw_level -> raw_level + +val pred : raw_level -> raw_level option + +module Index : Storage_description.INDEX with type t = raw_level diff --git a/src/proto_011_PtHangzH/lib_protocol/receipt_repr.ml b/src/proto_011_PtHangzH/lib_protocol/receipt_repr.ml new file mode 100644 index 000000000000..505320afc75c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/receipt_repr.ml @@ -0,0 +1,149 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type balance = + | Contract of Contract_repr.t + | Rewards of Signature.Public_key_hash.t * Cycle_repr.t + | Fees of Signature.Public_key_hash.t * Cycle_repr.t + | Deposits of Signature.Public_key_hash.t * Cycle_repr.t + +let balance_encoding = + let open Data_encoding in + def "operation_metadata.alpha.balance" + @@ union + [ + case + (Tag 0) + ~title:"Contract" + (obj2 + (req "kind" (constant "contract")) + (req "contract" Contract_repr.encoding)) + (function Contract c -> Some ((), c) | _ -> None) + (fun ((), c) -> Contract c); + case + (Tag 1) + ~title:"Rewards" + (obj4 + (req "kind" (constant "freezer")) + (req "category" (constant "rewards")) + (req "delegate" Signature.Public_key_hash.encoding) + (req "cycle" Cycle_repr.encoding)) + (function Rewards (d, l) -> Some ((), (), d, l) | _ -> None) + (fun ((), (), d, l) -> Rewards (d, l)); + case + (Tag 2) + ~title:"Fees" + (obj4 + (req "kind" (constant "freezer")) + (req "category" (constant "fees")) + (req "delegate" Signature.Public_key_hash.encoding) + (req "cycle" Cycle_repr.encoding)) + (function Fees (d, l) -> Some ((), (), d, l) | _ -> None) + (fun ((), (), d, l) -> Fees (d, l)); + case + (Tag 3) + ~title:"Deposits" + (obj4 + (req "kind" (constant "freezer")) + (req "category" (constant "deposits")) + (req "delegate" Signature.Public_key_hash.encoding) + (req "cycle" Cycle_repr.encoding)) + (function Deposits (d, l) -> Some ((), (), d, l) | _ -> None) + (fun ((), (), d, l) -> Deposits (d, l)); + ] + +type balance_update = Debited of Tez_repr.t | Credited of Tez_repr.t + +let balance_update_encoding = + let open Data_encoding in + def "operation_metadata.alpha.balance_update" + @@ obj1 + (req + "change" + (conv + (function + | Credited v -> Tez_repr.to_mutez v + | Debited v -> Int64.neg (Tez_repr.to_mutez v)) + ( Json.wrap_error @@ fun v -> + if Compare.Int64.(v < 0L) then + match Tez_repr.of_mutez (Int64.neg v) with + | Some v -> Debited v + | None -> assert false (* [of_mutez z] is [None] iff [z < 0] *) + else + match Tez_repr.of_mutez v with + | Some v -> Credited v + | None -> assert false (* same *) ) + int64)) + +type update_origin = Block_application | Protocol_migration | Subsidy + +let update_origin_encoding = + let open Data_encoding in + def "operation_metadata.alpha.update_origin" + @@ obj1 @@ req "origin" + @@ union + [ + case + (Tag 0) + ~title:"Block_application" + (constant "block") + (function Block_application -> Some () | _ -> None) + (fun () -> Block_application); + case + (Tag 1) + ~title:"Protocol_migration" + (constant "migration") + (function Protocol_migration -> Some () | _ -> None) + (fun () -> Protocol_migration); + case + (Tag 2) + ~title:"Subsidy" + (constant "subsidy") + (function Subsidy -> Some () | _ -> None) + (fun () -> Subsidy); + ] + +type balance_updates = (balance * balance_update * update_origin) list + +let balance_updates_encoding = + let open Data_encoding in + def "operation_metadata.alpha.balance_updates" + @@ list + (conv + (function + | (balance, balance_update, update_origin) -> + ((balance, balance_update), update_origin)) + (fun ((balance, balance_update), update_origin) -> + (balance, balance_update, update_origin)) + (merge_objs + (merge_objs balance_encoding balance_update_encoding) + update_origin_encoding)) + +let cleanup_balance_updates balance_updates = + List.filter + (fun (_, (Credited update | Debited update), _) -> + not (Tez_repr.equal update Tez_repr.zero)) + balance_updates diff --git a/src/proto_011_PtHangzH/lib_protocol/receipt_repr.mli b/src/proto_011_PtHangzH/lib_protocol/receipt_repr.mli new file mode 100644 index 000000000000..aca6492c6662 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/receipt_repr.mli @@ -0,0 +1,52 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Places where tez can be found in the ledger's state. *) +type balance = + | Contract of Contract_repr.t + | Rewards of Signature.Public_key_hash.t * Cycle_repr.t + | Fees of Signature.Public_key_hash.t * Cycle_repr.t + | Deposits of Signature.Public_key_hash.t * Cycle_repr.t + +(** A credit or debit of tez to a balance. *) +type balance_update = Debited of Tez_repr.t | Credited of Tez_repr.t + +(** An origin of a balance update *) +type update_origin = + | Block_application (** Update from a block application *) + | Protocol_migration (** Update from a protocol migration *) + | Subsidy (** Update from an inflationary subsidy *) + +(** A list of balance updates. Duplicates may happen. + For example, an entry of the form [(Rewards (b,c), Credited am, ...)] + indicates that the balance of frozen rewards has been increased by [am] + for baker [b] and cycle [c]. *) +type balance_updates = (balance * balance_update * update_origin) list + +val balance_updates_encoding : balance_updates Data_encoding.t + +(** Remove zero-valued balances from a list of updates. *) +val cleanup_balance_updates : balance_updates -> balance_updates diff --git a/src/proto_011_PtHangzH/lib_protocol/roll_repr.ml b/src/proto_011_PtHangzH/lib_protocol/roll_repr.ml new file mode 100644 index 000000000000..3ad3bcb0b181 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/roll_repr.ml @@ -0,0 +1,56 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +include Compare.Int32 + +type roll = t + +let encoding = Data_encoding.int32 + +let first = 0l + +let succ i = Int32.succ i + +let random sequence ~bound = Seed_repr.take_int32 sequence bound + +let rpc_arg = RPC_arg.like RPC_arg.int32 "roll" + +let to_int32 v = v + +module Index = struct + type t = roll + + let path_length = 1 + + let to_path roll l = Int32.to_string roll :: l + + let of_path = function s :: _ -> Int32.of_string_opt s | _ -> None + + let rpc_arg = rpc_arg + + let encoding = encoding + + let compare = compare +end diff --git a/src/proto_011_PtHangzH/lib_protocol/roll_repr.mli b/src/proto_011_PtHangzH/lib_protocol/roll_repr.mli new file mode 100644 index 000000000000..cb792b0128e7 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/roll_repr.mli @@ -0,0 +1,44 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type t = private int32 + +type roll = t + +val encoding : roll Data_encoding.t + +val rpc_arg : roll RPC_arg.t + +val random : Seed_repr.sequence -> bound:roll -> roll * Seed_repr.sequence + +val first : roll + +val succ : roll -> roll + +val to_int32 : roll -> Int32.t + +val ( = ) : roll -> roll -> bool + +module Index : Storage_description.INDEX with type t = roll diff --git a/src/proto_011_PtHangzH/lib_protocol/roll_storage.ml b/src/proto_011_PtHangzH/lib_protocol/roll_storage.ml new file mode 100644 index 000000000000..9b872cb49263 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/roll_storage.ml @@ -0,0 +1,491 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Misc + +type error += + | (* `Permanent *) Consume_roll_change + | (* `Permanent *) No_roll_for_delegate + | (* `Permanent *) No_roll_snapshot_for_cycle of Cycle_repr.t + | (* `Permanent *) Unregistered_delegate of Signature.Public_key_hash.t + +let () = + let open Data_encoding in + (* Consume roll change *) + register_error_kind + `Permanent + ~id:"contract.manager.consume_roll_change" + ~title:"Consume roll change" + ~description:"Change is not enough to consume a roll." + ~pp:(fun ppf () -> + Format.fprintf ppf "Not enough change to consume a roll.") + empty + (function Consume_roll_change -> Some () | _ -> None) + (fun () -> Consume_roll_change) ; + (* No roll for delegate *) + register_error_kind + `Permanent + ~id:"contract.manager.no_roll_for_delegate" + ~title:"No roll for delegate" + ~description:"Delegate has no roll." + ~pp:(fun ppf () -> Format.fprintf ppf "Delegate has no roll.") + empty + (function No_roll_for_delegate -> Some () | _ -> None) + (fun () -> No_roll_for_delegate) ; + (* No roll snapshot for cycle *) + register_error_kind + `Permanent + ~id:"contract.manager.no_roll_snapshot_for_cycle" + ~title:"No roll snapshot for cycle" + ~description: + "A snapshot of the rolls distribution does not exist for this cycle." + ~pp:(fun ppf c -> + Format.fprintf + ppf + "A snapshot of the rolls distribution does not exist for cycle %a" + Cycle_repr.pp + c) + (obj1 (req "cycle" Cycle_repr.encoding)) + (function No_roll_snapshot_for_cycle c -> Some c | _ -> None) + (fun c -> No_roll_snapshot_for_cycle c) ; + (* Unregistered delegate *) + register_error_kind + `Permanent + ~id:"contract.manager.unregistered_delegate" + ~title:"Unregistered delegate" + ~description:"A contract cannot be delegated to an unregistered delegate" + ~pp:(fun ppf k -> + Format.fprintf + ppf + "The provided public key (with hash %a) is not registered as valid \ + delegate key." + Signature.Public_key_hash.pp + k) + (obj1 (req "hash" Signature.Public_key_hash.encoding)) + (function Unregistered_delegate k -> Some k | _ -> None) + (fun k -> Unregistered_delegate k) + +let get_contract_delegate ctxt contract = + Storage.Contract.Delegate.find ctxt contract + +let delegate_pubkey ctxt delegate = + Storage.Contract.Manager.find ctxt (Contract_repr.implicit_contract delegate) + >>=? function + | None | Some (Manager_repr.Hash _) -> fail (Unregistered_delegate delegate) + | Some (Manager_repr.Public_key pk) -> return pk + +let clear_cycle ctxt cycle = + Storage.Roll.Snapshot_for_cycle.get ctxt cycle >>=? fun index -> + Storage.Roll.Snapshot_for_cycle.remove_existing ctxt cycle >>=? fun ctxt -> + Storage.Roll.Last_for_snapshot.remove_existing (ctxt, cycle) index + >>=? fun ctxt -> Storage.Roll.Owner.delete_snapshot ctxt (cycle, index) >|= ok + +let fold ctxt ~f init = + Storage.Roll.Next.get ctxt >>=? fun last -> + let[@coq_struct "roll"] rec loop ctxt roll acc = + if Roll_repr.(roll = last) then return acc + else + Storage.Roll.Owner.find ctxt roll >>=? function + | None -> loop ctxt (Roll_repr.succ roll) acc + | Some delegate -> + f roll delegate acc >>=? fun acc -> + loop ctxt (Roll_repr.succ roll) acc + in + loop ctxt Roll_repr.first init + +let snapshot_rolls_for_cycle ctxt cycle = + Storage.Roll.Snapshot_for_cycle.get ctxt cycle >>=? fun index -> + Storage.Roll.Snapshot_for_cycle.update ctxt cycle (index + 1) >>=? fun ctxt -> + Storage.Roll.Owner.snapshot ctxt (cycle, index) >>=? fun ctxt -> + Storage.Roll.Next.get ctxt >>=? fun last -> + Storage.Roll.Last_for_snapshot.init (ctxt, cycle) index last + +(* NOTE: Deletes all snapshots for a given cycle that are not randomly selected. *) +let freeze_rolls_for_cycle ctxt cycle = + Storage.Roll.Snapshot_for_cycle.get ctxt cycle >>=? fun max_index -> + Storage.Seed.For_cycle.get ctxt cycle >>=? fun seed -> + let rd = Seed_repr.initialize_new seed [Bytes.of_string "roll_snapshot"] in + let seq = Seed_repr.sequence rd 0l in + let selected_index = + Seed_repr.take_int32 seq (Int32.of_int max_index) |> fst |> Int32.to_int + in + Storage.Roll.Snapshot_for_cycle.update ctxt cycle selected_index + >>=? fun ctxt -> + List.fold_left_es + (fun ctxt index -> + if Compare.Int.(index = selected_index) then return ctxt + else + Storage.Roll.Owner.delete_snapshot ctxt (cycle, index) >>= fun ctxt -> + Storage.Roll.Last_for_snapshot.remove_existing (ctxt, cycle) index) + ctxt + (0 --> (max_index - 1)) + +(* Roll selection *) +module Random = struct + let int32_to_bytes i = + let b = Bytes.make 4 '0' in + TzEndian.set_int32 b 0 i ; + b + + let level_random seed use (level : Level_repr.t) = + let position = level.Level_repr.cycle_position in + Seed_repr.initialize_new + seed + [Bytes.of_string ("level " ^ use ^ ":"); int32_to_bytes position] + + let owner c kind (level : Level_repr.t) offset = + let cycle = level.Level_repr.cycle in + Seed_storage.for_cycle c cycle >>=? fun random_seed -> + let rd = level_random random_seed kind level in + let sequence = Seed_repr.sequence rd (Int32.of_int offset) in + Storage.Roll.Snapshot_for_cycle.get c cycle >>=? fun index -> + Storage.Roll.Last_for_snapshot.get (c, cycle) index >>=? fun bound -> + let rec loop sequence = + let (roll, sequence) = Roll_repr.random sequence ~bound in + Storage.Roll.Owner.Snapshot.find c ((cycle, index), roll) >>=? function + | None -> loop sequence + | Some delegate -> return delegate + in + Storage.Roll.Owner.snapshot_exists c (cycle, index) + >>= fun snapshot_exists -> + error_unless snapshot_exists (No_roll_snapshot_for_cycle cycle) + >>?= fun () -> loop sequence +end + +let baking_rights_owner c level ~priority = + Random.owner c "baking" level priority + +let endorsement_rights_owner c level ~slot = + Random.owner c "endorsement" level slot + +let count_rolls ctxt delegate = + Storage.Roll.Delegate_roll_list.find ctxt delegate >>=? function + | None -> return 0 + | Some head_roll -> + let[@coq_struct "roll"] rec loop acc roll = + Storage.Roll.Successor.find ctxt roll >>=? function + | None -> return acc + | Some next -> loop (succ acc) next + in + loop 1 head_roll + +let get_change ctxt delegate = + Storage.Roll.Delegate_change.find ctxt delegate + >|=? Option.value ~default:Tez_repr.zero + +module Delegate = struct + let fresh_roll ctxt = + Storage.Roll.Next.get ctxt >>=? fun roll -> + Storage.Roll.Next.update ctxt (Roll_repr.succ roll) >|=? fun ctxt -> + (roll, ctxt) + + let get_limbo_roll ctxt = + Storage.Roll.Limbo.find ctxt >>=? function + | None -> + fresh_roll ctxt >>=? fun (roll, ctxt) -> + Storage.Roll.Limbo.init ctxt roll >|=? fun ctxt -> (roll, ctxt) + | Some roll -> return (roll, ctxt) + + let consume_roll_change ctxt delegate = + let tokens_per_roll = Constants_storage.tokens_per_roll ctxt in + Storage.Roll.Delegate_change.get ctxt delegate >>=? fun change -> + record_trace Consume_roll_change Tez_repr.(change -? tokens_per_roll) + >>?= fun new_change -> + Storage.Roll.Delegate_change.update ctxt delegate new_change + + let recover_roll_change ctxt delegate = + let tokens_per_roll = Constants_storage.tokens_per_roll ctxt in + Storage.Roll.Delegate_change.get ctxt delegate >>=? fun change -> + Tez_repr.(change +? tokens_per_roll) >>?= fun new_change -> + Storage.Roll.Delegate_change.update ctxt delegate new_change + + let pop_roll_from_delegate ctxt delegate = + recover_roll_change ctxt delegate >>=? fun ctxt -> + (* beginning: + delegate : roll -> successor_roll -> ... + limbo : limbo_head -> ... + *) + Storage.Roll.Limbo.find ctxt >>=? fun limbo_head -> + Storage.Roll.Delegate_roll_list.find ctxt delegate >>=? function + | None -> fail No_roll_for_delegate + | Some roll -> + Storage.Roll.Owner.remove_existing ctxt roll >>=? fun ctxt -> + Storage.Roll.Successor.find ctxt roll >>=? fun successor_roll -> + Storage.Roll.Delegate_roll_list.add_or_remove + ctxt + delegate + successor_roll + >>= fun ctxt -> + (* delegate : successor_roll -> ... + roll ------^ + limbo : limbo_head -> ... *) + Storage.Roll.Successor.add_or_remove ctxt roll limbo_head + >>= fun ctxt -> + (* delegate : successor_roll -> ... + roll ------v + limbo : limbo_head -> ... *) + Storage.Roll.Limbo.add ctxt roll >|= fun ctxt -> + (* delegate : successor_roll -> ... + limbo : roll -> limbo_head -> ... *) + ok (roll, ctxt) + + let create_roll_in_delegate ctxt delegate delegate_pk = + consume_roll_change ctxt delegate >>=? fun ctxt -> + (* beginning: + delegate : delegate_head -> ... + limbo : roll -> limbo_successor -> ... + *) + Storage.Roll.Delegate_roll_list.find ctxt delegate >>=? fun delegate_head -> + get_limbo_roll ctxt >>=? fun (roll, ctxt) -> + Storage.Roll.Owner.init ctxt roll delegate_pk >>=? fun ctxt -> + Storage.Roll.Successor.find ctxt roll >>=? fun limbo_successor -> + Storage.Roll.Limbo.add_or_remove ctxt limbo_successor >>= fun ctxt -> + (* delegate : delegate_head -> ... + roll ------v + limbo : limbo_successor -> ... *) + Storage.Roll.Successor.add_or_remove ctxt roll delegate_head >>= fun ctxt -> + (* delegate : delegate_head -> ... + roll ------^ + limbo : limbo_successor -> ... *) + Storage.Roll.Delegate_roll_list.add ctxt delegate roll + (* delegate : roll -> delegate_head -> ... + limbo : limbo_successor -> ... *) + >|= ok + + let ensure_inited ctxt delegate = + Storage.Roll.Delegate_change.mem ctxt delegate >>= function + | true -> return ctxt + | false -> Storage.Roll.Delegate_change.init ctxt delegate Tez_repr.zero + + let is_inactive ctxt delegate = + Storage.Contract.Inactive_delegate.mem + ctxt + (Contract_repr.implicit_contract delegate) + >>= fun inactive -> + if inactive then return inactive + else + Storage.Contract.Delegate_desactivation.find + ctxt + (Contract_repr.implicit_contract delegate) + >|=? function + | Some last_active_cycle -> + let ({Level_repr.cycle = current_cycle; _} : Level_repr.t) = + Raw_context.current_level ctxt + in + Cycle_repr.(last_active_cycle < current_cycle) + | None -> + (* This case is only when called from `set_active`, when creating + a contract. *) + false + + let add_amount ctxt delegate amount = + ensure_inited ctxt delegate >>=? fun ctxt -> + let tokens_per_roll = Constants_storage.tokens_per_roll ctxt in + Storage.Roll.Delegate_change.get ctxt delegate >>=? fun change -> + Tez_repr.(amount +? change) >>?= fun change -> + Storage.Roll.Delegate_change.update ctxt delegate change >>=? fun ctxt -> + delegate_pubkey ctxt delegate >>=? fun delegate_pk -> + let[@coq_struct "change"] rec loop ctxt change = + if Tez_repr.(change < tokens_per_roll) then return ctxt + else + Tez_repr.(change -? tokens_per_roll) >>?= fun change -> + create_roll_in_delegate ctxt delegate delegate_pk >>=? fun ctxt -> + loop ctxt change + in + is_inactive ctxt delegate >>=? fun inactive -> + if inactive then return ctxt + else + loop ctxt change >>=? fun ctxt -> + Storage.Roll.Delegate_roll_list.find ctxt delegate >>=? fun rolls -> + match rolls with + | None -> return ctxt + | Some _ -> Storage.Active_delegates_with_rolls.add ctxt delegate >|= ok + + let remove_amount ctxt delegate amount = + let tokens_per_roll = Constants_storage.tokens_per_roll ctxt in + let[@coq_struct "change"] rec loop ctxt change = + if Tez_repr.(amount <= change) then return (ctxt, change) + else + pop_roll_from_delegate ctxt delegate >>=? fun (_, ctxt) -> + Tez_repr.(change +? tokens_per_roll) >>?= fun change -> loop ctxt change + in + Storage.Roll.Delegate_change.get ctxt delegate >>=? fun change -> + is_inactive ctxt delegate >>=? fun inactive -> + (if inactive then return (ctxt, change) + else + loop ctxt change >>=? fun (ctxt, change) -> + Storage.Roll.Delegate_roll_list.find ctxt delegate >>=? fun rolls -> + match rolls with + | None -> + Storage.Active_delegates_with_rolls.remove ctxt delegate + >|= fun ctxt -> ok (ctxt, change) + | Some _ -> return (ctxt, change)) + >>=? fun (ctxt, change) -> + Tez_repr.(change -? amount) >>?= fun change -> + Storage.Roll.Delegate_change.update ctxt delegate change + + let set_inactive ctxt delegate = + ensure_inited ctxt delegate >>=? fun ctxt -> + let tokens_per_roll = Constants_storage.tokens_per_roll ctxt in + Storage.Roll.Delegate_change.get ctxt delegate >>=? fun change -> + Storage.Contract.Inactive_delegate.add + ctxt + (Contract_repr.implicit_contract delegate) + >>= fun ctxt -> + Storage.Active_delegates_with_rolls.remove ctxt delegate >>= fun ctxt -> + let[@coq_struct "change"] rec loop ctxt change = + Storage.Roll.Delegate_roll_list.find ctxt delegate >>=? function + | None -> return (ctxt, change) + | Some _roll -> + pop_roll_from_delegate ctxt delegate >>=? fun (_, ctxt) -> + Tez_repr.(change +? tokens_per_roll) >>?= fun change -> + loop ctxt change + in + loop ctxt change >>=? fun (ctxt, change) -> + Storage.Roll.Delegate_change.update ctxt delegate change + + let set_active ctxt delegate = + is_inactive ctxt delegate >>=? fun inactive -> + let current_cycle = (Raw_context.current_level ctxt).cycle in + let preserved_cycles = Constants_storage.preserved_cycles ctxt in + (* When the delegate is new or inactive, she will become active in + `1+preserved_cycles`, and we allow `preserved_cycles` for the + delegate to start baking. When the delegate is active, we only + give her at least `preserved_cycles` after the current cycle + before to be deactivated. *) + Storage.Contract.Delegate_desactivation.find + ctxt + (Contract_repr.implicit_contract delegate) + >>=? fun current_expiration -> + let expiration = + match current_expiration with + | None -> Cycle_repr.add current_cycle (1 + (2 * preserved_cycles)) + | Some current_expiration -> + let delay = + if inactive then 1 + (2 * preserved_cycles) + else 1 + preserved_cycles + in + let updated = Cycle_repr.add current_cycle delay in + Cycle_repr.max current_expiration updated + in + Storage.Contract.Delegate_desactivation.add + ctxt + (Contract_repr.implicit_contract delegate) + expiration + >>= fun ctxt -> + if not inactive then return ctxt + else + ensure_inited ctxt delegate >>=? fun ctxt -> + let tokens_per_roll = Constants_storage.tokens_per_roll ctxt in + Storage.Roll.Delegate_change.get ctxt delegate >>=? fun change -> + Storage.Contract.Inactive_delegate.remove + ctxt + (Contract_repr.implicit_contract delegate) + >>= fun ctxt -> + delegate_pubkey ctxt delegate >>=? fun delegate_pk -> + let[@coq_struct "change"] rec loop ctxt change = + if Tez_repr.(change < tokens_per_roll) then return ctxt + else + Tez_repr.(change -? tokens_per_roll) >>?= fun change -> + create_roll_in_delegate ctxt delegate delegate_pk >>=? fun ctxt -> + loop ctxt change + in + loop ctxt change >>=? fun ctxt -> + Storage.Roll.Delegate_roll_list.find ctxt delegate >>=? fun rolls -> + match rolls with + | None -> return ctxt + | Some _ -> Storage.Active_delegates_with_rolls.add ctxt delegate >|= ok +end + +module Contract = struct + let add_amount c contract amount = + get_contract_delegate c contract >>=? function + | None -> return c + | Some delegate -> Delegate.add_amount c delegate amount + + let remove_amount c contract amount = + get_contract_delegate c contract >>=? function + | None -> return c + | Some delegate -> Delegate.remove_amount c delegate amount +end + +let init ctxt = Storage.Roll.Next.init ctxt Roll_repr.first + +let init_first_cycles ctxt = + let preserved = Constants_storage.preserved_cycles ctxt in + (* Precompute rolls for cycle (0 --> preserved_cycles) *) + List.fold_left_es + (fun ctxt c -> + let cycle = Cycle_repr.of_int32_exn (Int32.of_int c) in + Storage.Roll.Snapshot_for_cycle.init ctxt cycle 0 >>=? fun ctxt -> + snapshot_rolls_for_cycle ctxt cycle >>=? fun ctxt -> + freeze_rolls_for_cycle ctxt cycle) + ctxt + (0 --> preserved) + >>=? fun ctxt -> + let cycle = Cycle_repr.of_int32_exn (Int32.of_int (preserved + 1)) in + (* Precomputed a snapshot for cycle (preserved_cycles + 1) *) + Storage.Roll.Snapshot_for_cycle.init ctxt cycle 0 >>=? fun ctxt -> + snapshot_rolls_for_cycle ctxt cycle >>=? fun ctxt -> + (* Prepare storage for storing snapshots for cycle (preserved_cycles+2) *) + let cycle = Cycle_repr.of_int32_exn (Int32.of_int (preserved + 2)) in + Storage.Roll.Snapshot_for_cycle.init ctxt cycle 0 + +let snapshot_rolls ctxt = + let current_level = Raw_context.current_level ctxt in + let preserved = Constants_storage.preserved_cycles ctxt in + let cycle = Cycle_repr.add current_level.cycle (preserved + 2) in + snapshot_rolls_for_cycle ctxt cycle + +let cycle_end ctxt last_cycle = + let preserved = Constants_storage.preserved_cycles ctxt in + (match Cycle_repr.sub last_cycle preserved with + | None -> return ctxt + | Some cleared_cycle -> clear_cycle ctxt cleared_cycle) + >>=? fun ctxt -> + let frozen_roll_cycle = Cycle_repr.add last_cycle (preserved + 1) in + freeze_rolls_for_cycle ctxt frozen_roll_cycle >>=? fun ctxt -> + Storage.Roll.Snapshot_for_cycle.init + ctxt + (Cycle_repr.succ (Cycle_repr.succ frozen_roll_cycle)) + 0 + +let update_tokens_per_roll ctxt new_tokens_per_roll = + let constants = Raw_context.constants ctxt in + let old_tokens_per_roll = constants.tokens_per_roll in + Raw_context.patch_constants ctxt (fun constants -> + {constants with Constants_repr.tokens_per_roll = new_tokens_per_roll}) + >>= fun ctxt -> + let decrease = Tez_repr.(new_tokens_per_roll < old_tokens_per_roll) in + (if decrease then Tez_repr.(old_tokens_per_roll -? new_tokens_per_roll) + else Tez_repr.(new_tokens_per_roll -? old_tokens_per_roll)) + >>?= fun abs_diff -> + Storage.Delegates.fold ctxt ~init:(Ok ctxt) ~f:(fun pkh ctxt_opt -> + ctxt_opt >>?= fun ctxt -> + count_rolls ctxt pkh >>=? fun rolls -> + Tez_repr.(abs_diff *? Int64.of_int rolls) >>?= fun amount -> + if decrease then Delegate.add_amount ctxt pkh amount + else Delegate.remove_amount ctxt pkh amount) diff --git a/src/proto_011_PtHangzH/lib_protocol/roll_storage.mli b/src/proto_011_PtHangzH/lib_protocol/roll_storage.mli new file mode 100644 index 000000000000..f62e72ed4523 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/roll_storage.mli @@ -0,0 +1,260 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** + Basic roll manipulation. + + The storage related to roll (i.e. `Storage.Roll`) is not used outside of + this module. And, this interface enforces the invariant that a roll is + always either in the limbo list or owned by a delegate. +*) + +type error += + | (* `Permanent *) Consume_roll_change + | (* `Permanent *) No_roll_for_delegate + | (* `Permanent *) No_roll_snapshot_for_cycle of Cycle_repr.t + | (* `Permanent *) Unregistered_delegate of Signature.Public_key_hash.t + +(** + [init ctxt] returns a new context initialized from [ctxt] where the next + roll to be allocated is the first roll, i.e. + [(Storage.Roll.Next.get ctxt) = Roll_repr.first]. + This function returns a [{!Storage_error Existing_key}] error if the context + has already been initialized. +*) +val init : Raw_context.t -> Raw_context.t tzresult Lwt.t + +(** + [init_first_cycles ctxt] computes a new context from [ctxt] where the store + has been prepared to save roll snapshots for all cycles from [0] to + [Constants.preserved_cycles + 2]: + + 1. rolls for all cycles in the interval [(0, preserved_cycles)] are frozen + (after taking a snapshot), + 2. a snapshot is taken for rolls of cycle [preserved_cycles + 1], + 3. rolls for cycle [preserved_cycles + 2] are ready for a snapshot, i.e. the + necessary storage has been prepared. +*) +val init_first_cycles : Raw_context.t -> Raw_context.t tzresult Lwt.t + +(** + [cycle_end ctxt last_cycle] returns a new context after applying the + end-of-cycle bookkeeping to [ctxt]: + + 1. clears cycle [c = (last_cycle - preserved_cycles)] if [last_cycle >= + preserved_cycles] (this amounts to deleting the only snapshot left after + the freezing of [c]), + 2. freezes snapshot rolls for the cycle + [(last_cycle + preserved_cycles + 1)] (this amounts to removing all + snapshots for the cycle, except one randomly selected for computing + baking rights), + 3. makes cycle [(last_cycle + preserved_cycles + 2)] ready for snapshot. +*) +val cycle_end : Raw_context.t -> Cycle_repr.t -> Raw_context.t tzresult Lwt.t + +(** + [snapshot_rolls ctxt] creates roll snapshots for cycle + [c = level + preserved_cycles + 2]. The returned context is such that: + + 1. the snapshot index associated to cycle [c] is incremented, + 2. the rolls' owners are copied and associated to the snapshot id + [(c,index)] (where [index] is the current snapshot index of cycle [c]), + 3. the last roll for cycle [c], and snapshot [index] is set to be the next + roll of [ctxt]. +*) +val snapshot_rolls : Raw_context.t -> Raw_context.t tzresult Lwt.t + +(** + [fold ctxt f init] folds [f] on the list of all rolls from [Roll_repr.first] + to [Storage.Next.Roll] of the context [ctxt]. Only rolls which have owners + are considered, rolls without owners are skipped. The first parameter of [f] + is a roll [r], the second parameter of [f] is the owner of [r], and the last + parameter is the initial value of the accumulator. +*) +val fold : + Raw_context.t -> + f:(Roll_repr.roll -> Signature.Public_key.t -> 'a -> 'a tzresult Lwt.t) -> + 'a -> + 'a tzresult Lwt.t + +(** + May return a [No_roll_snapshot_for_cycle] error. +*) +val baking_rights_owner : + Raw_context.t -> + Level_repr.t -> + priority:int -> + Signature.Public_key.t tzresult Lwt.t + +(** + May return a [No_roll_snapshot_for_cycle] error. +*) +val endorsement_rights_owner : + Raw_context.t -> + Level_repr.t -> + slot:int -> + Signature.Public_key.t tzresult Lwt.t + +module Delegate : sig + val is_inactive : + Raw_context.t -> Signature.Public_key_hash.t -> bool tzresult Lwt.t + + (** + [add_amount ctxt dlg am] performs the following actions: + + 1. if the delegate [dlg] is inactive, increase its change [chg] by [am], + 2. if the [dlg] is active, update [dlg]'s number of rolls [nr], and change + [chg] so that [dlg]'s number of tokens is increased by [am], and equal + to [nr * tokens_per_roll + chg], where [chg < tokens_per_roll]. + *) + val add_amount : + Raw_context.t -> + Signature.Public_key_hash.t -> + Tez_repr.t -> + Raw_context.t tzresult Lwt.t + + (** + [remove_amount ctxt dlg am] performs the following actions: + + 1. if the delegate [dlg] is inactive, decrease its change [chg] by [am], + 2. if the [dlg] is active, update [dlg]'s number of rolls [nr], and change + [chg] so that [dlg]'s number of tokens is decreased by [am], and equal to + [nr * tokens_per_roll + chg], where [chg < tokens_per_roll]. + *) + val remove_amount : + Raw_context.t -> + Signature.Public_key_hash.t -> + Tez_repr.t -> + Raw_context.t tzresult Lwt.t + + (** + [set_inactive ctxt dlg] renders delegate [dlg] inactive and performs the + following actions: + + 1. empty the list of rolls of [dlg], + 2. increase the change of [dlg] by [nr * tokens_per_roll], where [nr] is + [dlg]'s number of rolls prior to inactivation. + *) + val set_inactive : + Raw_context.t -> Signature.Public_key_hash.t -> Raw_context.t tzresult Lwt.t + + (** + If the delegate [dlg] is already active then [set_active ctxt dlg] + performs the following sequence of actions: + + 1. if the delegate is not scheduled to become inactive, then schedule the + delegate to become inactive after [(preserved_cycles * 2) + 1] cycles, + 2. if the delegate is already scheduled to become inactive at cycle [ic], + then re-schedule it to become inactive at cycle + [max ic (cc + preserved_cycles + 1)], where [cc] is the current cycle. + + If [dlg] is inactive then this function puts [dlg] in active state and + performs the following actions: + + 1. if [dlg] is not scheduled to become inactive, schedule [dlg] to become + inactive after [(preserved_cycles * 2) + 1] cycles, + 2. if the [dlg] is already scheduled to become inactive at cycle [ic], + then re-schedule it to become inactive at cycle + [max ic (cc + (preserved_cycles * 2) + 1)], where [cc] is the current + cycle, + 3. dispatch [dlg]'s change [chg] into [nr] rolls of size [tokens_per_roll] + so that the total amount managed by [dlg] is unchanged and equal to + [(nr * tokens_per_roll) + chg], where [chg < tokens_per_roll]. + *) + val set_active : + Raw_context.t -> Signature.Public_key_hash.t -> Raw_context.t tzresult Lwt.t +end + +module Contract : sig + (** + Calls [Delegate.add_amount ctxt contract am] if a delegate is associated + to [contract], or returns unchanged [ctxt] otherwise. + *) + val add_amount : + Raw_context.t -> + Contract_repr.t -> + Tez_repr.t -> + Raw_context.t tzresult Lwt.t + + (** + Calls [Delegate.remove_amount ctxt contract am] if a delegate is associated + to [contract], or returns unchanged [ctxt] otherwise. + *) + val remove_amount : + Raw_context.t -> + Contract_repr.t -> + Tez_repr.t -> + Raw_context.t tzresult Lwt.t +end + +(** + [delegate_pubkey ctxt delegate] returns the public key of + [delegate] found in context [ctxt] if there exists a registered + contract. +*) +val delegate_pubkey : + Raw_context.t -> + Signature.Public_key_hash.t -> + Signature.Public_key.t tzresult Lwt.t + +(** + [count_rolls ctxt delegate] returns the number of rolls held by + [delegate] in context [ctxt]. +*) +val count_rolls : + Raw_context.t -> Signature.Public_key_hash.t -> int tzresult Lwt.t + +(** + [get_change ctxt delegate] returns the amount of change held by + [delegate] in context [ctxt]. The change is the part of the staking + balance of a delegate that is not part of a roll, i.e., the amount + of staking balance (smaller than the value of a roll) not being + taken into account for baking rights computation. +*) +val get_change : + Raw_context.t -> Signature.Public_key_hash.t -> Tez_repr.t tzresult Lwt.t + +(** + [update_tokens_per_roll ctxt am] performs the following actions: + + 1. set the constant [tokens_per_roll] to [am], + 2. if the constant was increased by [tpram], then add the amount + [nr * tpram] to each delegate, where [nr] is the delegate's + number of rolls, + 3. if the constant was instead decreased by [tpram], then remove + the amount [nr * tpram] from all delegates. +*) +val update_tokens_per_roll : + Raw_context.t -> Tez_repr.t -> Raw_context.t tzresult Lwt.t + +(** + [get_contract_delegate ctxt contract] returns the public key hash + of the delegate whose contract is [contract] in context [ctxt]. +*) +val get_contract_delegate : + Raw_context.t -> + Contract_repr.t -> + Signature.Public_key_hash.t option tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/sapling_repr.ml b/src/proto_011_PtHangzH/lib_protocol/sapling_repr.ml new file mode 100644 index 000000000000..2b5dc17ef038 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/sapling_repr.ml @@ -0,0 +1,200 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type transaction = Sapling.UTXO.transaction + +let transaction_encoding = Sapling.UTXO.transaction_encoding + +(* The two data structures in the state are all ordered by position, a diff + contains the elements starting from an offset position up to the most recent + position. A diff can be applied to a state stored in a context to obtain a + new state. + Diffs are used by the Michelson interpreter during the evaluation of smart + contracts to keep a temporary state that may be discarded. + Diffs are also returned by an RPC to allow a client to synchronize its own + state with the chain. + *) +type diff = { + commitments_and_ciphertexts : + (Sapling.Commitment.t * Sapling.Ciphertext.t) list; + nullifiers : Sapling.Nullifier.t list; +} + +let diff_encoding = + let open Data_encoding in + conv + (fun d -> (d.commitments_and_ciphertexts, d.nullifiers)) + (fun (commitments_and_ciphertexts, nullifiers) -> + (match commitments_and_ciphertexts with + | [] -> () + | (_cm_hd, ct_hd) :: rest -> + let memo_size = Sapling.Ciphertext.get_memo_size ct_hd in + List.iter + (fun (_cm, ct) -> + assert ( + Compare.Int.(Sapling.Ciphertext.get_memo_size ct = memo_size))) + rest) ; + {commitments_and_ciphertexts; nullifiers}) + (obj2 + (req + "commitments_and_ciphertexts" + (list (tup2 Sapling.Commitment.encoding Sapling.Ciphertext.encoding))) + (req "nullifiers" (list Sapling.Nullifier.encoding))) + +module Memo_size = struct + type t = int + + let encoding = Data_encoding.uint16 + + let equal = Compare.Int.( = ) + + let max_uint16 = 0xffff + + let max_uint16_z = Z.of_int max_uint16 + + let err = + Error + ("a positive 16-bit integer (between 0 and " ^ string_of_int max_uint16 + ^ ")") + + let parse_z z = + if Compare.Z.(Z.zero <= z) && Compare.Z.(z <= max_uint16_z) then + Ok (Z.to_int z) + else err + + let unparse_to_z = Z.of_int +end + +let transaction_get_memo_size (transaction : Sapling.UTXO.transaction) = + match transaction.outputs with + | [] -> None + | {ciphertext; _} :: _ -> + (* Encoding ensures all ciphertexts have the same memo size. *) + Some (Sapling.Ciphertext.get_memo_size ciphertext) + +open Cache_memory_helpers + +(* This should be exported by [lib_sapling] rather than implemented here. *) +let input_in_memory_size = + (* type input = + * Sapling.UTXO.input = { + * cv : Sapling.CV.t; + * nf : Sapling.Nullifier.t; + * rk : Sapling.UTXO.rk; + * proof_i : Sapling.UTXO.spend_proof; + * signature : Sapling.UTXO.spend_sig; + * } *) + let cv_size = string_size_gen 32 in + let nf_size = string_size_gen 32 in + let rk_size = string_size_gen 32 in + let proof_i_size = string_size_gen @@ (48 + 96 + 48) in + let signature_size = string_size_gen 64 in + header_size +! (word_size *? 5) +! cv_size +! nf_size +! rk_size + +! proof_i_size +! signature_size + +let ciphertext_size = + (* type t = { + * cv : CV.t; + * epk : DH.epk; + * payload_enc : Bytes.t; + * nonce_enc : Crypto_box.nonce; + * payload_out : Bytes.t; + * nonce_out : Crypto_box.nonce; + * } *) + let cv_size = string_size_gen 32 in + let epk_size = string_size_gen 32 in + let nonce_enc_size = + string_size_gen 24 + (* from lib_hacl_glue/unix/hacl.ml:Nonce.size *) + in + let payload_out_size = + string_size_gen (32 + 32 + 16) + (* from lib_sapling/core.ml:Ciphertext.encoding *) + in + let nonce_out_size = string_size_gen 24 in + let fixed_payload_data_size = + 11 + 8 + 32 + 16 + 4 + (* from lib_sapling/core.ml:Ciphertext.get_memo_size *) + in + + fun memo_size -> + let payload_size = string_size_gen (memo_size + fixed_payload_data_size) in + header_size +! (word_size *? 6) +! cv_size +! epk_size +! payload_size + +! nonce_enc_size +! payload_out_size +! nonce_out_size + +let output_in_memory_size = + (* type output = { + * cm : Commitment.t; + * proof_o : output_proof; + * ciphertext : Ciphertext.t; + * } *) + let cm_size = string_size_gen 32 in + let proof_o_size = string_size_gen @@ (48 + 96 + 48) in + let ciphertext_size = ciphertext_size in + + fun memo_size -> + header_size +! (word_size *? 3) +! cm_size +! proof_o_size + +! ciphertext_size memo_size + +(** Returns an approximation of the in-memory size of a Sapling transaction. *) +let transaction_in_memory_size (transaction : Sapling.UTXO.transaction) = + (* type transaction = + * transaction = { + * inputs : Sapling.UTXO.input list; + * outputs : Sapling.UTXO.output list; + * binding_sig : Sapling.UTXO.binding_sig; + * balance : int64; + * root : Sapling.Hash.t; + * } *) + let binding_sig_size = string_size_gen 64 in + let balance_size = int64_size in + let root_size = string_size_gen 32 in + let inputs = List.length transaction.inputs in + let outputs = List.length transaction.outputs in + let memo_size = + Option.value ~default:0 (transaction_get_memo_size transaction) + in + header_size +! (word_size *? 5) + +! (list_cell_size input_in_memory_size *? inputs) + +! (list_cell_size (output_in_memory_size memo_size) *? outputs) + +! binding_sig_size +! balance_size +! root_size + +(** Returns an approximation of the in-memory size of a Sapling diff. *) +let diff_in_memory_size ({commitments_and_ciphertexts; nullifiers} : diff) = + let cms_and_cts = List.length commitments_and_ciphertexts in + let nfs = List.length nullifiers in + let cm_size = string_size_gen 32 in + let nf_size = string_size_gen 32 in + let memo_size = + (* All memo_size in a diff should be equal (see invariant enforced by + [diff] encoding above) *) + match commitments_and_ciphertexts with + | [] -> 0 + | (_, ct) :: _ -> Sapling.Ciphertext.get_memo_size ct + in + header_size +! (word_size *? 2) + +! list_cell_size (boxed_tup2 cm_size (ciphertext_size memo_size)) + *? cms_and_cts + +! (list_cell_size nf_size *? nfs) diff --git a/src/proto_011_PtHangzH/lib_protocol/sapling_services.ml b/src/proto_011_PtHangzH/lib_protocol/sapling_services.ml new file mode 100644 index 000000000000..f4940edb80fe --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/sapling_services.ml @@ -0,0 +1,103 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +let custom_root = + (RPC_path.(open_root / "context" / "sapling") + : RPC_context.t RPC_path.context) + +type diff_query = { + offset_commitment : Int64.t option; + offset_nullifier : Int64.t option; +} + +module S = struct + module Args = struct + type ('query_type, 'output_type) t = { + name : string; + description : string; + query : 'query_type RPC_query.t; + output : 'output_type Data_encoding.t; + f : context -> Sapling.Id.t -> 'query_type -> 'output_type tzresult Lwt.t; + } + + let get_diff_query : diff_query RPC_query.t = + let open RPC_query in + query (fun offset_commitment offset_nullifier -> + {offset_commitment; offset_nullifier}) + |+ opt_field + ~descr: + "Commitments and ciphertexts are returned from the specified \ + offset up to the most recent." + "offset_commitment" + RPC_arg.int64 + (fun {offset_commitment; _} -> offset_commitment) + |+ opt_field + ~descr: + "Nullifiers are returned from the specified offset up to the most \ + recent." + "offset_nullifier" + RPC_arg.int64 + (fun {offset_nullifier; _} -> offset_nullifier) + |> seal + + let encoding = + let open Data_encoding in + merge_objs (obj1 (req "root" Sapling.root_encoding)) Sapling.diff_encoding + + let get_diff = + { + name = "get_diff"; + description = + "Returns the root and a diff of a state starting from an optional \ + offset which is zero by default."; + query = get_diff_query; + output = encoding; + f = + (fun ctxt id {offset_commitment; offset_nullifier} -> + Sapling.get_diff ctxt id ?offset_commitment ?offset_nullifier ()); + } + end + + let make_service Args.{name; description; query; output; f} = + let path = RPC_path.(custom_root /: Sapling.rpc_arg / name) in + let service = RPC_service.get_service ~description ~query ~output path in + (service, fun ctxt id q () -> f ctxt id q) + + let get_diff = make_service Args.get_diff +end + +let register () = + let reg ~chunked (service, f) = + Services_registration.register1 ~chunked service f + in + reg ~chunked:false S.get_diff + +let mk_call1 (service, _f) ctxt block id q = + RPC_context.make_call1 service ctxt block id q () + +let get_diff ctxt block id ?offset_commitment ?offset_nullifier () = + mk_call1 S.get_diff ctxt block id {offset_commitment; offset_nullifier} diff --git a/src/proto_011_PtHangzH/lib_protocol/sapling_storage.ml b/src/proto_011_PtHangzH/lib_protocol/sapling_storage.ml new file mode 100644 index 000000000000..167f75f1f913 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/sapling_storage.ml @@ -0,0 +1,489 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module type COMMITMENTS = sig + val init : Raw_context.t -> Storage.Sapling.id -> Raw_context.t Lwt.t + + val default_root : Sapling.Hash.t + + val get_root : + Raw_context.t -> + Storage.Sapling.id -> + (Raw_context.t * Sapling.Hash.t) tzresult Lwt.t + + val add : + Raw_context.t -> + Storage.Sapling.id -> + Sapling.Commitment.t list -> + int64 -> + (Raw_context.t * int) tzresult Lwt.t + + val get_from : + Raw_context.t -> + Storage.Sapling.id -> + int64 -> + Sapling.Commitment.t list tzresult Lwt.t +end + +module Commitments : COMMITMENTS = struct + module H = Sapling.Hash + + (** Incremental Merkle Tree + * + * A tree of height h contains 2^h leaves and h+1 levels of nodes with + * leaves at level 0 and root at level h. + * + * The leaves are commitments and the tree it is treated as always filled + * with a default value H.uncommitted. This allows to have proofs of + * membership, or witnesses, of fixed size. + * + * All the nodes at the same level of an empty tree have the same hash, + * which can be computed from the default value of the leaves. This is + * stored in the [uncommitted] list. + * + * Any subtree filled with default values is represented by the Empty + * constructor and given its height it's possible to compute its hash + * using the [uncommitted] list. + * + * The leaves are indexed by their position [pos], ranging from 0 to + * (2^h)-1. The encoding of [pos] limits the possible size of the tree. + * In any case the only valid height for the Sapling library is 32, so even + * if the library encodes positions as uint64, they never exceed uint32. + * + * The tree is incremental in the sense that leaves cannot be modified but + * only added and exclusively in successive positions. + * + * Given that elements are added and retrieved by position, it is possible + * to use this information to efficiently navigate the tree. + * Given a tree of height [h] and a position [pos], if pos < pow2 (h-1) only + * the left subtree needs to be inspected recursively. Otherwise only the + * right needs to be visited, decreasing [pos] by [pow2 (h-1)]. + * + * In order to avoid storing the height for each subtree (or worse + * recomputing it), each function with suffix `_height` expects the height + * of the tree as parameter. These functions are only for internal use and + * are later aliased by functions using the default height of a Sapling + * incremental Merkle tree. + * + * Each node of the tree is indexed starting from the root at index 1, + * followed by its left child at index 2, right child at index 3 and so on + * until the last leaf at index 2^(depth+1)-1, or in terms of height + * 2^(32 - height +1) -1. + * The functions left and right return the index of the left and right child + * of a node. + *) + + let pow2 h = Int64.(shift_left 1L h) + + let max_height = 32 + + let max_size = pow2 max_height + + let assert_node node height = + assert ( + let first_of_height = pow2 (max_height - height) in + let first_of_next_height = Int64.shift_left first_of_height 1 in + Compare.Int64.(node >= first_of_height && node < first_of_next_height)) + + let assert_height height = + assert (Compare.Int.(height >= 0 && height <= max_height)) + + let assert_pos pos height = + assert (Compare.Int64.(pos >= 0L && pos <= pow2 height)) + + let default_root = H.uncommitted ~height:max_height + + let init = Storage.Sapling.commitments_init + + let get_root_height ctx id node height = + assert_node node height ; + assert_height height ; + Storage.Sapling.Commitments.find (ctx, id) node >|=? function + | (ctx, None) -> + let hash = H.uncommitted ~height in + (ctx, hash) + | (ctx, Some hash) -> (ctx, hash) + + let left node = Int64.mul node 2L + + let right node = Int64.(add (mul node 2L) 1L) + + (* Not tail-recursive *) + let rec split_at n l = + if Compare.Int64.(n = 0L) then ([], l) + else + match l with + | [] -> ([], l) + | x :: xs -> + let (l1, l2) = split_at Int64.(pred n) xs in + (x :: l1, l2) + + (* [insert tree height pos cms] inserts the list of commitments + [cms] in the tree [tree] of height [height] at the next position [pos]. + Returns the context, the size of the added storage, and the hash of the + node. Not tail-recursive. + Pre: incremental tree /\ + size tree + List.length cms <= pow2 height /\ + pos = size tree /\ + Post: incremental tree /\ + to_list (insert tree height pos cms) = to_list t @ cms *) + let[@coq_struct "height"] rec insert ctx id node height pos cms = + assert_node node height ; + assert_height height ; + assert_pos pos height ; + match (height, cms) with + | (_, []) -> + get_root_height ctx id node height >|=? fun (ctx, h) -> (ctx, 0, h) + | (0, [cm]) -> + let h = H.of_commitment cm in + Storage.Sapling.Commitments.init (ctx, id) node h + >|=? fun (ctx, size) -> (ctx, size, h) + | _ -> + let height = height - 1 in + (if Compare.Int64.(pos < pow2 height) then + let at = Int64.(sub (pow2 height) pos) in + let (cml, cmr) = split_at at cms in + insert ctx id (left node) height pos cml >>=? fun (ctx, size_l, hl) -> + insert ctx id (right node) height 0L cmr >|=? fun (ctx, size_r, hr) -> + (ctx, size_l + size_r, hl, hr) + else + get_root_height ctx id (left node) height >>=? fun (ctx, hl) -> + let pos = Int64.(sub pos (pow2 height)) in + insert ctx id (right node) height pos cms + >|=? fun (ctx, size_r, hr) -> (ctx, size_r, hl, hr)) + >>=? fun (ctx, size_children, hl, hr) -> + let h = H.merkle_hash ~height hl hr in + Storage.Sapling.Commitments.add (ctx, id) node h + >|=? fun (ctx, size, _existing) -> (ctx, size + size_children, h) + + let[@coq_struct "height"] rec fold_from_height ctx id node ~pos ~f ~acc height + = + assert_node node height ; + assert_height height ; + assert_pos pos height ; + Storage.Sapling.Commitments.find (ctx, id) node + (* we don't count gas for this function, it is called only by RPC *) + >>=? + function + | (_ctx, None) -> return acc + | (_ctx, Some h) -> + if Compare.Int.(height = 0) then return (f acc h) + else + let full = pow2 (height - 1) in + if Compare.Int64.(pos < full) then + fold_from_height ctx id (left node) ~pos ~f ~acc (height - 1) + >>=? fun acc -> + (* Setting pos to 0 folds on the whole right subtree *) + fold_from_height ctx id (right node) ~pos:0L ~f ~acc (height - 1) + else + let pos = Int64.(sub pos full) in + fold_from_height ctx id (right node) ~pos ~f ~acc (height - 1) + + let root_node = 1L + + let get_root ctx id = get_root_height ctx id root_node max_height + + (* Expects pos to be the next position to insert. Pos is also the number of + inserted leaves. + A commitment should always be added together with a corresponding + ciphertext in the same position. + [insert] is not tail-recursive so we put a hard limit on the size of the + list of commitments. The use of [split_at] has O(n logn) complexity that is + less relevant on a smaller list. *) + let add ctx id cms pos = + let l = List.length cms in + assert (Compare.Int.(l <= 1000)) ; + let n' = Int64.(add pos (of_int l)) in + assert (Compare.Int64.(n' <= max_size)) ; + insert ctx id root_node max_height pos cms >|=? fun (ctx, size, _h) -> + (ctx, size) + + let get_from ctx id pos = + fold_from_height + ctx + id + root_node + ~pos + ~f:(fun acc c -> H.to_commitment c :: acc) + ~acc:[] + max_height + >|=? fun l -> List.rev l +end + +module Ciphertexts = struct + let init ctx id = Storage.Sapling.ciphertexts_init ctx id + + (* a ciphertext should always be added together with a corresponding + commitment in the same position *) + let add ctx id c pos = Storage.Sapling.Ciphertexts.init (ctx, id) pos c + + let get_from ctx id offset = + let rec aux (ctx, acc) pos = + Storage.Sapling.Ciphertexts.find (ctx, id) pos >>=? fun (ctx, c) -> + match c with + | None -> return (ctx, List.rev acc) + | Some c -> aux (ctx, c :: acc) (Int64.succ pos) + in + aux (ctx, []) offset +end + +(* Collection of nullifiers w/o duplicates, append-only. It has a dual + implementation with a hash map for constant `mem` and with a ordered set to + retrieve by position. *) +module Nullifiers = struct + let init = Storage.Sapling.nullifiers_init + + let size ctx id = Storage.Sapling.Nullifiers_size.get (ctx, id) + + let mem ctx id nf = Storage.Sapling.Nullifiers_hashed.mem (ctx, id) nf + + (* Allows for duplicates as they are already checked by verify_update before + updating the state. + Not tail-recursive so we put a hard limit on the size of the + list of nullifiers. *) + let add ctx id nfs = + assert (Compare.Int.(List.compare_length_with nfs 1000 <= 0)) ; + size ctx id >>=? fun nf_start_pos -> + List.fold_right_es + (fun nf (ctx, pos, acc_size) -> + Storage.Sapling.Nullifiers_hashed.init (ctx, id) nf + >>=? fun (ctx, size) -> + Storage.Sapling.Nullifiers_ordered.init (ctx, id) pos nf >|=? fun ctx -> + (ctx, Int64.succ pos, Z.add acc_size (Z.of_int size))) + nfs + (ctx, nf_start_pos, Z.zero) + >>=? fun (ctx, nf_end_pos, size) -> + Storage.Sapling.Nullifiers_size.update (ctx, id) nf_end_pos >|=? fun ctx -> + (ctx, size) + + let get_from ctx id offset = + let[@coq_struct "pos"] rec aux acc pos = + Storage.Sapling.Nullifiers_ordered.find (ctx, id) pos >>=? function + | None -> return @@ List.rev acc + | Some c -> aux (c :: acc) (Int64.succ pos) + in + aux [] offset +end + +(** Bounded queue of roots. The full size is initialized with the default + uncommitted root, that's why roots storage doesn't need to be carbonated. + A maximum of one new root is added per protocol level. + If multiple transactions for the same shielded pool are processed during the + same contract call or several calls in the same block, only the last root + will be stored. + This property prevents transactions in the same block from depending on each + other and guarantees that a transaction will be valid for a least two hours + (hence the 120 size) after being forged. *) +module Roots = struct + let size = 120l + + (* pos is the index of the last inserted element *) + + let get ctx id = + Storage.Sapling.Roots_pos.get (ctx, id) >>=? fun pos -> + Storage.Sapling.Roots.get (ctx, id) pos + + let init ctx id = + let[@coq_struct "pos"] rec aux ctx pos = + if Compare.Int32.(pos < 0l) then return ctx + else + Storage.Sapling.Roots.init (ctx, id) pos Commitments.default_root + >>=? fun ctx -> aux ctx (Int32.pred pos) + in + aux ctx (Int32.pred size) >>=? fun ctx -> + Storage.Sapling.Roots_pos.init (ctx, id) 0l >>=? fun ctx -> + let level = (Raw_context.current_level ctx).level in + Storage.Sapling.Roots_level.init (ctx, id) level + + let mem ctx id root = + Storage.Sapling.Roots_pos.get (ctx, id) >>=? fun start_pos -> + let rec aux pos = + Storage.Sapling.Roots.get (ctx, id) pos >>=? fun hash -> + if Compare.Int.(Sapling.Hash.compare hash root = 0) then return true + else + let pos = Int32.(pred pos) in + let pos = if Compare.Int32.(pos < 0l) then Int32.pred size else pos in + if Compare.Int32.(pos = start_pos) then return false else aux pos + in + aux start_pos + + (* allows duplicates *) + let add ctx id root = + Storage.Sapling.Roots_pos.get (ctx, id) >>=? fun pos -> + let level = (Raw_context.current_level ctx).level in + Storage.Sapling.Roots_level.get (ctx, id) >>=? fun stored_level -> + if Raw_level_repr.(stored_level = level) then + (* if there is another add during the same level, it will over-write on + the same position *) + Storage.Sapling.Roots.add (ctx, id) pos root >|= ok + else + (* it's the first add for this level *) + (* TODO(samoht): why is it using [update] and not [init] then? *) + Storage.Sapling.Roots_level.update (ctx, id) level >>=? fun ctx -> + let pos = Int32.rem (Int32.succ pos) size in + Storage.Sapling.Roots_pos.update (ctx, id) pos >>=? fun ctx -> + Storage.Sapling.Roots.add (ctx, id) pos root >|= ok +end + +(** This type links the permanent state stored in the context at the specified + id together with the ephemeral diff managed by the Michelson + interpreter. After a successful execution the diff can be applied to update + the state at id. The first time a state is created its id is None, one will + be assigned after the first application. *) +type state = { + id : Lazy_storage_kind.Sapling_state.Id.t option; + diff : Sapling_repr.diff; + memo_size : Sapling_repr.Memo_size.t; +} + +let empty_diff = + Sapling_repr.{commitments_and_ciphertexts = []; nullifiers = []} + +let empty_state ?id ~memo_size () = {id; diff = empty_diff; memo_size} + +(** Returns a state from an existing id. *) +let state_from_id ctxt id = + Storage.Sapling.Memo_size.get (ctxt, id) >|=? fun memo_size -> + ({id = Some id; diff = empty_diff; memo_size}, ctxt) + +let rpc_arg = Storage.Sapling.rpc_arg + +let get_memo_size ctx id = Storage.Sapling.Memo_size.get (ctx, id) + +let init ctx id ~memo_size = + Storage.Sapling.Memo_size.add (ctx, id) memo_size >>= fun ctx -> + Storage.Sapling.Commitments_size.add (ctx, id) Int64.zero >>= fun ctx -> + Commitments.init ctx id >>= fun ctx -> + Nullifiers.init ctx id >>= fun ctx -> + Roots.init ctx id >>=? fun ctx -> Ciphertexts.init ctx id >|= ok + +(* Gas costs for apply_diff. *) +let sapling_apply_diff_cost ~inputs ~outputs = + let open Saturation_repr in + add + (safe_int 1_300_000) + (add + (scale_fast (mul_safe_of_int_exn 5_000) (safe_int inputs)) + (scale_fast (mul_safe_of_int_exn 55_000) (safe_int outputs))) + +(** Applies a diff to a state id stored in the context. Updates Commitments, + Ciphertexts and Nullifiers using the diff and updates the Roots using the + new Commitments tree. *) +let apply_diff ctx id diff = + let open Sapling_repr in + let nb_commitments = List.length diff.commitments_and_ciphertexts in + let nb_nullifiers = List.length diff.nullifiers in + let sapling_cost = + sapling_apply_diff_cost ~inputs:nb_nullifiers ~outputs:nb_commitments + in + Raw_context.consume_gas ctx sapling_cost >>?= fun ctx -> + Storage.Sapling.Commitments_size.get (ctx, id) >>=? fun cm_start_pos -> + let cms = List.rev_map fst diff.commitments_and_ciphertexts in + Commitments.add ctx id cms cm_start_pos >>=? fun (ctx, size) -> + Storage.Sapling.Commitments_size.update + (ctx, id) + (Int64.add cm_start_pos (Int64.of_int nb_commitments)) + >>=? fun ctx -> + List.fold_right_es + (fun (_cm, cp) (ctx, pos, acc_size) -> + Ciphertexts.add ctx id cp pos >|=? fun (ctx, size) -> + (ctx, Int64.succ pos, Z.add acc_size (Z.of_int size))) + diff.commitments_and_ciphertexts + (ctx, cm_start_pos, Z.of_int size) + >>=? fun (ctx, _ct_end_pos, size) -> + Nullifiers.add ctx id diff.nullifiers >>=? fun (ctx, size_nf) -> + let size = Z.add size size_nf in + match diff.commitments_and_ciphertexts with + | [] -> + (* avoids adding duplicates to Roots *) + return (ctx, size) + | _ :: _ -> + Commitments.get_root ctx id >>=? fun (ctx, root) -> + Roots.add ctx id root >|=? fun ctx -> (ctx, size) + +let add {id; diff; memo_size} cm_cipher_list = + assert ( + List.for_all + (fun (_cm, cipher) -> + Compare.Int.(Sapling.Ciphertext.get_memo_size cipher = memo_size)) + cm_cipher_list) ; + { + id; + diff = + { + diff with + commitments_and_ciphertexts = + List.rev cm_cipher_list @ diff.commitments_and_ciphertexts; + }; + memo_size; + } + +let root_mem ctx {id; _} tested_root = + match id with + | Some id -> Roots.mem ctx id tested_root + | None -> + return + Compare.Int.( + Sapling.Hash.compare tested_root Commitments.default_root = 0) + +(* to avoid a double spend we need to check the disk AND the diff *) +let nullifiers_mem ctx {id; diff; _} nf = + let exists_in_diff = + List.exists + (fun v -> Compare.Int.(Sapling.Nullifier.compare nf v = 0)) + diff.nullifiers + in + if exists_in_diff then return (ctx, true) + else + match id with + | None -> return (ctx, false) + | Some id -> Nullifiers.mem ctx id nf + +(* Allows for duplicates as they are already checked by verify_update before + updating the state. *) +let nullifiers_add {id; diff; memo_size} nf = + {id; diff = {diff with nullifiers = nf :: diff.nullifiers}; memo_size} + +type root = Sapling.Hash.t + +let root_encoding = Sapling.Hash.encoding + +let get_diff ctx id ?(offset_commitment = 0L) ?(offset_nullifier = 0L) () = + if + not + Sapling.Commitment.( + valid_position offset_commitment && valid_position offset_nullifier) + then failwith "Invalid argument." + else + Commitments.get_from ctx id offset_commitment >>=? fun commitments -> + Roots.get ctx id >>=? fun root -> + Nullifiers.get_from ctx id offset_nullifier >>=? fun nullifiers -> + Ciphertexts.get_from ctx id offset_commitment + (* we don't count gas for RPCs *) + >|=? fun (_ctx, ciphertexts) -> + match List.combine ~when_different_lengths:() commitments ciphertexts with + | Error () -> failwith "Invalid argument." + | Ok commitments_and_ciphertexts -> + (root, Sapling_repr.{commitments_and_ciphertexts; nullifiers}) diff --git a/src/proto_011_PtHangzH/lib_protocol/sapling_validator.ml b/src/proto_011_PtHangzH/lib_protocol/sapling_validator.ml new file mode 100644 index 000000000000..ce0e41e0133c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/sapling_validator.ml @@ -0,0 +1,108 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Check that each nullifier is not already present in the state and add it. + Important to avoid spending the same input twice in a transaction. *) +let rec check_and_update_nullifiers ctxt state inputs = + match inputs with + | [] -> return (ctxt, Some state) + | input :: inputs -> ( + Sapling_storage.nullifiers_mem ctxt state Sapling.UTXO.(input.nf) + >>=? function + | (ctxt, true) -> return (ctxt, None) + | (ctxt, false) -> + let state = + Sapling_storage.nullifiers_add state Sapling.UTXO.(input.nf) + in + check_and_update_nullifiers ctxt state inputs) + +let verify_update : + Raw_context.t -> + Sapling_storage.state -> + Sapling_repr.transaction -> + string -> + (Raw_context.t * (Int64.t * Sapling_storage.state) option) tzresult Lwt.t = + fun ctxt state transaction key -> + (* Check the transaction *) + (* To avoid overflowing the balance, the number of inputs and outputs must be + bounded. + Ciphertexts' memo_size must match the state's memo_size. + These constraints are already enforced at the encoding level. *) + assert (Compare.Int.(List.compare_length_with transaction.inputs 5208 <= 0)) ; + assert (Compare.Int.(List.compare_length_with transaction.outputs 2019 <= 0)) ; + let pass = + List.for_all + (fun output -> + Compare.Int.( + Sapling.Ciphertext.get_memo_size Sapling.UTXO.(output.ciphertext) + = state.memo_size)) + transaction.outputs + in + if not pass then return (ctxt, None) + else + (* Check the root is a recent state *) + Sapling_storage.root_mem ctxt state transaction.root >>=? fun pass -> + if not pass then return (ctxt, None) + else + check_and_update_nullifiers ctxt state transaction.inputs >|=? function + | (ctxt, None) -> (ctxt, None) + | (ctxt, Some state) -> + Sapling.Verification.with_verification_ctx (fun vctx -> + let pass = + (* Check all the output ZK proofs *) + List.for_all + (fun output -> Sapling.Verification.check_output vctx output) + transaction.outputs + in + if not pass then (ctxt, None) + else + let pass = + (* Check all the input Zk proofs and signatures *) + List.for_all + (fun input -> + Sapling.Verification.check_spend + vctx + input + transaction.root + key) + transaction.inputs + in + if not pass then (ctxt, None) + else + let pass = + (* Check the signature and balance of the whole transaction *) + Sapling.Verification.final_check vctx transaction key + in + if not pass then (ctxt, None) + else + (* update tree *) + let list_to_add = + List.map + (fun output -> + Sapling.UTXO.(output.cm, output.ciphertext)) + transaction.outputs + in + let state = Sapling_storage.add state list_to_add in + (ctxt, Some (transaction.balance, state))) diff --git a/src/proto_011_PtHangzH/lib_protocol/saturation_repr.ml b/src/proto_011_PtHangzH/lib_protocol/saturation_repr.ml new file mode 100644 index 000000000000..abdbb379d3e2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/saturation_repr.ml @@ -0,0 +1,170 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* let () = assert (Sys.int_size = 63) *) + +type _ t = int + +type mul_safe + +type may_saturate + +let may_saturate : _ t -> may_saturate t = fun x -> x + +let to_int x = x + +let ( < ) : _ t -> _ t -> bool = Compare.Int.( < ) + +let ( <= ) : _ t -> _ t -> bool = Compare.Int.( <= ) + +let ( > ) : _ t -> _ t -> bool = Compare.Int.( > ) + +let ( >= ) : _ t -> _ t -> bool = Compare.Int.( >= ) + +let ( = ) : _ t -> _ t -> bool = Compare.Int.( = ) + +let equal = ( = ) + +let ( <> ) : _ t -> _ t -> bool = Compare.Int.( <> ) + +let max : _ t -> _ t -> _ t = fun x y -> if x >= y then x else y + +let min : _ t -> _ t -> _ t = fun x y -> if x >= y then y else x + +let compare : _ t -> _ t -> _ t = Compare.Int.compare + +let saturated = max_int + +let of_int_opt t = if t >= 0 && t < saturated then Some t else None + +let of_z_opt z = + match Z.to_int z with int -> of_int_opt int | exception Z.Overflow -> None + +let to_z x = Z.of_int x + +let saturate_if_undef = function None -> saturated | Some x -> x + +let safe_int x = of_int_opt x |> saturate_if_undef + +let numbits x = + let x = ref x and n = ref 0 in + (let y = !x lsr 32 in + if y <> 0 then ( + n := !n + 32 ; + x := y)) ; + (let y = !x lsr 16 in + if y <> 0 then ( + n := !n + 16 ; + x := y)) ; + (let y = !x lsr 8 in + if y <> 0 then ( + n := !n + 8 ; + x := y)) ; + (let y = !x lsr 4 in + if y <> 0 then ( + n := !n + 4 ; + x := y)) ; + (let y = !x lsr 2 in + if y <> 0 then ( + n := !n + 2 ; + x := y)) ; + if !x lsr 1 <> 0 then !n + 2 else !n + !x + +let zero = 0 + +let one = 1 + +let small_enough z = + (* The following literal triggers an error if compiled under 32-bit + architectures, please do not modify it. This is a static way to + ensure that this file is compiled under a 64-bit architecture. *) + z land 0x7fffffff80000000 = 0 + +let mul_safe x = if small_enough x then Some x else None + +let mul_safe_exn x = + if small_enough x then x + else failwith (Format.sprintf "mul_safe_exn: %d must be below 2147483648" x) + +let mul_safe_of_int_exn x = + Option.bind (of_int_opt x) mul_safe |> function + | None -> + failwith + (Format.sprintf "mul_safe_of_int_exn: %d must be below 2147483648" x) + | Some x -> x + +(* If [x] is positive, shifting to the right will produce a number + which is positive and is less than [x]. *) +let shift_right x y = (x :> int) lsr y + +let shift_left x y = + if shift_right saturated y < x then saturated else (x :> int) lsl y + +let mul x y = + (* assert (x >= 0 && y >= 0); *) + match x with + | 0 -> 0 + | x -> + if small_enough x && small_enough y then x * y + else if Compare.Int.(y > saturated / x) then saturated + else x * y + +let mul_fast x y = x * y + +let scale_fast x y = + if x = 0 then 0 + else if small_enough y then x * y + else if Compare.Int.(y > saturated / x) then saturated + else x * y + +let add x y = + let z = x + y in + if Compare.Int.(z >= 0) then z else saturated + +let succ x = add one x + +let sub x y = Compare.Int.max (x - y) 0 + +let sub_opt x y = + let s = x - y in + if Compare.Int.(s >= 0) then Some s else None + +(* Notice that Z.erem does not behave as mod on negative numbers. + Fortunately, the inhabitant of [t] are non-negative. *) +let erem x y = x mod y + +let ediv x y = x / y + +let t_to_z_exn z = + match of_z_opt z with + | None -> + (* since the encoding is applied to values of type [t]. *) assert false + | Some x -> x + +let z_encoding = Data_encoding.(check_size 9 (conv to_z t_to_z_exn z)) + +let n_encoding = Data_encoding.(check_size 9 (conv to_z t_to_z_exn n)) + +let pp fmt x = Format.pp_print_int fmt x diff --git a/src/proto_011_PtHangzH/lib_protocol/saturation_repr.mli b/src/proto_011_PtHangzH/lib_protocol/saturation_repr.mli new file mode 100644 index 000000000000..d937abc29813 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/saturation_repr.mli @@ -0,0 +1,204 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs, *) +(* *) +(* 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 saturated arithmetic between 0 and 2^62 - 1. + + This means that the arithmetic operations provided by this module + do not overflow. If an operation would produce an integer [x] + greater than [2 ^ 62 - 1], it is [saturated] to this + value. Similarly, if an operation would produce a negative integer, + it outputs [zero] instead. + + This saturation arithmetic is used to monitor gas levels. While the + gas model can produce values beyond 2^62 - 1, there is no point in + distinguishing these values from 2^62 - 1 because the amount of gas + available is significantly lower than this limit. + + Notice that most saturation arithmetic operations do not behave + as their standard counterparts when one of their operands is + saturated. For instance, + + (saturated + saturated) - saturated = 0 + + For more information about saturation arithmetic, take a look at: + + https://en.wikipedia.org/wiki/Saturation_arithmetic + +*) + +(** An integer of type ['a t] is between [0] and [saturated]. + + The type parameter ['a] is [mul_safe] if the integer is known + not to overflow when multiplied with another [mul_safe t]. + + The type parameter ['a] is [may_saturate] if the integer is + not known to be sufficiently small to prevent overflow during + multiplication. + +*) +type 'a t = private int + +type mul_safe + +type may_saturate + +val may_saturate : _ t -> may_saturate t + +(** [to_int x] returns the underlying integer representing [x]. *) +val to_int : 'a t -> int + +(** 0 *) +val zero : _ t + +(** 1 *) +val one : _ t + +(** 2^62 - 1 *) +val saturated : may_saturate t + +(** We inherit the order over native integers. *) +val ( >= ) : _ t -> _ t -> bool + +val ( > ) : _ t -> _ t -> bool + +val ( <= ) : _ t -> _ t -> bool + +val ( < ) : _ t -> _ t -> bool + +val ( = ) : _ t -> _ t -> bool + +val ( <> ) : _ t -> _ t -> bool + +val equal : _ t -> _ t -> bool + +val min : 'a t -> 'a t -> 'a t + +val max : 'a t -> 'a t -> 'a t + +val compare : 'a t -> 'b t -> int + +(** [numbits x] returns the number of bits used in the binary representation + of [x]. *) +val numbits : 'a t -> int + +(** [shift_right x y] behaves like a logical shift of [x] by [y] bits + to the right. [y] must be between 0 and 63. *) +val shift_right : 'a t -> int -> 'a t + +(** [shift_left x y] behaves like a logical shift of [x] by [y] bits + to the left. [y] must be between 0 and 63. In cases where [x lsl y] + is overflowing, [shift_left x y] is [saturated]. *) +val shift_left : 'a t -> int -> 'a t + +(** [mul x y] behaves like multiplication between native integers as + long as its result stay below [saturated]. Otherwise, [mul] returns + [saturated]. *) +val mul : _ t -> _ t -> may_saturate t + +(** [mul_safe x] returns a [mul_safe t] only if [x] does not trigger + overflows when multiplied with another [mul_safe t]. More precisely, + [x] is safe for fast multiplications if [x < 2147483648]. *) +val mul_safe : _ t -> mul_safe t option + +(** [mul_fast x y] exploits the fact that [x] and [y] are known not to + provoke overflows during multiplication to perform a mere + multiplication. *) +val mul_fast : mul_safe t -> mul_safe t -> may_saturate t + +(** [scale_fast x y] exploits the fact that [x] is known not to + provoke overflows during multiplication to perform a + multiplication faster than [mul]. *) +val scale_fast : mul_safe t -> _ t -> may_saturate t + +(** [add x y] behaves like addition between native integers as long as + its result stay below [saturated]. Otherwise, [add] returns + [saturated]. *) +val add : _ t -> _ t -> may_saturate t + +(** [succ x] is like [add one x] *) +val succ : _ t -> may_saturate t + +(** [sub x y] behaves like subtraction between native integers as long + as its result stay positive. Otherwise, [sub] returns [zero]. + This function assumes that [x] is not saturated. +*) +val sub : 'a t -> _ t -> 'a t + +(** [sub_opt x y] behaves like subtraction between native integers as + long as its result stay positive. Otherwise, [sub] returns + [None]. *) +val sub_opt : 'a t -> _ t -> 'a t option + +(** [ediv x y] returns [x / y]. This operation never saturates, hence + it is exactly the same as its native counterpart. [y] is supposed + to be strictly greater than 0, otherwise this function raises + [Division_by_zero]. *) +val ediv : 'a t -> _ t -> 'a t + +(** [erem x y] returns [x mod y]. [y] is supposed to be strictly + greater than 0, otherwise this function raises + [Division_by_zero]. *) +val erem : _ t -> 'b t -> 'b t + +(** [of_int_opt x] returns [Some x] if [x >= 0] and [x < saturated], + and [None] otherwise. *) +val of_int_opt : int -> may_saturate t option + +(** [of_z_opt x] returns [Some x] if [x >= 0] and [x < saturated], + and [None] otherwise. *) +val of_z_opt : Z.t -> may_saturate t option + +(** When a saturated integer is sufficiently small (i.e. strictly less + than 2147483648), we can assign it the type [mul_safe S.t] to use + it within fast multiplications, named [S.scale_fast] and + [S.mul_fast]. + + The following function allows such type assignment but may raise an + exception if the assumption is wrong. Therefore, [mul_safe_exn] + should only be used to define toplevel values, so that these + exceptions can only occur during startup. + *) +val mul_safe_exn : may_saturate t -> mul_safe t + +(** [mul_safe_of_int_exn x] is the composition of [of_int_opt] and + [mul_safe] in the option monad. This function raises [Invalid_argument] + if [x] is not safe. This function should be used on integer literals + that are obviously [mul_safe]. *) +val mul_safe_of_int_exn : int -> mul_safe t + +(** [safe_int x] is [of_int_opt x |> saturate_if_undef]. *) +val safe_int : int -> may_saturate t + +(** [to_z z] is [Z.of_int]. *) +val to_z : _ t -> Z.t + +(** Encoding for [t] through the encoding for [z] integers. *) +val z_encoding : _ t Data_encoding.t + +(** Encoding for [t] through the encoding for non-negative integers. *) +val n_encoding : _ t Data_encoding.t + +(** A pretty-printer for native integers. *) +val pp : Format.formatter -> _ t -> unit diff --git a/src/proto_011_PtHangzH/lib_protocol/script_cache.ml b/src/proto_011_PtHangzH/lib_protocol/script_cache.ml new file mode 100644 index 000000000000..a2a54f145420 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_cache.ml @@ -0,0 +1,109 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +type identifier = string + +let identifier_of_contract addr = Contract.to_b58check addr + +let contract_of_identifier identifier = Contract.of_b58check identifier + +type cached_contract = Script.t * Script_ir_translator.ex_script + +let load_and_elaborate ctxt addr = + Contract.get_script ctxt addr >>=? fun (ctxt, script) -> + match script with + | None -> return (ctxt, None) + | Some script -> + Script_ir_translator.( + parse_script ctxt script ~legacy:true ~allow_forged_in_storage:true + >>=? fun (ex_script, ctxt) -> + (* We consume gas after the fact in order to not have to instrument + [script_size] (for efficiency). + This is safe, as we already pay gas proportional to storage size + in [parse_script] beforehand. *) + let (size, cost) = script_size ex_script in + Gas.consume ctxt cost >>?= fun ctxt -> + return (ctxt, Some (script, ex_script, size))) + +module Client = struct + type cached_value = cached_contract + + let namespace = "contract" + + let cache_index = 0 + + let value_of_identifier ctxt identifier = + (* + + I/O, deserialization, and elaboration of contracts scripts + are cached. + + *) + contract_of_identifier identifier >>?= fun addr -> + load_and_elaborate ctxt addr >>=? function + | (_, None) -> + (* [value_of_identifier ctxt k] is applied to identifiers stored + in the cache. Only script-based contracts that have been + executed are in the cache. Hence, [get_script] always + succeeds for these identifiers if [ctxt] and the [cache] are + properly synchronized by the shell. *) + failwith "Script_cache: Inconsistent script cache." + | (_, Some (unparsed_script, ir_script, _)) -> + return (unparsed_script, ir_script) +end + +module Cache = (val Cache.register_exn (module Client)) + +let find ctxt addr = + let identifier = identifier_of_contract addr in + Cache.find ctxt identifier >>=? function + | Some (unparsed_script, ex_script) -> + return (ctxt, identifier, Some (unparsed_script, ex_script)) + | None -> ( + load_and_elaborate ctxt addr >>=? function + | (ctxt, None) -> return (ctxt, identifier, None) + | (ctxt, Some (unparsed_script, script_ir, size)) -> + let cached_value = (unparsed_script, script_ir) in + Lwt.return + ( Cache.update ctxt identifier (Some (cached_value, size)) + >>? fun ctxt -> + ok (ctxt, identifier, Some (unparsed_script, script_ir)) )) + +let update ctxt identifier updated_script approx_size = + Cache.update ctxt identifier (Some (updated_script, approx_size)) + +let entries ctxt = + Cache.list_identifiers ctxt + |> List.map_e @@ fun (identifier, age) -> + contract_of_identifier identifier >|? fun contract -> (contract, age) + +let contract_rank ctxt addr = + Cache.identifier_rank ctxt (identifier_of_contract addr) + +let size = Cache.size + +let size_limit = Cache.size_limit diff --git a/src/proto_011_PtHangzH/lib_protocol/script_cache.mli b/src/proto_011_PtHangzH/lib_protocol/script_cache.mli new file mode 100644 index 000000000000..641bad38e99a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_cache.mli @@ -0,0 +1,81 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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 manages the cache for smart contracts. + + This cache must be consistent with the on-disk representation + of the smart contracts. In particular, [update] must be called + each time a contract storage is updated. + +*) + +open Alpha_context + +(** Each cached script has a unique identifier in the cache. *) +type identifier + +(** The cache holds the unparsed and the internal representation of + the contract. *) +type cached_contract = Script.t * Script_ir_translator.ex_script + +(** [find ctxt contract] returns [(ctxt', identifier, script)] where: + - [ctxt'] is [ctxt] with less gas; + - [identifier] is the identifier identifying the [contract] in the cache; + - [script = None] if there is no such contract in [ctxt]; + - [script = Some (unparsed_script, ir_script)] where + - [unparsed_script] is the contract source code and storage; + - [script_ir] is a typed internal representation of the contract, i.e., + the abstract syntax tree of its code as well as its storage. + + This function consumes gas depending on the cache. If the contract is not + in the cache, then the function also consumes the gas of [Contract.get_script] + and [Script_ir_translator.parse_script]. *) +val find : + context -> + Contract.t -> + (context * identifier * cached_contract option) tzresult Lwt.t + +(** [update ctxt identifier unparsed_script ir_script size] refreshes the + cached contract identified by [identifier] with a new [unparsed_script], + a new [ir_script], and a new size. *) +val update : context -> identifier -> cached_contract -> int -> context tzresult + +(** [entries ctxt] returns the contracts in the cache as well as their + respective size. The list is sorted by date of last modification: + the least recently updated entry comes first. *) +val entries : context -> (Contract.t * int) list tzresult + +(** [contract_rank ctxt contract] returns the number of contracts + older than [contract] in the cache of [ctxt]. This function + returns [None] if [contract] does not exist in the cache of + [ctxt]. *) +val contract_rank : context -> Contract.t -> int option + +(** [size ctxt] is an overapproximation of the cache size in + memory (in bytes). *) +val size : context -> int + +(** [size_limit ctxt] is the maximal size of the cache (in bytes). *) +val size_limit : context -> int diff --git a/src/proto_011_PtHangzH/lib_protocol/script_comparable.ml b/src/proto_011_PtHangzH/lib_protocol/script_comparable.ml new file mode 100644 index 000000000000..ab542f4867f3 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_comparable.ml @@ -0,0 +1,89 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Script_typed_ir + +let compare_address (x, ex) (y, ey) = + let lres = Contract.compare x y in + if Compare.Int.(lres = 0) then Compare.String.compare ex ey else lres + +type compare_comparable_cont = + | Compare_comparable : + 'a comparable_ty * 'a * 'a * compare_comparable_cont + -> compare_comparable_cont + | Compare_comparable_return : compare_comparable_cont + +let compare_comparable : type a. a comparable_ty -> a -> a -> int = + let rec compare_comparable : + type a. a comparable_ty -> compare_comparable_cont -> a -> a -> int = + fun kind k x y -> + match (kind, x, y) with + | (Unit_key _, (), ()) -> (apply [@tailcall]) 0 k + | (Never_key _, _, _) -> . + | (Signature_key _, x, y) -> (apply [@tailcall]) (Signature.compare x y) k + | (String_key _, x, y) -> (apply [@tailcall]) (Script_string.compare x y) k + | (Bool_key _, x, y) -> (apply [@tailcall]) (Compare.Bool.compare x y) k + | (Mutez_key _, x, y) -> (apply [@tailcall]) (Tez.compare x y) k + | (Key_hash_key _, x, y) -> + (apply [@tailcall]) (Signature.Public_key_hash.compare x y) k + | (Key_key _, x, y) -> + (apply [@tailcall]) (Signature.Public_key.compare x y) k + | (Int_key _, x, y) -> (apply [@tailcall]) (Script_int.compare x y) k + | (Nat_key _, x, y) -> (apply [@tailcall]) (Script_int.compare x y) k + | (Timestamp_key _, x, y) -> + (apply [@tailcall]) (Script_timestamp.compare x y) k + | (Address_key _, x, y) -> (apply [@tailcall]) (compare_address x y) k + | (Bytes_key _, x, y) -> (apply [@tailcall]) (Compare.Bytes.compare x y) k + | (Chain_id_key _, x, y) -> (apply [@tailcall]) (Chain_id.compare x y) k + | (Pair_key ((tl, _), (tr, _), _), (lx, rx), (ly, ry)) -> + (compare_comparable [@tailcall]) + tl + (Compare_comparable (tr, rx, ry, k)) + lx + ly + | (Union_key ((tl, _), _, _), L x, L y) -> + (compare_comparable [@tailcall]) tl k x y + | (Union_key _, L _, R _) -> -1 + | (Union_key _, R _, L _) -> 1 + | (Union_key (_, (tr, _), _), R x, R y) -> + (compare_comparable [@tailcall]) tr k x y + | (Option_key _, None, None) -> (apply [@tailcall]) 0 k + | (Option_key _, None, Some _) -> -1 + | (Option_key _, Some _, None) -> 1 + | (Option_key (t, _), Some x, Some y) -> + (compare_comparable [@tailcall]) t k x y + and apply ret k = + match (ret, k) with + | (0, Compare_comparable (ty, x, y, k)) -> + (compare_comparable [@tailcall]) ty k x y + | (0, Compare_comparable_return) -> 0 + | (ret, _) -> + (* ret <> 0, we perform an early exit *) + if Compare.Int.(ret > 0) then 1 else -1 + in + fun t -> compare_comparable t Compare_comparable_return + [@@coq_axiom_with_reason "non top-level mutually recursive function"] diff --git a/src/proto_011_PtHangzH/lib_protocol/script_comparable.mli b/src/proto_011_PtHangzH/lib_protocol/script_comparable.mli new file mode 100644 index 000000000000..8f489511625a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_comparable.mli @@ -0,0 +1,29 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val compare_comparable : 'a Script_typed_ir.comparable_ty -> 'a -> 'a -> int + +val compare_address : Script_typed_ir.address -> Script_typed_ir.address -> int diff --git a/src/proto_011_PtHangzH/lib_protocol/script_expr_hash.ml b/src/proto_011_PtHangzH/lib_protocol/script_expr_hash.ml new file mode 100644 index 000000000000..4b26c6d4234d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_expr_hash.ml @@ -0,0 +1,44 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let script_expr_hash = "\013\044\064\027" (* expr(54) *) + +module H = + Blake2B.Make + (Base58) + (struct + let name = "script_expr" + + let title = "A script expression ID" + + let b58check_prefix = script_expr_hash + + let size = None + end) + +include H +include Path_encoding.Make_hex (H) + +let () = Base58.check_encoded_prefix b58check_encoding "expr" 54 diff --git a/src/proto_011_PtHangzH/lib_protocol/script_expr_hash.mli b/src/proto_011_PtHangzH/lib_protocol/script_expr_hash.mli new file mode 100644 index 000000000000..8ba38e2eaaf5 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_expr_hash.mli @@ -0,0 +1,31 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** A specialized Blake2B implementation for hashing Michelson expressions. *) + +include S.HASH + +include Path_encoding.S with type t := t diff --git a/src/proto_011_PtHangzH/lib_protocol/script_int_repr.ml b/src/proto_011_PtHangzH/lib_protocol/script_int_repr.ml new file mode 100644 index 000000000000..ee2c04408bfe --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_int_repr.ml @@ -0,0 +1,104 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type n = Natural_tag + +type z = Integer_tag + +type 't num = Z.t + +let compare x y = Z.compare x y + +let zero = Z.zero + +let zero_n = Z.zero + +let one_n = Z.one + +let to_string x = Z.to_string x + +let of_string s = Option.catch (fun () -> Z.of_string s) + +let of_int32 n = Z.of_int64 @@ Int64.of_int32 n + +let to_int64 x = Option.catch (fun () -> Z.to_int64 x) + +let of_int64 n = Z.of_int64 n + +let to_int x = Option.catch (fun () -> Z.to_int x) + +let of_int n = Z.of_int n + +let of_zint x = x + +let to_zint x = x + +let add x y = Z.add x y + +let sub x y = Z.sub x y + +let mul x y = Z.mul x y + +let ediv x y = Option.catch (fun () -> Z.ediv_rem x y) + +let add_n = add + +let succ_n = Z.succ + +let mul_n = mul + +let ediv_n = ediv + +let abs x = Z.abs x + +let is_nat x = if Compare.Z.(x < Z.zero) then None else Some x + +let neg x = Z.neg x + +let int x = x + +let shift_left x y = + if Compare.Int.(Z.compare y (Z.of_int 256) > 0) then None + else + let y = Z.to_int y in + Some (Z.shift_left x y) + +let shift_right x y = + if Compare.Int.(Z.compare y (Z.of_int 256) > 0) then None + else + let y = Z.to_int y in + Some (Z.shift_right x y) + +let shift_left_n = shift_left + +let shift_right_n = shift_right + +let logor x y = Z.logor x y + +let logxor x y = Z.logxor x y + +let logand x y = Z.logand x y + +let lognot x = Z.lognot x diff --git a/src/proto_011_PtHangzH/lib_protocol/script_int_repr.mli b/src/proto_011_PtHangzH/lib_protocol/script_int_repr.mli new file mode 100644 index 000000000000..f608cd6d50e9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_int_repr.mli @@ -0,0 +1,155 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** The types for arbitrary precision integers in Michelson. + The type variable ['t] is always [n] or [z], + [n num] and [z num] are incompatible. + + This is internally a [Z.t]. + This module mostly adds signedness preservation guarantees. *) +type 't num [@@coq_phantom] + +(** Flag for natural numbers. *) +type n = Natural_tag + +(** Flag for relative numbers. *) +type z = Integer_tag + +(** Natural zero. *) +val zero_n : n num + +(** Natural one. *) +val one_n : n num + +(** Natural successor. + + [succ_n x] is the same as [add_n one_n]. + *) +val succ_n : n num -> n num + +(** Relative zero. *) +val zero : z num + +(** Compare two numbers as if they were *) +val compare : 'a num -> 'a num -> int + +(** Conversion to an OCaml [string] in decimal notation. *) +val to_string : _ num -> string + +(** Conversion from an OCaml [string]. + Returns [None] in case of an invalid notation. + Supports [+] and [-] sign modifiers, and [0x], [0o] and [0b] base modifiers. *) +val of_string : string -> z num option + +(** Conversion from an OCaml [int32]. *) +val of_int32 : int32 -> z num + +(** Conversion to an OCaml [int64], returns [None] on overflow. *) +val to_int64 : _ num -> int64 option + +(** Conversion from an OCaml [int64]. *) +val of_int64 : int64 -> z num + +(** Conversion to an OCaml [int], returns [None] on overflow. *) +val to_int : _ num -> int option + +(** Conversion from an OCaml [int]. *) +val of_int : int -> z num + +(** Conversion from a Zarith integer ([Z.t]). *) +val of_zint : Z.t -> z num + +(** Conversion to a Zarith integer ([Z.t]). *) +val to_zint : 'a num -> Z.t + +(** Addition between naturals. *) +val add_n : n num -> n num -> n num + +(** Multiplication between naturals. *) +val mul_n : n num -> n num -> n num + +(** Euclidean division between naturals. + [ediv_n n d] returns [None] if divisor is zero, + or [Some (q, r)] where [n = d * q + r] and [[0 <= r < d]] otherwise. *) +val ediv_n : n num -> n num -> (n num * n num) option + +(** Sign agnostic addition. + Use {!add_n} when working with naturals to preserve the sign. *) +val add : _ num -> _ num -> z num + +(** Sign agnostic subtraction. + Use {!sub_n} when working with naturals to preserve the sign. *) +val sub : _ num -> _ num -> z num + +(** Sign agnostic multiplication. + Use {!mul_n} when working with naturals to preserve the sign. *) +val mul : _ num -> _ num -> z num + +(** Sign agnostic euclidean division. + [ediv n d] returns [None] if divisor is zero, + or [Some (q, r)] where [n = d * q + r] and [[0 <= r < |d|]] otherwise. + Use {!ediv_n} when working with naturals to preserve the sign. *) +val ediv : _ num -> _ num -> (z num * n num) option + +(** Compute the absolute value of a relative, turning it into a natural. *) +val abs : z num -> n num + +(** Partial identity over [N]. *) +val is_nat : z num -> n num option + +(** Negates a number. *) +val neg : _ num -> z num + +(** Turns a natural into a relative, not changing its value. *) +val int : n num -> z num + +(** Reverses each bit in the representation of the number. + Also applies to the sign. *) +val lognot : _ num -> z num + +(** Shifts the natural to the left of a number of bits between 0 and 256. + Returns [None] if the amount is too high. *) +val shift_left_n : n num -> n num -> n num option + +(** Shifts the natural to the right of a number of bits between 0 and 256. + Returns [None] if the amount is too high. *) +val shift_right_n : n num -> n num -> n num option + +(** Shifts the number to the left of a number of bits between 0 and 256. + Returns [None] if the amount is too high. *) +val shift_left : 'a num -> n num -> 'a num option + +(** Shifts the number to the right of a number of bits between 0 and 256. + Returns [None] if the amount is too high. *) +val shift_right : 'a num -> n num -> 'a num option + +(** Applies a boolean or operation to each bit. *) +val logor : 'a num -> 'a num -> 'a num + +(** Applies a boolean and operation to each bit. *) +val logand : _ num -> n num -> n num + +(** Applies a boolean xor operation to each bit. *) +val logxor : n num -> n num -> n num diff --git a/src/proto_011_PtHangzH/lib_protocol/script_interpreter.ml b/src/proto_011_PtHangzH/lib_protocol/script_interpreter.ml new file mode 100644 index 000000000000..0d2c4b995edc --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_interpreter.ml @@ -0,0 +1,1825 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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 implements an interpreter for Michelson. It takes the + form of a [step] function that interprets script instructions in a + dedicated abstract machine. + + The interpreter is written in a small-step style: an execution + [step] only interprets a single instruction by updating the + configuration of a dedicated abstract machine. + + This abstract machine has two components: + + - a stack to control which instructions must be executed ; and + + - a stack of values where instructions get their inputs and put + their outputs. + + In addition, the machine has access to effectful primitives to + interact with the execution environment (e.g. the Tezos + node). These primitives live in the [Lwt+State+Error] monad. Hence, + this interpreter produces a computation in the [Lwt+State+Error] + monad. + + This interpreter enjoys the following properties: + + - The interpreter is tail-recursive, hence it is robust to stack + overflow. This property is checked by the compiler thanks to the + [@ocaml.tailcall] annotation of each recursive call. + + - The interpreter is type-preserving. Thanks to GADTs, the typing + rules of Michelson are statically checked by the OCaml typechecker: + a Michelson program cannot go wrong. + + - The interpreter is tagless. Thanks to GADTs, the exact shape of + the stack is known statically so the interpreter does not have to + check that the input stack has the shape expected by the + instruction to be executed. + + Outline + ======= + + This file is organized as follows: + + 1. Definition of runtime errors. + + 2. Interpretation loop: This is the main functionality of this + module, aka the [step] function. + + 3. Interface functions: This part of the module builds high-level + functions on top of the more basic [step] function. + + Auxiliary definitions can be found in {!Script_interpreter_defs}. + + Implementation details are explained along the file. + +*) + +open Alpha_context +open Script +open Script_typed_ir +open Script_ir_translator +open Script_interpreter_defs +module S = Saturation_repr + +type step_constants = Script_interpreter_defs.step_constants = { + source : Contract.t; + payer : Contract.t; + self : Contract.t; + amount : Tez.t; + chain_id : Chain_id.t; +} + +(* ---- Run-time errors -----------------------------------------------------*) + +type error += Reject of Script.location * Script.expr * execution_trace option + +type error += Overflow of Script.location * execution_trace option + +type error += Runtime_contract_error : Contract.t * Script.expr -> error + +type error += Bad_contract_parameter of Contract.t (* `Permanent *) + +type error += Cannot_serialize_failure + +type error += Cannot_serialize_storage + +type error += Michelson_too_many_recursive_calls + +let () = + let open Data_encoding in + let trace_encoding = + list + @@ obj3 + (req "location" Script.location_encoding) + (req "gas" Gas.encoding) + (req + "stack" + (list (obj2 (req "item" Script.expr_encoding) (opt "annot" string)))) + in + (* Reject *) + register_error_kind + `Temporary + ~id:"michelson_v1.script_rejected" + ~title:"Script failed" + ~description:"A FAILWITH instruction was reached" + (obj3 + (req "location" Script.location_encoding) + (req "with" Script.expr_encoding) + (opt "trace" trace_encoding)) + (function Reject (loc, v, trace) -> Some (loc, v, trace) | _ -> None) + (fun (loc, v, trace) -> Reject (loc, v, trace)) ; + (* Overflow *) + register_error_kind + `Temporary + ~id:"michelson_v1.script_overflow" + ~title:"Script failed (overflow error)" + ~description: + "A FAIL instruction was reached due to the detection of an overflow" + (obj2 + (req "location" Script.location_encoding) + (opt "trace" trace_encoding)) + (function Overflow (loc, trace) -> Some (loc, trace) | _ -> None) + (fun (loc, trace) -> Overflow (loc, trace)) ; + (* Runtime contract error *) + register_error_kind + `Temporary + ~id:"michelson_v1.runtime_error" + ~title:"Script runtime error" + ~description:"Toplevel error for all runtime script errors" + (obj2 + (req "contract_handle" Contract.encoding) + (req "contract_code" Script.expr_encoding)) + (function + | Runtime_contract_error (contract, expr) -> Some (contract, expr) + | _ -> None) + (fun (contract, expr) -> Runtime_contract_error (contract, expr)) ; + (* Bad contract parameter *) + register_error_kind + `Permanent + ~id:"michelson_v1.bad_contract_parameter" + ~title:"Contract supplied an invalid parameter" + ~description: + "Either no parameter was supplied to a contract with a non-unit \ + parameter type, a non-unit parameter was passed to an account, or a \ + parameter was supplied of the wrong type" + Data_encoding.(obj1 (req "contract" Contract.encoding)) + (function Bad_contract_parameter c -> Some c | _ -> None) + (fun c -> Bad_contract_parameter c) ; + (* Cannot serialize failure *) + register_error_kind + `Temporary + ~id:"michelson_v1.cannot_serialize_failure" + ~title:"Not enough gas to serialize argument of FAILWITH" + ~description: + "Argument of FAILWITH was too big to be serialized with the provided gas" + Data_encoding.empty + (function Cannot_serialize_failure -> Some () | _ -> None) + (fun () -> Cannot_serialize_failure) ; + (* Cannot serialize storage *) + register_error_kind + `Temporary + ~id:"michelson_v1.cannot_serialize_storage" + ~title:"Not enough gas to serialize execution storage" + ~description: + "The returned storage was too big to be serialized with the provided gas" + Data_encoding.empty + (function Cannot_serialize_storage -> Some () | _ -> None) + (fun () -> Cannot_serialize_storage) + +(* + + Interpretation loop + =================== + +*) + +(* + + As announced earlier, the [step] function produces a computation in + the [Lwt+State+Error] monad. The [State] monad is implemented by + having the [context] passed as input and returned updated as + output. The [Error] monad is represented by the [tzresult] type + constructor. + + The [step] function is actually defined as an internal + tail-recursive routine of the toplevel [step]. It monitors the gas + level before executing the instruction under focus, once this is + done, it recursively calls itself on the continuation held by the + current instruction. + + For each pure instruction (i.e. that is not monadic), the + interpretation simply updates the input arguments of the [step] + function. Since these arguments are (most likely) stored in + hardware registers and since the tail-recursive calls are compiled + into direct jumps, this interpretation technique offers good + performances while saving safety thanks to a rich typing. + + For each impure instruction, the interpreter makes use of monadic + bindings to compose monadic primitives with the [step] function. + Again, we make sure that the recursive calls to [step] are tail + calls by annotating them with [@ocaml.tailcall]. + + The [step] function is actually based on several mutually + recursive functions that can be separated in two groups: the first + group focuses on the evaluation of continuations while the second + group is about evaluating the instructions. + +*) + +(* + + Evaluation of continuations + =========================== + + As explained in [Script_typed_ir], there are several kinds of + continuations, each having a specific evaluation rules. The + following group of functions starts with a list of evaluation + rules for continuations that generate fresh continuations. This + group ends with the definition of [next], which dispatches + evaluation rules depending on the continuation at stake. + + *) +let rec kmap_exit : + type a b c d e f g h m n o. (a, b, c, d, e, f, g, h, m, n, o) kmap_exit_type + = + fun mk g gas (body, xs, ys, yk) ks accu stack -> + let ys = Script_map.update yk (Some accu) ys in + let ks = mk (KMap_enter_body (body, xs, ys, ks)) in + let (accu, stack) = stack in + (next [@ocaml.tailcall]) g gas ks accu stack + [@@inline] + +and kmap_enter : type a b c d i j k. (a, b, c, d, i, j, k) kmap_enter_type = + fun mk g gas (body, xs, ys) ks accu stack -> + match xs with + | [] -> (next [@ocaml.tailcall]) g gas ks ys (accu, stack) + | (xk, xv) :: xs -> + let ks = mk (KMap_exit_body (body, xs, ys, xk, ks)) in + let res = (xk, xv) in + let stack = (accu, stack) in + (step [@ocaml.tailcall]) g gas body ks res stack + [@@inline] + +and klist_exit : type a b c d i j. (a, b, c, d, i, j) klist_exit_type = + fun mk g gas (body, xs, ys, len) ks accu stack -> + let ks = mk (KList_enter_body (body, xs, accu :: ys, len, ks)) in + let (accu, stack) = stack in + (next [@ocaml.tailcall]) g gas ks accu stack + [@@inline] + +and klist_enter : type a b c d e j. (a, b, c, d, e, j) klist_enter_type = + fun mk g gas (body, xs, ys, len) ks' accu stack -> + match xs with + | [] -> + let ys = {elements = List.rev ys; length = len} in + (next [@ocaml.tailcall]) g gas ks' ys (accu, stack) + | x :: xs -> + let ks = mk (KList_exit_body (body, xs, ys, len, ks')) in + (step [@ocaml.tailcall]) g gas body ks x (accu, stack) + [@@inline] + +and kloop_in_left : type a b c d e f g. (a, b, c, d, e, f, g) kloop_in_left_type + = + fun g gas ks0 ki ks' accu stack -> + match accu with + | L v -> (step [@ocaml.tailcall]) g gas ki ks0 v stack + | R v -> (next [@ocaml.tailcall]) g gas ks' v stack + [@@inline] + +and kloop_in : type a b c r f s. (a, b, c, r, f, s) kloop_in_type = + fun g gas ks0 ki ks' accu stack -> + let (accu', stack') = stack in + if accu then (step [@ocaml.tailcall]) g gas ki ks0 accu' stack' + else (next [@ocaml.tailcall]) g gas ks' accu' stack' + [@@inline] + +and kiter : type a b s r f. (a, b, s, r, f) kiter_type = + fun mk g gas (body, xs) ks accu stack -> + match xs with + | [] -> (next [@ocaml.tailcall]) g gas ks accu stack + | x :: xs -> + let ks = mk (KIter (body, xs, ks)) in + (step [@ocaml.tailcall]) g gas body ks x (accu, stack) + [@@inline] + +and next : + type a s r f. + outdated_context * step_constants -> + local_gas_counter -> + (a, s, r, f) continuation -> + a -> + s -> + (r * f * outdated_context * local_gas_counter) tzresult Lwt.t = + fun ((ctxt, _) as g) gas ks0 accu stack -> + match consume_control gas ks0 with + | None -> Lwt.return (Gas.gas_exhausted_error (update_context gas ctxt)) + | Some gas -> ( + match ks0 with + | KLog (ks, logger) -> + (klog [@ocaml.tailcall]) logger g gas ks0 ks accu stack + | KNil -> Lwt.return (Ok (accu, stack, ctxt, gas)) + | KCons (k, ks) -> (step [@ocaml.tailcall]) g gas k ks accu stack + | KLoop_in (ki, ks') -> + (kloop_in [@ocaml.tailcall]) g gas ks0 ki ks' accu stack + | KReturn (stack', ks) -> (next [@ocaml.tailcall]) g gas ks accu stack' + | KLoop_in_left (ki, ks') -> + (kloop_in_left [@ocaml.tailcall]) g gas ks0 ki ks' accu stack + | KUndip (x, ks) -> (next [@ocaml.tailcall]) g gas ks x (accu, stack) + | KIter (body, xs, ks) -> + let extra = (body, xs) in + (kiter [@ocaml.tailcall]) id g gas extra ks accu stack + | KList_enter_body (body, xs, ys, len, ks) -> + let extra = (body, xs, ys, len) in + (klist_enter [@ocaml.tailcall]) id g gas extra ks accu stack + | KList_exit_body (body, xs, ys, len, ks) -> + let extra = (body, xs, ys, len) in + (klist_exit [@ocaml.tailcall]) id g gas extra ks accu stack + | KMap_enter_body (body, xs, ys, ks) -> + let extra = (body, xs, ys) in + (kmap_enter [@ocaml.tailcall]) id g gas extra ks accu stack + | KMap_exit_body (body, xs, ys, yk, ks) -> + let extra = (body, xs, ys, yk) in + (kmap_exit [@ocaml.tailcall]) id g gas extra ks accu stack) + +(* + + Evaluation of instructions + ========================== + + The following functions define evaluation rules for instructions that + generate fresh continuations. As such, they expect a constructor + [log_if_needed] which inserts a [KLog] if the evaluation is logged. + + The [step] function is taking care of the evaluation of the other + instructions. + +*) +and ilist_map : type a b c d e f g h. (a, b, c, d, e, f, g, h) ilist_map_type = + fun log_if_needed g gas (body, k) ks accu stack -> + let xs = accu.elements in + let ys = [] in + let len = accu.length in + let ks = + log_if_needed (KList_enter_body (body, xs, ys, len, KCons (k, ks))) + in + let (accu, stack) = stack in + (next [@ocaml.tailcall]) g gas ks accu stack + [@@inline] + +and ilist_iter : type a b c d e f g. (a, b, c, d, e, f, g) ilist_iter_type = + fun log_if_needed g gas (body, k) ks accu stack -> + let xs = accu.elements in + let ks = log_if_needed (KIter (body, xs, KCons (k, ks))) in + let (accu, stack) = stack in + (next [@ocaml.tailcall]) g gas ks accu stack + [@@inline] + +and iset_iter : type a b c d e f g. (a, b, c, d, e, f, g) iset_iter_type = + fun log_if_needed g gas (body, k) ks accu stack -> + let set = accu in + let l = List.rev (Script_set.fold (fun e acc -> e :: acc) set []) in + let ks = log_if_needed (KIter (body, l, KCons (k, ks))) in + let (accu, stack) = stack in + (next [@ocaml.tailcall]) g gas ks accu stack + [@@inline] + +and imap_map : type a b c d e f g h i. (a, b, c, d, e, f, g, h, i) imap_map_type + = + fun log_if_needed g gas (body, k) ks accu stack -> + let map = accu in + let xs = List.rev (Script_map.fold (fun k v a -> (k, v) :: a) map []) in + let ys = Script_map.(empty @@ key_ty map) in + let ks = log_if_needed (KMap_enter_body (body, xs, ys, KCons (k, ks))) in + let (accu, stack) = stack in + (next [@ocaml.tailcall]) g gas ks accu stack + [@@inline] + +and imap_iter : type a b c d e f g h. (a, b, c, d, e, f, g, h) imap_iter_type = + fun log_if_needed g gas (body, k) ks accu stack -> + let map = accu in + let l = List.rev (Script_map.fold (fun k v a -> (k, v) :: a) map []) in + let ks = log_if_needed (KIter (body, l, KCons (k, ks))) in + let (accu, stack) = stack in + (next [@ocaml.tailcall]) g gas ks accu stack + [@@inline] + +and imul_teznat : type a b c d e f. (a, b, c, d, e, f) imul_teznat_type = + fun logger g gas (kinfo, k) ks accu stack -> + let x = accu in + let (y, stack) = stack in + match Script_int.to_int64 y with + | None -> get_log logger >>=? fun log -> fail (Overflow (kinfo.iloc, log)) + | Some y -> + Tez.(x *? y) >>?= fun res -> (step [@ocaml.tailcall]) g gas k ks res stack + +and imul_nattez : type a b c d e f. (a, b, c, d, e, f) imul_nattez_type = + fun logger g gas (kinfo, k) ks accu stack -> + let y = accu in + let (x, stack) = stack in + match Script_int.to_int64 y with + | None -> get_log logger >>=? fun log -> fail (Overflow (kinfo.iloc, log)) + | Some y -> + Tez.(x *? y) >>?= fun res -> (step [@ocaml.tailcall]) g gas k ks res stack + +and ilsl_nat : type a b c d e f. (a, b, c, d, e, f) ilsl_nat_type = + fun logger g gas (kinfo, k) ks accu stack -> + let x = accu and (y, stack) = stack in + match Script_int.shift_left_n x y with + | None -> get_log logger >>=? fun log -> fail (Overflow (kinfo.iloc, log)) + | Some x -> (step [@ocaml.tailcall]) g gas k ks x stack + +and ilsr_nat : type a b c d e f. (a, b, c, d, e, f) ilsr_nat_type = + fun logger g gas (kinfo, k) ks accu stack -> + let x = accu and (y, stack) = stack in + match Script_int.shift_right_n x y with + | None -> get_log logger >>=? fun log -> fail (Overflow (kinfo.iloc, log)) + | Some r -> (step [@ocaml.tailcall]) g gas k ks r stack + +and ifailwith : type a b. (a, b) ifailwith_type = + fun logger (ctxt, _) gas kloc tv accu -> + let v = accu in + let ctxt = update_context gas ctxt in + trace Cannot_serialize_failure (unparse_data ctxt Optimized tv v) + >>=? fun (v, _ctxt) -> + let v = Micheline.strip_locations v in + get_log logger >>=? fun log -> fail (Reject (kloc, v, log)) + +and iexec : type a b c d e f g. (a, b, c, d, e, f, g) iexec_type = + fun logger g gas k ks accu stack -> + let arg = accu and (code, stack) = stack in + let (Lam (code, _)) = code in + let code = + match logger with + | None -> code.kinstr + | Some logger -> log_kinstr logger code.kinstr + in + let ks = KReturn (stack, KCons (k, ks)) in + (step [@ocaml.tailcall]) g gas code ks arg (EmptyCell, EmptyCell) + +and step : type a s b t r f. (a, s, b, t, r, f) step_type = + fun ((ctxt, sc) as g) gas i ks accu stack -> + match consume gas i accu stack with + | None -> Lwt.return (Gas.gas_exhausted_error (update_context gas ctxt)) + | Some gas -> ( + match i with + | ILog (_, event, logger, k) -> + (log [@ocaml.tailcall]) (logger, event) g gas k ks accu stack + | IHalt _ -> (next [@ocaml.tailcall]) g gas ks accu stack + (* stack ops *) + | IDrop (_, k) -> + let (accu, stack) = stack in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IDup (_, k) -> (step [@ocaml.tailcall]) g gas k ks accu (accu, stack) + | ISwap (_, k) -> + let (top, stack) = stack in + (step [@ocaml.tailcall]) g gas k ks top (accu, stack) + | IConst (_, v, k) -> (step [@ocaml.tailcall]) g gas k ks v (accu, stack) + (* options *) + | ICons_some (_, k) -> + (step [@ocaml.tailcall]) g gas k ks (Some accu) stack + | ICons_none (_, k) -> + (step [@ocaml.tailcall]) g gas k ks None (accu, stack) + | IIf_none {branch_if_none; branch_if_some; k; _} -> ( + match accu with + | None -> + let (accu, stack) = stack in + (step [@ocaml.tailcall]) + g + gas + branch_if_none + (KCons (k, ks)) + accu + stack + | Some v -> + (step [@ocaml.tailcall]) + g + gas + branch_if_some + (KCons (k, ks)) + v + stack) + (* pairs *) + | ICons_pair (_, k) -> + let (b, stack) = stack in + (step [@ocaml.tailcall]) g gas k ks (accu, b) stack + | IUnpair (_, k) -> + let (a, b) = accu in + (step [@ocaml.tailcall]) g gas k ks a (b, stack) + | ICar (_, k) -> + let (a, _) = accu in + (step [@ocaml.tailcall]) g gas k ks a stack + | ICdr (_, k) -> + let (_, b) = accu in + (step [@ocaml.tailcall]) g gas k ks b stack + (* unions *) + | ICons_left (_, k) -> (step [@ocaml.tailcall]) g gas k ks (L accu) stack + | ICons_right (_, k) -> (step [@ocaml.tailcall]) g gas k ks (R accu) stack + | IIf_left {branch_if_left; branch_if_right; k; _} -> ( + match accu with + | L v -> + (step [@ocaml.tailcall]) + g + gas + branch_if_left + (KCons (k, ks)) + v + stack + | R v -> + (step [@ocaml.tailcall]) + g + gas + branch_if_right + (KCons (k, ks)) + v + stack) + (* lists *) + | ICons_list (_, k) -> + let (tl, stack) = stack in + let accu = Script_list.cons accu tl in + (step [@ocaml.tailcall]) g gas k ks accu stack + | INil (_, k) -> + let stack = (accu, stack) in + let accu = Script_list.empty in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IIf_cons {branch_if_cons; branch_if_nil; k; _} -> ( + match accu.elements with + | [] -> + let (accu, stack) = stack in + (step [@ocaml.tailcall]) + g + gas + branch_if_nil + (KCons (k, ks)) + accu + stack + | hd :: tl -> + let tl = {elements = tl; length = accu.length - 1} in + (step [@ocaml.tailcall]) + g + gas + branch_if_cons + (KCons (k, ks)) + hd + (tl, stack)) + | IList_map (_, body, k) -> + (ilist_map [@ocaml.tailcall]) id g gas (body, k) ks accu stack + | IList_size (_, k) -> + let list = accu in + let len = Script_int.(abs (of_int list.length)) in + (step [@ocaml.tailcall]) g gas k ks len stack + | IList_iter (_, body, k) -> + (ilist_iter [@ocaml.tailcall]) id g gas (body, k) ks accu stack + (* sets *) + | IEmpty_set (_, ty, k) -> + let res = Script_set.empty ty in + let stack = (accu, stack) in + (step [@ocaml.tailcall]) g gas k ks res stack + | ISet_iter (_, body, k) -> + (iset_iter [@ocaml.tailcall]) id g gas (body, k) ks accu stack + | ISet_mem (_, k) -> + let (set, stack) = stack in + let res = Script_set.mem accu set in + (step [@ocaml.tailcall]) g gas k ks res stack + | ISet_update (_, k) -> + let (presence, (set, stack)) = stack in + let res = Script_set.update accu presence set in + (step [@ocaml.tailcall]) g gas k ks res stack + | ISet_size (_, k) -> + let res = Script_set.size accu in + (step [@ocaml.tailcall]) g gas k ks res stack + (* maps *) + | IEmpty_map (_, ty, k) -> + let res = Script_map.empty ty and stack = (accu, stack) in + (step [@ocaml.tailcall]) g gas k ks res stack + | IMap_map (_, body, k) -> + (imap_map [@ocaml.tailcall]) id g gas (body, k) ks accu stack + | IMap_iter (_, body, k) -> + (imap_iter [@ocaml.tailcall]) id g gas (body, k) ks accu stack + | IMap_mem (_, k) -> + let (map, stack) = stack in + let res = Script_map.mem accu map in + (step [@ocaml.tailcall]) g gas k ks res stack + | IMap_get (_, k) -> + let (map, stack) = stack in + let res = Script_map.get accu map in + (step [@ocaml.tailcall]) g gas k ks res stack + | IMap_update (_, k) -> + let (v, (map, stack)) = stack in + let key = accu in + let res = Script_map.update key v map in + (step [@ocaml.tailcall]) g gas k ks res stack + | IMap_get_and_update (_, k) -> + let key = accu in + let (v, (map, rest)) = stack in + let map' = Script_map.update key v map in + let v' = Script_map.get key map in + (step [@ocaml.tailcall]) g gas k ks v' (map', rest) + | IMap_size (_, k) -> + let res = Script_map.size accu in + (step [@ocaml.tailcall]) g gas k ks res stack + (* Big map operations *) + | IEmpty_big_map (_, tk, tv, k) -> + let ebm = Script_ir_translator.empty_big_map tk tv in + (step [@ocaml.tailcall]) g gas k ks ebm (accu, stack) + | IBig_map_mem (_, k) -> + let (map, stack) = stack in + let key = accu in + ( use_gas_counter_in_ctxt ctxt gas @@ fun ctxt -> + Script_ir_translator.big_map_mem ctxt key map ) + >>=? fun (res, ctxt, gas) -> + (step [@ocaml.tailcall]) (ctxt, sc) gas k ks res stack + | IBig_map_get (_, k) -> + let (map, stack) = stack in + let key = accu in + ( use_gas_counter_in_ctxt ctxt gas @@ fun ctxt -> + Script_ir_translator.big_map_get ctxt key map ) + >>=? fun (res, ctxt, gas) -> + (step [@ocaml.tailcall]) (ctxt, sc) gas k ks res stack + | IBig_map_update (_, k) -> + let key = accu in + let (maybe_value, (map, stack)) = stack in + ( use_gas_counter_in_ctxt ctxt gas @@ fun ctxt -> + Script_ir_translator.big_map_update ctxt key maybe_value map ) + >>=? fun (big_map, ctxt, gas) -> + (step [@ocaml.tailcall]) (ctxt, sc) gas k ks big_map stack + | IBig_map_get_and_update (_, k) -> + let key = accu in + let (v, (map, stack)) = stack in + ( use_gas_counter_in_ctxt ctxt gas @@ fun ctxt -> + Script_ir_translator.big_map_get_and_update ctxt key v map ) + >>=? fun ((v', map'), ctxt, gas) -> + (step [@ocaml.tailcall]) (ctxt, sc) gas k ks v' (map', stack) + (* timestamp operations *) + | IAdd_seconds_to_timestamp (_, k) -> + let n = accu in + let (t, stack) = stack in + let result = Script_timestamp.add_delta t n in + (step [@ocaml.tailcall]) g gas k ks result stack + | IAdd_timestamp_to_seconds (_, k) -> + let t = accu in + let (n, stack) = stack in + let result = Script_timestamp.add_delta t n in + (step [@ocaml.tailcall]) g gas k ks result stack + | ISub_timestamp_seconds (_, k) -> + let t = accu in + let (s, stack) = stack in + let result = Script_timestamp.sub_delta t s in + (step [@ocaml.tailcall]) g gas k ks result stack + | IDiff_timestamps (_, k) -> + let t1 = accu in + let (t2, stack) = stack in + let result = Script_timestamp.diff t1 t2 in + (step [@ocaml.tailcall]) g gas k ks result stack + (* string operations *) + | IConcat_string_pair (_, k) -> + let x = accu in + let (y, stack) = stack in + let s = Script_string.concat_pair x y in + (step [@ocaml.tailcall]) g gas k ks s stack + | IConcat_string (_, k) -> + let ss = accu in + (* The cost for this fold_left has been paid upfront *) + let total_length = + List.fold_left + (fun acc s -> S.add acc (S.safe_int (Script_string.length s))) + S.zero + ss.elements + in + consume' ctxt gas (Interp_costs.concat_string total_length) + >>?= fun gas -> + let s = Script_string.concat ss.elements in + (step [@ocaml.tailcall]) g gas k ks s stack + | ISlice_string (_, k) -> + let offset = accu and (length, (s, stack)) = stack in + let s_length = Z.of_int (Script_string.length s) in + let offset = Script_int.to_zint offset in + let length = Script_int.to_zint length in + if Compare.Z.(offset < s_length && Z.add offset length <= s_length) + then + let s = Script_string.sub s (Z.to_int offset) (Z.to_int length) in + (step [@ocaml.tailcall]) g gas k ks (Some s) stack + else (step [@ocaml.tailcall]) g gas k ks None stack + | IString_size (_, k) -> + let s = accu in + let result = Script_int.(abs (of_int (Script_string.length s))) in + (step [@ocaml.tailcall]) g gas k ks result stack + (* bytes operations *) + | IConcat_bytes_pair (_, k) -> + let x = accu in + let (y, stack) = stack in + let s = Bytes.cat x y in + (step [@ocaml.tailcall]) g gas k ks s stack + | IConcat_bytes (_, k) -> + let ss = accu in + (* The cost for this fold_left has been paid upfront *) + let total_length = + List.fold_left + (fun acc s -> S.add acc (S.safe_int (Bytes.length s))) + S.zero + ss.elements + in + consume' ctxt gas (Interp_costs.concat_string total_length) + >>?= fun gas -> + let s = Bytes.concat Bytes.empty ss.elements in + (step [@ocaml.tailcall]) g gas k ks s stack + | ISlice_bytes (_, k) -> + let offset = accu and (length, (s, stack)) = stack in + let s_length = Z.of_int (Bytes.length s) in + let offset = Script_int.to_zint offset in + let length = Script_int.to_zint length in + if Compare.Z.(offset < s_length && Z.add offset length <= s_length) + then + let s = Bytes.sub s (Z.to_int offset) (Z.to_int length) in + (step [@ocaml.tailcall]) g gas k ks (Some s) stack + else (step [@ocaml.tailcall]) g gas k ks None stack + | IBytes_size (_, k) -> + let s = accu in + let result = Script_int.(abs (of_int (Bytes.length s))) in + (step [@ocaml.tailcall]) g gas k ks result stack + (* currency operations *) + | IAdd_tez (_, k) -> + let x = accu in + let (y, stack) = stack in + Tez.(x +? y) >>?= fun res -> + (step [@ocaml.tailcall]) g gas k ks res stack + | ISub_tez (_, k) -> + let x = accu in + let (y, stack) = stack in + Tez.(x -? y) >>?= fun res -> + (step [@ocaml.tailcall]) g gas k ks res stack + | IMul_teznat (kinfo, k) -> + imul_teznat None g gas (kinfo, k) ks accu stack + | IMul_nattez (kinfo, k) -> + imul_nattez None g gas (kinfo, k) ks accu stack + (* boolean operations *) + | IOr (_, k) -> + let x = accu in + let (y, stack) = stack in + (step [@ocaml.tailcall]) g gas k ks (x || y) stack + | IAnd (_, k) -> + let x = accu in + let (y, stack) = stack in + (step [@ocaml.tailcall]) g gas k ks (x && y) stack + | IXor (_, k) -> + let x = accu in + let (y, stack) = stack in + let res = Compare.Bool.(x <> y) in + (step [@ocaml.tailcall]) g gas k ks res stack + | INot (_, k) -> + let x = accu in + (step [@ocaml.tailcall]) g gas k ks (not x) stack + (* integer operations *) + | IIs_nat (_, k) -> + let x = accu in + let res = Script_int.is_nat x in + (step [@ocaml.tailcall]) g gas k ks res stack + | IAbs_int (_, k) -> + let x = accu in + let res = Script_int.abs x in + (step [@ocaml.tailcall]) g gas k ks res stack + | IInt_nat (_, k) -> + let x = accu in + let res = Script_int.int x in + (step [@ocaml.tailcall]) g gas k ks res stack + | INeg_int (_, k) -> + let x = accu in + let res = Script_int.neg x in + (step [@ocaml.tailcall]) g gas k ks res stack + | INeg_nat (_, k) -> + let x = accu in + let res = Script_int.neg x in + (step [@ocaml.tailcall]) g gas k ks res stack + | IAdd_intint (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.add x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IAdd_intnat (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.add x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IAdd_natint (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.add x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IAdd_natnat (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.add_n x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | ISub_int (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.sub x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IMul_intint (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.mul x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IMul_intnat (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.mul x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IMul_natint (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.mul x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IMul_natnat (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.mul_n x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IEdiv_teznat (_, k) -> + let x = accu and (y, stack) = stack in + let x = Script_int.of_int64 (Tez.to_mutez x) in + let result = + match Script_int.ediv x y with + | None -> None + | Some (q, r) -> ( + match (Script_int.to_int64 q, Script_int.to_int64 r) with + | (Some q, Some r) -> ( + match (Tez.of_mutez q, Tez.of_mutez r) with + | (Some q, Some r) -> Some (q, r) + (* Cannot overflow *) + | _ -> assert false) + (* Cannot overflow *) + | _ -> assert false) + in + (step [@ocaml.tailcall]) g gas k ks result stack + | IEdiv_tez (_, k) -> + let x = accu and (y, stack) = stack in + let x = Script_int.abs (Script_int.of_int64 (Tez.to_mutez x)) in + let y = Script_int.abs (Script_int.of_int64 (Tez.to_mutez y)) in + let result = + match Script_int.ediv_n x y with + | None -> None + | Some (q, r) -> ( + match Script_int.to_int64 r with + | None -> assert false (* Cannot overflow *) + | Some r -> ( + match Tez.of_mutez r with + | None -> assert false (* Cannot overflow *) + | Some r -> Some (q, r))) + in + (step [@ocaml.tailcall]) g gas k ks result stack + | IEdiv_intint (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.ediv x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IEdiv_intnat (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.ediv x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IEdiv_natint (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.ediv x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IEdiv_natnat (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.ediv_n x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | ILsl_nat (kinfo, k) -> ilsl_nat None g gas (kinfo, k) ks accu stack + | ILsr_nat (kinfo, k) -> ilsr_nat None g gas (kinfo, k) ks accu stack + | IOr_nat (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.logor x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IAnd_nat (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.logand x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IAnd_int_nat (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.logand x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IXor_nat (_, k) -> + let x = accu and (y, stack) = stack in + let res = Script_int.logxor x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | INot_int (_, k) -> + let x = accu in + let res = Script_int.lognot x in + (step [@ocaml.tailcall]) g gas k ks res stack + | INot_nat (_, k) -> + let x = accu in + let res = Script_int.lognot x in + (step [@ocaml.tailcall]) g gas k ks res stack + (* control *) + | IIf {branch_if_true; branch_if_false; k; _} -> + let (res, stack) = stack in + if accu then + (step [@ocaml.tailcall]) + g + gas + branch_if_true + (KCons (k, ks)) + res + stack + else + (step [@ocaml.tailcall]) + g + gas + branch_if_false + (KCons (k, ks)) + res + stack + | ILoop (_, body, k) -> + let ks = KLoop_in (body, KCons (k, ks)) in + (next [@ocaml.tailcall]) g gas ks accu stack + | ILoop_left (_, bl, br) -> + let ks = KLoop_in_left (bl, KCons (br, ks)) in + (next [@ocaml.tailcall]) g gas ks accu stack + | IDip (_, b, k) -> + let ign = accu in + let ks = KUndip (ign, KCons (k, ks)) in + let (accu, stack) = stack in + (step [@ocaml.tailcall]) g gas b ks accu stack + | IExec (_, k) -> iexec None g gas k ks accu stack + | IApply (_, capture_ty, k) -> + let capture = accu in + let (lam, stack) = stack in + apply ctxt gas capture_ty capture lam >>=? fun (lam', ctxt, gas) -> + (step [@ocaml.tailcall]) (ctxt, sc) gas k ks lam' stack + | ILambda (_, lam, k) -> + (step [@ocaml.tailcall]) g gas k ks lam (accu, stack) + | IFailwith (_, kloc, tv) -> ifailwith None g gas kloc tv accu + (* comparison *) + | ICompare (_, ty, k) -> + let a = accu in + let (b, stack) = stack in + let r = + Script_int.of_int @@ Script_comparable.compare_comparable ty a b + in + (step [@ocaml.tailcall]) g gas k ks r stack + (* comparators *) + | IEq (_, k) -> + let a = accu in + let a = Script_int.compare a Script_int.zero in + let a = Compare.Int.(a = 0) in + (step [@ocaml.tailcall]) g gas k ks a stack + | INeq (_, k) -> + let a = accu in + let a = Script_int.compare a Script_int.zero in + let a = Compare.Int.(a <> 0) in + (step [@ocaml.tailcall]) g gas k ks a stack + | ILt (_, k) -> + let a = accu in + let a = Script_int.compare a Script_int.zero in + let a = Compare.Int.(a < 0) in + (step [@ocaml.tailcall]) g gas k ks a stack + | ILe (_, k) -> + let a = accu in + let a = Script_int.compare a Script_int.zero in + let a = Compare.Int.(a <= 0) in + (step [@ocaml.tailcall]) g gas k ks a stack + | IGt (_, k) -> + let a = accu in + let a = Script_int.compare a Script_int.zero in + let a = Compare.Int.(a > 0) in + (step [@ocaml.tailcall]) g gas k ks a stack + | IGe (_, k) -> + let a = accu in + let a = Script_int.compare a Script_int.zero in + let a = Compare.Int.(a >= 0) in + (step [@ocaml.tailcall]) g gas k ks a stack + (* packing *) + | IPack (_, ty, k) -> + let value = accu in + ( use_gas_counter_in_ctxt ctxt gas @@ fun ctxt -> + Script_ir_translator.pack_data ctxt ty value ) + >>=? fun (bytes, ctxt, gas) -> + (step [@ocaml.tailcall]) (ctxt, sc) gas k ks bytes stack + | IUnpack (_, ty, k) -> + let bytes = accu in + ( use_gas_counter_in_ctxt ctxt gas @@ fun ctxt -> + unpack ctxt ~ty ~bytes ) + >>=? fun (opt, ctxt, gas) -> + (step [@ocaml.tailcall]) (ctxt, sc) gas k ks opt stack + | IAddress (_, k) -> + let (_, address) = accu in + (step [@ocaml.tailcall]) g gas k ks address stack + | IContract (kinfo, t, entrypoint, k) -> ( + let contract = accu in + match (contract, entrypoint) with + | ((contract, "default"), entrypoint) + | ((contract, entrypoint), "default") -> + let ctxt = update_context gas ctxt in + Script_ir_translator.parse_contract_for_script + ctxt + kinfo.iloc + t + contract + ~entrypoint + >>=? fun (ctxt, maybe_contract) -> + let gas = update_local_gas_counter ctxt in + let ctxt = outdated ctxt in + let accu = maybe_contract in + (step [@ocaml.tailcall]) (ctxt, sc) gas k ks accu stack + | _ -> (step [@ocaml.tailcall]) (ctxt, sc) gas k ks None stack) + | ITransfer_tokens (_, k) -> + let p = accu in + let (amount, ((tp, (destination, entrypoint)), stack)) = stack in + transfer (ctxt, sc) gas amount tp p destination entrypoint + >>=? fun (accu, ctxt, gas) -> + (step [@ocaml.tailcall]) (ctxt, sc) gas k ks accu stack + | IImplicit_account (_, k) -> + let key = accu in + let contract = Contract.implicit_contract key in + let res = (unit_t ~annot:None, (contract, "default")) in + (step [@ocaml.tailcall]) g gas k ks res stack + | IView (_, View_signature {name; input_ty; output_ty}, k) -> ( + let input = accu in + let ((c, _entrypoint_is_ignored), stack) = stack in + let ctxt = update_context gas ctxt in + Contract.get_script ctxt c >>=? fun (ctxt, script_opt) -> + let return_none ctxt = + (step [@ocaml.tailcall]) + (outdated ctxt, sc) + (update_local_gas_counter ctxt) + k + ks + None + stack + in + match script_opt with + | None -> (return_none [@ocaml.tailcall]) ctxt + | Some script -> ( + parse_script + ~legacy:true + ~allow_forged_in_storage:true + ctxt + script + >>=? fun (Ex_script {storage; storage_type; views; _}, ctxt) -> + Gas.consume ctxt (Interp_costs.view_get name views) + >>?= fun ctxt -> + match SMap.find name views with + | None -> (return_none [@ocaml.tailcall]) ctxt + | Some view -> ( + let view_result = + Script_ir_translator.parse_view_returning + ctxt + ~legacy:true + storage_type + view + in + trace_eval + (fun () -> + return + @@ Script_tc_errors.Ill_typed_contract + (Micheline.strip_locations view.view_code, [])) + view_result + >>=? fun (Ex_view f, ctxt) -> + match f with + | Lam + ( { + kloc; + kaft = Item_t (aft_ty, Bot_t, _); + kbef = Item_t (bef_ty, Bot_t, _); + kinstr; + }, + _script_view ) -> ( + pair_t + kloc + (input_ty, None, None) + (storage_type, None, None) + ~annot:None + >>?= fun pair_ty -> + let open Gas_monad in + let io_ty = + Script_ir_translator.merge_types + ~merge_type_error_flag:Default_merge_type_error + ~legacy:true + kloc + aft_ty + output_ty + >>$ fun (out_eq, _ty) -> + merge_types + ~merge_type_error_flag:Default_merge_type_error + ~legacy:true + kloc + bef_ty + pair_ty + >|$ fun (in_eq, _ty) -> (out_eq, in_eq) + in + Gas_monad.run ctxt io_ty >>?= fun (eq, ctxt) -> + match eq with + | Error _ -> (return_none [@ocaml.tailcall]) ctxt + | Ok (Eq, Eq) -> ( + let kkinfo = kinfo_of_kinstr k in + match kkinfo.kstack_ty with + | Item_t (_, s, a) -> + let kstack_ty = Item_t (output_ty, s, a) in + let kkinfo = {kkinfo with kstack_ty} in + let ks = KCons (ICons_some (kkinfo, k), ks) in + (step [@ocaml.tailcall]) + ( outdated ctxt, + { + sc with + source = sc.self; + self = c; + amount = Tez.zero; + } ) + (update_local_gas_counter ctxt) + kinstr + (KReturn (stack, ks)) + (input, storage) + (EmptyCell, EmptyCell)))))) + | ICreate_contract + { + storage_type; + arg_type; + lambda = Lam (_, code); + views; + root_name; + k; + _; + } -> + (* Removed the instruction's arguments manager, spendable and delegatable *) + let delegate = accu in + let (credit, (init, stack)) = stack in + create_contract + g + gas + storage_type + arg_type + code + views + root_name + delegate + credit + init + >>=? fun (res, contract, ctxt, gas) -> + let stack = ((contract, "default"), stack) in + (step [@ocaml.tailcall]) (ctxt, sc) gas k ks res stack + | ISet_delegate (_, k) -> + let delegate = accu in + let operation = Delegation delegate in + let ctxt = update_context gas ctxt in + fresh_internal_nonce ctxt >>?= fun (ctxt, nonce) -> + let res = + (Internal_operation {source = sc.self; operation; nonce}, None) + in + let gas = update_local_gas_counter ctxt in + let ctxt = outdated ctxt in + (step [@ocaml.tailcall]) (ctxt, sc) gas k ks res stack + | IBalance (_, k) -> + let ctxt = update_context gas ctxt in + Contract.get_balance_carbonated ctxt sc.self + >>=? fun (ctxt, balance) -> + let gas = update_local_gas_counter ctxt in + let ctxt = outdated ctxt in + let g = (ctxt, sc) in + (step [@ocaml.tailcall]) g gas k ks balance (accu, stack) + | ILevel (_, k) -> + let level = + (Level.current (context_from_outdated_context ctxt)).level + |> Raw_level.to_int32 |> Script_int.of_int32 |> Script_int.abs + in + (step [@ocaml.tailcall]) g gas k ks level (accu, stack) + | INow (_, k) -> + let now = Script_timestamp.now (context_from_outdated_context ctxt) in + (step [@ocaml.tailcall]) g gas k ks now (accu, stack) + | ICheck_signature (_, k) -> + let key = accu and (signature, (message, stack)) = stack in + let res = Signature.check key signature message in + (step [@ocaml.tailcall]) g gas k ks res stack + | IHash_key (_, k) -> + let key = accu in + let res = Signature.Public_key.hash key in + (step [@ocaml.tailcall]) g gas k ks res stack + | IBlake2b (_, k) -> + let bytes = accu in + let hash = Raw_hashes.blake2b bytes in + (step [@ocaml.tailcall]) g gas k ks hash stack + | ISha256 (_, k) -> + let bytes = accu in + let hash = Raw_hashes.sha256 bytes in + (step [@ocaml.tailcall]) g gas k ks hash stack + | ISha512 (_, k) -> + let bytes = accu in + let hash = Raw_hashes.sha512 bytes in + (step [@ocaml.tailcall]) g gas k ks hash stack + | ISource (_, k) -> + let res = (sc.payer, "default") in + (step [@ocaml.tailcall]) g gas k ks res (accu, stack) + | ISender (_, k) -> + let res = (sc.source, "default") in + (step [@ocaml.tailcall]) g gas k ks res (accu, stack) + | ISelf (_, ty, entrypoint, k) -> + let res = (ty, (sc.self, entrypoint)) in + (step [@ocaml.tailcall]) g gas k ks res (accu, stack) + | ISelf_address (_, k) -> + let res = (sc.self, "default") in + (step [@ocaml.tailcall]) g gas k ks res (accu, stack) + | IAmount (_, k) -> + let accu = sc.amount and stack = (accu, stack) in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IDig (_, _n, n', k) -> + let ((accu, stack), x) = + interp_stack_prefix_preserving_operation + (fun v stack -> (stack, v)) + n' + accu + stack + in + let accu = x and stack = (accu, stack) in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IDug (_, _n, n', k) -> + let v = accu in + let (accu, stack) = stack in + let ((accu, stack), ()) = + interp_stack_prefix_preserving_operation + (fun accu stack -> ((v, (accu, stack)), ())) + n' + accu + stack + in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IDipn (_, _n, n', b, k) -> + let (accu, stack, restore_prefix) = kundip n' accu stack k in + let ks = KCons (restore_prefix, ks) in + (step [@ocaml.tailcall]) g gas b ks accu stack + | IDropn (_, _n, n', k) -> + let stack = + let rec aux : + type a s b t. + (b, t, b, t, a, s, a, s) stack_prefix_preservation_witness -> + a -> + s -> + b * t = + fun w accu stack -> + match w with + | KRest -> (accu, stack) + | KPrefix (_, w) -> + let (accu, stack) = stack in + aux w accu stack + in + aux n' accu stack + in + let (accu, stack) = stack in + (step [@ocaml.tailcall]) g gas k ks accu stack + | ISapling_empty_state (_, memo_size, k) -> + let state = Sapling.empty_state ~memo_size () in + (step [@ocaml.tailcall]) g gas k ks state (accu, stack) + | ISapling_verify_update (_, k) -> ( + let transaction = accu in + let (state, stack) = stack in + let address = Contract.to_b58check sc.self in + let chain_id = Chain_id.to_b58check sc.chain_id in + let anti_replay = address ^ chain_id in + let ctxt = update_context gas ctxt in + Sapling.verify_update ctxt state transaction anti_replay + >>=? fun (ctxt, balance_state_opt) -> + let gas = update_local_gas_counter ctxt in + let ctxt = outdated ctxt in + match balance_state_opt with + | Some (balance, state) -> + let state = Some (Script_int.of_int64 balance, state) in + (step [@ocaml.tailcall]) (ctxt, sc) gas k ks state stack + | None -> (step [@ocaml.tailcall]) (ctxt, sc) gas k ks None stack) + | IChainId (_, k) -> + let accu = sc.chain_id and stack = (accu, stack) in + (step [@ocaml.tailcall]) g gas k ks accu stack + | INever _ -> ( match accu with _ -> .) + | IVoting_power (_, k) -> + let key_hash = accu in + let ctxt = update_context gas ctxt in + Vote.get_voting_power ctxt key_hash >>=? fun (ctxt, rolls) -> + let power = Script_int.(abs (of_int32 rolls)) in + let gas = update_local_gas_counter ctxt in + let ctxt = outdated ctxt in + (step [@ocaml.tailcall]) (ctxt, sc) gas k ks power stack + | ITotal_voting_power (_, k) -> + let ctxt = update_context gas ctxt in + Vote.get_total_voting_power ctxt >>=? fun (ctxt, rolls) -> + let power = Script_int.(abs (of_int32 rolls)) in + let gas = update_local_gas_counter ctxt in + let ctxt = outdated ctxt in + let g = (ctxt, sc) in + (step [@ocaml.tailcall]) g gas k ks power (accu, stack) + | IKeccak (_, k) -> + let bytes = accu in + let hash = Raw_hashes.keccak256 bytes in + (step [@ocaml.tailcall]) g gas k ks hash stack + | ISha3 (_, k) -> + let bytes = accu in + let hash = Raw_hashes.sha3_256 bytes in + (step [@ocaml.tailcall]) g gas k ks hash stack + | IAdd_bls12_381_g1 (_, k) -> + let x = accu and (y, stack) = stack in + let accu = Bls12_381.G1.add x y in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IAdd_bls12_381_g2 (_, k) -> + let x = accu and (y, stack) = stack in + let accu = Bls12_381.G2.add x y in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IAdd_bls12_381_fr (_, k) -> + let x = accu and (y, stack) = stack in + let accu = Bls12_381.Fr.add x y in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IMul_bls12_381_g1 (_, k) -> + let x = accu and (y, stack) = stack in + let accu = Bls12_381.G1.mul x y in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IMul_bls12_381_g2 (_, k) -> + let x = accu and (y, stack) = stack in + let accu = Bls12_381.G2.mul x y in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IMul_bls12_381_fr (_, k) -> + let x = accu and (y, stack) = stack in + let accu = Bls12_381.Fr.mul x y in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IMul_bls12_381_fr_z (_, k) -> + let x = accu and (y, stack) = stack in + let x = Bls12_381.Fr.of_z (Script_int.to_zint x) in + let res = Bls12_381.Fr.mul x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IMul_bls12_381_z_fr (_, k) -> + let y = accu and (x, stack) = stack in + let x = Bls12_381.Fr.of_z (Script_int.to_zint x) in + let res = Bls12_381.Fr.mul x y in + (step [@ocaml.tailcall]) g gas k ks res stack + | IInt_bls12_381_fr (_, k) -> + let x = accu in + let res = Script_int.of_zint (Bls12_381.Fr.to_z x) in + (step [@ocaml.tailcall]) g gas k ks res stack + | INeg_bls12_381_g1 (_, k) -> + let x = accu in + let accu = Bls12_381.G1.negate x in + (step [@ocaml.tailcall]) g gas k ks accu stack + | INeg_bls12_381_g2 (_, k) -> + let x = accu in + let accu = Bls12_381.G2.negate x in + (step [@ocaml.tailcall]) g gas k ks accu stack + | INeg_bls12_381_fr (_, k) -> + let x = accu in + let accu = Bls12_381.Fr.negate x in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IPairing_check_bls12_381 (_, k) -> + let pairs = accu in + let check = + match pairs.elements with + | [] -> true + | pairs -> + Bls12_381.( + miller_loop pairs |> final_exponentiation_opt + |> Option.map Gt.(eq one)) + |> Option.value ~default:false + in + (step [@ocaml.tailcall]) g gas k ks check stack + | IComb (_, _, witness, k) -> + let rec aux : + type before after. + (before, after) comb_gadt_witness -> before -> after = + fun witness stack -> + match (witness, stack) with + | (Comb_one, stack) -> stack + | (Comb_succ witness', (a, tl)) -> + let (b, tl') = aux witness' tl in + ((a, b), tl') + in + let stack = aux witness (accu, stack) in + let (accu, stack) = stack in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IUncomb (_, _, witness, k) -> + let rec aux : + type before after. + (before, after) uncomb_gadt_witness -> before -> after = + fun witness stack -> + match (witness, stack) with + | (Uncomb_one, stack) -> stack + | (Uncomb_succ witness', ((a, b), tl)) -> (a, aux witness' (b, tl)) + in + let stack = aux witness (accu, stack) in + let (accu, stack) = stack in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IComb_get (_, _, witness, k) -> + let comb = accu in + let rec aux : + type before after. + (before, after) comb_get_gadt_witness -> before -> after = + fun witness comb -> + match (witness, comb) with + | (Comb_get_zero, v) -> v + | (Comb_get_one, (a, _)) -> a + | (Comb_get_plus_two witness', (_, b)) -> aux witness' b + in + let accu = aux witness comb in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IComb_set (_, _, witness, k) -> + let value = accu and (comb, stack) = stack in + let rec aux : + type value before after. + (value, before, after) comb_set_gadt_witness -> + value -> + before -> + after = + fun witness value item -> + match (witness, item) with + | (Comb_set_zero, _) -> value + | (Comb_set_one, (_hd, tl)) -> (value, tl) + | (Comb_set_plus_two witness', (hd, tl)) -> + (hd, aux witness' value tl) + in + let accu = aux witness value comb in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IDup_n (_, _, witness, k) -> + let rec aux : + type before after. + (before, after) dup_n_gadt_witness -> before -> after = + fun witness stack -> + match (witness, stack) with + | (Dup_n_zero, (a, _)) -> a + | (Dup_n_succ witness', (_, tl)) -> aux witness' tl + in + let stack = (accu, stack) in + let accu = aux witness stack in + (step [@ocaml.tailcall]) g gas k ks accu stack + (* Tickets *) + | ITicket (_, k) -> + let contents = accu and (amount, stack) = stack in + let ticketer = (sc.self, "default") in + let accu = {ticketer; contents; amount} in + (step [@ocaml.tailcall]) g gas k ks accu stack + | IRead_ticket (_, k) -> + let {ticketer; contents; amount} = accu in + let stack = (accu, stack) in + let accu = (ticketer, (contents, amount)) in + (step [@ocaml.tailcall]) g gas k ks accu stack + | ISplit_ticket (_, k) -> + let ticket = accu and ((amount_a, amount_b), stack) = stack in + let result = + if + Compare.Int.( + Script_int.(compare (add_n amount_a amount_b) ticket.amount) = 0) + then + Some + ( {ticket with amount = amount_a}, + {ticket with amount = amount_b} ) + else None + in + (step [@ocaml.tailcall]) g gas k ks result stack + | IJoin_tickets (_, contents_ty, k) -> + let (ticket_a, ticket_b) = accu in + let result = + if + Compare.Int.( + Script_comparable.compare_address + ticket_a.ticketer + ticket_b.ticketer + = 0 + && Script_comparable.compare_comparable + contents_ty + ticket_a.contents + ticket_b.contents + = 0) + then + Some + { + ticketer = ticket_a.ticketer; + contents = ticket_a.contents; + amount = Script_int.add_n ticket_a.amount ticket_b.amount; + } + else None + in + (step [@ocaml.tailcall]) g gas k ks result stack + | IOpen_chest (_, k) -> + let open Timelock in + let chest_key = accu in + let (chest, (time_z, stack)) = stack in + (* If the time is not an integer we then consider the proof as + incorrect. Indeed the verification asks for an integer for practical reasons. + Therefore no proof can be correct.*) + let accu = + match Alpha_context.Script_int.to_int time_z with + | None -> R false + | Some time -> ( + match open_chest chest chest_key ~time with + | Correct bytes -> L bytes + | Bogus_cipher -> R false + | Bogus_opening -> R true) + in + (step [@ocaml.tailcall]) g gas k ks accu stack) + +(* + + Zero-cost logging + ================= + +*) + +(* + + The following functions insert a logging instruction and modify the + continuation to continue the logging process in the next execution + steps. + + There is a special treatment of instructions that generate fresh + continuations: we pass a constructor as argument to their + evaluation rules so that they can instrument these fresh + continuations by themselves. + + This on-the-fly instrumentation of the execution allows zero-cost + logging since logging instructions are only introduced if an + initial logging continuation is pushed in the initial continuation + that starts the evaluation. + +*) +and log : + type a s b t r f. logger * logging_event -> (a, s, b, t, r, f) step_type = + fun (logger, event) ((ctxt, _) as g) gas k ks accu stack -> + (match (k, event) with + | (ILog _, LogEntry) -> () + | (_, LogEntry) -> log_entry logger ctxt gas k accu stack + | (_, LogExit prev_kinfo) -> log_exit logger ctxt gas prev_kinfo k accu stack) ; + let k = log_next_kinstr logger k in + let with_log k = match k with KLog _ -> k | _ -> KLog (k, logger) in + match k with + | IList_map (_, body, k) -> + (ilist_map [@ocaml.tailcall]) with_log g gas (body, k) ks accu stack + | IList_iter (_, body, k) -> + (ilist_iter [@ocaml.tailcall]) with_log g gas (body, k) ks accu stack + | ISet_iter (_, body, k) -> + (iset_iter [@ocaml.tailcall]) with_log g gas (body, k) ks accu stack + | IMap_map (_, body, k) -> + (imap_map [@ocaml.tailcall]) with_log g gas (body, k) ks accu stack + | IMap_iter (_, body, k) -> + (imap_iter [@ocaml.tailcall]) with_log g gas (body, k) ks accu stack + | ILoop (_, body, k) -> + let ks = with_log (KLoop_in (body, KCons (k, ks))) in + (next [@ocaml.tailcall]) g gas ks accu stack + | ILoop_left (_, bl, br) -> + let ks = with_log (KLoop_in_left (bl, KCons (br, ks))) in + (next [@ocaml.tailcall]) g gas ks accu stack + | IMul_teznat (kinfo, k) -> + let extra = (kinfo, k) in + (imul_teznat [@ocaml.tailcall]) (Some logger) g gas extra ks accu stack + | IMul_nattez (kinfo, k) -> + let extra = (kinfo, k) in + (imul_nattez [@ocaml.tailcall]) (Some logger) g gas extra ks accu stack + | ILsl_nat (kinfo, k) -> + let extra = (kinfo, k) in + (ilsl_nat [@ocaml.tailcall]) (Some logger) g gas extra ks accu stack + | ILsr_nat (kinfo, k) -> + let extra = (kinfo, k) in + (ilsr_nat [@ocaml.tailcall]) (Some logger) g gas extra ks accu stack + | IFailwith (_, kloc, tv) -> + (ifailwith [@ocaml.tailcall]) (Some logger) g gas kloc tv accu + | IExec (_, k) -> + (iexec [@ocaml.tailcall]) (Some logger) g gas k ks accu stack + | _ -> (step [@ocaml.tailcall]) g gas k (with_log ks) accu stack + [@@inline] + +and klog : + type a s r f. + logger -> + outdated_context * step_constants -> + local_gas_counter -> + (a, s, r, f) continuation -> + (a, s, r, f) continuation -> + a -> + s -> + (r * f * outdated_context * local_gas_counter) tzresult Lwt.t = + fun logger g gas ks0 ks accu stack -> + (match ks with KLog _ -> () | _ -> log_control logger ks) ; + let enable_log ki = log_kinstr logger ki in + let mk k = match k with KLog _ -> k | _ -> KLog (k, logger) in + match ks with + | KCons (ki, ks') -> + let log = enable_log ki in + let ks = mk ks' in + (step [@ocaml.tailcall]) g gas log ks accu stack + | KNil -> (next [@ocaml.tailcall]) g gas ks accu stack + | KLoop_in (ki, ks') -> + let ks' = mk ks' in + let ki = enable_log ki in + (kloop_in [@ocaml.tailcall]) g gas ks0 ki ks' accu stack + | KReturn (stack', ks') -> + let ks' = mk ks' in + let ks = KReturn (stack', ks') in + (next [@ocaml.tailcall]) g gas ks accu stack + | KLoop_in_left (ki, ks') -> + let ks' = mk ks' in + let ki = enable_log ki in + (kloop_in_left [@ocaml.tailcall]) g gas ks0 ki ks' accu stack + | KUndip (x, ks') -> + let ks' = mk ks' in + let ks = KUndip (x, ks') in + (next [@ocaml.tailcall]) g gas ks accu stack + | KIter (body, xs, ks') -> + let ks' = mk ks' in + let body = enable_log body in + (kiter [@ocaml.tailcall]) mk g gas (body, xs) ks' accu stack + | KList_enter_body (body, xs, ys, len, ks') -> + let ks' = mk ks' in + let extra = (body, xs, ys, len) in + (klist_enter [@ocaml.tailcall]) mk g gas extra ks' accu stack + | KList_exit_body (body, xs, ys, len, ks') -> + let ks' = mk ks' in + let extra = (body, xs, ys, len) in + (klist_exit [@ocaml.tailcall]) mk g gas extra ks' accu stack + | KMap_enter_body (body, xs, ys, ks') -> + let ks' = mk ks' in + (kmap_enter [@ocaml.tailcall]) mk g gas (body, xs, ys) ks' accu stack + | KMap_exit_body (body, xs, ys, yk, ks') -> + let ks' = mk ks' in + (kmap_exit [@ocaml.tailcall]) mk g gas (body, xs, ys, yk) ks' accu stack + | KLog (_, _) -> + (* This case should never happen. *) + (next [@ocaml.tailcall]) g gas ks accu stack + [@@inline] + +(* + + Entrypoints + =========== + +*) + +let step_descr ~log_now logger (ctxt, sc) descr accu stack = + let gas = (Gas.remaining_operation_gas ctxt :> int) in + (match logger with + | None -> step (outdated ctxt, sc) gas descr.kinstr KNil accu stack + | Some logger -> + (if log_now then + let kinfo = kinfo_of_kinstr descr.kinstr in + logger.log_interp descr.kinstr ctxt kinfo.iloc descr.kbef (accu, stack)) ; + let log = + ILog (kinfo_of_kinstr descr.kinstr, LogEntry, logger, descr.kinstr) + in + step (outdated ctxt, sc) gas log KNil accu stack) + >>=? fun (accu, stack, ctxt, gas) -> + return (accu, stack, update_context gas ctxt) + +let interp logger g (Lam (code, _)) arg = + step_descr ~log_now:true logger g code arg (EmptyCell, EmptyCell) + >|=? fun (ret, (EmptyCell, EmptyCell), ctxt) -> (ret, ctxt) + +let kstep logger ctxt step_constants kinstr accu stack = + let gas = (Gas.remaining_operation_gas ctxt :> int) in + let kinstr = + match logger with + | None -> kinstr + | Some logger -> ILog (kinfo_of_kinstr kinstr, LogEntry, logger, kinstr) + in + step (outdated ctxt, step_constants) gas kinstr KNil accu stack + >>=? fun (accu, stack, ctxt, gas) -> + return (accu, stack, update_context gas ctxt) + +let internal_step ctxt step_constants gas kinstr accu stack = + step (ctxt, step_constants) gas kinstr KNil accu stack + +let step logger ctxt step_constants descr stack = + step_descr ~log_now:false logger (ctxt, step_constants) descr stack + +(* + + High-level functions + ==================== + +*) +let execute logger ctxt mode step_constants ~entrypoint ~internal + unparsed_script cached_script arg : + (Script.expr + * packed_internal_operation list + * context + * Lazy_storage.diffs option + * ex_script + * int) + tzresult + Lwt.t = + (match cached_script with + | None -> + parse_script + ctxt + unparsed_script + ~legacy:true + ~allow_forged_in_storage:true + | Some ex_script -> return (ex_script, ctxt)) + >>=? fun ( Ex_script + { + code_size; + code; + arg_type; + storage; + storage_type; + root_name; + views; + }, + ctxt ) -> + record_trace + (Bad_contract_parameter step_constants.self) + (find_entrypoint arg_type ~root_name entrypoint) + >>?= fun (box, _) -> + trace + (Bad_contract_parameter step_constants.self) + (parse_data ctxt ~legacy:false ~allow_forged:internal arg_type (box arg)) + >>=? fun (arg, ctxt) -> + Script.force_decode_in_context ctxt unparsed_script.code + >>?= fun (script_code, ctxt) -> + Script_ir_translator.collect_lazy_storage ctxt arg_type arg + >>?= fun (to_duplicate, ctxt) -> + Script_ir_translator.collect_lazy_storage ctxt storage_type storage + >>?= fun (to_update, ctxt) -> + trace + (Runtime_contract_error (step_constants.self, script_code)) + (interp logger (ctxt, step_constants) code (arg, storage)) + >>=? fun ((ops, storage), ctxt) -> + Script_ir_translator.extract_lazy_storage_diff + ctxt + mode + ~temporary:false + ~to_duplicate + ~to_update + storage_type + storage + >>=? fun (storage, lazy_storage_diff, ctxt) -> + trace + Cannot_serialize_storage + ( unparse_data ctxt mode storage_type storage + >>=? fun (unparsed_storage, ctxt) -> + Lwt.return + ( Gas.consume ctxt (Script.strip_locations_cost unparsed_storage) + >>? fun ctxt -> ok (Micheline.strip_locations unparsed_storage, ctxt) ) + ) + >>=? fun (unparsed_storage, ctxt) -> + Lwt.return + (let (ops, op_diffs) = List.split ops.elements in + let lazy_storage_diff = + match + List.flatten + (List.map + (Option.value ~default:[]) + (op_diffs @ [lazy_storage_diff])) + with + | [] -> None + | diff -> Some diff + in + let script = + Ex_script + {code_size; code; arg_type; storage; storage_type; root_name; views} + in + (* We consume gas after the fact in order to not have to instrument + [script_size] (for efficiency). + This is safe, as we already pay gas proportional to storage size + in [unparse_data]. *) + let (size, cost) = Script_ir_translator.script_size script in + Gas.consume ctxt cost >>? fun ctxt -> + ok (unparsed_storage, ops, ctxt, lazy_storage_diff, script, size)) + +type execution_result = { + ctxt : context; + storage : Script.expr; + lazy_storage_diff : Lazy_storage.diffs option; + operations : packed_internal_operation list; +} + +let execute ?logger ctxt ~cached_script mode step_constants ~script ~entrypoint + ~parameter ~internal = + execute + logger + ctxt + mode + step_constants + ~entrypoint + ~internal + script + cached_script + (Micheline.root parameter) + >|=? fun (storage, operations, ctxt, lazy_storage_diff, ex_script, approx_size) + -> ({ctxt; storage; lazy_storage_diff; operations}, (ex_script, approx_size)) + +(* + + Internals + ========= + +*) + +(* + + We export the internals definitions for tool that requires + a white-box view on the interpreter, typically snoop, the + gas model inference engine. + +*) +module Internals = struct + type nonrec local_gas_counter = local_gas_counter + + type nonrec outdated_context = outdated_context = + | OutDatedContext of Alpha_context.t + [@@unboxed] + + let next logger g gas ks accu stack = + let ks = + match logger with None -> ks | Some logger -> KLog (ks, logger) + in + next g gas ks accu stack + + let step (ctxt, step_constants) gas ks accu stack = + internal_step ctxt step_constants gas ks accu stack +end diff --git a/src/proto_011_PtHangzH/lib_protocol/script_interpreter.mli b/src/proto_011_PtHangzH/lib_protocol/script_interpreter.mli new file mode 100644 index 000000000000..917c16eb5879 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_interpreter.mli @@ -0,0 +1,166 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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 is the Michelson interpreter. + + This module offers a way to execute either a Michelson script or a + Michelson instruction. + + Implementation details are documented in the .ml file. + +*) + +open Alpha_context +open Script_typed_ir + +type error += Reject of Script.location * Script.expr * execution_trace option + +type error += Overflow of Script.location * execution_trace option + +type error += Runtime_contract_error : Contract.t * Script.expr -> error + +type error += Bad_contract_parameter of Contract.t (* `Permanent *) + +type error += Cannot_serialize_failure + +type error += Cannot_serialize_storage + +type error += Michelson_too_many_recursive_calls + +type execution_result = { + ctxt : context; + storage : Script.expr; + lazy_storage_diff : Lazy_storage.diffs option; + operations : packed_internal_operation list; +} + +type step_constants = { + source : Contract.t; + payer : Contract.t; + self : Contract.t; + amount : Tez.t; + chain_id : Chain_id.t; +} + +val step : + logger option -> + context -> + step_constants -> + ('a, 's, 'r, 'f) Script_typed_ir.kdescr -> + 'a -> + 's -> + ('r * 'f * context) tzresult Lwt.t + +(** [execute ?logger ctxt ~cached_script mode step_constant ~script + ~entrypoint ~parameter ~internal] interprets the [script]'s + [entrypoint] for a given [parameter]. + + This will update the local storage of the contract + [step_constants.self]. Other pieces of contextual information + ([source], [payer], [amount], and [chaind_id]) are also passed in + [step_constant]. + + [internal] is [true] if and only if the execution happens within an + internal operation. + + [mode] is the unparsing mode, as declared by + {!Script_ir_translator}. + + [cached_script] is the cached elaboration of [script], that is the + well typed abstract syntax tree produced by the type elaboration of + [script] during a previous execution and stored in the in-memory + cache. + +*) +val execute : + ?logger:logger -> + Alpha_context.t -> + cached_script:Script_ir_translator.ex_script option -> + Script_ir_translator.unparsing_mode -> + step_constants -> + script:Script.t -> + entrypoint:string -> + parameter:Script.expr -> + internal:bool -> + (execution_result * (Script_ir_translator.ex_script * int)) tzresult Lwt.t + +(** [kstep logger ctxt step_constants kinstr accu stack] interprets the + script represented by [kinstr] under the context [ctxt]. This will + turn a stack whose topmost element is [accu] and remaining elements + [stack] into a new accumulator and a new stack. This function also + returns an updated context. If [logger] is given, [kstep] calls back + its functions at specific points of the execution. The execution is + parameterized by some [step_constants]. *) +val kstep : + logger option -> + context -> + step_constants -> + ('a, 's, 'r, 'f) Script_typed_ir.kinstr -> + 'a -> + 's -> + ('r * 'f * context) tzresult Lwt.t + +(** Internal interpretation loop + ============================ + + The following types and the following functions are exposed + in the interface to allow the inference of a gas model in + snoop. + + Strictly speaking, they should not be considered as part of + the interface since they expose implementation details that + may change in the future. + +*) + +module Internals : sig + (** Internally, the interpretation loop uses a local gas counter. *) + type local_gas_counter = int + + (** During the evaluation, the gas level in the context is outdated. + See comments in the implementation file for more details. *) + type outdated_context = OutDatedContext of context [@@unboxed] + + (** [next logger (ctxt, step_constants) local_gas_counter ks accu + stack] is an internal function which interprets the continuation + [ks] to execute the interpreter on the current A-stack. *) + val next : + logger option -> + outdated_context * step_constants -> + local_gas_counter -> + ('a, 's, 'r, 'f) continuation -> + 'a -> + 's -> + ('r * 'f * outdated_context * local_gas_counter) tzresult Lwt.t + + val step : + outdated_context * step_constants -> + local_gas_counter -> + ('a, 's, 'r, 'f) Script_typed_ir.kinstr -> + 'a -> + 's -> + ('r * 'f * outdated_context * local_gas_counter) tzresult Lwt.t +end diff --git a/src/proto_011_PtHangzH/lib_protocol/script_interpreter_defs.ml b/src/proto_011_PtHangzH/lib_protocol/script_interpreter_defs.ml new file mode 100644 index 000000000000..b20f78f91354 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_interpreter_defs.ml @@ -0,0 +1,962 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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 + +(* + + 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 (map, _) = stack in + Interp_costs.big_map_mem map.diff + | IBig_map_get _ -> + let (map, _) = stack in + Interp_costs.big_map_get map.diff + | IBig_map_update _ -> + let (_, (map, _)) = stack in + Interp_costs.big_map_update map.diff + | IBig_map_get_and_update _ -> + let (_, (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 = 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 + | IMul_teznat _ -> Interp_costs.mul_teznat + | IMul_nattez _ -> Interp_costs.mul_nattez + | IAbs_int _ -> + let x = accu in + Interp_costs.abs_int x + | INeg_int _ -> + let x = accu in + Interp_costs.neg_int x + | INeg_nat _ -> + let x = accu in + Interp_costs.neg_nat x + | IAdd_intint _ -> + let x = accu and (y, _) = stack in + Interp_costs.add_intint x y + | IAdd_intnat _ -> + let x = accu and (y, _) = stack in + Interp_costs.add_intnat x y + | IAdd_natint _ -> + let x = accu and (y, _) = stack in + Interp_costs.add_natint x y + | IAdd_natnat _ -> + let x = accu and (y, _) = stack in + Interp_costs.add_natnat x y + | ISub_int _ -> + let x = accu and (y, _) = stack in + Interp_costs.sub_int x y + | IMul_intint _ -> + let x = accu and (y, _) = stack in + Interp_costs.mul_intint x y + | IMul_intnat _ -> + let x = accu and (y, _) = stack in + Interp_costs.mul_intnat x y + | IMul_natint _ -> + let x = accu and (y, _) = stack in + Interp_costs.mul_natint x y + | IMul_natnat _ -> + let x = accu and (y, _) = stack in + Interp_costs.mul_natnat x y + | IEdiv_teznat _ -> + let x = accu and (y, _) = stack in + Interp_costs.ediv_teznat x y + | IEdiv_intint _ -> + let x = accu and (y, _) = stack in + Interp_costs.ediv_intint x y + | IEdiv_intnat _ -> + let x = accu and (y, _) = stack in + Interp_costs.ediv_intnat x y + | IEdiv_natint _ -> + let x = accu and (y, _) = stack in + Interp_costs.ediv_natint x y + | IEdiv_natnat _ -> + let x = accu and (y, _) = stack in + Interp_costs.ediv_natnat x y + | ILsl_nat _ -> + let x = accu in + Interp_costs.lsl_nat x + | ILsr_nat _ -> + let x = accu in + Interp_costs.lsr_nat x + | IOr_nat _ -> + let x = accu and (y, _) = stack in + Interp_costs.or_nat 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 + | IXor_nat _ -> + let x = accu and (y, _) = stack in + Interp_costs.xor_nat x y + | INot_int _ -> + let x = accu in + Interp_costs.not_int x + | INot_nat _ -> + let x = accu in + Interp_costs.not_nat 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 = List.length tx.inputs in + let outputs = List.length tx.outputs in + Interp_costs.sapling_verify_update ~inputs ~outputs + | ISplit_ticket _ -> + let ticket = accu and ((amount_a, amount_b), _) = stack in + Interp_costs.split_ticket ticket.amount 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 + | IConst _ -> Interp_costs.const + | ICons_some _ -> Interp_costs.cons_some + | ICons_none _ -> Interp_costs.cons_none + | IIf_none _ -> Interp_costs.if_none + | 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 + | 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 _ -> Interp_costs.apply + | 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 + | 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 _ -> Interp_costs.ticket + | IRead_ticket _ -> Interp_costs.read_ticket + | IOpen_chest _ -> + let _chest_key = accu and (chest, (time, _)) = stack in + Interp_costs.open_chest + ~chest + ~time:(Alpha_context.Script_int.to_zint time) + | ILog _ -> Gas.free + [@@ocaml.inline always] + [@@coq_axiom_with_reason "unreachable expression `.` not handled"] + +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 + | 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 (_, _, _, _) -> Interp_costs.Control.map_enter_body + | KMap_exit_body (_, _, map, key, _) -> + Interp_costs.Control.map_exit_body key map + +(* + + Gas update and check for gas exhaustion + ======================================= + + Each instruction has a cost. The runtime subtracts this cost + from an amount of gas made available for the script execution. + + Updating the gas counter is a critical aspect to Michelson + execution because it is done at each execution step. + + For this reason, the interpreter must read and update the + gas counter as quickly as possible. Hence, the gas counter + should be stored in a machine register. To motivate the + OCaml compiler to make that choice, we represent the gas + counter as a local parameter of the execution [step] + function. + +*) + +type local_gas_counter = int + +(* + + The gas counter stored in the context is desynchronized with the + [local_gas_counter] used in the interpretation loop. When we have + to call a gas-consuming function which lives outside the + interpreter, we must update the context so that it carries an + up-to-date gas counter. Similarly, when we return from such a + function, the [local_gas_counter] must be updated as well. + + To statically track these points where the context's gas counter + must be updated, we introduce a type for outdated contexts. The + [step] function carries an [outdated_context]. When an external + function needs a [context], the typechecker points out the need for + a conversion: this forces us to either call [update_context], or + better, when this is possible, the function + [use_gas_counter_in_ctxt]. + +*) +type outdated_context = OutDatedContext of context [@@unboxed] + +let update_context local_gas_counter = function + | OutDatedContext ctxt -> + Gas.update_remaining_operation_gas + ctxt + (Saturation_repr.safe_int local_gas_counter) + [@@ocaml.inline always] + +let update_local_gas_counter ctxt = + (Gas.remaining_operation_gas ctxt :> int) + [@@ocaml.inline always] + +let outdated ctxt = OutDatedContext ctxt [@@ocaml.inline always] + +let context_from_outdated_context (OutDatedContext ctxt) = + ctxt + [@@ocaml.inline always] + +let use_gas_counter_in_ctxt ctxt local_gas_counter f = + let ctxt = update_context local_gas_counter ctxt in + f ctxt >>=? fun (y, ctxt) -> + return (y, outdated ctxt, update_local_gas_counter ctxt) + [@@ocaml.inline always] + +(* + + [step] calls [consume] at the beginning of each execution step. + + [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 update_and_check gas_counter (cost : Gas.cost) = + let gas_counter = gas_counter - (cost :> int) in + if Compare.Int.(gas_counter < 0) then None else Some gas_counter + [@@ocaml.inline always] + +let consume local_gas_counter k accu stack = + let cost = cost_of_instr k accu stack in + update_and_check local_gas_counter cost + [@@ocaml.inline always] + +let consume' ctxt local_gas_counter cost = + match update_and_check local_gas_counter cost with + | None -> Gas.gas_exhausted_error (update_context local_gas_counter ctxt) + | Some local_gas_counter -> Ok local_gas_counter + [@@ocaml.inline always] + +let consume_control local_gas_counter ks = + let cost = cost_of_control ks in + update_and_check local_gas_counter cost + [@@ocaml.inline always] + +(* + + Auxiliary functions used by the instrumentation + =============================================== + +*) + +let log_entry logger ctxt gas k accu stack = + let kinfo = kinfo_of_kinstr k in + let ctxt = update_context gas ctxt in + logger.log_entry k ctxt kinfo.iloc kinfo.kstack_ty (accu, stack) + +let log_exit logger ctxt gas kinfo_prev k accu stack = + let kinfo = kinfo_of_kinstr k in + let ctxt = update_context gas ctxt in + logger.log_exit k ctxt kinfo_prev.iloc kinfo.kstack_ty (accu, stack) + +let log_control logger ks = logger.log_control ks + +let get_log = function + | None -> Lwt.return (Ok None) + | Some logger -> logger.get_log () + [@@ocaml.inline always] + +(* [log_kinstr logger i] emits an instruction to instrument the + execution of [i] with [logger]. *) +let log_kinstr logger i = ILog (kinfo_of_kinstr i, LogEntry, logger, i) + +(* [log_next_kinstr logger i] instruments the next instruction of [i] + with the [logger]. + + Notice that the instrumentation breaks the sharing of continuations + that is normally enforced between branches of conditionals. This + has a performance cost. Anyway, the instrumentation allocates many + new [ILog] instructions and [KLog] continuations which makes + the execution of instrumented code significantly slower than + non-instrumented code. "Zero-cost logging" means that the normal + non-instrumented execution is not impacted by the ability to + instrument it, not that the logging itself has no cost. + +*) +let log_next_kinstr logger i = + let apply k = + ILog + ( kinfo_of_kinstr k, + LogExit (kinfo_of_kinstr i), + logger, + log_kinstr logger k ) + in + kinstr_rewritek i {apply} + +(* We pass the identity function when no instrumentation is needed. *) +let id x = x [@@inline] + +(* + + Interpreter parameters + ====================== + +*) +type step_constants = { + source : Contract.t; + payer : Contract.t; + self : Contract.t; + amount : Tez.t; + chain_id : Chain_id.t; +} + +(* + + 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 (kinfo, w) -> + let k = IConst (kinfo, 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 (Lam (descr, expr)) = lam in + let (Item_t (full_arg_ty, _, _)) = descr.kbef in + let ctxt = update_context gas ctxt in + unparse_data ctxt Optimized capture_ty capture >>=? fun (const_expr, ctxt) -> + unparse_ty ctxt capture_ty >>?= fun (ty_expr, ctxt) -> + match full_arg_ty with + | Pair_t ((capture_ty, _, _), (arg_ty, _, _), _) -> + let arg_stack_ty = Item_t (arg_ty, Bot_t, None) in + let full_descr = + { + kloc = descr.kloc; + kbef = arg_stack_ty; + kaft = descr.kaft; + kinstr = + (let kinfo_const = {iloc = descr.kloc; kstack_ty = arg_stack_ty} in + let kinfo_pair = + { + iloc = descr.kloc; + kstack_ty = Item_t (capture_ty, arg_stack_ty, None); + } + in + IConst (kinfo_const, capture, ICons_pair (kinfo_pair, descr.kinstr))); + } + in + let full_expr = + Micheline.Seq + ( 0, + [ + Prim (0, I_PUSH, [ty_expr; const_expr], []); + Prim (0, I_PAIR, [], []); + expr; + ] ) + in + let lam' = Lam (full_descr, full_expr) in + let gas = update_local_gas_counter ctxt in + return (lam', outdated ctxt, gas) + | _ -> assert false + +(* [transfer (ctxt, sc) gas tez tp p destination entrypoint] + creates an operation that transfers an amount of [tez] to + a contract determined by [(destination, entrypoint)] + instantiated with argument [p] of type [tp]. *) +let transfer (ctxt, sc) gas amount tp p destination entrypoint = + let ctxt = update_context gas ctxt in + collect_lazy_storage ctxt tp p >>?= fun (to_duplicate, ctxt) -> + let to_update = no_lazy_storage_id in + extract_lazy_storage_diff + ctxt + Optimized + tp + p + ~to_duplicate + ~to_update + ~temporary:true + >>=? fun (p, lazy_storage_diff, ctxt) -> + unparse_data ctxt Optimized tp p >>=? fun (p, ctxt) -> + Gas.consume ctxt (Script.strip_locations_cost p) >>?= fun ctxt -> + let operation = + Transaction + { + amount; + destination; + entrypoint; + parameters = Script.lazy_expr (Micheline.strip_locations p); + } + in + fresh_internal_nonce ctxt >>?= fun (ctxt, nonce) -> + let iop = {source = sc.self; operation; nonce} in + let res = (Internal_operation iop, lazy_storage_diff) in + let gas = update_local_gas_counter ctxt in + let ctxt = outdated ctxt in + return (res, ctxt, gas) + +(* [create_contract (ctxt, sc) gas storage_ty param_ty code root_name + delegate credit init] creates an origination operation for a + contract represented by [code], with some [root_name], some initial + [credit] (taken to contract being executed), and an initial storage + [init] of type [storage_ty]. The type of the new contract argument + is [param_ty]. *) + +(* TODO: https://gitlab.com/tezos/tezos/-/issues/1688 + Refactor the sharing part of unparse_script and create_contract *) +let create_contract (ctxt, sc) gas storage_type param_type code views root_name + delegate credit init = + let ctxt = update_context gas ctxt in + unparse_ty ctxt param_type >>?= fun (unparsed_param_type, ctxt) -> + let unparsed_param_type = + Script_ir_translator.add_field_annot root_name None unparsed_param_type + in + unparse_ty ctxt storage_type >>?= fun (unparsed_storage_type, ctxt) -> + let open Micheline in + let view name {input_ty; output_ty; view_code} views = + Prim + ( 0, + K_view, + [ + String (0, Script_string.to_string name); + input_ty; + output_ty; + view_code; + ], + [] ) + :: views + in + let views = SMap.fold view views [] |> List.rev in + let code = + strip_locations + (Seq + ( 0, + [ + Prim (0, K_parameter, [unparsed_param_type], []); + Prim (0, K_storage, [unparsed_storage_type], []); + Prim (0, K_code, [code], []); + ] + @ views )) + 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 (storage, ctxt) -> + Gas.consume ctxt (Script.strip_locations_cost storage) >>?= fun ctxt -> + let storage = strip_locations storage in + Contract.fresh_contract_from_current_nonce ctxt >>?= fun (ctxt, contract) -> + let operation = + Origination + { + credit; + delegate; + preorigination = Some contract; + script = + {code = Script.lazy_expr code; storage = Script.lazy_expr storage}; + } + in + fresh_internal_nonce ctxt >>?= fun (ctxt, nonce) -> + let res = + (Internal_operation {source = sc.self; operation; nonce}, lazy_storage_diff) + in + let gas = update_local_gas_counter ctxt in + let ctxt = outdated ctxt in + return (res, contract, 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 bytes = Bytes.sub bytes 1 (Bytes.length bytes - 1) in + match Data_encoding.Binary.of_bytes_opt Script.expr_encoding bytes with + | None -> + Lwt.return + ( Gas.consume ctxt (Interp_costs.unpack_failed bytes) >|? fun ctxt -> + (None, ctxt) ) + | Some expr -> ( + parse_data + ctxt + ~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 bytes) >|? 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: + +*) + +type ('a, 's, 'b, 't, 'r, 'f) step_type = + outdated_context * step_constants -> + local_gas_counter -> + ('a, 's, 'b, 't) kinstr -> + ('b, 't, 'r, 'f) continuation -> + 'a -> + 's -> + ('r * 'f * outdated_context * local_gas_counter) tzresult Lwt.t + +type ('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'm, 'n, 'o) kmap_exit_type = + (('c, 'd, 'e, 'f) continuation -> ('a, 'b, 'g, 'h) continuation) -> + outdated_context * step_constants -> + local_gas_counter -> + ('m * 'n, 'c * 'd, 'o, 'c * 'd) kinstr * ('m * 'n) list * ('m, 'o) map * 'm -> + (('m, 'o) map, 'c * 'd, 'e, 'f) continuation -> + 'o -> + 'a * 'b -> + ('g * 'h * outdated_context * local_gas_counter) tzresult Lwt.t + +type ('a, 'b, 'c, 'd, 'e, 'j, 'k) kmap_enter_type = + (('a, 'b * 'c, 'd, 'e) continuation -> ('a, 'b * 'c, 'd, 'e) continuation) -> + outdated_context * step_constants -> + local_gas_counter -> + ('j * 'k, 'b * 'c, 'a, 'b * 'c) kinstr * ('j * 'k) list * ('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, 'i, 'j) klist_exit_type = + (('a, 'b, 'c, 'd) continuation -> ('a, 'b, 'c, 'd) continuation) -> + outdated_context * step_constants -> + local_gas_counter -> + ('i, 'a * 'b, 'j, 'a * 'b) kinstr * 'i list * 'j list * local_gas_counter -> + ('j boxed_list, 'a * 'b, 'c, 'd) continuation -> + 'j -> + 'a * 'b -> + ('c * 'd * outdated_context * local_gas_counter) tzresult Lwt.t + +type ('a, 'b, 'c, 'd, 'e, 'j) klist_enter_type = + (('b, 'a * 'c, 'd, 'e) continuation -> ('b, 'a * 'c, 'd, 'e) continuation) -> + outdated_context * step_constants -> + local_gas_counter -> + ('j, 'a * 'c, 'b, 'a * 'c) kinstr * 'j list * 'b list * local_gas_counter -> + ('b boxed_list, '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) union -> + '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) kiter_type = + (('a, 's, 'r, 'f) continuation -> ('a, 's, 'r, 'f) continuation) -> + outdated_context * step_constants -> + local_gas_counter -> + ('b, 'a * 's, 'a, 's) kinstr * '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) ilist_map_type = + (('a, 'b, 'c, 'd) continuation -> ('a, 'b, 'c, 'd) continuation) -> + outdated_context * step_constants -> + local_gas_counter -> + ('e, 'a * 'b, 'f, 'a * 'b) kinstr * ('f boxed_list, 'a * 'b, 'g, 'h) kinstr -> + ('g, 'h, 'c, 'd) continuation -> + 'e boxed_list -> + 'a * 'b -> + ('c * 'd * outdated_context * local_gas_counter) tzresult Lwt.t + +type ('a, 'b, 'c, 'd, 'e, 'f, 'g) ilist_iter_type = + (('a, 'b, 'c, 'd) continuation -> ('a, 'b, 'c, 'd) continuation) -> + outdated_context * step_constants -> + local_gas_counter -> + ('e, 'a * 'b, 'a, 'b) kinstr * ('a, 'b, 'f, 'g) kinstr -> + ('f, 'g, 'c, 'd) continuation -> + 'e boxed_list -> + '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) continuation -> ('a, 'b, 'c, 'd) continuation) -> + outdated_context * step_constants -> + local_gas_counter -> + ('e, 'a * 'b, 'a, 'b) kinstr * ('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) imap_map_type = + (('a, 'b, 'c, 'd) continuation -> ('a, 'b, 'c, 'd) continuation) -> + 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, 'f) map -> + 'a * 'b -> + ('c * 'd * outdated_context * local_gas_counter) tzresult Lwt.t + +type ('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h) imap_iter_type = + (('a, 'b, 'c, 'd) continuation -> ('a, 'b, 'c, 'd) continuation) -> + outdated_context * step_constants -> + local_gas_counter -> + ('e * 'f, 'a * 'b, 'a, 'b) kinstr * ('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 -> + (Tez.t, 'a) kinfo * (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_int.n Script_int.num, 'a) kinfo * (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_int.n Script_int.num, 'a) kinfo + * (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_int.n Script_int.num, 'a) kinfo + * (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) ifailwith_type = + logger option -> + outdated_context * step_constants -> + local_gas_counter -> + int -> + 'a ty -> + 'a -> + ('b, error trace) result Lwt.t + +type ('a, 'b, 'c, 'd, 'e, 'f, 'g) iexec_type = + logger option -> + outdated_context * step_constants -> + local_gas_counter -> + ('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 diff --git a/src/proto_011_PtHangzH/lib_protocol/script_ir_annot.ml b/src/proto_011_PtHangzH/lib_protocol/script_ir_annot.ml new file mode 100644 index 000000000000..1eed346a893f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_ir_annot.ml @@ -0,0 +1,513 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Micheline +open Script_tc_errors +open Script_typed_ir + +let default_now_annot = Some (Var_annot "now") + +let default_amount_annot = Some (Var_annot "amount") + +let default_balance_annot = Some (Var_annot "balance") + +let default_level_annot = Some (Var_annot "level") + +let default_steps_annot = Some (Var_annot "steps") + +let default_source_annot = Some (Var_annot "source") + +let default_sender_annot = Some (Var_annot "sender") + +let default_self_annot = Some (Var_annot "self") + +let default_arg_annot = Some (Var_annot "arg") + +let default_param_annot = Some (Var_annot "parameter") + +let default_storage_annot = Some (Var_annot "storage") + +let default_car_annot = Some (Field_annot "car") + +let default_cdr_annot = Some (Field_annot "cdr") + +let default_contract_annot = Some (Field_annot "contract") + +let default_addr_annot = Some (Field_annot "address") + +let default_manager_annot = Some (Field_annot "manager") + +let default_pack_annot = Some (Field_annot "packed") + +let default_unpack_annot = Some (Field_annot "unpacked") + +let default_slice_annot = Some (Field_annot "slice") + +let default_elt_annot = Some (Field_annot "elt") + +let default_key_annot = Some (Field_annot "key") + +let default_hd_annot = Some (Field_annot "hd") + +let default_tl_annot = Some (Field_annot "tl") + +let default_some_annot = Some (Field_annot "some") + +let default_left_annot = Some (Field_annot "left") + +let default_right_annot = Some (Field_annot "right") + +let default_binding_annot = Some (Field_annot "bnd") + +let default_sapling_state_annot = Some (Var_annot "sapling") + +let default_sapling_balance_annot = Some (Var_annot "sapling_balance") + +let unparse_type_annot : type_annot option -> string list = function + | None -> [] + | Some (Type_annot a) -> [":" ^ a] + +let unparse_var_annot : var_annot option -> string list = function + | None -> [] + | Some (Var_annot a) -> ["@" ^ a] + +let unparse_field_annot : field_annot option -> string list = function + | None -> [] + | Some (Field_annot a) -> ["%" ^ a] + +let field_to_var_annot : field_annot option -> var_annot option = function + | None -> None + | Some (Field_annot s) -> Some (Var_annot s) + +let type_to_var_annot : type_annot option -> var_annot option = function + | None -> None + | Some (Type_annot s) -> Some (Var_annot s) + +let var_to_field_annot : var_annot option -> field_annot option = function + | None -> None + | Some (Var_annot s) -> Some (Field_annot s) + +let default_annot ~default = function None -> default | annot -> annot + +let gen_access_annot : + var_annot option -> + ?default:field_annot option -> + field_annot option -> + var_annot option = + fun value_annot ?(default = None) field_annot -> + match (value_annot, field_annot, default) with + | (None, None, _) | (Some _, None, None) | (None, Some (Field_annot ""), _) -> + None + | (None, Some (Field_annot f), _) -> Some (Var_annot f) + | (Some (Var_annot v), (None | Some (Field_annot "")), Some (Field_annot f)) + -> + Some (Var_annot (String.concat "." [v; f])) + | (Some (Var_annot v), Some (Field_annot f), _) -> + Some (Var_annot (String.concat "." [v; f])) + +let merge_type_annot : + legacy:bool -> + type_annot option -> + type_annot option -> + type_annot option tzresult = + fun ~legacy annot1 annot2 -> + match (annot1, annot2) with + | (None, None) | (Some _, None) | (None, Some _) -> ok_none + | (Some (Type_annot a1), Some (Type_annot a2)) -> + if legacy || String.equal a1 a2 then ok annot1 + else error (Inconsistent_annotations (":" ^ a1, ":" ^ a2)) + +let merge_field_annot : + legacy:bool -> + field_annot option -> + field_annot option -> + field_annot option tzresult = + fun ~legacy annot1 annot2 -> + match (annot1, annot2) with + | (None, None) | (Some _, None) | (None, Some _) -> ok_none + | (Some (Field_annot a1), Some (Field_annot a2)) -> + if legacy || String.equal a1 a2 then ok annot1 + else error (Inconsistent_annotations ("%" ^ a1, "%" ^ a2)) + +let merge_var_annot : var_annot option -> var_annot option -> var_annot option = + fun annot1 annot2 -> + match (annot1, annot2) with + | (None, None) | (Some _, None) | (None, Some _) -> None + | (Some (Var_annot a1), Some (Var_annot a2)) -> + if String.equal a1 a2 then annot1 else None + +let error_unexpected_annot loc annot = + match annot with [] -> ok_unit | _ :: _ -> error (Unexpected_annotation loc) + +(* Check that the predicate p holds on all s.[k] for k >= i *) +let string_iter p s i = + let len = String.length s in + let rec aux i = + if Compare.Int.(i >= len) then ok_unit else p s.[i] >>? fun () -> aux (i + 1) + in + aux i + +let is_allowed_char = function + | 'a' .. 'z' | 'A' .. 'Z' | '_' | '.' | '%' | '@' | '0' .. '9' -> true + | _ -> false + +(* Valid annotation characters as defined by the allowed_annot_char function from lib_micheline/micheline_parser *) +let check_char loc c = + if is_allowed_char c then ok_unit else error (Unexpected_annotation loc) + +(* This constant is defined in lib_micheline/micheline_parser which is not available in the environment. *) +let max_annot_length = 255 + +type annot_opt = + | Field_annot_opt of string option + | Type_annot_opt of string option + | Var_annot_opt of string option + +let parse_annots loc ?(allow_special_var = false) ?(allow_special_field = false) + l = + (* allow empty annotations as wildcards but otherwise only accept + annotations that start with [a-zA-Z_] *) + let sub_or_wildcard ~specials wrap s acc = + let mem_char c cs = List.exists (Char.equal c) cs in + let len = String.length s in + (if Compare.Int.(len > max_annot_length) then + error (Unexpected_annotation loc) + else ok_unit) + >>? fun () -> + if Compare.Int.(len = 1) then ok @@ wrap None :: acc + else + match s.[1] with + | 'a' .. 'z' | 'A' .. 'Z' | '_' | '0' .. '9' -> + (* check that all characters are valid*) + string_iter (check_char loc) s 2 >>? fun () -> + ok @@ wrap (Some (String.sub s 1 (len - 1))) :: acc + | '@' when Compare.Int.(len = 2) && mem_char '@' specials -> + ok @@ wrap (Some "@") :: acc + | '%' when mem_char '%' specials -> + if Compare.Int.(len = 2) then ok @@ wrap (Some "%") :: acc + else if Compare.Int.(len = 3) && Compare.Char.(s.[2] = '%') then + ok @@ wrap (Some "%%") :: acc + else error (Unexpected_annotation loc) + | _ -> error (Unexpected_annotation loc) + in + List.fold_left_e + (fun acc s -> + if Compare.Int.(String.length s = 0) then + error (Unexpected_annotation loc) + else + match s.[0] with + | ':' -> sub_or_wildcard ~specials:[] (fun a -> Type_annot_opt a) s acc + | '@' -> + sub_or_wildcard + ~specials:(if allow_special_var then ['%'] else []) + (fun a -> Var_annot_opt a) + s + acc + | '%' -> + sub_or_wildcard + ~specials:(if allow_special_field then ['@'] else []) + (fun a -> Field_annot_opt a) + s + acc + | _ -> error (Unexpected_annotation loc)) + [] + l + >|? List.rev + +let opt_var_of_var_opt = function None -> None | Some a -> Some (Var_annot a) + +let opt_field_of_field_opt = function + | None -> None + | Some a -> Some (Field_annot a) + +let opt_type_of_type_opt = function + | None -> None + | Some a -> Some (Type_annot a) + +let classify_annot loc l : + (var_annot option list * type_annot option list * field_annot option list) + tzresult = + try + let (_, rv, _, rt, _, rf) = + List.fold_left + (fun (in_v, rv, in_t, rt, in_f, rf) a -> + match (a, in_v, rv, in_t, rt, in_f, rf) with + | (Var_annot_opt a, true, _, _, _, _, _) + | (Var_annot_opt a, false, [], _, _, _, _) -> + (true, opt_var_of_var_opt a :: rv, false, rt, false, rf) + | (Type_annot_opt a, _, _, true, _, _, _) + | (Type_annot_opt a, _, _, false, [], _, _) -> + (false, rv, true, opt_type_of_type_opt a :: rt, false, rf) + | (Field_annot_opt a, _, _, _, _, true, _) + | (Field_annot_opt a, _, _, _, _, false, []) -> + (false, rv, false, rt, true, opt_field_of_field_opt a :: rf) + | _ -> raise Exit) + (false, [], false, [], false, []) + l + in + ok (List.rev rv, List.rev rt, List.rev rf) + with Exit -> error (Ungrouped_annotations loc) + +let get_one_annot loc = function + | [] -> ok_none + | [a] -> ok a + | _ -> error (Unexpected_annotation loc) + +let get_two_annot loc = function + | [] -> ok (None, None) + | [a] -> ok (a, None) + | [a; b] -> ok (a, b) + | _ -> error (Unexpected_annotation loc) + +let parse_type_annot : int -> string list -> type_annot option tzresult = + fun loc annot -> + parse_annots loc annot >>? classify_annot loc >>? fun (vars, types, fields) -> + error_unexpected_annot loc vars >>? fun () -> + error_unexpected_annot loc fields >>? fun () -> get_one_annot loc types + +let parse_type_field_annot : + int -> string list -> (type_annot option * field_annot option) tzresult = + fun loc annot -> + parse_annots loc annot >>? classify_annot loc >>? fun (vars, types, fields) -> + error_unexpected_annot loc vars >>? fun () -> + get_one_annot loc types >>? fun t -> + get_one_annot loc fields >|? fun f -> (t, f) + +let parse_composed_type_annot : + int -> + string list -> + (type_annot option * field_annot option * field_annot option) tzresult = + fun loc annot -> + parse_annots loc annot >>? classify_annot loc >>? fun (vars, types, fields) -> + error_unexpected_annot loc vars >>? fun () -> + get_one_annot loc types >>? fun t -> + get_two_annot loc fields >|? fun (f1, f2) -> (t, f1, f2) + +let parse_field_annot : int -> string list -> field_annot option tzresult = + fun loc annot -> + parse_annots loc annot >>? classify_annot loc >>? fun (vars, types, fields) -> + error_unexpected_annot loc vars >>? fun () -> + error_unexpected_annot loc types >>? fun () -> get_one_annot loc fields + +let extract_field_annot : + Script.node -> (Script.node * field_annot option) tzresult = function + | Prim (loc, prim, args, annot) -> + let rec extract_first acc = function + | [] -> (None, annot) + | s :: rest -> + if Compare.Int.(String.length s > 0) && Compare.Char.(s.[0] = '%') + then (Some s, List.rev_append acc rest) + else extract_first (s :: acc) rest + in + let (field_annot, annot) = extract_first [] annot in + (match field_annot with + | None -> ok_none + | Some field_annot -> parse_field_annot loc [field_annot]) + >|? fun field_annot -> (Prim (loc, prim, args, annot), field_annot) + | expr -> ok (expr, None) + +let check_correct_field : + field_annot option -> field_annot option -> unit tzresult = + fun f1 f2 -> + match (f1, f2) with + | (None, _) | (_, None) -> ok_unit + | (Some (Field_annot s1), Some (Field_annot s2)) -> + if String.equal s1 s2 then ok_unit + else error (Inconsistent_field_annotations ("%" ^ s1, "%" ^ s2)) + +let parse_var_annot : + int -> ?default:var_annot option -> string list -> var_annot option tzresult + = + fun loc ?default annot -> + parse_annots loc annot >>? classify_annot loc >>? fun (vars, types, fields) -> + error_unexpected_annot loc types >>? fun () -> + error_unexpected_annot loc fields >>? fun () -> + get_one_annot loc vars >|? function + | Some _ as a -> a + | None -> ( match default with Some a -> a | None -> None) + +let split_last_dot = function + | None -> (None, None) + | Some (Field_annot s) -> ( + match String.rindex_opt s '.' with + | None -> (None, Some (Field_annot s)) + | Some i -> + let s1 = String.sub s 0 i in + let s2 = String.sub s (i + 1) (String.length s - i - 1) in + let f = + if Compare.String.equal s2 "car" || Compare.String.equal s2 "cdr" + then None + else Some (Field_annot s2) + in + (Some (Var_annot s1), f)) + +let common_prefix v1 v2 = + match (v1, v2) with + | (Some (Var_annot s1), Some (Var_annot s2)) when Compare.String.equal s1 s2 + -> + v1 + | (Some _, None) -> v1 + | (None, Some _) -> v2 + | (_, _) -> None + +let parse_constr_annot : + int -> + ?if_special_first:field_annot option -> + ?if_special_second:field_annot option -> + string list -> + (var_annot option + * type_annot option + * field_annot option + * field_annot option) + tzresult = + fun loc ?if_special_first ?if_special_second annot -> + parse_annots ~allow_special_field:true loc annot >>? classify_annot loc + >>? fun (vars, types, fields) -> + get_one_annot loc vars >>? fun v -> + get_one_annot loc types >>? fun t -> + get_two_annot loc fields >>? fun (f1, f2) -> + (match (if_special_first, f1) with + | (Some special_var, Some (Field_annot "@")) -> + ok (split_last_dot special_var) + | (None, Some (Field_annot "@")) -> error (Unexpected_annotation loc) + | (_, _) -> ok (v, f1)) + >>? fun (v1, f1) -> + (match (if_special_second, f2) with + | (Some special_var, Some (Field_annot "@")) -> + ok (split_last_dot special_var) + | (None, Some (Field_annot "@")) -> error (Unexpected_annotation loc) + | (_, _) -> ok (v, f2)) + >|? fun (v2, f2) -> + let v = match v with None -> common_prefix v1 v2 | Some _ -> v in + (v, t, f1, f2) + +let parse_two_var_annot : + int -> string list -> (var_annot option * var_annot option) tzresult = + fun loc annot -> + parse_annots loc annot >>? classify_annot loc >>? fun (vars, types, fields) -> + error_unexpected_annot loc types >>? fun () -> + error_unexpected_annot loc fields >>? fun () -> get_two_annot loc vars + +let var_annot_from_special : + field_name:field_annot option -> + default:var_annot option -> + value_annot:var_annot option -> + var_annot option -> + var_annot option = + fun ~field_name ~default ~value_annot v -> + match v with + | Some (Var_annot "%") -> field_to_var_annot field_name + | Some (Var_annot "%%") -> default + | Some _ -> v + | None -> value_annot + +let parse_destr_annot : + int -> + string list -> + default_accessor:field_annot option -> + field_name:field_annot option -> + pair_annot:var_annot option -> + value_annot:var_annot option -> + (var_annot option * field_annot option) tzresult = + fun loc annot ~default_accessor ~field_name ~pair_annot ~value_annot -> + parse_annots loc ~allow_special_var:true annot >>? classify_annot loc + >>? fun (vars, types, fields) -> + error_unexpected_annot loc types >>? fun () -> + get_one_annot loc vars >>? fun v -> + get_one_annot loc fields >|? fun f -> + let default = + gen_access_annot pair_annot field_name ~default:default_accessor + in + let v = var_annot_from_special ~field_name ~default ~value_annot v in + (v, f) + +let parse_unpair_annot : + int -> + string list -> + field_name_car:field_annot option -> + field_name_cdr:field_annot option -> + pair_annot:var_annot option -> + value_annot_car:var_annot option -> + value_annot_cdr:var_annot option -> + (var_annot option + * var_annot option + * field_annot option + * field_annot option) + tzresult = + fun loc + annot + ~field_name_car + ~field_name_cdr + ~pair_annot + ~value_annot_car + ~value_annot_cdr -> + parse_annots loc ~allow_special_var:true annot >>? classify_annot loc + >>? fun (vars, types, fields) -> + error_unexpected_annot loc types >>? fun () -> + get_two_annot loc vars >>? fun (vcar, vcdr) -> + get_two_annot loc fields >|? fun (fcar, fcdr) -> + let default_car = + gen_access_annot pair_annot field_name_car ~default:default_car_annot + in + let default_cdr = + gen_access_annot pair_annot field_name_cdr ~default:default_cdr_annot + in + let vcar = + var_annot_from_special + ~field_name:field_name_car + ~default:default_car + ~value_annot:value_annot_car + vcar + in + let vcdr = + var_annot_from_special + ~field_name:field_name_cdr + ~default:default_cdr + ~value_annot:value_annot_cdr + vcdr + in + (vcar, vcdr, fcar, fcdr) + +let parse_entrypoint_annot : + int -> + ?default:var_annot option -> + string list -> + (var_annot option * field_annot option) tzresult = + fun loc ?default annot -> + parse_annots loc annot >>? classify_annot loc >>? fun (vars, types, fields) -> + error_unexpected_annot loc types >>? fun () -> + get_one_annot loc fields >>? fun f -> + get_one_annot loc vars >|? function + | Some _ as a -> (a, f) + | None -> ( match default with Some a -> (a, f) | None -> (None, f)) + +let parse_var_type_annot : + int -> string list -> (var_annot option * type_annot option) tzresult = + fun loc annot -> + parse_annots loc annot >>? classify_annot loc >>? fun (vars, types, fields) -> + error_unexpected_annot loc fields >>? fun () -> + get_one_annot loc vars >>? fun v -> + get_one_annot loc types >|? fun t -> (v, t) diff --git a/src/proto_011_PtHangzH/lib_protocol/script_ir_annot.mli b/src/proto_011_PtHangzH/lib_protocol/script_ir_annot.mli new file mode 100644 index 000000000000..63f3ad0c6b02 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_ir_annot.mli @@ -0,0 +1,217 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Script_typed_ir + +(** Default annotations *) + +val default_now_annot : var_annot option + +val default_amount_annot : var_annot option + +val default_balance_annot : var_annot option + +val default_level_annot : var_annot option + +val default_steps_annot : var_annot option + +val default_source_annot : var_annot option + +val default_sender_annot : var_annot option + +val default_self_annot : var_annot option + +val default_arg_annot : var_annot option + +val default_param_annot : var_annot option + +val default_storage_annot : var_annot option + +val default_sapling_state_annot : var_annot option + +val default_sapling_balance_annot : var_annot option + +val default_car_annot : field_annot option + +val default_cdr_annot : field_annot option + +val default_contract_annot : field_annot option + +val default_addr_annot : field_annot option + +val default_manager_annot : field_annot option + +val default_pack_annot : field_annot option + +val default_unpack_annot : field_annot option + +val default_slice_annot : field_annot option + +val default_elt_annot : field_annot option + +val default_key_annot : field_annot option + +val default_hd_annot : field_annot option + +val default_tl_annot : field_annot option + +val default_some_annot : field_annot option + +val default_left_annot : field_annot option + +val default_right_annot : field_annot option + +val default_binding_annot : field_annot option + +(** Unparse annotations to their string representation *) + +val unparse_type_annot : type_annot option -> string list + +val unparse_var_annot : var_annot option -> string list + +val unparse_field_annot : field_annot option -> string list + +(** Conversion functions between different annotation kinds *) + +val field_to_var_annot : field_annot option -> var_annot option + +val type_to_var_annot : type_annot option -> var_annot option + +val var_to_field_annot : var_annot option -> field_annot option + +(** Replace an annotation by its default value if it is [None] *) +val default_annot : default:'a option -> 'a option -> 'a option + +(** Generate annotation for field accesses, of the form [var.field1.field2] *) +val gen_access_annot : + var_annot option -> + ?default:field_annot option -> + field_annot option -> + var_annot option + +(** Merge type annotations. + @return an error {!Inconsistent_type_annotations} if they are both present + and different, unless [legacy] *) +val merge_type_annot : + legacy:bool -> + type_annot option -> + type_annot option -> + type_annot option tzresult + +(** Merge field annotations. + @return an error {!Inconsistent_type_annotations} if they are both present + and different, unless [legacy] *) +val merge_field_annot : + legacy:bool -> + field_annot option -> + field_annot option -> + field_annot option tzresult + +(** Merge variable annotations, does not fail ([None] if different). *) +val merge_var_annot : var_annot option -> var_annot option -> var_annot option + +(** @return an error {!Unexpected_annotation} in the monad the list is not empty. *) +val error_unexpected_annot : int -> 'a list -> unit tzresult + +(** Parse a type annotation only. *) +val parse_type_annot : int -> string list -> type_annot option tzresult + +(** Parse a field annotation only. *) +val parse_field_annot : int -> string list -> field_annot option tzresult + +(** Parse an annotation for composed types, of the form + [:ty_name %field] in any order. *) +val parse_type_field_annot : + int -> string list -> (type_annot option * field_annot option) tzresult + +(** Parse an annotation for composed types, of the form + [:ty_name %field1 %field2] in any order. *) +val parse_composed_type_annot : + int -> + string list -> + (type_annot option * field_annot option * field_annot option) tzresult + +(** Extract and remove a field annotation from a node *) +val extract_field_annot : + Script.node -> (Script.node * field_annot option) tzresult + +(** Check that field annotations match, used for field accesses. *) +val check_correct_field : + field_annot option -> field_annot option -> unit tzresult + +(** Instruction annotations parsing *) + +(** Parse a variable annotation, replaced by a default value if [None]. *) +val parse_var_annot : + int -> ?default:var_annot option -> string list -> var_annot option tzresult + +val is_allowed_char : char -> bool + +val parse_constr_annot : + int -> + ?if_special_first:field_annot option -> + ?if_special_second:field_annot option -> + string list -> + (var_annot option + * type_annot option + * field_annot option + * field_annot option) + tzresult + +val parse_two_var_annot : + int -> string list -> (var_annot option * var_annot option) tzresult + +val parse_destr_annot : + int -> + string list -> + default_accessor:field_annot option -> + field_name:field_annot option -> + pair_annot:var_annot option -> + value_annot:var_annot option -> + (var_annot option * field_annot option) tzresult + +val parse_unpair_annot : + int -> + string list -> + field_name_car:field_annot option -> + field_name_cdr:field_annot option -> + pair_annot:var_annot option -> + value_annot_car:var_annot option -> + value_annot_cdr:var_annot option -> + (var_annot option + * var_annot option + * field_annot option + * field_annot option) + tzresult + +val parse_entrypoint_annot : + int -> + ?default:var_annot option -> + string list -> + (var_annot option * field_annot option) tzresult + +val parse_var_type_annot : + int -> string list -> (var_annot option * type_annot option) tzresult diff --git a/src/proto_011_PtHangzH/lib_protocol/script_ir_translator.ml b/src/proto_011_PtHangzH/lib_protocol/script_ir_translator.ml new file mode 100644 index 000000000000..08c601db277f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_ir_translator.ml @@ -0,0 +1,6797 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Micheline +open Script +open Script_tc_errors +open Script_ir_annot +open Script_typed_ir +module Typecheck_costs = Michelson_v1_gas.Cost_of.Typechecking +module Unparse_costs = Michelson_v1_gas.Cost_of.Unparsing + +type ex_stack_ty = Ex_stack_ty : ('a, 's) stack_ty -> ex_stack_ty + +(* + + The following type represents an instruction parameterized by its + continuation. During the elaboration of the typed term, a sequence + of instructions in Micheline is read from left to right: hence, the + elaboration needs to wait for the next instruction to be elaborated + to be able to construct the current instruction. + +*) +type ('a, 's, 'b, 'u) cinstr = { + apply : + 'r 'f. ('a, 's) kinfo -> ('b, 'u, 'r, 'f) kinstr -> ('a, 's, 'r, 'f) kinstr; +} + +(* + + While a [Script_typed_ir.descr] contains a fully defined + instruction, [descr] contains a [cinstr], that is an instruction + parameterized by the next instruction, as explained in the previous + comment. + +*) +type ('a, 's, 'b, 'u) descr = { + loc : Script.location; + bef : ('a, 's) stack_ty; + aft : ('b, 'u) stack_ty; + instr : ('a, 's, 'b, 'u) cinstr; +} + +let close_descr {loc; bef; aft; instr} = + let kinfo = {iloc = loc; kstack_ty = aft} in + let kinfo' = {iloc = loc; kstack_ty = bef} in + let kinstr = instr.apply kinfo' (IHalt kinfo) in + {kloc = loc; kbef = bef; kaft = aft; kinstr} + +let kinfo_of_descr {loc; bef; _} = {iloc = loc; kstack_ty = bef} + +let compose_descr : + type a s b u c v. + Script.location -> + (a, s, b, u) descr -> + (b, u, c, v) descr -> + (a, s, c, v) descr = + fun loc d1 d2 -> + { + loc; + bef = d1.bef; + aft = d2.aft; + instr = + { + apply = + (fun _ k -> + d1.instr.apply + (kinfo_of_descr d1) + (d2.instr.apply (kinfo_of_descr d2) k)); + }; + } + +type tc_context = + | Lambda : tc_context + | Dip : ('a, 's) stack_ty * tc_context -> tc_context + | Toplevel : { + storage_type : 'sto ty; + param_type : 'param ty; + root_name : field_annot option; + legacy_create_contract_literal : bool; + } + -> tc_context + +type unparsing_mode = Optimized | Readable | Optimized_legacy + +type type_logger = + int -> + (Script.expr * Script.annot) list -> + (Script.expr * Script.annot) list -> + unit + +let add_dip ty annot prev = + match prev with + | Lambda | Toplevel _ -> + Dip (Item_t (ty, Item_t (unit_t ~annot:None, Bot_t, None), annot), prev) + | Dip (stack, _) -> Dip (Item_t (ty, stack, annot), prev) + +(* ---- Error helpers -------------------------------------------------------*) + +let location = function + | Prim (loc, _, _, _) + | Int (loc, _) + | String (loc, _) + | Bytes (loc, _) + | Seq (loc, _) -> + loc + +let kind_equal a b = + match (a, b) with + | (Int_kind, Int_kind) + | (String_kind, String_kind) + | (Bytes_kind, Bytes_kind) + | (Prim_kind, Prim_kind) + | (Seq_kind, Seq_kind) -> + true + | _ -> false + +let kind = function + | Int _ -> Int_kind + | String _ -> String_kind + | Bytes _ -> Bytes_kind + | Prim _ -> Prim_kind + | Seq _ -> Seq_kind + +let unexpected expr exp_kinds exp_ns exp_prims = + match expr with + | Int (loc, _) -> Invalid_kind (loc, Prim_kind :: exp_kinds, Int_kind) + | String (loc, _) -> Invalid_kind (loc, Prim_kind :: exp_kinds, String_kind) + | Bytes (loc, _) -> Invalid_kind (loc, Prim_kind :: exp_kinds, Bytes_kind) + | Seq (loc, _) -> Invalid_kind (loc, Prim_kind :: exp_kinds, Seq_kind) + | Prim (loc, name, _, _) -> ( + let open Michelson_v1_primitives in + match (namespace name, exp_ns) with + | (Type_namespace, Type_namespace) + | (Instr_namespace, Instr_namespace) + | (Constant_namespace, Constant_namespace) -> + Invalid_primitive (loc, exp_prims, name) + | (ns, _) -> Invalid_namespace (loc, name, exp_ns, ns)) + +let check_kind kinds expr = + let kind = kind expr in + if List.exists (kind_equal kind) kinds then ok_unit + else + let loc = location expr in + error (Invalid_kind (loc, kinds, kind)) + +(* ---- Unparsing (Typed IR -> Untyped expressions) of types -----------------*) + +(* This part contains the unparsing that does not depend on parsing + (everything that cannot contain a lambda). The rest is located at + the end of the file. *) + +let rec ty_of_comparable_ty : type a. a comparable_ty -> a ty = function + | Unit_key tname -> Unit_t tname + | Never_key tname -> Never_t tname + | Int_key tname -> Int_t tname + | Nat_key tname -> Nat_t tname + | Signature_key tname -> Signature_t tname + | String_key tname -> String_t tname + | Bytes_key tname -> Bytes_t tname + | Mutez_key tname -> Mutez_t tname + | Bool_key tname -> Bool_t tname + | Key_hash_key tname -> Key_hash_t tname + | Key_key tname -> Key_t tname + | Timestamp_key tname -> Timestamp_t tname + | Address_key tname -> Address_t tname + | Chain_id_key tname -> Chain_id_t tname + | Pair_key ((l, al), (r, ar), tname) -> + Pair_t + ( (ty_of_comparable_ty l, al, None), + (ty_of_comparable_ty r, ar, None), + tname ) + | Union_key ((l, al), (r, ar), tname) -> + Union_t ((ty_of_comparable_ty l, al), (ty_of_comparable_ty r, ar), tname) + | Option_key (t, tname) -> Option_t (ty_of_comparable_ty t, tname) + +let add_field_annot a var = function + | Prim (loc, prim, args, annots) -> + Prim + (loc, prim, args, annots @ unparse_field_annot a @ unparse_var_annot var) + | expr -> expr + +let rec unparse_comparable_ty : type a. a comparable_ty -> Script.node = + function + | Unit_key meta -> Prim (-1, T_unit, [], unparse_type_annot meta.annot) + | Never_key meta -> Prim (-1, T_never, [], unparse_type_annot meta.annot) + | Int_key meta -> Prim (-1, T_int, [], unparse_type_annot meta.annot) + | Nat_key meta -> Prim (-1, T_nat, [], unparse_type_annot meta.annot) + | Signature_key meta -> + Prim (-1, T_signature, [], unparse_type_annot meta.annot) + | String_key meta -> Prim (-1, T_string, [], unparse_type_annot meta.annot) + | Bytes_key meta -> Prim (-1, T_bytes, [], unparse_type_annot meta.annot) + | Mutez_key meta -> Prim (-1, T_mutez, [], unparse_type_annot meta.annot) + | Bool_key meta -> Prim (-1, T_bool, [], unparse_type_annot meta.annot) + | Key_hash_key meta -> Prim (-1, T_key_hash, [], unparse_type_annot meta.annot) + | Key_key meta -> Prim (-1, T_key, [], unparse_type_annot meta.annot) + | Timestamp_key meta -> + Prim (-1, T_timestamp, [], unparse_type_annot meta.annot) + | Address_key meta -> Prim (-1, T_address, [], unparse_type_annot meta.annot) + | Chain_id_key meta -> Prim (-1, T_chain_id, [], unparse_type_annot meta.annot) + | Pair_key ((l, al), (r, ar), meta) -> ( + let tl = add_field_annot al None (unparse_comparable_ty l) in + let tr = add_field_annot ar None (unparse_comparable_ty r) in + (* Fold [pair a1 (pair ... (pair an-1 an))] into [pair a1 ... an] *) + (* Note that the folding does not happen if the pair on the right has a + field annotation because this annotation would be lost *) + match tr with + | Prim (_, T_pair, ts, []) -> + Prim (-1, T_pair, tl :: ts, unparse_type_annot meta.annot) + | _ -> Prim (-1, T_pair, [tl; tr], unparse_type_annot meta.annot)) + | Union_key ((l, al), (r, ar), meta) -> + let tl = add_field_annot al None (unparse_comparable_ty l) in + let tr = add_field_annot ar None (unparse_comparable_ty r) in + Prim (-1, T_or, [tl; tr], unparse_type_annot meta.annot) + | Option_key (t, meta) -> + Prim + (-1, T_option, [unparse_comparable_ty t], unparse_type_annot meta.annot) + +let unparse_memo_size memo_size = + let z = Sapling.Memo_size.unparse_to_z memo_size in + Int (-1, z) + +let rec unparse_ty : type a. context -> a ty -> (Script.node * context) tzresult + = + fun ctxt ty -> + Gas.consume ctxt Unparse_costs.unparse_type_cycle >>? fun ctxt -> + let return ctxt (name, args, annot) = + let result = Prim (-1, name, args, annot) in + ok (result, ctxt) + in + match ty with + | Unit_t meta -> return ctxt (T_unit, [], unparse_type_annot meta.annot) + | Int_t meta -> return ctxt (T_int, [], unparse_type_annot meta.annot) + | Nat_t meta -> return ctxt (T_nat, [], unparse_type_annot meta.annot) + | Signature_t meta -> + return ctxt (T_signature, [], unparse_type_annot meta.annot) + | String_t meta -> return ctxt (T_string, [], unparse_type_annot meta.annot) + | Bytes_t meta -> return ctxt (T_bytes, [], unparse_type_annot meta.annot) + | Mutez_t meta -> return ctxt (T_mutez, [], unparse_type_annot meta.annot) + | Bool_t meta -> return ctxt (T_bool, [], unparse_type_annot meta.annot) + | Key_hash_t meta -> + return ctxt (T_key_hash, [], unparse_type_annot meta.annot) + | Key_t meta -> return ctxt (T_key, [], unparse_type_annot meta.annot) + | Timestamp_t meta -> + return ctxt (T_timestamp, [], unparse_type_annot meta.annot) + | Address_t meta -> return ctxt (T_address, [], unparse_type_annot meta.annot) + | Operation_t meta -> + return ctxt (T_operation, [], unparse_type_annot meta.annot) + | Chain_id_t meta -> + return ctxt (T_chain_id, [], unparse_type_annot meta.annot) + | Never_t meta -> return ctxt (T_never, [], unparse_type_annot meta.annot) + | Bls12_381_g1_t meta -> + return ctxt (T_bls12_381_g1, [], unparse_type_annot meta.annot) + | Bls12_381_g2_t meta -> + return ctxt (T_bls12_381_g2, [], unparse_type_annot meta.annot) + | Bls12_381_fr_t meta -> + return ctxt (T_bls12_381_fr, [], unparse_type_annot meta.annot) + | Contract_t (ut, meta) -> + unparse_ty ctxt ut >>? fun (t, ctxt) -> + return ctxt (T_contract, [t], unparse_type_annot meta.annot) + | Pair_t ((utl, l_field, l_var), (utr, r_field, r_var), meta) -> + let annot = unparse_type_annot meta.annot in + unparse_ty ctxt utl >>? fun (utl, ctxt) -> + let tl = add_field_annot l_field l_var utl in + unparse_ty ctxt utr >>? fun (utr, ctxt) -> + let tr = add_field_annot r_field r_var utr in + (* Fold [pair a1 (pair ... (pair an-1 an))] into [pair a1 ... an] *) + (* Note that the folding does not happen if the pair on the right has an + annotation because this annotation would be lost *) + return + ctxt + (match tr with + | Prim (_, T_pair, ts, []) -> (T_pair, tl :: ts, annot) + | _ -> (T_pair, [tl; tr], annot)) + | Union_t ((utl, l_field), (utr, r_field), meta) -> + let annot = unparse_type_annot meta.annot in + unparse_ty ctxt utl >>? fun (utl, ctxt) -> + let tl = add_field_annot l_field None utl in + unparse_ty ctxt utr >>? fun (utr, ctxt) -> + let tr = add_field_annot r_field None utr in + return ctxt (T_or, [tl; tr], annot) + | Lambda_t (uta, utr, meta) -> + unparse_ty ctxt uta >>? fun (ta, ctxt) -> + unparse_ty ctxt utr >>? fun (tr, ctxt) -> + return ctxt (T_lambda, [ta; tr], unparse_type_annot meta.annot) + | Option_t (ut, meta) -> + let annot = unparse_type_annot meta.annot in + unparse_ty ctxt ut >>? fun (ut, ctxt) -> + return ctxt (T_option, [ut], annot) + | List_t (ut, meta) -> + unparse_ty ctxt ut >>? fun (t, ctxt) -> + return ctxt (T_list, [t], unparse_type_annot meta.annot) + | Ticket_t (ut, meta) -> + let t = unparse_comparable_ty ut in + return ctxt (T_ticket, [t], unparse_type_annot meta.annot) + | Set_t (ut, meta) -> + let t = unparse_comparable_ty ut in + return ctxt (T_set, [t], unparse_type_annot meta.annot) + | Map_t (uta, utr, meta) -> + let ta = unparse_comparable_ty uta in + unparse_ty ctxt utr >>? fun (tr, ctxt) -> + return ctxt (T_map, [ta; tr], unparse_type_annot meta.annot) + | Big_map_t (uta, utr, meta) -> + let ta = unparse_comparable_ty uta in + unparse_ty ctxt utr >>? fun (tr, ctxt) -> + return ctxt (T_big_map, [ta; tr], unparse_type_annot meta.annot) + | Sapling_transaction_t (memo_size, meta) -> + return + ctxt + ( T_sapling_transaction, + [unparse_memo_size memo_size], + unparse_type_annot meta.annot ) + | Sapling_state_t (memo_size, meta) -> + return + ctxt + ( T_sapling_state, + [unparse_memo_size memo_size], + unparse_type_annot meta.annot ) + | Chest_key_t meta -> + return ctxt (T_chest_key, [], unparse_type_annot meta.annot) + | Chest_t meta -> return ctxt (T_chest, [], unparse_type_annot meta.annot) + +let[@coq_struct "function_parameter"] rec strip_var_annots = function + | (Int _ | String _ | Bytes _) as atom -> atom + | Seq (loc, args) -> Seq (loc, List.map strip_var_annots args) + | Prim (loc, name, args, annots) -> + let not_var_annot s = Compare.Char.(s.[0] <> '@') in + let annots = List.filter not_var_annot annots in + Prim (loc, name, List.map strip_var_annots args, annots) + +let serialize_ty_for_error ctxt ty = + unparse_ty ctxt ty + >>? (fun (ty, ctxt) -> + Gas.consume ctxt (Script.strip_locations_cost ty) >|? fun ctxt -> + (Micheline.strip_locations (strip_var_annots ty), ctxt)) + |> record_trace Cannot_serialize_error + +let[@coq_axiom_with_reason "gadt"] rec comparable_ty_of_ty : + type a. + context -> Script.location -> a ty -> (a comparable_ty * context) tzresult = + fun ctxt loc ty -> + Gas.consume ctxt Typecheck_costs.comparable_ty_of_ty_cycle >>? fun ctxt -> + match ty with + | Unit_t tname -> ok ((Unit_key tname : a comparable_ty), ctxt) + | Never_t tname -> ok (Never_key tname, ctxt) + | Int_t tname -> ok (Int_key tname, ctxt) + | Nat_t tname -> ok (Nat_key tname, ctxt) + | Signature_t tname -> ok (Signature_key tname, ctxt) + | String_t tname -> ok (String_key tname, ctxt) + | Bytes_t tname -> ok (Bytes_key tname, ctxt) + | Mutez_t tname -> ok (Mutez_key tname, ctxt) + | Bool_t tname -> ok (Bool_key tname, ctxt) + | Key_hash_t tname -> ok (Key_hash_key tname, ctxt) + | Key_t tname -> ok (Key_key tname, ctxt) + | Timestamp_t tname -> ok (Timestamp_key tname, ctxt) + | Address_t tname -> ok (Address_key tname, ctxt) + | Chain_id_t tname -> ok (Chain_id_key tname, ctxt) + | Pair_t ((l, al, _), (r, ar, _), pname) -> + comparable_ty_of_ty ctxt loc l >>? fun (lty, ctxt) -> + comparable_ty_of_ty ctxt loc r >|? fun (rty, ctxt) -> + (Pair_key ((lty, al), (rty, ar), pname), ctxt) + | Union_t ((l, al), (r, ar), tname) -> + comparable_ty_of_ty ctxt loc l >>? fun (lty, ctxt) -> + comparable_ty_of_ty ctxt loc r >|? fun (rty, ctxt) -> + (Union_key ((lty, al), (rty, ar), tname), ctxt) + | Option_t (tt, tname) -> + comparable_ty_of_ty ctxt loc tt >|? fun (ty, ctxt) -> + (Option_key (ty, tname), ctxt) + | Lambda_t _ | List_t _ | Ticket_t _ | Set_t _ | Map_t _ | Big_map_t _ + | Contract_t _ | Operation_t _ | Bls12_381_fr_t _ | Bls12_381_g1_t _ + | Bls12_381_g2_t _ | Sapling_state_t _ | Sapling_transaction_t _ + | Chest_key_t _ | Chest_t _ -> + serialize_ty_for_error ctxt ty >>? fun (t, _ctxt) -> + error (Comparable_type_expected (loc, t)) + +let rec unparse_stack : + type a s. + context -> + (a, s) stack_ty -> + ((Script.expr * Script.annot) list * context) tzresult = + fun ctxt -> function + | Bot_t -> ok ([], ctxt) + | Item_t (ty, rest, annot) -> + unparse_ty ctxt ty >>? fun (uty, ctxt) -> + unparse_stack ctxt rest >|? fun (urest, ctxt) -> + ((strip_locations uty, unparse_var_annot annot) :: urest, ctxt) + +let serialize_stack_for_error ctxt stack_ty = + record_trace Cannot_serialize_error (unparse_stack ctxt stack_ty) + +let name_of_ty : type a. a ty -> type_annot option = function + | Unit_t meta -> meta.annot + | Int_t meta -> meta.annot + | Nat_t meta -> meta.annot + | String_t meta -> meta.annot + | Bytes_t meta -> meta.annot + | Mutez_t meta -> meta.annot + | Bool_t meta -> meta.annot + | Key_hash_t meta -> meta.annot + | Key_t meta -> meta.annot + | Timestamp_t meta -> meta.annot + | Address_t meta -> meta.annot + | Signature_t meta -> meta.annot + | Operation_t meta -> meta.annot + | Chain_id_t meta -> meta.annot + | Never_t meta -> meta.annot + | Contract_t (_, meta) -> meta.annot + | Pair_t (_, _, meta) -> meta.annot + | Union_t (_, _, meta) -> meta.annot + | Lambda_t (_, _, meta) -> meta.annot + | Option_t (_, meta) -> meta.annot + | List_t (_, meta) -> meta.annot + | Ticket_t (_, meta) -> meta.annot + | Set_t (_, meta) -> meta.annot + | Map_t (_, _, meta) -> meta.annot + | Big_map_t (_, _, meta) -> meta.annot + | Bls12_381_g1_t meta -> meta.annot + | Bls12_381_g2_t meta -> meta.annot + | Bls12_381_fr_t meta -> meta.annot + | Sapling_state_t (_, meta) -> meta.annot + | Sapling_transaction_t (_, meta) -> meta.annot + | Chest_key_t meta -> meta.annot + | Chest_t meta -> meta.annot + +let unparse_unit ctxt () = ok (Prim (-1, D_Unit, [], []), ctxt) + +let unparse_int ctxt v = ok (Int (-1, Script_int.to_zint v), ctxt) + +let unparse_nat ctxt v = ok (Int (-1, Script_int.to_zint v), ctxt) + +let unparse_string ctxt s = ok (String (-1, Script_string.to_string s), ctxt) + +let unparse_bytes ctxt s = ok (Bytes (-1, s), ctxt) + +let unparse_bool ctxt b = + ok (Prim (-1, (if b then D_True else D_False), [], []), ctxt) + +let unparse_timestamp ctxt mode t = + match mode with + | Optimized | Optimized_legacy -> + ok (Int (-1, Script_timestamp.to_zint t), ctxt) + | Readable -> ( + Gas.consume ctxt Unparse_costs.timestamp_readable >>? fun ctxt -> + match Script_timestamp.to_notation t with + | None -> ok (Int (-1, Script_timestamp.to_zint t), ctxt) + | Some s -> ok (String (-1, s), ctxt)) + +let unparse_address ctxt mode (c, entrypoint) = + Gas.consume ctxt Unparse_costs.contract >>? fun ctxt -> + (match entrypoint with + (* given parse_address, this should not happen *) + | "" -> error Unparsing_invariant_violated + | _ -> ok ()) + >|? fun () -> + match mode with + | Optimized | Optimized_legacy -> + let entrypoint = match entrypoint with "default" -> "" | name -> name in + let bytes = + Data_encoding.Binary.to_bytes_exn + Data_encoding.(tup2 Contract.encoding Variable.string) + (c, entrypoint) + in + (Bytes (-1, bytes), ctxt) + | Readable -> + let notation = + match entrypoint with + | "default" -> Contract.to_b58check c + | entrypoint -> Contract.to_b58check c ^ "%" ^ entrypoint + in + (String (-1, notation), ctxt) + +let unparse_contract ctxt mode (_, address) = unparse_address ctxt mode address + +let unparse_signature ctxt mode s = + match mode with + | Optimized | Optimized_legacy -> + Gas.consume ctxt Unparse_costs.signature_optimized >|? fun ctxt -> + let bytes = Data_encoding.Binary.to_bytes_exn Signature.encoding s in + (Bytes (-1, bytes), ctxt) + | Readable -> + Gas.consume ctxt Unparse_costs.signature_readable >|? fun ctxt -> + (String (-1, Signature.to_b58check s), ctxt) + +let unparse_mutez ctxt v = ok (Int (-1, Z.of_int64 (Tez.to_mutez v)), ctxt) + +let unparse_key ctxt mode k = + match mode with + | Optimized | Optimized_legacy -> + Gas.consume ctxt Unparse_costs.public_key_optimized >|? fun ctxt -> + let bytes = + Data_encoding.Binary.to_bytes_exn Signature.Public_key.encoding k + in + (Bytes (-1, bytes), ctxt) + | Readable -> + Gas.consume ctxt Unparse_costs.public_key_readable >|? fun ctxt -> + (String (-1, Signature.Public_key.to_b58check k), ctxt) + +let unparse_key_hash ctxt mode k = + match mode with + | Optimized | Optimized_legacy -> + Gas.consume ctxt Unparse_costs.key_hash_optimized >|? fun ctxt -> + let bytes = + Data_encoding.Binary.to_bytes_exn Signature.Public_key_hash.encoding k + in + (Bytes (-1, bytes), ctxt) + | Readable -> + Gas.consume ctxt Unparse_costs.key_hash_readable >|? fun ctxt -> + (String (-1, Signature.Public_key_hash.to_b58check k), ctxt) + +let unparse_operation ctxt (op, _big_map_diff) = + let bytes = + Data_encoding.Binary.to_bytes_exn Operation.internal_operation_encoding op + in + Gas.consume ctxt (Unparse_costs.operation bytes) >|? fun ctxt -> + (Bytes (-1, bytes), ctxt) + +let unparse_chain_id ctxt mode chain_id = + match mode with + | Optimized | Optimized_legacy -> + Gas.consume ctxt Unparse_costs.chain_id_optimized >|? fun ctxt -> + let bytes = + Data_encoding.Binary.to_bytes_exn Chain_id.encoding chain_id + in + (Bytes (-1, bytes), ctxt) + | Readable -> + Gas.consume ctxt Unparse_costs.chain_id_readable >|? fun ctxt -> + (String (-1, Chain_id.to_b58check chain_id), ctxt) + +let unparse_bls12_381_g1 ctxt x = + Gas.consume ctxt Unparse_costs.bls12_381_g1 >|? fun ctxt -> + let bytes = Bls12_381.G1.to_bytes x in + (Bytes (-1, bytes), ctxt) + +let unparse_bls12_381_g2 ctxt x = + Gas.consume ctxt Unparse_costs.bls12_381_g2 >|? fun ctxt -> + let bytes = Bls12_381.G2.to_bytes x in + (Bytes (-1, bytes), ctxt) + +let unparse_bls12_381_fr ctxt x = + Gas.consume ctxt Unparse_costs.bls12_381_fr >|? fun ctxt -> + let bytes = Bls12_381.Fr.to_bytes x in + (Bytes (-1, bytes), ctxt) + +let unparse_with_data_encoding ctxt s unparse_cost encoding = + Lwt.return + ( Gas.consume ctxt unparse_cost >|? fun ctxt -> + let bytes = Data_encoding.Binary.to_bytes_exn encoding s in + (Bytes (-1, bytes), ctxt) ) + +(* -- Unparsing data of complex types -- *) + +type ('ty, 'depth) comb_witness = + | Comb_Pair : ('t, 'd) comb_witness -> (_ * 't, unit -> 'd) comb_witness + | Comb_Any : (_, _) comb_witness + +let unparse_pair (type r) unparse_l unparse_r ctxt mode + (r_comb_witness : (r, unit -> unit -> _) comb_witness) (l, (r : r)) = + unparse_l ctxt l >>=? fun (l, ctxt) -> + unparse_r ctxt r >|=? fun (r, ctxt) -> + (* Fold combs. + For combs, three notations are supported: + - a) [Pair x1 (Pair x2 ... (Pair xn-1 xn) ...)], + - b) [Pair x1 x2 ... xn-1 xn], and + - c) [{x1; x2; ...; xn-1; xn}]. + In readable mode, we always use b), + in optimized mode we use the shortest to serialize: + - for n=2, [Pair x1 x2], + - for n=3, [Pair x1 (Pair x2 x3)], + - for n>=4, [{x1; x2; ...; xn}]. + *) + let res = + match (mode, r_comb_witness, r) with + | (Optimized, Comb_Pair _, Micheline.Seq (_, r)) -> + (* Optimized case n > 4 *) + Micheline.Seq (-1, l :: r) + | ( Optimized, + Comb_Pair (Comb_Pair _), + Prim (_, D_Pair, [x2; Prim (_, D_Pair, [x3; x4], [])], []) ) -> + (* Optimized case n = 4 *) + Micheline.Seq (-1, [l; x2; x3; x4]) + | (Readable, Comb_Pair _, Prim (_, D_Pair, xs, [])) -> + (* Readable case n > 2 *) + Prim (-1, D_Pair, l :: xs, []) + | _ -> + (* The remaining cases are: + - Optimized n = 2, + - Optimized n = 3, and + - Readable n = 2, + - Optimized_legacy, any n *) + Prim (-1, D_Pair, [l; r], []) + in + (res, ctxt) + +let unparse_union unparse_l unparse_r ctxt = function + | L l -> + unparse_l ctxt l >|=? fun (l, ctxt) -> (Prim (-1, D_Left, [l], []), ctxt) + | R r -> + unparse_r ctxt r >|=? fun (r, ctxt) -> (Prim (-1, D_Right, [r], []), ctxt) + +let unparse_option unparse_v ctxt = function + | Some v -> + unparse_v ctxt v >|=? fun (v, ctxt) -> (Prim (-1, D_Some, [v], []), ctxt) + | None -> return (Prim (-1, D_None, [], []), ctxt) + +(* -- Unparsing data of comparable types -- *) + +let comparable_comb_witness2 : + type t. t comparable_ty -> (t, unit -> unit -> unit) comb_witness = function + | Pair_key (_, (Pair_key _, _), _) -> Comb_Pair (Comb_Pair Comb_Any) + | Pair_key _ -> Comb_Pair Comb_Any + | _ -> Comb_Any + +let[@coq_axiom_with_reason "gadt"] rec unparse_comparable_data : + type a. + context -> + unparsing_mode -> + a comparable_ty -> + a -> + (Script.node * context) tzresult Lwt.t = + fun ctxt mode ty a -> + (* No need for stack_depth here. Unlike [unparse_data], + [unparse_comparable_data] doesn't call [unparse_code]. + The stack depth is bounded by the type depth, currently bounded + by 1000 (michelson_maximum_type_size). *) + Gas.consume ctxt Unparse_costs.unparse_data_cycle + (* We could have a smaller cost but let's keep it consistent with + [unparse_data] for now. *) + >>?= + fun ctxt -> + match (ty, a) with + | (Unit_key _, v) -> Lwt.return @@ unparse_unit ctxt v + | (Int_key _, v) -> Lwt.return @@ unparse_int ctxt v + | (Nat_key _, v) -> Lwt.return @@ unparse_nat ctxt v + | (String_key _, s) -> Lwt.return @@ unparse_string ctxt s + | (Bytes_key _, s) -> Lwt.return @@ unparse_bytes ctxt s + | (Bool_key _, b) -> Lwt.return @@ unparse_bool ctxt b + | (Timestamp_key _, t) -> Lwt.return @@ unparse_timestamp ctxt mode t + | (Address_key _, address) -> Lwt.return @@ unparse_address ctxt mode address + | (Signature_key _, s) -> Lwt.return @@ unparse_signature ctxt mode s + | (Mutez_key _, v) -> Lwt.return @@ unparse_mutez ctxt v + | (Key_key _, k) -> Lwt.return @@ unparse_key ctxt mode k + | (Key_hash_key _, k) -> Lwt.return @@ unparse_key_hash ctxt mode k + | (Chain_id_key _, chain_id) -> + Lwt.return @@ unparse_chain_id ctxt mode chain_id + | (Pair_key ((tl, _), (tr, _), _), pair) -> + let r_witness = comparable_comb_witness2 tr in + let unparse_l ctxt v = unparse_comparable_data ctxt mode tl v in + let unparse_r ctxt v = unparse_comparable_data ctxt mode tr v in + unparse_pair unparse_l unparse_r ctxt mode r_witness pair + | (Union_key ((tl, _), (tr, _), _), v) -> + let unparse_l ctxt v = unparse_comparable_data ctxt mode tl v in + let unparse_r ctxt v = unparse_comparable_data ctxt mode tr v in + unparse_union unparse_l unparse_r ctxt v + | (Option_key (t, _), v) -> + let unparse_v ctxt v = unparse_comparable_data ctxt mode t v in + unparse_option unparse_v ctxt v + | (Never_key _, _) -> . + +let pack_node unparsed ctxt = + Gas.consume ctxt (Script.strip_locations_cost unparsed) >>? fun ctxt -> + let bytes = + Data_encoding.Binary.to_bytes_exn + expr_encoding + (Micheline.strip_locations unparsed) + in + Gas.consume ctxt (Script.serialized_cost bytes) >>? fun ctxt -> + let bytes = Bytes.cat (Bytes.of_string "\005") bytes in + Gas.consume ctxt (Script.serialized_cost bytes) >|? fun ctxt -> (bytes, ctxt) + +let pack_comparable_data ctxt typ data ~mode = + unparse_comparable_data ctxt mode typ data >>=? fun (unparsed, ctxt) -> + Lwt.return @@ pack_node unparsed ctxt + +let hash_bytes ctxt bytes = + Gas.consume ctxt (Michelson_v1_gas.Cost_of.Interpreter.blake2b bytes) + >|? fun ctxt -> (Script_expr_hash.(hash_bytes [bytes]), ctxt) + +let hash_comparable_data ctxt typ data = + pack_comparable_data ctxt typ data ~mode:Optimized_legacy + >>=? fun (bytes, ctxt) -> Lwt.return @@ hash_bytes ctxt bytes + +(* ---- Tickets ------------------------------------------------------------ *) + +(* + All comparable types are dupable, this function exists only to not forget + checking this property when adding new types. +*) +let check_dupable_comparable_ty : type a. a comparable_ty -> unit = function + | Unit_key _ | Never_key _ | Int_key _ | Nat_key _ | Signature_key _ + | String_key _ | Bytes_key _ | Mutez_key _ | Bool_key _ | Key_hash_key _ + | Key_key _ | Timestamp_key _ | Chain_id_key _ | Address_key _ | Pair_key _ + | Union_key _ | Option_key _ -> + () + +let rec check_dupable_ty : + type a. context -> location -> a ty -> context tzresult = + fun ctxt loc ty -> + Gas.consume ctxt Typecheck_costs.check_dupable_cycle >>? fun ctxt -> + match ty with + | Unit_t _ -> ok ctxt + | Int_t _ -> ok ctxt + | Nat_t _ -> ok ctxt + | Signature_t _ -> ok ctxt + | String_t _ -> ok ctxt + | Bytes_t _ -> ok ctxt + | Mutez_t _ -> ok ctxt + | Key_hash_t _ -> ok ctxt + | Key_t _ -> ok ctxt + | Timestamp_t _ -> ok ctxt + | Address_t _ -> ok ctxt + | Bool_t _ -> ok ctxt + | Contract_t (_, _) -> ok ctxt + | Operation_t _ -> ok ctxt + | Chain_id_t _ -> ok ctxt + | Never_t _ -> ok ctxt + | Bls12_381_g1_t _ -> ok ctxt + | Bls12_381_g2_t _ -> ok ctxt + | Bls12_381_fr_t _ -> ok ctxt + | Sapling_state_t _ -> ok ctxt + | Sapling_transaction_t _ -> ok ctxt + | Chest_t _ -> ok ctxt + | Chest_key_t _ -> ok ctxt + | Ticket_t _ -> error (Unexpected_ticket loc) + | Pair_t ((ty_a, _, _), (ty_b, _, _), _) -> + check_dupable_ty ctxt loc ty_a >>? fun ctxt -> + check_dupable_ty ctxt loc ty_b + | Union_t ((ty_a, _), (ty_b, _), _) -> + check_dupable_ty ctxt loc ty_a >>? fun ctxt -> + check_dupable_ty ctxt loc ty_b + | Lambda_t (_, _, _) -> + (* + Lambda are dupable as long as: + - they don't contain non-dupable values, e.g. in `PUSH` + (mostly non-dupable values should probably be considered forged) + - they are not the result of a partial application on a non-dupable + value. `APPLY` rejects non-packable types (because of `PUSH`). + Hence non-dupable should imply non-packable. + *) + ok ctxt + | Option_t (ty, _) -> check_dupable_ty ctxt loc ty + | List_t (ty, _) -> check_dupable_ty ctxt loc ty + | Set_t (key_ty, _) -> + let () = check_dupable_comparable_ty key_ty in + ok ctxt + | Map_t (key_ty, val_ty, _) -> + let () = check_dupable_comparable_ty key_ty in + check_dupable_ty ctxt loc val_ty + | Big_map_t (key_ty, val_ty, _) -> + let () = check_dupable_comparable_ty key_ty in + check_dupable_ty ctxt loc val_ty + +(* ---- Equality witnesses --------------------------------------------------*) + +type ('ta, 'tb) eq = Eq : ('same, 'same) eq + +let record_inconsistent_types ctxt loc ta tb = + record_trace_eval (fun () -> + serialize_ty_for_error ctxt ta >>? fun (ta, ctxt) -> + serialize_ty_for_error ctxt tb >|? fun (tb, _ctxt) -> + Inconsistent_types (Some loc, ta, tb)) + +module type GAS_MONAD = sig + type 'a t + + type 'a gas_monad = 'a t + + val return : 'a -> 'a t + + val ( >>$ ) : 'a t -> ('a -> 'b t) -> 'b t + + val ( >|$ ) : 'a t -> ('a -> 'b) -> 'b t + + val ( >?$ ) : 'a t -> ('a -> 'b tzresult) -> 'b t + + val ( >??$ ) : 'a t -> ('a tzresult -> 'b t) -> 'b t + + val from_tzresult : 'a tzresult -> 'a t + + val unsafe_embed : (context -> ('a * context) tzresult) -> 'a t + + val gas_consume : Gas.cost -> unit t + + val run : context -> 'a t -> ('a tzresult * context) tzresult + + val record_trace_eval : (unit -> error tzresult) -> 'a t -> 'a t + + val get_context : context t +end + +module Gas_monad : GAS_MONAD = struct + (* The outer tzresult is for gas exhaustion only. The inner one is for all + other (non-gas) errors. *) + type 'a t = context -> ('a tzresult * context) tzresult + + type 'a gas_monad = 'a t + + let from_tzresult x ctxt = ok (x, ctxt) + + let return x = from_tzresult (ok x) + + let ( >>$ ) m f ctxt = + m ctxt >>? fun (x, ctxt) -> + match x with Ok y -> f y ctxt | Error _ as err -> from_tzresult err ctxt + + let ( >|$ ) m f ctxt = + m ctxt >>? fun (x, ctxt) -> from_tzresult (x >|? f) ctxt + + let ( >?$ ) m f = m >>$ fun x -> from_tzresult (f x) + + let ( >??$ ) m f ctxt = m ctxt >>? fun (x, ctxt) -> f x ctxt + + let unsafe_embed f ctxt = f ctxt >>? fun (x, ctxt) -> return x ctxt + + let gas_consume cost ctxt = Gas.consume ctxt cost >>? return () + + let run ctxt x = x ctxt + + let get_context ctxt = return ctxt ctxt + + let record_trace_eval f x ctxt = record_trace_eval f (x ctxt) +end + +let serialize_ty_for_error_carbonated t = + Gas_monad.unsafe_embed (fun ctxt -> serialize_ty_for_error ctxt t) + +let merge_type_metadata : + legacy:bool -> 'a ty_metadata -> 'b ty_metadata -> 'a ty_metadata tzresult = + fun ~legacy {size = size_a; annot = annot_a} {size = size_b; annot = annot_b} -> + Type_size.merge size_a size_b >>? fun size -> + merge_type_annot ~legacy annot_a annot_b >|? fun annot -> {annot; size} + +(* Takes two comparable types and simultaneously merge their annotations and + check that they represent the same type. + + The result contains: + - an equality witness between the types of the two inputs + - the merged type + - an updated context (for gas consumption) + + The tzresult monad is used at two levels: the inner tzresult + is used for tracking merge errors (types of different shapes + or annotation mismatches), the outer tzresult is used only + for gas consumption. Separating these two error cases like + this allows to recover from a type comparison error without + reverting the gas consumption. + *) +let rec merge_comparable_types : + type ta tb. + legacy:bool -> + ta comparable_ty -> + tb comparable_ty -> + ((ta comparable_ty, tb comparable_ty) eq * ta comparable_ty) Gas_monad.t = + let open Gas_monad in + fun ~legacy ta tb -> + gas_consume Typecheck_costs.merge_cycle >>$ fun () -> + let merge_type_metadata ~legacy meta_a meta_b = + from_tzresult @@ merge_type_metadata ~legacy meta_a meta_b + in + let merge_field_annot ~legacy annot_a annot_b = + from_tzresult @@ merge_field_annot ~legacy annot_a annot_b + in + let return f eq annot_a annot_b : + ((ta comparable_ty, tb comparable_ty) eq * ta comparable_ty) gas_monad = + merge_type_metadata ~legacy annot_a annot_b >>$ fun annot -> + return (eq, f annot) + in + match (ta, tb) with + | (Unit_key annot_a, Unit_key annot_b) -> + return (fun annot -> Unit_key annot) Eq annot_a annot_b + | (Never_key annot_a, Never_key annot_b) -> + return (fun annot -> Never_key annot) Eq annot_a annot_b + | (Int_key annot_a, Int_key annot_b) -> + return (fun annot -> Int_key annot) Eq annot_a annot_b + | (Nat_key annot_a, Nat_key annot_b) -> + return (fun annot -> Nat_key annot) Eq annot_a annot_b + | (Signature_key annot_a, Signature_key annot_b) -> + return (fun annot -> Signature_key annot) Eq annot_a annot_b + | (String_key annot_a, String_key annot_b) -> + return (fun annot -> String_key annot) Eq annot_a annot_b + | (Bytes_key annot_a, Bytes_key annot_b) -> + return (fun annot -> Bytes_key annot) Eq annot_a annot_b + | (Mutez_key annot_a, Mutez_key annot_b) -> + return (fun annot -> Mutez_key annot) Eq annot_a annot_b + | (Bool_key annot_a, Bool_key annot_b) -> + return (fun annot -> Bool_key annot) Eq annot_a annot_b + | (Key_hash_key annot_a, Key_hash_key annot_b) -> + return (fun annot -> Key_hash_key annot) Eq annot_a annot_b + | (Key_key annot_a, Key_key annot_b) -> + return (fun annot -> Key_key annot) Eq annot_a annot_b + | (Timestamp_key annot_a, Timestamp_key annot_b) -> + return (fun annot -> Timestamp_key annot) Eq annot_a annot_b + | (Chain_id_key annot_a, Chain_id_key annot_b) -> + return (fun annot -> Chain_id_key annot) Eq annot_a annot_b + | (Address_key annot_a, Address_key annot_b) -> + return (fun annot -> Address_key annot) Eq annot_a annot_b + | ( Pair_key ((left_a, annot_left_a), (right_a, annot_right_a), annot_a), + Pair_key ((left_b, annot_left_b), (right_b, annot_right_b), annot_b) ) + -> + merge_type_metadata ~legacy annot_a annot_b >>$ fun annot -> + merge_field_annot ~legacy annot_left_a annot_left_b + >>$ fun annot_left -> + merge_field_annot ~legacy annot_right_a annot_right_b + >>$ fun annot_right -> + merge_comparable_types ~legacy left_a left_b >>$ fun (Eq, left) -> + merge_comparable_types ~legacy right_a right_b >|$ fun (Eq, right) -> + ( (Eq : (ta comparable_ty, tb comparable_ty) eq), + Pair_key ((left, annot_left), (right, annot_right), annot) ) + | ( Union_key ((left_a, annot_left_a), (right_a, annot_right_a), annot_a), + Union_key ((left_b, annot_left_b), (right_b, annot_right_b), annot_b) ) + -> + merge_type_metadata ~legacy annot_a annot_b >>$ fun annot -> + merge_field_annot ~legacy annot_left_a annot_left_b + >>$ fun annot_left -> + merge_field_annot ~legacy annot_right_a annot_right_b + >>$ fun annot_right -> + merge_comparable_types ~legacy left_a left_b >>$ fun (Eq, left) -> + merge_comparable_types ~legacy right_a right_b >|$ fun (Eq, right) -> + ( (Eq : (ta comparable_ty, tb comparable_ty) eq), + Union_key ((left, annot_left), (right, annot_right), annot) ) + | (Option_key (ta, annot_a), Option_key (tb, annot_b)) -> + merge_type_metadata ~legacy annot_a annot_b >>$ fun annot -> + merge_comparable_types ~legacy ta tb >|$ fun (Eq, t) -> + ((Eq : (ta comparable_ty, tb comparable_ty) eq), Option_key (t, annot)) + | (_, _) -> + serialize_ty_for_error_carbonated (ty_of_comparable_ty ta) >>$ fun ta -> + serialize_ty_for_error_carbonated (ty_of_comparable_ty tb) >?$ fun tb -> + error (Inconsistent_types (None, ta, tb)) + +(* This function does not distinguish gas errors from merge errors. If you need + to recover from a type mismatch and consume the exact gas for the failed + comparison, use [merge_comparable_types] instead. +*) +let comparable_ty_eq : + type ta tb. + context -> + ta comparable_ty -> + tb comparable_ty -> + ((ta comparable_ty, tb comparable_ty) eq * context) tzresult = + fun ctxt ta tb -> + Gas_monad.run ctxt (merge_comparable_types ~legacy:true ta tb) + >>? fun (eq_ty, ctxt) -> + eq_ty >|? fun (eq, _ty) -> (eq, ctxt) + +let merge_memo_sizes ms1 ms2 = + if Sapling.Memo_size.equal ms1 ms2 then ok ms1 + else error (Inconsistent_memo_sizes (ms1, ms2)) + +type merge_type_error_flag = Default_merge_type_error | Fast_merge_type_error + +let default_merge_type_error ty1 ty2 = + let open Gas_monad in + serialize_ty_for_error_carbonated ty1 >>$ fun ty1 -> + serialize_ty_for_error_carbonated ty2 >?$ fun ty2 -> + ok (Inconsistent_types (None, ty1, ty2)) + +type error += Inconsistent_types_fast + +let fast_merge_type_error _ty1 _ty2 = Gas_monad.return Inconsistent_types_fast + +let merge_type_error ~merge_type_error_flag = + match merge_type_error_flag with + | Default_merge_type_error -> default_merge_type_error + | Fast_merge_type_error -> fast_merge_type_error + +let record_inconsistent_carbonated ctxt ta tb = + Gas_monad.record_trace_eval (fun () -> + serialize_ty_for_error ctxt ta >>? fun (ta, ctxt) -> + serialize_ty_for_error ctxt tb >|? fun (tb, _ctxt) -> + Inconsistent_types (None, ta, tb)) + +(* Same as merge_comparable_types but for any types *) +let merge_types : + type a b. + legacy:bool -> + merge_type_error_flag:merge_type_error_flag -> + Script.location -> + a ty -> + b ty -> + ((a ty, b ty) eq * a ty) Gas_monad.t = + let open Gas_monad in + fun ~legacy ~merge_type_error_flag loc ty1 ty2 -> + get_context >>$ fun initial_ctxt -> + let merge_type_metadata tn1 tn2 = + from_tzresult + (merge_type_metadata ~legacy tn1 tn2 + |> record_inconsistent_types initial_ctxt loc ty1 ty2) + in + let merge_field_annot ~legacy tn1 tn2 = + from_tzresult (merge_field_annot ~legacy tn1 tn2) + in + let merge_memo_sizes ms1 ms2 = from_tzresult (merge_memo_sizes ms1 ms2) in + let rec help : + type ta tb. ta ty -> tb ty -> ((ta ty, tb ty) eq * ta ty) gas_monad = + fun ty1 ty2 -> + help0 ty1 ty2 |> record_inconsistent_carbonated initial_ctxt ty1 ty2 + and help0 : + type ta tb. ta ty -> tb ty -> ((ta ty, tb ty) eq * ta ty) gas_monad = + fun ty1 ty2 -> + gas_consume Typecheck_costs.merge_cycle >>$ fun () -> + let return f eq annot_a annot_b : ((ta ty, tb ty) eq * ta ty) gas_monad = + merge_type_metadata annot_a annot_b >>$ fun annot -> return (eq, f annot) + in + match (ty1, ty2) with + | (Unit_t tn1, Unit_t tn2) -> + return (fun tname -> Unit_t tname) Eq tn1 tn2 + | (Int_t tn1, Int_t tn2) -> return (fun tname -> Int_t tname) Eq tn1 tn2 + | (Nat_t tn1, Nat_t tn2) -> return (fun tname -> Nat_t tname) Eq tn1 tn2 + | (Key_t tn1, Key_t tn2) -> return (fun tname -> Key_t tname) Eq tn1 tn2 + | (Key_hash_t tn1, Key_hash_t tn2) -> + return (fun tname -> Key_hash_t tname) Eq tn1 tn2 + | (String_t tn1, String_t tn2) -> + return (fun tname -> String_t tname) Eq tn1 tn2 + | (Bytes_t tn1, Bytes_t tn2) -> + return (fun tname -> Bytes_t tname) Eq tn1 tn2 + | (Signature_t tn1, Signature_t tn2) -> + return (fun tname -> Signature_t tname) Eq tn1 tn2 + | (Mutez_t tn1, Mutez_t tn2) -> + return (fun tname -> Mutez_t tname) Eq tn1 tn2 + | (Timestamp_t tn1, Timestamp_t tn2) -> + return (fun tname -> Timestamp_t tname) Eq tn1 tn2 + | (Address_t tn1, Address_t tn2) -> + return (fun tname -> Address_t tname) Eq tn1 tn2 + | (Bool_t tn1, Bool_t tn2) -> + return (fun tname -> Bool_t tname) Eq tn1 tn2 + | (Chain_id_t tn1, Chain_id_t tn2) -> + return (fun tname -> Chain_id_t tname) Eq tn1 tn2 + | (Never_t tn1, Never_t tn2) -> + return (fun tname -> Never_t tname) Eq tn1 tn2 + | (Operation_t tn1, Operation_t tn2) -> + return (fun tname -> Operation_t tname) Eq tn1 tn2 + | (Bls12_381_g1_t tn1, Bls12_381_g1_t tn2) -> + return (fun tname -> Bls12_381_g1_t tname) Eq tn1 tn2 + | (Bls12_381_g2_t tn1, Bls12_381_g2_t tn2) -> + return (fun tname -> Bls12_381_g2_t tname) Eq tn1 tn2 + | (Bls12_381_fr_t tn1, Bls12_381_fr_t tn2) -> + return (fun tname -> Bls12_381_fr_t tname) Eq tn1 tn2 + | (Map_t (tal, tar, tn1), Map_t (tbl, tbr, tn2)) -> + merge_type_metadata tn1 tn2 >>$ fun tname -> + help tar tbr >>$ fun (Eq, value) -> + merge_comparable_types ~legacy tal tbl >|$ fun (Eq, tk) -> + ((Eq : (ta ty, tb ty) eq), Map_t (tk, value, tname)) + | (Big_map_t (tal, tar, tn1), Big_map_t (tbl, tbr, tn2)) -> + merge_type_metadata tn1 tn2 >>$ fun tname -> + help tar tbr >>$ fun (Eq, value) -> + merge_comparable_types ~legacy tal tbl >|$ fun (Eq, tk) -> + ((Eq : (ta ty, tb ty) eq), Big_map_t (tk, value, tname)) + | (Set_t (ea, tn1), Set_t (eb, tn2)) -> + merge_type_metadata tn1 tn2 >>$ fun tname -> + merge_comparable_types ~legacy ea eb >|$ fun (Eq, e) -> + ((Eq : (ta ty, tb ty) eq), Set_t (e, tname)) + | (Ticket_t (ea, tn1), Ticket_t (eb, tn2)) -> + merge_type_metadata tn1 tn2 >>$ fun tname -> + merge_comparable_types ~legacy ea eb >|$ fun (Eq, e) -> + ((Eq : (ta ty, tb ty) eq), Ticket_t (e, tname)) + | ( Pair_t ((tal, l_field1, l_var1), (tar, r_field1, r_var1), tn1), + Pair_t ((tbl, l_field2, l_var2), (tbr, r_field2, r_var2), tn2) ) -> + merge_type_metadata tn1 tn2 >>$ fun tname -> + merge_field_annot ~legacy l_field1 l_field2 >>$ fun l_field -> + merge_field_annot ~legacy r_field1 r_field2 >>$ fun r_field -> + let l_var = merge_var_annot l_var1 l_var2 in + let r_var = merge_var_annot r_var1 r_var2 in + help tal tbl >>$ fun (Eq, left_ty) -> + help tar tbr >|$ fun (Eq, right_ty) -> + ( (Eq : (ta ty, tb ty) eq), + Pair_t ((left_ty, l_field, l_var), (right_ty, r_field, r_var), tname) + ) + | ( Union_t ((tal, tal_annot), (tar, tar_annot), tn1), + Union_t ((tbl, tbl_annot), (tbr, tbr_annot), tn2) ) -> + merge_type_metadata tn1 tn2 >>$ fun tname -> + merge_field_annot ~legacy tal_annot tbl_annot >>$ fun left_annot -> + merge_field_annot ~legacy tar_annot tbr_annot >>$ fun right_annot -> + help tal tbl >>$ fun (Eq, left_ty) -> + help tar tbr >|$ fun (Eq, right_ty) -> + ( (Eq : (ta ty, tb ty) eq), + Union_t ((left_ty, left_annot), (right_ty, right_annot), tname) ) + | (Lambda_t (tal, tar, tn1), Lambda_t (tbl, tbr, tn2)) -> + merge_type_metadata tn1 tn2 >>$ fun tname -> + help tal tbl >>$ fun (Eq, left_ty) -> + help tar tbr >|$ fun (Eq, right_ty) -> + ((Eq : (ta ty, tb ty) eq), Lambda_t (left_ty, right_ty, tname)) + | (Contract_t (tal, tn1), Contract_t (tbl, tn2)) -> + merge_type_metadata tn1 tn2 >>$ fun tname -> + help tal tbl >|$ fun (Eq, arg_ty) -> + ((Eq : (ta ty, tb ty) eq), Contract_t (arg_ty, tname)) + | (Option_t (tva, tn1), Option_t (tvb, tn2)) -> + merge_type_metadata tn1 tn2 >>$ fun tname -> + help tva tvb >|$ fun (Eq, ty) -> + ((Eq : (ta ty, tb ty) eq), Option_t (ty, tname)) + | (List_t (tva, tn1), List_t (tvb, tn2)) -> + merge_type_metadata tn1 tn2 >>$ fun tname -> + help tva tvb >|$ fun (Eq, ty) -> + ((Eq : (ta ty, tb ty) eq), List_t (ty, tname)) + | (Sapling_state_t (ms1, tn1), Sapling_state_t (ms2, tn2)) -> + merge_type_metadata tn1 tn2 >>$ fun tname -> + merge_memo_sizes ms1 ms2 >|$ fun ms -> + (Eq, Sapling_state_t (ms, tname)) + | (Sapling_transaction_t (ms1, tn1), Sapling_transaction_t (ms2, tn2)) -> + merge_type_metadata tn1 tn2 >>$ fun tname -> + merge_memo_sizes ms1 ms2 >|$ fun ms -> + (Eq, Sapling_transaction_t (ms, tname)) + | (Chest_t tn1, Chest_t tn2) -> + return (fun tname -> Chest_t tname) Eq tn1 tn2 + | (Chest_key_t tn1, Chest_key_t tn2) -> + return (fun tname -> Chest_key_t tname) Eq tn1 tn2 + | (_, _) -> + merge_type_error ~merge_type_error_flag ty1 ty2 >?$ fun err -> + error err + in + help ty1 ty2 + [@@coq_axiom_with_reason "non-top-level mutual recursion"] + +(* This function does not distinguish gas errors from merge errors. If you need + to recover from a type mismatch and consume the exact gas for the failed + comparison, use [merge_types] instead. +*) +let ty_eq : + type ta tb. + legacy:bool -> + context -> + Script.location -> + ta ty -> + tb ty -> + ((ta ty, tb ty) eq * context) tzresult = + fun ~legacy ctxt loc ta tb -> + Gas_monad.run ctxt + @@ merge_types + ~merge_type_error_flag:Default_merge_type_error + ~legacy + loc + ta + tb + >>? fun (eq_ty, ctxt) -> + eq_ty >|? fun (eq, _ty) -> (eq, ctxt) + +(* Same as merge_comparable_types and merge_types but for stacks. + A single error monad is used here because there is no need to + recover from stack merging errors. *) +let merge_stacks : + type ta tb ts tu. + legacy:bool -> + Script.location -> + context -> + int -> + (ta, ts) stack_ty -> + (tb, tu) stack_ty -> + (((ta, ts) stack_ty, (tb, tu) stack_ty) eq * (ta, ts) stack_ty * context) + tzresult = + fun ~legacy loc -> + let rec help : + type ta tb ts tu. + context -> + int -> + (ta, ts) stack_ty -> + (tb, tu) stack_ty -> + (((ta, ts) stack_ty, (tb, tu) stack_ty) eq * (ta, ts) stack_ty * context) + tzresult = + fun ctxt lvl stack1 stack2 -> + match (stack1, stack2) with + | (Bot_t, Bot_t) -> ok (Eq, Bot_t, ctxt) + | (Item_t (ty1, rest1, annot1), Item_t (ty2, rest2, annot2)) -> + Gas_monad.run ctxt + @@ merge_types + ~merge_type_error_flag:Default_merge_type_error + ~legacy + loc + ty1 + ty2 + |> record_trace (Bad_stack_item lvl) + >>? fun (eq_ty, ctxt) -> + eq_ty >>? fun (Eq, ty) -> + help ctxt (lvl + 1) rest1 rest2 >|? fun (Eq, rest, ctxt) -> + let annot = merge_var_annot annot1 annot2 in + ( (Eq : ((ta, ts) stack_ty, (tb, tu) stack_ty) eq), + Item_t (ty, rest, annot), + ctxt ) + | (_, _) -> error Bad_stack_length + in + help + +(* ---- Type checker results -------------------------------------------------*) + +type ('a, 's) judgement = + | Typed : ('a, 's, 'b, 'u) descr -> ('a, 's) judgement + | Failed : { + descr : 'b 'u. ('b, 'u) stack_ty -> ('a, 's, 'b, 'u) descr; + } + -> ('a, 's) judgement + +(* ---- Type checker (Untyped expressions -> Typed IR) ----------------------*) + +type ('a, 's, 'b, 'u, 'c, 'v) branch = { + branch : + 'r 'f. + ('a, 's, 'r, 'f) descr -> ('b, 'u, 'r, 'f) descr -> ('c, 'v, 'r, 'f) descr; +} +[@@unboxed] + +let merge_branches : + type a s b u c v. + legacy:bool -> + context -> + int -> + (a, s) judgement -> + (b, u) judgement -> + (a, s, b, u, c, v) branch -> + ((c, v) judgement * context) tzresult = + fun ~legacy ctxt loc btr bfr {branch} -> + match (btr, bfr) with + | (Typed ({aft = aftbt; _} as dbt), Typed ({aft = aftbf; _} as dbf)) -> + let unmatched_branches () = + serialize_stack_for_error ctxt aftbt >>? fun (aftbt, ctxt) -> + serialize_stack_for_error ctxt aftbf >|? fun (aftbf, _ctxt) -> + Unmatched_branches (loc, aftbt, aftbf) + in + record_trace_eval + unmatched_branches + ( merge_stacks ~legacy loc ctxt 1 aftbt aftbf + >|? fun (Eq, merged_stack, ctxt) -> + ( Typed + (branch + {dbt with aft = merged_stack} + {dbf with aft = merged_stack}), + ctxt ) ) + | (Failed {descr = descrt}, Failed {descr = descrf}) -> + let descr ret = branch (descrt ret) (descrf ret) in + ok (Failed {descr}, ctxt) + | (Typed dbt, Failed {descr = descrf}) -> + ok (Typed (branch dbt (descrf dbt.aft)), ctxt) + | (Failed {descr = descrt}, Typed dbf) -> + ok (Typed (branch (descrt dbf.aft) dbf), ctxt) + +let parse_memo_size (n : (location, _) Micheline.node) : + Sapling.Memo_size.t tzresult = + match n with + | Int (_, z) -> ( + match Sapling.Memo_size.parse_z z with + | Ok _ as ok_memo_size -> ok_memo_size [@coq_cast] + | Error msg -> + error + @@ Invalid_syntactic_constant (location n, strip_locations n, msg)) + | _ -> error @@ Invalid_kind (location n, [Int_kind], kind n) + +type ex_comparable_ty = + | Ex_comparable_ty : 'a comparable_ty -> ex_comparable_ty + +let[@coq_struct "ty"] rec parse_comparable_ty : + stack_depth:int -> + context -> + Script.node -> + (ex_comparable_ty * context) tzresult = + fun ~stack_depth ctxt ty -> + Gas.consume ctxt Typecheck_costs.parse_type_cycle >>? fun ctxt -> + if Compare.Int.(stack_depth > 10000) then + error Typechecking_too_many_recursive_calls + else + match ty with + | Prim (loc, T_unit, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (unit_key ~annot), ctxt) + | Prim (loc, T_never, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (never_key ~annot), ctxt) + | Prim (loc, T_int, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (int_key ~annot), ctxt) + | Prim (loc, T_nat, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (nat_key ~annot), ctxt) + | Prim (loc, T_signature, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (signature_key ~annot), ctxt) + | Prim (loc, T_string, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (string_key ~annot), ctxt) + | Prim (loc, T_bytes, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (bytes_key ~annot), ctxt) + | Prim (loc, T_mutez, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (mutez_key ~annot), ctxt) + | Prim (loc, T_bool, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (bool_key ~annot), ctxt) + | Prim (loc, T_key_hash, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (key_hash_key ~annot), ctxt) + | Prim (loc, T_key, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (key_key ~annot), ctxt) + | Prim (loc, T_timestamp, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (timestamp_key ~annot), ctxt) + | Prim (loc, T_chain_id, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (chain_id_key ~annot), ctxt) + | Prim (loc, T_address, [], annot) -> + parse_type_annot loc annot >|? fun annot -> + (Ex_comparable_ty (address_key ~annot), ctxt) + | Prim + ( loc, + (( T_unit | T_never | T_int | T_nat | T_string | T_bytes | T_mutez + | T_bool | T_key_hash | T_timestamp | T_address | T_chain_id + | T_signature | T_key ) as prim), + l, + _ ) -> + error (Invalid_arity (loc, prim, 0, List.length l)) + | Prim (loc, T_pair, left :: right, annot) -> + parse_type_annot loc annot >>? fun annot -> + extract_field_annot left >>? fun (left, left_annot) -> + (match right with + | [right] -> extract_field_annot right + | right -> + (* Unfold [pair t1 ... tn] as [pair t1 (... (pair tn-1 tn))] *) + ok (Prim (loc, T_pair, right, []), None)) + >>? fun (right, right_annot) -> + parse_comparable_ty ~stack_depth:(stack_depth + 1) ctxt right + >>? fun (Ex_comparable_ty right, ctxt) -> + parse_comparable_ty ~stack_depth:(stack_depth + 1) ctxt left + >>? fun (Ex_comparable_ty left, ctxt) -> + pair_key loc (left, left_annot) (right, right_annot) ~annot + >|? fun ty -> (Ex_comparable_ty ty, ctxt) + | Prim (loc, T_or, [left; right], annot) -> + parse_type_annot loc annot >>? fun annot -> + extract_field_annot left >>? fun (left, left_annot) -> + extract_field_annot right >>? fun (right, right_annot) -> + parse_comparable_ty ~stack_depth:(stack_depth + 1) ctxt right + >>? fun (Ex_comparable_ty right, ctxt) -> + parse_comparable_ty ~stack_depth:(stack_depth + 1) ctxt left + >>? fun (Ex_comparable_ty left, ctxt) -> + union_key loc (left, left_annot) (right, right_annot) ~annot + >|? fun ty -> (Ex_comparable_ty ty, ctxt) + | Prim (loc, ((T_pair | T_or) as prim), l, _) -> + error (Invalid_arity (loc, prim, 2, List.length l)) + | Prim (loc, T_option, [t], annot) -> + parse_type_annot loc annot >>? fun annot -> + parse_comparable_ty ~stack_depth:(stack_depth + 1) ctxt t + >>? fun (Ex_comparable_ty t, ctxt) -> + option_key loc t ~annot >|? fun ty -> (Ex_comparable_ty ty, ctxt) + | Prim (loc, T_option, l, _) -> + error (Invalid_arity (loc, T_option, 1, List.length l)) + | Prim + ( loc, + (T_set | T_map | T_list | T_lambda | T_contract | T_operation), + _, + _ ) -> + error (Comparable_type_expected (loc, Micheline.strip_locations ty)) + | expr -> + error + @@ unexpected + expr + [] + Type_namespace + [ + T_unit; + T_never; + T_int; + T_nat; + T_string; + T_bytes; + T_mutez; + T_bool; + T_key_hash; + T_timestamp; + T_address; + T_pair; + T_or; + T_option; + T_chain_id; + T_signature; + T_key; + ] + +type ex_ty = Ex_ty : 'a ty -> ex_ty + +let[@coq_axiom_with_reason "complex mutually recursive definition"] rec parse_packable_ty + : + context -> + stack_depth:int -> + legacy:bool -> + Script.node -> + (ex_ty * context) tzresult = + fun ctxt ~stack_depth ~legacy -> + (parse_ty [@tailcall]) + ctxt + ~stack_depth + ~legacy + ~allow_lazy_storage:false + ~allow_operation:false + ~allow_contract:legacy + ~allow_ticket:false + +and[@coq_axiom_with_reason "complex mutually recursive definition"] parse_parameter_ty + : + context -> + stack_depth:int -> + legacy:bool -> + Script.node -> + (ex_ty * context) tzresult = + fun ctxt ~stack_depth ~legacy -> + (parse_ty [@tailcall]) + ctxt + ~stack_depth + ~legacy + ~allow_lazy_storage:true + ~allow_operation:false + ~allow_contract:true + ~allow_ticket:true + +and parse_view_input_ty : + context -> + stack_depth:int -> + legacy:bool -> + Script.node -> + (ex_ty * context) tzresult = + fun ctxt ~stack_depth ~legacy -> + (parse_ty [@tailcall]) + ctxt + ~stack_depth + ~legacy + ~allow_lazy_storage:false + ~allow_operation:false + ~allow_contract:true + ~allow_ticket:false + +and parse_view_output_ty : + context -> + stack_depth:int -> + legacy:bool -> + Script.node -> + (ex_ty * context) tzresult = + fun ctxt ~stack_depth ~legacy -> + (parse_ty [@tailcall]) + ctxt + ~stack_depth + ~legacy + ~allow_lazy_storage:false + ~allow_operation:false + ~allow_contract:true + ~allow_ticket:false + +and[@coq_axiom_with_reason "complex mutually recursive definition"] parse_normal_storage_ty + : + context -> + stack_depth:int -> + legacy:bool -> + Script.node -> + (ex_ty * context) tzresult = + fun ctxt ~stack_depth ~legacy -> + (parse_ty [@tailcall]) + ctxt + ~stack_depth + ~legacy + ~allow_lazy_storage:true + ~allow_operation:false + ~allow_contract:legacy + ~allow_ticket:true + +and[@coq_axiom_with_reason "complex mutually recursive definition"] parse_any_ty + : + context -> + stack_depth:int -> + legacy:bool -> + Script.node -> + (ex_ty * context) tzresult = + fun ctxt ~stack_depth ~legacy -> + (parse_ty [@tailcall]) + ctxt + ~stack_depth + ~legacy + ~allow_lazy_storage:true + ~allow_operation:true + ~allow_contract:true + ~allow_ticket:true + +and[@coq_axiom_with_reason "complex mutually recursive definition"] parse_ty : + context -> + stack_depth:int -> + legacy:bool -> + allow_lazy_storage:bool -> + allow_operation:bool -> + allow_contract:bool -> + allow_ticket:bool -> + Script.node -> + (ex_ty * context) tzresult = + fun ctxt + ~stack_depth + ~legacy + ~allow_lazy_storage + ~allow_operation + ~allow_contract + ~allow_ticket + node -> + Gas.consume ctxt Typecheck_costs.parse_type_cycle >>? fun ctxt -> + if Compare.Int.(stack_depth > 10000) then + error Typechecking_too_many_recursive_calls + else + match node with + | Prim (loc, T_unit, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (unit_t ~annot), ctxt) + | Prim (loc, T_int, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (int_t ~annot), ctxt) + | Prim (loc, T_nat, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (nat_t ~annot), ctxt) + | Prim (loc, T_string, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (string_t ~annot), ctxt) + | Prim (loc, T_bytes, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (bytes_t ~annot), ctxt) + | Prim (loc, T_mutez, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (mutez_t ~annot), ctxt) + | Prim (loc, T_bool, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (bool_t ~annot), ctxt) + | Prim (loc, T_key, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (key_t ~annot), ctxt) + | Prim (loc, T_key_hash, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (key_hash_t ~annot), ctxt) + | Prim (loc, T_chest_key, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (chest_key_t ~annot), ctxt) + | Prim (loc, T_chest, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (chest_t ~annot), ctxt) + | Prim (loc, T_timestamp, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (timestamp_t ~annot), ctxt) + | Prim (loc, T_address, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (address_t ~annot), ctxt) + | Prim (loc, T_signature, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (signature_t ~annot), ctxt) + | Prim (loc, T_operation, [], annot) -> + if allow_operation then + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (operation_t ~annot), ctxt) + else error (Unexpected_operation loc) + | Prim (loc, T_chain_id, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (chain_id_t ~annot), ctxt) + | Prim (loc, T_never, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (never_t ~annot), ctxt) + | Prim (loc, T_bls12_381_g1, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (bls12_381_g1_t ~annot), ctxt) + | Prim (loc, T_bls12_381_g2, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (bls12_381_g2_t ~annot), ctxt) + | Prim (loc, T_bls12_381_fr, [], annot) -> + parse_type_annot loc annot >>? fun annot -> + ok (Ex_ty (bls12_381_fr_t ~annot), ctxt) + | Prim (loc, T_contract, [utl], annot) -> + if allow_contract then + parse_parameter_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy utl + >>? fun (Ex_ty tl, ctxt) -> + parse_type_annot loc annot >>? fun annot -> + contract_t loc tl ~annot >|? fun ty -> (Ex_ty ty, ctxt) + else error (Unexpected_contract loc) + | Prim (loc, T_pair, utl :: utr, annot) -> + extract_field_annot utl >>? fun (utl, left_field) -> + parse_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + ~allow_lazy_storage + ~allow_operation + ~allow_contract + ~allow_ticket + utl + >>? fun (Ex_ty tl, ctxt) -> + (match utr with + | [utr] -> extract_field_annot utr + | utr -> + (* Unfold [pair t1 ... tn] as [pair t1 (... (pair tn-1 tn))] *) + ok (Prim (loc, T_pair, utr, []), None)) + >>? fun (utr, right_field) -> + parse_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + ~allow_lazy_storage + ~allow_operation + ~allow_contract + ~allow_ticket + utr + >>? fun (Ex_ty tr, ctxt) -> + parse_type_annot loc annot >>? fun annot -> + pair_t loc (tl, left_field, None) (tr, right_field, None) ~annot + >|? fun ty -> (Ex_ty ty, ctxt) + | Prim (loc, T_or, [utl; utr], annot) -> + extract_field_annot utl >>? fun (utl, left_constr) -> + extract_field_annot utr >>? fun (utr, right_constr) -> + parse_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + ~allow_lazy_storage + ~allow_operation + ~allow_contract + ~allow_ticket + utl + >>? fun (Ex_ty tl, ctxt) -> + parse_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + ~allow_lazy_storage + ~allow_operation + ~allow_contract + ~allow_ticket + utr + >>? fun (Ex_ty tr, ctxt) -> + parse_type_annot loc annot >>? fun annot -> + union_t loc (tl, left_constr) (tr, right_constr) ~annot >|? fun ty -> + (Ex_ty ty, ctxt) + | Prim (loc, T_lambda, [uta; utr], annot) -> + parse_any_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy uta + >>? fun (Ex_ty ta, ctxt) -> + parse_any_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy utr + >>? fun (Ex_ty tr, ctxt) -> + parse_type_annot loc annot >>? fun annot -> + lambda_t loc ta tr ~annot >|? fun ty -> (Ex_ty ty, ctxt) + | Prim (loc, T_option, [ut], annot) -> + (if legacy then + (* legacy semantics with (broken) field annotations *) + extract_field_annot ut >>? fun (ut, _some_constr) -> + parse_composed_type_annot loc annot + >>? fun (ty_name, _none_constr, _) -> ok (ut, ty_name) + else parse_type_annot loc annot >>? fun annot -> ok (ut, annot)) + >>? fun (ut, annot) -> + parse_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + ~allow_lazy_storage + ~allow_operation + ~allow_contract + ~allow_ticket + ut + >>? fun (Ex_ty t, ctxt) -> + option_t loc t ~annot >|? fun ty -> (Ex_ty ty, ctxt) + | Prim (loc, T_list, [ut], annot) -> + parse_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + ~allow_lazy_storage + ~allow_operation + ~allow_contract + ~allow_ticket + ut + >>? fun (Ex_ty t, ctxt) -> + parse_type_annot loc annot >>? fun annot -> + list_t loc t ~annot >|? fun ty -> (Ex_ty ty, ctxt) + | Prim (loc, T_ticket, [ut], annot) -> + if allow_ticket then + parse_comparable_ty ~stack_depth:(stack_depth + 1) ctxt ut + >>? fun (Ex_comparable_ty t, ctxt) -> + parse_type_annot loc annot >>? fun annot -> + ticket_t loc t ~annot >|? fun ty -> (Ex_ty ty, ctxt) + else error (Unexpected_ticket loc) + | Prim (loc, T_set, [ut], annot) -> + parse_comparable_ty ~stack_depth:(stack_depth + 1) ctxt ut + >>? fun (Ex_comparable_ty t, ctxt) -> + parse_type_annot loc annot >>? fun annot -> + set_t loc t ~annot >|? fun ty -> (Ex_ty ty, ctxt) + | Prim (loc, T_map, [uta; utr], annot) -> + parse_comparable_ty ~stack_depth:(stack_depth + 1) ctxt uta + >>? fun (Ex_comparable_ty ta, ctxt) -> + parse_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + ~allow_lazy_storage + ~allow_operation + ~allow_contract + ~allow_ticket + utr + >>? fun (Ex_ty tr, ctxt) -> + parse_type_annot loc annot >>? fun annot -> + map_t loc ta tr ~annot >|? fun ty -> (Ex_ty ty, ctxt) + | Prim (loc, T_sapling_transaction, [memo_size], annot) -> + parse_type_annot loc annot >>? fun annot -> + parse_memo_size memo_size >|? fun memo_size -> + (Ex_ty (sapling_transaction_t ~memo_size ~annot), ctxt) + (* + /!\ When adding new lazy storage kinds, be careful to use + [when allow_lazy_storage] /!\ + Lazy storage should not be packable to avoid stealing a lazy storage + from another contract with `PUSH t id` or `UNPACK`. + *) + | Prim (loc, T_big_map, args, annot) when allow_lazy_storage -> + (parse_big_map_ty [@tailcall]) ctxt ~stack_depth ~legacy loc args annot + | Prim (loc, T_sapling_state, [memo_size], annot) when allow_lazy_storage -> + parse_type_annot loc annot >>? fun annot -> + parse_memo_size memo_size >|? fun memo_size -> + (Ex_ty (sapling_state_t ~memo_size ~annot), ctxt) + | Prim (loc, (T_big_map | T_sapling_state), _, _) -> + error (Unexpected_lazy_storage loc) + | Prim + ( loc, + (( T_unit | T_signature | T_int | T_nat | T_string | T_bytes | T_mutez + | T_bool | T_key | T_key_hash | T_timestamp | T_address | T_chain_id + | T_operation | T_never ) as prim), + l, + _ ) -> + error (Invalid_arity (loc, prim, 0, List.length l)) + | Prim + ( loc, + ((T_set | T_list | T_option | T_contract | T_ticket) as prim), + l, + _ ) -> + error (Invalid_arity (loc, prim, 1, List.length l)) + | Prim (loc, ((T_pair | T_or | T_map | T_lambda) as prim), l, _) -> + error (Invalid_arity (loc, prim, 2, List.length l)) + | expr -> + error + @@ unexpected + expr + [] + Type_namespace + [ + T_pair; + T_or; + T_set; + T_map; + T_list; + T_option; + T_lambda; + T_unit; + T_signature; + T_contract; + T_int; + T_nat; + T_operation; + T_string; + T_bytes; + T_mutez; + T_bool; + T_key; + T_key_hash; + T_timestamp; + T_chain_id; + T_never; + T_bls12_381_g1; + T_bls12_381_g2; + T_bls12_381_fr; + T_ticket; + ] + +and[@coq_axiom_with_reason "complex mutually recursive definition"] parse_big_map_ty + ctxt ~stack_depth ~legacy big_map_loc args map_annot = + Gas.consume ctxt Typecheck_costs.parse_type_cycle >>? fun ctxt -> + match args with + | [key_ty; value_ty] -> + parse_comparable_ty ~stack_depth:(stack_depth + 1) ctxt key_ty + >>? fun (Ex_comparable_ty key_ty, ctxt) -> + parse_big_map_value_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + value_ty + >>? fun (Ex_ty value_ty, ctxt) -> + parse_type_annot big_map_loc map_annot >>? fun annot -> + big_map_t big_map_loc key_ty value_ty ~annot >|? fun big_map_ty -> + (Ex_ty big_map_ty, ctxt) + | args -> error @@ Invalid_arity (big_map_loc, T_big_map, 2, List.length args) + +and[@coq_axiom_with_reason "complex mutually recursive definition"] parse_big_map_value_ty + ctxt ~stack_depth ~legacy value_ty = + (parse_ty [@tailcall]) + ctxt + ~stack_depth + ~legacy + ~allow_lazy_storage:false + ~allow_operation:false + ~allow_contract:legacy + ~allow_ticket:true + value_ty + +let parse_storage_ty : + context -> + stack_depth:int -> + legacy:bool -> + Script.node -> + (ex_ty * context) tzresult = + fun ctxt ~stack_depth ~legacy node -> + match node with + | Prim + ( loc, + T_pair, + [Prim (big_map_loc, T_big_map, args, map_annot); remaining_storage], + storage_annot ) + when legacy -> ( + match storage_annot with + | [] -> + (parse_normal_storage_ty [@tailcall]) ctxt ~stack_depth ~legacy node + | [single] + when Compare.Int.(String.length single > 0) + && Compare.Char.(single.[0] = '%') -> + (parse_normal_storage_ty [@tailcall]) ctxt ~stack_depth ~legacy node + | _ -> + (* legacy semantics of big maps used the wrong annotation parser *) + Gas.consume ctxt Typecheck_costs.parse_type_cycle >>? fun ctxt -> + parse_big_map_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + big_map_loc + args + map_annot + >>? fun (Ex_ty big_map_ty, ctxt) -> + parse_normal_storage_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + remaining_storage + >>? fun (Ex_ty remaining_storage, ctxt) -> + parse_composed_type_annot loc storage_annot + >>? fun (annot, map_field, storage_field) -> + pair_t + loc + (big_map_ty, map_field, None) + (remaining_storage, storage_field, None) + ~annot + >|? fun ty -> (Ex_ty ty, ctxt)) + | _ -> (parse_normal_storage_ty [@tailcall]) ctxt ~stack_depth ~legacy node + +let check_packable ~legacy loc root = + let rec check : type t. t ty -> unit tzresult = function + (* /!\ When adding new lazy storage kinds, be sure to return an error. /!\ + Lazy storage should not be packable. *) + | Big_map_t _ -> error (Unexpected_lazy_storage loc) + | Sapling_state_t _ -> error (Unexpected_lazy_storage loc) + | Operation_t _ -> error (Unexpected_operation loc) + | Unit_t _ -> ok_unit + | Int_t _ -> ok_unit + | Nat_t _ -> ok_unit + | Signature_t _ -> ok_unit + | String_t _ -> ok_unit + | Bytes_t _ -> ok_unit + | Mutez_t _ -> ok_unit + | Key_hash_t _ -> ok_unit + | Key_t _ -> ok_unit + | Timestamp_t _ -> ok_unit + | Address_t _ -> ok_unit + | Bool_t _ -> ok_unit + | Chain_id_t _ -> ok_unit + | Never_t _ -> ok_unit + | Set_t (_, _) -> ok_unit + | Ticket_t _ -> error (Unexpected_ticket loc) + | Lambda_t (_, _, _) -> ok_unit + | Bls12_381_g1_t _ -> ok_unit + | Bls12_381_g2_t _ -> ok_unit + | Bls12_381_fr_t _ -> ok_unit + | Pair_t ((l_ty, _, _), (r_ty, _, _), _) -> + check l_ty >>? fun () -> check r_ty + | Union_t ((l_ty, _), (r_ty, _), _) -> check l_ty >>? fun () -> check r_ty + | Option_t (v_ty, _) -> check v_ty + | List_t (elt_ty, _) -> check elt_ty + | Map_t (_, elt_ty, _) -> check elt_ty + | Contract_t (_, _) when legacy -> ok_unit + | Contract_t (_, _) -> error (Unexpected_contract loc) + | Sapling_transaction_t _ -> ok () + | Chest_key_t _ -> ok_unit + | Chest_t _ -> ok_unit + in + check root + +type toplevel = { + code_field : Script.node; + arg_type : Script.node; + storage_type : Script.node; + views : view SMap.t; + root_name : field_annot option; +} + +type ('arg, 'storage) code = { + code : (('arg, 'storage) pair, (operation boxed_list, 'storage) pair) lambda; + arg_type : 'arg ty; + storage_type : 'storage ty; + views : view SMap.t; + root_name : field_annot option; + code_size : Cache_memory_helpers.sint; +} + +type ex_script = Ex_script : ('a, 'c) script -> ex_script + +type ex_code = Ex_code : ('a, 'c) code -> ex_code + +type 'storage ex_view = + | Ex_view : + ('input * 'storage, 'output) Script_typed_ir.lambda + -> 'storage ex_view + +type (_, _) dig_proof_argument = + | Dig_proof_argument : + ('x, 'a * 's, 'a, 's, 'b, 't, 'c, 'u) stack_prefix_preservation_witness + * 'x ty + * var_annot option + * ('c, 'u) stack_ty + -> ('b, 't) dig_proof_argument + +type (_, _, _) dug_proof_argument = + | Dug_proof_argument : + (('a, 's, 'x, 'a * 's, 'b, 't, 'c, 'u) stack_prefix_preservation_witness + * unit + * ('c, 'u) stack_ty) + -> ('b, 't, 'x) dug_proof_argument + +type (_, _) dipn_proof_argument = + | Dipn_proof_argument : + ('fa, 'fs, 'fb, 'fu, 'a, 's, 'b, 'u) stack_prefix_preservation_witness + * context + * ('fa, 'fs, 'fb, 'fu) descr + * ('b, 'u) stack_ty + -> ('a, 's) dipn_proof_argument + +type (_, _) dropn_proof_argument = + | Dropn_proof_argument : + ('fa, 'fs, 'fa, 'fs, 'a, 's, 'a, 's) stack_prefix_preservation_witness + * ('fa, 'fs) stack_ty + -> ('a, 's) dropn_proof_argument + +type 'before comb_proof_argument = + | Comb_proof_argument : + ('a * 's, 'b * 'u) comb_gadt_witness * ('b, 'u) stack_ty + -> ('a * 's) comb_proof_argument + +type 'before uncomb_proof_argument = + | Uncomb_proof_argument : + ('a * 's, 'b * 'u) uncomb_gadt_witness * ('b, 'u) stack_ty + -> ('a * 's) uncomb_proof_argument + +type 'before comb_get_proof_argument = + | Comb_get_proof_argument : + ('before, 'after) comb_get_gadt_witness * 'after ty + -> 'before comb_get_proof_argument + +type ('rest, 'before) comb_set_proof_argument = + | Comb_set_proof_argument : + ('rest, 'before, 'after) comb_set_gadt_witness * 'after ty + -> ('rest, 'before) comb_set_proof_argument + +type 'before dup_n_proof_argument = + | Dup_n_proof_argument : + ('before, 'a) dup_n_gadt_witness * 'a ty + -> 'before dup_n_proof_argument + +let find_entrypoint (type full) (full : full ty) ~root_name entrypoint = + let annot_is_entrypoint entrypoint = function + | None -> false + | Some (Field_annot l) -> Compare.String.(l = entrypoint) + in + let rec find_entrypoint : + type t. t ty -> string -> ((Script.node -> Script.node) * ex_ty) option = + fun t entrypoint -> + match t with + | Union_t ((tl, al), (tr, ar), _) -> ( + if annot_is_entrypoint entrypoint al then + Some ((fun e -> Prim (0, D_Left, [e], [])), Ex_ty tl) + else if annot_is_entrypoint entrypoint ar then + Some ((fun e -> Prim (0, D_Right, [e], [])), Ex_ty tr) + else + match find_entrypoint tl entrypoint with + | Some (f, t) -> Some ((fun e -> Prim (0, D_Left, [f e], [])), t) + | None -> ( + match find_entrypoint tr entrypoint with + | Some (f, t) -> Some ((fun e -> Prim (0, D_Right, [f e], [])), t) + | None -> None)) + | _ -> None + in + let entrypoint = + if Compare.String.(entrypoint = "") then "default" else entrypoint + in + if Compare.Int.(String.length entrypoint > 31) then + error (Entrypoint_name_too_long entrypoint) + else + match root_name with + | Some (Field_annot root_name) when Compare.String.(entrypoint = root_name) + -> + ok ((fun e -> e), Ex_ty full) + | _ -> ( + match find_entrypoint full entrypoint with + | Some result -> ok result + | None -> ( + match entrypoint with + | "default" -> ok ((fun e -> e), Ex_ty full) + | _ -> error (No_such_entrypoint entrypoint))) + +let find_entrypoint_for_type (type full exp) ~legacy ~merge_type_error_flag + ~(full : full ty) ~(expected : exp ty) ~root_name entrypoint loc : + (string * exp ty) Gas_monad.t = + let open Gas_monad in + match find_entrypoint full ~root_name entrypoint with + | Error _ as err -> from_tzresult err + | Ok (_, Ex_ty ty) -> ( + merge_types ~legacy ~merge_type_error_flag loc ty expected + >??$ fun eq_ty -> + match (entrypoint, root_name) with + | ("default", Some (Field_annot "root")) -> ( + match eq_ty with + | Ok (Eq, ty) -> return ("default", (ty : exp ty)) + | Error _ -> + merge_types ~legacy ~merge_type_error_flag loc full expected + >?$ fun (Eq, full) -> ok ("root", (full : exp ty))) + | _ -> + from_tzresult (eq_ty >|? fun (Eq, ty) -> (entrypoint, (ty : exp ty)))) + +module Entrypoints = Set.Make (String) + +exception Duplicate of string + +exception Too_long of string + +let[@coq_axiom_with_reason "use of exceptions"] well_formed_entrypoints + (type full) (full : full ty) ~root_name = + let merge path annot (type t) (ty : t ty) reachable + ((first_unreachable, all) as acc) = + match annot with + | None | Some (Field_annot "") -> ( + if reachable then acc + else + match ty with + | Union_t _ -> acc + | _ -> ( + match first_unreachable with + | None -> (Some (List.rev path), all) + | Some _ -> acc)) + | Some (Field_annot name) -> + if Compare.Int.(String.length name > 31) then raise (Too_long name) + else if Entrypoints.mem name all then raise (Duplicate name) + else (first_unreachable, Entrypoints.add name all) + in + let rec check : + type t. + t ty -> + prim list -> + bool -> + prim list option * Entrypoints.t -> + prim list option * Entrypoints.t = + fun t path reachable acc -> + match t with + | Union_t ((tl, al), (tr, ar), _) -> + let acc = merge (D_Left :: path) al tl reachable acc in + let acc = merge (D_Right :: path) ar tr reachable acc in + let acc = + check + tl + (D_Left :: path) + (match al with Some _ -> true | None -> reachable) + acc + in + check + tr + (D_Right :: path) + (match ar with Some _ -> true | None -> reachable) + acc + | _ -> acc + in + try + let (init, reachable) = + match root_name with + | None | Some (Field_annot "") -> (Entrypoints.empty, false) + | Some (Field_annot name) -> (Entrypoints.singleton name, true) + in + let (first_unreachable, all) = check full [] reachable (None, init) in + if not (Entrypoints.mem "default" all) then ok_unit + else + match first_unreachable with + | None -> ok_unit + | Some path -> error (Unreachable_entrypoint path) + with + | Duplicate name -> error (Duplicate_entrypoint name) + | Too_long name -> error (Entrypoint_name_too_long name) + +let parse_uint ~nb_bits = + assert (Compare.Int.(nb_bits >= 0 && nb_bits <= 30)) ; + let max_int = (1 lsl nb_bits) - 1 in + let max_z = Z.of_int max_int in + function + | Micheline.Int (_, n) when Compare.Z.(Z.zero <= n) && Compare.Z.(n <= max_z) + -> + ok (Z.to_int n) + | node -> + error + @@ Invalid_syntactic_constant + ( location node, + strip_locations node, + "a positive " ^ string_of_int nb_bits + ^ "-bit integer (between 0 and " ^ string_of_int max_int ^ ")" ) + +let parse_uint10 = parse_uint ~nb_bits:10 + +let parse_uint11 = parse_uint ~nb_bits:11 + +(* This type is used to: + - serialize and deserialize tickets when they are stored or transferred, + - type the READ_TICKET instruction. *) +let opened_ticket_type loc ty = + pair_3_key + loc + (address_key ~annot:None, None) + (ty, None) + (nat_key ~annot:None, None) + +(* -- parse data of primitive types -- *) + +let parse_unit ctxt ~legacy = function + | Prim (loc, D_Unit, [], annot) -> + (if legacy then ok_unit else error_unexpected_annot loc annot) + >>? fun () -> + Gas.consume ctxt Typecheck_costs.unit >|? fun ctxt -> ((), ctxt) + | Prim (loc, D_Unit, l, _) -> + error @@ Invalid_arity (loc, D_Unit, 0, List.length l) + | expr -> error @@ unexpected expr [] Constant_namespace [D_Unit] + +let parse_bool ctxt ~legacy = function + | Prim (loc, D_True, [], annot) -> + (if legacy then ok_unit else error_unexpected_annot loc annot) + >>? fun () -> + Gas.consume ctxt Typecheck_costs.bool >|? fun ctxt -> (true, ctxt) + | Prim (loc, D_False, [], annot) -> + (if legacy then ok_unit else error_unexpected_annot loc annot) + >>? fun () -> + Gas.consume ctxt Typecheck_costs.bool >|? fun ctxt -> (false, ctxt) + | Prim (loc, ((D_True | D_False) as c), l, _) -> + error @@ Invalid_arity (loc, c, 0, List.length l) + | expr -> error @@ unexpected expr [] Constant_namespace [D_True; D_False] + +let parse_string ctxt : Script.node -> (Script_string.t * context) tzresult = + function + | String (loc, v) as expr -> + Gas.consume ctxt (Typecheck_costs.check_printable v) >>? fun ctxt -> + record_trace + (Invalid_syntactic_constant + (loc, strip_locations expr, "a printable ascii string")) + (Script_string.of_string v >|? fun s -> (s, ctxt)) + | expr -> error @@ Invalid_kind (location expr, [String_kind], kind expr) + +let parse_bytes ctxt = function + | Bytes (_, v) -> ok (v, ctxt) + | expr -> error @@ Invalid_kind (location expr, [Bytes_kind], kind expr) + +let parse_int ctxt = function + | Int (_, v) -> ok (Script_int.of_zint v, ctxt) + | expr -> error @@ Invalid_kind (location expr, [Int_kind], kind expr) + +let parse_nat ctxt : + Script.node -> (Script_int.n Script_int.num * context) tzresult = function + | Int (loc, v) as expr -> ( + let v = Script_int.of_zint v in + match Script_int.is_nat v with + | Some nat -> ok (nat, ctxt) + | None -> + error + @@ Invalid_syntactic_constant + (loc, strip_locations expr, "a non-negative integer")) + | expr -> error @@ Invalid_kind (location expr, [Int_kind], kind expr) + +let parse_mutez ctxt : Script.node -> (Tez.t * context) tzresult = function + | Int (loc, v) as expr -> ( + match + let open Option in + bind (catch (fun () -> Z.to_int64 v)) Tez.of_mutez + with + | Some tez -> Ok (tez, ctxt) + | None -> + error + @@ Invalid_syntactic_constant + (loc, strip_locations expr, "a valid mutez amount")) + | expr -> error @@ Invalid_kind (location expr, [Int_kind], kind expr) + +let parse_timestamp ctxt : + Script.node -> (Script_timestamp.t * context) tzresult = function + | Int (_, v) (* As unparsed with [Optimized] or out of bounds [Readable]. *) + -> + ok (Script_timestamp.of_zint v, ctxt) + | String (loc, s) as expr (* As unparsed with [Readable]. *) -> ( + Gas.consume ctxt Typecheck_costs.timestamp_readable >>? fun ctxt -> + match Script_timestamp.of_string s with + | Some v -> ok (v, ctxt) + | None -> + error + @@ Invalid_syntactic_constant + (loc, strip_locations expr, "a valid timestamp")) + | expr -> + error @@ Invalid_kind (location expr, [String_kind; Int_kind], kind expr) + +let parse_key ctxt : Script.node -> (public_key * context) tzresult = function + | Bytes (loc, bytes) as expr -> ( + (* As unparsed with [Optimized]. *) + Gas.consume ctxt Typecheck_costs.public_key_optimized + >>? fun ctxt -> + match + Data_encoding.Binary.of_bytes_opt Signature.Public_key.encoding bytes + with + | Some k -> ok (k, ctxt) + | None -> + error + @@ Invalid_syntactic_constant + (loc, strip_locations expr, "a valid public key")) + | String (loc, s) as expr -> ( + (* As unparsed with [Readable]. *) + Gas.consume ctxt Typecheck_costs.public_key_readable + >>? fun ctxt -> + match Signature.Public_key.of_b58check_opt s with + | Some k -> ok (k, ctxt) + | None -> + error + @@ Invalid_syntactic_constant + (loc, strip_locations expr, "a valid public key")) + | expr -> + error @@ Invalid_kind (location expr, [String_kind; Bytes_kind], kind expr) + +let parse_key_hash ctxt : Script.node -> (public_key_hash * context) tzresult = + function + | Bytes (loc, bytes) as expr -> ( + (* As unparsed with [Optimized]. *) + Gas.consume ctxt Typecheck_costs.key_hash_optimized + >>? fun ctxt -> + match + Data_encoding.Binary.of_bytes_opt + Signature.Public_key_hash.encoding + bytes + with + | Some k -> ok (k, ctxt) + | None -> + error + @@ Invalid_syntactic_constant + (loc, strip_locations expr, "a valid key hash")) + | String (loc, s) as expr (* As unparsed with [Readable]. *) -> ( + Gas.consume ctxt Typecheck_costs.key_hash_readable >>? fun ctxt -> + match Signature.Public_key_hash.of_b58check_opt s with + | Some k -> ok (k, ctxt) + | None -> + error + @@ Invalid_syntactic_constant + (loc, strip_locations expr, "a valid key hash")) + | expr -> + error @@ Invalid_kind (location expr, [String_kind; Bytes_kind], kind expr) + +let parse_signature ctxt : Script.node -> (signature * context) tzresult = + function + | Bytes (loc, bytes) as expr (* As unparsed with [Optimized]. *) -> ( + Gas.consume ctxt Typecheck_costs.signature_optimized >>? fun ctxt -> + match Data_encoding.Binary.of_bytes_opt Signature.encoding bytes with + | Some k -> ok (k, ctxt) + | None -> + error + @@ Invalid_syntactic_constant + (loc, strip_locations expr, "a valid signature")) + | String (loc, s) as expr (* As unparsed with [Readable]. *) -> ( + Gas.consume ctxt Typecheck_costs.signature_readable >>? fun ctxt -> + match Signature.of_b58check_opt s with + | Some s -> ok (s, ctxt) + | None -> + error + @@ Invalid_syntactic_constant + (loc, strip_locations expr, "a valid signature")) + | expr -> + error @@ Invalid_kind (location expr, [String_kind; Bytes_kind], kind expr) + +let parse_chain_id ctxt : Script.node -> (Chain_id.t * context) tzresult = + function + | Bytes (loc, bytes) as expr -> ( + Gas.consume ctxt Typecheck_costs.chain_id_optimized >>? fun ctxt -> + match Data_encoding.Binary.of_bytes_opt Chain_id.encoding bytes with + | Some k -> ok (k, ctxt) + | None -> + error + @@ Invalid_syntactic_constant + (loc, strip_locations expr, "a valid chain id")) + | String (loc, s) as expr -> ( + Gas.consume ctxt Typecheck_costs.chain_id_readable >>? fun ctxt -> + match Chain_id.of_b58check_opt s with + | Some s -> ok (s, ctxt) + | None -> + error + @@ Invalid_syntactic_constant + (loc, strip_locations expr, "a valid chain id")) + | expr -> + error @@ Invalid_kind (location expr, [String_kind; Bytes_kind], kind expr) + +let parse_address ctxt : Script.node -> (address * context) tzresult = function + | Bytes (loc, bytes) as expr (* As unparsed with [Optimized]. *) -> ( + Gas.consume ctxt Typecheck_costs.contract >>? fun ctxt -> + match + Data_encoding.Binary.of_bytes_opt + Data_encoding.(tup2 Contract.encoding Variable.string) + bytes + with + | Some (c, entrypoint) -> ( + if Compare.Int.(String.length entrypoint > 31) then + error (Entrypoint_name_too_long entrypoint) + else + match entrypoint with + | "" -> ok ((c, "default"), ctxt) + | "default" -> error (Unexpected_annotation loc) + | name -> ok ((c, name), ctxt)) + | None -> + error + @@ Invalid_syntactic_constant + (loc, strip_locations expr, "a valid address")) + | String (loc, s) (* As unparsed with [Readable]. *) -> + Gas.consume ctxt Typecheck_costs.contract >>? fun ctxt -> + (match String.index_opt s '%' with + | None -> ok (s, "default") + | Some pos -> ( + let len = String.length s - pos - 1 in + let name = String.sub s (pos + 1) len in + if Compare.Int.(len > 31) then error (Entrypoint_name_too_long name) + else + match (String.sub s 0 pos, name) with + | (addr, "") -> ok (addr, "default") + | (_, "default") -> error @@ Unexpected_annotation loc + | addr_and_name -> ok addr_and_name)) + >>? fun (addr, entrypoint) -> + Contract.of_b58check addr >|? fun c -> ((c, entrypoint), ctxt) + | expr -> + error @@ Invalid_kind (location expr, [String_kind; Bytes_kind], kind expr) + +let parse_never expr : (never * context) tzresult = + error @@ Invalid_never_expr (location expr) + +(* -- parse data of complex types -- *) + +let parse_pair (type r) parse_l parse_r ctxt ~legacy + (r_comb_witness : (r, unit -> _) comb_witness) expr = + let parse_comb loc l rs = + parse_l ctxt l >>=? fun (l, ctxt) -> + (match (rs, r_comb_witness) with + | ([r], _) -> ok r + | ([], _) -> error @@ Invalid_arity (loc, D_Pair, 2, 1) + | (_ :: _, Comb_Pair _) -> + (* Unfold [Pair x1 ... xn] as [Pair x1 (Pair x2 ... xn-1 xn))] + for type [pair ta (pair tb1 tb2)] and n >= 3 only *) + ok (Prim (loc, D_Pair, rs, [])) + | _ -> error @@ Invalid_arity (loc, D_Pair, 2, 1 + List.length rs)) + >>?= fun r -> + parse_r ctxt r >|=? fun (r, ctxt) -> ((l, r), ctxt) + in + match expr with + | Prim (loc, D_Pair, l :: rs, annot) -> + (if legacy then ok_unit else error_unexpected_annot loc annot) + >>?= fun () -> parse_comb loc l rs + | Prim (loc, D_Pair, l, _) -> + fail @@ Invalid_arity (loc, D_Pair, 2, List.length l) + (* Unfold [{x1; ...; xn}] as [Pair x1 x2 ... xn-1 xn] for n >= 2 *) + | Seq (loc, l :: (_ :: _ as rs)) -> parse_comb loc l rs + | Seq (loc, l) -> fail @@ Invalid_seq_arity (loc, 2, List.length l) + | expr -> fail @@ unexpected expr [] Constant_namespace [D_Pair] + +let parse_union parse_l parse_r ctxt ~legacy = function + | Prim (loc, D_Left, [v], annot) -> + (if legacy then ok_unit else error_unexpected_annot loc annot) + >>?= fun () -> + parse_l ctxt v >|=? fun (v, ctxt) -> (L v, ctxt) + | Prim (loc, D_Left, l, _) -> + fail @@ Invalid_arity (loc, D_Left, 1, List.length l) + | Prim (loc, D_Right, [v], annot) -> + (if legacy then ok_unit else error_unexpected_annot loc annot) + >>?= fun () -> + parse_r ctxt v >|=? fun (v, ctxt) -> (R v, ctxt) + | Prim (loc, D_Right, l, _) -> + fail @@ Invalid_arity (loc, D_Right, 1, List.length l) + | expr -> fail @@ unexpected expr [] Constant_namespace [D_Left; D_Right] + +let parse_option parse_v ctxt ~legacy = function + | Prim (loc, D_Some, [v], annot) -> + (if legacy then ok_unit else error_unexpected_annot loc annot) + >>?= fun () -> + parse_v ctxt v >|=? fun (v, ctxt) -> (Some v, ctxt) + | Prim (loc, D_Some, l, _) -> + fail @@ Invalid_arity (loc, D_Some, 1, List.length l) + | Prim (loc, D_None, [], annot) -> + Lwt.return + ( (if legacy then ok_unit else error_unexpected_annot loc annot) + >|? fun () -> (None, ctxt) ) + | Prim (loc, D_None, l, _) -> + fail @@ Invalid_arity (loc, D_None, 0, List.length l) + | expr -> fail @@ unexpected expr [] Constant_namespace [D_Some; D_None] + +(* -- parse data of comparable types -- *) + +let comparable_comb_witness1 : + type t. t comparable_ty -> (t, unit -> unit) comb_witness = function + | Pair_key _ -> Comb_Pair Comb_Any + | _ -> Comb_Any + +let[@coq_axiom_with_reason "gadt"] rec parse_comparable_data : + type a. + ?type_logger:type_logger -> + context -> + a comparable_ty -> + Script.node -> + (a * context) tzresult Lwt.t = + fun ?type_logger ctxt ty script_data -> + (* No need for stack_depth here. Unlike [parse_data], + [parse_comparable_data] doesn't call [parse_returning]. + The stack depth is bounded by the type depth, bounded by 1024. *) + let parse_data_error () = + serialize_ty_for_error ctxt (ty_of_comparable_ty ty) >|? fun (ty, _ctxt) -> + Invalid_constant (location script_data, strip_locations script_data, ty) + in + let traced_no_lwt body = record_trace_eval parse_data_error body in + let traced body = + trace_eval (fun () -> Lwt.return @@ parse_data_error ()) body + in + Gas.consume ctxt Typecheck_costs.parse_data_cycle + (* We could have a smaller cost but let's keep it consistent with + [parse_data] for now. *) + >>?= + fun ctxt -> + let legacy = false in + match (ty, script_data) with + | (Unit_key _, expr) -> + Lwt.return @@ traced_no_lwt + @@ (parse_unit ctxt ~legacy expr : (a * context) tzresult) + | (Bool_key _, expr) -> + Lwt.return @@ traced_no_lwt @@ parse_bool ctxt ~legacy expr + | (String_key _, expr) -> + Lwt.return @@ traced_no_lwt @@ parse_string ctxt expr + | (Bytes_key _, expr) -> Lwt.return @@ traced_no_lwt @@ parse_bytes ctxt expr + | (Int_key _, expr) -> Lwt.return @@ traced_no_lwt @@ parse_int ctxt expr + | (Nat_key _, expr) -> Lwt.return @@ traced_no_lwt @@ parse_nat ctxt expr + | (Mutez_key _, expr) -> Lwt.return @@ traced_no_lwt @@ parse_mutez ctxt expr + | (Timestamp_key _, expr) -> + Lwt.return @@ traced_no_lwt @@ parse_timestamp ctxt expr + | (Key_key _, expr) -> Lwt.return @@ traced_no_lwt @@ parse_key ctxt expr + | (Key_hash_key _, expr) -> + Lwt.return @@ traced_no_lwt @@ parse_key_hash ctxt expr + | (Signature_key _, expr) -> + Lwt.return @@ traced_no_lwt @@ parse_signature ctxt expr + | (Chain_id_key _, expr) -> + Lwt.return @@ traced_no_lwt @@ parse_chain_id ctxt expr + | (Address_key _, expr) -> + Lwt.return @@ traced_no_lwt @@ parse_address ctxt expr + | (Pair_key ((tl, _), (tr, _), _), expr) -> + let r_witness = comparable_comb_witness1 tr in + let parse_l ctxt v = parse_comparable_data ?type_logger ctxt tl v in + let parse_r ctxt v = parse_comparable_data ?type_logger ctxt tr v in + traced @@ parse_pair parse_l parse_r ctxt ~legacy r_witness expr + | (Union_key ((tl, _), (tr, _), _), expr) -> + let parse_l ctxt v = parse_comparable_data ?type_logger ctxt tl v in + let parse_r ctxt v = parse_comparable_data ?type_logger ctxt tr v in + traced @@ parse_union parse_l parse_r ctxt ~legacy expr + | (Option_key (t, _), expr) -> + let parse_v ctxt v = parse_comparable_data ?type_logger ctxt t v in + traced @@ parse_option parse_v ctxt ~legacy expr + | (Never_key _, expr) -> Lwt.return @@ traced_no_lwt @@ parse_never expr + +(* -- parse data of any type -- *) + +let comb_witness1 : type t. t ty -> (t, unit -> unit) comb_witness = function + | Pair_t _ -> Comb_Pair Comb_Any + | _ -> Comb_Any + +(* + Some values, such as operations, tickets, or big map ids, are used only + internally and are not allowed to be forged by users. + In [parse_data], [allow_forged] should be [false] for: + - PUSH + - UNPACK + - user-provided script parameters + - storage on origination + And [true] for: + - internal calls parameters + - storage after origination +*) + +let[@coq_axiom_with_reason "gadt"] rec parse_data : + type a. + ?type_logger:type_logger -> + stack_depth:int -> + context -> + legacy:bool -> + allow_forged:bool -> + a ty -> + Script.node -> + (a * context) tzresult Lwt.t = + fun ?type_logger ~stack_depth ctxt ~legacy ~allow_forged ty script_data -> + Gas.consume ctxt Typecheck_costs.parse_data_cycle >>?= fun ctxt -> + let non_terminal_recursion ?type_logger ctxt ~legacy ty script_data = + if Compare.Int.(stack_depth > 10_000) then + fail Typechecking_too_many_recursive_calls + else + parse_data + ?type_logger + ~stack_depth:(stack_depth + 1) + ctxt + ~legacy + ~allow_forged + ty + script_data + in + let parse_data_error () = + serialize_ty_for_error ctxt ty >|? fun (ty, _ctxt) -> + Invalid_constant (location script_data, strip_locations script_data, ty) + in + let fail_parse_data () = parse_data_error () >>?= fail in + let traced_no_lwt body = record_trace_eval parse_data_error body in + let traced body = + trace_eval (fun () -> Lwt.return @@ parse_data_error ()) body + in + let traced_fail err = Lwt.return @@ traced_no_lwt (error err) in + let parse_items ?type_logger ctxt expr key_type value_type items item_wrapper + = + List.fold_left_es + (fun (last_value, map, ctxt) item -> + match item with + | Prim (loc, D_Elt, [k; v], annot) -> + (if legacy then ok_unit else error_unexpected_annot loc annot) + >>?= fun () -> + parse_comparable_data ?type_logger ctxt key_type k + >>=? fun (k, ctxt) -> + non_terminal_recursion ?type_logger ctxt ~legacy value_type v + >>=? fun (v, ctxt) -> + Lwt.return + ( (match last_value with + | Some value -> + Gas.consume + ctxt + (Michelson_v1_gas.Cost_of.Interpreter.compare + key_type + value + k) + >>? fun ctxt -> + let c = + Script_comparable.compare_comparable key_type value k + in + if Compare.Int.(0 <= c) then + if Compare.Int.(0 = c) then + error (Duplicate_map_keys (loc, strip_locations expr)) + else + error (Unordered_map_keys (loc, strip_locations expr)) + else ok ctxt + | None -> ok ctxt) + >>? fun ctxt -> + Gas.consume + ctxt + (Michelson_v1_gas.Cost_of.Interpreter.map_update k map) + >|? fun ctxt -> + (Some k, Script_map.update k (Some (item_wrapper v)) map, ctxt) + ) + | Prim (loc, D_Elt, l, _) -> + fail @@ Invalid_arity (loc, D_Elt, 2, List.length l) + | Prim (loc, name, _, _) -> + fail @@ Invalid_primitive (loc, [D_Elt], name) + | Int _ | String _ | Bytes _ | Seq _ -> fail_parse_data ()) + (None, Script_map.empty key_type, ctxt) + items + |> traced + >|=? fun (_, items, ctxt) -> (items, ctxt) + in + let parse_big_map_items (type t) ?type_logger ctxt expr + (key_type : t comparable_ty) value_type items item_wrapper = + List.fold_left_es + (fun (last_key, {map; size}, ctxt) item -> + match item with + | Prim (loc, D_Elt, [k; v], annot) -> + (if legacy then ok_unit else error_unexpected_annot loc annot) + >>?= fun () -> + parse_comparable_data ?type_logger ctxt key_type k + >>=? fun (k, ctxt) -> + hash_comparable_data ctxt key_type k >>=? fun (key_hash, ctxt) -> + non_terminal_recursion ?type_logger ctxt ~legacy value_type v + >>=? fun (v, ctxt) -> + Lwt.return + ( (match last_key with + | Some last_key -> + Gas.consume + ctxt + (Michelson_v1_gas.Cost_of.Interpreter.compare + key_type + last_key + k) + >>? fun ctxt -> + let c = + Script_comparable.compare_comparable key_type last_key k + in + if Compare.Int.(0 <= c) then + if Compare.Int.(0 = c) then + error (Duplicate_map_keys (loc, strip_locations expr)) + else + error (Unordered_map_keys (loc, strip_locations expr)) + else ok ctxt + | None -> ok ctxt) + >>? fun ctxt -> + Gas.consume + ctxt + (Michelson_v1_gas.Cost_of.Interpreter.big_map_update + {map; size}) + >>? fun ctxt -> + if Big_map_overlay.mem key_hash map then + error (Duplicate_map_keys (loc, strip_locations expr)) + else + ok + ( Some k, + { + map = + Big_map_overlay.add key_hash (k, item_wrapper v) map; + size = size + 1; + }, + ctxt ) ) + | Prim (loc, D_Elt, l, _) -> + fail @@ Invalid_arity (loc, D_Elt, 2, List.length l) + | Prim (loc, name, _, _) -> + fail @@ Invalid_primitive (loc, [D_Elt], name) + | Int _ | String _ | Bytes _ | Seq _ -> fail_parse_data ()) + (None, {map = Big_map_overlay.empty; size = 0}, ctxt) + items + |> traced + >|=? fun (_, map, ctxt) -> (map, ctxt) + in + match (ty, script_data) with + | (Unit_t _, expr) -> + Lwt.return @@ traced_no_lwt + @@ (parse_unit ctxt ~legacy expr : (a * context) tzresult) + | (Bool_t _, expr) -> + Lwt.return @@ traced_no_lwt @@ parse_bool ctxt ~legacy expr + | (String_t _, expr) -> Lwt.return @@ traced_no_lwt @@ parse_string ctxt expr + | (Bytes_t _, expr) -> Lwt.return @@ traced_no_lwt @@ parse_bytes ctxt expr + | (Int_t _, expr) -> Lwt.return @@ traced_no_lwt @@ parse_int ctxt expr + | (Nat_t _, expr) -> Lwt.return @@ traced_no_lwt @@ parse_nat ctxt expr + | (Mutez_t _, expr) -> Lwt.return @@ traced_no_lwt @@ parse_mutez ctxt expr + | (Timestamp_t _, expr) -> + Lwt.return @@ traced_no_lwt @@ parse_timestamp ctxt expr + | (Key_t _, expr) -> Lwt.return @@ traced_no_lwt @@ parse_key ctxt expr + | (Key_hash_t _, expr) -> + Lwt.return @@ traced_no_lwt @@ parse_key_hash ctxt expr + | (Signature_t _, expr) -> + Lwt.return @@ traced_no_lwt @@ parse_signature ctxt expr + | (Operation_t _, _) -> + (* operations cannot appear in parameters or storage, + the protocol should never parse the bytes of an operation *) + assert false + | (Chain_id_t _, expr) -> + Lwt.return @@ traced_no_lwt @@ parse_chain_id ctxt expr + | (Address_t _, expr) -> + Lwt.return @@ traced_no_lwt @@ parse_address ctxt expr + | (Contract_t (ty, _), expr) -> + traced + ( parse_address ctxt expr >>?= fun ((c, entrypoint), ctxt) -> + let loc = location expr in + parse_contract + ~stack_depth:(stack_depth + 1) + ~legacy + ctxt + loc + ty + c + ~entrypoint + >|=? fun (ctxt, _) -> ((ty, (c, entrypoint)), ctxt) ) + (* Pairs *) + | (Pair_t ((tl, _, _), (tr, _, _), _), expr) -> + let r_witness = comb_witness1 tr in + let parse_l ctxt v = + non_terminal_recursion ?type_logger ctxt ~legacy tl v + in + let parse_r ctxt v = + non_terminal_recursion ?type_logger ctxt ~legacy tr v + in + traced @@ parse_pair parse_l parse_r ctxt ~legacy r_witness expr + (* Unions *) + | (Union_t ((tl, _), (tr, _), _), expr) -> + let parse_l ctxt v = + non_terminal_recursion ?type_logger ctxt ~legacy tl v + in + let parse_r ctxt v = + non_terminal_recursion ?type_logger ctxt ~legacy tr v + in + traced @@ parse_union parse_l parse_r ctxt ~legacy expr + (* Lambdas *) + | (Lambda_t (ta, tr, _ty_name), (Seq (_loc, _) as script_instr)) -> + traced + @@ parse_returning + Lambda + ?type_logger + ~stack_depth:(stack_depth + 1) + ctxt + ~legacy + (ta, Some (Var_annot "@arg")) + tr + script_instr + | (Lambda_t _, expr) -> + traced_fail (Invalid_kind (location expr, [Seq_kind], kind expr)) + (* Options *) + | (Option_t (t, _), expr) -> + let parse_v ctxt v = + non_terminal_recursion ?type_logger ctxt ~legacy t v + in + traced @@ parse_option parse_v ctxt ~legacy expr + (* Lists *) + | (List_t (t, _ty_name), Seq (_loc, items)) -> + traced + @@ List.fold_right_es + (fun v (rest, ctxt) -> + non_terminal_recursion ?type_logger ctxt ~legacy t v + >|=? fun (v, ctxt) -> (Script_list.cons v rest, ctxt)) + items + (Script_list.empty, ctxt) + | (List_t _, expr) -> + traced_fail (Invalid_kind (location expr, [Seq_kind], kind expr)) + (* Tickets *) + | (Ticket_t (t, _ty_name), expr) -> + if allow_forged then + opened_ticket_type (location expr) t >>?= fun ty -> + parse_comparable_data ?type_logger ctxt ty expr + >|=? fun ((ticketer, (contents, amount)), ctxt) -> + ({ticketer; contents; amount}, ctxt) + else traced_fail (Unexpected_forged_value (location expr)) + (* Sets *) + | (Set_t (t, _ty_name), (Seq (loc, vs) as expr)) -> + traced + @@ List.fold_left_es + (fun (last_value, set, ctxt) v -> + parse_comparable_data ?type_logger ctxt t v >>=? fun (v, ctxt) -> + Lwt.return + ( (match last_value with + | Some value -> + Gas.consume + ctxt + (Michelson_v1_gas.Cost_of.Interpreter.compare t value v) + >>? fun ctxt -> + let c = Script_comparable.compare_comparable t value v in + if Compare.Int.(0 <= c) then + if Compare.Int.(0 = c) then + error + (Duplicate_set_values (loc, strip_locations expr)) + else + error + (Unordered_set_values (loc, strip_locations expr)) + else ok ctxt + | None -> ok ctxt) + >>? fun ctxt -> + Gas.consume + ctxt + (Michelson_v1_gas.Cost_of.Interpreter.set_update v set) + >|? fun ctxt -> (Some v, Script_set.update v true set, ctxt) )) + (None, Script_set.empty t, ctxt) + vs + >|=? fun (_, set, ctxt) -> (set, ctxt) + | (Set_t _, expr) -> + traced_fail (Invalid_kind (location expr, [Seq_kind], kind expr)) + (* Maps *) + | (Map_t (tk, tv, _ty_name), (Seq (_, vs) as expr)) -> + parse_items ?type_logger ctxt expr tk tv vs (fun x -> x) + | (Map_t _, expr) -> + traced_fail (Invalid_kind (location expr, [Seq_kind], kind expr)) + | (Big_map_t (tk, tv, _ty_name), expr) -> + (match expr with + | Int (loc, id) -> + return (Some (id, loc), {map = Big_map_overlay.empty; size = 0}, ctxt) + | Seq (_, vs) -> + parse_big_map_items ?type_logger ctxt expr tk tv vs (fun x -> Some x) + >|=? fun (diff, ctxt) -> (None, diff, ctxt) + | Prim (loc, D_Pair, [Int (loc_id, id); Seq (_, vs)], annot) -> + error_unexpected_annot loc annot >>?= fun () -> + option_t loc tv ~annot:None >>?= fun tv_opt -> + parse_big_map_items ?type_logger ctxt expr tk tv_opt vs (fun x -> x) + >|=? fun (diff, ctxt) -> (Some (id, loc_id), diff, ctxt) + | Prim (_, D_Pair, [Int _; expr], _) -> + traced_fail (Invalid_kind (location expr, [Seq_kind], kind expr)) + | Prim (_, D_Pair, [expr; _], _) -> + traced_fail (Invalid_kind (location expr, [Int_kind], kind expr)) + | Prim (loc, D_Pair, l, _) -> + traced_fail @@ Invalid_arity (loc, D_Pair, 2, List.length l) + | _ -> + traced_fail + (unexpected expr [Seq_kind; Int_kind] Constant_namespace [D_Pair])) + >>=? fun (id_opt, diff, ctxt) -> + (match id_opt with + | None -> return @@ (None, ctxt) + | Some (id, loc) -> + if allow_forged then + let id = Big_map.Id.parse_z id in + Big_map.exists ctxt id >>=? function + | (_, None) -> traced_fail (Invalid_big_map (loc, id)) + | (ctxt, Some (btk, btv)) -> + Lwt.return + ( parse_comparable_ty + ~stack_depth:(stack_depth + 1) + ctxt + (Micheline.root btk) + >>? fun (Ex_comparable_ty btk, ctxt) -> + parse_big_map_value_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + (Micheline.root btv) + >>? fun (Ex_ty btv, ctxt) -> + comparable_ty_eq ctxt tk btk >>? fun (Eq, ctxt) -> + ty_eq ~legacy:true ctxt loc tv btv >>? fun (Eq, ctxt) -> + ok (Some id, ctxt) ) + else traced_fail (Unexpected_forged_value loc)) + >|=? fun (id, ctxt) -> ({id; diff; key_type = tk; value_type = tv}, ctxt) + | (Never_t _, expr) -> Lwt.return @@ traced_no_lwt @@ parse_never expr + (* Bls12_381 types *) + | (Bls12_381_g1_t _, Bytes (_, bs)) -> ( + Gas.consume ctxt Typecheck_costs.bls12_381_g1 >>?= fun ctxt -> + match Bls12_381.G1.of_bytes_opt bs with + | Some pt -> return (pt, ctxt) + | None -> fail_parse_data ()) + | (Bls12_381_g1_t _, expr) -> + traced_fail (Invalid_kind (location expr, [Bytes_kind], kind expr)) + | (Bls12_381_g2_t _, Bytes (_, bs)) -> ( + Gas.consume ctxt Typecheck_costs.bls12_381_g2 >>?= fun ctxt -> + match Bls12_381.G2.of_bytes_opt bs with + | Some pt -> return (pt, ctxt) + | None -> fail_parse_data ()) + | (Bls12_381_g2_t _, expr) -> + traced_fail (Invalid_kind (location expr, [Bytes_kind], kind expr)) + | (Bls12_381_fr_t _, Bytes (_, bs)) -> ( + Gas.consume ctxt Typecheck_costs.bls12_381_fr >>?= fun ctxt -> + match Bls12_381.Fr.of_bytes_opt bs with + | Some pt -> return (pt, ctxt) + | None -> fail_parse_data ()) + | (Bls12_381_fr_t _, Int (_, v)) -> + Gas.consume ctxt Typecheck_costs.bls12_381_fr >>?= fun ctxt -> + return (Bls12_381.Fr.of_z v, ctxt) + | (Bls12_381_fr_t _, expr) -> + traced_fail (Invalid_kind (location expr, [Bytes_kind], kind expr)) + (* + /!\ When adding new lazy storage kinds, you may want to guard the parsing + of identifiers with [allow_forged]. + *) + (* Sapling *) + | (Sapling_transaction_t (memo_size, _), Bytes (_, bytes)) -> ( + match + Data_encoding.Binary.of_bytes_opt Sapling.transaction_encoding bytes + with + | Some transaction -> ( + match Sapling.transaction_get_memo_size transaction with + | None -> return (transaction, ctxt) + | Some transac_memo_size -> + Lwt.return + ( merge_memo_sizes memo_size transac_memo_size >|? fun _ms -> + (transaction, ctxt) )) + | None -> fail_parse_data ()) + | (Sapling_transaction_t _, expr) -> + traced_fail (Invalid_kind (location expr, [Bytes_kind], kind expr)) + | (Sapling_state_t (memo_size, _), Int (loc, id)) -> + if allow_forged then + let id = Sapling.Id.parse_z id in + Sapling.state_from_id ctxt id >>=? fun (state, ctxt) -> + Lwt.return + ( traced_no_lwt @@ merge_memo_sizes memo_size state.Sapling.memo_size + >|? fun _memo_size -> (state, ctxt) ) + else traced_fail (Unexpected_forged_value loc) + | (Sapling_state_t (memo_size, _), Seq (_, [])) -> + return (Sapling.empty_state ~memo_size (), ctxt) + | (Sapling_state_t _, expr) -> + (* Do not allow to input diffs as they are untrusted and may not be the + result of a verify_update. *) + traced_fail + (Invalid_kind (location expr, [Int_kind; Seq_kind], kind expr)) + (* Time lock*) + | (Chest_key_t _, Bytes (_, bytes)) -> ( + Gas.consume ctxt Typecheck_costs.chest_key >>?= fun ctxt -> + match + Data_encoding.Binary.of_bytes_opt Timelock.chest_key_encoding bytes + with + | Some chest_key -> return (chest_key, ctxt) + | None -> fail_parse_data ()) + | (Chest_key_t _, expr) -> + traced_fail (Invalid_kind (location expr, [Bytes_kind], kind expr)) + | (Chest_t _, Bytes (_, bytes)) -> ( + Gas.consume ctxt (Typecheck_costs.chest ~bytes:(Bytes.length bytes)) + >>?= fun ctxt -> + match Data_encoding.Binary.of_bytes_opt Timelock.chest_encoding bytes with + | Some chest -> return (chest, ctxt) + | None -> fail_parse_data ()) + | (Chest_t _, expr) -> + traced_fail (Invalid_kind (location expr, [Bytes_kind], kind expr)) + +and parse_view_returning : + type storage. + ?type_logger:type_logger -> + context -> + legacy:bool -> + storage ty -> + view -> + (storage ex_view * context) tzresult Lwt.t = + fun ?type_logger ctxt ~legacy storage_type {input_ty; output_ty; view_code} -> + let input_ty_loc = location input_ty in + record_trace_eval + (fun () -> + ok + @@ Ill_formed_type + (Some "arg of view", strip_locations input_ty, input_ty_loc)) + (parse_view_input_ty ctxt ~stack_depth:0 ~legacy input_ty) + >>?= fun (Ex_ty input_ty', ctxt) -> + let output_ty_loc = location output_ty in + record_trace_eval + (fun () -> + ok + @@ Ill_formed_type + (Some "return of view", strip_locations output_ty, output_ty_loc)) + (parse_view_output_ty ctxt ~stack_depth:0 ~legacy output_ty) + >>?= fun (Ex_ty output_ty', ctxt) -> + pair_t + input_ty_loc + (input_ty', None, None) + (storage_type, None, None) + ~annot:None + >>?= fun pair_ty -> + parse_instr + ?type_logger + ~stack_depth:0 + Lambda + ctxt + ~legacy + view_code + (Item_t (pair_ty, Bot_t, None)) + >>=? fun (judgement, ctxt) -> + Lwt.return + @@ + match judgement with + | Failed {descr} -> + let cur_view' = + Ex_view + (Lam + (close_descr (descr (Item_t (output_ty', Bot_t, None))), view_code)) + in + ok (cur_view', ctxt) + | Typed ({loc; aft; _} as descr) -> ( + let ill_type_view loc stack_ty = + serialize_stack_for_error ctxt stack_ty >>? fun (actual, ctxt) -> + let expected_stack = Item_t (output_ty', Bot_t, None) in + serialize_stack_for_error ctxt expected_stack + >>? fun (expected, _ctxt) -> + error (Ill_typed_view {loc; actual; expected}) + in + match aft with + | Item_t (ty, Bot_t, _) -> + record_trace_eval + (fun () -> ill_type_view loc aft) + ( ty_eq ~legacy ctxt loc ty output_ty' >|? fun (Eq, ctxt) -> + let view' = Ex_view (Lam (close_descr descr, view_code)) in + (view', ctxt) ) + | _ -> ill_type_view loc aft) + +and typecheck_views : + type storage. + ?type_logger:type_logger -> + context -> + legacy:bool -> + storage ty -> + view SMap.t -> + context tzresult Lwt.t = + fun ?type_logger ctxt ~legacy storage_type views -> + let aux _name cur_view ctxt = + parse_view_returning ?type_logger ctxt ~legacy storage_type cur_view + >|=? fun (_parsed_view, ctxt) -> ctxt + in + SMap.fold_es aux views ctxt + +and[@coq_axiom_with_reason "gadt"] parse_returning : + type arg ret. + ?type_logger:type_logger -> + stack_depth:int -> + tc_context -> + context -> + legacy:bool -> + arg ty * var_annot option -> + ret ty -> + Script.node -> + ((arg, ret) lambda * context) tzresult Lwt.t = + fun ?type_logger + ~stack_depth + tc_context + ctxt + ~legacy + (arg, arg_annot) + ret + script_instr -> + parse_instr + ?type_logger + tc_context + ctxt + ~legacy + ~stack_depth:(stack_depth + 1) + script_instr + (Item_t (arg, Bot_t, arg_annot)) + >>=? function + | (Typed ({loc; aft = Item_t (ty, Bot_t, _) as stack_ty; _} as descr), ctxt) + -> + Lwt.return + @@ record_trace_eval + (fun () -> + serialize_ty_for_error ctxt ret >>? fun (ret, ctxt) -> + serialize_stack_for_error ctxt stack_ty + >|? fun (stack_ty, _ctxt) -> Bad_return (loc, stack_ty, ret)) + ( ty_eq ~legacy ctxt loc ty ret >|? fun (Eq, ctxt) -> + ((Lam (close_descr descr, script_instr) : (arg, ret) lambda), ctxt) + ) + | (Typed {loc; aft = stack_ty; _}, ctxt) -> + Lwt.return + ( serialize_ty_for_error ctxt ret >>? fun (ret, ctxt) -> + serialize_stack_for_error ctxt stack_ty >>? fun (stack_ty, _ctxt) -> + error (Bad_return (loc, stack_ty, ret)) ) + | (Failed {descr}, ctxt) -> + return + ( (Lam (close_descr (descr (Item_t (ret, Bot_t, None))), script_instr) + : (arg, ret) lambda), + ctxt ) + +and[@coq_axiom_with_reason "gadt"] parse_instr : + type a s. + ?type_logger:type_logger -> + stack_depth:int -> + tc_context -> + context -> + legacy:bool -> + Script.node -> + (a, s) stack_ty -> + ((a, s) judgement * context) tzresult Lwt.t = + fun ?type_logger ~stack_depth tc_context ctxt ~legacy script_instr stack_ty -> + let check_item_ty (type a b) ctxt (exp : a ty) (got : b ty) loc name n m : + ((a, b) eq * a ty * context) tzresult = + record_trace_eval (fun () -> + serialize_stack_for_error ctxt stack_ty >|? fun (stack_ty, _ctxt) -> + Bad_stack (loc, name, m, stack_ty)) + @@ record_trace + (Bad_stack_item n) + ( Gas_monad.run ctxt + @@ merge_types + ~legacy + ~merge_type_error_flag:Default_merge_type_error + loc + exp + got + >>? fun (eq_ty, ctxt) -> + eq_ty >|? fun (Eq, ty) -> ((Eq : (a, b) eq), (ty : a ty), ctxt) ) + in + let log_stack ctxt loc stack_ty aft = + match (type_logger, script_instr) with + | (None, _) | (Some _, (Seq (-1, _) | Int _ | String _ | Bytes _)) -> + ok_unit + | (Some log, (Prim _ | Seq _)) -> + (* Unparsing for logging done in an unlimited context as this + is used only by the client and not the protocol *) + let ctxt = Gas.set_unlimited ctxt in + unparse_stack ctxt stack_ty >>? fun (stack_ty, _) -> + unparse_stack ctxt aft >|? fun (aft, _) -> + log loc stack_ty aft ; + () + in + let typed_no_lwt ctxt loc instr aft = + log_stack ctxt loc stack_ty aft >|? fun () -> + let j = Typed {loc; instr; bef = stack_ty; aft} in + (j, ctxt) + in + let typed ctxt loc instr aft = + Lwt.return @@ typed_no_lwt ctxt loc instr aft + in + Gas.consume ctxt Typecheck_costs.parse_instr_cycle >>?= fun ctxt -> + let non_terminal_recursion ?type_logger tc_context ctxt ~legacy script_instr + stack_ty = + if Compare.Int.(stack_depth > 10000) then + fail Typechecking_too_many_recursive_calls + else + parse_instr + ?type_logger + tc_context + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + script_instr + stack_ty + in + match (script_instr, stack_ty) with + (* stack ops *) + | (Prim (loc, I_DROP, [], annot), Item_t (_, rest, _)) -> + (error_unexpected_annot loc annot >>?= fun () -> + typed ctxt loc {apply = (fun kinfo k -> IDrop (kinfo, k))} rest + : ((a, s) judgement * context) tzresult Lwt.t) + | (Prim (loc, I_DROP, [n], result_annot), whole_stack) -> + parse_uint10 n >>?= fun whole_n -> + Gas.consume ctxt (Typecheck_costs.proof_argument whole_n) >>?= fun ctxt -> + let rec make_proof_argument : + type a s. + int -> (a, s) stack_ty -> (a, s) dropn_proof_argument tzresult = + fun n stk -> + match (Compare.Int.(n = 0), stk) with + | (true, rest) -> ok @@ Dropn_proof_argument (KRest, rest) + | (false, Item_t (_, rest, _)) -> + make_proof_argument (n - 1) rest + >|? fun (Dropn_proof_argument (n', stack_after_drops)) -> + let kinfo = {iloc = loc; kstack_ty = rest} in + Dropn_proof_argument (KPrefix (kinfo, n'), stack_after_drops) + | (_, _) -> + serialize_stack_for_error ctxt whole_stack + >>? fun (whole_stack, _ctxt) -> + error (Bad_stack (loc, I_DROP, whole_n, whole_stack)) + in + error_unexpected_annot loc result_annot >>?= fun () -> + make_proof_argument whole_n whole_stack + >>?= fun (Dropn_proof_argument (n', stack_after_drops)) -> + let kdropn kinfo k = IDropn (kinfo, whole_n, n', k) in + typed ctxt loc {apply = kdropn} stack_after_drops + | (Prim (loc, I_DROP, (_ :: _ :: _ as l), _), _) -> + (* Technically, the arities 0 and 1 are allowed but the error only mentions 1. + However, DROP is equivalent to DROP 1 so hinting at an arity of 1 makes sense. *) + fail (Invalid_arity (loc, I_DROP, 1, List.length l)) + | (Prim (loc, I_DUP, [], annot), Item_t (v, rest, stack_annot)) -> + parse_var_annot loc annot ~default:stack_annot >>?= fun annot -> + record_trace_eval + (fun () -> + serialize_ty_for_error ctxt v >|? fun (t, _ctxt) -> + Non_dupable_type (loc, t)) + (check_dupable_ty ctxt loc v) + >>?= fun ctxt -> + let dup = {apply = (fun kinfo k -> IDup (kinfo, k))} in + typed ctxt loc dup (Item_t (v, Item_t (v, rest, stack_annot), annot)) + | (Prim (loc, I_DUP, [n], v_annot), stack_ty) -> + parse_var_annot loc v_annot >>?= fun annot -> + let rec make_proof_argument : + type a s. + int -> (a, s) stack_ty -> (a * s) dup_n_proof_argument tzresult = + fun n (stack_ty : (a, s) stack_ty) -> + match (n, stack_ty) with + | (1, Item_t (hd_ty, _, _)) -> + ok @@ Dup_n_proof_argument (Dup_n_zero, hd_ty) + | (n, Item_t (_, tl_ty, _)) -> + make_proof_argument (n - 1) tl_ty + >|? fun (Dup_n_proof_argument (dup_n_witness, b_ty)) -> + Dup_n_proof_argument (Dup_n_succ dup_n_witness, b_ty) + | _ -> + serialize_stack_for_error ctxt stack_ty + >>? fun (whole_stack, _ctxt) -> + error (Bad_stack (loc, I_DUP, 1, whole_stack)) + in + parse_uint10 n >>?= fun n -> + Gas.consume ctxt (Typecheck_costs.proof_argument n) >>?= fun ctxt -> + error_unless (Compare.Int.( > ) n 0) (Dup_n_bad_argument loc) + >>?= fun () -> + record_trace (Dup_n_bad_stack loc) (make_proof_argument n stack_ty) + >>?= fun (Dup_n_proof_argument (witness, after_ty)) -> + record_trace_eval + (fun () -> + serialize_ty_for_error ctxt after_ty >|? fun (t, _ctxt) -> + Non_dupable_type (loc, t)) + (check_dupable_ty ctxt loc after_ty) + >>?= fun ctxt -> + let dupn = {apply = (fun kinfo k -> IDup_n (kinfo, n, witness, k))} in + typed ctxt loc dupn (Item_t (after_ty, stack_ty, annot)) + | (Prim (loc, I_DIG, [n], result_annot), stack) -> + let rec make_proof_argument : + type a s. int -> (a, s) stack_ty -> (a, s) dig_proof_argument tzresult + = + fun n stk -> + match (Compare.Int.(n = 0), stk) with + | (true, Item_t (v, rest, annot)) -> + ok @@ Dig_proof_argument (KRest, v, annot, rest) + | (false, Item_t (v, rest, annot)) -> + make_proof_argument (n - 1) rest + >|? fun (Dig_proof_argument (n', x, xv, aft')) -> + let kinfo = {iloc = loc; kstack_ty = aft'} in + Dig_proof_argument + (KPrefix (kinfo, n'), x, xv, Item_t (v, aft', annot)) + | (_, _) -> + serialize_stack_for_error ctxt stack >>? fun (whole_stack, _ctxt) -> + error (Bad_stack (loc, I_DIG, 3, whole_stack)) + in + parse_uint10 n >>?= fun n -> + Gas.consume ctxt (Typecheck_costs.proof_argument n) >>?= fun ctxt -> + error_unexpected_annot loc result_annot >>?= fun () -> + make_proof_argument n stack + >>?= fun (Dig_proof_argument (n', x, stack_annot, aft)) -> + let dig = {apply = (fun kinfo k -> IDig (kinfo, n, n', k))} in + typed ctxt loc dig (Item_t (x, aft, stack_annot)) + | (Prim (loc, I_DIG, (([] | _ :: _ :: _) as l), _), _) -> + fail (Invalid_arity (loc, I_DIG, 1, List.length l)) + | (Prim (loc, I_DUG, [n], result_annot), Item_t (x, whole_stack, stack_annot)) + -> + parse_uint10 n >>?= fun whole_n -> + Gas.consume ctxt (Typecheck_costs.proof_argument whole_n) >>?= fun ctxt -> + let rec make_proof_argument : + type a s x. + int -> + x ty -> + var_annot option -> + (a, s) stack_ty -> + (a, s, x) dug_proof_argument tzresult = + fun n x stack_annot stk -> + match (Compare.Int.(n = 0), stk) with + | (true, rest) -> + ok @@ Dug_proof_argument (KRest, (), Item_t (x, rest, stack_annot)) + | (false, Item_t (v, rest, annot)) -> + make_proof_argument (n - 1) x stack_annot rest + >|? fun (Dug_proof_argument (n', (), aft')) -> + let kinfo = {iloc = loc; kstack_ty = aft'} in + Dug_proof_argument (KPrefix (kinfo, n'), (), Item_t (v, aft', annot)) + | (_, _) -> + serialize_stack_for_error ctxt whole_stack + >>? fun (whole_stack, _ctxt) -> + error (Bad_stack (loc, I_DUG, whole_n, whole_stack)) + in + error_unexpected_annot loc result_annot >>?= fun () -> + make_proof_argument whole_n x stack_annot whole_stack + >>?= fun (Dug_proof_argument (n', (), aft)) -> + let dug = {apply = (fun kinfo k -> IDug (kinfo, whole_n, n', k))} in + typed ctxt loc dug aft + | (Prim (loc, I_DUG, [_], result_annot), stack) -> + Lwt.return + ( error_unexpected_annot loc result_annot >>? fun () -> + serialize_stack_for_error ctxt stack >>? fun (stack, _ctxt) -> + error (Bad_stack (loc, I_DUG, 1, stack)) ) + | (Prim (loc, I_DUG, (([] | _ :: _ :: _) as l), _), _) -> + fail (Invalid_arity (loc, I_DUG, 1, List.length l)) + | ( Prim (loc, I_SWAP, [], annot), + Item_t (v, Item_t (w, rest, stack_annot), cur_top_annot) ) -> + error_unexpected_annot loc annot >>?= fun () -> + let swap = {apply = (fun kinfo k -> ISwap (kinfo, k))} in + let stack_ty = Item_t (w, Item_t (v, rest, cur_top_annot), stack_annot) in + typed ctxt loc swap stack_ty + | (Prim (loc, I_PUSH, [t; d], annot), stack) -> + parse_var_annot loc annot >>?= fun annot -> + parse_packable_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy t + >>?= fun (Ex_ty t, ctxt) -> + parse_data + ?type_logger + ~stack_depth:(stack_depth + 1) + ctxt + ~legacy + ~allow_forged:false + t + d + >>=? fun (v, ctxt) -> + let const = {apply = (fun kinfo k -> IConst (kinfo, v, k))} in + typed ctxt loc const (Item_t (t, stack, annot)) + | (Prim (loc, I_UNIT, [], annot), stack) -> + parse_var_type_annot loc annot >>?= fun (annot, ty_name) -> + let const = {apply = (fun kinfo k -> IConst (kinfo, (), k))} in + typed ctxt loc const (Item_t (unit_t ~annot:ty_name, stack, annot)) + (* options *) + | (Prim (loc, I_SOME, [], annot), Item_t (t, rest, _)) -> + parse_var_type_annot loc annot >>?= fun (annot, ty_name) -> + let cons_some = {apply = (fun kinfo k -> ICons_some (kinfo, k))} in + option_t loc t ~annot:ty_name >>?= fun ty -> + typed ctxt loc cons_some (Item_t (ty, rest, annot)) + | (Prim (loc, I_NONE, [t], annot), stack) -> + parse_any_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy t + >>?= fun (Ex_ty t, ctxt) -> + parse_var_type_annot loc annot >>?= fun (annot, ty_name) -> + let cons_none = {apply = (fun kinfo k -> ICons_none (kinfo, k))} in + option_t loc t ~annot:ty_name >>?= fun ty -> + let stack_ty = Item_t (ty, stack, annot) in + typed ctxt loc cons_none stack_ty + | ( Prim (loc, I_IF_NONE, [bt; bf], annot), + (Item_t (Option_t (t, _), rest, option_annot) as bef) ) -> + check_kind [Seq_kind] bt >>?= fun () -> + check_kind [Seq_kind] bf >>?= fun () -> + error_unexpected_annot loc annot >>?= fun () -> + let annot = gen_access_annot option_annot default_some_annot in + non_terminal_recursion ?type_logger tc_context ctxt ~legacy bt rest + >>=? fun (btr, ctxt) -> + let stack_ty = Item_t (t, rest, annot) in + non_terminal_recursion ?type_logger tc_context ctxt ~legacy bf stack_ty + >>=? fun (bfr, ctxt) -> + let branch ibt ibf = + let ifnone = + { + apply = + (fun kinfo k -> + let hinfo = kinfo_of_kinstr k in + let btinfo = kinfo_of_descr ibt + and bfinfo = kinfo_of_descr ibf in + let branch_if_none = ibt.instr.apply btinfo (IHalt hinfo) + and branch_if_some = ibf.instr.apply bfinfo (IHalt hinfo) in + IIf_none {kinfo; branch_if_none; branch_if_some; k}); + } + in + {loc; instr = ifnone; bef; aft = ibt.aft} + in + Lwt.return @@ merge_branches ~legacy ctxt loc btr bfr {branch} + (* pairs *) + | ( Prim (loc, I_PAIR, [], annot), + Item_t (a, Item_t (b, rest, snd_annot), fst_annot) ) -> + parse_constr_annot + loc + annot + ~if_special_first:(var_to_field_annot fst_annot) + ~if_special_second:(var_to_field_annot snd_annot) + >>?= fun (annot, ty_name, l_field, r_field) -> + pair_t loc (a, l_field, fst_annot) (b, r_field, snd_annot) ~annot:ty_name + >>?= fun ty -> + let stack_ty = Item_t (ty, rest, annot) in + let cons_pair = {apply = (fun kinfo k -> ICons_pair (kinfo, k))} in + typed ctxt loc cons_pair stack_ty + | (Prim (loc, I_PAIR, [n], annot), stack_ty) -> + parse_var_annot loc annot >>?= fun annot -> + let rec make_proof_argument : + type a s. + int -> (a, s) stack_ty -> (a * s) comb_proof_argument tzresult = + fun n stack_ty -> + match (n, stack_ty) with + | (1, Item_t (a_ty, tl_ty, _a_annot_opt)) -> + ok (Comb_proof_argument (Comb_one, Item_t (a_ty, tl_ty, annot))) + | (n, Item_t (a_ty, tl_ty, _prop_annot_opt)) -> + make_proof_argument (n - 1) tl_ty + >>? fun (Comb_proof_argument + (comb_witness, Item_t (b_ty, tl_ty', annot))) -> + pair_t loc (a_ty, None, None) (b_ty, None, None) ~annot:None + >|? fun pair_t -> + Comb_proof_argument + (Comb_succ comb_witness, Item_t (pair_t, tl_ty', annot)) + | _ -> + serialize_stack_for_error ctxt stack_ty + >>? fun (whole_stack, _ctxt) -> + error (Bad_stack (loc, I_PAIR, 1, whole_stack)) + in + parse_uint10 n >>?= fun n -> + Gas.consume ctxt (Typecheck_costs.proof_argument n) >>?= fun ctxt -> + error_unless (Compare.Int.( > ) n 1) (Pair_bad_argument loc) + >>?= fun () -> + make_proof_argument n stack_ty + >>?= fun (Comb_proof_argument (witness, after_ty)) -> + let comb = {apply = (fun kinfo k -> IComb (kinfo, n, witness, k))} in + typed ctxt loc comb after_ty + | (Prim (loc, I_UNPAIR, [n], annot), stack_ty) -> + error_unexpected_annot loc annot >>?= fun () -> + let rec make_proof_argument : + type a s. + int -> (a, s) stack_ty -> (a * s) uncomb_proof_argument tzresult = + fun n stack_ty -> + match (n, stack_ty) with + | (1, Item_t (a_ty, tl_ty, annot)) -> + ok @@ Uncomb_proof_argument (Uncomb_one, Item_t (a_ty, tl_ty, annot)) + | ( n, + Item_t + ( Pair_t ((a_ty, field_opt, _), (b_ty, b_field_opt, _), _), + tl_ty, + _ ) ) -> + let b_annot = Script_ir_annot.field_to_var_annot b_field_opt in + make_proof_argument (n - 1) (Item_t (b_ty, tl_ty, b_annot)) + >|? fun (Uncomb_proof_argument (uncomb_witness, after_ty)) -> + Uncomb_proof_argument + ( Uncomb_succ uncomb_witness, + Item_t + (a_ty, after_ty, Script_ir_annot.field_to_var_annot field_opt) + ) + | _ -> + serialize_stack_for_error ctxt stack_ty + >>? fun (whole_stack, _ctxt) -> + error (Bad_stack (loc, I_UNPAIR, 1, whole_stack)) + in + parse_uint10 n >>?= fun n -> + Gas.consume ctxt (Typecheck_costs.proof_argument n) >>?= fun ctxt -> + error_unless (Compare.Int.( > ) n 1) (Unpair_bad_argument loc) + >>?= fun () -> + make_proof_argument n stack_ty + >>?= fun (Uncomb_proof_argument (witness, after_ty)) -> + let uncomb = {apply = (fun kinfo k -> IUncomb (kinfo, n, witness, k))} in + typed ctxt loc uncomb after_ty + | (Prim (loc, I_GET, [n], annot), Item_t (comb_ty, rest_ty, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let rec make_proof_argument : + type b. int -> b ty -> b comb_get_proof_argument tzresult = + fun n ty -> + match (n, ty) with + | (0, value_ty) -> + ok @@ Comb_get_proof_argument (Comb_get_zero, value_ty) + | (1, Pair_t ((hd_ty, _at1, _at2), _, _annot)) -> + ok @@ Comb_get_proof_argument (Comb_get_one, hd_ty) + | (n, Pair_t (_, (tl_ty, _bt1, _bt2), _annot)) -> + make_proof_argument (n - 2) tl_ty + >|? fun (Comb_get_proof_argument (comb_get_left_witness, ty')) -> + Comb_get_proof_argument + (Comb_get_plus_two comb_get_left_witness, ty') + | _ -> + serialize_stack_for_error ctxt stack_ty + >>? fun (whole_stack, _ctxt) -> + error (Bad_stack (loc, I_GET, 1, whole_stack)) + in + parse_uint11 n >>?= fun n -> + Gas.consume ctxt (Typecheck_costs.proof_argument n) >>?= fun ctxt -> + make_proof_argument n comb_ty + >>?= fun (Comb_get_proof_argument (witness, ty')) -> + let after_stack_ty = Item_t (ty', rest_ty, annot) in + let comb_get = + {apply = (fun kinfo k -> IComb_get (kinfo, n, witness, k))} + in + typed ctxt loc comb_get after_stack_ty + | ( Prim (loc, I_UPDATE, [n], annot), + Item_t (value_ty, Item_t (comb_ty, rest_ty, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let rec make_proof_argument : + type value before. + int -> + value ty -> + before ty -> + (value, before) comb_set_proof_argument tzresult = + fun n value_ty ty -> + match (n, ty) with + | (0, _) -> ok @@ Comb_set_proof_argument (Comb_set_zero, value_ty) + | (1, Pair_t ((_hd_ty, at1, at2), (tl_ty, bt1, bt2), {annot; _})) -> + pair_t loc (value_ty, at1, at2) (tl_ty, bt1, bt2) ~annot + >|? fun after_ty -> Comb_set_proof_argument (Comb_set_one, after_ty) + | (n, Pair_t ((hd_ty, at1, at2), (tl_ty, bt1, bt2), {annot; _})) -> + make_proof_argument (n - 2) value_ty tl_ty + >>? fun (Comb_set_proof_argument (comb_set_left_witness, tl_ty')) -> + pair_t loc (hd_ty, at1, at2) (tl_ty', bt1, bt2) ~annot + >|? fun after_ty -> + Comb_set_proof_argument + (Comb_set_plus_two comb_set_left_witness, after_ty) + | _ -> + serialize_stack_for_error ctxt stack_ty + >>? fun (whole_stack, _ctxt) -> + error (Bad_stack (loc, I_UPDATE, 2, whole_stack)) + in + parse_uint11 n >>?= fun n -> + Gas.consume ctxt (Typecheck_costs.proof_argument n) >>?= fun ctxt -> + make_proof_argument n value_ty comb_ty + >>?= fun (Comb_set_proof_argument (witness, after_ty)) -> + let after_stack_ty = Item_t (after_ty, rest_ty, annot) in + let comb_set = + {apply = (fun kinfo k -> IComb_set (kinfo, n, witness, k))} + in + typed ctxt loc comb_set after_stack_ty + | ( Prim (loc, I_UNPAIR, [], annot), + Item_t + ( Pair_t + ( (a, expected_field_annot_a, a_annot), + (b, expected_field_annot_b, b_annot), + _ ), + rest, + pair_annot ) ) -> + parse_unpair_annot + loc + annot + ~pair_annot + ~value_annot_car:a_annot + ~value_annot_cdr:b_annot + ~field_name_car:expected_field_annot_a + ~field_name_cdr:expected_field_annot_b + >>?= fun (annot_a, annot_b, field_a, field_b) -> + check_correct_field field_a expected_field_annot_a >>?= fun () -> + check_correct_field field_b expected_field_annot_b >>?= fun () -> + let unpair = {apply = (fun kinfo k -> IUnpair (kinfo, k))} in + typed ctxt loc unpair (Item_t (a, Item_t (b, rest, annot_b), annot_a)) + | ( Prim (loc, I_CAR, [], annot), + Item_t + (Pair_t ((a, expected_field_annot, a_annot), _, _), rest, pair_annot) ) + -> + parse_destr_annot + loc + annot + ~pair_annot + ~value_annot:a_annot + ~field_name:expected_field_annot + ~default_accessor:default_car_annot + >>?= fun (annot, field_annot) -> + check_correct_field field_annot expected_field_annot >>?= fun () -> + let car = {apply = (fun kinfo k -> ICar (kinfo, k))} in + typed ctxt loc car (Item_t (a, rest, annot)) + | ( Prim (loc, I_CDR, [], annot), + Item_t + (Pair_t (_, (b, expected_field_annot, b_annot), _), rest, pair_annot) ) + -> + parse_destr_annot + loc + annot + ~pair_annot + ~value_annot:b_annot + ~field_name:expected_field_annot + ~default_accessor:default_cdr_annot + >>?= fun (annot, field_annot) -> + check_correct_field field_annot expected_field_annot >>?= fun () -> + let cdr = {apply = (fun kinfo k -> ICdr (kinfo, k))} in + typed ctxt loc cdr (Item_t (b, rest, annot)) + (* unions *) + | (Prim (loc, I_LEFT, [tr], annot), Item_t (tl, rest, stack_annot)) -> + parse_any_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy tr + >>?= fun (Ex_ty tr, ctxt) -> + parse_constr_annot + loc + annot + ~if_special_first:(var_to_field_annot stack_annot) + >>?= fun (annot, tname, l_field, r_field) -> + let cons_left = {apply = (fun kinfo k -> ICons_left (kinfo, k))} in + union_t loc (tl, l_field) (tr, r_field) ~annot:tname >>?= fun ty -> + let stack_ty = Item_t (ty, rest, annot) in + typed ctxt loc cons_left stack_ty + | (Prim (loc, I_RIGHT, [tl], annot), Item_t (tr, rest, stack_annot)) -> + parse_any_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy tl + >>?= fun (Ex_ty tl, ctxt) -> + parse_constr_annot + loc + annot + ~if_special_second:(var_to_field_annot stack_annot) + >>?= fun (annot, tname, l_field, r_field) -> + let cons_right = {apply = (fun kinfo k -> ICons_right (kinfo, k))} in + union_t loc (tl, l_field) (tr, r_field) ~annot:tname >>?= fun ty -> + let stack_ty = Item_t (ty, rest, annot) in + typed ctxt loc cons_right stack_ty + | ( Prim (loc, I_IF_LEFT, [bt; bf], annot), + (Item_t (Union_t ((tl, l_field), (tr, r_field), _), rest, union_annot) as + bef) ) -> + check_kind [Seq_kind] bt >>?= fun () -> + check_kind [Seq_kind] bf >>?= fun () -> + error_unexpected_annot loc annot >>?= fun () -> + let left_annot = + gen_access_annot union_annot l_field ~default:default_left_annot + in + let right_annot = + gen_access_annot union_annot r_field ~default:default_right_annot + in + non_terminal_recursion + ?type_logger + tc_context + ctxt + ~legacy + bt + (Item_t (tl, rest, left_annot)) + >>=? fun (btr, ctxt) -> + non_terminal_recursion + ?type_logger + tc_context + ctxt + ~legacy + bf + (Item_t (tr, rest, right_annot)) + >>=? fun (bfr, ctxt) -> + let branch ibt ibf = + let infobt = kinfo_of_descr ibt and infobf = kinfo_of_descr ibf in + let instr = + { + apply = + (fun kinfo k -> + let hinfo = kinfo_of_kinstr k in + let branch_if_left = ibt.instr.apply infobt (IHalt hinfo) + and branch_if_right = ibf.instr.apply infobf (IHalt hinfo) in + IIf_left {kinfo; branch_if_left; branch_if_right; k}); + } + in + {loc; instr; bef; aft = ibt.aft} + in + Lwt.return @@ merge_branches ~legacy ctxt loc btr bfr {branch} + (* lists *) + | (Prim (loc, I_NIL, [t], annot), stack) -> + parse_any_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy t + >>?= fun (Ex_ty t, ctxt) -> + parse_var_type_annot loc annot >>?= fun (annot, ty_name) -> + let nil = {apply = (fun kinfo k -> INil (kinfo, k))} in + list_t loc t ~annot:ty_name >>?= fun ty -> + typed ctxt loc nil (Item_t (ty, stack, annot)) + | ( Prim (loc, I_CONS, [], annot), + Item_t (tv, Item_t (List_t (t, ty_name), rest, _), _) ) -> + check_item_ty ctxt tv t loc I_CONS 1 2 >>?= fun (Eq, t, ctxt) -> + parse_var_annot loc annot >>?= fun annot -> + let cons_list = {apply = (fun kinfo k -> ICons_list (kinfo, k))} in + (typed ctxt loc cons_list (Item_t (List_t (t, ty_name), rest, annot)) + : ((a, s) judgement * context) tzresult Lwt.t) + | ( Prim (loc, I_IF_CONS, [bt; bf], annot), + (Item_t (List_t (t, ty_name), rest, list_annot) as bef) ) -> + check_kind [Seq_kind] bt >>?= fun () -> + check_kind [Seq_kind] bf >>?= fun () -> + error_unexpected_annot loc annot >>?= fun () -> + let hd_annot = gen_access_annot list_annot default_hd_annot in + let tl_annot = gen_access_annot list_annot default_tl_annot in + non_terminal_recursion + ?type_logger + tc_context + ctxt + ~legacy + bt + (Item_t (t, Item_t (List_t (t, ty_name), rest, tl_annot), hd_annot)) + >>=? fun (btr, ctxt) -> + non_terminal_recursion ?type_logger tc_context ctxt ~legacy bf rest + >>=? fun (bfr, ctxt) -> + let branch ibt ibf = + let infobt = kinfo_of_descr ibt and infobf = kinfo_of_descr ibf in + let instr = + { + apply = + (fun kinfo k -> + let hinfo = kinfo_of_kinstr k in + let branch_if_cons = ibt.instr.apply infobt (IHalt hinfo) + and branch_if_nil = ibf.instr.apply infobf (IHalt hinfo) in + IIf_cons {kinfo; branch_if_nil; branch_if_cons; k}); + } + in + {loc; instr; bef; aft = ibt.aft} + in + Lwt.return @@ merge_branches ~legacy ctxt loc btr bfr {branch} + | (Prim (loc, I_SIZE, [], annot), Item_t (List_t _, rest, _)) -> + parse_var_type_annot loc annot >>?= fun (annot, tname) -> + let list_size = {apply = (fun kinfo k -> IList_size (kinfo, k))} in + typed ctxt loc list_size (Item_t (nat_t ~annot:tname, rest, annot)) + | ( Prim (loc, I_MAP, [body], annot), + Item_t (List_t (elt, _), starting_rest, list_annot) ) -> ( + check_kind [Seq_kind] body >>?= fun () -> + parse_var_type_annot loc annot >>?= fun (ret_annot, list_ty_name) -> + let elt_annot = gen_access_annot list_annot default_elt_annot in + non_terminal_recursion + ?type_logger + tc_context + ctxt + ~legacy + body + (Item_t (elt, starting_rest, elt_annot)) + >>=? fun (judgement, ctxt) -> + Lwt.return + @@ + match judgement with + | Typed ({aft = Item_t (ret, rest, _); _} as kibody) -> + let invalid_map_body () = + serialize_stack_for_error ctxt kibody.aft >|? fun (aft, _ctxt) -> + Invalid_map_body (loc, aft) + in + record_trace_eval + invalid_map_body + ( merge_stacks ~legacy loc ctxt 1 rest starting_rest + >>? fun (Eq, rest, ctxt) -> + let binfo = kinfo_of_descr kibody in + let hinfo = + {iloc = loc; kstack_ty = Item_t (ret, rest, ret_annot)} + in + let ibody = kibody.instr.apply binfo (IHalt hinfo) in + let list_map = + {apply = (fun kinfo k -> IList_map (kinfo, ibody, k))} + in + list_t loc ret ~annot:list_ty_name >>? fun ty -> + let stack = Item_t (ty, rest, ret_annot) in + typed_no_lwt ctxt loc list_map stack ) + | Typed {aft; _} -> + serialize_stack_for_error ctxt aft >>? fun (aft, _ctxt) -> + error (Invalid_map_body (loc, aft)) + | Failed _ -> error (Invalid_map_block_fail loc)) + | ( Prim (loc, I_ITER, [body], annot), + Item_t (List_t (elt, _), rest, list_annot) ) -> ( + check_kind [Seq_kind] body >>?= fun () -> + error_unexpected_annot loc annot >>?= fun () -> + let elt_annot = gen_access_annot list_annot default_elt_annot in + non_terminal_recursion + ?type_logger + tc_context + ctxt + ~legacy + body + (Item_t (elt, rest, elt_annot)) + >>=? fun (judgement, ctxt) -> + let mk_list_iter ibody = + { + apply = + (fun kinfo k -> + let hinfo = {iloc = loc; kstack_ty = rest} in + let binfo = kinfo_of_descr ibody in + let ibody = ibody.instr.apply binfo (IHalt hinfo) in + IList_iter (kinfo, ibody, k)); + } + in + Lwt.return + @@ + match judgement with + | Typed ({aft; _} as ibody) -> + let invalid_iter_body () = + serialize_stack_for_error ctxt ibody.aft >>? fun (aft, ctxt) -> + serialize_stack_for_error ctxt rest >|? fun (rest, _ctxt) -> + Invalid_iter_body (loc, rest, aft) + in + record_trace_eval + invalid_iter_body + ( merge_stacks ~legacy loc ctxt 1 aft rest + >>? fun (Eq, rest, ctxt) : ((a, s) judgement * context) tzresult -> + typed_no_lwt ctxt loc (mk_list_iter ibody) rest ) + | Failed {descr} -> typed_no_lwt ctxt loc (mk_list_iter (descr rest)) rest + ) + (* sets *) + | (Prim (loc, I_EMPTY_SET, [t], annot), rest) -> + parse_comparable_ty ~stack_depth:(stack_depth + 1) ctxt t + >>?= fun (Ex_comparable_ty t, ctxt) -> + parse_var_type_annot loc annot >>?= fun (annot, tname) -> + let instr = {apply = (fun kinfo k -> IEmpty_set (kinfo, t, k))} in + set_t loc t ~annot:tname >>?= fun ty -> + typed ctxt loc instr (Item_t (ty, rest, annot)) + | ( Prim (loc, I_ITER, [body], annot), + Item_t (Set_t (comp_elt, _), rest, set_annot) ) -> ( + check_kind [Seq_kind] body >>?= fun () -> + error_unexpected_annot loc annot >>?= fun () -> + let elt_annot = gen_access_annot set_annot default_elt_annot in + let elt = ty_of_comparable_ty comp_elt in + non_terminal_recursion + ?type_logger + tc_context + ctxt + ~legacy + body + (Item_t (elt, rest, elt_annot)) + >>=? fun (judgement, ctxt) -> + let mk_iset_iter ibody = + { + apply = + (fun kinfo k -> + let hinfo = {iloc = loc; kstack_ty = rest} in + let binfo = kinfo_of_descr ibody in + let ibody = ibody.instr.apply binfo (IHalt hinfo) in + ISet_iter (kinfo, ibody, k)); + } + in + Lwt.return + @@ + match judgement with + | Typed ({aft; _} as ibody) -> + let invalid_iter_body () = + serialize_stack_for_error ctxt ibody.aft >>? fun (aft, ctxt) -> + serialize_stack_for_error ctxt rest >|? fun (rest, _ctxt) -> + Invalid_iter_body (loc, rest, aft) + in + record_trace_eval + invalid_iter_body + ( merge_stacks ~legacy loc ctxt 1 aft rest + >>? fun (Eq, rest, ctxt) : ((a, s) judgement * context) tzresult -> + typed_no_lwt ctxt loc (mk_iset_iter ibody) rest ) + | Failed {descr} -> typed_no_lwt ctxt loc (mk_iset_iter (descr rest)) rest + ) + | ( Prim (loc, I_MEM, [], annot), + Item_t (v, Item_t (Set_t (elt, _), rest, _), _) ) -> + let elt = ty_of_comparable_ty elt in + parse_var_type_annot loc annot >>?= fun (annot, tname) -> + check_item_ty ctxt elt v loc I_MEM 1 2 >>?= fun (Eq, _, ctxt) -> + let instr = {apply = (fun kinfo k -> ISet_mem (kinfo, k))} in + (typed ctxt loc instr (Item_t (bool_t ~annot:tname, rest, annot)) + : ((a, s) judgement * context) tzresult Lwt.t) + | ( Prim (loc, I_UPDATE, [], annot), + Item_t + ( v, + Item_t (Bool_t _, Item_t (Set_t (elt, tname), rest, set_annot), _), + _ ) ) -> + check_item_ty ctxt (ty_of_comparable_ty elt) v loc I_UPDATE 1 3 + >>?= fun (Eq, _, ctxt) -> + parse_var_annot loc annot ~default:set_annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ISet_update (kinfo, k))} in + (typed ctxt loc instr (Item_t (Set_t (elt, tname), rest, annot)) + : ((a, s) judgement * context) tzresult Lwt.t) + | (Prim (loc, I_SIZE, [], annot), Item_t (Set_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ISet_size (kinfo, k))} in + typed ctxt loc instr (Item_t (nat_t ~annot:None, rest, annot)) + (* maps *) + | (Prim (loc, I_EMPTY_MAP, [tk; tv], annot), stack) -> + parse_comparable_ty ~stack_depth:(stack_depth + 1) ctxt tk + >>?= fun (Ex_comparable_ty tk, ctxt) -> + parse_any_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy tv + >>?= fun (Ex_ty tv, ctxt) -> + parse_var_type_annot loc annot >>?= fun (annot, ty_name) -> + let instr = {apply = (fun kinfo k -> IEmpty_map (kinfo, tk, k))} in + map_t loc tk tv ~annot:ty_name >>?= fun ty -> + typed ctxt loc instr (Item_t (ty, stack, annot)) + | ( Prim (loc, I_MAP, [body], annot), + Item_t (Map_t (ck, elt, _), starting_rest, _map_annot) ) -> ( + let k = ty_of_comparable_ty ck in + check_kind [Seq_kind] body >>?= fun () -> + parse_var_type_annot loc annot >>?= fun (ret_annot, ty_name) -> + let k_name = field_to_var_annot default_key_annot in + let e_name = field_to_var_annot default_elt_annot in + pair_t loc (k, None, k_name) (elt, None, e_name) ~annot:None + >>?= fun ty -> + non_terminal_recursion + ?type_logger + tc_context + ctxt + ~legacy + body + (Item_t (ty, starting_rest, None)) + >>=? fun (judgement, ctxt) -> + Lwt.return + @@ + match judgement with + | Typed ({aft = Item_t (ret, rest, _); _} as ibody) -> + let invalid_map_body () = + serialize_stack_for_error ctxt ibody.aft >|? fun (aft, _ctxt) -> + Invalid_map_body (loc, aft) + in + record_trace_eval + invalid_map_body + ( merge_stacks ~legacy loc ctxt 1 rest starting_rest + >>? fun (Eq, rest, ctxt) -> + let instr = + { + apply = + (fun kinfo k -> + let binfo = kinfo_of_descr ibody in + let hinfo = + {iloc = loc; kstack_ty = Item_t (ret, rest, ret_annot)} + in + let ibody = ibody.instr.apply binfo (IHalt hinfo) in + IMap_map (kinfo, ibody, k)); + } + in + map_t loc ck ret ~annot:ty_name >>? fun ty -> + let stack = Item_t (ty, rest, ret_annot) in + typed_no_lwt ctxt loc instr stack ) + | Typed {aft; _} -> + serialize_stack_for_error ctxt aft >>? fun (aft, _ctxt) -> + error (Invalid_map_body (loc, aft)) + | Failed _ -> error (Invalid_map_block_fail loc)) + | ( Prim (loc, I_ITER, [body], annot), + Item_t (Map_t (comp_elt, element_ty, _), rest, _map_annot) ) -> ( + check_kind [Seq_kind] body >>?= fun () -> + error_unexpected_annot loc annot >>?= fun () -> + let k_name = field_to_var_annot default_key_annot in + let e_name = field_to_var_annot default_elt_annot in + let key = ty_of_comparable_ty comp_elt in + pair_t loc (key, None, k_name) (element_ty, None, e_name) ~annot:None + >>?= fun ty -> + non_terminal_recursion + ?type_logger + tc_context + ctxt + ~legacy + body + (Item_t (ty, rest, None)) + >>=? fun (judgement, ctxt) -> + let make_instr ibody = + { + apply = + (fun kinfo k -> + let hinfo = {iloc = loc; kstack_ty = rest} in + let binfo = kinfo_of_descr ibody in + let ibody = ibody.instr.apply binfo (IHalt hinfo) in + IMap_iter (kinfo, ibody, k)); + } + in + Lwt.return + @@ + match judgement with + | Typed ({aft; _} as ibody) -> + let invalid_iter_body () = + serialize_stack_for_error ctxt ibody.aft >>? fun (aft, ctxt) -> + serialize_stack_for_error ctxt rest >|? fun (rest, _ctxt) -> + Invalid_iter_body (loc, rest, aft) + in + record_trace_eval + invalid_iter_body + ( merge_stacks ~legacy loc ctxt 1 aft rest + >>? fun (Eq, rest, ctxt) : ((a, s) judgement * context) tzresult -> + typed_no_lwt ctxt loc (make_instr ibody) rest ) + | Failed {descr} -> typed_no_lwt ctxt loc (make_instr (descr rest)) rest) + | ( Prim (loc, I_MEM, [], annot), + Item_t (vk, Item_t (Map_t (ck, _, _), rest, _), _) ) -> + let k = ty_of_comparable_ty ck in + check_item_ty ctxt vk k loc I_MEM 1 2 >>?= fun (Eq, _, ctxt) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMap_mem (kinfo, k))} in + (typed ctxt loc instr (Item_t (bool_t ~annot:None, rest, annot)) + : ((a, s) judgement * context) tzresult Lwt.t) + | ( Prim (loc, I_GET, [], annot), + Item_t (vk, Item_t (Map_t (ck, elt, _), rest, _), _) ) -> + let k = ty_of_comparable_ty ck in + check_item_ty ctxt vk k loc I_GET 1 2 >>?= fun (Eq, _, ctxt) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMap_get (kinfo, k))} in + option_t loc elt ~annot:None + >>?= fun ty : ((a, s) judgement * context) tzresult Lwt.t -> + typed ctxt loc instr (Item_t (ty, rest, annot)) + | ( Prim (loc, I_UPDATE, [], annot), + Item_t + ( vk, + Item_t + ( Option_t (vv, _), + Item_t (Map_t (ck, v, map_name), rest, map_annot), + _ ), + _ ) ) -> + let k = ty_of_comparable_ty ck in + check_item_ty ctxt vk k loc I_UPDATE 1 3 >>?= fun (Eq, _, ctxt) -> + check_item_ty ctxt vv v loc I_UPDATE 2 3 >>?= fun (Eq, v, ctxt) -> + parse_var_annot loc annot ~default:map_annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMap_update (kinfo, k))} in + (typed ctxt loc instr (Item_t (Map_t (ck, v, map_name), rest, annot)) + : ((a, s) judgement * context) tzresult Lwt.t) + | ( Prim (loc, I_GET_AND_UPDATE, [], annot), + Item_t + ( vk, + Item_t + ( Option_t (vv, vname), + Item_t (Map_t (ck, v, map_name), rest, map_annot), + v_annot ), + _ ) ) -> + let k = ty_of_comparable_ty ck in + check_item_ty ctxt vk k loc I_GET_AND_UPDATE 1 3 >>?= fun (Eq, _, ctxt) -> + check_item_ty ctxt vv v loc I_GET_AND_UPDATE 2 3 >>?= fun (Eq, v, ctxt) -> + parse_var_annot loc annot ~default:map_annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMap_get_and_update (kinfo, k))} in + let stack = + Item_t + ( Option_t (vv, vname), + Item_t (Map_t (ck, v, map_name), rest, annot), + v_annot ) + in + (typed ctxt loc instr stack : ((a, s) judgement * context) tzresult Lwt.t) + | (Prim (loc, I_SIZE, [], annot), Item_t (Map_t (_, _, _), rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMap_size (kinfo, k))} in + typed ctxt loc instr (Item_t (nat_t ~annot:None, rest, annot)) + (* big_map *) + | (Prim (loc, I_EMPTY_BIG_MAP, [tk; tv], annot), stack) -> + parse_comparable_ty ~stack_depth:(stack_depth + 1) ctxt tk + >>?= fun (Ex_comparable_ty tk, ctxt) -> + parse_big_map_value_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy tv + >>?= fun (Ex_ty tv, ctxt) -> + parse_var_type_annot loc annot >>?= fun (annot, ty_name) -> + let instr = + {apply = (fun kinfo k -> IEmpty_big_map (kinfo, tk, tv, k))} + in + big_map_t loc tk tv ~annot:ty_name >>?= fun ty -> + let stack = Item_t (ty, stack, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MEM, [], annot), + Item_t (set_key, Item_t (Big_map_t (map_key, _, _), rest, _), _) ) -> + let k = ty_of_comparable_ty map_key in + check_item_ty ctxt set_key k loc I_MEM 1 2 >>?= fun (Eq, _, ctxt) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IBig_map_mem (kinfo, k))} in + let stack = Item_t (bool_t ~annot:None, rest, annot) in + (typed ctxt loc instr stack : ((a, s) judgement * context) tzresult Lwt.t) + | ( Prim (loc, I_GET, [], annot), + Item_t (vk, Item_t (Big_map_t (ck, elt, _), rest, _), _) ) -> + let k = ty_of_comparable_ty ck in + check_item_ty ctxt vk k loc I_GET 1 2 >>?= fun (Eq, _, ctxt) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IBig_map_get (kinfo, k))} in + option_t loc elt ~annot:None >>?= fun ty -> + let stack = Item_t (ty, rest, annot) in + (typed ctxt loc instr stack : ((a, s) judgement * context) tzresult Lwt.t) + | ( Prim (loc, I_UPDATE, [], annot), + Item_t + ( set_key, + Item_t + ( Option_t (set_value, _), + Item_t (Big_map_t (map_key, map_value, map_name), rest, map_annot), + _ ), + _ ) ) -> + let k = ty_of_comparable_ty map_key in + check_item_ty ctxt set_key k loc I_UPDATE 1 3 >>?= fun (Eq, _, ctxt) -> + check_item_ty ctxt set_value map_value loc I_UPDATE 2 3 + >>?= fun (Eq, map_value, ctxt) -> + parse_var_annot loc annot ~default:map_annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IBig_map_update (kinfo, k))} in + let stack = + Item_t (Big_map_t (map_key, map_value, map_name), rest, annot) + in + (typed ctxt loc instr stack : ((a, s) judgement * context) tzresult Lwt.t) + | ( Prim (loc, I_GET_AND_UPDATE, [], annot), + Item_t + ( vk, + Item_t + ( Option_t (vv, vname), + Item_t (Big_map_t (ck, v, map_name), rest, map_annot), + v_annot ), + _ ) ) -> + let k = ty_of_comparable_ty ck in + check_item_ty ctxt vk k loc I_GET_AND_UPDATE 1 3 >>?= fun (Eq, _, ctxt) -> + check_item_ty ctxt vv v loc I_GET_AND_UPDATE 2 3 >>?= fun (Eq, v, ctxt) -> + parse_var_annot loc annot ~default:map_annot >>?= fun annot -> + let instr = + {apply = (fun kinfo k -> IBig_map_get_and_update (kinfo, k))} + in + let stack = + Item_t + ( Option_t (vv, vname), + Item_t (Big_map_t (ck, v, map_name), rest, annot), + v_annot ) + in + (typed ctxt loc instr stack : ((a, s) judgement * context) tzresult Lwt.t) + (* Sapling *) + | (Prim (loc, I_SAPLING_EMPTY_STATE, [memo_size], annot), rest) -> + parse_memo_size memo_size >>?= fun memo_size -> + parse_var_annot loc annot ~default:default_sapling_state_annot + >>?= fun annot -> + let instr = + {apply = (fun kinfo k -> ISapling_empty_state (kinfo, memo_size, k))} + in + let stack = + Item_t (sapling_state_t ~memo_size ~annot:None, rest, annot) + in + typed ctxt loc instr stack + | ( Prim (loc, I_SAPLING_VERIFY_UPDATE, [], _), + Item_t + ( Sapling_transaction_t (transaction_memo_size, _), + Item_t + ( (Sapling_state_t (state_memo_size, _) as state_ty), + rest, + stack_annot ), + _ ) ) -> + merge_memo_sizes state_memo_size transaction_memo_size + >>?= fun _memo_size -> + let instr = + {apply = (fun kinfo k -> ISapling_verify_update (kinfo, k))} + in + pair_t + loc + (int_t ~annot:None, None, default_sapling_balance_annot) + (state_ty, None, None) + ~annot:None + >>?= fun pair_ty -> + option_t loc pair_ty ~annot:None >>?= fun ty -> + let stack = Item_t (ty, rest, stack_annot) in + typed ctxt loc instr stack + (* control *) + | (Seq (loc, []), stack) -> + let instr = {apply = (fun _kinfo k -> k)} in + typed ctxt loc instr stack + | (Seq (_, [single]), stack) -> + non_terminal_recursion ?type_logger tc_context ctxt ~legacy single stack + | (Seq (loc, hd :: tl), stack) -> ( + non_terminal_recursion ?type_logger tc_context ctxt ~legacy hd stack + >>=? fun (judgement, ctxt) -> + match judgement with + | Failed _ -> fail (Fail_not_in_tail_position (Micheline.location hd)) + | Typed ({aft = middle; _} as ihd) -> + non_terminal_recursion + ?type_logger + tc_context + ctxt + ~legacy + (Seq (-1, tl)) + middle + >|=? fun (judgement, ctxt) -> + let judgement = + match judgement with + | Failed {descr} -> + let descr ret = compose_descr loc ihd (descr ret) in + Failed {descr} + | Typed itl -> Typed (compose_descr loc ihd itl) + in + (judgement, ctxt)) + | (Prim (loc, I_IF, [bt; bf], annot), (Item_t (Bool_t _, rest, _) as bef)) -> + check_kind [Seq_kind] bt >>?= fun () -> + check_kind [Seq_kind] bf >>?= fun () -> + error_unexpected_annot loc annot >>?= fun () -> + non_terminal_recursion ?type_logger tc_context ctxt ~legacy bt rest + >>=? fun (btr, ctxt) -> + non_terminal_recursion ?type_logger tc_context ctxt ~legacy bf rest + >>=? fun (bfr, ctxt) -> + let branch ibt ibf = + let infobt = kinfo_of_descr ibt and infobf = kinfo_of_descr ibf in + let instr = + { + apply = + (fun kinfo k -> + let hinfo = kinfo_of_kinstr k in + let branch_if_true = ibt.instr.apply infobt (IHalt hinfo) + and branch_if_false = ibf.instr.apply infobf (IHalt hinfo) in + IIf {kinfo; branch_if_true; branch_if_false; k}); + } + in + {loc; instr; bef; aft = ibt.aft} + in + Lwt.return @@ merge_branches ~legacy ctxt loc btr bfr {branch} + | ( Prim (loc, I_LOOP, [body], annot), + (Item_t (Bool_t _, rest, _stack_annot) as stack) ) -> ( + check_kind [Seq_kind] body >>?= fun () -> + error_unexpected_annot loc annot >>?= fun () -> + non_terminal_recursion ?type_logger tc_context ctxt ~legacy body rest + >>=? fun (judgement, ctxt) -> + Lwt.return + @@ + match judgement with + | Typed ibody -> + let unmatched_branches () = + serialize_stack_for_error ctxt ibody.aft >>? fun (aft, ctxt) -> + serialize_stack_for_error ctxt stack >|? fun (stack, _ctxt) -> + Unmatched_branches (loc, aft, stack) + in + record_trace_eval + unmatched_branches + ( merge_stacks ~legacy loc ctxt 1 ibody.aft stack + >>? fun (Eq, _stack, ctxt) -> + let instr = + { + apply = + (fun kinfo k -> + let ibody = + ibody.instr.apply (kinfo_of_descr ibody) (IHalt kinfo) + in + ILoop (kinfo, ibody, k)); + } + in + typed_no_lwt ctxt loc instr rest ) + | Failed {descr} -> + let instr = + { + apply = + (fun kinfo k -> + let ibody = descr stack in + let ibody = + ibody.instr.apply (kinfo_of_descr ibody) (IHalt kinfo) + in + ILoop (kinfo, ibody, k)); + } + in + typed_no_lwt ctxt loc instr rest) + | ( Prim (loc, I_LOOP_LEFT, [body], annot), + (Item_t (Union_t ((tl, l_field), (tr, _), _), rest, union_annot) as stack) + ) -> ( + check_kind [Seq_kind] body >>?= fun () -> + parse_var_annot loc annot >>?= fun annot -> + let l_annot = + gen_access_annot union_annot l_field ~default:default_left_annot + in + non_terminal_recursion + ?type_logger + tc_context + ctxt + ~legacy + body + (Item_t (tl, rest, l_annot)) + >>=? fun (judgement, ctxt) -> + Lwt.return + @@ + match judgement with + | Typed ibody -> + let unmatched_branches () = + serialize_stack_for_error ctxt ibody.aft >>? fun (aft, ctxt) -> + serialize_stack_for_error ctxt stack >|? fun (stack, _ctxt) -> + Unmatched_branches (loc, aft, stack) + in + record_trace_eval + unmatched_branches + ( merge_stacks ~legacy loc ctxt 1 ibody.aft stack + >>? fun (Eq, _stack, ctxt) -> + let instr = + { + apply = + (fun kinfo k -> + let ibody = + ibody.instr.apply (kinfo_of_descr ibody) (IHalt kinfo) + in + ILoop_left (kinfo, ibody, k)); + } + in + let stack = Item_t (tr, rest, annot) in + typed_no_lwt ctxt loc instr stack ) + | Failed {descr} -> + let instr = + { + apply = + (fun kinfo k -> + let ibody = descr stack in + let ibody = + ibody.instr.apply (kinfo_of_descr ibody) (IHalt kinfo) + in + ILoop_left (kinfo, ibody, k)); + } + in + let stack = Item_t (tr, rest, annot) in + typed_no_lwt ctxt loc instr stack) + | (Prim (loc, I_LAMBDA, [arg; ret; code], annot), stack) -> + parse_any_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy arg + >>?= fun (Ex_ty arg, ctxt) -> + parse_any_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy ret + >>?= fun (Ex_ty ret, ctxt) -> + check_kind [Seq_kind] code >>?= fun () -> + parse_var_annot loc annot >>?= fun annot -> + parse_returning + Lambda + ?type_logger + ~stack_depth:(stack_depth + 1) + ctxt + ~legacy + (arg, default_arg_annot) + ret + code + >>=? fun (lambda, ctxt) -> + let instr = {apply = (fun kinfo k -> ILambda (kinfo, lambda, k))} in + lambda_t loc arg ret ~annot:None >>?= fun ty -> + let stack = Item_t (ty, stack, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_EXEC, [], annot), + Item_t (arg, Item_t (Lambda_t (param, ret, _), rest, _), _) ) -> + check_item_ty ctxt arg param loc I_EXEC 1 2 >>?= fun (Eq, _, ctxt) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IExec (kinfo, k))} in + let stack = Item_t (ret, rest, annot) in + (typed ctxt loc instr stack : ((a, s) judgement * context) tzresult Lwt.t) + | ( Prim (loc, I_APPLY, [], annot), + Item_t + ( capture, + Item_t + ( Lambda_t + ( Pair_t + ((capture_ty, _, _), (arg_ty, _, _), {annot = lam_annot; _}), + ret, + _ ), + rest, + _ ), + _ ) ) -> + check_packable ~legacy:false loc capture_ty >>?= fun () -> + check_item_ty ctxt capture capture_ty loc I_APPLY 1 2 + >>?= fun (Eq, capture_ty, ctxt) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IApply (kinfo, capture_ty, k))} in + lambda_t loc arg_ty ret ~annot:lam_annot + (* This cannot fail because the type [lambda 'arg 'ret] is always smaller than + the input type [lambda (pair 'arg 'capture) 'ret]. In an ideal world, there + would be a smart deconstructor to ensure this statically. *) + >>?= + fun res_ty -> + let stack = Item_t (res_ty, rest, annot) in + (typed ctxt loc instr stack : ((a, s) judgement * context) tzresult Lwt.t) + | (Prim (loc, I_DIP, [code], annot), Item_t (v, rest, stack_annot)) -> ( + error_unexpected_annot loc annot >>?= fun () -> + check_kind [Seq_kind] code >>?= fun () -> + non_terminal_recursion + ?type_logger + (add_dip v stack_annot tc_context) + ctxt + ~legacy + code + rest + >>=? fun (judgement, ctxt) -> + match judgement with + | Typed descr -> + let instr = + { + apply = + (fun kinfo k -> + let binfo = {iloc = descr.loc; kstack_ty = descr.bef} in + let kinfoh = {iloc = descr.loc; kstack_ty = descr.aft} in + let b = descr.instr.apply binfo (IHalt kinfoh) in + IDip (kinfo, b, k)); + } + in + let stack = Item_t (v, descr.aft, stack_annot) in + typed ctxt loc instr stack + | Failed _ -> fail (Fail_not_in_tail_position loc)) + | (Prim (loc, I_DIP, [n; code], result_annot), stack) -> + parse_uint10 n >>?= fun n -> + Gas.consume ctxt (Typecheck_costs.proof_argument n) >>?= fun ctxt -> + let rec make_proof_argument : + type a s. + int -> + tc_context -> + (a, s) stack_ty -> + (a, s) dipn_proof_argument tzresult Lwt.t = + fun n inner_tc_context stk -> + match (Compare.Int.(n = 0), stk) with + | (true, rest) -> ( + non_terminal_recursion + ?type_logger + inner_tc_context + ctxt + ~legacy + code + rest + >>=? fun (judgement, ctxt) -> + Lwt.return + @@ + match judgement with + | Typed descr -> + ok + (Dipn_proof_argument (KRest, ctxt, descr, descr.aft) + : (a, s) dipn_proof_argument) + | Failed _ -> error (Fail_not_in_tail_position loc)) + | (false, Item_t (v, rest, annot)) -> + make_proof_argument (n - 1) (add_dip v annot tc_context) rest + >|=? fun (Dipn_proof_argument (n', ctxt, descr, aft')) -> + let kinfo' = {iloc = loc; kstack_ty = aft'} in + let w = KPrefix (kinfo', n') in + Dipn_proof_argument (w, ctxt, descr, Item_t (v, aft', annot)) + | (_, _) -> + Lwt.return + ( serialize_stack_for_error ctxt stack + >>? fun (whole_stack, _ctxt) -> + error (Bad_stack (loc, I_DIP, 1, whole_stack)) ) + in + error_unexpected_annot loc result_annot >>?= fun () -> + make_proof_argument n tc_context stack + >>=? fun (Dipn_proof_argument (n', ctxt, descr, aft)) -> + let kinfo = {iloc = descr.loc; kstack_ty = descr.bef} in + let kinfoh = {iloc = descr.loc; kstack_ty = descr.aft} in + let b = descr.instr.apply kinfo (IHalt kinfoh) in + let res = {apply = (fun kinfo k -> IDipn (kinfo, n, n', b, k))} in + typed ctxt loc res aft + | (Prim (loc, I_DIP, (([] | _ :: _ :: _ :: _) as l), _), _) -> + (* Technically, the arities 1 and 2 are allowed but the error only mentions 2. + However, DIP {code} is equivalent to DIP 1 {code} so hinting at an arity of 2 makes sense. *) + fail (Invalid_arity (loc, I_DIP, 2, List.length l)) + | (Prim (loc, I_FAILWITH, [], annot), Item_t (v, _rest, _)) -> + Lwt.return + ( error_unexpected_annot loc annot >>? fun () -> + (if legacy then ok_unit else check_packable ~legacy:false loc v) + >>? fun () -> + let instr = {apply = (fun kinfo _k -> IFailwith (kinfo, loc, v))} in + let descr aft = {loc; instr; bef = stack_ty; aft} in + log_stack ctxt loc stack_ty Bot_t >|? fun () -> (Failed {descr}, ctxt) + ) + | (Prim (loc, I_NEVER, [], annot), Item_t (Never_t _, _rest, _)) -> + Lwt.return + ( error_unexpected_annot loc annot >>? fun () -> + let instr = {apply = (fun kinfo _k -> INever kinfo)} in + let descr aft = {loc; instr; bef = stack_ty; aft} in + log_stack ctxt loc stack_ty Bot_t >|? fun () -> (Failed {descr}, ctxt) + ) + (* timestamp operations *) + | ( Prim (loc, I_ADD, [], annot), + Item_t (Timestamp_t tname, Item_t (Int_t _, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = + {apply = (fun kinfo k -> IAdd_timestamp_to_seconds (kinfo, k))} + in + typed ctxt loc instr (Item_t (Timestamp_t tname, rest, annot)) + | ( Prim (loc, I_ADD, [], annot), + Item_t (Int_t _, Item_t (Timestamp_t tname, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = + {apply = (fun kinfo k -> IAdd_seconds_to_timestamp (kinfo, k))} + in + typed ctxt loc instr (Item_t (Timestamp_t tname, rest, annot)) + | ( Prim (loc, I_SUB, [], annot), + Item_t (Timestamp_t tname, Item_t (Int_t _, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = + {apply = (fun kinfo k -> ISub_timestamp_seconds (kinfo, k))} + in + let stack = Item_t (Timestamp_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_SUB, [], annot), + Item_t + ( Timestamp_t {annot = tn1; size = _}, + Item_t (Timestamp_t {annot = tn2; size = _}, rest, _), + _ ) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_annot ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IDiff_timestamps (kinfo, k))} in + let stack = Item_t (int_t ~annot:tname, rest, annot) in + typed ctxt loc instr stack + (* string operations *) + | ( Prim (loc, I_CONCAT, [], annot), + Item_t (String_t tn1, Item_t (String_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IConcat_string_pair (kinfo, k))} in + typed ctxt loc instr (Item_t (String_t tname, rest, annot)) + | ( Prim (loc, I_CONCAT, [], annot), + Item_t (List_t (String_t tname, _), rest, list_annot) ) -> + parse_var_annot ~default:list_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IConcat_string (kinfo, k))} in + typed ctxt loc instr (Item_t (String_t tname, rest, annot)) + | ( Prim (loc, I_SLICE, [], annot), + Item_t + ( Nat_t _, + Item_t (Nat_t _, Item_t (String_t tname, rest, string_annot), _), + _ ) ) -> + parse_var_annot + ~default:(gen_access_annot string_annot default_slice_annot) + loc + annot + >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ISlice_string (kinfo, k))} in + let stack = Item_t (option_string'_t tname, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_SIZE, [], annot), Item_t (String_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IString_size (kinfo, k))} in + let stack = Item_t (nat_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + (* bytes operations *) + | ( Prim (loc, I_CONCAT, [], annot), + Item_t (Bytes_t tn1, Item_t (Bytes_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IConcat_bytes_pair (kinfo, k))} in + let stack = Item_t (Bytes_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_CONCAT, [], annot), + Item_t (List_t (Bytes_t tname, _), rest, list_annot) ) -> + parse_var_annot ~default:list_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IConcat_bytes (kinfo, k))} in + let stack = Item_t (Bytes_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_SLICE, [], annot), + Item_t + ( Nat_t _, + Item_t (Nat_t _, Item_t (Bytes_t tname, rest, bytes_annot), _), + _ ) ) -> + parse_var_annot + ~default:(gen_access_annot bytes_annot default_slice_annot) + loc + annot + >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ISlice_bytes (kinfo, k))} in + let stack = Item_t (option_bytes'_t tname, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_SIZE, [], annot), Item_t (Bytes_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IBytes_size (kinfo, k))} in + let stack = Item_t (nat_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + (* currency operations *) + | ( Prim (loc, I_ADD, [], annot), + Item_t (Mutez_t tn1, Item_t (Mutez_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IAdd_tez (kinfo, k))} in + let stack = Item_t (Mutez_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_SUB, [], annot), + Item_t (Mutez_t tn1, Item_t (Mutez_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> ISub_tez (kinfo, k))} in + let stack = Item_t (Mutez_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MUL, [], annot), + Item_t (Mutez_t tname, Item_t (Nat_t _, rest, _), _) ) -> + (* no type name check *) + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMul_teznat (kinfo, k))} in + let stack = Item_t (Mutez_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MUL, [], annot), + Item_t (Nat_t _, Item_t (Mutez_t tname, rest, _), _) ) -> + (* no type name check *) + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMul_nattez (kinfo, k))} in + let stack = Item_t (Mutez_t tname, rest, annot) in + typed ctxt loc instr stack + (* boolean operations *) + | ( Prim (loc, I_OR, [], annot), + Item_t (Bool_t tn1, Item_t (Bool_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IOr (kinfo, k))} in + let stack = Item_t (Bool_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_AND, [], annot), + Item_t (Bool_t tn1, Item_t (Bool_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IAnd (kinfo, k))} in + let stack = Item_t (Bool_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_XOR, [], annot), + Item_t (Bool_t tn1, Item_t (Bool_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IXor (kinfo, k))} in + let stack = Item_t (Bool_t tname, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_NOT, [], annot), Item_t (Bool_t tname, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> INot (kinfo, k))} in + let stack = Item_t (Bool_t tname, rest, annot) in + typed ctxt loc instr stack + (* integer operations *) + | (Prim (loc, I_ABS, [], annot), Item_t (Int_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IAbs_int (kinfo, k))} in + let stack = Item_t (nat_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_ISNAT, [], annot), Item_t (Int_t _, rest, int_annot)) -> + parse_var_annot loc annot ~default:int_annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IIs_nat (kinfo, k))} in + let stack = Item_t (option_nat_t, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_INT, [], annot), Item_t (Nat_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IInt_nat (kinfo, k))} in + let stack = Item_t (int_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_NEG, [], annot), Item_t (Int_t tname, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> INeg_int (kinfo, k))} in + let stack = Item_t (Int_t tname, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_NEG, [], annot), Item_t (Nat_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> INeg_nat (kinfo, k))} in + let stack = Item_t (int_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_ADD, [], annot), + Item_t (Int_t tn1, Item_t (Int_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IAdd_intint (kinfo, k))} in + let stack = Item_t (Int_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_ADD, [], annot), + Item_t (Int_t tname, Item_t (Nat_t _, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IAdd_intnat (kinfo, k))} in + let stack = Item_t (Int_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_ADD, [], annot), + Item_t (Nat_t _, Item_t (Int_t tname, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IAdd_natint (kinfo, k))} in + let stack = Item_t (Int_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_ADD, [], annot), + Item_t (Nat_t tn1, Item_t (Nat_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IAdd_natnat (kinfo, k))} in + let stack = Item_t (Nat_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_SUB, [], annot), + Item_t (Int_t tn1, Item_t (Int_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> ISub_int (kinfo, k))} in + let stack = Item_t (Int_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_SUB, [], annot), + Item_t (Int_t tname, Item_t (Nat_t _, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ISub_int (kinfo, k))} in + let stack = Item_t (Int_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_SUB, [], annot), + Item_t (Nat_t _, Item_t (Int_t tname, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ISub_int (kinfo, k))} in + let stack = Item_t (Int_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_SUB, [], annot), + Item_t (Nat_t tn1, Item_t (Nat_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun _tname -> + let instr = {apply = (fun kinfo k -> ISub_int (kinfo, k))} in + let stack = Item_t (int_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MUL, [], annot), + Item_t (Int_t tn1, Item_t (Int_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IMul_intint (kinfo, k))} in + let stack = Item_t (Int_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MUL, [], annot), + Item_t (Int_t tname, Item_t (Nat_t _, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMul_intnat (kinfo, k))} in + let stack = Item_t (Int_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MUL, [], annot), + Item_t (Nat_t _, Item_t (Int_t tname, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMul_natint (kinfo, k))} in + let stack = Item_t (Int_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MUL, [], annot), + Item_t (Nat_t tn1, Item_t (Nat_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IMul_natnat (kinfo, k))} in + let stack = Item_t (Nat_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_EDIV, [], annot), + Item_t (Mutez_t tname, Item_t (Nat_t _, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IEdiv_teznat (kinfo, k))} in + let stack = Item_t (option_pair_mutez'_mutez'_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_EDIV, [], annot), + Item_t (Mutez_t tn1, Item_t (Mutez_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IEdiv_tez (kinfo, k))} in + let stack = Item_t (option_pair_nat_mutez'_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_EDIV, [], annot), + Item_t (Int_t tn1, Item_t (Int_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IEdiv_intint (kinfo, k))} in + let stack = Item_t (option_pair_int'_nat_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_EDIV, [], annot), + Item_t (Int_t tname, Item_t (Nat_t _, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IEdiv_intnat (kinfo, k))} in + let stack = Item_t (option_pair_int'_nat_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_EDIV, [], annot), + Item_t (Nat_t tname, Item_t (Int_t _, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IEdiv_natint (kinfo, k))} in + let stack = Item_t (option_pair_int_nat'_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_EDIV, [], annot), + Item_t (Nat_t tn1, Item_t (Nat_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IEdiv_natnat (kinfo, k))} in + let stack = Item_t (option_pair_nat'_nat'_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_LSL, [], annot), + Item_t (Nat_t tn1, Item_t (Nat_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> ILsl_nat (kinfo, k))} in + let stack = Item_t (Nat_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_LSR, [], annot), + Item_t (Nat_t tn1, Item_t (Nat_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> ILsr_nat (kinfo, k))} in + let stack = Item_t (Nat_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_OR, [], annot), + Item_t (Nat_t tn1, Item_t (Nat_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IOr_nat (kinfo, k))} in + let stack = Item_t (Nat_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_AND, [], annot), + Item_t (Nat_t tn1, Item_t (Nat_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IAnd_nat (kinfo, k))} in + let stack = Item_t (Nat_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_AND, [], annot), + Item_t (Int_t _, Item_t (Nat_t tname, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IAnd_int_nat (kinfo, k))} in + let stack = Item_t (Nat_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_XOR, [], annot), + Item_t (Nat_t tn1, Item_t (Nat_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IXor_nat (kinfo, k))} in + let stack = Item_t (Nat_t tname, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_NOT, [], annot), Item_t (Int_t tname, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> INot_int (kinfo, k))} in + let stack = Item_t (Int_t tname, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_NOT, [], annot), Item_t (Nat_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> INot_nat (kinfo, k))} in + let stack = Item_t (int_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + (* comparison *) + | (Prim (loc, I_COMPARE, [], annot), Item_t (t1, Item_t (t2, rest, _), _)) -> + parse_var_annot loc annot >>?= fun annot -> + check_item_ty ctxt t1 t2 loc I_COMPARE 1 2 >>?= fun (Eq, t, ctxt) -> + comparable_ty_of_ty ctxt loc t >>?= fun (key, ctxt) -> + let instr = {apply = (fun kinfo k -> ICompare (kinfo, key, k))} in + let stack = Item_t (int_t ~annot:None, rest, annot) in + (typed ctxt loc instr stack : ((a, s) judgement * context) tzresult Lwt.t) + (* comparators *) + | (Prim (loc, I_EQ, [], annot), Item_t (Int_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IEq (kinfo, k))} in + let stack = Item_t (bool_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_NEQ, [], annot), Item_t (Int_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> INeq (kinfo, k))} in + let stack = Item_t (bool_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_LT, [], annot), Item_t (Int_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ILt (kinfo, k))} in + let stack = Item_t (bool_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_GT, [], annot), Item_t (Int_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IGt (kinfo, k))} in + let stack = Item_t (bool_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_LE, [], annot), Item_t (Int_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ILe (kinfo, k))} in + let stack = Item_t (bool_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_GE, [], annot), Item_t (Int_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IGe (kinfo, k))} in + let stack = Item_t (bool_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + (* annotations *) + | (Prim (loc, I_CAST, [cast_t], annot), Item_t (t, stack, item_annot)) -> + parse_var_annot loc annot ~default:item_annot >>?= fun annot -> + parse_any_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy cast_t + >>?= fun (Ex_ty cast_t, ctxt) -> + ty_eq ~legacy ctxt loc cast_t t >>?= fun (Eq, ctxt) -> + let instr = {apply = (fun _ k -> k)} in + let stack = Item_t (cast_t, stack, annot) in + (typed ctxt loc instr stack : ((a, s) judgement * context) tzresult Lwt.t) + | (Prim (loc, I_RENAME, [], annot), Item_t (t, stack, _)) -> + parse_var_annot loc annot >>?= fun annot -> + (* can erase annot *) + let instr = {apply = (fun _ k -> k)} in + let stack = Item_t (t, stack, annot) in + typed ctxt loc instr stack + (* packing *) + | (Prim (loc, I_PACK, [], annot), Item_t (t, rest, unpacked_annot)) -> + check_packable + ~legacy:true + (* allow to pack contracts for hash/signature checks *) loc + t + >>?= fun () -> + parse_var_annot + loc + annot + ~default:(gen_access_annot unpacked_annot default_pack_annot) + >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IPack (kinfo, t, k))} in + let stack = Item_t (bytes_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_UNPACK, [ty], annot), Item_t (Bytes_t _, rest, packed_annot)) + -> + parse_packable_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy ty + >>?= fun (Ex_ty t, ctxt) -> + parse_var_type_annot loc annot >>?= fun (annot, ty_name) -> + option_t loc t ~annot:ty_name >>?= fun res_ty -> + let annot = + default_annot + annot + ~default:(gen_access_annot packed_annot default_unpack_annot) + in + let instr = {apply = (fun kinfo k -> IUnpack (kinfo, t, k))} in + let stack = Item_t (res_ty, rest, annot) in + typed ctxt loc instr stack + (* protocol *) + | ( Prim (loc, I_ADDRESS, [], annot), + Item_t (Contract_t _, rest, contract_annot) ) -> + parse_var_annot + loc + annot + ~default:(gen_access_annot contract_annot default_addr_annot) + >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IAddress (kinfo, k))} in + let stack = Item_t (address_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_CONTRACT, [ty], annot), Item_t (Address_t _, rest, addr_annot)) + -> + parse_parameter_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy ty + >>?= fun (Ex_ty t, ctxt) -> + contract_t loc t ~annot:None >>?= fun contract_ty -> + option_t loc contract_ty ~annot:None >>?= fun res_ty -> + parse_entrypoint_annot + loc + annot + ~default:(gen_access_annot addr_annot default_contract_annot) + >>?= fun (annot, entrypoint) -> + (match entrypoint with + | None -> Ok "default" + | Some (Field_annot "default") -> error (Unexpected_annotation loc) + | Some (Field_annot entrypoint) -> + if Compare.Int.(String.length entrypoint > 31) then + error (Entrypoint_name_too_long entrypoint) + else Ok entrypoint) + >>?= fun entrypoint -> + let instr = + {apply = (fun kinfo k -> IContract (kinfo, t, entrypoint, k))} + in + let stack = Item_t (res_ty, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_VIEW, [name; output_ty], annot), + Item_t (input_ty, Item_t (Address_t _, rest, addr_annot), _) ) -> + let output_ty_loc = location output_ty in + parse_view_name ctxt name >>?= fun (name, ctxt) -> + parse_view_output_ty ctxt ~stack_depth:0 ~legacy output_ty + >>?= fun (Ex_ty output_ty, ctxt) -> + option_t output_ty_loc output_ty ~annot:None >>?= fun res_ty -> + parse_var_annot + loc + annot + ~default:(gen_access_annot addr_annot default_contract_annot) + >>?= fun annot -> + let instr = + { + apply = + (fun kinfo k -> + IView (kinfo, View_signature {name; input_ty; output_ty}, k)); + } + in + let stack = Item_t (res_ty, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_TRANSFER_TOKENS, [], annot), + Item_t (p, Item_t (Mutez_t _, Item_t (Contract_t (cp, _), rest, _), _), _) + ) -> + check_item_ty ctxt p cp loc I_TRANSFER_TOKENS 1 4 + >>?= fun (Eq, _, ctxt) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ITransfer_tokens (kinfo, k))} in + let stack = Item_t (operation_t ~annot:None, rest, annot) in + (typed ctxt loc instr stack : ((a, s) judgement * context) tzresult Lwt.t) + | ( Prim (loc, I_SET_DELEGATE, [], annot), + Item_t (Option_t (Key_hash_t _, _), rest, _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ISet_delegate (kinfo, k))} in + let stack = Item_t (operation_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (_, I_CREATE_ACCOUNT, _, _), _) -> + fail (Deprecated_instruction I_CREATE_ACCOUNT) + | (Prim (loc, I_IMPLICIT_ACCOUNT, [], annot), Item_t (Key_hash_t _, rest, _)) + -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IImplicit_account (kinfo, k))} in + let stack = Item_t (contract_unit_t, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_CREATE_CONTRACT, [(Seq _ as code)], annot), + Item_t + ( Option_t (Key_hash_t _, _), + Item_t (Mutez_t _, Item_t (ginit, rest, _), _), + _ ) ) -> + parse_two_var_annot loc annot >>?= fun (op_annot, addr_annot) -> + let canonical_code = fst @@ Micheline.extract_locations code in + parse_toplevel ctxt ~legacy canonical_code + >>?= fun ({arg_type; storage_type; code_field; views; root_name}, ctxt) -> + record_trace + (Ill_formed_type (Some "parameter", canonical_code, location arg_type)) + (parse_parameter_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + arg_type) + >>?= fun (Ex_ty arg_type, ctxt) -> + (if legacy then ok_unit else well_formed_entrypoints ~root_name arg_type) + >>?= fun () -> + record_trace + (Ill_formed_type (Some "storage", canonical_code, location storage_type)) + (parse_storage_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + storage_type) + >>?= fun (Ex_ty storage_type, ctxt) -> + let arg_annot = + default_annot + (type_to_var_annot (name_of_ty arg_type)) + ~default:default_param_annot + in + let storage_annot = + default_annot + (type_to_var_annot (name_of_ty storage_type)) + ~default:default_storage_annot + in + pair_t + loc + (arg_type, None, arg_annot) + (storage_type, None, storage_annot) + ~annot:None + >>?= fun arg_type_full -> + pair_t + loc + (list_operation_t, None, None) + (storage_type, None, None) + ~annot:None + >>?= fun ret_type_full -> + trace + (Ill_typed_contract (canonical_code, [])) + (parse_returning + (Toplevel + { + storage_type; + param_type = arg_type; + root_name; + legacy_create_contract_literal = false; + }) + ctxt + ~legacy + ?type_logger + ~stack_depth:(stack_depth + 1) + (arg_type_full, None) + ret_type_full + code_field) + >>=? fun ( (Lam + ( { + kbef = Item_t (arg, Bot_t, _); + kaft = Item_t (ret, Bot_t, _); + _; + }, + _ ) as lambda), + ctxt ) -> + let views_result = + typecheck_views ctxt ?type_logger ~legacy storage_type views + in + trace (Ill_typed_contract (canonical_code, [])) views_result + >>=? fun ctxt -> + ty_eq ~legacy ctxt loc arg arg_type_full >>?= fun (Eq, ctxt) -> + ty_eq ~legacy ctxt loc ret ret_type_full >>?= fun (Eq, ctxt) -> + ty_eq ~legacy ctxt loc storage_type ginit >>?= fun (Eq, ctxt) -> + let instr = + { + apply = + (fun kinfo k -> + ICreate_contract + {kinfo; storage_type; arg_type; lambda; views; root_name; k}); + } + in + let stack = + Item_t + ( operation_t ~annot:None, + Item_t (address_t ~annot:None, rest, addr_annot), + op_annot ) + in + typed ctxt loc instr stack + | (Prim (loc, I_NOW, [], annot), stack) -> + parse_var_annot loc annot ~default:default_now_annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> INow (kinfo, k))} in + let stack = Item_t (timestamp_t ~annot:None, stack, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_AMOUNT, [], annot), stack) -> + parse_var_annot loc annot ~default:default_amount_annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IAmount (kinfo, k))} in + let stack = Item_t (mutez_t ~annot:None, stack, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_CHAIN_ID, [], annot), stack) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IChainId (kinfo, k))} in + let stack = Item_t (chain_id_t ~annot:None, stack, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_BALANCE, [], annot), stack) -> + parse_var_annot loc annot ~default:default_balance_annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IBalance (kinfo, k))} in + let stack = Item_t (mutez_t ~annot:None, stack, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_LEVEL, [], annot), stack) -> + parse_var_annot loc annot ~default:default_level_annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ILevel (kinfo, k))} in + let stack = Item_t (nat_t ~annot:None, stack, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_VOTING_POWER, [], annot), Item_t (Key_hash_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IVoting_power (kinfo, k))} in + let stack = Item_t (nat_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_TOTAL_VOTING_POWER, [], annot), stack) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ITotal_voting_power (kinfo, k))} in + let stack = Item_t (nat_t ~annot:None, stack, annot) in + typed ctxt loc instr stack + | (Prim (_, I_STEPS_TO_QUOTA, _, _), _) -> + fail (Deprecated_instruction I_STEPS_TO_QUOTA) + | (Prim (loc, I_SOURCE, [], annot), stack) -> + parse_var_annot loc annot ~default:default_source_annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ISource (kinfo, k))} in + let stack = Item_t (address_t ~annot:None, stack, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_SENDER, [], annot), stack) -> + parse_var_annot loc annot ~default:default_sender_annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ISender (kinfo, k))} in + let stack = Item_t (address_t ~annot:None, stack, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_SELF, [], annot), stack) -> + Lwt.return + ( parse_entrypoint_annot loc annot ~default:default_self_annot + >>? fun (annot, entrypoint) -> + let entrypoint = + Option.fold + ~some:(fun (Field_annot annot) -> annot) + ~none:"default" + entrypoint + in + let rec get_toplevel_type : + tc_context -> ((a, s) judgement * context) tzresult = function + | Lambda -> error (Self_in_lambda loc) + | Dip (_, prev) -> get_toplevel_type prev + | Toplevel + { + param_type; + root_name; + legacy_create_contract_literal = false; + _; + } -> + find_entrypoint param_type ~root_name entrypoint + >>? fun (_, Ex_ty param_type) -> + contract_t loc param_type ~annot:None >>? fun res_ty -> + let instr = + { + apply = + (fun kinfo k -> ISelf (kinfo, param_type, entrypoint, k)); + } + in + let stack = Item_t (res_ty, stack, annot) in + typed_no_lwt ctxt loc instr stack + | Toplevel + { + param_type; + root_name = _; + legacy_create_contract_literal = true; + _; + } -> + contract_t loc param_type ~annot:None >>? fun res_ty -> + let instr = + { + apply = + (fun kinfo k -> ISelf (kinfo, param_type, "default", k)); + } + in + let stack = Item_t (res_ty, stack, annot) in + typed_no_lwt ctxt loc instr stack + in + get_toplevel_type tc_context ) + | (Prim (loc, I_SELF_ADDRESS, [], annot), stack) -> + parse_var_annot loc annot ~default:default_self_annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ISelf_address (kinfo, k))} in + let stack = Item_t (address_t ~annot:None, stack, annot) in + typed ctxt loc instr stack + (* cryptography *) + | (Prim (loc, I_HASH_KEY, [], annot), Item_t (Key_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IHash_key (kinfo, k))} in + let stack = Item_t (key_hash_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_CHECK_SIGNATURE, [], annot), + Item_t (Key_t _, Item_t (Signature_t _, Item_t (Bytes_t _, rest, _), _), _) + ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ICheck_signature (kinfo, k))} in + let stack = Item_t (bool_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_BLAKE2B, [], annot), Item_t (Bytes_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IBlake2b (kinfo, k))} in + let stack = Item_t (bytes_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_SHA256, [], annot), Item_t (Bytes_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ISha256 (kinfo, k))} in + let stack = Item_t (bytes_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_SHA512, [], annot), Item_t (Bytes_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ISha512 (kinfo, k))} in + let stack = Item_t (bytes_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_KECCAK, [], annot), Item_t (Bytes_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IKeccak (kinfo, k))} in + let stack = Item_t (bytes_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_SHA3, [], annot), Item_t (Bytes_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> ISha3 (kinfo, k))} in + let stack = Item_t (bytes_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_ADD, [], annot), + Item_t (Bls12_381_g1_t tn1, Item_t (Bls12_381_g1_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IAdd_bls12_381_g1 (kinfo, k))} in + let stack = Item_t (Bls12_381_g1_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_ADD, [], annot), + Item_t (Bls12_381_g2_t tn1, Item_t (Bls12_381_g2_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IAdd_bls12_381_g2 (kinfo, k))} in + let stack = Item_t (Bls12_381_g2_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_ADD, [], annot), + Item_t (Bls12_381_fr_t tn1, Item_t (Bls12_381_fr_t tn2, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + merge_type_metadata ~legacy tn1 tn2 >>?= fun tname -> + let instr = {apply = (fun kinfo k -> IAdd_bls12_381_fr (kinfo, k))} in + let stack = Item_t (Bls12_381_fr_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MUL, [], annot), + Item_t (Bls12_381_g1_t tname, Item_t (Bls12_381_fr_t _, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMul_bls12_381_g1 (kinfo, k))} in + let stack = Item_t (Bls12_381_g1_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MUL, [], annot), + Item_t (Bls12_381_g2_t tname, Item_t (Bls12_381_fr_t _, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMul_bls12_381_g2 (kinfo, k))} in + let stack = Item_t (Bls12_381_g2_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MUL, [], annot), + Item_t (Bls12_381_fr_t tname, Item_t (Bls12_381_fr_t _, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMul_bls12_381_fr (kinfo, k))} in + let stack = Item_t (Bls12_381_fr_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MUL, [], annot), + Item_t (Nat_t {annot = tname; _}, Item_t (Bls12_381_fr_t _, rest, _), _) + ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMul_bls12_381_fr_z (kinfo, k))} in + let stack = Item_t (bls12_381_fr_t ~annot:tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MUL, [], annot), + Item_t (Int_t {annot = tname; _}, Item_t (Bls12_381_fr_t _, rest, _), _) + ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMul_bls12_381_fr_z (kinfo, k))} in + let stack = Item_t (bls12_381_fr_t ~annot:tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MUL, [], annot), + Item_t (Bls12_381_fr_t tname, Item_t (Int_t _, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMul_bls12_381_z_fr (kinfo, k))} in + let stack = Item_t (Bls12_381_fr_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_MUL, [], annot), + Item_t (Bls12_381_fr_t tname, Item_t (Nat_t _, rest, _), _) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IMul_bls12_381_z_fr (kinfo, k))} in + let stack = Item_t (Bls12_381_fr_t tname, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_INT, [], annot), Item_t (Bls12_381_fr_t _, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> IInt_bls12_381_fr (kinfo, k))} in + let stack = Item_t (int_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_NEG, [], annot), Item_t (Bls12_381_g1_t tname, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> INeg_bls12_381_g1 (kinfo, k))} in + let stack = Item_t (Bls12_381_g1_t tname, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_NEG, [], annot), Item_t (Bls12_381_g2_t tname, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> INeg_bls12_381_g2 (kinfo, k))} in + let stack = Item_t (Bls12_381_g2_t tname, rest, annot) in + typed ctxt loc instr stack + | (Prim (loc, I_NEG, [], annot), Item_t (Bls12_381_fr_t tname, rest, _)) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = {apply = (fun kinfo k -> INeg_bls12_381_fr (kinfo, k))} in + let stack = Item_t (Bls12_381_fr_t tname, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_PAIRING_CHECK, [], annot), + Item_t + ( List_t + (Pair_t ((Bls12_381_g1_t _, _, _), (Bls12_381_g2_t _, _, _), _), _), + rest, + _ ) ) -> + parse_var_annot loc annot >>?= fun annot -> + let instr = + {apply = (fun kinfo k -> IPairing_check_bls12_381 (kinfo, k))} + in + let stack = Item_t (bool_t ~annot:None, rest, annot) in + typed ctxt loc instr stack + (* Tickets *) + | (Prim (loc, I_TICKET, [], annot), Item_t (t, Item_t (Nat_t _, rest, _), _)) + -> + parse_var_annot loc annot >>?= fun annot -> + comparable_ty_of_ty ctxt loc t >>?= fun (ty, ctxt) -> + ticket_t loc ty ~annot:None >>?= fun res_ty -> + let instr = {apply = (fun kinfo k -> ITicket (kinfo, k))} in + let stack = Item_t (res_ty, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_READ_TICKET, [], annot), + (Item_t (Ticket_t (t, _), _, _) as full_stack) ) -> + parse_var_annot loc annot >>?= fun annot -> + let () = check_dupable_comparable_ty t in + opened_ticket_type loc t >>?= fun opened_ticket_ty -> + let result = ty_of_comparable_ty opened_ticket_ty in + let instr = {apply = (fun kinfo k -> IRead_ticket (kinfo, k))} in + let stack = Item_t (result, full_stack, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_SPLIT_TICKET, [], annot), + Item_t + ( (Ticket_t (t, _) as ticket_t), + Item_t + (Pair_t ((Nat_t _, fa_a, a_a), (Nat_t _, fa_b, a_b), _), rest, _), + _ ) ) -> + parse_var_annot loc annot >>?= fun annot -> + let () = check_dupable_comparable_ty t in + pair_t loc (ticket_t, fa_a, a_a) (ticket_t, fa_b, a_b) ~annot:None + >>?= fun pair_tickets_ty -> + option_t loc pair_tickets_ty ~annot:None >>?= fun res_ty -> + let instr = {apply = (fun kinfo k -> ISplit_ticket (kinfo, k))} in + let stack = Item_t (res_ty, rest, annot) in + typed ctxt loc instr stack + | ( Prim (loc, I_JOIN_TICKETS, [], annot), + Item_t + ( Pair_t (((Ticket_t _ as ty_a), _, _), ((Ticket_t _ as ty_b), _, _), _), + rest, + _ ) ) -> ( + parse_var_annot loc annot >>?= fun annot -> + Gas_monad.run ctxt + @@ merge_types + ~legacy + ~merge_type_error_flag:Default_merge_type_error + loc + ty_a + ty_b + >>?= fun (eq_ty, ctxt) -> + eq_ty >>?= fun (Eq, ty) -> + match ty with + | Ticket_t (contents_ty, _) -> + option_t loc ty ~annot:None >>?= fun res_ty -> + let instr = + {apply = (fun kinfo k -> IJoin_tickets (kinfo, contents_ty, k))} + in + let stack = Item_t (res_ty, rest, annot) in + typed ctxt loc instr stack + | _ -> (* TODO: fix injectivity of types *) assert false) + (* Timelocks *) + | ( Prim (loc, I_OPEN_CHEST, [], _), + Item_t (Chest_key_t _, Item_t (Chest_t _, Item_t (Nat_t _, rest, _), _), _) + ) -> + let instr = {apply = (fun kinfo k -> IOpen_chest (kinfo, k))} in + typed ctxt loc instr (Item_t (union_bytes_bool_t, rest, None)) + (* Primitive parsing errors *) + | ( Prim + ( loc, + (( I_DUP | I_SWAP | I_SOME | I_UNIT | I_PAIR | I_UNPAIR | I_CAR + | I_CDR | I_CONS | I_CONCAT | I_SLICE | I_MEM | I_UPDATE | I_GET + | I_EXEC | I_FAILWITH | I_SIZE | I_ADD | I_SUB | I_MUL | I_EDIV + | I_OR | I_AND | I_XOR | I_NOT | I_ABS | I_NEG | I_LSL | I_LSR + | I_COMPARE | I_EQ | I_NEQ | I_LT | I_GT | I_LE | I_GE + | I_TRANSFER_TOKENS | I_SET_DELEGATE | I_NOW | I_IMPLICIT_ACCOUNT + | I_AMOUNT | I_BALANCE | I_LEVEL | I_CHECK_SIGNATURE | I_HASH_KEY + | I_SOURCE | I_SENDER | I_BLAKE2B | I_SHA256 | I_SHA512 | I_ADDRESS + | I_RENAME | I_PACK | I_ISNAT | I_INT | I_SELF | I_CHAIN_ID | I_NEVER + | I_VOTING_POWER | I_TOTAL_VOTING_POWER | I_KECCAK | I_SHA3 + | I_PAIRING_CHECK | I_TICKET | I_READ_TICKET | I_SPLIT_TICKET + | I_JOIN_TICKETS | I_OPEN_CHEST ) as name), + (_ :: _ as l), + _ ), + _ ) -> + fail (Invalid_arity (loc, name, 0, List.length l)) + | ( Prim + ( loc, + (( I_NONE | I_LEFT | I_RIGHT | I_NIL | I_MAP | I_ITER | I_EMPTY_SET + | I_LOOP | I_LOOP_LEFT | I_CONTRACT | I_CAST | I_UNPACK + | I_CREATE_CONTRACT ) as name), + (([] | _ :: _ :: _) as l), + _ ), + _ ) -> + fail (Invalid_arity (loc, name, 1, List.length l)) + | ( Prim + ( loc, + (( I_PUSH | I_VIEW | I_IF_NONE | I_IF_LEFT | I_IF_CONS | I_EMPTY_MAP + | I_EMPTY_BIG_MAP | I_IF ) as name), + (([] | [_] | _ :: _ :: _ :: _) as l), + _ ), + _ ) -> + fail (Invalid_arity (loc, name, 2, List.length l)) + | ( Prim (loc, I_LAMBDA, (([] | [_] | [_; _] | _ :: _ :: _ :: _ :: _) as l), _), + _ ) -> + fail (Invalid_arity (loc, I_LAMBDA, 3, List.length l)) + (* Stack errors *) + | ( Prim + ( loc, + (( I_ADD | I_SUB | I_MUL | I_EDIV | I_AND | I_OR | I_XOR | I_LSL + | I_LSR | I_CONCAT | I_PAIRING_CHECK ) as name), + [], + _ ), + Item_t (ta, Item_t (tb, _, _), _) ) -> + serialize_ty_for_error ctxt ta >>?= fun (ta, ctxt) -> + serialize_ty_for_error ctxt tb >>?= fun (tb, _ctxt) -> + fail (Undefined_binop (loc, name, ta, tb)) + | ( Prim + ( loc, + (( I_NEG | I_ABS | I_NOT | I_SIZE | I_EQ | I_NEQ | I_LT | I_GT | I_LE + | I_GE + (* CONCAT is both unary and binary; this case can only be triggered + on a singleton stack *) + | I_CONCAT ) as name), + [], + _ ), + Item_t (t, _, _) ) -> + serialize_ty_for_error ctxt t >>?= fun (t, _ctxt) -> + fail (Undefined_unop (loc, name, t)) + | (Prim (loc, ((I_UPDATE | I_SLICE | I_OPEN_CHEST) as name), [], _), stack) -> + Lwt.return + ( serialize_stack_for_error ctxt stack >>? fun (stack, _ctxt) -> + error (Bad_stack (loc, name, 3, stack)) ) + | (Prim (loc, I_CREATE_CONTRACT, _, _), stack) -> + serialize_stack_for_error ctxt stack >>?= fun (stack, _ctxt) -> + fail (Bad_stack (loc, I_CREATE_CONTRACT, 7, stack)) + | (Prim (loc, I_TRANSFER_TOKENS, [], _), stack) -> + Lwt.return + ( serialize_stack_for_error ctxt stack >>? fun (stack, _ctxt) -> + error (Bad_stack (loc, I_TRANSFER_TOKENS, 4, stack)) ) + | ( Prim + ( loc, + (( I_DROP | I_DUP | I_CAR | I_CDR | I_UNPAIR | I_SOME | I_BLAKE2B + | I_SHA256 | I_SHA512 | I_DIP | I_IF_NONE | I_LEFT | I_RIGHT + | I_IF_LEFT | I_IF | I_LOOP | I_IF_CONS | I_IMPLICIT_ACCOUNT | I_NEG + | I_ABS | I_INT | I_NOT | I_HASH_KEY | I_EQ | I_NEQ | I_LT | I_GT + | I_LE | I_GE | I_SIZE | I_FAILWITH | I_RENAME | I_PACK | I_ISNAT + | I_ADDRESS | I_SET_DELEGATE | I_CAST | I_MAP | I_ITER | I_LOOP_LEFT + | I_UNPACK | I_CONTRACT | I_NEVER | I_KECCAK | I_SHA3 | I_READ_TICKET + | I_JOIN_TICKETS ) as name), + _, + _ ), + stack ) -> + Lwt.return + ( serialize_stack_for_error ctxt stack >>? fun (stack, _ctxt) -> + error (Bad_stack (loc, name, 1, stack)) ) + | ( Prim + ( loc, + (( I_SWAP | I_PAIR | I_CONS | I_GET | I_MEM | I_EXEC + | I_CHECK_SIGNATURE | I_ADD | I_SUB | I_MUL | I_EDIV | I_AND | I_OR + | I_XOR | I_LSL | I_LSR | I_COMPARE | I_PAIRING_CHECK | I_TICKET + | I_SPLIT_TICKET ) as name), + _, + _ ), + stack ) -> + Lwt.return + ( serialize_stack_for_error ctxt stack >>? fun (stack, _ctxt) -> + error (Bad_stack (loc, name, 2, stack)) ) + (* Generic parsing errors *) + | (expr, _) -> + fail + @@ unexpected + expr + [Seq_kind] + Instr_namespace + [ + I_DROP; + I_DUP; + I_DIG; + I_DUG; + I_VIEW; + I_SWAP; + I_SOME; + I_UNIT; + I_PAIR; + I_UNPAIR; + I_CAR; + I_CDR; + I_CONS; + I_MEM; + I_UPDATE; + I_MAP; + I_ITER; + I_GET; + I_GET_AND_UPDATE; + I_EXEC; + I_FAILWITH; + I_SIZE; + I_CONCAT; + I_ADD; + I_SUB; + I_MUL; + I_EDIV; + I_OR; + I_AND; + I_XOR; + I_NOT; + I_ABS; + I_INT; + I_NEG; + I_LSL; + I_LSR; + I_COMPARE; + I_EQ; + I_NEQ; + I_LT; + I_GT; + I_LE; + I_GE; + I_TRANSFER_TOKENS; + I_CREATE_CONTRACT; + I_NOW; + I_AMOUNT; + I_BALANCE; + I_LEVEL; + I_IMPLICIT_ACCOUNT; + I_CHECK_SIGNATURE; + I_BLAKE2B; + I_SHA256; + I_SHA512; + I_HASH_KEY; + I_PUSH; + I_NONE; + I_LEFT; + I_RIGHT; + I_NIL; + I_EMPTY_SET; + I_DIP; + I_LOOP; + I_IF_NONE; + I_IF_LEFT; + I_IF_CONS; + I_EMPTY_MAP; + I_EMPTY_BIG_MAP; + I_IF; + I_SOURCE; + I_SENDER; + I_SELF; + I_SELF_ADDRESS; + I_LAMBDA; + I_NEVER; + I_VOTING_POWER; + I_TOTAL_VOTING_POWER; + I_KECCAK; + I_SHA3; + I_PAIRING_CHECK; + I_SAPLING_EMPTY_STATE; + I_SAPLING_VERIFY_UPDATE; + I_TICKET; + I_READ_TICKET; + I_SPLIT_TICKET; + I_JOIN_TICKETS; + I_OPEN_CHEST; + ] + +and[@coq_axiom_with_reason "complex mutually recursive definition"] parse_contract : + type arg. + stack_depth:int -> + legacy:bool -> + context -> + Script.location -> + arg ty -> + Contract.t -> + entrypoint:string -> + (context * arg typed_contract) tzresult Lwt.t = + fun ~stack_depth ~legacy ctxt loc arg contract ~entrypoint -> + match Contract.is_implicit contract with + | Some _ -> ( + match entrypoint with + | "default" -> + (* An implicit account on the "default" entrypoint always exists and has type unit. *) + Lwt.return + ( ty_eq ~legacy:true ctxt loc arg (unit_t ~annot:None) + >|? fun (Eq, ctxt) -> + let contract : arg typed_contract = + (arg, (contract, entrypoint)) + in + (ctxt, contract) ) + | _ -> fail (No_such_entrypoint entrypoint)) + | None -> ( + (* Originated account *) + trace (Invalid_contract (loc, contract)) + @@ Contract.get_script_code ctxt contract + >>=? fun (ctxt, code) -> + match code with + | None -> fail (Invalid_contract (loc, contract)) + | Some code -> + Lwt.return + ( Script.force_decode_in_context ctxt code >>? fun (code, ctxt) -> + (* can only fail because of gas *) + parse_toplevel ctxt ~legacy:true code + >>? fun ({arg_type; root_name; _}, ctxt) -> + parse_parameter_ty + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy:true + arg_type + >>? fun (Ex_ty targ, ctxt) -> + (* we don't check targ size here because it's a legacy contract code *) + Gas_monad.run ctxt + @@ find_entrypoint_for_type + ~legacy + ~merge_type_error_flag:Default_merge_type_error + ~full:targ + ~expected:arg + ~root_name + entrypoint + loc + >>? fun (entrypoint_arg, ctxt) -> + entrypoint_arg >|? fun (entrypoint, arg) -> + let contract : arg typed_contract = + (arg, (contract, entrypoint)) + in + (ctxt, contract) )) + +and parse_view_name ctxt : Script.node -> (Script_string.t * context) tzresult = + function + | String (loc, v) as expr -> + (* The limitation of length of string is same as entrypoint *) + if Compare.Int.(String.length v > 31) then error (View_name_too_long v) + else + let rec check_char i = + if Compare.Int.(i < 0) then ok v + else if Script_ir_annot.is_allowed_char v.[i] then check_char (i - 1) + else error (Bad_view_name loc) + in + Gas.consume ctxt (Typecheck_costs.check_printable v) >>? fun ctxt -> + record_trace + (Invalid_syntactic_constant + ( loc, + strip_locations expr, + "string [a-zA-Z0-9_.%@] and the maximum string length of 31 \ + characters" )) + ( check_char (String.length v - 1) >>? fun v -> + Script_string.of_string v >|? fun s -> (s, ctxt) ) + | expr -> error @@ Invalid_kind (location expr, [String_kind], kind expr) + +and parse_toplevel : + context -> legacy:bool -> Script.expr -> (toplevel * context) tzresult = + fun ctxt ~legacy toplevel -> + record_trace (Ill_typed_contract (toplevel, [])) + @@ + match root toplevel with + | Int (loc, _) -> error (Invalid_kind (loc, [Seq_kind], Int_kind)) + | String (loc, _) -> error (Invalid_kind (loc, [Seq_kind], String_kind)) + | Bytes (loc, _) -> error (Invalid_kind (loc, [Seq_kind], Bytes_kind)) + | Prim (loc, _, _, _) -> error (Invalid_kind (loc, [Seq_kind], Prim_kind)) + | Seq (_, fields) -> ( + let rec find_fields ctxt p s c views fields = + match fields with + | [] -> ok (ctxt, (p, s, c, views)) + | Int (loc, _) :: _ -> error (Invalid_kind (loc, [Prim_kind], Int_kind)) + | String (loc, _) :: _ -> + error (Invalid_kind (loc, [Prim_kind], String_kind)) + | Bytes (loc, _) :: _ -> + error (Invalid_kind (loc, [Prim_kind], Bytes_kind)) + | Seq (loc, _) :: _ -> error (Invalid_kind (loc, [Prim_kind], Seq_kind)) + | Prim (loc, K_parameter, [arg], annot) :: rest -> ( + match p with + | None -> find_fields ctxt (Some (arg, loc, annot)) s c views rest + | Some _ -> error (Duplicate_field (loc, K_parameter))) + | Prim (loc, K_storage, [arg], annot) :: rest -> ( + match s with + | None -> find_fields ctxt p (Some (arg, loc, annot)) c views rest + | Some _ -> error (Duplicate_field (loc, K_storage))) + | Prim (loc, K_code, [arg], annot) :: rest -> ( + match c with + | None -> find_fields ctxt p s (Some (arg, loc, annot)) views rest + | Some _ -> error (Duplicate_field (loc, K_code))) + | Prim (loc, ((K_parameter | K_storage | K_code) as name), args, _) :: _ + -> + error (Invalid_arity (loc, name, 1, List.length args)) + | Prim (loc, K_view, [name; input_ty; output_ty; view_code], _) :: rest + -> + parse_view_name ctxt name >>? fun (str, ctxt) -> + Gas.consume + ctxt + (Michelson_v1_gas.Cost_of.Interpreter.view_update str views) + >>? fun ctxt -> + if SMap.mem str views then error (Duplicated_view_name loc) + else + let views' = + SMap.add str {input_ty; output_ty; view_code} views + in + find_fields ctxt p s c views' rest + | Prim (loc, K_view, args, _) :: _ -> + error (Invalid_arity (loc, K_view, 4, List.length args)) + | Prim (loc, name, _, _) :: _ -> + let allowed = [K_parameter; K_storage; K_code; K_view] in + error (Invalid_primitive (loc, allowed, name)) + in + find_fields ctxt None None None SMap.empty fields + >>? fun (ctxt, toplevel) -> + match toplevel with + | (None, _, _, _) -> error (Missing_field K_parameter) + | (Some _, None, _, _) -> error (Missing_field K_storage) + | (Some _, Some _, None, _) -> error (Missing_field K_code) + | ( Some (p, ploc, pannot), + Some (s, sloc, sannot), + Some (c, cloc, carrot), + views ) -> + let maybe_root_name = + (* root name can be attached to either the parameter + primitive or the toplevel constructor *) + Script_ir_annot.extract_field_annot p >>? fun (p, root_name) -> + match root_name with + | Some _ -> ok (p, pannot, root_name) + | None -> ( + match pannot with + | [single] + when Compare.Int.(String.length single > 0) + && Compare.Char.(single.[0] = '%') -> + parse_field_annot ploc [single] >>? fun pannot -> + ok (p, [], pannot) + | _ -> ok (p, pannot, None)) + in + (if legacy then + (* legacy semantics ignores spurious annotations *) + match maybe_root_name with + | Ok (p, _, root_name) -> ok (p, root_name) + | Error _ -> ok (p, None) + else + (* only one field annot is allowed to set the root entrypoint name *) + maybe_root_name >>? fun (p, pannot, root_name) -> + Script_ir_annot.error_unexpected_annot ploc pannot >>? fun () -> + Script_ir_annot.error_unexpected_annot cloc carrot >>? fun () -> + Script_ir_annot.error_unexpected_annot sloc sannot >|? fun () -> + (p, root_name)) + >|? fun (arg_type, root_name) -> + ({code_field = c; arg_type; root_name; views; storage_type = s}, ctxt) + ) + +(* Same as [parse_contract], but does not fail when the contact is missing or + if the expected type doesn't match the actual one. In that case None is + returned and some overapproximation of the typechecking gas is consumed. + This can still fail on gas exhaustion. *) +let parse_contract_for_script : + type arg. + context -> + Script.location -> + arg ty -> + Contract.t -> + entrypoint:string -> + (context * arg typed_contract option) tzresult Lwt.t = + fun ctxt loc arg contract ~entrypoint -> + match Contract.is_implicit contract with + | Some _ -> ( + match entrypoint with + | "default" -> + (* An implicit account on the "default" entrypoint always exists and has type unit. *) + Lwt.return + ( Gas_monad.run ctxt + @@ merge_types + ~legacy:true + ~merge_type_error_flag:Fast_merge_type_error + loc + arg + (unit_t ~annot:None) + >|? fun (eq_ty, ctxt) -> + match eq_ty with + | Ok (Eq, _ty) -> + let contract : arg typed_contract = + (arg, (contract, entrypoint)) + in + (ctxt, Some contract) + | Error _ -> (ctxt, None) ) + | _ -> + Lwt.return + ( Gas.consume ctxt Typecheck_costs.parse_instr_cycle >|? fun ctxt -> + (* An implicit account on any other entrypoint is not a valid contract. *) + (ctxt, None) )) + | None -> ( + (* Originated account *) + trace (Invalid_contract (loc, contract)) + @@ Contract.get_script_code ctxt contract + >>=? fun (ctxt, code) -> + match code with + | None -> return (ctxt, None) + | Some code -> + Lwt.return + ( Script.force_decode_in_context ctxt code >>? fun (code, ctxt) -> + (* can only fail because of gas *) + match parse_toplevel ctxt ~legacy:true code with + | Error _ -> error (Invalid_contract (loc, contract)) + | Ok ({arg_type; root_name; _}, ctxt) -> ( + match + parse_parameter_ty ctxt ~stack_depth:0 ~legacy:true arg_type + with + | Error _ -> error (Invalid_contract (loc, contract)) + | Ok (Ex_ty targ, ctxt) -> ( + (* we don't check targ size here because it's a legacy contract code *) + Gas_monad.run ctxt + @@ find_entrypoint_for_type + ~legacy:false + ~merge_type_error_flag:Fast_merge_type_error + ~full:targ + ~expected:arg + ~root_name + entrypoint + loc + >|? fun (entrypoint_arg, ctxt) -> + match entrypoint_arg with + | Ok (entrypoint, arg) -> + let contract : arg typed_contract = + (arg, (contract, entrypoint)) + in + (ctxt, Some contract) + | Error _ -> (ctxt, None))) )) + +let parse_code : + ?type_logger:type_logger -> + context -> + legacy:bool -> + code:lazy_expr -> + (ex_code * context) tzresult Lwt.t = + fun ?type_logger ctxt ~legacy ~code -> + Script.force_decode_in_context ctxt code >>?= fun (code, ctxt) -> + Global_constants_storage.expand ctxt code >>=? fun (ctxt, code) -> + parse_toplevel ctxt ~legacy code + >>?= fun ({arg_type; storage_type; code_field; views; root_name}, ctxt) -> + let arg_type_loc = location arg_type in + record_trace + (Ill_formed_type (Some "parameter", code, arg_type_loc)) + (parse_parameter_ty ctxt ~stack_depth:0 ~legacy arg_type) + >>?= fun (Ex_ty arg_type, ctxt) -> + (if legacy then ok_unit else well_formed_entrypoints ~root_name arg_type) + >>?= fun () -> + let storage_type_loc = location storage_type in + record_trace + (Ill_formed_type (Some "storage", code, storage_type_loc)) + (parse_storage_ty ctxt ~stack_depth:0 ~legacy storage_type) + >>?= fun (Ex_ty storage_type, ctxt) -> + let arg_annot = + default_annot + (type_to_var_annot (name_of_ty arg_type)) + ~default:default_param_annot + in + let storage_annot = + default_annot + (type_to_var_annot (name_of_ty storage_type)) + ~default:default_storage_annot + in + + pair_t + storage_type_loc + (arg_type, None, arg_annot) + (storage_type, None, storage_annot) + ~annot:None + >>?= fun arg_type_full -> + pair_t + storage_type_loc + (list_operation_t, None, None) + (storage_type, None, None) + ~annot:None + >>?= fun ret_type_full -> + trace + (Ill_typed_contract (code, [])) + (parse_returning + (Toplevel + { + storage_type; + param_type = arg_type; + root_name; + legacy_create_contract_literal = false; + }) + ctxt + ~legacy + ~stack_depth:0 + ?type_logger + (arg_type_full, None) + ret_type_full + code_field) + >>=? fun (code, ctxt) -> + Lwt.return + (let open Script_typed_ir_size in + let view_size view = + node_size view.view_code ++ node_size view.input_ty + ++ node_size view.output_ty + in + let views_size = SMap.fold (fun _ v s -> view_size v ++ s) views zero in + (* The size of the storage_type and the arg_type is counted by + [lambda_size]. *) + let ir_size = lambda_size code in + let (nodes, code_size) = views_size ++ ir_size in + (* We consume gas after the fact in order to not have to instrument + [node_size] (for efficiency). + This is safe, as we already pay gas proportional to [views_size] + and [ir_size] during their typechecking. *) + Gas.consume ctxt (Script_typed_ir_size_costs.nodes_cost ~nodes) + >>? fun ctxt -> + ok + (Ex_code {code; arg_type; storage_type; views; root_name; code_size}, ctxt)) + +let parse_storage : + ?type_logger:type_logger -> + context -> + legacy:bool -> + allow_forged:bool -> + 'storage ty -> + storage:lazy_expr -> + ('storage * context) tzresult Lwt.t = + fun ?type_logger ctxt ~legacy ~allow_forged storage_type ~storage -> + Script.force_decode_in_context ctxt storage >>?= fun (storage, ctxt) -> + trace_eval + (fun () -> + Lwt.return + ( serialize_ty_for_error ctxt storage_type + >|? fun (storage_type, _ctxt) -> + Ill_typed_data (None, storage, storage_type) )) + (parse_data + ?type_logger + ~stack_depth:0 + ctxt + ~legacy + ~allow_forged + storage_type + (root storage)) + +let[@coq_axiom_with_reason "gadt"] parse_script : + ?type_logger:type_logger -> + context -> + legacy:bool -> + allow_forged_in_storage:bool -> + Script.t -> + (ex_script * context) tzresult Lwt.t = + fun ?type_logger ctxt ~legacy ~allow_forged_in_storage {code; storage} -> + parse_code ~legacy ctxt ?type_logger ~code + >>=? fun ( Ex_code {code; arg_type; storage_type; views; root_name; code_size}, + ctxt ) -> + parse_storage + ?type_logger + ctxt + ~legacy + ~allow_forged:allow_forged_in_storage + storage_type + ~storage + >|=? fun (storage, ctxt) -> + ( Ex_script + {code_size; code; arg_type; storage; storage_type; views; root_name}, + ctxt ) + +let typecheck_code : + legacy:bool -> context -> Script.expr -> (type_map * context) tzresult Lwt.t + = + fun ~legacy ctxt code -> + (* Constants need to be expanded or [parse_toplevel] may fail. *) + Global_constants_storage.expand ctxt code >>=? fun (ctxt, code) -> + parse_toplevel ctxt ~legacy code + >>?= fun ({arg_type; storage_type; code_field; views; root_name}, ctxt) -> + let type_map = ref [] in + let arg_type_loc = location arg_type in + record_trace + (Ill_formed_type (Some "parameter", code, arg_type_loc)) + (parse_parameter_ty ctxt ~stack_depth:0 ~legacy arg_type) + >>?= fun (Ex_ty arg_type, ctxt) -> + (if legacy then ok_unit else well_formed_entrypoints ~root_name arg_type) + >>?= fun () -> + let storage_type_loc = location storage_type in + record_trace + (Ill_formed_type (Some "storage", code, storage_type_loc)) + (parse_storage_ty ctxt ~stack_depth:0 ~legacy storage_type) + >>?= fun (Ex_ty storage_type, ctxt) -> + let arg_annot = + default_annot + (type_to_var_annot (name_of_ty arg_type)) + ~default:default_param_annot + in + let storage_annot = + default_annot + (type_to_var_annot (name_of_ty storage_type)) + ~default:default_storage_annot + in + pair_t + storage_type_loc + (arg_type, None, arg_annot) + (storage_type, None, storage_annot) + ~annot:None + >>?= fun arg_type_full -> + pair_t + storage_type_loc + (list_operation_t, None, None) + (storage_type, None, None) + ~annot:None + >>?= fun ret_type_full -> + let result = + parse_returning + (Toplevel + { + storage_type; + param_type = arg_type; + root_name; + legacy_create_contract_literal = false; + }) + ctxt + ~legacy + ~stack_depth:0 + ~type_logger:(fun loc bef aft -> + type_map := (loc, (bef, aft)) :: !type_map) + (arg_type_full, None) + ret_type_full + code_field + in + trace (Ill_typed_contract (code, !type_map)) result >>=? fun (Lam _, ctxt) -> + let views_result = + typecheck_views + ctxt + ~type_logger:(fun loc bef aft -> + type_map := (loc, (bef, aft)) :: !type_map) + ~legacy + storage_type + views + in + trace (Ill_typed_contract (code, !type_map)) views_result >|=? fun ctxt -> + (!type_map, ctxt) + +module Entrypoints_map = Map.Make (String) + +let list_entrypoints (type full) (full : full ty) ctxt ~root_name = + let merge path annot (type t) (ty : t ty) reachable + ((unreachables, all) as acc) = + match annot with + | None | Some (Field_annot "") -> ( + ok + @@ + if reachable then acc + else + match ty with + | Union_t _ -> acc + | _ -> (List.rev path :: unreachables, all)) + | Some (Field_annot name) -> + if Compare.Int.(String.length name > 31) then + ok (List.rev path :: unreachables, all) + else if Entrypoints_map.mem name all then + ok (List.rev path :: unreachables, all) + else + unparse_ty ctxt ty >>? fun (unparsed_ty, _) -> + ok + ( unreachables, + Entrypoints_map.add name (List.rev path, unparsed_ty) all ) + in + let rec fold_tree : + type t. + t ty -> + prim list -> + bool -> + prim list list * (prim list * Script.node) Entrypoints_map.t -> + (prim list list * (prim list * Script.node) Entrypoints_map.t) tzresult = + fun t path reachable acc -> + match t with + | Union_t ((tl, al), (tr, ar), _) -> + merge (D_Left :: path) al tl reachable acc >>? fun acc -> + merge (D_Right :: path) ar tr reachable acc >>? fun acc -> + fold_tree + tl + (D_Left :: path) + (match al with Some _ -> true | None -> reachable) + acc + >>? fun acc -> + fold_tree + tr + (D_Right :: path) + (match ar with Some _ -> true | None -> reachable) + acc + | _ -> ok acc + in + unparse_ty ctxt full >>? fun (unparsed_full, _) -> + let (init, reachable) = + match root_name with + | None | Some (Field_annot "") -> (Entrypoints_map.empty, false) + | Some (Field_annot name) -> + (Entrypoints_map.singleton name ([], unparsed_full), true) + in + fold_tree full [] reachable ([], init) + [@@coq_axiom_with_reason "unsupported syntax"] + +(* ---- Unparsing (Typed IR -> Untyped expressions) --------------------------*) + +(* -- Unparsing data of any type -- *) + +let comb_witness2 : type t. t ty -> (t, unit -> unit -> unit) comb_witness = + function + | Pair_t (_, (Pair_t _, _, _), _) -> Comb_Pair (Comb_Pair Comb_Any) + | Pair_t _ -> Comb_Pair Comb_Any + | _ -> Comb_Any + +let[@coq_axiom_with_reason "gadt"] rec unparse_data : + type a. + context -> + stack_depth:int -> + unparsing_mode -> + a ty -> + a -> + (Script.node * context) tzresult Lwt.t = + fun ctxt ~stack_depth mode ty a -> + Gas.consume ctxt Unparse_costs.unparse_data_cycle >>?= fun ctxt -> + let non_terminal_recursion ctxt mode ty a = + if Compare.Int.(stack_depth > 10_000) then + fail Unparsing_too_many_recursive_calls + else unparse_data ctxt ~stack_depth:(stack_depth + 1) mode ty a + in + match (ty, a) with + | (Unit_t _, v) -> Lwt.return @@ unparse_unit ctxt v + | (Int_t _, v) -> Lwt.return @@ unparse_int ctxt v + | (Nat_t _, v) -> Lwt.return @@ unparse_nat ctxt v + | (String_t _, s) -> Lwt.return @@ unparse_string ctxt s + | (Bytes_t _, s) -> Lwt.return @@ unparse_bytes ctxt s + | (Bool_t _, b) -> Lwt.return @@ unparse_bool ctxt b + | (Timestamp_t _, t) -> Lwt.return @@ unparse_timestamp ctxt mode t + | (Address_t _, address) -> Lwt.return @@ unparse_address ctxt mode address + | (Contract_t _, contract) -> + Lwt.return @@ unparse_contract ctxt mode contract + | (Signature_t _, s) -> Lwt.return @@ unparse_signature ctxt mode s + | (Mutez_t _, v) -> Lwt.return @@ unparse_mutez ctxt v + | (Key_t _, k) -> Lwt.return @@ unparse_key ctxt mode k + | (Key_hash_t _, k) -> Lwt.return @@ unparse_key_hash ctxt mode k + | (Operation_t _, operation) -> Lwt.return @@ unparse_operation ctxt operation + | (Chain_id_t _, chain_id) -> + Lwt.return @@ unparse_chain_id ctxt mode chain_id + | (Bls12_381_g1_t _, x) -> Lwt.return @@ unparse_bls12_381_g1 ctxt x + | (Bls12_381_g2_t _, x) -> Lwt.return @@ unparse_bls12_381_g2 ctxt x + | (Bls12_381_fr_t _, x) -> Lwt.return @@ unparse_bls12_381_fr ctxt x + | (Pair_t ((tl, _, _), (tr, _, _), _), pair) -> + let r_witness = comb_witness2 tr in + let unparse_l ctxt v = non_terminal_recursion ctxt mode tl v in + let unparse_r ctxt v = non_terminal_recursion ctxt mode tr v in + unparse_pair unparse_l unparse_r ctxt mode r_witness pair + | (Union_t ((tl, _), (tr, _), _), v) -> + let unparse_l ctxt v = non_terminal_recursion ctxt mode tl v in + let unparse_r ctxt v = non_terminal_recursion ctxt mode tr v in + unparse_union unparse_l unparse_r ctxt v + | (Option_t (t, _), v) -> + let unparse_v ctxt v = non_terminal_recursion ctxt mode t v in + unparse_option unparse_v ctxt v + | (List_t (t, _), items) -> + List.fold_left_es + (fun (l, ctxt) element -> + non_terminal_recursion ctxt mode t element + >|=? fun (unparsed, ctxt) -> (unparsed :: l, ctxt)) + ([], ctxt) + items.elements + >|=? fun (items, ctxt) -> (Micheline.Seq (-1, List.rev items), ctxt) + | (Ticket_t (t, _), {ticketer; contents; amount}) -> + (let fake_loc = -1 in + (* ideally we would like to allow a little overhead here because it is only used for unparsing *) + opened_ticket_type fake_loc t) + >>?= fun opened_ticket_ty -> + let t = ty_of_comparable_ty opened_ticket_ty in + (unparse_data [@tailcall]) + ctxt + ~stack_depth + mode + t + (ticketer, (contents, amount)) + | (Set_t (t, _), set) -> + List.fold_left_es + (fun (l, ctxt) item -> + unparse_comparable_data ctxt mode t item >|=? fun (item, ctxt) -> + (item :: l, ctxt)) + ([], ctxt) + (Script_set.fold (fun e acc -> e :: acc) set []) + >|=? fun (items, ctxt) -> (Micheline.Seq (-1, items), ctxt) + | (Map_t (kt, vt, _), map) -> + let items = Script_map.fold (fun k v acc -> (k, v) :: acc) map [] in + unparse_items ctxt ~stack_depth:(stack_depth + 1) mode kt vt items + >|=? fun (items, ctxt) -> (Micheline.Seq (-1, items), ctxt) + | (Big_map_t (_kt, _vt, _), {id = Some id; diff = {size; _}; _}) + when Compare.Int.( = ) size 0 -> + return (Micheline.Int (-1, Big_map.Id.unparse_to_z id), ctxt) + | (Big_map_t (kt, vt, _), {id = Some id; diff = {map; _}; _}) -> + let items = + Big_map_overlay.fold (fun _ (k, v) acc -> (k, v) :: acc) map [] + in + let items = + (* Sort the items in Michelson comparison order and not in key + hash order. This code path is only exercised for tracing, + so we don't bother carbonating this sort operation + precisely. Also, the sort uses a reverse compare because + [unparse_items] will reverse the result. *) + List.sort + (fun (a, _) (b, _) -> Script_comparable.compare_comparable kt b a) + items + in + (* this can't fail if the original type is well-formed + because [option vt] is always strictly smaller than [big_map kt vt] *) + option_t (-1) vt ~annot:None >>?= fun vt -> + unparse_items ctxt ~stack_depth:(stack_depth + 1) mode kt vt items + >|=? fun (items, ctxt) -> + ( Micheline.Prim + ( -1, + D_Pair, + [Int (-1, Big_map.Id.unparse_to_z id); Seq (-1, items)], + [] ), + ctxt ) + | (Big_map_t (kt, vt, _), {id = None; diff = {map; _}; _}) -> + let items = + Big_map_overlay.fold + (fun _ (k, v) acc -> + match v with None -> acc | Some v -> (k, v) :: acc) + map + [] + in + let items = + (* See note above. *) + List.sort + (fun (a, _) (b, _) -> Script_comparable.compare_comparable kt b a) + items + in + unparse_items ctxt ~stack_depth:(stack_depth + 1) mode kt vt items + >|=? fun (items, ctxt) -> (Micheline.Seq (-1, items), ctxt) + | (Lambda_t _, Lam (_, original_code)) -> + unparse_code ctxt ~stack_depth:(stack_depth + 1) mode original_code + | (Never_t _, _) -> . + | (Sapling_transaction_t _, s) -> + Lwt.return + ( Gas.consume ctxt (Unparse_costs.sapling_transaction s) >|? fun ctxt -> + let bytes = + Data_encoding.Binary.to_bytes_exn Sapling.transaction_encoding s + in + (Bytes (-1, bytes), ctxt) ) + | (Sapling_state_t _, {id; diff; _}) -> + Lwt.return + ( Gas.consume ctxt (Unparse_costs.sapling_diff diff) >|? fun ctxt -> + ( (match diff with + | {commitments_and_ciphertexts = []; nullifiers = []} -> ( + match id with + | None -> Micheline.Seq (-1, []) + | Some id -> + let id = Sapling.Id.unparse_to_z id in + Micheline.Int (-1, id)) + | diff -> ( + let diff_bytes = + Data_encoding.Binary.to_bytes_exn Sapling.diff_encoding diff + in + let unparsed_diff = Bytes (-1, diff_bytes) in + match id with + | None -> unparsed_diff + | Some id -> + let id = Sapling.Id.unparse_to_z id in + Micheline.Prim + (-1, D_Pair, [Int (-1, id); unparsed_diff], []))), + ctxt ) ) + | (Chest_key_t _, s) -> + unparse_with_data_encoding + ctxt + s + Unparse_costs.chest_key + Timelock.chest_key_encoding + | (Chest_t _, s) -> + unparse_with_data_encoding + ctxt + s + (Unparse_costs.chest ~plaintext_size:(Timelock.get_plaintext_size s)) + Timelock.chest_encoding + +and unparse_items : + type k v. + context -> + stack_depth:int -> + unparsing_mode -> + k comparable_ty -> + v ty -> + (k * v) list -> + (Script.node list * context) tzresult Lwt.t = + fun ctxt ~stack_depth mode kt vt items -> + List.fold_left_es + (fun (l, ctxt) (k, v) -> + unparse_comparable_data ctxt mode kt k >>=? fun (key, ctxt) -> + unparse_data ctxt ~stack_depth:(stack_depth + 1) mode vt v + >|=? fun (value, ctxt) -> (Prim (-1, D_Elt, [key; value], []) :: l, ctxt)) + ([], ctxt) + items + +and[@coq_axiom_with_reason "gadt"] unparse_code ctxt ~stack_depth mode code = + let legacy = true in + Gas.consume ctxt Unparse_costs.unparse_instr_cycle >>?= fun ctxt -> + let non_terminal_recursion ctxt mode code = + if Compare.Int.(stack_depth > 10_000) then + fail Unparsing_too_many_recursive_calls + else unparse_code ctxt ~stack_depth:(stack_depth + 1) mode code + in + match code with + | Prim (loc, I_PUSH, [ty; data], annot) -> + parse_packable_ty ctxt ~stack_depth:(stack_depth + 1) ~legacy ty + >>?= fun (Ex_ty t, ctxt) -> + let allow_forged = + false + (* Forgeable in PUSH data are already forbidden at parsing, + the only case for which this matters is storing a lambda resulting + from APPLYing a non-forgeable but this cannot happen either as long + as all packable values are also forgeable. *) + in + parse_data + ctxt + ~stack_depth:(stack_depth + 1) + ~legacy + ~allow_forged + t + data + >>=? fun (data, ctxt) -> + unparse_data ctxt ~stack_depth:(stack_depth + 1) mode t data + >>=? fun (data, ctxt) -> + return (Prim (loc, I_PUSH, [ty; data], annot), ctxt) + | Seq (loc, items) -> + List.fold_left_es + (fun (l, ctxt) item -> + non_terminal_recursion ctxt mode item >|=? fun (item, ctxt) -> + (item :: l, ctxt)) + ([], ctxt) + items + >>=? fun (items, ctxt) -> + return (Micheline.Seq (loc, List.rev items), ctxt) + | Prim (loc, prim, items, annot) -> + List.fold_left_es + (fun (l, ctxt) item -> + non_terminal_recursion ctxt mode item >|=? fun (item, ctxt) -> + (item :: l, ctxt)) + ([], ctxt) + items + >>=? fun (items, ctxt) -> + return (Prim (loc, prim, List.rev items, annot), ctxt) + | (Int _ | String _ | Bytes _) as atom -> return (atom, ctxt) + +(* Gas accounting may not be perfect in this function, as it is only called by RPCs. *) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/1688 + Refactor the sharing part of unparse_script and create_contract *) +let unparse_script ctxt mode + {code; arg_type; storage; storage_type; root_name; views; _} = + let (Lam (_, original_code)) = code in + unparse_code ctxt ~stack_depth:0 mode original_code >>=? fun (code, ctxt) -> + unparse_data ctxt ~stack_depth:0 mode storage_type storage + >>=? fun (storage, ctxt) -> + Lwt.return + ( unparse_ty ctxt arg_type >>? fun (arg_type, ctxt) -> + unparse_ty ctxt storage_type >>? fun (storage_type, ctxt) -> + let arg_type = add_field_annot root_name None arg_type in + let open Micheline in + let view name {input_ty; output_ty; view_code} views = + Prim + ( -1, + K_view, + [ + String (-1, Script_string.to_string name); + input_ty; + output_ty; + view_code; + ], + [] ) + :: views + in + let views = SMap.fold view views [] |> List.rev in + let code = + Seq + ( -1, + [ + Prim (-1, K_parameter, [arg_type], []); + Prim (-1, K_storage, [storage_type], []); + Prim (-1, K_code, [code], []); + ] + @ views ) + in + Gas.consume ctxt Unparse_costs.unparse_instr_cycle >>? fun ctxt -> + Gas.consume ctxt Unparse_costs.unparse_instr_cycle >>? fun ctxt -> + Gas.consume ctxt Unparse_costs.unparse_instr_cycle >>? fun ctxt -> + Gas.consume ctxt Unparse_costs.unparse_instr_cycle >>? fun ctxt -> + Gas.consume ctxt (Script.strip_locations_cost code) >>? fun ctxt -> + Gas.consume ctxt (Script.strip_locations_cost storage) >|? fun ctxt -> + ( { + code = lazy_expr (strip_locations code); + storage = lazy_expr (strip_locations storage); + }, + ctxt ) ) + +let pack_data_with_mode ctxt typ data ~mode = + unparse_data ~stack_depth:0 ctxt mode typ data >>=? fun (unparsed, ctxt) -> + Lwt.return @@ pack_node unparsed ctxt + +let hash_data ctxt typ data = + pack_data_with_mode ctxt typ data ~mode:Optimized_legacy + >>=? fun (bytes, ctxt) -> Lwt.return @@ hash_bytes ctxt bytes + +let pack_data ctxt typ data = + pack_data_with_mode ctxt typ data ~mode:Optimized_legacy + +(* ---------------- Big map -------------------------------------------------*) + +let empty_big_map key_type value_type = + { + id = None; + diff = {map = Big_map_overlay.empty; size = 0}; + key_type; + value_type; + } + +let big_map_mem ctxt key {id; diff; key_type; _} = + hash_comparable_data ctxt key_type key >>=? fun (key, ctxt) -> + match (Big_map_overlay.find key diff.map, id) with + | (None, None) -> return (false, ctxt) + | (None, Some id) -> + Alpha_context.Big_map.mem ctxt id key >|=? fun (ctxt, res) -> (res, ctxt) + | (Some (_, None), _) -> return (false, ctxt) + | (Some (_, Some _), _) -> return (true, ctxt) + +let big_map_get_by_hash ctxt key {id; diff; value_type; _} = + match (Big_map_overlay.find key diff.map, id) with + | (Some (_, x), _) -> return (x, ctxt) + | (None, None) -> return (None, ctxt) + | (None, Some id) -> ( + Alpha_context.Big_map.get_opt ctxt id key >>=? function + | (ctxt, None) -> return (None, ctxt) + | (ctxt, Some value) -> + parse_data + ~stack_depth:0 + ctxt + ~legacy:true + ~allow_forged:true + value_type + (Micheline.root value) + >|=? fun (x, ctxt) -> (Some x, ctxt)) + +let big_map_get ctxt key map = + hash_comparable_data ctxt map.key_type key >>=? fun (key_hash, ctxt) -> + big_map_get_by_hash ctxt key_hash map + +let big_map_update_by_hash ctxt key_hash key value map = + let contains = Big_map_overlay.mem key_hash map.diff.map in + return + ( { + map with + diff = + { + map = Big_map_overlay.add key_hash (key, value) map.diff.map; + size = (if contains then map.diff.size else map.diff.size + 1); + }; + }, + ctxt ) + +let big_map_update ctxt key value map = + hash_comparable_data ctxt map.key_type key >>=? fun (key_hash, ctxt) -> + big_map_update_by_hash ctxt key_hash key value map + +let big_map_get_and_update ctxt key value map = + hash_comparable_data ctxt map.key_type key >>=? fun (key_hash, ctxt) -> + big_map_update_by_hash ctxt key_hash key value map >>=? fun (map', ctxt) -> + big_map_get_by_hash ctxt key_hash map >>=? fun (old_value, ctxt) -> + return ((old_value, map'), ctxt) + +(* ---------------- Lazy storage---------------------------------------------*) + +type lazy_storage_ids = Lazy_storage.IdSet.t + +let no_lazy_storage_id = Lazy_storage.IdSet.empty + +let diff_of_big_map ctxt mode ~temporary ~ids_to_copy + {id; key_type; value_type; diff} = + (match id with + | Some id -> + if Lazy_storage.IdSet.mem Big_map id ids_to_copy then + Big_map.fresh ~temporary ctxt >|=? fun (ctxt, duplicate) -> + (ctxt, Lazy_storage.Copy {src = id}, duplicate) + else + (* The first occurrence encountered of a big_map reuses the + ID. This way, the payer is only charged for the diff. + For this to work, this diff has to be put at the end of + the global diff, otherwise the duplicates will use the + updated version as a base. This is true because we add + this diff first in the accumulator of + `extract_lazy_storage_updates`, and this accumulator is not + reversed. *) + return (ctxt, Lazy_storage.Existing, id) + | None -> + Big_map.fresh ~temporary ctxt >>=? fun (ctxt, id) -> + Lwt.return + (let kt = unparse_comparable_ty key_type in + Gas.consume ctxt (Script.strip_locations_cost kt) >>? fun ctxt -> + unparse_ty ctxt value_type >>? fun (kv, ctxt) -> + Gas.consume ctxt (Script.strip_locations_cost kv) >|? fun ctxt -> + let key_type = Micheline.strip_locations kt in + let value_type = Micheline.strip_locations kv in + (ctxt, Lazy_storage.(Alloc Big_map.{key_type; value_type}), id))) + >>=? fun (ctxt, init, id) -> + let pairs = + Big_map_overlay.fold + (fun key_hash (key, value) acc -> (key_hash, key, value) :: acc) + diff.map + [] + in + List.fold_left_es + (fun (acc, ctxt) (key_hash, key, value) -> + Gas.consume ctxt Typecheck_costs.parse_instr_cycle >>?= fun ctxt -> + unparse_comparable_data ctxt mode key_type key + >>=? fun (key_node, ctxt) -> + Gas.consume ctxt (Script.strip_locations_cost key_node) >>?= fun ctxt -> + let key = Micheline.strip_locations key_node in + (match value with + | None -> return (None, ctxt) + | Some x -> + unparse_data ~stack_depth:0 ctxt mode value_type x + >>=? fun (node, ctxt) -> + Lwt.return + ( Gas.consume ctxt (Script.strip_locations_cost node) >|? fun ctxt -> + (Some (Micheline.strip_locations node), ctxt) )) + >|=? fun (value, ctxt) -> + let diff_item = Big_map.{key; key_hash; value} in + (diff_item :: acc, ctxt)) + ([], ctxt) + (List.rev pairs) + >|=? fun (updates, ctxt) -> (Lazy_storage.Update {init; updates}, id, ctxt) + +let diff_of_sapling_state ctxt ~temporary ~ids_to_copy + ({id; diff; memo_size} : Sapling.state) = + (match id with + | Some id -> + if Lazy_storage.IdSet.mem Sapling_state id ids_to_copy then + Sapling.fresh ~temporary ctxt >|=? fun (ctxt, duplicate) -> + (ctxt, Lazy_storage.Copy {src = id}, duplicate) + else return (ctxt, Lazy_storage.Existing, id) + | None -> + Sapling.fresh ~temporary ctxt >|=? fun (ctxt, id) -> + (ctxt, Lazy_storage.Alloc Sapling.{memo_size}, id)) + >|=? fun (ctxt, init, id) -> + (Lazy_storage.Update {init; updates = diff}, id, ctxt) + +(** + Witness flag for whether a type can be populated by a value containing a + lazy storage. + [False_f] must be used only when a value of the type cannot contain a lazy + storage. + + This flag is built in [has_lazy_storage] and used only in + [extract_lazy_storage_updates] and [collect_lazy_storage]. + + This flag is necessary to avoid these two functions to have a quadratic + complexity in the size of the type. + + Add new lazy storage kinds here. + + Please keep the usage of this GADT local. +*) +type 'ty has_lazy_storage = + | True_f : _ has_lazy_storage + | False_f : _ has_lazy_storage + | Pair_f : + 'a has_lazy_storage * 'b has_lazy_storage + -> ('a, 'b) pair has_lazy_storage + | Union_f : + 'a has_lazy_storage * 'b has_lazy_storage + -> ('a, 'b) union has_lazy_storage + | Option_f : 'a has_lazy_storage -> 'a option has_lazy_storage + | List_f : 'a has_lazy_storage -> 'a boxed_list has_lazy_storage + | Map_f : 'v has_lazy_storage -> (_, 'v) map has_lazy_storage + +(** + This function is called only on storage and parameter types of contracts, + once per typechecked contract. It has a complexity linear in the size of + the types, which happen to be literally written types, so the gas for them + has already been paid. +*) +let rec has_lazy_storage : type t. t ty -> t has_lazy_storage = + fun ty -> + let aux1 cons t = + match has_lazy_storage t with False_f -> False_f | h -> cons h + in + let aux2 cons t1 t2 = + match (has_lazy_storage t1, has_lazy_storage t2) with + | (False_f, False_f) -> False_f + | (h1, h2) -> cons h1 h2 + in + match ty with + | Big_map_t (_, _, _) -> True_f + | Sapling_state_t _ -> True_f + | Unit_t _ -> False_f + | Int_t _ -> False_f + | Nat_t _ -> False_f + | Signature_t _ -> False_f + | String_t _ -> False_f + | Bytes_t _ -> False_f + | Mutez_t _ -> False_f + | Key_hash_t _ -> False_f + | Key_t _ -> False_f + | Timestamp_t _ -> False_f + | Address_t _ -> False_f + | Bool_t _ -> False_f + | Lambda_t (_, _, _) -> False_f + | Set_t (_, _) -> False_f + | Contract_t (_, _) -> False_f + | Operation_t _ -> False_f + | Chain_id_t _ -> False_f + | Never_t _ -> False_f + | Bls12_381_g1_t _ -> False_f + | Bls12_381_g2_t _ -> False_f + | Bls12_381_fr_t _ -> False_f + | Sapling_transaction_t _ -> False_f + | Ticket_t _ -> False_f + | Chest_key_t _ -> False_f + | Chest_t _ -> False_f + | Pair_t ((l, _, _), (r, _, _), _) -> aux2 (fun l r -> Pair_f (l, r)) l r + | Union_t ((l, _), (r, _), _) -> aux2 (fun l r -> Union_f (l, r)) l r + | Option_t (t, _) -> aux1 (fun h -> Option_f h) t + | List_t (t, _) -> aux1 (fun h -> List_f h) t + | Map_t (_, t, _) -> aux1 (fun h -> Map_f h) t + +(** + Transforms a value potentially containing lazy storage in an intermediary + state to a value containing lazy storage only represented by identifiers. + + Returns the updated value, the updated set of ids to copy, and the lazy + storage diff to show on the receipt and apply on the storage. + +*) +let[@coq_axiom_with_reason "gadt"] extract_lazy_storage_updates ctxt mode + ~temporary ids_to_copy acc ty x = + let rec aux : + type a. + context -> + unparsing_mode -> + temporary:bool -> + Lazy_storage.IdSet.t -> + Lazy_storage.diffs -> + a ty -> + a -> + has_lazy_storage:a has_lazy_storage -> + (context * a * Lazy_storage.IdSet.t * Lazy_storage.diffs) tzresult Lwt.t = + fun ctxt mode ~temporary ids_to_copy acc ty x ~has_lazy_storage -> + Gas.consume ctxt Typecheck_costs.parse_instr_cycle >>?= fun ctxt -> + match (has_lazy_storage, ty, x) with + | (False_f, _, _) -> return (ctxt, x, ids_to_copy, acc) + | (_, Big_map_t (_, _, _), map) -> + diff_of_big_map ctxt mode ~temporary ~ids_to_copy map + >|=? fun (diff, id, ctxt) -> + let map = + { + map with + diff = {map = Big_map_overlay.empty; size = 0}; + id = Some id; + } + in + let diff = Lazy_storage.make Big_map id diff in + let ids_to_copy = Lazy_storage.IdSet.add Big_map id ids_to_copy in + (ctxt, map, ids_to_copy, diff :: acc) + | (_, Sapling_state_t _, sapling_state) -> + diff_of_sapling_state ctxt ~temporary ~ids_to_copy sapling_state + >|=? fun (diff, id, ctxt) -> + let sapling_state = + Sapling.empty_state ~id ~memo_size:sapling_state.memo_size () + in + let diff = Lazy_storage.make Sapling_state id diff in + let ids_to_copy = Lazy_storage.IdSet.add Sapling_state id ids_to_copy in + (ctxt, sapling_state, ids_to_copy, diff :: acc) + | (Pair_f (hl, hr), Pair_t ((tyl, _, _), (tyr, _, _), _), (xl, xr)) -> + aux ctxt mode ~temporary ids_to_copy acc tyl xl ~has_lazy_storage:hl + >>=? fun (ctxt, xl, ids_to_copy, acc) -> + aux ctxt mode ~temporary ids_to_copy acc tyr xr ~has_lazy_storage:hr + >|=? fun (ctxt, xr, ids_to_copy, acc) -> + (ctxt, (xl, xr), ids_to_copy, acc) + | (Union_f (has_lazy_storage, _), Union_t ((ty, _), (_, _), _), L x) -> + aux ctxt mode ~temporary ids_to_copy acc ty x ~has_lazy_storage + >|=? fun (ctxt, x, ids_to_copy, acc) -> (ctxt, L x, ids_to_copy, acc) + | (Union_f (_, has_lazy_storage), Union_t ((_, _), (ty, _), _), R x) -> + aux ctxt mode ~temporary ids_to_copy acc ty x ~has_lazy_storage + >|=? fun (ctxt, x, ids_to_copy, acc) -> (ctxt, R x, ids_to_copy, acc) + | (Option_f has_lazy_storage, Option_t (ty, _), Some x) -> + aux ctxt mode ~temporary ids_to_copy acc ty x ~has_lazy_storage + >|=? fun (ctxt, x, ids_to_copy, acc) -> (ctxt, Some x, ids_to_copy, acc) + | (List_f has_lazy_storage, List_t (ty, _), l) -> + List.fold_left_es + (fun (ctxt, l, ids_to_copy, acc) x -> + aux ctxt mode ~temporary ids_to_copy acc ty x ~has_lazy_storage + >|=? fun (ctxt, x, ids_to_copy, acc) -> + (ctxt, Script_list.cons x l, ids_to_copy, acc)) + (ctxt, Script_list.empty, ids_to_copy, acc) + l.elements + >|=? fun (ctxt, l, ids_to_copy, acc) -> + let reversed = {length = l.length; elements = List.rev l.elements} in + (ctxt, reversed, ids_to_copy, acc) + | (Map_f has_lazy_storage, Map_t (_, ty, _), (module M)) -> + let bindings m = M.OPS.fold (fun k v bs -> (k, v) :: bs) m [] in + List.fold_left_es + (fun (ctxt, m, ids_to_copy, acc) (k, x) -> + aux ctxt mode ~temporary ids_to_copy acc ty x ~has_lazy_storage + >|=? fun (ctxt, x, ids_to_copy, acc) -> + (ctxt, M.OPS.add k x m, ids_to_copy, acc)) + (ctxt, M.OPS.empty, ids_to_copy, acc) + (bindings (fst M.boxed)) + >|=? fun (ctxt, m, ids_to_copy, acc) -> + let module M = struct + module OPS = M.OPS + + type key = M.key + + type value = M.value + + let key_ty = M.key_ty + + let boxed = (m, snd M.boxed) + end in + ( ctxt, + (module M : Boxed_map with type key = M.key and type value = M.value), + ids_to_copy, + acc ) + | (_, Option_t (_, _), None) -> return (ctxt, None, ids_to_copy, acc) + | _ -> assert false + (* TODO: fix injectivity of types *) + in + let has_lazy_storage = has_lazy_storage ty in + aux ctxt mode ~temporary ids_to_copy acc ty x ~has_lazy_storage + +(** We namespace an error type for [fold_lazy_storage]. The error case is only + available when the ['error] parameter is equal to unit. *) +module Fold_lazy_storage = struct + type ('acc, 'error) result = + | Ok : 'acc -> ('acc, 'error) result + | Error : ('acc, unit) result +end + +(** Prematurely abort if [f] generates an error. Use this function without the + [unit] type for [error] if you are in a case where errors are impossible. +*) +let[@coq_axiom_with_reason "gadt"] rec fold_lazy_storage : + type a error. + f:('acc, error) Fold_lazy_storage.result Lazy_storage.IdSet.fold_f -> + init:'acc -> + context -> + a ty -> + a -> + has_lazy_storage:a has_lazy_storage -> + (('acc, error) Fold_lazy_storage.result * context) tzresult = + fun ~f ~init ctxt ty x ~has_lazy_storage -> + Gas.consume ctxt Typecheck_costs.parse_instr_cycle >>? fun ctxt -> + match (has_lazy_storage, ty, x) with + | (_, Big_map_t (_, _, _), {id = Some id; _}) -> + Gas.consume ctxt Typecheck_costs.parse_instr_cycle >>? fun ctxt -> + ok (f.f Big_map id (Fold_lazy_storage.Ok init), ctxt) + | (_, Sapling_state_t _, {id = Some id; _}) -> + Gas.consume ctxt Typecheck_costs.parse_instr_cycle >>? fun ctxt -> + ok (f.f Sapling_state id (Fold_lazy_storage.Ok init), ctxt) + | (False_f, _, _) -> ok (Fold_lazy_storage.Ok init, ctxt) + | (_, Big_map_t (_, _, _), {id = None; _}) -> + ok (Fold_lazy_storage.Ok init, ctxt) + | (_, Sapling_state_t _, {id = None; _}) -> + ok (Fold_lazy_storage.Ok init, ctxt) + | (Pair_f (hl, hr), Pair_t ((tyl, _, _), (tyr, _, _), _), (xl, xr)) -> ( + fold_lazy_storage ~f ~init ctxt tyl xl ~has_lazy_storage:hl + >>? fun (init, ctxt) -> + match init with + | Fold_lazy_storage.Ok init -> + fold_lazy_storage ~f ~init ctxt tyr xr ~has_lazy_storage:hr + | Fold_lazy_storage.Error -> ok (init, ctxt)) + | (Union_f (has_lazy_storage, _), Union_t ((ty, _), (_, _), _), L x) -> + fold_lazy_storage ~f ~init ctxt ty x ~has_lazy_storage + | (Union_f (_, has_lazy_storage), Union_t ((_, _), (ty, _), _), R x) -> + fold_lazy_storage ~f ~init ctxt ty x ~has_lazy_storage + | (_, Option_t (_, _), None) -> ok (Fold_lazy_storage.Ok init, ctxt) + | (Option_f has_lazy_storage, Option_t (ty, _), Some x) -> + fold_lazy_storage ~f ~init ctxt ty x ~has_lazy_storage + | (List_f has_lazy_storage, List_t (ty, _), l) -> + List.fold_left + (fun (acc : (('acc, error) Fold_lazy_storage.result * context) tzresult) + x -> + acc >>? fun (init, ctxt) -> + match init with + | Fold_lazy_storage.Ok init -> + fold_lazy_storage ~f ~init ctxt ty x ~has_lazy_storage + | Fold_lazy_storage.Error -> ok (init, ctxt)) + (ok (Fold_lazy_storage.Ok init, ctxt)) + l.elements + | (Map_f has_lazy_storage, Map_t (_, ty, _), m) -> + Script_map.fold + (fun _ + v + (acc : (('acc, error) Fold_lazy_storage.result * context) tzresult) -> + acc >>? fun (init, ctxt) -> + match init with + | Fold_lazy_storage.Ok init -> + fold_lazy_storage ~f ~init ctxt ty v ~has_lazy_storage + | Fold_lazy_storage.Error -> ok (init, ctxt)) + m + (ok (Fold_lazy_storage.Ok init, ctxt)) + | _ -> (* TODO: fix injectivity of types *) assert false + +let[@coq_axiom_with_reason "gadt"] collect_lazy_storage ctxt ty x = + let has_lazy_storage = has_lazy_storage ty in + let f kind id (acc : (_, never) Fold_lazy_storage.result) = + let acc = match acc with Fold_lazy_storage.Ok acc -> acc in + Fold_lazy_storage.Ok (Lazy_storage.IdSet.add kind id acc) + in + fold_lazy_storage ~f:{f} ~init:no_lazy_storage_id ctxt ty x ~has_lazy_storage + >>? fun (ids, ctxt) -> + match ids with Fold_lazy_storage.Ok ids -> ok (ids, ctxt) + +let[@coq_axiom_with_reason "gadt"] extract_lazy_storage_diff ctxt mode + ~temporary ~to_duplicate ~to_update ty v = + (* + Basically [to_duplicate] are ids from the argument and [to_update] are ids + from the storage before execution (i.e. it is safe to reuse them since they + will be owned by the same contract). + *) + let to_duplicate = Lazy_storage.IdSet.diff to_duplicate to_update in + extract_lazy_storage_updates ctxt mode ~temporary to_duplicate [] ty v + >|=? fun (ctxt, v, alive, diffs) -> + let diffs = + if temporary then diffs + else + let dead = Lazy_storage.IdSet.diff to_update alive in + Lazy_storage.IdSet.fold_all + {f = (fun kind id acc -> Lazy_storage.make kind id Remove :: acc)} + dead + diffs + in + match diffs with + | [] -> (v, None, ctxt) + | diffs -> (v, Some diffs (* do not reverse *), ctxt) + +let list_of_big_map_ids ids = + Lazy_storage.IdSet.fold Big_map (fun id acc -> id :: acc) ids [] + +let parse_data = parse_data ~stack_depth:0 + +let parse_instr : + type a s. + ?type_logger:type_logger -> + tc_context -> + context -> + legacy:bool -> + Script.node -> + (a, s) stack_ty -> + ((a, s) judgement * context) tzresult Lwt.t = + fun ?type_logger tc_context ctxt ~legacy script_instr stack_ty -> + parse_instr + ~stack_depth:0 + ?type_logger + tc_context + ctxt + ~legacy + script_instr + stack_ty + +let unparse_data = unparse_data ~stack_depth:0 + +let unparse_code ctxt mode code = + (* Constants need to be expanded or [unparse_code] may fail. *) + Global_constants_storage.expand ctxt (strip_locations code) + >>=? fun (ctxt, code) -> unparse_code ~stack_depth:0 ctxt mode (root code) + +let parse_contract ~legacy context loc arg_ty contract ~entrypoint = + parse_contract ~stack_depth:0 ~legacy context loc arg_ty contract ~entrypoint + +let parse_comparable_ty = parse_comparable_ty ~stack_depth:0 + +let parse_big_map_value_ty = parse_big_map_value_ty ~stack_depth:0 + +let parse_packable_ty = parse_packable_ty ~stack_depth:0 + +let parse_parameter_ty = parse_parameter_ty ~stack_depth:0 + +let parse_any_ty = parse_any_ty ~stack_depth:0 + +let parse_ty = parse_ty ~stack_depth:0 + +let ty_eq ctxt = ty_eq ~legacy:true ctxt + +let[@coq_axiom_with_reason "gadt"] get_single_sapling_state ctxt ty x = + let has_lazy_storage = has_lazy_storage ty in + let f (type i a u) (kind : (i, a, u) Lazy_storage.Kind.t) (id : i) + single_id_opt : (Sapling.Id.t option, unit) Fold_lazy_storage.result = + match kind with + | Lazy_storage.Kind.Sapling_state -> ( + match single_id_opt with + | Fold_lazy_storage.Ok None -> Fold_lazy_storage.Ok (Some id) + | Fold_lazy_storage.Ok (Some _) -> + Fold_lazy_storage.Error (* more than one *) + | Fold_lazy_storage.Error -> single_id_opt) + | _ -> single_id_opt + in + fold_lazy_storage ~f:{f} ~init:None ctxt ty x ~has_lazy_storage + >>? fun (id, ctxt) -> + match id with + | Fold_lazy_storage.Ok (Some id) -> ok (Some id, ctxt) + | Fold_lazy_storage.Ok None | Fold_lazy_storage.Error -> ok (None, ctxt) + +(* + + {!Script_cache} needs a measure of the script size in memory. + Determining this size is not easy in OCaml because of sharing. + + Indeed, many values present in the script share the same memory + area. This is especially true for types and stack types: they are + heavily shared in every typed IR internal representation. As a + consequence, computing the size of the typed IR without taking + sharing into account leads to a size which is sometimes two order + of magnitude bigger than the actual size. + + We could track down this sharing. Unfortunately, sharing is not + part of OCaml semantics: for this reason, a compiler can optimize + memory representation by adding more sharing. If two nodes use + different optimization flags or compilers, such a precise + computation of the memory footprint of scripts would lead to two + distinct sizes. As these sizes occur in the blockchain context, + this situation would lead to a fork. + + For this reason, we introduce a *size model* for the script size. + This model provides an overapproximation of the actual size in + memory. The risk is to be too far from the actual size: the cache + would then be wrongly marked as full. This situation would make the + cache less useful but should present no security risk . + +*) +let script_size + (Ex_script + { + code_size; + code = _; + arg_type = _; + storage; + storage_type; + root_name = _; + views = _; + }) = + let (nodes, storage_size) = + Script_typed_ir_size.value_size storage_type storage + in + let cost = Script_typed_ir_size_costs.nodes_cost ~nodes in + (Saturation_repr.(add code_size storage_size |> to_int), cost) diff --git a/src/proto_011_PtHangzH/lib_protocol/script_ir_translator.mli b/src/proto_011_PtHangzH/lib_protocol/script_ir_translator.mli new file mode 100644 index 000000000000..6e930c8b36bc --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_ir_translator.mli @@ -0,0 +1,479 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Script_tc_errors + +type ('ta, 'tb) eq = Eq : ('same, 'same) eq + +type ex_comparable_ty = + | Ex_comparable_ty : 'a Script_typed_ir.comparable_ty -> ex_comparable_ty + +type ex_ty = Ex_ty : 'a Script_typed_ir.ty -> ex_ty + +type ex_stack_ty = + | Ex_stack_ty : ('a, 's) Script_typed_ir.stack_ty -> ex_stack_ty + +type ex_script = Ex_script : ('a, 'b) Script_typed_ir.script -> ex_script + +type toplevel = { + code_field : Script.node; + arg_type : Script.node; + storage_type : Script.node; + views : Script_typed_ir.view Script_typed_ir.SMap.t; + root_name : Script_typed_ir.field_annot option; +} + +type ('arg, 'storage) code = { + code : + ( ('arg, 'storage) Script_typed_ir.pair, + ( Script_typed_ir.operation Script_typed_ir.boxed_list, + 'storage ) + Script_typed_ir.pair ) + Script_typed_ir.lambda; + arg_type : 'arg Script_typed_ir.ty; + storage_type : 'storage Script_typed_ir.ty; + views : Script_typed_ir.view Script_typed_ir.SMap.t; + root_name : Script_typed_ir.field_annot option; + code_size : Cache_memory_helpers.sint; + (** This is an over-approximation of the value size in memory, in + bytes, of the contract's static part, that is its source + code. This includes the code of the contract as well as the code + of the views. The storage size is not taken into account by this + field as it has a dynamic size. *) +} + +type ex_code = Ex_code : ('a, 'c) code -> ex_code + +type 'storage ex_view = + | Ex_view : + ('input * 'storage, 'output) Script_typed_ir.lambda + -> 'storage ex_view + +type ('a, 's, 'b, 'u) cinstr = { + apply : + 'r 'f. + ('a, 's) Script_typed_ir.kinfo -> + ('b, 'u, 'r, 'f) Script_typed_ir.kinstr -> + ('a, 's, 'r, 'f) Script_typed_ir.kinstr; +} + +type ('a, 's, 'b, 'u) descr = { + loc : Script.location; + bef : ('a, 's) Script_typed_ir.stack_ty; + aft : ('b, 'u) Script_typed_ir.stack_ty; + instr : ('a, 's, 'b, 'u) cinstr; +} + +type tc_context = + | Lambda : tc_context + | Dip : ('a, 's) Script_typed_ir.stack_ty * tc_context -> tc_context + | Toplevel : { + storage_type : 'sto Script_typed_ir.ty; + param_type : 'param Script_typed_ir.ty; + root_name : Script_typed_ir.field_annot option; + legacy_create_contract_literal : bool; + } + -> tc_context + +type ('a, 's) judgement = + | Typed : ('a, 's, 'b, 'u) descr -> ('a, 's) judgement + | Failed : { + descr : 'b 'u. ('b, 'u) Script_typed_ir.stack_ty -> ('a, 's, 'b, 'u) descr; + } + -> ('a, 's) judgement + +val close_descr : + ('a, 'b, 'c, 'd) descr -> ('a, 'b, 'c, 'd) Script_typed_ir.kdescr + +type unparsing_mode = Optimized | Readable | Optimized_legacy + +type merge_type_error_flag = Default_merge_type_error | Fast_merge_type_error + +module Gas_monad : sig + (** This monad combines: + - a state monad where the state is the context + - two levels of error monad to distinguish gas exhaustion from other errors + + It is useful for backtracking on type checking errors without backtracking + the consumed gas. + *) + type 'a t + + (** Alias of ['a t] to avoid confusion when the module is open *) + type 'a gas_monad = 'a t + + (** monadic return operator of the gas monad *) + val return : 'a -> 'a t + + (** Binding operator for the gas monad *) + val ( >>$ ) : 'a t -> ('a -> 'b t) -> 'b t + + (** Mapping operator for the gas monad, [m >|$ f] is equivalent to + [m >>$ fun x -> return (f x)] *) + val ( >|$ ) : 'a t -> ('a -> 'b) -> 'b t + + (** Variant of [( >>$ )] to bind uncarbonated functions *) + val ( >?$ ) : 'a t -> ('a -> 'b tzresult) -> 'b t + + (** Another variant of [( >>$ )] that lets recover from inner errors *) + val ( >??$ ) : 'a t -> ('a tzresult -> 'b t) -> 'b t + + (** gas-free embedding of tzresult values. [from_tzresult x] is equivalent to [return () >?$ fun () -> x] *) + val from_tzresult : 'a tzresult -> 'a t + + (** Open the abstraction barrier to construct an 'a t from a function. + This must only be used on functions that can only fail because of gas + such as unparse_ty *) + val unsafe_embed : (context -> ('a * context) tzresult) -> 'a t + + (** Gas consumption *) + val gas_consume : Gas.cost -> unit t + + (** Escaping the gas monad *) + val run : context -> 'a t -> ('a tzresult * context) tzresult + + (** re-export of [Error_monad.record_trace_eval] *) + val record_trace_eval : (unit -> error tzresult) -> 'a t -> 'a t + + (** read the state of the state monad *) + val get_context : context t +end + +type type_logger = + int -> + (Script.expr * Script.annot) list -> + (Script.expr * Script.annot) list -> + unit + +(** Create an empty big_map *) +val empty_big_map : + 'a Script_typed_ir.comparable_ty -> + 'b Script_typed_ir.ty -> + ('a, 'b) Script_typed_ir.big_map + +val big_map_mem : + context -> + 'key -> + ('key, 'value) Script_typed_ir.big_map -> + (bool * context) tzresult Lwt.t + +val big_map_get : + context -> + 'key -> + ('key, 'value) Script_typed_ir.big_map -> + ('value option * context) tzresult Lwt.t + +(** Update a big map. See {!big_map_get_and_update} for details. *) +val big_map_update : + context -> + 'key -> + 'value option -> + ('key, 'value) Script_typed_ir.big_map -> + (('key, 'value) Script_typed_ir.big_map * context) tzresult Lwt.t + +(** Update a big map, returning the old value of the given key and the new map. + + This does {i not} modify the underlying storage, only the diff table. + *) +val big_map_get_and_update : + context -> + 'key -> + 'value option -> + ('key, 'value) Script_typed_ir.big_map -> + (('value option * ('key, 'value) Script_typed_ir.big_map) * context) tzresult + Lwt.t + +val ty_eq : + context -> + Script.location -> + 'ta Script_typed_ir.ty -> + 'tb Script_typed_ir.ty -> + (('ta Script_typed_ir.ty, 'tb Script_typed_ir.ty) eq * context) tzresult + +val merge_types : + legacy:bool -> + merge_type_error_flag:merge_type_error_flag -> + Script.location -> + 'a Script_typed_ir.ty -> + 'b Script_typed_ir.ty -> + (('a Script_typed_ir.ty, 'b Script_typed_ir.ty) eq * 'a Script_typed_ir.ty) + Gas_monad.t + +val parse_comparable_data : + ?type_logger:type_logger -> + context -> + 'a Script_typed_ir.comparable_ty -> + Script.node -> + ('a * context) tzresult Lwt.t + +val parse_data : + ?type_logger:type_logger -> + context -> + legacy:bool -> + allow_forged:bool -> + 'a Script_typed_ir.ty -> + Script.node -> + ('a * context) tzresult Lwt.t + +val unparse_data : + context -> + unparsing_mode -> + 'a Script_typed_ir.ty -> + 'a -> + (Script.node * context) tzresult Lwt.t + +val unparse_code : + context -> + unparsing_mode -> + Script.node -> + (Script.node * context) tzresult Lwt.t + +val parse_instr : + ?type_logger:type_logger -> + tc_context -> + context -> + legacy:bool -> + Script.node -> + ('a, 's) Script_typed_ir.stack_ty -> + (('a, 's) judgement * context) tzresult Lwt.t + +(** + [parse_ty] specialized for the right-hand side part of a big map type, i.e. + the `value` in `big_map key value`. +*) +val parse_big_map_value_ty : + context -> legacy:bool -> Script.node -> (ex_ty * context) tzresult + +val parse_packable_ty : + context -> legacy:bool -> Script.node -> (ex_ty * context) tzresult + +val parse_parameter_ty : + context -> legacy:bool -> Script.node -> (ex_ty * context) tzresult + +val parse_comparable_ty : + context -> Script.node -> (ex_comparable_ty * context) tzresult + +val parse_view_input_ty : + context -> + stack_depth:int -> + legacy:bool -> + Script.node -> + (ex_ty * context) tzresult + +val parse_view_output_ty : + context -> + stack_depth:int -> + legacy:bool -> + Script.node -> + (ex_ty * context) tzresult + +val parse_view_returning : + ?type_logger:type_logger -> + context -> + legacy:bool -> + 'storage Script_typed_ir.ty -> + Script_typed_ir.view -> + ('storage ex_view * context) tzresult Lwt.t + +val typecheck_views : + ?type_logger:type_logger -> + context -> + legacy:bool -> + 'storage Script_typed_ir.ty -> + Script_typed_ir.view Script_typed_ir.SMap.t -> + context tzresult Lwt.t + +(** + [parse_ty] allowing big_map values, operations, contract and tickets. +*) +val parse_any_ty : + context -> legacy:bool -> Script.node -> (ex_ty * context) tzresult + +(** We expose [parse_ty] for convenience to external tools. Please use + specialized versions such as [parse_packable_ty], [parse_parameter_ty], + [parse_comparable_ty], or [parse_big_map_value_ty] if possible. *) +val parse_ty : + context -> + legacy:bool -> + allow_lazy_storage:bool -> + allow_operation:bool -> + allow_contract:bool -> + allow_ticket:bool -> + Script.node -> + (ex_ty * context) tzresult + +val unparse_ty : + context -> 'a Script_typed_ir.ty -> (Script.node * context) tzresult + +val ty_of_comparable_ty : + 'a Script_typed_ir.comparable_ty -> 'a Script_typed_ir.ty + +val parse_toplevel : + context -> legacy:bool -> Script.expr -> (toplevel * context) tzresult + +val add_field_annot : + Script_typed_ir.field_annot option -> + Script_typed_ir.var_annot option -> + Script.node -> + Script.node + +val typecheck_code : + legacy:bool -> context -> Script.expr -> (type_map * context) tzresult Lwt.t + +val serialize_ty_for_error : + context -> 'a Script_typed_ir.ty -> (Script.expr * context) tzresult + +val parse_code : + ?type_logger:type_logger -> + context -> + legacy:bool -> + code:Script.lazy_expr -> + (ex_code * context) tzresult Lwt.t + +val parse_storage : + ?type_logger:type_logger -> + context -> + legacy:bool -> + allow_forged:bool -> + 'storage Script_typed_ir.ty -> + storage:Script.lazy_expr -> + ('storage * context) tzresult Lwt.t + +(** Combines [parse_code] and [parse_storage] *) +val parse_script : + ?type_logger:type_logger -> + context -> + legacy:bool -> + allow_forged_in_storage:bool -> + Script.t -> + (ex_script * context) tzresult Lwt.t + +(* Gas accounting may not be perfect in this function, as it is only called by RPCs. *) +val unparse_script : + context -> + unparsing_mode -> + ('a, 'b) Script_typed_ir.script -> + (Script.t * context) tzresult Lwt.t + +val parse_contract : + legacy:bool -> + context -> + Script.location -> + 'a Script_typed_ir.ty -> + Contract.t -> + entrypoint:string -> + (context * 'a Script_typed_ir.typed_contract) tzresult Lwt.t + +val parse_contract_for_script : + context -> + Script.location -> + 'a Script_typed_ir.ty -> + Contract.t -> + entrypoint:string -> + (context * 'a Script_typed_ir.typed_contract option) tzresult Lwt.t + +val find_entrypoint : + 't Script_typed_ir.ty -> + root_name:Script_typed_ir.field_annot option -> + string -> + ((Script.node -> Script.node) * ex_ty) tzresult + +module Entrypoints_map : Map.S with type key = string + +val list_entrypoints : + 't Script_typed_ir.ty -> + context -> + root_name:Script_typed_ir.field_annot option -> + (Michelson_v1_primitives.prim list list + * (Michelson_v1_primitives.prim list * Script.node) Entrypoints_map.t) + tzresult + +val pack_data : + context -> 'a Script_typed_ir.ty -> 'a -> (bytes * context) tzresult Lwt.t + +val hash_comparable_data : + context -> + 'a Script_typed_ir.comparable_ty -> + 'a -> + (Script_expr_hash.t * context) tzresult Lwt.t + +val hash_data : + context -> + 'a Script_typed_ir.ty -> + 'a -> + (Script_expr_hash.t * context) tzresult Lwt.t + +type lazy_storage_ids + +val no_lazy_storage_id : lazy_storage_ids + +(** Traverse the given type, producing a {!lazy_storage_ids} for + use with {!extract_lazy_storage_diff}. + *) +val collect_lazy_storage : + context -> + 'a Script_typed_ir.ty -> + 'a -> + (lazy_storage_ids * context) tzresult + +val list_of_big_map_ids : lazy_storage_ids -> Big_map.Id.t list + +(** Produce a lazy storage diff, containing in-memory writes to + lazy data structures such as big_maps yet to be committed. + + The resulting diff can be committed to the underlying storage + (context) using [Lazy_storage_diff.apply]. + + @param to_duplicate + Lazy data structure reference produced via {!collect_lazy_storage} + that can not be reused. Typically collected via traversing + the parameters to a smart contract. + @param to_update + Lazy data structure reference produced via {!collect_lazy_storage} + that can be reused. Typically collected via traversing the previous + storage of a smart contract. + *) +val extract_lazy_storage_diff : + context -> + unparsing_mode -> + temporary:bool -> + to_duplicate:lazy_storage_ids -> + to_update:lazy_storage_ids -> + 'a Script_typed_ir.ty -> + 'a -> + ('a * Lazy_storage.diffs option * context) tzresult Lwt.t + +(* return [None] if none or more than one found *) +val get_single_sapling_state : + context -> + 'a Script_typed_ir.ty -> + 'a -> + (Sapling.Id.t option * context) tzresult + +(** [script_size script] returns an overapproximation of the size of + the in-memory representation of [script] as well as the cost + associated to computing that overapproximation. *) +val script_size : ex_script -> int * Gas_limit_repr.cost diff --git a/src/proto_011_PtHangzH/lib_protocol/script_list.ml b/src/proto_011_PtHangzH/lib_protocol/script_list.ml new file mode 100644 index 000000000000..7e9cbdeb2214 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_list.ml @@ -0,0 +1,32 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Script_typed_ir + +let empty : 'a boxed_list = {elements = []; length = 0} + +let cons : 'a -> 'a boxed_list -> 'a boxed_list = + fun elt l -> {length = 1 + l.length; elements = elt :: l.elements} diff --git a/src/proto_011_PtHangzH/lib_protocol/script_list.mli b/src/proto_011_PtHangzH/lib_protocol/script_list.mli new file mode 100644 index 000000000000..01a4670df6b4 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_list.mli @@ -0,0 +1,31 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Empty list. *) +val empty : 'a Script_typed_ir.boxed_list + +(** Prepend an element. *) +val cons : 'a -> 'a Script_typed_ir.boxed_list -> 'a Script_typed_ir.boxed_list diff --git a/src/proto_011_PtHangzH/lib_protocol/script_map.ml b/src/proto_011_PtHangzH/lib_protocol/script_map.ml new file mode 100644 index 000000000000..6ea174609f7f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_map.ml @@ -0,0 +1,90 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Script_typed_ir + +let key_ty : type a b. (a, b) map -> a comparable_ty = + fun (module Box) -> Box.key_ty + +let empty : type a b. a comparable_ty -> (a, b) map = + fun ty -> + let module OPS = Map.Make (struct + type t = a + + let compare = Script_comparable.compare_comparable ty + end) in + (module struct + type key = a + + type value = b + + let key_ty = ty + + module OPS = struct + type value = b + + include OPS + end + + let boxed = (OPS.empty, 0) + end) + +let get : type key value. key -> (key, value) map -> value option = + fun k (module Box) -> Box.OPS.find k (fst Box.boxed) + +let update : type a b. a -> b option -> (a, b) map -> (a, b) map = + fun k v (module Box) -> + (module struct + type key = a + + type value = b + + let key_ty = Box.key_ty + + module OPS = Box.OPS + + let boxed = + let (map, size) = Box.boxed in + let contains = + match Box.OPS.find k map with None -> false | _ -> true + in + match v with + | Some v -> (Box.OPS.add k v map, size + if contains then 0 else 1) + | None -> (Box.OPS.remove k map, size - if contains then 1 else 0) + end) + +let mem : type key value. key -> (key, value) map -> bool = + fun k (module Box) -> + match Box.OPS.find k (fst Box.boxed) with None -> false | _ -> true + +let fold : + type key value acc. + (key -> value -> acc -> acc) -> (key, value) map -> acc -> acc = + fun f (module Box) -> Box.OPS.fold f (fst Box.boxed) + +let size : type key value. (key, value) map -> Script_int.n Script_int.num = + fun (module Box) -> Script_int.(abs (of_int (snd Box.boxed))) diff --git a/src/proto_011_PtHangzH/lib_protocol/script_map.mli b/src/proto_011_PtHangzH/lib_protocol/script_map.mli new file mode 100644 index 000000000000..7bd3cd51e4b4 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_map.mli @@ -0,0 +1,49 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +val empty : 'a Script_typed_ir.comparable_ty -> ('a, 'b) Script_typed_ir.map + +val fold : + ('key -> 'value -> 'acc -> 'acc) -> + ('key, 'value) Script_typed_ir.map -> + 'acc -> + 'acc + +val update : + 'a -> + 'b option -> + ('a, 'b) Script_typed_ir.map -> + ('a, 'b) Script_typed_ir.map + +val mem : 'key -> ('key, 'value) Script_typed_ir.map -> bool + +val get : 'key -> ('key, 'value) Script_typed_ir.map -> 'value option + +val key_ty : ('a, 'b) Script_typed_ir.map -> 'a Script_typed_ir.comparable_ty + +val size : ('a, 'b) Script_typed_ir.map -> Script_int.n Script_int.num diff --git a/src/proto_011_PtHangzH/lib_protocol/script_repr.ml b/src/proto_011_PtHangzH/lib_protocol/script_repr.ml new file mode 100644 index 000000000000..cf361c027f63 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_repr.ml @@ -0,0 +1,304 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type location = Micheline.canonical_location + +let location_encoding = Micheline.canonical_location_encoding + +type annot = Micheline.annot + +type expr = Michelson_v1_primitives.prim Micheline.canonical + +type lazy_expr = expr Data_encoding.lazy_t + +type node = (location, Michelson_v1_primitives.prim) Micheline.node + +let expr_encoding = + Micheline.canonical_encoding_v1 + ~variant:"michelson_v1" + Michelson_v1_primitives.prim_encoding + +type error += Lazy_script_decode (* `Permanent *) + +let () = + register_error_kind + `Permanent + ~id:"invalid_binary_format" + ~title:"Invalid binary format" + ~description: + "Could not deserialize some piece of data from its binary representation" + Data_encoding.empty + (function Lazy_script_decode -> Some () | _ -> None) + (fun () -> Lazy_script_decode) + +let lazy_expr_encoding = Data_encoding.lazy_encoding expr_encoding + +let lazy_expr expr = Data_encoding.make_lazy expr_encoding expr + +type t = {code : lazy_expr; storage : lazy_expr} + +let encoding = + let open Data_encoding in + def "scripted.contracts" + @@ conv + (fun {code; storage} -> (code, storage)) + (fun (code, storage) -> {code; storage}) + (obj2 (req "code" lazy_expr_encoding) (req "storage" lazy_expr_encoding)) + +module S = Saturation_repr + +module Micheline_size = struct + type t = { + nodes : S.may_saturate S.t; + string_bytes : S.may_saturate S.t; + z_bytes : S.may_saturate S.t; + } + + let make ~nodes ~string_bytes ~z_bytes = {nodes; string_bytes; z_bytes} + + let zero = {nodes = S.zero; string_bytes = S.zero; z_bytes = S.zero} + + let add_int acc n = + let numbits = Z.numbits n in + let z_bytes = + S.safe_int ((numbits + 7) / 8) + (* Compute the number of bytes in a Z.t *) + in + { + nodes = S.succ acc.nodes; + string_bytes = acc.string_bytes; + z_bytes = S.add acc.z_bytes z_bytes; + } + + let add_string acc n = + let string_bytes = S.safe_int (String.length n) in + { + nodes = S.succ acc.nodes; + string_bytes = S.add acc.string_bytes string_bytes; + z_bytes = acc.z_bytes; + } + + let add_bytes acc n = + let string_bytes = S.safe_int (Bytes.length n) in + { + nodes = S.succ acc.nodes; + string_bytes = S.add acc.string_bytes string_bytes; + z_bytes = acc.z_bytes; + } + + let add_node s = {s with nodes = S.succ s.nodes} + + (* We model annotations as Seqs of Strings *) + let of_annots acc annots = + List.fold_left (fun acc s -> add_string acc s) acc annots + + let[@coq_struct "nodes"] rec of_nodes acc nodes more_nodes = + let open Micheline in + match nodes with + | [] -> ( + match more_nodes with + | [] -> acc + | nodes :: more_nodes -> + (of_nodes [@ocaml.tailcall]) acc nodes more_nodes) + | Int (_, n) :: nodes -> + let acc = add_int acc n in + (of_nodes [@ocaml.tailcall]) acc nodes more_nodes + | String (_, s) :: nodes -> + let acc = add_string acc s in + (of_nodes [@ocaml.tailcall]) acc nodes more_nodes + | Bytes (_, s) :: nodes -> + let acc = add_bytes acc s in + (of_nodes [@ocaml.tailcall]) acc nodes more_nodes + | Prim (_, _, args, annots) :: nodes -> + let acc = add_node acc in + let acc = of_annots acc annots in + (of_nodes [@ocaml.tailcall]) acc args (nodes :: more_nodes) + | Seq (_, args) :: nodes -> + let acc = add_node acc in + (of_nodes [@ocaml.tailcall]) acc args (nodes :: more_nodes) + + let of_node node = of_nodes zero [node] [] + + let dot_product s1 s2 = + S.add + (S.mul s1.nodes s2.nodes) + (S.add + (S.mul s1.string_bytes s2.string_bytes) + (S.mul s1.z_bytes s2.z_bytes)) +end + +(* Costs pertaining to deserialization of Micheline values (bytes to Micheline). + The costs are given in atomic steps (see [Gas_limit_repr]). *) +module Micheline_decoding = struct + (* Cost vector allowing to compute decoding costs as a function of the + size of the Micheline term *) + let micheline_size_dependent_cost = + let traversal_cost = S.safe_int 60 in + let string_per_byte_cost = S.safe_int 10 in + let z_per_byte_cost = S.safe_int 10 in + Micheline_size.make + ~nodes:traversal_cost + ~string_bytes:string_per_byte_cost + ~z_bytes:z_per_byte_cost + + let bytes_dependent_cost = S.safe_int 20 +end + +(* Costs pertaining to serialization of Micheline values (Micheline to bytes) + The costs are given in atomic steps (see [Gas_limit_repr]). *) +module Micheline_encoding = struct + (* Cost vector allowing to compute encoding cost as a function of the + size of the Micheline term *) + let micheline_size_dependent_cost = + let traversal_cost = S.safe_int 100 in + let string_per_byte_cost = S.safe_int 10 in + let z_per_byte_cost = S.safe_int 25 in + Micheline_size.make + ~nodes:traversal_cost + ~string_bytes:string_per_byte_cost + ~z_bytes:z_per_byte_cost + + let bytes_dependent_cost = S.safe_int 33 +end + +let expr_size expr = Micheline_size.of_node (Micheline.root expr) + +(* Compute the cost of serializing a term of given [size]. *) +let serialization_cost size = + Gas_limit_repr.atomic_step_cost + @@ Micheline_size.dot_product + size + Micheline_encoding.micheline_size_dependent_cost + +(* Compute the cost of deserializing a term of given [size]. *) +let deserialization_cost size = + Gas_limit_repr.atomic_step_cost + @@ Micheline_size.dot_product + size + Micheline_decoding.micheline_size_dependent_cost + +(* Estimate the cost of deserializing a term encoded in [bytes_len] bytes. *) +let deserialization_cost_estimated_from_bytes bytes_len = + Gas_limit_repr.atomic_step_cost + @@ S.mul Micheline_decoding.bytes_dependent_cost (S.safe_int bytes_len) + +(* Estimate the cost of serializing a term from its encoded form, + having [bytes_len] bytes. *) +let serialization_cost_estimated_from_bytes bytes_len = + Gas_limit_repr.atomic_step_cost + @@ S.mul Micheline_encoding.bytes_dependent_cost (S.safe_int bytes_len) + +(* Cost of running [strip_locations] on a term with [size] nodes. + Note that [strip_locations] will reallocate a fresh Micheline tree. + This only depends on the total number of nodes (not the size of + the leaves). *) +let cost_micheline_strip_locations size = + Gas_limit_repr.atomic_step_cost @@ S.mul (S.safe_int size) (S.safe_int 51) + +(* This is currently used to estimate the cost of serializing an operation. *) +let bytes_node_cost s = serialization_cost_estimated_from_bytes (Bytes.length s) + +let deserialized_cost expr = + Gas_limit_repr.atomic_step_cost @@ deserialization_cost (expr_size expr) + +let serialized_cost bytes = + Gas_limit_repr.atomic_step_cost + @@ serialization_cost_estimated_from_bytes (Bytes.length bytes) + +let force_decode_cost lexpr = + Data_encoding.apply_lazy + ~fun_value:(fun _ -> Gas_limit_repr.free) + ~fun_bytes:(fun b -> + deserialization_cost_estimated_from_bytes (Bytes.length b)) + ~fun_combine:(fun _ _ -> Gas_limit_repr.free) + lexpr + +let force_decode lexpr = + match Data_encoding.force_decode lexpr with + | Some v -> ok v + | None -> error Lazy_script_decode + +let force_bytes_cost expr = + (* Estimating the cost directly from the bytes would be cheaper, but + using [serialized_cost] is more accurate. *) + Data_encoding.apply_lazy + ~fun_value:(fun v -> serialization_cost (expr_size v)) + ~fun_bytes:(fun _ -> Gas_limit_repr.free) + ~fun_combine:(fun _ _ -> Gas_limit_repr.free) + expr + +let force_bytes expr = + Error_monad.catch_f + (fun () -> Data_encoding.force_bytes expr) + (fun _ -> Lazy_script_decode) + +let unit = + Micheline.strip_locations (Prim (0, Michelson_v1_primitives.D_Unit, [], [])) + +let unit_parameter = lazy_expr unit + +let is_unit_parameter = + let unit_bytes = Data_encoding.force_bytes unit_parameter in + Data_encoding.apply_lazy + ~fun_value:(fun v -> + match Micheline.root v with + | Prim (_, Michelson_v1_primitives.D_Unit, [], []) -> true + | _ -> false) + ~fun_bytes:(fun b -> Compare.Bytes.equal b unit_bytes) + ~fun_combine:(fun res _ -> res) + +let[@coq_struct "node"] rec strip_annotations node = + let open Micheline in + match node with + | (Int (_, _) | String (_, _) | Bytes (_, _)) as leaf -> leaf + | Prim (loc, name, args, _) -> + Prim (loc, name, List.map strip_annotations args, []) + | Seq (loc, args) -> Seq (loc, List.map strip_annotations args) + +let rec micheline_fold_aux node f acc k = + match node with + | Micheline.Int (_, _) -> k (f acc node) + | Micheline.String (_, _) -> k (f acc node) + | Micheline.Bytes (_, _) -> k (f acc node) + | Micheline.Prim (_, _, subterms, _) -> + micheline_fold_nodes subterms f (f acc node) k + | Micheline.Seq (_, subterms) -> + micheline_fold_nodes subterms f (f acc node) k + +and[@coq_mutual_as_notation] [@coq_struct "subterms"] micheline_fold_nodes + subterms f acc k = + match subterms with + | [] -> k acc + | node :: nodes -> + micheline_fold_nodes nodes f acc @@ fun acc -> + micheline_fold_aux node f acc k + +let fold node init f = micheline_fold_aux node f init (fun x -> x) + +let micheline_nodes node = fold node 0 @@ fun n _ -> n + 1 + +let strip_locations_cost node = + let nodes = micheline_nodes node in + cost_micheline_strip_locations nodes diff --git a/src/proto_011_PtHangzH/lib_protocol/script_repr.mli b/src/proto_011_PtHangzH/lib_protocol/script_repr.mli new file mode 100644 index 000000000000..34d6a8305de8 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_repr.mli @@ -0,0 +1,109 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Defines a Michelson expression representation as a Micheline node with + canonical ([int]) location and [Michelson_v1_primitives.prim] as content. + + Types [expr] and [node] both define representation of Michelson + expressions and are indeed the same type internally, although this is not + visible outside Micheline due to interface abstraction. *) + +(** Locations are used by Micheline mostly for error-reporting and pretty- + printing expressions. [canonical_location] is simply an [int]. *) +type location = Micheline.canonical_location + +(** Annotations attached to Michelson expressions. *) +type annot = Micheline.annot + +(** Represents a Michelson expression as canonical Micheline. *) +type expr = Michelson_v1_primitives.prim Micheline.canonical + +type error += Lazy_script_decode (* `Permanent *) + +(** A record containing either an underlying serialized representation of an + expression or a deserialized one, or both. If either is absent, it will be + computed on-demand. *) +type lazy_expr = expr Data_encoding.lazy_t + +(** Same as [expr], but used in different contexts, as required by Micheline's + abstract interface. *) +type node = (location, Michelson_v1_primitives.prim) Micheline.node + +val location_encoding : location Data_encoding.t + +val expr_encoding : expr Data_encoding.t + +val lazy_expr_encoding : lazy_expr Data_encoding.t + +val lazy_expr : expr -> lazy_expr + +(** Type [t] joins the contract's code and storage in a single record. *) +type t = {code : lazy_expr; storage : lazy_expr} + +val encoding : t Data_encoding.encoding + +(* Basic gas costs of operations related to processing Michelson: *) + +val deserialization_cost_estimated_from_bytes : int -> Gas_limit_repr.cost + +val deserialized_cost : expr -> Gas_limit_repr.cost + +val serialized_cost : bytes -> Gas_limit_repr.cost + +val bytes_node_cost : bytes -> Gas_limit_repr.cost + +val force_decode_cost : lazy_expr -> Gas_limit_repr.cost + +val force_decode : lazy_expr -> expr tzresult + +val force_bytes_cost : lazy_expr -> Gas_limit_repr.cost + +val force_bytes : lazy_expr -> bytes tzresult + +val unit_parameter : lazy_expr + +val is_unit_parameter : lazy_expr -> bool + +val strip_annotations : node -> node + +val strip_locations_cost : node -> Gas_limit_repr.cost + +module Micheline_size : sig + type t = { + nodes : Saturation_repr.may_saturate Saturation_repr.t; + string_bytes : Saturation_repr.may_saturate Saturation_repr.t; + z_bytes : Saturation_repr.may_saturate Saturation_repr.t; + } + + val of_node : node -> t +end + +(** [micheline_nodes root] returns the number of internal nodes in the + micheline expression held from [root]. *) +val micheline_nodes : node -> int + +(** [fold node i f] traverses [node] applying [f] on an + accumulator initialized by [i]. *) +val fold : node -> 'c -> ('c -> node -> 'c) -> 'c diff --git a/src/proto_011_PtHangzH/lib_protocol/script_set.ml b/src/proto_011_PtHangzH/lib_protocol/script_set.ml new file mode 100644 index 000000000000..703ffae7aaa7 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_set.ml @@ -0,0 +1,75 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Script_typed_ir + +let empty : type a. a comparable_ty -> a set = + fun ty -> + let module OPS = Set.Make (struct + type t = a + + let compare = Script_comparable.compare_comparable ty + end) in + (module struct + type elt = a + + let elt_ty = ty + + module OPS = OPS + + let boxed = OPS.empty + + let size = 0 + end) + +let update : type a. a -> bool -> a set -> a set = + fun v b (module Box) -> + (module struct + type elt = a + + let elt_ty = Box.elt_ty + + module OPS = Box.OPS + + let boxed = + if b then Box.OPS.add v Box.boxed else Box.OPS.remove v Box.boxed + + let size = + let mem = Box.OPS.mem v Box.boxed in + if mem then if b then Box.size else Box.size - 1 + else if b then Box.size + 1 + else Box.size + end) + +let mem : type elt. elt -> elt set -> bool = + fun v (module Box) -> Box.OPS.mem v Box.boxed + +let fold : type elt acc. (elt -> acc -> acc) -> elt set -> acc -> acc = + fun f (module Box) -> Box.OPS.fold f Box.boxed + +let size : type elt. elt set -> Script_int.n Script_int.num = + fun (module Box) -> Script_int.(abs (of_int Box.size)) diff --git a/src/proto_011_PtHangzH/lib_protocol/script_set.mli b/src/proto_011_PtHangzH/lib_protocol/script_set.mli new file mode 100644 index 000000000000..f97a434c25ab --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_set.mli @@ -0,0 +1,37 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +val empty : 'a Script_typed_ir.comparable_ty -> 'a Script_typed_ir.set + +val fold : ('elt -> 'acc -> 'acc) -> 'elt Script_typed_ir.set -> 'acc -> 'acc + +val update : 'a -> bool -> 'a Script_typed_ir.set -> 'a Script_typed_ir.set + +val mem : 'elt -> 'elt Script_typed_ir.set -> bool + +val size : 'elt Script_typed_ir.set -> Script_int.n Script_int.num diff --git a/src/proto_011_PtHangzH/lib_protocol/script_string_repr.ml b/src/proto_011_PtHangzH/lib_protocol/script_string_repr.ml new file mode 100644 index 000000000000..0d74baa4893d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_string_repr.ml @@ -0,0 +1,77 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Strings of printable characters *) + +type t = string (* Invariant: contains only printable characters *) + +type error += Non_printable_character of (int * string) + +let () = + let open Data_encoding in + register_error_kind + `Permanent + ~id:"michelson_v1.non_printable_character" + ~title:"Non printable character in a Michelson string" + ~description: + "Michelson strings are only allowed to contain printable characters \ + (either the newline character or characters in the [32, 126] ASCII \ + range)." + ~pp:(fun ppf (pos, s) -> + Format.fprintf + ppf + "In Michelson string \"%s\", character at position %d has ASCII code \ + %d. Expected: either a newline character (ASCII code 10) or a \ + printable character (ASCII code between 32 and 126)." + s + pos + (Char.code s.[pos])) + (obj2 (req "position" int31) (req "string" string)) + (function Non_printable_character (pos, s) -> Some (pos, s) | _ -> None) + (fun (pos, s) -> Non_printable_character (pos, s)) + +let empty = "" + +let of_string v = + let rec check_printable_ascii i = + if Compare.Int.(i < 0) then ok v + else + match v.[i] with + | '\n' | '\x20' .. '\x7E' -> check_printable_ascii (i - 1) + | _ -> error @@ Non_printable_character (i, v) + in + check_printable_ascii (String.length v - 1) + +let to_string s = s + +let compare = Compare.String.compare + +let length = String.length + +let concat_pair x y = String.concat "" [x; y] + +let concat l = String.concat "" l + +let sub s offset length = String.sub s offset length diff --git a/src/proto_011_PtHangzH/lib_protocol/script_string_repr.mli b/src/proto_011_PtHangzH/lib_protocol/script_string_repr.mli new file mode 100644 index 000000000000..f94b65b389e1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_string_repr.mli @@ -0,0 +1,46 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Strings of printable characters *) + +type t + +type error += Non_printable_character of (int * string) + +val empty : t + +val of_string : string -> t tzresult + +val to_string : t -> string + +val compare : t -> t -> int + +val length : t -> int + +val concat_pair : t -> t -> t + +val concat : t list -> t + +val sub : t -> int -> int -> t diff --git a/src/proto_011_PtHangzH/lib_protocol/script_tc_errors.ml b/src/proto_011_PtHangzH/lib_protocol/script_tc_errors.ml new file mode 100644 index 000000000000..1abe59e2e508 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_tc_errors.ml @@ -0,0 +1,204 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Script + +(* ---- Error definitions ---------------------------------------------------*) + +type kind = Int_kind | String_kind | Bytes_kind | Prim_kind | Seq_kind + +type unparsed_stack_ty = (Script.expr * Script.annot) list + +type type_map = (int * (unparsed_stack_ty * unparsed_stack_ty)) list + +(* Structure errors *) +type error += Invalid_arity of Script.location * prim * int * int + +type error += Invalid_seq_arity of Script.location * int * int + +type error += + | Invalid_namespace of + Script.location + * prim + * Michelson_v1_primitives.namespace + * Michelson_v1_primitives.namespace + +type error += Invalid_primitive of Script.location * prim list * prim + +type error += Invalid_kind of Script.location * kind list * kind + +type error += Invalid_never_expr of Script.location + +type error += Missing_field of prim + +type error += Duplicate_field of Script.location * prim + +type error += Unexpected_lazy_storage of Script.location + +type error += Unexpected_operation of Script.location + +type error += Unexpected_contract of Script.location + +type error += No_such_entrypoint of string + +type error += Duplicate_entrypoint of string + +type error += Unreachable_entrypoint of prim list + +type error += Entrypoint_name_too_long of string + +(* Instruction typing errors *) +type error += Fail_not_in_tail_position of Script.location + +type error += + | Undefined_binop : + Script.location * prim * Script.expr * Script.expr + -> error + +type error += Undefined_unop : Script.location * prim * Script.expr -> error + +type error += + | Bad_return : Script.location * unparsed_stack_ty * Script.expr -> error + +type error += + | Bad_stack : Script.location * prim * int * unparsed_stack_ty -> error + +type error += + | Unmatched_branches : + Script.location * unparsed_stack_ty * unparsed_stack_ty + -> error + +(* View errors *) +type error += View_name_too_long of string + +type error += Bad_view_name of Script.location + +type error += + | Ill_typed_view of { + loc : Script.location; + actual : unparsed_stack_ty; + expected : unparsed_stack_ty; + } + +type error += Duplicated_view_name of Script.location + +type error += Self_in_lambda of Script.location + +type error += Bad_stack_length + +type error += Bad_stack_item of int + +type error += Inconsistent_annotations of string * string + +type error += + | Inconsistent_type_annotations : + Script.location * Script.expr * Script.expr + -> error + +type error += Inconsistent_field_annotations of string * string + +type error += Unexpected_annotation of Script.location + +type error += Ungrouped_annotations of Script.location + +type error += Invalid_map_body : Script.location * unparsed_stack_ty -> error + +type error += Invalid_map_block_fail of Script.location + +type error += + | Invalid_iter_body : + Script.location * unparsed_stack_ty * unparsed_stack_ty + -> error + +type error += Type_too_large : Script.location * int -> error + +type error += Pair_bad_argument of Script.location + +type error += Unpair_bad_argument of Script.location + +type error += Dup_n_bad_argument of Script.location + +type error += Dup_n_bad_stack of Script.location + +(* Value typing errors *) +type error += + | Invalid_constant : Script.location * Script.expr * Script.expr -> error + +type error += + | Invalid_syntactic_constant : Script.location * Script.expr * string -> error + +type error += Invalid_contract of Script.location * Contract.t + +type error += Invalid_big_map of Script.location * Big_map.Id.t + +type error += Comparable_type_expected : Script.location * Script.expr -> error + +type error += Inconsistent_type_sizes : int * int -> error + +type error += + | Inconsistent_types : + Script.location option * Script.expr * Script.expr + -> error + +type error += + | Inconsistent_memo_sizes : Sapling.Memo_size.t * Sapling.Memo_size.t -> error + +type error += Unordered_map_keys of Script.location * Script.expr + +type error += Unordered_set_values of Script.location * Script.expr + +type error += Duplicate_map_keys of Script.location * Script.expr + +type error += Duplicate_set_values of Script.location * Script.expr + +(* Toplevel errors *) +type error += + | Ill_typed_data : string option * Script.expr * Script.expr -> error + +type error += Ill_formed_type of string option * Script.expr * Script.location + +type error += Ill_typed_contract : Script.expr * type_map -> error + +(* Gas related errors *) +type error += Cannot_serialize_error + +(* Deprecation errors *) +type error += Deprecated_instruction of prim + +(* Stackoverflow errors *) +type error += Typechecking_too_many_recursive_calls + +type error += Unparsing_too_many_recursive_calls + +(* Ticket errors *) +type error += Unexpected_ticket of Script.location + +type error += Unexpected_forged_value of Script.location + +type error += Non_dupable_type of Script.location * Script.expr + +(* Impossible errors *) +type error += Unparsing_invariant_violated diff --git a/src/proto_011_PtHangzH/lib_protocol/script_tc_errors_registration.ml b/src/proto_011_PtHangzH/lib_protocol/script_tc_errors_registration.ml new file mode 100644 index 000000000000..e6dde353d9a6 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_tc_errors_registration.ml @@ -0,0 +1,814 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Script +open Script_tc_errors + +(* Helpers for encoding *) +let type_map_enc = + let open Data_encoding in + let stack_enc = list (tup2 Script.expr_encoding (list string)) in + list + (conv + (fun (loc, (bef, aft)) -> (loc, bef, aft)) + (fun (loc, bef, aft) -> (loc, (bef, aft))) + (obj3 + (req "location" Script.location_encoding) + (req "stack_before" stack_enc) + (req "stack_after" stack_enc))) + +let stack_ty_enc = + let open Data_encoding in + list (obj2 (req "type" Script.expr_encoding) (dft "annots" (list string) [])) + +(* main registration *) +let () = + let open Data_encoding in + let located enc = + merge_objs (obj1 (req "location" Script.location_encoding)) enc + in + let arity_enc = int8 in + let namespace_enc = + def + "primitiveNamespace" + ~title:"Primitive namespace" + ~description: + "One of the five possible namespaces of primitive (data constructor, \ + type name, instruction, keyword, or constant hash)." + @@ string_enum + [ + ("type", Michelson_v1_primitives.Type_namespace); + ("constant", Constant_namespace); + ("instruction", Instr_namespace); + ("keyword", Keyword_namespace); + ("constant_hash", Constant_hash_namespace); + ] + in + let kind_enc = + def + "expressionKind" + ~title:"Expression kind" + ~description: + "One of the four possible kinds of expression (integer, string, \ + primitive application or sequence)." + @@ string_enum + [ + ("integer", Int_kind); + ("string", String_kind); + ("bytes", Bytes_kind); + ("primitiveApplication", Prim_kind); + ("sequence", Seq_kind); + ] + in + (* -- Structure errors ---------------------- *) + (* Invalid arity *) + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_arity" + ~title:"Invalid arity" + ~description: + "In a script or data expression, a primitive was applied to an \ + unsupported number of arguments." + (located + (obj3 + (req "primitive_name" Script.prim_encoding) + (req "expected_arity" arity_enc) + (req "wrong_arity" arity_enc))) + (function + | Invalid_arity (loc, name, exp, got) -> Some (loc, (name, exp, got)) + | _ -> None) + (fun (loc, (name, exp, got)) -> Invalid_arity (loc, name, exp, got)) ; + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_seq_arity" + ~title:"Invalid sequence arity" + ~description: + "In a script or data expression, a sequence was used with a number of \ + elements too small." + (located + (obj2 + (req "minimal_expected_arity" arity_enc) + (req "wrong_arity" arity_enc))) + (function + | Invalid_seq_arity (loc, exp, got) -> Some (loc, (exp, got)) | _ -> None) + (fun (loc, (exp, got)) -> Invalid_seq_arity (loc, exp, got)) ; + (* Missing field *) + register_error_kind + `Permanent + ~id:"michelson_v1.missing_script_field" + ~title:"Script is missing a field (parse error)" + ~description:"When parsing script, a field was expected, but not provided" + (obj1 (req "prim" prim_encoding)) + (function Missing_field prim -> Some prim | _ -> None) + (fun prim -> Missing_field prim) ; + (* Invalid primitive *) + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_primitive" + ~title:"Invalid primitive" + ~description:"In a script or data expression, a primitive was unknown." + (located + (obj2 + (dft "expected_primitive_names" (list prim_encoding) []) + (req "wrong_primitive_name" prim_encoding))) + (function + | Invalid_primitive (loc, exp, got) -> Some (loc, (exp, got)) | _ -> None) + (fun (loc, (exp, got)) -> Invalid_primitive (loc, exp, got)) ; + (* Invalid kind *) + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_expression_kind" + ~title:"Invalid expression kind" + ~description: + "In a script or data expression, an expression was of the wrong kind \ + (for instance a string where only a primitive applications can appear)." + (located + (obj2 (req "expected_kinds" (list kind_enc)) (req "wrong_kind" kind_enc))) + (function + | Invalid_kind (loc, exp, got) -> Some (loc, (exp, got)) | _ -> None) + (fun (loc, (exp, got)) -> Invalid_kind (loc, exp, got)) ; + (* Invalid namespace *) + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_primitive_namespace" + ~title:"Invalid primitive namespace" + ~description: + "In a script or data expression, a primitive was of the wrong namespace." + (located + (obj3 + (req "primitive_name" prim_encoding) + (req "expected_namespace" namespace_enc) + (req "wrong_namespace" namespace_enc))) + (function + | Invalid_namespace (loc, name, exp, got) -> Some (loc, (name, exp, got)) + | _ -> None) + (fun (loc, (name, exp, got)) -> Invalid_namespace (loc, name, exp, got)) ; + (* Invalid literal for type never *) + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_never_expr" + ~title:"Invalid expression for type never" + ~description: + "In a script or data expression, an expression was provided but a value \ + of type never was expected. No expression can have type never." + (located unit) + (function Invalid_never_expr loc -> Some (loc, ()) | _ -> None) + (fun (loc, ()) -> Invalid_never_expr loc) ; + (* Duplicate field *) + register_error_kind + `Permanent + ~id:"michelson_v1.duplicate_script_field" + ~title:"Script has a duplicated field (parse error)" + ~description:"When parsing script, a field was found more than once" + (obj2 (req "loc" location_encoding) (req "prim" prim_encoding)) + (function Duplicate_field (loc, prim) -> Some (loc, prim) | _ -> None) + (fun (loc, prim) -> Duplicate_field (loc, prim)) ; + (* Unexpected big_map *) + register_error_kind + `Permanent + ~id:"michelson_v1.unexpected_lazy_storage" + ~title:"Lazy storage in unauthorized position (type error)" + ~description: + "When parsing script, a big_map or sapling_state type was found in a \ + position where it could end up stored inside a big_map, which is \ + forbidden for now." + (obj1 (req "loc" location_encoding)) + (function Unexpected_lazy_storage loc -> Some loc | _ -> None) + (fun loc -> Unexpected_lazy_storage loc) ; + (* Unexpected operation *) + register_error_kind + `Permanent + ~id:"michelson_v1.unexpected_operation" + ~title:"Operation in unauthorized position (type error)" + ~description: + "When parsing script, an operation type was found in the storage or \ + parameter field." + (obj1 (req "loc" location_encoding)) + (function Unexpected_operation loc -> Some loc | _ -> None) + (fun loc -> Unexpected_operation loc) ; + (* No such entrypoint *) + register_error_kind + `Permanent + ~id:"michelson_v1.no_such_entrypoint" + ~title:"No such entrypoint (type error)" + ~description:"An entrypoint was not found when calling a contract." + (obj1 (req "entrypoint" string)) + (function No_such_entrypoint entrypoint -> Some entrypoint | _ -> None) + (fun entrypoint -> No_such_entrypoint entrypoint) ; + (* Unreachable entrypoint *) + register_error_kind + `Permanent + ~id:"michelson_v1.unreachable_entrypoint" + ~title:"Unreachable entrypoint (type error)" + ~description:"An entrypoint in the contract is not reachable." + (obj1 (req "path" (list prim_encoding))) + (function Unreachable_entrypoint path -> Some path | _ -> None) + (fun path -> Unreachable_entrypoint path) ; + (* Duplicate entrypoint *) + register_error_kind + `Permanent + ~id:"michelson_v1.duplicate_entrypoint" + ~title:"Duplicate entrypoint (type error)" + ~description:"Two entrypoints have the same name." + (obj1 (req "path" string)) + (function Duplicate_entrypoint entrypoint -> Some entrypoint | _ -> None) + (fun entrypoint -> Duplicate_entrypoint entrypoint) ; + (* Entrypoint name too long *) + register_error_kind + `Permanent + ~id:"michelson_v1.entrypoint_name_too_long" + ~title:"Entrypoint name too long (type error)" + ~description: + "An entrypoint name exceeds the maximum length of 31 characters." + (obj1 (req "name" string)) + (function + | Entrypoint_name_too_long entrypoint -> Some entrypoint | _ -> None) + (fun entrypoint -> Entrypoint_name_too_long entrypoint) ; + (* Unexpected contract *) + register_error_kind + `Permanent + ~id:"michelson_v1.unexpected_contract" + ~title:"Contract in unauthorized position (type error)" + ~description: + "When parsing script, a contract type was found in the storage or \ + parameter field." + (obj1 (req "loc" location_encoding)) + (function Unexpected_contract loc -> Some loc | _ -> None) + (fun loc -> Unexpected_contract loc) ; + (* -- Value typing errors ---------------------- *) + (* Unordered map keys *) + register_error_kind + `Permanent + ~id:"michelson_v1.unordered_map_literal" + ~title:"Invalid map key order" + ~description:"Map keys must be in strictly increasing order" + (obj2 + (req "location" Script.location_encoding) + (req "item" Script.expr_encoding)) + (function Unordered_map_keys (loc, expr) -> Some (loc, expr) | _ -> None) + (fun (loc, expr) -> Unordered_map_keys (loc, expr)) ; + (* Duplicate map keys *) + register_error_kind + `Permanent + ~id:"michelson_v1.duplicate_map_keys" + ~title:"Duplicate map keys" + ~description:"Map literals cannot contain duplicated keys" + (obj2 + (req "location" Script.location_encoding) + (req "item" Script.expr_encoding)) + (function Duplicate_map_keys (loc, expr) -> Some (loc, expr) | _ -> None) + (fun (loc, expr) -> Duplicate_map_keys (loc, expr)) ; + (* Unordered set values *) + register_error_kind + `Permanent + ~id:"michelson_v1.unordered_set_literal" + ~title:"Invalid set value order" + ~description:"Set values must be in strictly increasing order" + (obj2 + (req "location" Script.location_encoding) + (req "value" Script.expr_encoding)) + (function + | Unordered_set_values (loc, expr) -> Some (loc, expr) | _ -> None) + (fun (loc, expr) -> Unordered_set_values (loc, expr)) ; + (* Duplicate set values *) + register_error_kind + `Permanent + ~id:"michelson_v1.duplicate_set_values_in_literal" + ~title:"Sets literals cannot contain duplicate elements" + ~description: + "Set literals cannot contain duplicate elements, but a duplicate was \ + found while parsing." + (obj2 + (req "location" Script.location_encoding) + (req "value" Script.expr_encoding)) + (function + | Duplicate_set_values (loc, expr) -> Some (loc, expr) | _ -> None) + (fun (loc, expr) -> Duplicate_set_values (loc, expr)) ; + (* -- Instruction typing errors ------------- *) + (* Fail not in tail position *) + register_error_kind + `Permanent + ~id:"michelson_v1.fail_not_in_tail_position" + ~title:"FAIL not in tail position" + ~description:"There is non trivial garbage code after a FAIL instruction." + (located empty) + (function Fail_not_in_tail_position loc -> Some (loc, ()) | _ -> None) + (fun (loc, ()) -> Fail_not_in_tail_position loc) ; + (* Undefined binary operation *) + register_error_kind + `Permanent + ~id:"michelson_v1.undefined_binop" + ~title:"Undefined binop" + ~description: + "A binary operation is called on operands of types over which it is not \ + defined." + (located + (obj3 + (req "operator_name" prim_encoding) + (req "wrong_left_operand_type" Script.expr_encoding) + (req "wrong_right_operand_type" Script.expr_encoding))) + (function + | Undefined_binop (loc, n, tyl, tyr) -> Some (loc, (n, tyl, tyr)) + | _ -> None) + (fun (loc, (n, tyl, tyr)) -> Undefined_binop (loc, n, tyl, tyr)) ; + (* Undefined unary operation *) + register_error_kind + `Permanent + ~id:"michelson_v1.undefined_unop" + ~title:"Undefined unop" + ~description: + "A unary operation is called on an operand of type over which it is not \ + defined." + (located + (obj2 + (req "operator_name" prim_encoding) + (req "wrong_operand_type" Script.expr_encoding))) + (function Undefined_unop (loc, n, ty) -> Some (loc, (n, ty)) | _ -> None) + (fun (loc, (n, ty)) -> Undefined_unop (loc, n, ty)) ; + (* Bad return *) + register_error_kind + `Permanent + ~id:"michelson_v1.bad_return" + ~title:"Bad return" + ~description:"Unexpected stack at the end of a lambda or script." + (located + (obj2 + (req "expected_return_type" Script.expr_encoding) + (req "wrong_stack_type" stack_ty_enc))) + (function Bad_return (loc, sty, ty) -> Some (loc, (ty, sty)) | _ -> None) + (fun (loc, (ty, sty)) -> Bad_return (loc, sty, ty)) ; + (* Bad stack *) + register_error_kind + `Permanent + ~id:"michelson_v1.bad_stack" + ~title:"Bad stack" + ~description:"The stack has an unexpected length or contents." + (located + (obj3 + (req "primitive_name" prim_encoding) + (req "relevant_stack_portion" int16) + (req "wrong_stack_type" stack_ty_enc))) + (function + | Bad_stack (loc, name, s, sty) -> Some (loc, (name, s, sty)) | _ -> None) + (fun (loc, (name, s, sty)) -> Bad_stack (loc, name, s, sty)) ; + (* Inconsistent annotations *) + register_error_kind + `Permanent + ~id:"michelson_v1.inconsistent_annotations" + ~title:"Annotations inconsistent between branches" + ~description:"The annotations on two types could not be merged" + (obj2 (req "annot1" string) (req "annot2" string)) + (function + | Inconsistent_annotations (annot1, annot2) -> Some (annot1, annot2) + | _ -> None) + (fun (annot1, annot2) -> Inconsistent_annotations (annot1, annot2)) ; + (* Inconsistent field annotations *) + register_error_kind + `Permanent + ~id:"michelson_v1.inconsistent_field_annotations" + ~title:"Annotations for field accesses is inconsistent" + ~description: + "The specified field does not match the field annotation in the type" + (obj2 (req "annot1" string) (req "annot2" string)) + (function + | Inconsistent_field_annotations (annot1, annot2) -> Some (annot1, annot2) + | _ -> None) + (fun (annot1, annot2) -> Inconsistent_field_annotations (annot1, annot2)) ; + (* Inconsistent type annotations *) + register_error_kind + `Permanent + ~id:"michelson_v1.inconsistent_type_annotations" + ~title:"Types contain inconsistent annotations" + ~description:"The two types contain annotations that do not match" + (located + (obj2 + (req "type1" Script.expr_encoding) + (req "type2" Script.expr_encoding))) + (function + | Inconsistent_type_annotations (loc, ty1, ty2) -> Some (loc, (ty1, ty2)) + | _ -> None) + (fun (loc, (ty1, ty2)) -> Inconsistent_type_annotations (loc, ty1, ty2)) ; + (* Unexpected annotation *) + register_error_kind + `Permanent + ~id:"michelson_v1.unexpected_annotation" + ~title:"An annotation was encountered where no annotation is expected" + ~description:"A node in the syntax tree was improperly annotated" + (located empty) + (function Unexpected_annotation loc -> Some (loc, ()) | _ -> None) + (fun (loc, ()) -> Unexpected_annotation loc) ; + (* Ungrouped annotations *) + register_error_kind + `Permanent + ~id:"michelson_v1.ungrouped_annotations" + ~title:"Annotations of the same kind were found spread apart" + ~description:"Annotations of the same kind must be grouped" + (located empty) + (function Ungrouped_annotations loc -> Some (loc, ()) | _ -> None) + (fun (loc, ()) -> Ungrouped_annotations loc) ; + (* Unmatched branches *) + register_error_kind + `Permanent + ~id:"michelson_v1.unmatched_branches" + ~title:"Unmatched branches" + ~description: + "At the join point at the end of two code branches the stacks have \ + inconsistent lengths or contents." + (located + (obj2 + (req "first_stack_type" stack_ty_enc) + (req "other_stack_type" stack_ty_enc))) + (function + | Unmatched_branches (loc, stya, styb) -> Some (loc, (stya, styb)) + | _ -> None) + (fun (loc, (stya, styb)) -> Unmatched_branches (loc, stya, styb)) ; + (* Bad stack item *) + register_error_kind + `Permanent + ~id:"michelson_v1.bad_stack_item" + ~title:"Bad stack item" + ~description: + "The type of a stack item is unexpected (this error is always \ + accompanied by a more precise one)." + (obj1 (req "item_level" int16)) + (function Bad_stack_item n -> Some n | _ -> None) + (fun n -> Bad_stack_item n) ; + (* SELF in lambda *) + register_error_kind + `Permanent + ~id:"michelson_v1.self_in_lambda" + ~title:"SELF instruction in lambda" + ~description:"A SELF instruction was encountered in a lambda expression." + (located empty) + (function Self_in_lambda loc -> Some (loc, ()) | _ -> None) + (fun (loc, ()) -> Self_in_lambda loc) ; + (* Bad stack length *) + register_error_kind + `Permanent + ~id:"michelson_v1.inconsistent_stack_lengths" + ~title:"Inconsistent stack lengths" + ~description: + "A stack was of an unexpected length (this error is always in the \ + context of a located error)." + empty + (function Bad_stack_length -> Some () | _ -> None) + (fun () -> Bad_stack_length) ; + (* -- Value typing errors ------------------- *) + (* Invalid constant *) + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_constant" + ~title:"Invalid constant" + ~description:"A data expression was invalid for its expected type." + (located + (obj2 + (req "expected_type" Script.expr_encoding) + (req "wrong_expression" Script.expr_encoding))) + (function + | Invalid_constant (loc, expr, ty) -> Some (loc, (ty, expr)) | _ -> None) + (fun (loc, (ty, expr)) -> Invalid_constant (loc, expr, ty)) ; + (* View name too long *) + register_error_kind + `Permanent + ~id:"michelson_v1.view_name_too_long" + ~title:"View name too long (type error)" + ~description:"A view name exceeds the maximum length of 31 characters." + (obj1 (req "name" string)) + (function View_name_too_long name -> Some name | _ -> None) + (fun name -> View_name_too_long name) ; + (* Duplicated view name *) + register_error_kind + `Permanent + ~id:"michelson_v1.duplicated_view_name" + ~title:"Duplicated view name" + ~description:"The name of view in toplevel should be unique." + (obj1 (req "location" Script.location_encoding)) + (function Duplicated_view_name loc -> Some loc | _ -> None) + (fun loc -> Duplicated_view_name loc) ; + (* Invalid syntactic constant *) + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_syntactic_constant" + ~title:"Invalid constant (parse error)" + ~description:"A compile-time constant was invalid for its expected form." + (located + (obj2 + (req "expected_form" string) + (req "wrong_expression" Script.expr_encoding))) + (function + | Invalid_syntactic_constant (loc, expr, expected) -> + Some (loc, (expected, expr)) + | _ -> None) + (fun (loc, (expected, expr)) -> + Invalid_syntactic_constant (loc, expr, expected)) ; + (* Invalid contract *) + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_contract" + ~title:"Invalid contract" + ~description: + "A script or data expression references a contract that does not exist \ + or assumes a wrong type for an existing contract." + (located (obj1 (req "contract" Contract.encoding))) + (function Invalid_contract (loc, c) -> Some (loc, c) | _ -> None) + (fun (loc, c) -> Invalid_contract (loc, c)) ; + (* Invalid big_map *) + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_big_map" + ~title:"Invalid big_map" + ~description: + "A script or data expression references a big_map that does not exist or \ + assumes a wrong type for an existing big_map." + (located (obj1 (req "big_map" Big_map.Id.encoding))) + (function Invalid_big_map (loc, c) -> Some (loc, c) | _ -> None) + (fun (loc, c) -> Invalid_big_map (loc, c)) ; + (* Comparable type expected *) + register_error_kind + `Permanent + ~id:"michelson_v1.comparable_type_expected" + ~title:"Comparable type expected" + ~description: + "A non comparable type was used in a place where only comparable types \ + are accepted." + (located (obj1 (req "wrong_type" Script.expr_encoding))) + (function + | Comparable_type_expected (loc, ty) -> Some (loc, ty) | _ -> None) + (fun (loc, ty) -> Comparable_type_expected (loc, ty)) ; + (* Inconsistent type sizes *) + register_error_kind + `Permanent + ~id:"michelson_v1.inconsistent_type_sizes" + ~title:"Inconsistent type sizes" + ~description: + "Two types were expected to be equal but they have different sizes." + (obj2 (req "first_type_size" int31) (req "other_type_size" int31)) + (function + | Inconsistent_type_sizes (tya, tyb) -> Some (tya, tyb) | _ -> None) + (fun (tya, tyb) -> Inconsistent_type_sizes (tya, tyb)) ; + (* Inconsistent types *) + register_error_kind + `Permanent + ~id:"michelson_v1.inconsistent_types" + ~title:"Inconsistent types" + ~description: + "This is the basic type clash error, that appears in several places \ + where the equality of two types have to be proven, it is always \ + accompanied with another error that provides more context." + (obj3 + (opt "loc" Script.location_encoding) + (req "first_type" Script.expr_encoding) + (req "other_type" Script.expr_encoding)) + (function + | Inconsistent_types (loc, tya, tyb) -> Some (loc, tya, tyb) | _ -> None) + (fun (loc, tya, tyb) -> Inconsistent_types (loc, tya, tyb)) ; + (* Inconsistent memo_sizes *) + register_error_kind + `Permanent + ~id:"michelson_v1.inconsistent_memo_sizes" + ~title:"Inconsistent memo sizes" + ~description:"Memo sizes of two sapling states or transactions do not match" + (obj2 + (req "first_memo_size" Sapling.Memo_size.encoding) + (req "other_memo_size" Sapling.Memo_size.encoding)) + (function + | Inconsistent_memo_sizes (msa, msb) -> Some (msa, msb) | _ -> None) + (fun (msa, msb) -> Inconsistent_memo_sizes (msa, msb)) ; + (* -- Instruction typing errors ------------------- *) + (* Bad view name *) + register_error_kind + `Permanent + ~id:"michelson_v1.bad_view_name" + ~title:"Bad view name" + ~description:"In a view declaration, the view name must be a string" + (obj1 (req "loc" Script.location_encoding)) + (function Bad_view_name loc -> Some loc | _ -> None) + (fun loc -> Bad_view_name loc) ; + (* Invalid view body *) + register_error_kind + `Permanent + ~id:"michelson_v1.ill_typed_view" + ~title:"Ill typed view" + ~description:"The return of a view block did not match the expected type" + (obj3 + (req "loc" Script.location_encoding) + (req "resulted_view_stack" stack_ty_enc) + (req "expected_view_stack" stack_ty_enc)) + (function + | Ill_typed_view {loc; actual; expected} -> Some (loc, actual, expected) + | _ -> None) + (fun (loc, actual, expected) -> Ill_typed_view {loc; actual; expected}) ; + (* Invalid map body *) + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_map_body" + ~title:"Invalid map body" + ~description:"The body of a map block did not match the expected type" + (obj2 (req "loc" Script.location_encoding) (req "body_type" stack_ty_enc)) + (function Invalid_map_body (loc, stack) -> Some (loc, stack) | _ -> None) + (fun (loc, stack) -> Invalid_map_body (loc, stack)) ; + (* Invalid map block FAIL *) + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_map_block_fail" + ~title:"FAIL instruction occurred as body of map block" + ~description: + "FAIL cannot be the only instruction in the body. The proper type of the \ + return list cannot be inferred." + (obj1 (req "loc" Script.location_encoding)) + (function Invalid_map_block_fail loc -> Some loc | _ -> None) + (fun loc -> Invalid_map_block_fail loc) ; + (* Invalid ITER body *) + register_error_kind + `Permanent + ~id:"michelson_v1.invalid_iter_body" + ~title:"ITER body returned wrong stack type" + ~description: + "The body of an ITER instruction must result in the same stack type as \ + before the ITER." + (obj3 + (req "loc" Script.location_encoding) + (req "bef_stack" stack_ty_enc) + (req "aft_stack" stack_ty_enc)) + (function + | Invalid_iter_body (loc, bef, aft) -> Some (loc, bef, aft) | _ -> None) + (fun (loc, bef, aft) -> Invalid_iter_body (loc, bef, aft)) ; + (* Type too large *) + register_error_kind + `Permanent + ~id:"michelson_v1.type_too_large" + ~title:"Stack item type too large" + ~description:"An instruction generated a type larger than the limit." + (obj2 (req "loc" Script.location_encoding) (req "maximum_type_size" uint16)) + (function Type_too_large (loc, maxts) -> Some (loc, maxts) | _ -> None) + (fun (loc, maxts) -> Type_too_large (loc, maxts)) ; + (* Bad PAIR argument *) + register_error_kind + `Permanent + ~id:"michelson_v1.bad_pair_argument" + ~title:"0 or 1 passed to PAIR" + ~description:"PAIR expects an argument of at least 2" + (obj1 (req "loc" Script.location_encoding)) + (function Pair_bad_argument loc -> Some loc | _ -> None) + (fun loc -> Pair_bad_argument loc) ; + (* Bad UNPAIR argument *) + register_error_kind + `Permanent + ~id:"michelson_v1.bad_unpair_argument" + ~title:"0 or 1 passed to UNPAIR" + ~description:"UNPAIR expects an argument of at least 2" + (obj1 (req "loc" Script.location_encoding)) + (function Unpair_bad_argument loc -> Some loc | _ -> None) + (fun loc -> Unpair_bad_argument loc) ; + (* Bad dup_n argument *) + register_error_kind + `Permanent + ~id:"michelson_v1.bad_dupn_argument" + ~title:"0 passed to DUP n" + ~description:"DUP expects an argument of at least 1 (passed 0)" + (obj1 (req "loc" Script.location_encoding)) + (function Dup_n_bad_argument loc -> Some loc | _ -> None) + (fun loc -> Dup_n_bad_argument loc) ; + (* Bad dup_n stack *) + register_error_kind + `Permanent + ~id:"michelson_v1.bad_dupn_stack" + ~title:"Stack too short when typing DUP n" + ~description:"Stack present when typing DUP n was too short" + (obj1 (req "loc" Script.location_encoding)) + (function Dup_n_bad_stack x -> Some x | _ -> None) + (fun x -> Dup_n_bad_stack x) ; + (* -- Toplevel errors ------------------- *) + (* Ill typed data *) + register_error_kind + `Permanent + ~id:"michelson_v1.ill_typed_data" + ~title:"Ill typed data" + ~description: + "The toplevel error thrown when trying to typecheck a data expression \ + against a given type (always followed by more precise errors)." + (obj3 + (opt "identifier" string) + (req "expected_type" Script.expr_encoding) + (req "ill_typed_expression" Script.expr_encoding)) + (function + | Ill_typed_data (name, expr, ty) -> Some (name, ty, expr) | _ -> None) + (fun (name, ty, expr) -> Ill_typed_data (name, expr, ty)) ; + (* Ill formed type *) + register_error_kind + `Permanent + ~id:"michelson_v1.ill_formed_type" + ~title:"Ill formed type" + ~description: + "The toplevel error thrown when trying to parse a type expression \ + (always followed by more precise errors)." + (obj3 + (opt "identifier" string) + (req "ill_formed_expression" Script.expr_encoding) + (req "location" Script.location_encoding)) + (function + | Ill_formed_type (name, expr, loc) -> Some (name, expr, loc) | _ -> None) + (fun (name, expr, loc) -> Ill_formed_type (name, expr, loc)) ; + (* Ill typed contract *) + register_error_kind + `Permanent + ~id:"michelson_v1.ill_typed_contract" + ~title:"Ill typed contract" + ~description: + "The toplevel error thrown when trying to typecheck a contract code \ + against given input, output and storage types (always followed by more \ + precise errors)." + (obj2 + (req "ill_typed_code" Script.expr_encoding) + (req "type_map" type_map_enc)) + (function + | Ill_typed_contract (expr, type_map) -> Some (expr, type_map) | _ -> None) + (fun (expr, type_map) -> Ill_typed_contract (expr, type_map)) ; + (* Cannot serialize error *) + register_error_kind + `Temporary + ~id:"michelson_v1.cannot_serialize_error" + ~title:"Not enough gas to serialize error" + ~description:"The error was too big to be serialized with the provided gas" + Data_encoding.empty + (function Cannot_serialize_error -> Some () | _ -> None) + (fun () -> Cannot_serialize_error) ; + (* Deprecated instruction *) + register_error_kind + `Permanent + ~id:"michelson_v1.deprecated_instruction" + ~title:"Script is using a deprecated instruction" + ~description: + "A deprecated instruction usage is disallowed in newly created contracts" + (obj1 (req "prim" prim_encoding)) + (function Deprecated_instruction prim -> Some prim | _ -> None) + (fun prim -> Deprecated_instruction prim) ; + (* Typechecking stack overflow *) + register_error_kind + `Temporary + ~id:"michelson_v1.typechecking_too_many_recursive_calls" + ~title:"Too many recursive calls during typechecking" + ~description:"Too many recursive calls were needed for typechecking" + Data_encoding.empty + (function Typechecking_too_many_recursive_calls -> Some () | _ -> None) + (fun () -> Typechecking_too_many_recursive_calls) ; + (* Unparsing stack overflow *) + register_error_kind + `Temporary + ~id:"michelson_v1.unparsing_stack_overflow" + ~title:"Too many recursive calls during unparsing" + ~description:"Too many recursive calls were needed for unparsing" + Data_encoding.empty + (function Unparsing_too_many_recursive_calls -> Some () | _ -> None) + (fun () -> Unparsing_too_many_recursive_calls) ; + (* Unexpected forged value *) + register_error_kind + `Permanent + ~id:"michelson_v1.unexpected_forged_value" + ~title:"Unexpected forged value" + ~description: + "A forged value was encountered but disallowed for that position." + (obj1 (req "location" Script.location_encoding)) + (function Unexpected_forged_value loc -> Some loc | _ -> None) + (fun loc -> Unexpected_forged_value loc) ; + (* Unexpected ticket *) + register_error_kind + `Permanent + ~id:"michelson_v1.unexpected_ticket" + ~title:"Ticket in unauthorized position (type error)" + ~description:"A ticket type has been found" + (obj1 (req "loc" location_encoding)) + (function Unexpected_ticket loc -> Some loc | _ -> None) + (fun loc -> Unexpected_ticket loc) ; + (* Attempt to duplicate a non-dupable type *) + register_error_kind + `Permanent + ~id:"michelson_v1.non_dupable_type" + ~title:"Non-dupable type duplication attempt" + ~description:"DUP was used on a non-dupable type (e.g. tickets)." + (obj2 (req "loc" location_encoding) (req "type" Script.expr_encoding)) + (function Non_dupable_type (loc, ty) -> Some (loc, ty) | _ -> None) + (fun (loc, ty) -> Non_dupable_type (loc, ty)) diff --git a/src/proto_011_PtHangzH/lib_protocol/script_tc_errors_registration.mli b/src/proto_011_PtHangzH/lib_protocol/script_tc_errors_registration.mli new file mode 100644 index 000000000000..c8dd34c2e0bd --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_tc_errors_registration.mli @@ -0,0 +1,34 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Script + +val type_map_enc : + (location * ((expr * string list) list * (expr * string list) list)) list + Data_encoding.encoding + +val stack_ty_enc : (expr * string list) list Data_encoding.encoding diff --git a/src/proto_011_PtHangzH/lib_protocol/script_timestamp_repr.ml b/src/proto_011_PtHangzH/lib_protocol/script_timestamp_repr.ml new file mode 100644 index 000000000000..ee4fd84cf788 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_timestamp_repr.ml @@ -0,0 +1,53 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type t = Z.t + +let compare = Z.compare + +let of_int64 = Z.of_int64 + +let of_string x = + match Time_repr.of_notation x with + | None -> Option.catch (fun () -> Z.of_string x) + | Some time -> Some (of_int64 (Time_repr.to_seconds time)) + +let to_notation x = + Option.catch (fun () -> + Time_repr.to_notation (Time.of_seconds (Z.to_int64 x))) + +let to_num_str = Z.to_string + +let to_string x = match to_notation x with None -> to_num_str x | Some s -> s + +let diff x y = Script_int_repr.of_zint @@ Z.sub x y + +let sub_delta t delta = Z.sub t (Script_int_repr.to_zint delta) + +let add_delta t delta = Z.add t (Script_int_repr.to_zint delta) + +let to_zint x = x + +let of_zint x = x diff --git a/src/proto_011_PtHangzH/lib_protocol/script_timestamp_repr.mli b/src/proto_011_PtHangzH/lib_protocol/script_timestamp_repr.mli new file mode 100644 index 000000000000..7b6533e9b606 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_timestamp_repr.mli @@ -0,0 +1,65 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Defines the internal Michelson representation for timestamps and basic + operations that can be performed on it. *) + +open Script_int_repr + +(** Representation of timestamps specific to the Michelson interpreter. + A number of seconds since the epoch. *) +type t + +(** Convert a number of seconds since the epoch to a timestamp.*) +val of_int64 : int64 -> t + +(** Compare timestamps. Returns [1] if the first timestamp is later than the + second one; [0] if they're equal and [-1] othwerwise. *) +val compare : t -> t -> int + +(** Convert a timestamp to RFC3339 notation if possible **) +val to_notation : t -> string option + +(** Convert a timestamp to a string representation of the seconds *) +val to_num_str : t -> string + +(** Convert to RFC3339 notation if possible, or num if not *) +val to_string : t -> string + +val of_string : string -> t option + +(** Returns difference between timestamps as integral number of seconds + in Michelson representation of numbers. *) +val diff : t -> t -> z num + +(** Add a number of seconds to the timestamp. *) +val add_delta : t -> z num -> t + +(** Subtract a number of seconds from the timestamp. *) +val sub_delta : t -> z num -> t + +val to_zint : t -> Z.t + +val of_zint : Z.t -> t diff --git a/src/proto_011_PtHangzH/lib_protocol/script_typed_ir.ml b/src/proto_011_PtHangzH/lib_protocol/script_typed_ir.ml new file mode 100644 index 000000000000..859c02e51adb --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_typed_ir.ml @@ -0,0 +1,2184 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Script_int + +(* Preliminary definitions. *) + +type var_annot = Var_annot of string [@@ocaml.unboxed] + +type type_annot = Type_annot of string [@@ocaml.unboxed] + +type field_annot = Field_annot of string [@@ocaml.unboxed] + +type never = | + +type address = Contract.t * string + +type ('a, 'b) pair = 'a * 'b + +type ('a, 'b) union = L of 'a | R of 'b + +type operation = packed_internal_operation * Lazy_storage.diffs option + +type 'a ticket = {ticketer : address; contents : 'a; amount : n num} + +module type TYPE_SIZE = sig + (* A type size represents the size of its type parameter. + This constraint is enforced inside this module (Script_type_ir), hence there + should be no way to construct a type size outside of it. + + It allows keeping type metadata and types non-private. + + This module is here because we want three levels of visibility over this + code: + - inside this submodule, we have [type 'a t = int] + - outside of [Script_typed_ir], the ['a t] type is abstract and we have + the invariant that whenever [x : 'a t] we have that [x] is exactly + the size of ['a]. + - in-between (inside [Script_typed_ir] but outside the [Type_size] + submodule), the type is abstract but we have access to unsafe + constructors that can break the invariant. + *) + type 'a t + + val merge : 'a t -> 'b t -> 'a t tzresult + + (* Unsafe constructors, to be used only safely and inside this module *) + + val one : _ t + + val two : _ t + + val three : _ t + + val four : (_, _) pair option t + + val compound1 : Script.location -> _ t -> _ t tzresult + + val compound2 : Script.location -> _ t -> _ t -> _ t tzresult +end + +module Type_size : TYPE_SIZE = struct + type 'a t = int + + let one = 1 + + let two = 2 + + let three = 3 + + let four = 4 + + let merge x y = + if Compare.Int.(x = y) then ok x + else error @@ Script_tc_errors.Inconsistent_type_sizes (x, y) + + let of_int loc size = + let max_size = Constants.michelson_maximum_type_size in + if Compare.Int.(size <= max_size) then ok size + else error (Script_tc_errors.Type_too_large (loc, max_size)) + + let compound1 loc size = of_int loc (1 + size) + + let compound2 loc size1 size2 = of_int loc (1 + size1 + size2) +end + +type empty_cell = EmptyCell + +type end_of_stack = empty_cell * empty_cell + +type 'a ty_metadata = {annot : type_annot option; size : 'a Type_size.t} + +type _ comparable_ty = + | Unit_key : unit ty_metadata -> unit comparable_ty + | Never_key : never ty_metadata -> never comparable_ty + | Int_key : z num ty_metadata -> z num comparable_ty + | Nat_key : n num ty_metadata -> n num comparable_ty + | Signature_key : signature ty_metadata -> signature comparable_ty + | String_key : Script_string.t ty_metadata -> Script_string.t comparable_ty + | Bytes_key : Bytes.t ty_metadata -> Bytes.t comparable_ty + | Mutez_key : Tez.t ty_metadata -> Tez.t comparable_ty + | Bool_key : bool ty_metadata -> bool comparable_ty + | Key_hash_key : public_key_hash ty_metadata -> public_key_hash comparable_ty + | Key_key : public_key ty_metadata -> public_key comparable_ty + | Timestamp_key : + Script_timestamp.t ty_metadata + -> Script_timestamp.t comparable_ty + | Chain_id_key : Chain_id.t ty_metadata -> Chain_id.t comparable_ty + | Address_key : address ty_metadata -> address comparable_ty + | Pair_key : + ('a comparable_ty * field_annot option) + * ('b comparable_ty * field_annot option) + * ('a, 'b) pair ty_metadata + -> ('a, 'b) pair comparable_ty + | Union_key : + ('a comparable_ty * field_annot option) + * ('b comparable_ty * field_annot option) + * ('a, 'b) union ty_metadata + -> ('a, 'b) union comparable_ty + | Option_key : + 'v comparable_ty * 'v option ty_metadata + -> 'v option comparable_ty + +let comparable_ty_metadata : type a. a comparable_ty -> a ty_metadata = function + | Unit_key meta -> meta + | Never_key meta -> meta + | Int_key meta -> meta + | Nat_key meta -> meta + | Signature_key meta -> meta + | String_key meta -> meta + | Bytes_key meta -> meta + | Mutez_key meta -> meta + | Bool_key meta -> meta + | Key_hash_key meta -> meta + | Key_key meta -> meta + | Timestamp_key meta -> meta + | Chain_id_key meta -> meta + | Address_key meta -> meta + | Pair_key (_, _, meta) -> meta + | Union_key (_, _, meta) -> meta + | Option_key (_, meta) -> meta + +let comparable_ty_size t = (comparable_ty_metadata t).size + +let unit_key ~annot = Unit_key {annot; size = Type_size.one} + +let never_key ~annot = Never_key {annot; size = Type_size.one} + +let int_key ~annot = Int_key {annot; size = Type_size.one} + +let nat_key ~annot = Nat_key {annot; size = Type_size.one} + +let signature_key ~annot = Signature_key {annot; size = Type_size.one} + +let string_key ~annot = String_key {annot; size = Type_size.one} + +let bytes_key ~annot = Bytes_key {annot; size = Type_size.one} + +let mutez_key ~annot = Mutez_key {annot; size = Type_size.one} + +let bool_key ~annot = Bool_key {annot; size = Type_size.one} + +let key_hash_key ~annot = Key_hash_key {annot; size = Type_size.one} + +let key_key ~annot = Key_key {annot; size = Type_size.one} + +let timestamp_key ~annot = Timestamp_key {annot; size = Type_size.one} + +let chain_id_key ~annot = Chain_id_key {annot; size = Type_size.one} + +let address_key ~annot = Address_key {annot; size = Type_size.one} + +let pair_key loc (l, fannot_l) (r, fannot_r) ~annot = + Type_size.compound2 loc (comparable_ty_size l) (comparable_ty_size r) + >|? fun size -> Pair_key ((l, fannot_l), (r, fannot_r), {annot; size}) + +let pair_3_key loc l m r = + pair_key loc m r ~annot:None >>? fun r -> pair_key loc l (r, None) ~annot:None + +let union_key loc (l, fannot_l) (r, fannot_r) ~annot = + Type_size.compound2 loc (comparable_ty_size l) (comparable_ty_size r) + >|? fun size -> Union_key ((l, fannot_l), (r, fannot_r), {annot; size}) + +let option_key loc t ~annot = + Type_size.compound1 loc (comparable_ty_size t) >|? fun size -> + Option_key (t, {annot; size}) + +(* + + This signature contains the exact set of functions used in the + protocol. We do not include all [Set.S] because this would + increase the size of the first class modules used to represent + [boxed_set]. + + Warning: for any change in this signature, there must be a + change in [Script_typed_ir_size.value_size] which updates + [boxing_space] in the case for sets. + +*) +module type Boxed_set_OPS = sig + type t + + type elt + + val empty : t + + val add : elt -> t -> t + + val mem : elt -> t -> bool + + val remove : elt -> t -> t + + val fold : (elt -> 'a -> 'a) -> t -> 'a -> 'a +end + +module type Boxed_set = sig + type elt + + val elt_ty : elt comparable_ty + + module OPS : Boxed_set_OPS with type elt = elt + + val boxed : OPS.t + + val size : int +end + +type 'elt set = (module Boxed_set with type elt = 'elt) + +(* + + Same remark as for [Boxed_set_OPS]. (See below.) + +*) +module type Boxed_map_OPS = sig + type key + + type value + + type 'a t + + val empty : value t + + val add : key -> value -> value t -> value t + + val remove : key -> value t -> value t + + val find : key -> value t -> value option + + val fold : (key -> value -> 'a -> 'a) -> value t -> 'a -> 'a +end + +module type Boxed_map = sig + type key + + type value + + val key_ty : key comparable_ty + + module OPS : Boxed_map_OPS with type key = key and type value = value + + val boxed : value OPS.t * int +end + +type ('key, 'value) map = + (module Boxed_map with type key = 'key and type value = 'value) + +module Big_map_overlay = Map.Make (struct + type t = Script_expr_hash.t + + let compare = Script_expr_hash.compare +end) + +type ('key, 'value) big_map_overlay = { + map : ('key * 'value option) Big_map_overlay.t; + size : int; +} + +type 'elt boxed_list = {elements : 'elt list; length : int} + +module SMap = Map.Make (Script_string) + +type view = { + input_ty : Script.node; + output_ty : Script.node; + view_code : Script.node; +} + +type ('arg, 'storage) script = { + code : (('arg, 'storage) pair, (operation boxed_list, 'storage) pair) lambda; + arg_type : 'arg ty; + storage : 'storage; + storage_type : 'storage ty; + views : view SMap.t; + root_name : field_annot option; + code_size : Cache_memory_helpers.sint; + (* This is an over-approximation of the value size in memory, in + bytes, of the contract's static part, that is its source + code. This includes the code of the contract as well as the code + of the views. The storage size is not taken into account by this + field as it has a dynamic size. *) +} + +(* ---- Instructions --------------------------------------------------------*) +and ('before_top, 'before, 'result_top, 'result) kinstr = + (* + Stack + ----- + *) + | IDrop : + ('a, 'b * 's) kinfo * ('b, 's, 'r, 'f) kinstr + -> ('a, 'b * 's, 'r, 'f) kinstr + | IDup : + ('a, 's) kinfo * ('a, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ISwap : + ('a, 'b * 's) kinfo * ('b, 'a * 's, 'r, 'f) kinstr + -> ('a, 'b * 's, 'r, 'f) kinstr + | IConst : + ('a, 's) kinfo * 'ty * ('ty, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + (* + Pairs + ----- + *) + | ICons_pair : + ('a, 'b * 's) kinfo * ('a * 'b, 's, 'r, 'f) kinstr + -> ('a, 'b * 's, 'r, 'f) kinstr + | ICar : + ('a * 'b, 's) kinfo * ('a, 's, 'r, 'f) kinstr + -> ('a * 'b, 's, 'r, 'f) kinstr + | ICdr : + ('a * 'b, 's) kinfo * ('b, 's, 'r, 'f) kinstr + -> ('a * 'b, 's, 'r, 'f) kinstr + | IUnpair : + ('a * 'b, 's) kinfo * ('a, 'b * 's, 'r, 'f) kinstr + -> ('a * 'b, 's, 'r, 'f) kinstr + (* + Options + ------- + *) + | ICons_some : + ('v, 's) kinfo * ('v option, 's, 'r, 'f) kinstr + -> ('v, 's, 'r, 'f) kinstr + | ICons_none : + ('a, 's) kinfo * ('b option, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IIf_none : { + kinfo : ('a option, 'b * 's) kinfo; + branch_if_none : ('b, 's, 'c, 't) kinstr; + branch_if_some : ('a, 'b * 's, 'c, 't) kinstr; + k : ('c, 't, 'r, 'f) kinstr; + } + -> ('a option, 'b * 's, 'r, 'f) kinstr + (* + Unions + ------ + *) + | ICons_left : + ('a, 's) kinfo * (('a, 'b) union, 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ICons_right : + ('b, 's) kinfo * (('a, 'b) union, 's, 'r, 'f) kinstr + -> ('b, 's, 'r, 'f) kinstr + | IIf_left : { + kinfo : (('a, 'b) union, 's) kinfo; + branch_if_left : ('a, 's, 'c, 't) kinstr; + branch_if_right : ('b, 's, 'c, 't) kinstr; + k : ('c, 't, 'r, 'f) kinstr; + } + -> (('a, 'b) union, 's, 'r, 'f) kinstr + (* + Lists + ----- + *) + | ICons_list : + ('a, 'a boxed_list * 's) kinfo * ('a boxed_list, 's, 'r, 'f) kinstr + -> ('a, 'a boxed_list * 's, 'r, 'f) kinstr + | INil : + ('a, 's) kinfo * ('b boxed_list, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IIf_cons : { + kinfo : ('a boxed_list, 'b * 's) kinfo; + branch_if_cons : ('a, 'a boxed_list * ('b * 's), 'c, 't) kinstr; + branch_if_nil : ('b, 's, 'c, 't) kinstr; + k : ('c, 't, 'r, 'f) kinstr; + } + -> ('a boxed_list, 'b * 's, 'r, 'f) kinstr + | IList_map : + ('a boxed_list, 'c * 's) kinfo + * ('a, 'c * 's, 'b, 'c * 's) kinstr + * ('b boxed_list, 'c * 's, 'r, 'f) kinstr + -> ('a boxed_list, 'c * 's, 'r, 'f) kinstr + | IList_iter : + ('a boxed_list, 'b * 's) kinfo + * ('a, 'b * 's, 'b, 's) kinstr + * ('b, 's, 'r, 'f) kinstr + -> ('a boxed_list, 'b * 's, 'r, 'f) kinstr + | IList_size : + ('a boxed_list, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> ('a boxed_list, 's, 'r, 'f) kinstr + (* + Sets + ---- + *) + | IEmpty_set : + ('a, 's) kinfo * 'b comparable_ty * ('b set, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ISet_iter : + ('a set, 'b * 's) kinfo + * ('a, 'b * 's, 'b, 's) kinstr + * ('b, 's, 'r, 'f) kinstr + -> ('a set, 'b * 's, 'r, 'f) kinstr + | ISet_mem : + ('a, 'a set * 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> ('a, 'a set * 's, 'r, 'f) kinstr + | ISet_update : + ('a, bool * ('a set * 's)) kinfo * ('a set, 's, 'r, 'f) kinstr + -> ('a, bool * ('a set * 's), 'r, 'f) kinstr + | ISet_size : + ('a set, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> ('a set, 's, 'r, 'f) kinstr + (* + Maps + ---- + *) + | IEmpty_map : + ('a, 's) kinfo * 'b comparable_ty * (('b, 'c) map, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IMap_map : + (('a, 'b) map, 'd * 's) kinfo + * ('a * 'b, 'd * 's, 'c, 'd * 's) kinstr + * (('a, 'c) map, 'd * 's, 'r, 'f) kinstr + -> (('a, 'b) map, 'd * 's, 'r, 'f) kinstr + | IMap_iter : + (('a, 'b) map, 'c * 's) kinfo + * ('a * 'b, 'c * 's, 'c, 's) kinstr + * ('c, 's, 'r, 'f) kinstr + -> (('a, 'b) map, 'c * 's, 'r, 'f) kinstr + | IMap_mem : + ('a, ('a, 'b) map * 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> ('a, ('a, 'b) map * 's, 'r, 'f) kinstr + | IMap_get : + ('a, ('a, 'b) map * 's) kinfo * ('b option, 's, 'r, 'f) kinstr + -> ('a, ('a, 'b) map * 's, 'r, 'f) kinstr + | IMap_update : + ('a, 'b option * (('a, 'b) map * 's)) kinfo + * (('a, 'b) map, 's, 'r, 'f) kinstr + -> ('a, 'b option * (('a, 'b) map * 's), 'r, 'f) kinstr + | IMap_get_and_update : + ('a, 'b option * (('a, 'b) map * 's)) kinfo + * ('b option, ('a, 'b) map * 's, 'r, 'f) kinstr + -> ('a, 'b option * (('a, 'b) map * 's), 'r, 'f) kinstr + | IMap_size : + (('a, 'b) map, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (('a, 'b) map, 's, 'r, 'f) kinstr + (* + Big maps + -------- + *) + | IEmpty_big_map : + ('a, 's) kinfo + * 'b comparable_ty + * 'c ty + * (('b, 'c) big_map, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IBig_map_mem : + ('a, ('a, 'b) big_map * 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> ('a, ('a, 'b) big_map * 's, 'r, 'f) kinstr + | IBig_map_get : + ('a, ('a, 'b) big_map * 's) kinfo * ('b option, 's, 'r, 'f) kinstr + -> ('a, ('a, 'b) big_map * 's, 'r, 'f) kinstr + | IBig_map_update : + ('a, 'b option * (('a, 'b) big_map * 's)) kinfo + * (('a, 'b) big_map, 's, 'r, 'f) kinstr + -> ('a, 'b option * (('a, 'b) big_map * 's), 'r, 'f) kinstr + | IBig_map_get_and_update : + ('a, 'b option * (('a, 'b) big_map * 's)) kinfo + * ('b option, ('a, 'b) big_map * 's, 'r, 'f) kinstr + -> ('a, 'b option * (('a, 'b) big_map * 's), 'r, 'f) kinstr + (* + Strings + ------- + *) + | IConcat_string : + (Script_string.t boxed_list, 's) kinfo + * (Script_string.t, 's, 'r, 'f) kinstr + -> (Script_string.t boxed_list, 's, 'r, 'f) kinstr + | IConcat_string_pair : + (Script_string.t, Script_string.t * 's) kinfo + * (Script_string.t, 's, 'r, 'f) kinstr + -> (Script_string.t, Script_string.t * 's, 'r, 'f) kinstr + | ISlice_string : + (n num, n num * (Script_string.t * 's)) kinfo + * (Script_string.t option, 's, 'r, 'f) kinstr + -> (n num, n num * (Script_string.t * 's), 'r, 'f) kinstr + | IString_size : + (Script_string.t, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (Script_string.t, 's, 'r, 'f) kinstr + (* + Bytes + ----- + *) + | IConcat_bytes : + (bytes boxed_list, 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes boxed_list, 's, 'r, 'f) kinstr + | IConcat_bytes_pair : + (bytes, bytes * 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes, bytes * 's, 'r, 'f) kinstr + | ISlice_bytes : + (n num, n num * (bytes * 's)) kinfo * (bytes option, 's, 'r, 'f) kinstr + -> (n num, n num * (bytes * 's), 'r, 'f) kinstr + | IBytes_size : + (bytes, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + (* + Timestamps + ---------- + *) + | IAdd_seconds_to_timestamp : + (z num, Script_timestamp.t * 's) kinfo + * (Script_timestamp.t, 's, 'r, 'f) kinstr + -> (z num, Script_timestamp.t * 's, 'r, 'f) kinstr + | IAdd_timestamp_to_seconds : + (Script_timestamp.t, z num * 's) kinfo + * (Script_timestamp.t, 's, 'r, 'f) kinstr + -> (Script_timestamp.t, z num * 's, 'r, 'f) kinstr + | ISub_timestamp_seconds : + (Script_timestamp.t, z num * 's) kinfo + * (Script_timestamp.t, 's, 'r, 'f) kinstr + -> (Script_timestamp.t, z num * 's, 'r, 'f) kinstr + | IDiff_timestamps : + (Script_timestamp.t, Script_timestamp.t * 's) kinfo + * (z num, 's, 'r, 'f) kinstr + -> (Script_timestamp.t, Script_timestamp.t * 's, 'r, 'f) kinstr + (* + Tez + --- + *) + | IAdd_tez : + (Tez.t, Tez.t * 's) kinfo * (Tez.t, 's, 'r, 'f) kinstr + -> (Tez.t, Tez.t * 's, 'r, 'f) kinstr + | ISub_tez : + (Tez.t, Tez.t * 's) kinfo * (Tez.t, 's, 'r, 'f) kinstr + -> (Tez.t, Tez.t * 's, 'r, 'f) kinstr + | IMul_teznat : + (Tez.t, n num * 's) kinfo * (Tez.t, 's, 'r, 'f) kinstr + -> (Tez.t, n num * 's, 'r, 'f) kinstr + | IMul_nattez : + (n num, Tez.t * 's) kinfo * (Tez.t, 's, 'r, 'f) kinstr + -> (n num, Tez.t * 's, 'r, 'f) kinstr + | IEdiv_teznat : + (Tez.t, n num * 's) kinfo + * ((Tez.t, Tez.t) pair option, 's, 'r, 'f) kinstr + -> (Tez.t, n num * 's, 'r, 'f) kinstr + | IEdiv_tez : + (Tez.t, Tez.t * 's) kinfo + * ((n num, Tez.t) pair option, 's, 'r, 'f) kinstr + -> (Tez.t, Tez.t * 's, 'r, 'f) kinstr + (* + Booleans + -------- + *) + | IOr : + (bool, bool * 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (bool, bool * 's, 'r, 'f) kinstr + | IAnd : + (bool, bool * 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (bool, bool * 's, 'r, 'f) kinstr + | IXor : + (bool, bool * 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (bool, bool * 's, 'r, 'f) kinstr + | INot : + (bool, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (bool, 's, 'r, 'f) kinstr + (* + Integers + -------- + *) + | IIs_nat : + (z num, 's) kinfo * (n num option, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | INeg_nat : + (n num, 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (n num, 's, 'r, 'f) kinstr + | INeg_int : + (z num, 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | IAbs_int : + (z num, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | IInt_nat : + (n num, 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (n num, 's, 'r, 'f) kinstr + | IAdd_intint : + (z num, z num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (z num, z num * 's, 'r, 'f) kinstr + | IAdd_intnat : + (z num, n num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (z num, n num * 's, 'r, 'f) kinstr + | IAdd_natint : + (n num, z num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (n num, z num * 's, 'r, 'f) kinstr + | IAdd_natnat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | ISub_int : + ('a num, 'b num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> ('a num, 'b num * 's, 'r, 'f) kinstr + | IMul_intint : + (z num, z num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (z num, z num * 's, 'r, 'f) kinstr + | IMul_intnat : + (z num, n num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (z num, n num * 's, 'r, 'f) kinstr + | IMul_natint : + (n num, z num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (n num, z num * 's, 'r, 'f) kinstr + | IMul_natnat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | IEdiv_intint : + (z num, z num * 's) kinfo + * ((z num, n num) pair option, 's, 'r, 'f) kinstr + -> (z num, z num * 's, 'r, 'f) kinstr + | IEdiv_intnat : + (z num, n num * 's) kinfo + * ((z num, n num) pair option, 's, 'r, 'f) kinstr + -> (z num, n num * 's, 'r, 'f) kinstr + | IEdiv_natint : + (n num, z num * 's) kinfo + * ((z num, n num) pair option, 's, 'r, 'f) kinstr + -> (n num, z num * 's, 'r, 'f) kinstr + | IEdiv_natnat : + (n num, n num * 's) kinfo + * ((n num, n num) pair option, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | ILsl_nat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | ILsr_nat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | IOr_nat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | IAnd_nat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | IAnd_int_nat : + (z num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (z num, n num * 's, 'r, 'f) kinstr + | IXor_nat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | INot_nat : + (n num, 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (n num, 's, 'r, 'f) kinstr + | INot_int : + (z num, 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + (* + Control + ------- + *) + | IIf : { + kinfo : (bool, 'a * 's) kinfo; + branch_if_true : ('a, 's, 'b, 'u) kinstr; + branch_if_false : ('a, 's, 'b, 'u) kinstr; + k : ('b, 'u, 'r, 'f) kinstr; + } + -> (bool, 'a * 's, 'r, 'f) kinstr + | ILoop : + (bool, 'a * 's) kinfo + * ('a, 's, bool, 'a * 's) kinstr + * ('a, 's, 'r, 'f) kinstr + -> (bool, 'a * 's, 'r, 'f) kinstr + | ILoop_left : + (('a, 'b) union, 's) kinfo + * ('a, 's, ('a, 'b) union, 's) kinstr + * ('b, 's, 'r, 'f) kinstr + -> (('a, 'b) union, 's, 'r, 'f) kinstr + | IDip : + ('a, 'b * 's) kinfo + * ('b, 's, 'c, 't) kinstr + * ('a, 'c * 't, 'r, 'f) kinstr + -> ('a, 'b * 's, 'r, 'f) kinstr + | IExec : + ('a, ('a, 'b) lambda * 's) kinfo * ('b, 's, 'r, 'f) kinstr + -> ('a, ('a, 'b) lambda * 's, 'r, 'f) kinstr + | IApply : + ('a, ('a * 'b, 'c) lambda * 's) kinfo + * 'a ty + * (('b, 'c) lambda, 's, 'r, 'f) kinstr + -> ('a, ('a * 'b, 'c) lambda * 's, 'r, 'f) kinstr + | ILambda : + ('a, 's) kinfo + * ('b, 'c) lambda + * (('b, 'c) lambda, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IFailwith : + ('a, 's) kinfo * Script.location * 'a ty + -> ('a, 's, 'r, 'f) kinstr + (* + Comparison + ---------- + *) + | ICompare : + ('a, 'a * 's) kinfo * 'a comparable_ty * (z num, 's, 'r, 'f) kinstr + -> ('a, 'a * 's, 'r, 'f) kinstr + (* + Comparators + ----------- + *) + | IEq : + (z num, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | INeq : + (z num, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | ILt : + (z num, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | IGt : + (z num, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | ILe : + (z num, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | IGe : + (z num, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + (* + Protocol + -------- + *) + | IAddress : + ('a typed_contract, 's) kinfo * (address, 's, 'r, 'f) kinstr + -> ('a typed_contract, 's, 'r, 'f) kinstr + | IContract : + (address, 's) kinfo + * 'a ty + * string + * ('a typed_contract option, 's, 'r, 'f) kinstr + -> (address, 's, 'r, 'f) kinstr + | IView : + ('a, address * 's) kinfo + * ('a, 'b) view_signature + * ('b option, 's, 'r, 'f) kinstr + -> ('a, address * 's, 'r, 'f) kinstr + | ITransfer_tokens : + ('a, Tez.t * ('a typed_contract * 's)) kinfo + * (operation, 's, 'r, 'f) kinstr + -> ('a, Tez.t * ('a typed_contract * 's), 'r, 'f) kinstr + | IImplicit_account : + (public_key_hash, 's) kinfo * (unit typed_contract, 's, 'r, 'f) kinstr + -> (public_key_hash, 's, 'r, 'f) kinstr + | ICreate_contract : { + kinfo : (public_key_hash option, Tez.t * ('a * 's)) kinfo; + storage_type : 'a ty; + arg_type : 'b ty; + lambda : ('b * 'a, operation boxed_list * 'a) lambda; + views : view SMap.t; + root_name : field_annot option; + k : (operation, address * 's, 'r, 'f) kinstr; + } + -> (public_key_hash option, Tez.t * ('a * 's), 'r, 'f) kinstr + | ISet_delegate : + (public_key_hash option, 's) kinfo * (operation, 's, 'r, 'f) kinstr + -> (public_key_hash option, 's, 'r, 'f) kinstr + | INow : + ('a, 's) kinfo * (Script_timestamp.t, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IBalance : + ('a, 's) kinfo * (Tez.t, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ILevel : + ('a, 's) kinfo * (n num, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ICheck_signature : + (public_key, signature * (bytes * 's)) kinfo * (bool, 's, 'r, 'f) kinstr + -> (public_key, signature * (bytes * 's), 'r, 'f) kinstr + | IHash_key : + (public_key, 's) kinfo * (public_key_hash, 's, 'r, 'f) kinstr + -> (public_key, 's, 'r, 'f) kinstr + | IPack : + ('a, 's) kinfo * 'a ty * (bytes, 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IUnpack : + (bytes, 's) kinfo * 'a ty * ('a option, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + | IBlake2b : + (bytes, 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + | ISha256 : + (bytes, 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + | ISha512 : + (bytes, 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + | ISource : + ('a, 's) kinfo * (address, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ISender : + ('a, 's) kinfo * (address, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ISelf : + ('a, 's) kinfo + * 'b ty + * string + * ('b typed_contract, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ISelf_address : + ('a, 's) kinfo * (address, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IAmount : + ('a, 's) kinfo * (Tez.t, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ISapling_empty_state : + ('a, 's) kinfo + * Sapling.Memo_size.t + * (Sapling.state, 'a * 's, 'b, 'f) kinstr + -> ('a, 's, 'b, 'f) kinstr + | ISapling_verify_update : + (Sapling.transaction, Sapling.state * 's) kinfo + * ((z num, Sapling.state) pair option, 's, 'r, 'f) kinstr + -> (Sapling.transaction, Sapling.state * 's, 'r, 'f) kinstr + | IDig : + ('a, 's) kinfo + * int + * ('b, 'c * 't, 'c, 't, 'a, 's, 'd, 'u) stack_prefix_preservation_witness + * ('b, 'd * 'u, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IDug : + ('a, 'b * 's) kinfo + * int + * ('c, 't, 'a, 'c * 't, 'b, 's, 'd, 'u) stack_prefix_preservation_witness + * ('d, 'u, 'r, 'f) kinstr + -> ('a, 'b * 's, 'r, 'f) kinstr + | IDipn : + ('a, 's) kinfo + * int + * ('c, 't, 'd, 'v, 'a, 's, 'b, 'u) stack_prefix_preservation_witness + * ('c, 't, 'd, 'v) kinstr + * ('b, 'u, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IDropn : + ('a, 's) kinfo + * int + * ('b, 'u, 'b, 'u, 'a, 's, 'a, 's) stack_prefix_preservation_witness + * ('b, 'u, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IChainId : + ('a, 's) kinfo * (Chain_id.t, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | INever : (never, 's) kinfo -> (never, 's, 'r, 'f) kinstr + | IVoting_power : + (public_key_hash, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (public_key_hash, 's, 'r, 'f) kinstr + | ITotal_voting_power : + ('a, 's) kinfo * (n num, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IKeccak : + (bytes, 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + | ISha3 : + (bytes, 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + | IAdd_bls12_381_g1 : + (Bls12_381.G1.t, Bls12_381.G1.t * 's) kinfo + * (Bls12_381.G1.t, 's, 'r, 'f) kinstr + -> (Bls12_381.G1.t, Bls12_381.G1.t * 's, 'r, 'f) kinstr + | IAdd_bls12_381_g2 : + (Bls12_381.G2.t, Bls12_381.G2.t * 's) kinfo + * (Bls12_381.G2.t, 's, 'r, 'f) kinstr + -> (Bls12_381.G2.t, Bls12_381.G2.t * 's, 'r, 'f) kinstr + | IAdd_bls12_381_fr : + (Bls12_381.Fr.t, Bls12_381.Fr.t * 's) kinfo + * (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + -> (Bls12_381.Fr.t, Bls12_381.Fr.t * 's, 'r, 'f) kinstr + | IMul_bls12_381_g1 : + (Bls12_381.G1.t, Bls12_381.Fr.t * 's) kinfo + * (Bls12_381.G1.t, 's, 'r, 'f) kinstr + -> (Bls12_381.G1.t, Bls12_381.Fr.t * 's, 'r, 'f) kinstr + | IMul_bls12_381_g2 : + (Bls12_381.G2.t, Bls12_381.Fr.t * 's) kinfo + * (Bls12_381.G2.t, 's, 'r, 'f) kinstr + -> (Bls12_381.G2.t, Bls12_381.Fr.t * 's, 'r, 'f) kinstr + | IMul_bls12_381_fr : + (Bls12_381.Fr.t, Bls12_381.Fr.t * 's) kinfo + * (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + -> (Bls12_381.Fr.t, Bls12_381.Fr.t * 's, 'r, 'f) kinstr + | IMul_bls12_381_z_fr : + (Bls12_381.Fr.t, 'a num * 's) kinfo * (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + -> (Bls12_381.Fr.t, 'a num * 's, 'r, 'f) kinstr + | IMul_bls12_381_fr_z : + ('a num, Bls12_381.Fr.t * 's) kinfo * (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + -> ('a num, Bls12_381.Fr.t * 's, 'r, 'f) kinstr + | IInt_bls12_381_fr : + (Bls12_381.Fr.t, 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + | INeg_bls12_381_g1 : + (Bls12_381.G1.t, 's) kinfo * (Bls12_381.G1.t, 's, 'r, 'f) kinstr + -> (Bls12_381.G1.t, 's, 'r, 'f) kinstr + | INeg_bls12_381_g2 : + (Bls12_381.G2.t, 's) kinfo * (Bls12_381.G2.t, 's, 'r, 'f) kinstr + -> (Bls12_381.G2.t, 's, 'r, 'f) kinstr + | INeg_bls12_381_fr : + (Bls12_381.Fr.t, 's) kinfo * (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + -> (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + | IPairing_check_bls12_381 : + ((Bls12_381.G1.t, Bls12_381.G2.t) pair boxed_list, 's) kinfo + * (bool, 's, 'r, 'f) kinstr + -> ((Bls12_381.G1.t, Bls12_381.G2.t) pair boxed_list, 's, 'r, 'f) kinstr + | IComb : + ('a, 's) kinfo + * int + * ('a * 's, 'b * 'u) comb_gadt_witness + * ('b, 'u, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IUncomb : + ('a, 's) kinfo + * int + * ('a * 's, 'b * 'u) uncomb_gadt_witness + * ('b, 'u, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IComb_get : + ('t, 's) kinfo + * int + * ('t, 'v) comb_get_gadt_witness + * ('v, 's, 'r, 'f) kinstr + -> ('t, 's, 'r, 'f) kinstr + | IComb_set : + ('a, 'b * 's) kinfo + * int + * ('a, 'b, 'c) comb_set_gadt_witness + * ('c, 's, 'r, 'f) kinstr + -> ('a, 'b * 's, 'r, 'f) kinstr + | IDup_n : + ('a, 's) kinfo + * int + * ('a * 's, 't) dup_n_gadt_witness + * ('t, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ITicket : + ('a, n num * 's) kinfo * ('a ticket, 's, 'r, 'f) kinstr + -> ('a, n num * 's, 'r, 'f) kinstr + | IRead_ticket : + ('a ticket, 's) kinfo + * (address * ('a * n num), 'a ticket * 's, 'r, 'f) kinstr + -> ('a ticket, 's, 'r, 'f) kinstr + | ISplit_ticket : + ('a ticket, (n num * n num) * 's) kinfo + * (('a ticket * 'a ticket) option, 's, 'r, 'f) kinstr + -> ('a ticket, (n num * n num) * 's, 'r, 'f) kinstr + | IJoin_tickets : + ('a ticket * 'a ticket, 's) kinfo + * 'a comparable_ty + * ('a ticket option, 's, 'r, 'f) kinstr + -> ('a ticket * 'a ticket, 's, 'r, 'f) kinstr + | IOpen_chest : + (Timelock.chest_key, Timelock.chest * (n num * 's)) kinfo + * ((bytes, bool) union, 's, 'r, 'f) kinstr + -> (Timelock.chest_key, Timelock.chest * (n num * 's), 'r, 'f) kinstr + (* + Internal control instructions + ----------------------------- + *) + | IHalt : ('a, 's) kinfo -> ('a, 's, 'a, 's) kinstr + | ILog : + ('a, 's) kinfo * logging_event * logger * ('a, 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + +and logging_event = + | LogEntry : logging_event + | LogExit : ('b, 'u) kinfo -> logging_event + +and ('arg, 'ret) lambda = + | Lam : + ('arg, end_of_stack, 'ret, end_of_stack) kdescr * Script.node + -> ('arg, 'ret) lambda +[@@coq_force_gadt] + +and 'arg typed_contract = 'arg ty * address + +and (_, _, _, _) continuation = + | KNil : ('r, 'f, 'r, 'f) continuation + | KCons : + ('a, 's, 'b, 't) kinstr * ('b, 't, 'r, 'f) continuation + -> ('a, 's, 'r, 'f) continuation + | KReturn : + 's * ('a, 's, 'r, 'f) continuation + -> ('a, end_of_stack, 'r, 'f) continuation + | KUndip : + 'b * ('b, 'a * 's, 'r, 'f) continuation + -> ('a, 's, 'r, 'f) continuation + | KLoop_in : + ('a, 's, bool, 'a * 's) kinstr * ('a, 's, 'r, 'f) continuation + -> (bool, 'a * 's, 'r, 'f) continuation + | KLoop_in_left : + ('a, 's, ('a, 'b) union, 's) kinstr * ('b, 's, 'r, 'f) continuation + -> (('a, 'b) union, 's, 'r, 'f) continuation + | KIter : + ('a, 'b * 's, 'b, 's) kinstr * 'a list * ('b, 's, 'r, 'f) continuation + -> ('b, 's, 'r, 'f) continuation + | KList_enter_body : + ('a, 'c * 's, 'b, 'c * 's) kinstr + * 'a list + * 'b list + * int + * ('b boxed_list, 'c * 's, 'r, 'f) continuation + -> ('c, 's, 'r, 'f) continuation + | KList_exit_body : + ('a, 'c * 's, 'b, 'c * 's) kinstr + * 'a list + * 'b list + * int + * ('b boxed_list, 'c * 's, 'r, 'f) continuation + -> ('b, 'c * 's, 'r, 'f) continuation + | KMap_enter_body : + ('a * 'b, 'd * 's, 'c, 'd * 's) kinstr + * ('a * 'b) list + * ('a, 'c) map + * (('a, 'c) map, 'd * 's, 'r, 'f) continuation + -> ('d, 's, 'r, 'f) continuation + | KMap_exit_body : + ('a * 'b, 'd * 's, 'c, 'd * 's) kinstr + * ('a * 'b) list + * ('a, 'c) map + * 'a + * (('a, 'c) map, 'd * 's, 'r, 'f) continuation + -> ('c, 'd * 's, 'r, 'f) continuation + | KLog : + ('a, 's, 'r, 'f) continuation * logger + -> ('a, 's, 'r, 'f) continuation + +and ('a, 's, 'b, 'f, 'c, 'u) logging_function = + ('a, 's, 'b, 'f) kinstr -> + context -> + Script.location -> + ('c, 'u) stack_ty -> + 'c * 'u -> + unit + +and execution_trace = + (Script.location * Gas.t * (Script.expr * string option) list) list + +and logger = { + log_interp : 'a 's 'b 'f 'c 'u. ('a, 's, 'b, 'f, 'c, 'u) logging_function; + log_entry : 'a 's 'b 'f. ('a, 's, 'b, 'f, 'a, 's) logging_function; + log_control : 'a 's 'b 'f. ('a, 's, 'b, 'f) continuation -> unit; + log_exit : 'a 's 'b 'f 'c 'u. ('a, 's, 'b, 'f, 'c, 'u) logging_function; + get_log : unit -> execution_trace option tzresult Lwt.t; +} + +(* ---- Auxiliary types -----------------------------------------------------*) +and 'ty ty = + | Unit_t : unit ty_metadata -> unit ty + | Int_t : z num ty_metadata -> z num ty + | Nat_t : n num ty_metadata -> n num ty + | Signature_t : signature ty_metadata -> signature ty + | String_t : Script_string.t ty_metadata -> Script_string.t ty + | Bytes_t : Bytes.t ty_metadata -> bytes ty + | Mutez_t : Tez.t ty_metadata -> Tez.t ty + | Key_hash_t : public_key_hash ty_metadata -> public_key_hash ty + | Key_t : public_key ty_metadata -> public_key ty + | Timestamp_t : Script_timestamp.t ty_metadata -> Script_timestamp.t ty + | Address_t : address ty_metadata -> address ty + | Bool_t : bool ty_metadata -> bool ty + | Pair_t : + ('a ty * field_annot option * var_annot option) + * ('b ty * field_annot option * var_annot option) + * ('a, 'b) pair ty_metadata + -> ('a, 'b) pair ty + | Union_t : + ('a ty * field_annot option) + * ('b ty * field_annot option) + * ('a, 'b) union ty_metadata + -> ('a, 'b) union ty + | Lambda_t : + 'arg ty * 'ret ty * ('arg, 'ret) lambda ty_metadata + -> ('arg, 'ret) lambda ty + | Option_t : 'v ty * 'v option ty_metadata -> 'v option ty + | List_t : 'v ty * 'v boxed_list ty_metadata -> 'v boxed_list ty + | Set_t : 'v comparable_ty * 'v set ty_metadata -> 'v set ty + | Map_t : + 'k comparable_ty * 'v ty * ('k, 'v) map ty_metadata + -> ('k, 'v) map ty + | Big_map_t : + 'k comparable_ty * 'v ty * ('k, 'v) big_map ty_metadata + -> ('k, 'v) big_map ty + | Contract_t : + 'arg ty * 'arg typed_contract ty_metadata + -> 'arg typed_contract ty + | Sapling_transaction_t : + Sapling.Memo_size.t * Sapling.transaction ty_metadata + -> Sapling.transaction ty + | Sapling_state_t : + Sapling.Memo_size.t * Sapling.state ty_metadata + -> Sapling.state ty + | Operation_t : operation ty_metadata -> operation ty + | Chain_id_t : Chain_id.t ty_metadata -> Chain_id.t ty + | Never_t : never ty_metadata -> never ty + | Bls12_381_g1_t : Bls12_381.G1.t ty_metadata -> Bls12_381.G1.t ty + | Bls12_381_g2_t : Bls12_381.G2.t ty_metadata -> Bls12_381.G2.t ty + | Bls12_381_fr_t : Bls12_381.Fr.t ty_metadata -> Bls12_381.Fr.t ty + | Ticket_t : 'a comparable_ty * 'a ticket ty_metadata -> 'a ticket ty + | Chest_key_t : Timelock.chest_key ty_metadata -> Timelock.chest_key ty + | Chest_t : Timelock.chest ty_metadata -> Timelock.chest ty + +and ('top_ty, 'resty) stack_ty = + | Item_t : + 'ty ty * ('ty2, 'rest) stack_ty * var_annot option + -> ('ty, 'ty2 * 'rest) stack_ty + | Bot_t : (empty_cell, empty_cell) stack_ty + +and ('key, 'value) big_map = { + id : Big_map.Id.t option; + diff : ('key, 'value) big_map_overlay; + key_type : 'key comparable_ty; + value_type : 'value ty; +} + +and ('a, 's, 'r, 'f) kdescr = { + kloc : Script.location; + kbef : ('a, 's) stack_ty; + kaft : ('r, 'f) stack_ty; + kinstr : ('a, 's, 'r, 'f) kinstr; +} + +and ('a, 's) kinfo = {iloc : Script.location; kstack_ty : ('a, 's) stack_ty} + +and (_, _, _, _, _, _, _, _) stack_prefix_preservation_witness = + | KPrefix : + ('y, 'u) kinfo + * ('c, 'v, 'd, 'w, 'x, 's, 'y, 'u) stack_prefix_preservation_witness + -> ( 'c, + 'v, + 'd, + 'w, + 'a, + 'x * 's, + 'a, + 'y * 'u ) + stack_prefix_preservation_witness + | KRest : ('a, 's, 'b, 'u, 'a, 's, 'b, 'u) stack_prefix_preservation_witness + +and ('before, 'after) comb_gadt_witness = + | Comb_one : ('a * ('x * 'before), 'a * ('x * 'before)) comb_gadt_witness + | Comb_succ : + ('before, 'b * 'after) comb_gadt_witness + -> ('a * 'before, ('a * 'b) * 'after) comb_gadt_witness + +and ('before, 'after) uncomb_gadt_witness = + | Uncomb_one : ('rest, 'rest) uncomb_gadt_witness + | Uncomb_succ : + ('b * 'before, 'after) uncomb_gadt_witness + -> (('a * 'b) * 'before, 'a * 'after) uncomb_gadt_witness + +and ('before, 'after) comb_get_gadt_witness = + | Comb_get_zero : ('b, 'b) comb_get_gadt_witness + | Comb_get_one : ('a * 'b, 'a) comb_get_gadt_witness + | Comb_get_plus_two : + ('before, 'after) comb_get_gadt_witness + -> ('a * 'before, 'after) comb_get_gadt_witness + +and ('value, 'before, 'after) comb_set_gadt_witness = + | Comb_set_zero : ('value, _, 'value) comb_set_gadt_witness + | Comb_set_one : ('value, 'hd * 'tl, 'value * 'tl) comb_set_gadt_witness + | Comb_set_plus_two : + ('value, 'before, 'after) comb_set_gadt_witness + -> ('value, 'a * 'before, 'a * 'after) comb_set_gadt_witness +[@@coq_force_gadt] + +and (_, _) dup_n_gadt_witness = + | Dup_n_zero : ('a * 'rest, 'a) dup_n_gadt_witness + | Dup_n_succ : + ('stack, 'b) dup_n_gadt_witness + -> ('a * 'stack, 'b) dup_n_gadt_witness + +and ('a, 'b) view_signature = + | View_signature of { + name : Script_string.t; + input_ty : 'a ty; + output_ty : 'b ty; + } + +let kinfo_of_kinstr : type a s b f. (a, s, b, f) kinstr -> (a, s) kinfo = + fun i -> + match i with + | IDrop (kinfo, _) -> kinfo + | IDup (kinfo, _) -> kinfo + | ISwap (kinfo, _) -> kinfo + | IConst (kinfo, _, _) -> kinfo + | ICons_pair (kinfo, _) -> kinfo + | ICar (kinfo, _) -> kinfo + | ICdr (kinfo, _) -> kinfo + | IUnpair (kinfo, _) -> kinfo + | ICons_some (kinfo, _) -> kinfo + | ICons_none (kinfo, _) -> kinfo + | IIf_none {kinfo; _} -> kinfo + | ICons_left (kinfo, _) -> kinfo + | ICons_right (kinfo, _) -> kinfo + | IIf_left {kinfo; _} -> kinfo + | ICons_list (kinfo, _) -> kinfo + | INil (kinfo, _) -> kinfo + | IIf_cons {kinfo; _} -> kinfo + | IList_map (kinfo, _, _) -> kinfo + | IList_iter (kinfo, _, _) -> kinfo + | IList_size (kinfo, _) -> kinfo + | IEmpty_set (kinfo, _, _) -> kinfo + | ISet_iter (kinfo, _, _) -> kinfo + | ISet_mem (kinfo, _) -> kinfo + | ISet_update (kinfo, _) -> kinfo + | ISet_size (kinfo, _) -> kinfo + | IEmpty_map (kinfo, _, _) -> kinfo + | IMap_map (kinfo, _, _) -> kinfo + | IMap_iter (kinfo, _, _) -> kinfo + | IMap_mem (kinfo, _) -> kinfo + | IMap_get (kinfo, _) -> kinfo + | IMap_update (kinfo, _) -> kinfo + | IMap_get_and_update (kinfo, _) -> kinfo + | IMap_size (kinfo, _) -> kinfo + | IEmpty_big_map (kinfo, _, _, _) -> kinfo + | IBig_map_mem (kinfo, _) -> kinfo + | IBig_map_get (kinfo, _) -> kinfo + | IBig_map_update (kinfo, _) -> kinfo + | IBig_map_get_and_update (kinfo, _) -> kinfo + | IConcat_string (kinfo, _) -> kinfo + | IConcat_string_pair (kinfo, _) -> kinfo + | ISlice_string (kinfo, _) -> kinfo + | IString_size (kinfo, _) -> kinfo + | IConcat_bytes (kinfo, _) -> kinfo + | IConcat_bytes_pair (kinfo, _) -> kinfo + | ISlice_bytes (kinfo, _) -> kinfo + | IBytes_size (kinfo, _) -> kinfo + | IAdd_seconds_to_timestamp (kinfo, _) -> kinfo + | IAdd_timestamp_to_seconds (kinfo, _) -> kinfo + | ISub_timestamp_seconds (kinfo, _) -> kinfo + | IDiff_timestamps (kinfo, _) -> kinfo + | IAdd_tez (kinfo, _) -> kinfo + | ISub_tez (kinfo, _) -> kinfo + | IMul_teznat (kinfo, _) -> kinfo + | IMul_nattez (kinfo, _) -> kinfo + | IEdiv_teznat (kinfo, _) -> kinfo + | IEdiv_tez (kinfo, _) -> kinfo + | IOr (kinfo, _) -> kinfo + | IAnd (kinfo, _) -> kinfo + | IXor (kinfo, _) -> kinfo + | INot (kinfo, _) -> kinfo + | IIs_nat (kinfo, _) -> kinfo + | INeg_nat (kinfo, _) -> kinfo + | INeg_int (kinfo, _) -> kinfo + | IAbs_int (kinfo, _) -> kinfo + | IInt_nat (kinfo, _) -> kinfo + | IAdd_intint (kinfo, _) -> kinfo + | IAdd_intnat (kinfo, _) -> kinfo + | IAdd_natint (kinfo, _) -> kinfo + | IAdd_natnat (kinfo, _) -> kinfo + | ISub_int (kinfo, _) -> kinfo + | IMul_intint (kinfo, _) -> kinfo + | IMul_intnat (kinfo, _) -> kinfo + | IMul_natint (kinfo, _) -> kinfo + | IMul_natnat (kinfo, _) -> kinfo + | IEdiv_intint (kinfo, _) -> kinfo + | IEdiv_intnat (kinfo, _) -> kinfo + | IEdiv_natint (kinfo, _) -> kinfo + | IEdiv_natnat (kinfo, _) -> kinfo + | ILsl_nat (kinfo, _) -> kinfo + | ILsr_nat (kinfo, _) -> kinfo + | IOr_nat (kinfo, _) -> kinfo + | IAnd_nat (kinfo, _) -> kinfo + | IAnd_int_nat (kinfo, _) -> kinfo + | IXor_nat (kinfo, _) -> kinfo + | INot_nat (kinfo, _) -> kinfo + | INot_int (kinfo, _) -> kinfo + | IIf {kinfo; _} -> kinfo + | ILoop (kinfo, _, _) -> kinfo + | ILoop_left (kinfo, _, _) -> kinfo + | IDip (kinfo, _, _) -> kinfo + | IExec (kinfo, _) -> kinfo + | IApply (kinfo, _, _) -> kinfo + | ILambda (kinfo, _, _) -> kinfo + | IFailwith (kinfo, _, _) -> kinfo + | ICompare (kinfo, _, _) -> kinfo + | IEq (kinfo, _) -> kinfo + | INeq (kinfo, _) -> kinfo + | ILt (kinfo, _) -> kinfo + | IGt (kinfo, _) -> kinfo + | ILe (kinfo, _) -> kinfo + | IGe (kinfo, _) -> kinfo + | IAddress (kinfo, _) -> kinfo + | IContract (kinfo, _, _, _) -> kinfo + | ITransfer_tokens (kinfo, _) -> kinfo + | IView (kinfo, _, _) -> kinfo + | IImplicit_account (kinfo, _) -> kinfo + | ICreate_contract {kinfo; _} -> kinfo + | ISet_delegate (kinfo, _) -> kinfo + | INow (kinfo, _) -> kinfo + | IBalance (kinfo, _) -> kinfo + | ILevel (kinfo, _) -> kinfo + | ICheck_signature (kinfo, _) -> kinfo + | IHash_key (kinfo, _) -> kinfo + | IPack (kinfo, _, _) -> kinfo + | IUnpack (kinfo, _, _) -> kinfo + | IBlake2b (kinfo, _) -> kinfo + | ISha256 (kinfo, _) -> kinfo + | ISha512 (kinfo, _) -> kinfo + | ISource (kinfo, _) -> kinfo + | ISender (kinfo, _) -> kinfo + | ISelf (kinfo, _, _, _) -> kinfo + | ISelf_address (kinfo, _) -> kinfo + | IAmount (kinfo, _) -> kinfo + | ISapling_empty_state (kinfo, _, _) -> kinfo + | ISapling_verify_update (kinfo, _) -> kinfo + | IDig (kinfo, _, _, _) -> kinfo + | IDug (kinfo, _, _, _) -> kinfo + | IDipn (kinfo, _, _, _, _) -> kinfo + | IDropn (kinfo, _, _, _) -> kinfo + | IChainId (kinfo, _) -> kinfo + | INever kinfo -> kinfo + | IVoting_power (kinfo, _) -> kinfo + | ITotal_voting_power (kinfo, _) -> kinfo + | IKeccak (kinfo, _) -> kinfo + | ISha3 (kinfo, _) -> kinfo + | IAdd_bls12_381_g1 (kinfo, _) -> kinfo + | IAdd_bls12_381_g2 (kinfo, _) -> kinfo + | IAdd_bls12_381_fr (kinfo, _) -> kinfo + | IMul_bls12_381_g1 (kinfo, _) -> kinfo + | IMul_bls12_381_g2 (kinfo, _) -> kinfo + | IMul_bls12_381_fr (kinfo, _) -> kinfo + | IMul_bls12_381_z_fr (kinfo, _) -> kinfo + | IMul_bls12_381_fr_z (kinfo, _) -> kinfo + | IInt_bls12_381_fr (kinfo, _) -> kinfo + | INeg_bls12_381_g1 (kinfo, _) -> kinfo + | INeg_bls12_381_g2 (kinfo, _) -> kinfo + | INeg_bls12_381_fr (kinfo, _) -> kinfo + | IPairing_check_bls12_381 (kinfo, _) -> kinfo + | IComb (kinfo, _, _, _) -> kinfo + | IUncomb (kinfo, _, _, _) -> kinfo + | IComb_get (kinfo, _, _, _) -> kinfo + | IComb_set (kinfo, _, _, _) -> kinfo + | IDup_n (kinfo, _, _, _) -> kinfo + | ITicket (kinfo, _) -> kinfo + | IRead_ticket (kinfo, _) -> kinfo + | ISplit_ticket (kinfo, _) -> kinfo + | IJoin_tickets (kinfo, _, _) -> kinfo + | IHalt kinfo -> kinfo + | ILog (kinfo, _, _, _) -> kinfo + | IOpen_chest (kinfo, _) -> kinfo + +type kinstr_rewritek = { + apply : 'b 'u 'r 'f. ('b, 'u, 'r, 'f) kinstr -> ('b, 'u, 'r, 'f) kinstr; +} + +let kinstr_rewritek : + type a s r f. (a, s, r, f) kinstr -> kinstr_rewritek -> (a, s, r, f) kinstr + = + fun i f -> + match i with + | IDrop (kinfo, k) -> IDrop (kinfo, f.apply k) + | IDup (kinfo, k) -> IDup (kinfo, f.apply k) + | ISwap (kinfo, k) -> ISwap (kinfo, f.apply k) + | IConst (kinfo, x, k) -> IConst (kinfo, x, f.apply k) + | ICons_pair (kinfo, k) -> ICons_pair (kinfo, f.apply k) + | ICar (kinfo, k) -> ICar (kinfo, f.apply k) + | ICdr (kinfo, k) -> ICdr (kinfo, f.apply k) + | IUnpair (kinfo, k) -> IUnpair (kinfo, f.apply k) + | ICons_some (kinfo, k) -> ICons_some (kinfo, f.apply k) + | ICons_none (kinfo, k) -> ICons_none (kinfo, f.apply k) + | IIf_none {kinfo; branch_if_none; branch_if_some; k} -> + IIf_none + { + kinfo; + branch_if_none = f.apply branch_if_none; + branch_if_some = f.apply branch_if_some; + k = f.apply k; + } + | ICons_left (kinfo, k) -> ICons_left (kinfo, f.apply k) + | ICons_right (kinfo, k) -> ICons_right (kinfo, f.apply k) + | IIf_left {kinfo; branch_if_left; branch_if_right; k} -> + IIf_left + { + kinfo; + branch_if_left = f.apply branch_if_left; + branch_if_right = f.apply branch_if_right; + k = f.apply k; + } + | ICons_list (kinfo, k) -> ICons_list (kinfo, f.apply k) + | INil (kinfo, k) -> INil (kinfo, f.apply k) + | IIf_cons {kinfo; branch_if_cons; branch_if_nil; k} -> + IIf_cons + { + kinfo; + branch_if_cons = f.apply branch_if_cons; + branch_if_nil = f.apply branch_if_nil; + k = f.apply k; + } + | IList_map (kinfo, body, k) -> IList_map (kinfo, f.apply body, f.apply k) + | IList_iter (kinfo, body, k) -> IList_iter (kinfo, f.apply body, f.apply k) + | IList_size (kinfo, k) -> IList_size (kinfo, f.apply k) + | IEmpty_set (kinfo, ty, k) -> IEmpty_set (kinfo, ty, f.apply k) + | ISet_iter (kinfo, body, k) -> ISet_iter (kinfo, f.apply body, f.apply k) + | ISet_mem (kinfo, k) -> ISet_mem (kinfo, f.apply k) + | ISet_update (kinfo, k) -> ISet_update (kinfo, f.apply k) + | ISet_size (kinfo, k) -> ISet_size (kinfo, f.apply k) + | IEmpty_map (kinfo, cty, k) -> IEmpty_map (kinfo, cty, f.apply k) + | IMap_map (kinfo, body, k) -> IMap_map (kinfo, f.apply body, f.apply k) + | IMap_iter (kinfo, body, k) -> IMap_iter (kinfo, f.apply body, f.apply k) + | IMap_mem (kinfo, k) -> IMap_mem (kinfo, f.apply k) + | IMap_get (kinfo, k) -> IMap_get (kinfo, f.apply k) + | IMap_update (kinfo, k) -> IMap_update (kinfo, f.apply k) + | IMap_get_and_update (kinfo, k) -> IMap_get_and_update (kinfo, f.apply k) + | IMap_size (kinfo, k) -> IMap_size (kinfo, f.apply k) + | IEmpty_big_map (kinfo, cty, ty, k) -> + IEmpty_big_map (kinfo, cty, ty, f.apply k) + | IBig_map_mem (kinfo, k) -> IBig_map_mem (kinfo, f.apply k) + | IBig_map_get (kinfo, k) -> IBig_map_get (kinfo, f.apply k) + | IBig_map_update (kinfo, k) -> IBig_map_update (kinfo, f.apply k) + | IBig_map_get_and_update (kinfo, k) -> + IBig_map_get_and_update (kinfo, f.apply k) + | IConcat_string (kinfo, k) -> IConcat_string (kinfo, f.apply k) + | IConcat_string_pair (kinfo, k) -> IConcat_string_pair (kinfo, f.apply k) + | ISlice_string (kinfo, k) -> ISlice_string (kinfo, f.apply k) + | IString_size (kinfo, k) -> IString_size (kinfo, f.apply k) + | IConcat_bytes (kinfo, k) -> IConcat_bytes (kinfo, f.apply k) + | IConcat_bytes_pair (kinfo, k) -> IConcat_bytes_pair (kinfo, f.apply k) + | ISlice_bytes (kinfo, k) -> ISlice_bytes (kinfo, f.apply k) + | IBytes_size (kinfo, k) -> IBytes_size (kinfo, f.apply k) + | IAdd_seconds_to_timestamp (kinfo, k) -> + IAdd_seconds_to_timestamp (kinfo, f.apply k) + | IAdd_timestamp_to_seconds (kinfo, k) -> + IAdd_timestamp_to_seconds (kinfo, f.apply k) + | ISub_timestamp_seconds (kinfo, k) -> + ISub_timestamp_seconds (kinfo, f.apply k) + | IDiff_timestamps (kinfo, k) -> IDiff_timestamps (kinfo, f.apply k) + | IAdd_tez (kinfo, k) -> IAdd_tez (kinfo, f.apply k) + | ISub_tez (kinfo, k) -> ISub_tez (kinfo, f.apply k) + | IMul_teznat (kinfo, k) -> IMul_teznat (kinfo, f.apply k) + | IMul_nattez (kinfo, k) -> IMul_nattez (kinfo, f.apply k) + | IEdiv_teznat (kinfo, k) -> IEdiv_teznat (kinfo, f.apply k) + | IEdiv_tez (kinfo, k) -> IEdiv_tez (kinfo, f.apply k) + | IOr (kinfo, k) -> IOr (kinfo, f.apply k) + | IAnd (kinfo, k) -> IAnd (kinfo, f.apply k) + | IXor (kinfo, k) -> IXor (kinfo, f.apply k) + | INot (kinfo, k) -> INot (kinfo, f.apply k) + | IIs_nat (kinfo, k) -> IIs_nat (kinfo, f.apply k) + | INeg_nat (kinfo, k) -> INeg_nat (kinfo, f.apply k) + | INeg_int (kinfo, k) -> INeg_int (kinfo, f.apply k) + | IAbs_int (kinfo, k) -> IAbs_int (kinfo, f.apply k) + | IInt_nat (kinfo, k) -> IInt_nat (kinfo, f.apply k) + | IAdd_intint (kinfo, k) -> IAdd_intint (kinfo, f.apply k) + | IAdd_intnat (kinfo, k) -> IAdd_intnat (kinfo, f.apply k) + | IAdd_natint (kinfo, k) -> IAdd_natint (kinfo, f.apply k) + | IAdd_natnat (kinfo, k) -> IAdd_natnat (kinfo, f.apply k) + | ISub_int (kinfo, k) -> ISub_int (kinfo, f.apply k) + | IMul_intint (kinfo, k) -> IMul_intint (kinfo, f.apply k) + | IMul_intnat (kinfo, k) -> IMul_intnat (kinfo, f.apply k) + | IMul_natint (kinfo, k) -> IMul_natint (kinfo, f.apply k) + | IMul_natnat (kinfo, k) -> IMul_natnat (kinfo, f.apply k) + | IEdiv_intint (kinfo, k) -> IEdiv_intint (kinfo, f.apply k) + | IEdiv_intnat (kinfo, k) -> IEdiv_intnat (kinfo, f.apply k) + | IEdiv_natint (kinfo, k) -> IEdiv_natint (kinfo, f.apply k) + | IEdiv_natnat (kinfo, k) -> IEdiv_natnat (kinfo, f.apply k) + | ILsl_nat (kinfo, k) -> ILsl_nat (kinfo, f.apply k) + | ILsr_nat (kinfo, k) -> ILsr_nat (kinfo, f.apply k) + | IOr_nat (kinfo, k) -> IOr_nat (kinfo, f.apply k) + | IAnd_nat (kinfo, k) -> IAnd_nat (kinfo, f.apply k) + | IAnd_int_nat (kinfo, k) -> IAnd_int_nat (kinfo, f.apply k) + | IXor_nat (kinfo, k) -> IXor_nat (kinfo, f.apply k) + | INot_nat (kinfo, k) -> INot_nat (kinfo, f.apply k) + | INot_int (kinfo, k) -> INot_int (kinfo, f.apply k) + | IIf {kinfo; branch_if_true; branch_if_false; k} -> + IIf + { + kinfo; + branch_if_true = f.apply branch_if_true; + branch_if_false = f.apply branch_if_false; + k = f.apply k; + } + | ILoop (kinfo, kbody, k) -> ILoop (kinfo, f.apply kbody, f.apply k) + | ILoop_left (kinfo, kl, kr) -> ILoop_left (kinfo, f.apply kl, f.apply kr) + | IDip (kinfo, body, k) -> IDip (kinfo, f.apply body, f.apply k) + | IExec (kinfo, k) -> IExec (kinfo, f.apply k) + | IApply (kinfo, ty, k) -> IApply (kinfo, ty, f.apply k) + | ILambda (kinfo, l, k) -> ILambda (kinfo, l, f.apply k) + | IFailwith (kinfo, i, ty) -> IFailwith (kinfo, i, ty) + | ICompare (kinfo, ty, k) -> ICompare (kinfo, ty, f.apply k) + | IEq (kinfo, k) -> IEq (kinfo, f.apply k) + | INeq (kinfo, k) -> INeq (kinfo, f.apply k) + | ILt (kinfo, k) -> ILt (kinfo, f.apply k) + | IGt (kinfo, k) -> IGt (kinfo, f.apply k) + | ILe (kinfo, k) -> ILe (kinfo, f.apply k) + | IGe (kinfo, k) -> IGe (kinfo, f.apply k) + | IAddress (kinfo, k) -> IAddress (kinfo, f.apply k) + | IContract (kinfo, ty, code, k) -> IContract (kinfo, ty, code, f.apply k) + | ITransfer_tokens (kinfo, k) -> ITransfer_tokens (kinfo, f.apply k) + | IView (kinfo, view_signature, k) -> IView (kinfo, view_signature, f.apply k) + | IImplicit_account (kinfo, k) -> IImplicit_account (kinfo, f.apply k) + | ICreate_contract + {kinfo; storage_type; arg_type; lambda; views; root_name; k} -> + let k = f.apply k in + ICreate_contract + {kinfo; storage_type; arg_type; lambda; views; root_name; k} + | ISet_delegate (kinfo, k) -> ISet_delegate (kinfo, f.apply k) + | INow (kinfo, k) -> INow (kinfo, f.apply k) + | IBalance (kinfo, k) -> IBalance (kinfo, f.apply k) + | ILevel (kinfo, k) -> ILevel (kinfo, f.apply k) + | ICheck_signature (kinfo, k) -> ICheck_signature (kinfo, f.apply k) + | IHash_key (kinfo, k) -> IHash_key (kinfo, f.apply k) + | IPack (kinfo, ty, k) -> IPack (kinfo, ty, f.apply k) + | IUnpack (kinfo, ty, k) -> IUnpack (kinfo, ty, f.apply k) + | IBlake2b (kinfo, k) -> IBlake2b (kinfo, f.apply k) + | ISha256 (kinfo, k) -> ISha256 (kinfo, f.apply k) + | ISha512 (kinfo, k) -> ISha512 (kinfo, f.apply k) + | ISource (kinfo, k) -> ISource (kinfo, f.apply k) + | ISender (kinfo, k) -> ISender (kinfo, f.apply k) + | ISelf (kinfo, ty, s, k) -> ISelf (kinfo, ty, s, f.apply k) + | ISelf_address (kinfo, k) -> ISelf_address (kinfo, f.apply k) + | IAmount (kinfo, k) -> IAmount (kinfo, f.apply k) + | ISapling_empty_state (kinfo, s, k) -> + ISapling_empty_state (kinfo, s, f.apply k) + | ISapling_verify_update (kinfo, k) -> + ISapling_verify_update (kinfo, f.apply k) + | IDig (kinfo, n, p, k) -> IDig (kinfo, n, p, f.apply k) + | IDug (kinfo, n, p, k) -> IDug (kinfo, n, p, f.apply k) + | IDipn (kinfo, n, p, k1, k2) -> IDipn (kinfo, n, p, f.apply k1, f.apply k2) + | IDropn (kinfo, n, p, k) -> IDropn (kinfo, n, p, f.apply k) + | IChainId (kinfo, k) -> IChainId (kinfo, f.apply k) + | INever kinfo -> INever kinfo + | IVoting_power (kinfo, k) -> IVoting_power (kinfo, f.apply k) + | ITotal_voting_power (kinfo, k) -> ITotal_voting_power (kinfo, f.apply k) + | IKeccak (kinfo, k) -> IKeccak (kinfo, f.apply k) + | ISha3 (kinfo, k) -> ISha3 (kinfo, f.apply k) + | IAdd_bls12_381_g1 (kinfo, k) -> IAdd_bls12_381_g1 (kinfo, f.apply k) + | IAdd_bls12_381_g2 (kinfo, k) -> IAdd_bls12_381_g2 (kinfo, f.apply k) + | IAdd_bls12_381_fr (kinfo, k) -> IAdd_bls12_381_fr (kinfo, f.apply k) + | IMul_bls12_381_g1 (kinfo, k) -> IMul_bls12_381_g1 (kinfo, f.apply k) + | IMul_bls12_381_g2 (kinfo, k) -> IMul_bls12_381_g2 (kinfo, f.apply k) + | IMul_bls12_381_fr (kinfo, k) -> IMul_bls12_381_fr (kinfo, f.apply k) + | IMul_bls12_381_z_fr (kinfo, k) -> IMul_bls12_381_z_fr (kinfo, f.apply k) + | IMul_bls12_381_fr_z (kinfo, k) -> IMul_bls12_381_fr_z (kinfo, f.apply k) + | IInt_bls12_381_fr (kinfo, k) -> IInt_bls12_381_fr (kinfo, f.apply k) + | INeg_bls12_381_g1 (kinfo, k) -> INeg_bls12_381_g1 (kinfo, f.apply k) + | INeg_bls12_381_g2 (kinfo, k) -> INeg_bls12_381_g2 (kinfo, f.apply k) + | INeg_bls12_381_fr (kinfo, k) -> INeg_bls12_381_fr (kinfo, f.apply k) + | IPairing_check_bls12_381 (kinfo, k) -> + IPairing_check_bls12_381 (kinfo, f.apply k) + | IComb (kinfo, n, p, k) -> IComb (kinfo, n, p, f.apply k) + | IUncomb (kinfo, n, p, k) -> IUncomb (kinfo, n, p, f.apply k) + | IComb_get (kinfo, n, p, k) -> IComb_get (kinfo, n, p, f.apply k) + | IComb_set (kinfo, n, p, k) -> IComb_set (kinfo, n, p, f.apply k) + | IDup_n (kinfo, n, p, k) -> IDup_n (kinfo, n, p, f.apply k) + | ITicket (kinfo, k) -> ITicket (kinfo, f.apply k) + | IRead_ticket (kinfo, k) -> IRead_ticket (kinfo, f.apply k) + | ISplit_ticket (kinfo, k) -> ISplit_ticket (kinfo, f.apply k) + | IJoin_tickets (kinfo, ty, k) -> IJoin_tickets (kinfo, ty, f.apply k) + | IHalt kinfo -> IHalt kinfo + | ILog (kinfo, event, logger, k) -> ILog (kinfo, event, logger, k) + | IOpen_chest (kinfo, k) -> IOpen_chest (kinfo, f.apply k) + +let ty_metadata : type a. a ty -> a ty_metadata = function + | Unit_t meta -> meta + | Never_t meta -> meta + | Int_t meta -> meta + | Nat_t meta -> meta + | Signature_t meta -> meta + | String_t meta -> meta + | Bytes_t meta -> meta + | Mutez_t meta -> meta + | Bool_t meta -> meta + | Key_hash_t meta -> meta + | Key_t meta -> meta + | Timestamp_t meta -> meta + | Chain_id_t meta -> meta + | Address_t meta -> meta + | Pair_t (_, _, meta) -> meta + | Union_t (_, _, meta) -> meta + | Option_t (_, meta) -> meta + | Lambda_t (_, _, meta) -> meta + | List_t (_, meta) -> meta + | Set_t (_, meta) -> meta + | Map_t (_, _, meta) -> meta + | Big_map_t (_, _, meta) -> meta + | Ticket_t (_, meta) -> meta + | Contract_t (_, meta) -> meta + | Sapling_transaction_t (_, meta) -> meta + | Sapling_state_t (_, meta) -> meta + | Operation_t meta -> meta + | Bls12_381_g1_t meta -> meta + | Bls12_381_g2_t meta -> meta + | Bls12_381_fr_t meta -> meta + | Chest_t meta -> meta + | Chest_key_t meta -> meta + +let ty_size t = (ty_metadata t).size + +let unit_t ~annot = Unit_t {annot; size = Type_size.one} + +let int_t ~annot = Int_t {annot; size = Type_size.one} + +let nat_t ~annot = Nat_t {annot; size = Type_size.one} + +let signature_t ~annot = Signature_t {annot; size = Type_size.one} + +let string_t ~annot = String_t {annot; size = Type_size.one} + +let bytes_t ~annot = Bytes_t {annot; size = Type_size.one} + +let mutez_t ~annot = Mutez_t {annot; size = Type_size.one} + +let key_hash_t ~annot = Key_hash_t {annot; size = Type_size.one} + +let key_t ~annot = Key_t {annot; size = Type_size.one} + +let timestamp_t ~annot = Timestamp_t {annot; size = Type_size.one} + +let address_t ~annot = Address_t {annot; size = Type_size.one} + +let bool_t ~annot = Bool_t {annot; size = Type_size.one} + +let pair_t loc (l, fannot_l, vannot_l) (r, fannot_r, vannot_r) ~annot = + Type_size.compound2 loc (ty_size l) (ty_size r) >|? fun size -> + Pair_t ((l, fannot_l, vannot_l), (r, fannot_r, vannot_r), {annot; size}) + +let union_t loc (l, fannot_l) (r, fannot_r) ~annot = + Type_size.compound2 loc (ty_size l) (ty_size r) >|? fun size -> + Union_t ((l, fannot_l), (r, fannot_r), {annot; size}) + +let union_bytes_bool_t = + Union_t + ( (bytes_t ~annot:None, None), + (bool_t ~annot:None, None), + {annot = None; size = Type_size.three} ) + +let lambda_t loc l r ~annot = + Type_size.compound2 loc (ty_size l) (ty_size r) >|? fun size -> + Lambda_t (l, r, {annot; size}) + +let option_t loc t ~annot = + Type_size.compound1 loc (ty_size t) >|? fun size -> Option_t (t, {annot; size}) + +let option_string'_t meta = + let {annot; size = _} = meta in + Option_t (string_t ~annot, {annot = None; size = Type_size.two}) + +let option_bytes'_t meta = + let {annot; size = _} = meta in + Option_t (bytes_t ~annot, {annot = None; size = Type_size.two}) + +let option_nat_t = + Option_t (nat_t ~annot:None, {annot = None; size = Type_size.two}) + +let option_pair_nat_nat_t = + Option_t + ( Pair_t + ( (nat_t ~annot:None, None, None), + (nat_t ~annot:None, None, None), + {annot = None; size = Type_size.three} ), + {annot = None; size = Type_size.four} ) + +let option_pair_nat'_nat'_t meta = + let {annot; size = _} = meta in + Option_t + ( Pair_t + ( (nat_t ~annot, None, None), + (nat_t ~annot, None, None), + {annot = None; size = Type_size.three} ), + {annot = None; size = Type_size.four} ) + +let option_pair_nat_mutez'_t meta = + let {annot; size = _} = meta in + Option_t + ( Pair_t + ( (nat_t ~annot:None, None, None), + (mutez_t ~annot, None, None), + {annot = None; size = Type_size.three} ), + {annot = None; size = Type_size.four} ) + +let option_pair_mutez'_mutez'_t meta = + let {annot; size = _} = meta in + Option_t + ( Pair_t + ( (mutez_t ~annot, None, None), + (mutez_t ~annot, None, None), + {annot = None; size = Type_size.three} ), + {annot = None; size = Type_size.four} ) + +let option_pair_int'_nat_t meta = + let {annot; size = _} = meta in + Option_t + ( Pair_t + ( (int_t ~annot, None, None), + (nat_t ~annot:None, None, None), + {annot = None; size = Type_size.three} ), + {annot = None; size = Type_size.four} ) + +let option_pair_int_nat'_t meta = + let {annot; size = _} = meta in + Option_t + ( Pair_t + ( (int_t ~annot:None, None, None), + (nat_t ~annot, None, None), + {annot = None; size = Type_size.three} ), + {annot = None; size = Type_size.four} ) + +let list_t loc t ~annot = + Type_size.compound1 loc (ty_size t) >|? fun size -> List_t (t, {annot; size}) + +let operation_t ~annot = Operation_t {annot; size = Type_size.one} + +let list_operation_t = + List_t (operation_t ~annot:None, {annot = None; size = Type_size.two}) + +let set_t loc t ~annot = + Type_size.compound1 loc (comparable_ty_size t) >|? fun size -> + Set_t (t, {annot; size}) + +let map_t loc l r ~annot = + Type_size.compound2 loc (comparable_ty_size l) (ty_size r) >|? fun size -> + Map_t (l, r, {annot; size}) + +let big_map_t loc l r ~annot = + Type_size.compound2 loc (comparable_ty_size l) (ty_size r) >|? fun size -> + Big_map_t (l, r, {annot; size}) + +let contract_t loc t ~annot = + Type_size.compound1 loc (ty_size t) >|? fun size -> + Contract_t (t, {annot; size}) + +let contract_unit_t = + Contract_t (unit_t ~annot:None, {annot = None; size = Type_size.two}) + +let sapling_transaction_t ~memo_size ~annot = + Sapling_transaction_t (memo_size, {annot; size = Type_size.one}) + +let sapling_state_t ~memo_size ~annot = + Sapling_state_t (memo_size, {annot; size = Type_size.one}) + +let chain_id_t ~annot = Chain_id_t {annot; size = Type_size.one} + +let never_t ~annot = Never_t {annot; size = Type_size.one} + +let bls12_381_g1_t ~annot = Bls12_381_g1_t {annot; size = Type_size.one} + +let bls12_381_g2_t ~annot = Bls12_381_g2_t {annot; size = Type_size.one} + +let bls12_381_fr_t ~annot = Bls12_381_fr_t {annot; size = Type_size.one} + +let ticket_t loc t ~annot = + Type_size.compound1 loc (comparable_ty_size t) >|? fun size -> + Ticket_t (t, {annot; size}) + +let chest_key_t ~annot = Chest_key_t {annot; size = Type_size.one} + +let chest_t ~annot = Chest_t {annot; size = Type_size.one} + +type 'a kinstr_traverse = { + apply : 'b 'u 'r 'f. 'a -> ('b, 'u, 'r, 'f) kinstr -> 'a; +} + +let kinstr_traverse i init f = + let rec aux : + type ret a s r f. 'accu -> (a, s, r, f) kinstr -> ('accu -> ret) -> ret = + fun accu t continue -> + let accu = f.apply accu t in + let next k = + (aux [@ocaml.tailcall]) accu k @@ fun accu -> + (continue [@ocaml.tailcall]) accu + in + let next2 k1 k2 = + (aux [@ocaml.tailcall]) accu k1 @@ fun accu -> + (aux [@ocaml.tailcall]) accu k2 @@ fun accu -> + (continue [@ocaml.tailcall]) accu + in + let next3 k1 k2 k3 = + (aux [@ocaml.tailcall]) accu k1 @@ fun accu -> + (aux [@ocaml.tailcall]) accu k2 @@ fun accu -> + (aux [@ocaml.tailcall]) accu k3 @@ fun accu -> + (continue [@ocaml.tailcall]) accu + in + let return () = (continue [@ocaml.tailcall]) accu in + match t with + | IDrop (_, k) -> (next [@ocaml.tailcall]) k + | IDup (_, k) -> (next [@ocaml.tailcall]) k + | ISwap (_, k) -> (next [@ocaml.tailcall]) k + | IConst (_, _, k) -> (next [@ocaml.tailcall]) k + | ICons_pair (_, k) -> (next [@ocaml.tailcall]) k + | ICar (_, k) -> (next [@ocaml.tailcall]) k + | ICdr (_, k) -> (next [@ocaml.tailcall]) k + | IUnpair (_, k) -> (next [@ocaml.tailcall]) k + | ICons_some (_, k) -> (next [@ocaml.tailcall]) k + | ICons_none (_, k) -> (next [@ocaml.tailcall]) k + | IIf_none {kinfo = _; branch_if_none = k1; branch_if_some = k2; k} -> + (next3 [@ocaml.tailcall]) k1 k2 k + | ICons_left (_, k) -> (next [@ocaml.tailcall]) k + | ICons_right (_, k) -> (next [@ocaml.tailcall]) k + | IIf_left {kinfo = _; branch_if_left = k1; branch_if_right = k2; k} -> + (next3 [@ocaml.tailcall]) k1 k2 k + | ICons_list (_, k) -> (next [@ocaml.tailcall]) k + | INil (_, k) -> (next [@ocaml.tailcall]) k + | IIf_cons {kinfo = _; branch_if_nil = k1; branch_if_cons = k2; k} -> + (next3 [@ocaml.tailcall]) k1 k2 k + | IList_map (_, k1, k2) -> (next2 [@ocaml.tailcall]) k1 k2 + | IList_iter (_, k1, k2) -> (next2 [@ocaml.tailcall]) k1 k2 + | IList_size (_, k) -> (next [@ocaml.tailcall]) k + | IEmpty_set (_, _, k) -> (next [@ocaml.tailcall]) k + | ISet_iter (_, k1, k2) -> (next2 [@ocaml.tailcall]) k1 k2 + | ISet_mem (_, k) -> (next [@ocaml.tailcall]) k + | ISet_update (_, k) -> (next [@ocaml.tailcall]) k + | ISet_size (_, k) -> (next [@ocaml.tailcall]) k + | IEmpty_map (_, _, k) -> (next [@ocaml.tailcall]) k + | IMap_map (_, k1, k2) -> (next2 [@ocaml.tailcall]) k1 k2 + | IMap_iter (_, k1, k2) -> (next2 [@ocaml.tailcall]) k1 k2 + | IMap_mem (_, k) -> (next [@ocaml.tailcall]) k + | IMap_get (_, k) -> (next [@ocaml.tailcall]) k + | IMap_update (_, k) -> (next [@ocaml.tailcall]) k + | IMap_get_and_update (_, k) -> (next [@ocaml.tailcall]) k + | IMap_size (_, k) -> (next [@ocaml.tailcall]) k + | IEmpty_big_map (_, _, _, k) -> (next [@ocaml.tailcall]) k + | IBig_map_mem (_, k) -> (next [@ocaml.tailcall]) k + | IBig_map_get (_, k) -> (next [@ocaml.tailcall]) k + | IBig_map_update (_, k) -> (next [@ocaml.tailcall]) k + | IBig_map_get_and_update (_, k) -> (next [@ocaml.tailcall]) k + | IConcat_string (_, k) -> (next [@ocaml.tailcall]) k + | IConcat_string_pair (_, k) -> (next [@ocaml.tailcall]) k + | ISlice_string (_, k) -> (next [@ocaml.tailcall]) k + | IString_size (_, k) -> (next [@ocaml.tailcall]) k + | IConcat_bytes (_, k) -> (next [@ocaml.tailcall]) k + | IConcat_bytes_pair (_, k) -> (next [@ocaml.tailcall]) k + | ISlice_bytes (_, k) -> (next [@ocaml.tailcall]) k + | IBytes_size (_, k) -> (next [@ocaml.tailcall]) k + | IAdd_seconds_to_timestamp (_, k) -> (next [@ocaml.tailcall]) k + | IAdd_timestamp_to_seconds (_, k) -> (next [@ocaml.tailcall]) k + | ISub_timestamp_seconds (_, k) -> (next [@ocaml.tailcall]) k + | IDiff_timestamps (_, k) -> (next [@ocaml.tailcall]) k + | IAdd_tez (_, k) -> (next [@ocaml.tailcall]) k + | ISub_tez (_, k) -> (next [@ocaml.tailcall]) k + | IMul_teznat (_, k) -> (next [@ocaml.tailcall]) k + | IMul_nattez (_, k) -> (next [@ocaml.tailcall]) k + | IEdiv_teznat (_, k) -> (next [@ocaml.tailcall]) k + | IEdiv_tez (_, k) -> (next [@ocaml.tailcall]) k + | IOr (_, k) -> (next [@ocaml.tailcall]) k + | IAnd (_, k) -> (next [@ocaml.tailcall]) k + | IXor (_, k) -> (next [@ocaml.tailcall]) k + | INot (_, k) -> (next [@ocaml.tailcall]) k + | IIs_nat (_, k) -> (next [@ocaml.tailcall]) k + | INeg_nat (_, k) -> (next [@ocaml.tailcall]) k + | INeg_int (_, k) -> (next [@ocaml.tailcall]) k + | IAbs_int (_, k) -> (next [@ocaml.tailcall]) k + | IInt_nat (_, k) -> (next [@ocaml.tailcall]) k + | IAdd_intint (_, k) -> (next [@ocaml.tailcall]) k + | IAdd_intnat (_, k) -> (next [@ocaml.tailcall]) k + | IAdd_natint (_, k) -> (next [@ocaml.tailcall]) k + | IAdd_natnat (_, k) -> (next [@ocaml.tailcall]) k + | ISub_int (_, k) -> (next [@ocaml.tailcall]) k + | IMul_intint (_, k) -> (next [@ocaml.tailcall]) k + | IMul_intnat (_, k) -> (next [@ocaml.tailcall]) k + | IMul_natint (_, k) -> (next [@ocaml.tailcall]) k + | IMul_natnat (_, k) -> (next [@ocaml.tailcall]) k + | IEdiv_intint (_, k) -> (next [@ocaml.tailcall]) k + | IEdiv_intnat (_, k) -> (next [@ocaml.tailcall]) k + | IEdiv_natint (_, k) -> (next [@ocaml.tailcall]) k + | IEdiv_natnat (_, k) -> (next [@ocaml.tailcall]) k + | ILsl_nat (_, k) -> (next [@ocaml.tailcall]) k + | ILsr_nat (_, k) -> (next [@ocaml.tailcall]) k + | IOr_nat (_, k) -> (next [@ocaml.tailcall]) k + | IAnd_nat (_, k) -> (next [@ocaml.tailcall]) k + | IAnd_int_nat (_, k) -> (next [@ocaml.tailcall]) k + | IXor_nat (_, k) -> (next [@ocaml.tailcall]) k + | INot_nat (_, k) -> (next [@ocaml.tailcall]) k + | INot_int (_, k) -> (next [@ocaml.tailcall]) k + | IIf {kinfo = _; branch_if_true = k1; branch_if_false = k2; k} -> + (next3 [@ocaml.tailcall]) k1 k2 k + | ILoop (_, k1, k2) -> (next2 [@ocaml.tailcall]) k1 k2 + | ILoop_left (_, k1, k2) -> (next2 [@ocaml.tailcall]) k1 k2 + | IDip (_, k1, k2) -> (next2 [@ocaml.tailcall]) k1 k2 + | IExec (_, k) -> (next [@ocaml.tailcall]) k + | IApply (_, _, k) -> (next [@ocaml.tailcall]) k + | ILambda (_, _, k) -> (next [@ocaml.tailcall]) k + | IFailwith (_, _, _) -> (return [@ocaml.tailcall]) () + | ICompare (_, _, k) -> (next [@ocaml.tailcall]) k + | IEq (_, k) -> (next [@ocaml.tailcall]) k + | INeq (_, k) -> (next [@ocaml.tailcall]) k + | ILt (_, k) -> (next [@ocaml.tailcall]) k + | IGt (_, k) -> (next [@ocaml.tailcall]) k + | ILe (_, k) -> (next [@ocaml.tailcall]) k + | IGe (_, k) -> (next [@ocaml.tailcall]) k + | IAddress (_, k) -> (next [@ocaml.tailcall]) k + | IContract (_, _, _, k) -> (next [@ocaml.tailcall]) k + | IView (_, _, k) -> (next [@ocaml.tailcall]) k + | ITransfer_tokens (_, k) -> (next [@ocaml.tailcall]) k + | IImplicit_account (_, k) -> (next [@ocaml.tailcall]) k + | ICreate_contract {k; _} -> (next [@ocaml.tailcall]) k + | ISet_delegate (_, k) -> (next [@ocaml.tailcall]) k + | INow (_, k) -> (next [@ocaml.tailcall]) k + | IBalance (_, k) -> (next [@ocaml.tailcall]) k + | ILevel (_, k) -> (next [@ocaml.tailcall]) k + | ICheck_signature (_, k) -> (next [@ocaml.tailcall]) k + | IHash_key (_, k) -> (next [@ocaml.tailcall]) k + | IPack (_, _, k) -> (next [@ocaml.tailcall]) k + | IUnpack (_, _, k) -> (next [@ocaml.tailcall]) k + | IBlake2b (_, k) -> (next [@ocaml.tailcall]) k + | ISha256 (_, k) -> (next [@ocaml.tailcall]) k + | ISha512 (_, k) -> (next [@ocaml.tailcall]) k + | ISource (_, k) -> (next [@ocaml.tailcall]) k + | ISender (_, k) -> (next [@ocaml.tailcall]) k + | ISelf (_, _, _, k) -> (next [@ocaml.tailcall]) k + | ISelf_address (_, k) -> (next [@ocaml.tailcall]) k + | IAmount (_, k) -> (next [@ocaml.tailcall]) k + | ISapling_empty_state (_, _, k) -> (next [@ocaml.tailcall]) k + | ISapling_verify_update (_, k) -> (next [@ocaml.tailcall]) k + | IDig (_, _, _, k) -> (next [@ocaml.tailcall]) k + | IDug (_, _, _, k) -> (next [@ocaml.tailcall]) k + | IDipn (_, _, _, k1, k2) -> (next2 [@ocaml.tailcall]) k1 k2 + | IDropn (_, _, _, k) -> (next [@ocaml.tailcall]) k + | IChainId (_, k) -> (next [@ocaml.tailcall]) k + | INever _ -> (return [@ocaml.tailcall]) () + | IVoting_power (_, k) -> (next [@ocaml.tailcall]) k + | ITotal_voting_power (_, k) -> (next [@ocaml.tailcall]) k + | IKeccak (_, k) -> (next [@ocaml.tailcall]) k + | ISha3 (_, k) -> (next [@ocaml.tailcall]) k + | IAdd_bls12_381_g1 (_, k) -> (next [@ocaml.tailcall]) k + | IAdd_bls12_381_g2 (_, k) -> (next [@ocaml.tailcall]) k + | IAdd_bls12_381_fr (_, k) -> (next [@ocaml.tailcall]) k + | IMul_bls12_381_g1 (_, k) -> (next [@ocaml.tailcall]) k + | IMul_bls12_381_g2 (_, k) -> (next [@ocaml.tailcall]) k + | IMul_bls12_381_fr (_, k) -> (next [@ocaml.tailcall]) k + | IMul_bls12_381_z_fr (_, k) -> (next [@ocaml.tailcall]) k + | IMul_bls12_381_fr_z (_, k) -> (next [@ocaml.tailcall]) k + | IInt_bls12_381_fr (_, k) -> (next [@ocaml.tailcall]) k + | INeg_bls12_381_g1 (_, k) -> (next [@ocaml.tailcall]) k + | INeg_bls12_381_g2 (_, k) -> (next [@ocaml.tailcall]) k + | INeg_bls12_381_fr (_, k) -> (next [@ocaml.tailcall]) k + | IPairing_check_bls12_381 (_, k) -> (next [@ocaml.tailcall]) k + | IComb (_, _, _, k) -> (next [@ocaml.tailcall]) k + | IUncomb (_, _, _, k) -> (next [@ocaml.tailcall]) k + | IComb_get (_, _, _, k) -> (next [@ocaml.tailcall]) k + | IComb_set (_, _, _, k) -> (next [@ocaml.tailcall]) k + | IDup_n (_, _, _, k) -> (next [@ocaml.tailcall]) k + | ITicket (_, k) -> (next [@ocaml.tailcall]) k + | IRead_ticket (_, k) -> (next [@ocaml.tailcall]) k + | ISplit_ticket (_, k) -> (next [@ocaml.tailcall]) k + | IJoin_tickets (_, _, k) -> (next [@ocaml.tailcall]) k + | IOpen_chest (_, k) -> (next [@ocaml.tailcall]) k + | IHalt _ -> (return [@ocaml.tailcall]) () + | ILog (_, _, _, k) -> (next [@ocaml.tailcall]) k + in + aux init i (fun accu -> accu) + +type 'a ty_traverse = { + apply : 't. 'a -> 't ty -> 'a; + apply_comparable : 't. 'a -> 't comparable_ty -> 'a; +} + +let (ty_traverse, comparable_ty_traverse) = + let rec aux : + type t ret accu. + accu ty_traverse -> accu -> t comparable_ty -> (accu -> ret) -> ret = + fun f accu ty continue -> + let accu = f.apply_comparable accu ty in + let next2 ty1 ty2 = + (aux [@ocaml.tailcall]) f accu ty1 @@ fun accu -> + (aux [@ocaml.tailcall]) f accu ty2 @@ fun accu -> + (continue [@ocaml.tailcall]) accu + in + let next ty1 = + (aux [@ocaml.tailcall]) f accu ty1 @@ fun accu -> + (continue [@ocaml.tailcall]) accu + in + let return () = (continue [@ocaml.tailcall]) accu in + match ty with + | Unit_key _ | Int_key _ | Nat_key _ | Signature_key _ | String_key _ + | Bytes_key _ | Mutez_key _ | Key_hash_key _ | Key_key _ | Timestamp_key _ + | Address_key _ | Bool_key _ | Chain_id_key _ | Never_key _ -> + (return [@ocaml.tailcall]) () + | Pair_key ((ty1, _), (ty2, _), _) -> (next2 [@ocaml.tailcall]) ty1 ty2 + | Union_key ((ty1, _), (ty2, _), _) -> (next2 [@ocaml.tailcall]) ty1 ty2 + | Option_key (ty, _) -> (next [@ocaml.tailcall]) ty + and aux' : + type ret t accu. accu ty_traverse -> accu -> t ty -> (accu -> ret) -> ret + = + fun f accu ty continue -> + let accu = f.apply accu ty in + match (ty : t ty) with + | Unit_t _ | Int_t _ | Nat_t _ | Signature_t _ | String_t _ | Bytes_t _ + | Mutez_t _ | Key_hash_t _ | Key_t _ | Timestamp_t _ | Address_t _ + | Bool_t _ + | Sapling_transaction_t (_, _) + | Sapling_state_t (_, _) + | Operation_t _ | Chain_id_t _ | Never_t _ | Bls12_381_g1_t _ + | Bls12_381_g2_t _ | Bls12_381_fr_t _ -> + (continue [@ocaml.tailcall]) accu + | Ticket_t (cty, _) -> aux f accu cty continue + | Chest_key_t _ | Chest_t _ -> (continue [@ocaml.tailcall]) accu + | Pair_t ((ty1, _, _), (ty2, _, _), _) -> + (next2' [@ocaml.tailcall]) f accu ty1 ty2 continue + | Union_t ((ty1, _), (ty2, _), _) -> + (next2' [@ocaml.tailcall]) f accu ty1 ty2 continue + | Lambda_t (ty1, ty2, _) -> + (next2' [@ocaml.tailcall]) f accu ty1 ty2 continue + | Option_t (ty1, _) -> (next' [@ocaml.tailcall]) f accu ty1 continue + | List_t (ty1, _) -> (next' [@ocaml.tailcall]) f accu ty1 continue + | Set_t (cty, _) -> (aux [@ocaml.tailcall]) f accu cty @@ continue + | Map_t (cty, ty1, _) -> + (aux [@ocaml.tailcall]) f accu cty @@ fun accu -> + (next' [@ocaml.tailcall]) f accu ty1 continue + | Big_map_t (cty, ty1, _) -> + (aux [@ocaml.tailcall]) f accu cty @@ fun accu -> + (next' [@ocaml.tailcall]) f accu ty1 continue + | Contract_t (ty1, _) -> (next' [@ocaml.tailcall]) f accu ty1 continue + and next2' : + type a b ret accu. + accu ty_traverse -> accu -> a ty -> b ty -> (accu -> ret) -> ret = + fun f accu ty1 ty2 continue -> + (aux' [@ocaml.tailcall]) f accu ty1 @@ fun accu -> + (aux' [@ocaml.tailcall]) f accu ty2 @@ fun accu -> + (continue [@ocaml.tailcall]) accu + and next' : + type a ret accu. accu ty_traverse -> accu -> a ty -> (accu -> ret) -> ret + = + fun f accu ty1 continue -> + (aux' [@ocaml.tailcall]) f accu ty1 @@ fun accu -> + (continue [@ocaml.tailcall]) accu + in + ( (fun ty init f -> aux' f init ty (fun accu -> accu)), + fun cty init f -> aux f init cty (fun accu -> accu) ) + +type 'accu stack_ty_traverse = { + apply : 'ty 's. 'accu -> ('ty, 's) stack_ty -> 'accu; +} + +let stack_ty_traverse (type a t) (sty : (a, t) stack_ty) init f = + let rec aux : type b u. 'accu -> (b, u) stack_ty -> 'accu = + fun accu sty -> + match sty with + | Bot_t -> f.apply accu sty + | Item_t (_, sty', _) -> aux (f.apply accu sty) sty' + in + aux init sty + +type 'a value_traverse = { + apply : 't. 'a -> 't ty -> 't -> 'a; + apply_comparable : 't. 'a -> 't comparable_ty -> 't -> 'a; +} + +let value_traverse (type t) (ty : (t ty, t comparable_ty) union) (x : t) init f + = + let rec aux : type ret t. 'accu -> t ty -> t -> ('accu -> ret) -> ret = + fun accu ty x continue -> + let accu = f.apply accu ty x in + let next2 ty1 ty2 x1 x2 = + (aux [@ocaml.tailcall]) accu ty1 x1 @@ fun accu -> + (aux [@ocaml.tailcall]) accu ty2 x2 @@ fun accu -> + (continue [@ocaml.tailcall]) accu + in + let next ty1 x1 = + (aux [@ocaml.tailcall]) accu ty1 x1 @@ fun accu -> + (continue [@ocaml.tailcall]) accu + in + let return () = (continue [@ocaml.tailcall]) accu in + let rec on_list ty' accu = function + | [] -> (continue [@ocaml.tailcall]) accu + | x :: xs -> + (aux [@ocaml.tailcall]) accu ty' x @@ fun accu -> + (on_list [@ocaml.tailcall]) ty' accu xs + in + match ty with + | Unit_t _ | Int_t _ | Nat_t _ | Signature_t _ | String_t _ | Bytes_t _ + | Mutez_t _ | Key_hash_t _ | Key_t _ | Timestamp_t _ | Address_t _ + | Bool_t _ + | Sapling_transaction_t (_, _) + | Sapling_state_t (_, _) + | Operation_t _ | Chain_id_t _ | Never_t _ | Bls12_381_g1_t _ + | Bls12_381_g2_t _ | Bls12_381_fr_t _ | Chest_key_t _ | Chest_t _ + | Lambda_t (_, _, _) -> + (return [@ocaml.tailcall]) () + | Pair_t ((ty1, _, _), (ty2, _, _), _) -> + (next2 [@ocaml.tailcall]) ty1 ty2 (fst x) (snd x) + | Union_t ((ty1, _), (ty2, _), _) -> ( + match x with + | L l -> (next [@ocaml.tailcall]) ty1 l + | R r -> (next [@ocaml.tailcall]) ty2 r) + | Option_t (ty, _) -> ( + match x with + | None -> return () + | Some v -> (next [@ocaml.tailcall]) ty v) + | Ticket_t (cty, _) -> (aux' [@ocaml.tailcall]) accu cty x.contents continue + | List_t (ty', _) -> on_list ty' accu x.elements + | Map_t (kty, ty', _) -> + let module M = (val x) in + let bindings = + M.OPS.fold (fun k v bs -> (k, v) :: bs) (fst M.boxed) [] + in + on_bindings accu kty ty' continue bindings + | Set_t (ty', _) -> + let module M = (val x) in + let elements = M.OPS.fold (fun x s -> x :: s) M.boxed [] in + on_list' accu ty' elements continue + | Big_map_t (_, _, _) -> + (* For big maps, there is no obvious recursion scheme so we + delegate this case to the client. *) + (return [@ocaml.tailcall]) () + | Contract_t (_, _) -> (return [@ocaml.tailcall]) () + and on_list' : + type ret t. 'accu -> t comparable_ty -> t list -> ('accu -> ret) -> ret = + fun accu ty' xs continue -> + match xs with + | [] -> (continue [@ocaml.tailcall]) accu + | x :: xs -> + (aux' [@ocaml.tailcall]) accu ty' x @@ fun accu -> + (on_list' [@ocaml.tailcall]) accu ty' xs continue + and on_bindings : + type ret k v. + 'accu -> k comparable_ty -> v ty -> ('accu -> ret) -> (k * v) list -> ret + = + fun accu kty ty' continue xs -> + match xs with + | [] -> (continue [@ocaml.tailcall]) accu + | (k, v) :: xs -> + (aux' [@ocaml.tailcall]) accu kty k @@ fun accu -> + (aux [@ocaml.tailcall]) accu ty' v @@ fun accu -> + (on_bindings [@ocaml.tailcall]) accu kty ty' continue xs + and aux' : type ret t. 'accu -> t comparable_ty -> t -> ('accu -> ret) -> ret + = + fun accu ty x continue -> + let accu = f.apply_comparable accu ty x in + let next2 ty1 ty2 x1 x2 = + (aux' [@ocaml.tailcall]) accu ty1 x1 @@ fun accu -> + (aux' [@ocaml.tailcall]) accu ty2 x2 @@ fun accu -> + (continue [@ocaml.tailcall]) accu + in + let next ty1 x1 = + (aux' [@ocaml.tailcall]) accu ty1 x1 @@ fun accu -> + (continue [@ocaml.tailcall]) accu + in + let return () = (continue [@ocaml.tailcall]) accu in + match ty with + | Unit_key _ | Int_key _ | Nat_key _ | Signature_key _ | String_key _ + | Bytes_key _ | Mutez_key _ | Key_hash_key _ | Key_key _ | Timestamp_key _ + | Address_key _ | Bool_key _ | Chain_id_key _ | Never_key _ -> + (return [@ocaml.tailcall]) () + | Pair_key ((ty1, _), (ty2, _), _) -> + (next2 [@ocaml.tailcall]) ty1 ty2 (fst x) (snd x) + | Union_key ((ty1, _), (ty2, _), _) -> ( + match x with + | L l -> (next [@ocaml.tailcall]) ty1 l + | R r -> (next [@ocaml.tailcall]) ty2 r) + | Option_key (ty, _) -> ( + match x with + | None -> (return [@ocaml.tailcall]) () + | Some v -> (next [@ocaml.tailcall]) ty v) + in + match ty with + | L ty -> aux init ty x (fun accu -> accu) + | R cty -> aux' init cty x (fun accu -> accu) + [@@coq_axiom_with_reason "local mutually recursive definition not handled"] + +let stack_top_ty : type a b s. (a, b * s) stack_ty -> a ty = function + | Item_t (ty, _, _) -> ty diff --git a/src/proto_011_PtHangzH/lib_protocol/script_typed_ir.mli b/src/proto_011_PtHangzH/lib_protocol/script_typed_ir.mli new file mode 100644 index 000000000000..f79048fa6e17 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_typed_ir.mli @@ -0,0 +1,1579 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Script_int + +(* Preliminary definitions. *) + +type var_annot = Var_annot of string [@@ocaml.unboxed] + +type type_annot = Type_annot of string [@@ocaml.unboxed] + +type field_annot = Field_annot of string [@@ocaml.unboxed] + +type never = | + +type address = Contract.t * string + +type ('a, 'b) pair = 'a * 'b + +type ('a, 'b) union = L of 'a | R of 'b + +type operation = packed_internal_operation * Lazy_storage.diffs option + +type 'a ticket = {ticketer : address; contents : 'a; amount : n num} + +type empty_cell = EmptyCell + +type end_of_stack = empty_cell * empty_cell + +module Type_size : sig + type 'a t + + val merge : 'a t -> 'b t -> 'a t tzresult +end + +type 'a ty_metadata = {annot : type_annot option; size : 'a Type_size.t} + +type _ comparable_ty = + | Unit_key : unit ty_metadata -> unit comparable_ty + | Never_key : never ty_metadata -> never comparable_ty + | Int_key : z num ty_metadata -> z num comparable_ty + | Nat_key : n num ty_metadata -> n num comparable_ty + | Signature_key : signature ty_metadata -> signature comparable_ty + | String_key : Script_string.t ty_metadata -> Script_string.t comparable_ty + | Bytes_key : Bytes.t ty_metadata -> Bytes.t comparable_ty + | Mutez_key : Tez.t ty_metadata -> Tez.t comparable_ty + | Bool_key : bool ty_metadata -> bool comparable_ty + | Key_hash_key : public_key_hash ty_metadata -> public_key_hash comparable_ty + | Key_key : public_key ty_metadata -> public_key comparable_ty + | Timestamp_key : + Script_timestamp.t ty_metadata + -> Script_timestamp.t comparable_ty + | Chain_id_key : Chain_id.t ty_metadata -> Chain_id.t comparable_ty + | Address_key : address ty_metadata -> address comparable_ty + | Pair_key : + ('a comparable_ty * field_annot option) + * ('b comparable_ty * field_annot option) + * ('a, 'b) pair ty_metadata + -> ('a, 'b) pair comparable_ty + | Union_key : + ('a comparable_ty * field_annot option) + * ('b comparable_ty * field_annot option) + * ('a, 'b) union ty_metadata + -> ('a, 'b) union comparable_ty + | Option_key : + 'v comparable_ty * 'v option ty_metadata + -> 'v option comparable_ty + +val unit_key : annot:type_annot option -> unit comparable_ty + +val never_key : annot:type_annot option -> never comparable_ty + +val int_key : annot:type_annot option -> z num comparable_ty + +val nat_key : annot:type_annot option -> n num comparable_ty + +val signature_key : annot:type_annot option -> signature comparable_ty + +val string_key : annot:type_annot option -> Script_string.t comparable_ty + +val bytes_key : annot:type_annot option -> Bytes.t comparable_ty + +val mutez_key : annot:type_annot option -> Tez.t comparable_ty + +val bool_key : annot:type_annot option -> bool comparable_ty + +val key_hash_key : annot:type_annot option -> public_key_hash comparable_ty + +val key_key : annot:type_annot option -> public_key comparable_ty + +val timestamp_key : annot:type_annot option -> Script_timestamp.t comparable_ty + +val chain_id_key : annot:type_annot option -> Chain_id.t comparable_ty + +val address_key : annot:type_annot option -> address comparable_ty + +val pair_key : + Script.location -> + 'a comparable_ty * field_annot option -> + 'b comparable_ty * field_annot option -> + annot:type_annot option -> + ('a, 'b) pair comparable_ty tzresult + +val pair_3_key : + Script.location -> + 'a comparable_ty * field_annot option -> + 'b comparable_ty * field_annot option -> + 'c comparable_ty * field_annot option -> + ('a, ('b, 'c) pair) pair comparable_ty tzresult + +val union_key : + Script.location -> + 'a comparable_ty * field_annot option -> + 'b comparable_ty * field_annot option -> + annot:type_annot option -> + ('a, 'b) union comparable_ty tzresult + +val option_key : + Script.location -> + 'v comparable_ty -> + annot:type_annot option -> + 'v option comparable_ty tzresult + +module type Boxed_set_OPS = sig + type t + + type elt + + val empty : t + + val add : elt -> t -> t + + val mem : elt -> t -> bool + + val remove : elt -> t -> t + + val fold : (elt -> 'a -> 'a) -> t -> 'a -> 'a +end + +module type Boxed_set = sig + type elt + + val elt_ty : elt comparable_ty + + module OPS : Boxed_set_OPS with type elt = elt + + val boxed : OPS.t + + val size : int +end + +type 'elt set = (module Boxed_set with type elt = 'elt) + +module type Boxed_map_OPS = sig + type key + + type value + + type 'a t + + val empty : value t + + val add : key -> value -> value t -> value t + + val remove : key -> value t -> value t + + val find : key -> value t -> value option + + val fold : (key -> value -> 'a -> 'a) -> value t -> 'a -> 'a +end + +module type Boxed_map = sig + type key + + type value + + val key_ty : key comparable_ty + + module OPS : Boxed_map_OPS with type key = key and type value = value + + val boxed : value OPS.t * int +end + +type ('key, 'value) map = + (module Boxed_map with type key = 'key and type value = 'value) + +module Big_map_overlay : Map.S with type key = Script_expr_hash.t + +type ('key, 'value) big_map_overlay = { + map : ('key * 'value option) Big_map_overlay.t; + size : int; +} + +type 'elt boxed_list = {elements : 'elt list; length : int} + +module SMap : Map.S with type key = Script_string.t + +type view = { + input_ty : Script.node; + output_ty : Script.node; + view_code : Script.node; +} + +type ('arg, 'storage) script = { + code : (('arg, 'storage) pair, (operation boxed_list, 'storage) pair) lambda; + arg_type : 'arg ty; + storage : 'storage; + storage_type : 'storage ty; + views : view SMap.t; + root_name : field_annot option; + code_size : Cache_memory_helpers.sint; +} + +(* ---- Instructions --------------------------------------------------------*) + +(* + + The instructions of Michelson are represented in the following + Generalized Algebraic Datatypes. + + There are three important aspects in that type declaration. + + First, we follow a tagless approach for values: they are directly + represented as OCaml values. This reduces the computational cost of + interpretation because there is no need to check the shape of a + value before applying an operation to it. To achieve that, the GADT + encodes the typing rules of the Michelson programming + language. This static information is sufficient for the typechecker + to justify the absence of runtime checks. As a bonus, it also + ensures that well-typed Michelson programs cannot go wrong: if the + interpreter typechecks then we have the static guarantee that no + stack underflow or type error can occur at runtime. + + Second, we maintain the invariant that the stack type always has a + distinguished topmost element. This invariant is important to + implement the stack as an accumulator followed by a linked list of + cells, a so-called A-Stack. This representation is considered in + the literature[1] as an efficient representation of the stack for a + stack-based abstract machine, mainly because this opens the + opportunity for the accumulator to be stored in a hardware + register. In the GADT, this invariant is encoded by representing + the stack type using two parameters instead of one: the first one + is the type of the accumulator while the second is the type of the + rest of the stack. + + Third, in this representation, each instruction embeds its + potential successor instructions in the control flow. This design + choice permits an efficient implementation of the continuation + stack in the interpreter. Assigning a precise type to this kind of + instruction which is a cell in a linked list of instructions is + similar to the typing of delimited continuations: we need to give a + type to the stack ['before] the execution of the instruction, a + type to the stack ['after] the execution of the instruction and + before the execution of the next, and a type for the [`result]ing + stack type after the execution of the whole chain of instructions. + + Combining these three aspects, the type [kinstr] needs four + parameters: + + ('before_top, 'before, 'result_top, 'result) kinstr + + Notice that we could have chosen to only give two parameters to + [kinstr] by manually enforcing each argument to be a pair but this + is error-prone: with four parameters, this constraint is enforced + by the arity of the type constructor itself. + + Hence, an instruction which has a successor instruction enjoys a + type of the form: + + ... * ('after_top, 'after, 'result_top, 'result) kinstr * ... -> + ('before_top, 'before, 'result_top, 'result) kinstr + + where ['before_top] and ['before] are the types of the stack top + and rest before the instruction chain, ['after_top] and ['after] + are the types of the stack top and rest after the instruction + chain, and ['result_top] and ['result] are the types of the stack + top and rest after the instruction chain. The [IHalt] instruction + ends a sequence of instructions and has no successor, as shown by + its type: + + IHalt : ('a, 's) kinfo -> ('a, 's, 'a, 's) kinstr + + Each instruction is decorated by some metadata (typically to hold + locations). The type for these metadata is [kinfo]: such a value is + only used for logging and error reporting and has no impact on the + operational semantics. + + Notations: + ---------- + + In the following declaration, we use 'a, 'b, 'c, 'd, ... to assign + types to stack cell contents while we use 's, 't, 'u, 'v, ... to + assign types to stacks. + + The types for the final result and stack rest of a whole sequence + of instructions are written 'r and 'f (standing for "result" and + "final stack rest", respectively). + + Instructions for internal execution steps + ========================================= + + Some instructions encoded in the following type are not present in the + source language. They only appear during evaluation to account for + intermediate execution steps. Indeed, since the interpreter follows + a small-step style, it is sometimes necessary to decompose a + source-level instruction (e.g. List_map) into several instructions + with smaller steps. This technique seems required to get an + efficient tail-recursive interpreter. + + References + ========== + [1]: http://www.complang.tuwien.ac.at/projects/interpreters.html + + *) +and ('before_top, 'before, 'result_top, 'result) kinstr = + (* + Stack + ----- + *) + | IDrop : + ('a, 'b * 's) kinfo * ('b, 's, 'r, 'f) kinstr + -> ('a, 'b * 's, 'r, 'f) kinstr + | IDup : + ('a, 's) kinfo * ('a, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ISwap : + ('a, 'b * 's) kinfo * ('b, 'a * 's, 'r, 'f) kinstr + -> ('a, 'b * 's, 'r, 'f) kinstr + | IConst : + ('a, 's) kinfo * 'ty * ('ty, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + (* + Pairs + ----- + *) + | ICons_pair : + ('a, 'b * 's) kinfo * ('a * 'b, 's, 'r, 'f) kinstr + -> ('a, 'b * 's, 'r, 'f) kinstr + | ICar : + ('a * 'b, 's) kinfo * ('a, 's, 'r, 'f) kinstr + -> ('a * 'b, 's, 'r, 'f) kinstr + | ICdr : + ('a * 'b, 's) kinfo * ('b, 's, 'r, 'f) kinstr + -> ('a * 'b, 's, 'r, 'f) kinstr + | IUnpair : + ('a * 'b, 's) kinfo * ('a, 'b * 's, 'r, 'f) kinstr + -> ('a * 'b, 's, 'r, 'f) kinstr + (* + Options + ------- + *) + | ICons_some : + ('v, 's) kinfo * ('v option, 's, 'r, 'f) kinstr + -> ('v, 's, 'r, 'f) kinstr + | ICons_none : + ('a, 's) kinfo * ('b option, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IIf_none : { + kinfo : ('a option, 'b * 's) kinfo; + branch_if_none : ('b, 's, 'c, 't) kinstr; + branch_if_some : ('a, 'b * 's, 'c, 't) kinstr; + k : ('c, 't, 'r, 'f) kinstr; + } + -> ('a option, 'b * 's, 'r, 'f) kinstr + (* + Unions + ------ + *) + | ICons_left : + ('a, 's) kinfo * (('a, 'b) union, 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ICons_right : + ('b, 's) kinfo * (('a, 'b) union, 's, 'r, 'f) kinstr + -> ('b, 's, 'r, 'f) kinstr + | IIf_left : { + kinfo : (('a, 'b) union, 's) kinfo; + branch_if_left : ('a, 's, 'c, 't) kinstr; + branch_if_right : ('b, 's, 'c, 't) kinstr; + k : ('c, 't, 'r, 'f) kinstr; + } + -> (('a, 'b) union, 's, 'r, 'f) kinstr + (* + Lists + ----- + *) + | ICons_list : + ('a, 'a boxed_list * 's) kinfo * ('a boxed_list, 's, 'r, 'f) kinstr + -> ('a, 'a boxed_list * 's, 'r, 'f) kinstr + | INil : + ('a, 's) kinfo * ('b boxed_list, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IIf_cons : { + kinfo : ('a boxed_list, 'b * 's) kinfo; + branch_if_cons : ('a, 'a boxed_list * ('b * 's), 'c, 't) kinstr; + branch_if_nil : ('b, 's, 'c, 't) kinstr; + k : ('c, 't, 'r, 'f) kinstr; + } + -> ('a boxed_list, 'b * 's, 'r, 'f) kinstr + | IList_map : + ('a boxed_list, 'c * 's) kinfo + * ('a, 'c * 's, 'b, 'c * 's) kinstr + * ('b boxed_list, 'c * 's, 'r, 'f) kinstr + -> ('a boxed_list, 'c * 's, 'r, 'f) kinstr + | IList_iter : + ('a boxed_list, 'b * 's) kinfo + * ('a, 'b * 's, 'b, 's) kinstr + * ('b, 's, 'r, 'f) kinstr + -> ('a boxed_list, 'b * 's, 'r, 'f) kinstr + | IList_size : + ('a boxed_list, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> ('a boxed_list, 's, 'r, 'f) kinstr + (* + Sets + ---- + *) + | IEmpty_set : + ('a, 's) kinfo * 'b comparable_ty * ('b set, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ISet_iter : + ('a set, 'b * 's) kinfo + * ('a, 'b * 's, 'b, 's) kinstr + * ('b, 's, 'r, 'f) kinstr + -> ('a set, 'b * 's, 'r, 'f) kinstr + | ISet_mem : + ('a, 'a set * 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> ('a, 'a set * 's, 'r, 'f) kinstr + | ISet_update : + ('a, bool * ('a set * 's)) kinfo * ('a set, 's, 'r, 'f) kinstr + -> ('a, bool * ('a set * 's), 'r, 'f) kinstr + | ISet_size : + ('a set, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> ('a set, 's, 'r, 'f) kinstr + (* + Maps + ---- + *) + | IEmpty_map : + ('a, 's) kinfo * 'b comparable_ty * (('b, 'c) map, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IMap_map : + (('a, 'b) map, 'd * 's) kinfo + * ('a * 'b, 'd * 's, 'c, 'd * 's) kinstr + * (('a, 'c) map, 'd * 's, 'r, 'f) kinstr + -> (('a, 'b) map, 'd * 's, 'r, 'f) kinstr + | IMap_iter : + (('a, 'b) map, 'c * 's) kinfo + * ('a * 'b, 'c * 's, 'c, 's) kinstr + * ('c, 's, 'r, 'f) kinstr + -> (('a, 'b) map, 'c * 's, 'r, 'f) kinstr + | IMap_mem : + ('a, ('a, 'b) map * 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> ('a, ('a, 'b) map * 's, 'r, 'f) kinstr + | IMap_get : + ('a, ('a, 'b) map * 's) kinfo * ('b option, 's, 'r, 'f) kinstr + -> ('a, ('a, 'b) map * 's, 'r, 'f) kinstr + | IMap_update : + ('a, 'b option * (('a, 'b) map * 's)) kinfo + * (('a, 'b) map, 's, 'r, 'f) kinstr + -> ('a, 'b option * (('a, 'b) map * 's), 'r, 'f) kinstr + | IMap_get_and_update : + ('a, 'b option * (('a, 'b) map * 's)) kinfo + * ('b option, ('a, 'b) map * 's, 'r, 'f) kinstr + -> ('a, 'b option * (('a, 'b) map * 's), 'r, 'f) kinstr + | IMap_size : + (('a, 'b) map, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (('a, 'b) map, 's, 'r, 'f) kinstr + (* + Big maps + -------- + *) + | IEmpty_big_map : + ('a, 's) kinfo + * 'b comparable_ty + * 'c ty + * (('b, 'c) big_map, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IBig_map_mem : + ('a, ('a, 'b) big_map * 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> ('a, ('a, 'b) big_map * 's, 'r, 'f) kinstr + | IBig_map_get : + ('a, ('a, 'b) big_map * 's) kinfo * ('b option, 's, 'r, 'f) kinstr + -> ('a, ('a, 'b) big_map * 's, 'r, 'f) kinstr + | IBig_map_update : + ('a, 'b option * (('a, 'b) big_map * 's)) kinfo + * (('a, 'b) big_map, 's, 'r, 'f) kinstr + -> ('a, 'b option * (('a, 'b) big_map * 's), 'r, 'f) kinstr + | IBig_map_get_and_update : + ('a, 'b option * (('a, 'b) big_map * 's)) kinfo + * ('b option, ('a, 'b) big_map * 's, 'r, 'f) kinstr + -> ('a, 'b option * (('a, 'b) big_map * 's), 'r, 'f) kinstr + (* + Strings + ------- + *) + | IConcat_string : + (Script_string.t boxed_list, 's) kinfo + * (Script_string.t, 's, 'r, 'f) kinstr + -> (Script_string.t boxed_list, 's, 'r, 'f) kinstr + | IConcat_string_pair : + (Script_string.t, Script_string.t * 's) kinfo + * (Script_string.t, 's, 'r, 'f) kinstr + -> (Script_string.t, Script_string.t * 's, 'r, 'f) kinstr + | ISlice_string : + (n num, n num * (Script_string.t * 's)) kinfo + * (Script_string.t option, 's, 'r, 'f) kinstr + -> (n num, n num * (Script_string.t * 's), 'r, 'f) kinstr + | IString_size : + (Script_string.t, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (Script_string.t, 's, 'r, 'f) kinstr + (* + Bytes + ----- + *) + | IConcat_bytes : + (bytes boxed_list, 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes boxed_list, 's, 'r, 'f) kinstr + | IConcat_bytes_pair : + (bytes, bytes * 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes, bytes * 's, 'r, 'f) kinstr + | ISlice_bytes : + (n num, n num * (bytes * 's)) kinfo * (bytes option, 's, 'r, 'f) kinstr + -> (n num, n num * (bytes * 's), 'r, 'f) kinstr + | IBytes_size : + (bytes, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + (* + Timestamps + ---------- + *) + | IAdd_seconds_to_timestamp : + (z num, Script_timestamp.t * 's) kinfo + * (Script_timestamp.t, 's, 'r, 'f) kinstr + -> (z num, Script_timestamp.t * 's, 'r, 'f) kinstr + | IAdd_timestamp_to_seconds : + (Script_timestamp.t, z num * 's) kinfo + * (Script_timestamp.t, 's, 'r, 'f) kinstr + -> (Script_timestamp.t, z num * 's, 'r, 'f) kinstr + | ISub_timestamp_seconds : + (Script_timestamp.t, z num * 's) kinfo + * (Script_timestamp.t, 's, 'r, 'f) kinstr + -> (Script_timestamp.t, z num * 's, 'r, 'f) kinstr + | IDiff_timestamps : + (Script_timestamp.t, Script_timestamp.t * 's) kinfo + * (z num, 's, 'r, 'f) kinstr + -> (Script_timestamp.t, Script_timestamp.t * 's, 'r, 'f) kinstr + (* + Tez + --- + *) + | IAdd_tez : + (Tez.t, Tez.t * 's) kinfo * (Tez.t, 's, 'r, 'f) kinstr + -> (Tez.t, Tez.t * 's, 'r, 'f) kinstr + | ISub_tez : + (Tez.t, Tez.t * 's) kinfo * (Tez.t, 's, 'r, 'f) kinstr + -> (Tez.t, Tez.t * 's, 'r, 'f) kinstr + | IMul_teznat : + (Tez.t, n num * 's) kinfo * (Tez.t, 's, 'r, 'f) kinstr + -> (Tez.t, n num * 's, 'r, 'f) kinstr + | IMul_nattez : + (n num, Tez.t * 's) kinfo * (Tez.t, 's, 'r, 'f) kinstr + -> (n num, Tez.t * 's, 'r, 'f) kinstr + | IEdiv_teznat : + (Tez.t, n num * 's) kinfo + * ((Tez.t, Tez.t) pair option, 's, 'r, 'f) kinstr + -> (Tez.t, n num * 's, 'r, 'f) kinstr + | IEdiv_tez : + (Tez.t, Tez.t * 's) kinfo + * ((n num, Tez.t) pair option, 's, 'r, 'f) kinstr + -> (Tez.t, Tez.t * 's, 'r, 'f) kinstr + (* + Booleans + -------- + *) + | IOr : + (bool, bool * 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (bool, bool * 's, 'r, 'f) kinstr + | IAnd : + (bool, bool * 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (bool, bool * 's, 'r, 'f) kinstr + | IXor : + (bool, bool * 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (bool, bool * 's, 'r, 'f) kinstr + | INot : + (bool, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (bool, 's, 'r, 'f) kinstr + (* + Integers + -------- + *) + | IIs_nat : + (z num, 's) kinfo * (n num option, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | INeg_nat : + (n num, 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (n num, 's, 'r, 'f) kinstr + | INeg_int : + (z num, 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | IAbs_int : + (z num, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | IInt_nat : + (n num, 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (n num, 's, 'r, 'f) kinstr + | IAdd_intint : + (z num, z num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (z num, z num * 's, 'r, 'f) kinstr + | IAdd_intnat : + (z num, n num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (z num, n num * 's, 'r, 'f) kinstr + | IAdd_natint : + (n num, z num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (n num, z num * 's, 'r, 'f) kinstr + | IAdd_natnat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | ISub_int : + ('a num, 'b num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> ('a num, 'b num * 's, 'r, 'f) kinstr + | IMul_intint : + (z num, z num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (z num, z num * 's, 'r, 'f) kinstr + | IMul_intnat : + (z num, n num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (z num, n num * 's, 'r, 'f) kinstr + | IMul_natint : + (n num, z num * 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (n num, z num * 's, 'r, 'f) kinstr + | IMul_natnat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | IEdiv_intint : + (z num, z num * 's) kinfo + * ((z num, n num) pair option, 's, 'r, 'f) kinstr + -> (z num, z num * 's, 'r, 'f) kinstr + | IEdiv_intnat : + (z num, n num * 's) kinfo + * ((z num, n num) pair option, 's, 'r, 'f) kinstr + -> (z num, n num * 's, 'r, 'f) kinstr + | IEdiv_natint : + (n num, z num * 's) kinfo + * ((z num, n num) pair option, 's, 'r, 'f) kinstr + -> (n num, z num * 's, 'r, 'f) kinstr + | IEdiv_natnat : + (n num, n num * 's) kinfo + * ((n num, n num) pair option, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | ILsl_nat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | ILsr_nat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | IOr_nat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | IAnd_nat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | IAnd_int_nat : + (z num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (z num, n num * 's, 'r, 'f) kinstr + | IXor_nat : + (n num, n num * 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (n num, n num * 's, 'r, 'f) kinstr + | INot_nat : + (n num, 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (n num, 's, 'r, 'f) kinstr + | INot_int : + (z num, 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + (* + Control + ------- + *) + | IIf : { + kinfo : (bool, 'a * 's) kinfo; + branch_if_true : ('a, 's, 'b, 'u) kinstr; + branch_if_false : ('a, 's, 'b, 'u) kinstr; + k : ('b, 'u, 'r, 'f) kinstr; + } + -> (bool, 'a * 's, 'r, 'f) kinstr + | ILoop : + (bool, 'a * 's) kinfo + * ('a, 's, bool, 'a * 's) kinstr + * ('a, 's, 'r, 'f) kinstr + -> (bool, 'a * 's, 'r, 'f) kinstr + | ILoop_left : + (('a, 'b) union, 's) kinfo + * ('a, 's, ('a, 'b) union, 's) kinstr + * ('b, 's, 'r, 'f) kinstr + -> (('a, 'b) union, 's, 'r, 'f) kinstr + | IDip : + ('a, 'b * 's) kinfo + * ('b, 's, 'c, 't) kinstr + * ('a, 'c * 't, 'r, 'f) kinstr + -> ('a, 'b * 's, 'r, 'f) kinstr + | IExec : + ('a, ('a, 'b) lambda * 's) kinfo * ('b, 's, 'r, 'f) kinstr + -> ('a, ('a, 'b) lambda * 's, 'r, 'f) kinstr + | IApply : + ('a, ('a * 'b, 'c) lambda * 's) kinfo + * 'a ty + * (('b, 'c) lambda, 's, 'r, 'f) kinstr + -> ('a, ('a * 'b, 'c) lambda * 's, 'r, 'f) kinstr + | ILambda : + ('a, 's) kinfo + * ('b, 'c) lambda + * (('b, 'c) lambda, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IFailwith : + ('a, 's) kinfo * Script.location * 'a ty + -> ('a, 's, 'r, 'f) kinstr + (* + Comparison + ---------- + *) + | ICompare : + ('a, 'a * 's) kinfo * 'a comparable_ty * (z num, 's, 'r, 'f) kinstr + -> ('a, 'a * 's, 'r, 'f) kinstr + (* + Comparators + ----------- + *) + | IEq : + (z num, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | INeq : + (z num, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | ILt : + (z num, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | IGt : + (z num, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | ILe : + (z num, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + | IGe : + (z num, 's) kinfo * (bool, 's, 'r, 'f) kinstr + -> (z num, 's, 'r, 'f) kinstr + (* + Protocol + -------- + *) + | IAddress : + ('a typed_contract, 's) kinfo * (address, 's, 'r, 'f) kinstr + -> ('a typed_contract, 's, 'r, 'f) kinstr + | IContract : + (address, 's) kinfo + * 'a ty + * string + * ('a typed_contract option, 's, 'r, 'f) kinstr + -> (address, 's, 'r, 'f) kinstr + | IView : + ('a, address * 's) kinfo + * ('a, 'b) view_signature + * ('b option, 's, 'r, 'f) kinstr + -> ('a, address * 's, 'r, 'f) kinstr + | ITransfer_tokens : + ('a, Tez.t * ('a typed_contract * 's)) kinfo + * (operation, 's, 'r, 'f) kinstr + -> ('a, Tez.t * ('a typed_contract * 's), 'r, 'f) kinstr + | IImplicit_account : + (public_key_hash, 's) kinfo * (unit typed_contract, 's, 'r, 'f) kinstr + -> (public_key_hash, 's, 'r, 'f) kinstr + | ICreate_contract : { + kinfo : (public_key_hash option, Tez.t * ('a * 's)) kinfo; + storage_type : 'a ty; + arg_type : 'b ty; + lambda : ('b * 'a, operation boxed_list * 'a) lambda; + views : view SMap.t; + root_name : field_annot option; + k : (operation, address * 's, 'r, 'f) kinstr; + } + -> (public_key_hash option, Tez.t * ('a * 's), 'r, 'f) kinstr + | ISet_delegate : + (public_key_hash option, 's) kinfo * (operation, 's, 'r, 'f) kinstr + -> (public_key_hash option, 's, 'r, 'f) kinstr + | INow : + ('a, 's) kinfo * (Script_timestamp.t, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IBalance : + ('a, 's) kinfo * (Tez.t, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ILevel : + ('a, 's) kinfo * (n num, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ICheck_signature : + (public_key, signature * (bytes * 's)) kinfo * (bool, 's, 'r, 'f) kinstr + -> (public_key, signature * (bytes * 's), 'r, 'f) kinstr + | IHash_key : + (public_key, 's) kinfo * (public_key_hash, 's, 'r, 'f) kinstr + -> (public_key, 's, 'r, 'f) kinstr + | IPack : + ('a, 's) kinfo * 'a ty * (bytes, 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IUnpack : + (bytes, 's) kinfo * 'a ty * ('a option, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + | IBlake2b : + (bytes, 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + | ISha256 : + (bytes, 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + | ISha512 : + (bytes, 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + | ISource : + ('a, 's) kinfo * (address, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ISender : + ('a, 's) kinfo * (address, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ISelf : + ('a, 's) kinfo + * 'b ty + * string + * ('b typed_contract, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ISelf_address : + ('a, 's) kinfo * (address, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IAmount : + ('a, 's) kinfo * (Tez.t, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ISapling_empty_state : + ('a, 's) kinfo + * Sapling.Memo_size.t + * (Sapling.state, 'a * 's, 'b, 'f) kinstr + -> ('a, 's, 'b, 'f) kinstr + | ISapling_verify_update : + (Sapling.transaction, Sapling.state * 's) kinfo + * ((z num, Sapling.state) pair option, 's, 'r, 'f) kinstr + -> (Sapling.transaction, Sapling.state * 's, 'r, 'f) kinstr + | IDig : + ('a, 's) kinfo + (* + There is a prefix of length [n] common to the input stack + of type ['a * 's] and an intermediary stack of type ['d * 'u]. + *) + * int + (* + Under this common prefix, the input stack has type ['b * 'c * 't] and + the intermediary stack type ['c * 't] because we removed the ['b] from + the input stack. This value of type ['b] is pushed on top of the + stack passed to the continuation. + *) + * ('b, 'c * 't, 'c, 't, 'a, 's, 'd, 'u) stack_prefix_preservation_witness + * ('b, 'd * 'u, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IDug : + ('a, 'b * 's) kinfo + (* + The input stack has type ['a * 'b * 's]. + + There is a prefix of length [n] common to its substack + of type ['b * 's] and the output stack of type ['d * 'u]. + *) + * int + (* + Under this common prefix, the first stack has type ['c * 't] + and the second has type ['a * 'c * 't] because we have pushed + the topmost element of this input stack under the common prefix. + *) + * ('c, 't, 'a, 'c * 't, 'b, 's, 'd, 'u) stack_prefix_preservation_witness + * ('d, 'u, 'r, 'f) kinstr + -> ('a, 'b * 's, 'r, 'f) kinstr + | IDipn : + ('a, 's) kinfo + (* + The body of Dipn is applied under a prefix of size [n]... + *) + * int + (* + ... the relation between the types of the input and output stacks + is characterized by the following witness. + (See forthcoming comments about [stack_prefix_preservation_witness].) + *) + * ('c, 't, 'd, 'v, 'a, 's, 'b, 'u) stack_prefix_preservation_witness + * ('c, 't, 'd, 'v) kinstr + * ('b, 'u, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IDropn : + ('a, 's) kinfo + (* + The input stack enjoys a prefix of length [n]... + *) + * int + (* + ... and the following value witnesses that under this prefix + the stack has type ['b * 'u]. + *) + * ('b, 'u, 'b, 'u, 'a, 's, 'a, 's) stack_prefix_preservation_witness + (* + This stack is passed to the continuation since we drop the + entire prefix. + *) + * ('b, 'u, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IChainId : + ('a, 's) kinfo * (Chain_id.t, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | INever : (never, 's) kinfo -> (never, 's, 'r, 'f) kinstr + | IVoting_power : + (public_key_hash, 's) kinfo * (n num, 's, 'r, 'f) kinstr + -> (public_key_hash, 's, 'r, 'f) kinstr + | ITotal_voting_power : + ('a, 's) kinfo * (n num, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IKeccak : + (bytes, 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + | ISha3 : + (bytes, 's) kinfo * (bytes, 's, 'r, 'f) kinstr + -> (bytes, 's, 'r, 'f) kinstr + | IAdd_bls12_381_g1 : + (Bls12_381.G1.t, Bls12_381.G1.t * 's) kinfo + * (Bls12_381.G1.t, 's, 'r, 'f) kinstr + -> (Bls12_381.G1.t, Bls12_381.G1.t * 's, 'r, 'f) kinstr + | IAdd_bls12_381_g2 : + (Bls12_381.G2.t, Bls12_381.G2.t * 's) kinfo + * (Bls12_381.G2.t, 's, 'r, 'f) kinstr + -> (Bls12_381.G2.t, Bls12_381.G2.t * 's, 'r, 'f) kinstr + | IAdd_bls12_381_fr : + (Bls12_381.Fr.t, Bls12_381.Fr.t * 's) kinfo + * (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + -> (Bls12_381.Fr.t, Bls12_381.Fr.t * 's, 'r, 'f) kinstr + | IMul_bls12_381_g1 : + (Bls12_381.G1.t, Bls12_381.Fr.t * 's) kinfo + * (Bls12_381.G1.t, 's, 'r, 'f) kinstr + -> (Bls12_381.G1.t, Bls12_381.Fr.t * 's, 'r, 'f) kinstr + | IMul_bls12_381_g2 : + (Bls12_381.G2.t, Bls12_381.Fr.t * 's) kinfo + * (Bls12_381.G2.t, 's, 'r, 'f) kinstr + -> (Bls12_381.G2.t, Bls12_381.Fr.t * 's, 'r, 'f) kinstr + | IMul_bls12_381_fr : + (Bls12_381.Fr.t, Bls12_381.Fr.t * 's) kinfo + * (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + -> (Bls12_381.Fr.t, Bls12_381.Fr.t * 's, 'r, 'f) kinstr + | IMul_bls12_381_z_fr : + (Bls12_381.Fr.t, 'a num * 's) kinfo * (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + -> (Bls12_381.Fr.t, 'a num * 's, 'r, 'f) kinstr + | IMul_bls12_381_fr_z : + ('a num, Bls12_381.Fr.t * 's) kinfo * (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + -> ('a num, Bls12_381.Fr.t * 's, 'r, 'f) kinstr + | IInt_bls12_381_fr : + (Bls12_381.Fr.t, 's) kinfo * (z num, 's, 'r, 'f) kinstr + -> (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + | INeg_bls12_381_g1 : + (Bls12_381.G1.t, 's) kinfo * (Bls12_381.G1.t, 's, 'r, 'f) kinstr + -> (Bls12_381.G1.t, 's, 'r, 'f) kinstr + | INeg_bls12_381_g2 : + (Bls12_381.G2.t, 's) kinfo * (Bls12_381.G2.t, 's, 'r, 'f) kinstr + -> (Bls12_381.G2.t, 's, 'r, 'f) kinstr + | INeg_bls12_381_fr : + (Bls12_381.Fr.t, 's) kinfo * (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + -> (Bls12_381.Fr.t, 's, 'r, 'f) kinstr + | IPairing_check_bls12_381 : + ((Bls12_381.G1.t, Bls12_381.G2.t) pair boxed_list, 's) kinfo + * (bool, 's, 'r, 'f) kinstr + -> ((Bls12_381.G1.t, Bls12_381.G2.t) pair boxed_list, 's, 'r, 'f) kinstr + | IComb : + ('a, 's) kinfo + * int + * ('a * 's, 'b * 'u) comb_gadt_witness + * ('b, 'u, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IUncomb : + ('a, 's) kinfo + * int + * ('a * 's, 'b * 'u) uncomb_gadt_witness + * ('b, 'u, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | IComb_get : + ('t, 's) kinfo + * int + * ('t, 'v) comb_get_gadt_witness + * ('v, 's, 'r, 'f) kinstr + -> ('t, 's, 'r, 'f) kinstr + | IComb_set : + ('a, 'b * 's) kinfo + * int + * ('a, 'b, 'c) comb_set_gadt_witness + * ('c, 's, 'r, 'f) kinstr + -> ('a, 'b * 's, 'r, 'f) kinstr + | IDup_n : + ('a, 's) kinfo + * int + * ('a * 's, 't) dup_n_gadt_witness + * ('t, 'a * 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + | ITicket : + ('a, n num * 's) kinfo * ('a ticket, 's, 'r, 'f) kinstr + -> ('a, n num * 's, 'r, 'f) kinstr + | IRead_ticket : + ('a ticket, 's) kinfo + * (address * ('a * n num), 'a ticket * 's, 'r, 'f) kinstr + -> ('a ticket, 's, 'r, 'f) kinstr + | ISplit_ticket : + ('a ticket, (n num * n num) * 's) kinfo + * (('a ticket * 'a ticket) option, 's, 'r, 'f) kinstr + -> ('a ticket, (n num * n num) * 's, 'r, 'f) kinstr + | IJoin_tickets : + ('a ticket * 'a ticket, 's) kinfo + * 'a comparable_ty + * ('a ticket option, 's, 'r, 'f) kinstr + -> ('a ticket * 'a ticket, 's, 'r, 'f) kinstr + | IOpen_chest : + (Timelock.chest_key, Timelock.chest * (n num * 's)) kinfo + * ((bytes, bool) union, 's, 'r, 'f) kinstr + -> (Timelock.chest_key, Timelock.chest * (n num * 's), 'r, 'f) kinstr + (* + + Internal control instructions + ============================= + + The following instructions are not available in the source language. + They are used by the internals of the interpreter. + *) + | IHalt : ('a, 's) kinfo -> ('a, 's, 'a, 's) kinstr + | ILog : + ('a, 's) kinfo * logging_event * logger * ('a, 's, 'r, 'f) kinstr + -> ('a, 's, 'r, 'f) kinstr + +and logging_event = + | LogEntry : logging_event + | LogExit : ('b, 'u) kinfo -> logging_event + +and ('arg, 'ret) lambda = + | Lam : + ('arg, end_of_stack, 'ret, end_of_stack) kdescr * Script.node + -> ('arg, 'ret) lambda +[@@coq_force_gadt] + +and 'arg typed_contract = 'arg ty * address + +(* + + Control stack + ============= + + The control stack is a list of [kinstr]. + + Since [kinstr] denotes a list of instructions, the control stack + can be seen as a list of instruction sequences, each representing a + form of delimited continuation (i.e. a control stack fragment). The + [continuation] GADT ensures that the input and output stack types of the + continuations are consistent. + + Loops have a special treatment because their control stack is reused + as is for the next iteration. This avoids the reallocation of a + control stack cell at each iteration. + + To implement [step] as a tail-recursive function, we implement + higher-order iterators (i.e. MAPs and ITERs) using internal instructions +. Roughly speaking, these instructions help in decomposing the execution + of [I f c] (where [I] is an higher-order iterator over a container [c]) + into three phases: to start the iteration, to execute [f] if there are + elements to be processed in [c], and to loop. + + Dip also has a dedicated constructor in the control stack. This + allows the stack prefix to be restored after the execution of the + [Dip]'s body. + + Following the same style as in [kinstr], [continuation] has four + arguments, two for each stack types. More precisely, with + + [('bef_top, 'bef, 'aft_top, 'aft) continuation] + + we encode the fact that the stack before executing the continuation + has type [('bef_top * 'bef)] and that the stack after this execution + has type [('aft_top * 'aft)]. + +*) +and (_, _, _, _) continuation = + (* This continuation returns immediately. *) + | KNil : ('r, 'f, 'r, 'f) continuation + (* This continuation starts with the next instruction to execute. *) + | KCons : + ('a, 's, 'b, 't) kinstr * ('b, 't, 'r, 'f) continuation + -> ('a, 's, 'r, 'f) continuation + (* This continuation represents a call frame: it stores the caller's + stack of type ['s] and the continuation which expects the callee's + result on top of the stack. *) + | KReturn : + 's * ('a, 's, 'r, 'f) continuation + -> ('a, end_of_stack, 'r, 'f) continuation + (* This continuation comes right after a [Dip i] to restore the topmost + element ['b] of the stack after having executed [i] in the substack + of type ['a * 's]. *) + | KUndip : + 'b * ('b, 'a * 's, 'r, 'f) continuation + -> ('a, 's, 'r, 'f) continuation + (* This continuation is executed at each iteration of a loop with + a Boolean condition. *) + | KLoop_in : + ('a, 's, bool, 'a * 's) kinstr * ('a, 's, 'r, 'f) continuation + -> (bool, 'a * 's, 'r, 'f) continuation + (* This continuation is executed at each iteration of a loop with + a condition encoded by a sum type. *) + | KLoop_in_left : + ('a, 's, ('a, 'b) union, 's) kinstr * ('b, 's, 'r, 'f) continuation + -> (('a, 'b) union, 's, 'r, 'f) continuation + (* This continuation is executed at each iteration of a traversal. + (Used in List, Map and Set.) *) + | KIter : + ('a, 'b * 's, 'b, 's) kinstr * 'a list * ('b, 's, 'r, 'f) continuation + -> ('b, 's, 'r, 'f) continuation + (* This continuation represents each step of a List.map. *) + | KList_enter_body : + ('a, 'c * 's, 'b, 'c * 's) kinstr + * 'a list + * 'b list + * int + * ('b boxed_list, 'c * 's, 'r, 'f) continuation + -> ('c, 's, 'r, 'f) continuation + (* This continuation represents what is done after each step of a List.map. *) + | KList_exit_body : + ('a, 'c * 's, 'b, 'c * 's) kinstr + * 'a list + * 'b list + * int + * ('b boxed_list, 'c * 's, 'r, 'f) continuation + -> ('b, 'c * 's, 'r, 'f) continuation + (* This continuation represents each step of a Map.map. *) + | KMap_enter_body : + ('a * 'b, 'd * 's, 'c, 'd * 's) kinstr + * ('a * 'b) list + * ('a, 'c) map + * (('a, 'c) map, 'd * 's, 'r, 'f) continuation + -> ('d, 's, 'r, 'f) continuation + (* This continuation represents what is done after each step of a Map.map. *) + | KMap_exit_body : + ('a * 'b, 'd * 's, 'c, 'd * 's) kinstr + * ('a * 'b) list + * ('a, 'c) map + * 'a + * (('a, 'c) map, 'd * 's, 'r, 'f) continuation + -> ('c, 'd * 's, 'r, 'f) continuation + (* This continuation instruments the execution with a [logger]. *) + | KLog : + ('a, 's, 'r, 'f) continuation * logger + -> ('a, 's, 'r, 'f) continuation + +(* + + Execution instrumentation + ========================= + + One can observe the context and the stack at some specific points + of an execution step. This feature is implemented by calling back + some [logging_function]s defined in a record of type [logger] + passed as argument to the step function. + + A [logger] is typically embedded in an [KLog] continuation by the + client to trigger an evaluation instrumented with some logging. The + logger is then automatically propagated to the logging instruction + [ILog] as well as to any instructions that need to generate a + backtrace when it fails (e.g., [IFailwith], [IMul_teznat], ...). + +*) +and ('a, 's, 'b, 'f, 'c, 'u) logging_function = + ('a, 's, 'b, 'f) kinstr -> + context -> + Script.location -> + ('c, 'u) stack_ty -> + 'c * 'u -> + unit + +and execution_trace = + (Script.location * Gas.t * (Script.expr * string option) list) list + +and logger = { + log_interp : 'a 's 'b 'f 'c 'u. ('a, 's, 'b, 'f, 'c, 'u) logging_function; + (** [log_interp] is called at each call of the internal function + [interp]. [interp] is called when starting the interpretation of + a script and subsequently at each [Exec] instruction. *) + log_entry : 'a 's 'b 'f. ('a, 's, 'b, 'f, 'a, 's) logging_function; + (** [log_entry] is called {i before} executing each instruction but + {i after} gas for this instruction has been successfully + consumed. *) + log_control : 'a 's 'b 'f. ('a, 's, 'b, 'f) continuation -> unit; + (** [log_control] is called {i before} the interpretation of the + current continuation. *) + log_exit : 'a 's 'b 'f 'c 'u. ('a, 's, 'b, 'f, 'c, 'u) logging_function; + (** [log_exit] is called {i after} executing each instruction. *) + get_log : unit -> execution_trace option tzresult Lwt.t; + (** [get_log] allows to obtain an execution trace, if any was + produced. *) +} + +(* ---- Auxiliary types -----------------------------------------------------*) +and 'ty ty = + | Unit_t : unit ty_metadata -> unit ty + | Int_t : z num ty_metadata -> z num ty + | Nat_t : n num ty_metadata -> n num ty + | Signature_t : signature ty_metadata -> signature ty + | String_t : Script_string.t ty_metadata -> Script_string.t ty + | Bytes_t : Bytes.t ty_metadata -> bytes ty + | Mutez_t : Tez.t ty_metadata -> Tez.t ty + | Key_hash_t : public_key_hash ty_metadata -> public_key_hash ty + | Key_t : public_key ty_metadata -> public_key ty + | Timestamp_t : Script_timestamp.t ty_metadata -> Script_timestamp.t ty + | Address_t : address ty_metadata -> address ty + | Bool_t : bool ty_metadata -> bool ty + | Pair_t : + ('a ty * field_annot option * var_annot option) + * ('b ty * field_annot option * var_annot option) + * ('a, 'b) pair ty_metadata + -> ('a, 'b) pair ty + | Union_t : + ('a ty * field_annot option) + * ('b ty * field_annot option) + * ('a, 'b) union ty_metadata + -> ('a, 'b) union ty + | Lambda_t : + 'arg ty * 'ret ty * ('arg, 'ret) lambda ty_metadata + -> ('arg, 'ret) lambda ty + | Option_t : 'v ty * 'v option ty_metadata -> 'v option ty + | List_t : 'v ty * 'v boxed_list ty_metadata -> 'v boxed_list ty + | Set_t : 'v comparable_ty * 'v set ty_metadata -> 'v set ty + | Map_t : + 'k comparable_ty * 'v ty * ('k, 'v) map ty_metadata + -> ('k, 'v) map ty + | Big_map_t : + 'k comparable_ty * 'v ty * ('k, 'v) big_map ty_metadata + -> ('k, 'v) big_map ty + | Contract_t : + 'arg ty * 'arg typed_contract ty_metadata + -> 'arg typed_contract ty + | Sapling_transaction_t : + Sapling.Memo_size.t * Sapling.transaction ty_metadata + -> Sapling.transaction ty + | Sapling_state_t : + Sapling.Memo_size.t * Sapling.state ty_metadata + -> Sapling.state ty + | Operation_t : operation ty_metadata -> operation ty + | Chain_id_t : Chain_id.t ty_metadata -> Chain_id.t ty + | Never_t : never ty_metadata -> never ty + | Bls12_381_g1_t : Bls12_381.G1.t ty_metadata -> Bls12_381.G1.t ty + | Bls12_381_g2_t : Bls12_381.G2.t ty_metadata -> Bls12_381.G2.t ty + | Bls12_381_fr_t : Bls12_381.Fr.t ty_metadata -> Bls12_381.Fr.t ty + | Ticket_t : 'a comparable_ty * 'a ticket ty_metadata -> 'a ticket ty + | Chest_key_t : Timelock.chest_key ty_metadata -> Timelock.chest_key ty + | Chest_t : Timelock.chest ty_metadata -> Timelock.chest ty + +and ('top_ty, 'resty) stack_ty = + | Item_t : + 'ty ty * ('ty2, 'rest) stack_ty * var_annot option + -> ('ty, 'ty2 * 'rest) stack_ty + | Bot_t : (empty_cell, empty_cell) stack_ty + +and ('key, 'value) big_map = { + id : Big_map.Id.t option; + diff : ('key, 'value) big_map_overlay; + key_type : 'key comparable_ty; + value_type : 'value ty; +} + +and ('a, 's, 'r, 'f) kdescr = { + kloc : Script.location; + kbef : ('a, 's) stack_ty; + kaft : ('r, 'f) stack_ty; + kinstr : ('a, 's, 'r, 'f) kinstr; +} + +and ('a, 's) kinfo = {iloc : Script.location; kstack_ty : ('a, 's) stack_ty} + +(* + + Several instructions work under an arbitrary deep stack prefix + (e.g, IDipn, IDropn, etc). To convince the typechecker that + these instructions are well-typed, we must provide a witness + to statically characterize the relationship between the input + and the output stacks. The inhabitants of the following GADT + act as such witnesses. + + More precisely, a value [w] of type + + [(c, t, d, v, a, s, b, u) stack_prefix_preservation_witness] + + proves that there is a common prefix between an input stack + of type [a * s] and an output stack of type [b * u]. This prefix + is as deep as the number of [KPrefix] application in [w]. When + used with an operation parameterized by a natural number [n] + characterizing the depth at which the operation must be applied, + [w] is the Peano encoding of [n]. + + When this prefix is removed from the two stacks, the input stack + has type [c * t] while the output stack has type [d * v]. + +*) +and (_, _, _, _, _, _, _, _) stack_prefix_preservation_witness = + | KPrefix : + ('y, 'u) kinfo + * ('c, 'v, 'd, 'w, 'x, 's, 'y, 'u) stack_prefix_preservation_witness + -> ( 'c, + 'v, + 'd, + 'w, + 'a, + 'x * 's, + 'a, + 'y * 'u ) + stack_prefix_preservation_witness + | KRest : ('a, 's, 'b, 'u, 'a, 's, 'b, 'u) stack_prefix_preservation_witness + +and ('before, 'after) comb_gadt_witness = + | Comb_one : ('a * ('x * 'before), 'a * ('x * 'before)) comb_gadt_witness + | Comb_succ : + ('before, 'b * 'after) comb_gadt_witness + -> ('a * 'before, ('a * 'b) * 'after) comb_gadt_witness + +and ('before, 'after) uncomb_gadt_witness = + | Uncomb_one : ('rest, 'rest) uncomb_gadt_witness + | Uncomb_succ : + ('b * 'before, 'after) uncomb_gadt_witness + -> (('a * 'b) * 'before, 'a * 'after) uncomb_gadt_witness + +and ('before, 'after) comb_get_gadt_witness = + | Comb_get_zero : ('b, 'b) comb_get_gadt_witness + | Comb_get_one : ('a * 'b, 'a) comb_get_gadt_witness + | Comb_get_plus_two : + ('before, 'after) comb_get_gadt_witness + -> ('a * 'before, 'after) comb_get_gadt_witness + +and ('value, 'before, 'after) comb_set_gadt_witness = + | Comb_set_zero : ('value, _, 'value) comb_set_gadt_witness + | Comb_set_one : ('value, 'hd * 'tl, 'value * 'tl) comb_set_gadt_witness + | Comb_set_plus_two : + ('value, 'before, 'after) comb_set_gadt_witness + -> ('value, 'a * 'before, 'a * 'after) comb_set_gadt_witness +[@@coq_force_gadt] + +(* + + [dup_n_gadt_witness ('s, 't)] ensures that there exists at least + [n] elements in ['s] and that the [n]-th element of ['s] is of type + ['t]. Here [n] follows Peano's encoding (0 and successor). + Besides, [0] corresponds to the topmost element of ['s]. + + This relational predicate is defined by induction on [n]. + +*) +and (_, _) dup_n_gadt_witness = + | Dup_n_zero : ('a * 'rest, 'a) dup_n_gadt_witness + | Dup_n_succ : + ('stack, 'b) dup_n_gadt_witness + -> ('a * 'stack, 'b) dup_n_gadt_witness + +and ('a, 'b) view_signature = + | View_signature of { + name : Script_string.t; + input_ty : 'a ty; + output_ty : 'b ty; + } + +val kinfo_of_kinstr : ('a, 's, 'b, 'f) kinstr -> ('a, 's) kinfo + +type kinstr_rewritek = { + apply : 'b 'u 'r 'f. ('b, 'u, 'r, 'f) kinstr -> ('b, 'u, 'r, 'f) kinstr; +} + +val kinstr_rewritek : + ('a, 's, 'r, 'f) kinstr -> kinstr_rewritek -> ('a, 's, 'r, 'f) kinstr + +val unit_t : annot:type_annot option -> unit ty + +val int_t : annot:type_annot option -> z num ty + +val nat_t : annot:type_annot option -> n num ty + +val signature_t : annot:type_annot option -> signature ty + +val string_t : annot:type_annot option -> Script_string.t ty + +val bytes_t : annot:type_annot option -> Bytes.t ty + +val mutez_t : annot:type_annot option -> Tez.t ty + +val key_hash_t : annot:type_annot option -> public_key_hash ty + +val key_t : annot:type_annot option -> public_key ty + +val timestamp_t : annot:type_annot option -> Script_timestamp.t ty + +val address_t : annot:type_annot option -> address ty + +val bool_t : annot:type_annot option -> bool ty + +val pair_t : + Script.location -> + 'a ty * field_annot option * var_annot option -> + 'b ty * field_annot option * var_annot option -> + annot:type_annot option -> + ('a, 'b) pair ty tzresult + +val union_t : + Script.location -> + 'a ty * field_annot option -> + 'b ty * field_annot option -> + annot:type_annot option -> + ('a, 'b) union ty tzresult + +val union_bytes_bool_t : (Bytes.t, bool) union ty + +val lambda_t : + Script.location -> + 'arg ty -> + 'ret ty -> + annot:type_annot option -> + ('arg, 'ret) lambda ty tzresult + +val option_t : + Script.location -> 'v ty -> annot:type_annot option -> 'v option ty tzresult + +(* the quote is used to indicate where the annotation will go *) + +val option_string'_t : _ ty_metadata -> Script_string.t option ty + +val option_bytes'_t : _ ty_metadata -> Bytes.t option ty + +val option_nat_t : n num option ty + +val option_pair_nat_nat_t : (n num, n num) pair option ty + +val option_pair_nat'_nat'_t : _ ty_metadata -> (n num, n num) pair option ty + +val option_pair_nat_mutez'_t : _ ty_metadata -> (n num, Tez.t) pair option ty + +val option_pair_mutez'_mutez'_t : _ ty_metadata -> (Tez.t, Tez.t) pair option ty + +val option_pair_int'_nat_t : _ ty_metadata -> (z num, n num) pair option ty + +val option_pair_int_nat'_t : _ ty_metadata -> (z num, n num) pair option ty + +val list_t : + Script.location -> + 'v ty -> + annot:type_annot option -> + 'v boxed_list ty tzresult + +val list_operation_t : operation boxed_list ty + +val set_t : + Script.location -> + 'v comparable_ty -> + annot:type_annot option -> + 'v set ty tzresult + +val map_t : + Script.location -> + 'k comparable_ty -> + 'v ty -> + annot:type_annot option -> + ('k, 'v) map ty tzresult + +val big_map_t : + Script.location -> + 'k comparable_ty -> + 'v ty -> + annot:type_annot option -> + ('k, 'v) big_map ty tzresult + +val contract_t : + Script.location -> + 'arg ty -> + annot:type_annot option -> + 'arg typed_contract ty tzresult + +val contract_unit_t : unit typed_contract ty + +val sapling_transaction_t : + memo_size:Sapling.Memo_size.t -> + annot:type_annot option -> + Sapling.transaction ty + +val sapling_state_t : + memo_size:Sapling.Memo_size.t -> annot:type_annot option -> Sapling.state ty + +val operation_t : annot:type_annot option -> operation ty + +val chain_id_t : annot:type_annot option -> Chain_id.t ty + +val never_t : annot:type_annot option -> never ty + +val bls12_381_g1_t : annot:type_annot option -> Bls12_381.G1.t ty + +val bls12_381_g2_t : annot:type_annot option -> Bls12_381.G2.t ty + +val bls12_381_fr_t : annot:type_annot option -> Bls12_381.Fr.t ty + +val ticket_t : + Script.location -> + 'a comparable_ty -> + annot:type_annot option -> + 'a ticket ty tzresult + +val chest_key_t : annot:type_annot option -> Timelock.chest_key ty + +val chest_t : annot:type_annot option -> Timelock.chest ty + +(** + + The following functions named `X_traverse` for X in { kinstr, ty, + comparable_ty, value } provide tail recursive top down traversals + over the values of these types. + + The traversal goes through a value and rewrites an accumulator + along the way starting from some [init]ial value for the + accumulator. + + All these traversals follow the same recursion scheme: the + user-provided function is first called on the toplevel value, then + the traversal recurses on the direct subvalues of the same type. + + Hence, the user-provided function must only compute the + contribution of the value on the accumulator minus the contribution + of its subvalues of the same type. + +*) +type 'a kinstr_traverse = { + apply : 'b 'u 'r 'f. 'a -> ('b, 'u, 'r, 'f) kinstr -> 'a; +} + +val kinstr_traverse : + ('a, 'b, 'c, 'd) kinstr -> 'ret -> 'ret kinstr_traverse -> 'ret + +type 'a ty_traverse = { + apply : 't. 'a -> 't ty -> 'a; + apply_comparable : 't. 'a -> 't comparable_ty -> 'a; +} + +val comparable_ty_traverse : 'a comparable_ty -> 'r -> 'r ty_traverse -> 'r + +val ty_traverse : 'a ty -> 'r -> 'r ty_traverse -> 'r + +type 'accu stack_ty_traverse = { + apply : 'ty 's. 'accu -> ('ty, 's) stack_ty -> 'accu; +} + +val stack_ty_traverse : ('a, 's) stack_ty -> 'r -> 'r stack_ty_traverse -> 'r + +type 'a value_traverse = { + apply : 't. 'a -> 't ty -> 't -> 'a; + apply_comparable : 't. 'a -> 't comparable_ty -> 't -> 'a; +} + +val value_traverse : + ('t ty, 't comparable_ty) union -> 't -> 'r -> 'r value_traverse -> 'r + +val stack_top_ty : ('a, 'b * 's) stack_ty -> 'a ty diff --git a/src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size.ml b/src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size.ml new file mode 100644 index 000000000000..7eaf39e6b5c9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size.ml @@ -0,0 +1,766 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context +open Script_typed_ir +include Cache_memory_helpers + +let script_string_size s = Script_string.to_string s |> string_size + +(* The model assumes that annotations' sizes are counted once in the + Micheline representation and that the strings are always + shared. (One can check that they are never copied.) Besides, the + following types are unboxed so that they have no tags. *) +let type_annot_size (Type_annot _) = !!0 + +let field_annot_size (Field_annot _) = !!0 + +let var_annot_size (Var_annot _) = !!0 + +(* Memo-sizes are 16-bit integers *) +let sapling_memo_size_size = !!0 + +let (comparable_ty_size, ty_size) = + let base {annot; size = _} = hh3w +! option_size type_annot_size annot in + let apply_comparable : + type a. nodes_and_size -> a comparable_ty -> nodes_and_size = + fun accu cty -> + match cty with + | Unit_key a -> ret_succ_adding accu (base a) + | Int_key a -> ret_succ_adding accu (base a) + | Nat_key a -> ret_succ_adding accu (base a) + | Signature_key a -> ret_succ_adding accu (base a) + | String_key a -> ret_succ_adding accu (base a) + | Bytes_key a -> ret_succ_adding accu (base a) + | Mutez_key a -> ret_succ_adding accu (base a) + | Key_hash_key a -> ret_succ_adding accu (base a) + | Key_key a -> ret_succ_adding accu (base a) + | Timestamp_key a -> ret_succ_adding accu (base a) + | Address_key a -> ret_succ_adding accu (base a) + | Bool_key a -> ret_succ_adding accu (base a) + | Chain_id_key a -> ret_succ_adding accu (base a) + | Never_key a -> ret_succ_adding accu (base a) + | Pair_key ((_ty1, fa1), (_ty2, fa2), a) -> + ret_succ_adding accu + @@ base a +! hh6w + +! option_size field_annot_size fa1 + +! option_size field_annot_size fa2 + | Union_key ((_ty1, fa1), (_ty2, fa2), a) -> + ret_succ_adding accu + @@ base a +! hh6w + +! option_size field_annot_size fa1 + +! option_size field_annot_size fa2 + | Option_key (_ty, a) -> ret_succ_adding accu @@ (base a +! word_size) + and apply : type a. nodes_and_size -> a ty -> nodes_and_size = + fun accu ty -> + match ty with + | Unit_t a -> ret_succ_adding accu @@ base a + | Int_t a -> ret_succ_adding accu @@ base a + | Nat_t a -> ret_succ_adding accu @@ base a + | Signature_t a -> ret_succ_adding accu @@ base a + | String_t a -> ret_succ_adding accu @@ base a + | Bytes_t a -> ret_succ_adding accu @@ base a + | Mutez_t a -> ret_succ_adding accu @@ base a + | Key_hash_t a -> ret_succ_adding accu @@ base a + | Key_t a -> ret_succ_adding accu @@ base a + | Timestamp_t a -> ret_succ_adding accu @@ base a + | Address_t a -> ret_succ_adding accu @@ base a + | Bool_t a -> ret_succ_adding accu @@ base a + | Operation_t a -> ret_succ_adding accu @@ base a + | Chain_id_t a -> ret_succ_adding accu @@ base a + | Never_t a -> ret_succ_adding accu @@ base a + | Bls12_381_g1_t a -> ret_succ_adding accu @@ base a + | Bls12_381_g2_t a -> ret_succ_adding accu @@ base a + | Bls12_381_fr_t a -> ret_succ_adding accu @@ base a + | Chest_key_t a -> ret_succ_adding accu @@ base a + | Chest_t a -> ret_succ_adding accu @@ base a + | Pair_t ((_ty1, fa1, va1), (_ty2, fa2, va2), a) -> + ret_succ_adding accu + @@ base a +! hh8w + +! option_size field_annot_size fa1 + +! option_size var_annot_size va1 + +! option_size field_annot_size fa2 + +! option_size var_annot_size va2 + | Union_t ((_ty1, fa1), (_ty2, fa2), a) -> + ret_succ_adding accu + @@ base a +! hh6w + +! option_size field_annot_size fa1 + +! option_size field_annot_size fa2 + | Lambda_t (_ty1, _ty2, a) -> + ret_succ_adding accu @@ (base a +! (word_size *? 2)) + | Option_t (_ty, a) -> ret_succ_adding accu @@ (base a +! word_size) + | List_t (_ty, a) -> ret_succ_adding accu @@ (base a +! word_size) + | Set_t (_cty, a) -> ret_succ_adding accu @@ (base a +! word_size) + | Map_t (_cty, _ty, a) -> + ret_succ_adding accu @@ (base a +! (word_size *? 2)) + | Big_map_t (_cty, _ty, a) -> + ret_succ_adding accu @@ (base a +! (word_size *? 2)) + | Contract_t (_ty, a) -> ret_succ_adding accu @@ (base a +! word_size) + | Sapling_transaction_t (_m, a) -> + ret_succ_adding accu @@ (base a +! sapling_memo_size_size +! word_size) + | Sapling_state_t (_m, a) -> + ret_succ_adding accu @@ (base a +! sapling_memo_size_size +! word_size) + | Ticket_t (_cty, a) -> ret_succ_adding accu @@ (base a +! word_size) + in + let f = ({apply; apply_comparable} : nodes_and_size ty_traverse) in + ( (fun cty -> comparable_ty_traverse cty zero f), + fun ty -> ty_traverse ty zero f ) + +let stack_ty_size s = + let apply : type a s. nodes_and_size -> (a, s) stack_ty -> nodes_and_size = + fun accu s -> + match s with + | Bot_t -> ret_succ accu + | Item_t (ty, _, annot) -> + ret_succ_adding + (accu ++ ty_size ty) + (h3w +! option_size var_annot_size annot) + in + stack_ty_traverse s zero {apply} + +let script_nat_size n = Script_int.to_zint n |> z_size + +let script_int_size n = Script_int.to_zint n |> z_size + +let signature_size = h3w +? Signature.size + +let key_hash_size (x : Signature.public_key_hash) = + h1w + +? Signature.( + match x with + | Ed25519 _ -> Ed25519.Public_key_hash.size + | Secp256k1 _ -> Secp256k1.Public_key_hash.size + | P256 _ -> P256.Public_key_hash.size) + +let public_key_size (x : public_key) = + let ks = Signature.Public_key.size x in + h1w +? ks + +let mutez_size = h2w + +let timestamp_size x = Script_timestamp.to_zint x |> z_size + +let contract_size = Contract.in_memory_size + +let address_size ((c, s) : address) = h2w +! contract_size c +! string_size s + +let view_signature_size (View_signature {name; input_ty; output_ty}) = + ret_adding + (ty_size input_ty ++ ty_size output_ty) + (h3w +! script_string_size name) + +let script_expr_hash_size = Script_expr_hash.size + +let peano_shape_proof = + let scale = header_size +! h1w in + fun k -> scale *? k + +let stack_prefix_preservation_witness_size = + let kinfo_size = h2w in + let scale = header_size +! (h2w +! kinfo_size) in + fun k -> scale *? k + +let comb_gadt_witness_size = peano_shape_proof + +let uncomb_gadt_witness_size = peano_shape_proof + +let comb_get_gadt_witness_size = peano_shape_proof + +let comb_set_gadt_witness_size = peano_shape_proof + +let dup_n_gadt_witness_size = peano_shape_proof + +let contract_size (arg_ty, address) = + ret_adding (ty_size arg_ty) (h2w +! address_size address) + +let sapling_state_size {Sapling.id; diff; memo_size = _} = + h3w + +! option_size (fun x -> z_size (Sapling.Id.unparse_to_z x)) id + +! Sapling.diff_in_memory_size diff + +! sapling_memo_size_size + +let operation_size + (operation : + packed_internal_operation * Lazy_storage.diffs_item list option) = + let (poi, diffs) = operation in + ret_adding + (Operation.packed_internal_operation_in_memory_size poi + ++ option_size_vec Lazy_storage.diffs_in_memory_size diffs) + h2w + +let chain_id_size = h1w +? Chain_id.size + +(* [contents] is handle by the recursion scheme in [value_size] *) +let ticket_size {ticketer; contents = _; amount} = + h3w +! address_size ticketer +! script_nat_size amount + +let chest_size chest = + (* + type chest = { + locked_value : locked_value; + rsa_public : rsa_public; + ciphertext : ciphertext; + } + *) + let locked_value_size = 256 in + let rsa_public_size = 256 in + let ciphertext_size = Timelock.get_plaintext_size chest in + h3w +? (locked_value_size + rsa_public_size + ciphertext_size) + +let chest_key_size _ = + (* + type chest_key = { + unlocked_value : unlocked_value; + proof : time_lock_proof + } + *) + let unlocked_value_size = 256 in + let proof_size = 256 in + h2w +? (unlocked_value_size + proof_size) + +let view_size {input_ty; output_ty; view_code} = + ret_adding + (node_size input_ty ++ node_size output_ty ++ node_size view_code) + h3w + +let views_size views = + SMap.fold + (fun k view accu -> + ret_adding (accu ++ view_size view) (script_string_size k +! h4w)) + views + zero + +let kinfo_size {iloc = _; kstack_ty = _} = h2w + +(* The following mutually recursive functions are mostly + tail-recursive and the only recursive call that is not a tailcall + cannot be nested. (See [big_map_size].) For this reason, these + functions should not trigger stack overflows. *) +let rec value_size : + type a. + count_lambda_nodes:bool -> + nodes_and_size -> + (a ty, a comparable_ty) union -> + a -> + nodes_and_size = + fun ~count_lambda_nodes accu ty x -> + let apply : type a. nodes_and_size -> a ty -> a -> nodes_and_size = + fun accu ty x -> + match ty with + | Unit_t _ -> ret_succ accu + | Int_t _ -> ret_succ_adding accu (script_int_size x) + | Nat_t _ -> ret_succ_adding accu (script_nat_size x) + | Signature_t _ -> ret_succ_adding accu signature_size + | String_t _ -> ret_succ_adding accu (script_string_size x) + | Bytes_t _ -> ret_succ_adding accu (bytes_size x) + | Mutez_t _ -> ret_succ_adding accu mutez_size + | Key_hash_t _ -> ret_succ_adding accu (key_hash_size x) + | Key_t _ -> ret_succ_adding accu (public_key_size x) + | Timestamp_t _ -> ret_succ_adding accu (timestamp_size x) + | Address_t _ -> ret_succ_adding accu (address_size x) + | Bool_t _ -> ret_succ accu + | Pair_t (_, _, _) -> ret_succ_adding accu h2w + | Union_t (_, _, _) -> ret_succ_adding accu h1w + | Lambda_t (_, _, _) -> + (lambda_size [@ocaml.tailcall]) ~count_lambda_nodes (ret_succ accu) x + | Option_t (_, _) -> ret_succ_adding accu (option_size (fun _ -> !!0) x) + | List_t (_, _) -> ret_succ_adding accu (h2w +! (h2w *? x.length)) + | Set_t (_, _) -> + let module M = (val x) in + let boxing_space = !!300 in + ret_succ_adding accu (boxing_space +! (h4w *? M.size)) + | Map_t (_, _, _) -> + let module M = (val x) in + let size = snd M.boxed in + let boxing_space = !!300 in + ret_succ_adding accu (boxing_space +! (h5w *? size)) + | Big_map_t (cty, ty', _) -> + (big_map_size [@ocaml.tailcall]) + ~count_lambda_nodes + (ret_succ accu) + cty + ty' + x + | Contract_t (_, _) -> ret_succ (accu ++ contract_size x) + | Sapling_transaction_t (_, _) -> + ret_succ_adding accu (Sapling.transaction_in_memory_size x) + | Sapling_state_t (_, _) -> ret_succ_adding accu (sapling_state_size x) + | Operation_t _ -> ret_succ (accu ++ operation_size x) + | Chain_id_t _ -> ret_succ_adding accu chain_id_size + | Never_t _ -> ( match x with _ -> .) + | Bls12_381_g1_t _ -> ret_succ_adding accu !!Bls12_381.G1.size_in_bytes + | Bls12_381_g2_t _ -> ret_succ_adding accu !!Bls12_381.G2.size_in_bytes + | Bls12_381_fr_t _ -> ret_succ_adding accu !!Bls12_381.Fr.size_in_bytes + | Ticket_t (_, _) -> ret_succ_adding accu (ticket_size x) + | Chest_key_t _ -> ret_succ_adding accu (chest_key_size x) + | Chest_t _ -> ret_succ_adding accu (chest_size x) + in + let apply_comparable : + type a. nodes_and_size -> a comparable_ty -> a -> nodes_and_size = + fun accu ty x -> + match ty with + | Unit_key _ -> ret_succ accu + | Int_key _ -> ret_succ_adding accu (script_int_size x) + | Nat_key _ -> ret_succ_adding accu (script_nat_size x) + | Signature_key _ -> ret_succ_adding accu signature_size + | String_key _ -> ret_succ_adding accu (script_string_size x) + | Bytes_key _ -> ret_succ_adding accu (bytes_size x) + | Mutez_key _ -> ret_succ_adding accu mutez_size + | Key_hash_key _ -> ret_succ_adding accu (key_hash_size x) + | Key_key _ -> ret_succ_adding accu (public_key_size x) + | Timestamp_key _ -> ret_succ_adding accu (timestamp_size x) + | Address_key _ -> ret_succ_adding accu (address_size x) + | Bool_key _ -> ret_succ accu + | Pair_key (_, _, _) -> ret_succ_adding accu h2w + | Union_key (_, _, _) -> ret_succ_adding accu h1w + | Option_key (_, _) -> ret_succ_adding accu (option_size (fun _ -> !!0) x) + | Chain_id_key _ -> ret_succ_adding accu chain_id_size + | Never_key _ -> ( match x with _ -> .) + in + value_traverse ty x accu {apply; apply_comparable} + [@@coq_axiom_with_reason "unreachable expressions '.' not handled for now"] + +and big_map_size : + type a b. + count_lambda_nodes:bool -> + nodes_and_size -> + a comparable_ty -> + b ty -> + (a, b) big_map -> + nodes_and_size = + fun ~count_lambda_nodes accu cty ty' {id; diff; key_type; value_type} -> + (* [Map.bindings] cannot overflow and only consumes a + logarithmic amount of stack. *) + let diff_size = + let map_size = + Big_map_overlay.fold + (fun _key_hash (key, value) accu -> + let accu = ret_succ_adding accu !!script_expr_hash_size in + (* The following recursive call cannot introduce a stack + overflow because this would require a key of type + big_map while big_map is not comparable. *) + let accu = value_size ~count_lambda_nodes accu (R cty) key in + match value with + | None -> accu + | Some value -> + (value_size [@ocaml.tailcall]) + ~count_lambda_nodes + accu + (L ty') + value) + diff.map + accu + in + + ret_adding map_size h2w + in + let big_map_id_size s = z_size (Big_map.Id.unparse_to_z s) in + let id_size = option_size big_map_id_size id in + ret_adding + (comparable_ty_size key_type ++ ty_size value_type ++ diff_size) + (h4w +! id_size) + +and lambda_size : + type i o. + count_lambda_nodes:bool -> nodes_and_size -> (i, o) lambda -> nodes_and_size + = + fun ~count_lambda_nodes accu (Lam (kdescr, node)) -> + (* We assume that the nodes' size have already been counted if the + lambda is not a toplevel lambda. *) + let accu = + ret_adding (accu ++ if count_lambda_nodes then node_size node else zero) h2w + in + (kdescr_size [@ocaml.tailcall]) ~count_lambda_nodes:false accu kdescr + +and kdescr_size : + type a s r f. + count_lambda_nodes:bool -> + nodes_and_size -> + (a, s, r, f) kdescr -> + nodes_and_size = + fun ~count_lambda_nodes accu {kloc = _; kbef; kaft; kinstr} -> + let accu = + ret_adding (accu ++ stack_ty_size kbef ++ stack_ty_size kaft) h4w + in + (kinstr_size [@ocaml.tailcall]) ~count_lambda_nodes accu kinstr + +and kinstr_size : + type a s r f. + count_lambda_nodes:bool -> + nodes_and_size -> + (a, s, r, f) kinstr -> + nodes_and_size = + fun ~count_lambda_nodes accu t -> + let base kinfo = h2w +! kinfo_size kinfo in + let apply : + type a s r f. nodes_and_size -> (a, s, r, f) kinstr -> nodes_and_size = + fun accu t -> + match t with + | IDrop (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IDup (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISwap (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IConst (kinfo, x, k) -> + let accu = ret_succ_adding accu (base kinfo +! word_size) in + (value_size [@ocaml.tailcall]) + ~count_lambda_nodes + accu + (L (stack_top_ty (kinfo_of_kinstr k).kstack_ty)) + x + | ICons_pair (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ICar (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ICdr (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IUnpair (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ICons_some (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ICons_none (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IIf_none {kinfo; _} -> ret_succ_adding accu (base kinfo) + | ICons_left (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ICons_right (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IIf_left {kinfo; _} -> ret_succ_adding accu (base kinfo) + | ICons_list (kinfo, _) -> ret_succ_adding accu (base kinfo) + | INil (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IIf_cons {kinfo; _} -> ret_succ_adding accu (base kinfo) + | IList_map (kinfo, _, _) -> ret_succ_adding accu (base kinfo) + | IList_iter (kinfo, _, _) -> ret_succ_adding accu (base kinfo) + | IList_size (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IEmpty_set (kinfo, cty, _) -> + ret_succ_adding + (accu ++ comparable_ty_size cty) + (base kinfo +! word_size) + | ISet_iter (kinfo, _, _) -> ret_succ_adding accu (base kinfo) + | ISet_mem (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISet_update (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISet_size (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IEmpty_map (kinfo, cty, _) -> + ret_succ_adding + (accu ++ comparable_ty_size cty) + (base kinfo +! word_size) + | IMap_map (kinfo, _, _) -> ret_succ_adding accu (base kinfo +! word_size) + | IMap_iter (kinfo, _, _) -> ret_succ_adding accu (base kinfo +! word_size) + | IMap_mem (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMap_get (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMap_update (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMap_get_and_update (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMap_size (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IEmpty_big_map (kinfo, cty, ty, _) -> + ret_succ_adding + (accu ++ comparable_ty_size cty ++ ty_size ty) + (base kinfo +! (word_size *? 2)) + | IBig_map_mem (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IBig_map_get (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IBig_map_update (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IBig_map_get_and_update (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IConcat_string (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IConcat_string_pair (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISlice_string (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IString_size (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IConcat_bytes (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IConcat_bytes_pair (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISlice_bytes (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IBytes_size (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAdd_seconds_to_timestamp (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAdd_timestamp_to_seconds (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISub_timestamp_seconds (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IDiff_timestamps (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAdd_tez (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISub_tez (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMul_teznat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMul_nattez (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IEdiv_teznat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IEdiv_tez (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IOr (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAnd (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IXor (kinfo, _) -> ret_succ_adding accu (base kinfo) + | INot (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IIs_nat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | INeg_nat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | INeg_int (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAbs_int (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IInt_nat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAdd_intint (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAdd_intnat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAdd_natint (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAdd_natnat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISub_int (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMul_intint (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMul_intnat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMul_natint (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMul_natnat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IEdiv_intint (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IEdiv_intnat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IEdiv_natint (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IEdiv_natnat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ILsl_nat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ILsr_nat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IOr_nat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAnd_nat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAnd_int_nat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IXor_nat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | INot_nat (kinfo, _) -> ret_succ_adding accu (base kinfo) + | INot_int (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IIf {kinfo; _} -> ret_succ_adding accu (base kinfo) + | ILoop (kinfo, _, _) -> ret_succ_adding accu (base kinfo) + | ILoop_left (kinfo, _, _) -> ret_succ_adding accu (base kinfo +! word_size) + | IDip (kinfo, _, _) -> ret_succ_adding accu (base kinfo +! word_size) + | IExec (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IApply (kinfo, ty, _) -> + ret_succ_adding (accu ++ ty_size ty) (base kinfo +! word_size) + | ILambda (kinfo, lambda, _) -> + let accu = ret_succ_adding accu (base kinfo +! word_size) in + (lambda_size [@ocaml.tailcall]) ~count_lambda_nodes accu lambda + | IFailwith (kinfo, _, ty) -> + ret_succ_adding (accu ++ ty_size ty) (base kinfo +! word_size) + | ICompare (kinfo, cty, _) -> + ret_succ_adding + (accu ++ comparable_ty_size cty) + (base kinfo +! word_size) + | IEq (kinfo, _) -> ret_succ_adding accu (base kinfo) + | INeq (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ILt (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IGt (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ILe (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IGe (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAddress (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IContract (kinfo, ty, s, _) -> + ret_succ_adding + (accu ++ ty_size ty) + (base kinfo +! string_size s +! (word_size *? 2)) + | IView (kinfo, s, _) -> + ret_succ_adding (accu ++ view_signature_size s) (base kinfo +! word_size) + | ITransfer_tokens (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IImplicit_account (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ICreate_contract + {kinfo; storage_type; arg_type; lambda; root_name; views; k = _} -> + let accu = + ret_succ_adding + (accu ++ ty_size storage_type ++ ty_size arg_type + ++ views_size views) + (base kinfo +! (word_size *? 4) + +! option_size field_annot_size root_name) + in + (lambda_size [@ocaml.tailcall]) ~count_lambda_nodes accu lambda + | ISet_delegate (kinfo, _) -> ret_succ_adding accu (base kinfo) + | INow (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IBalance (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ILevel (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ICheck_signature (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IHash_key (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IPack (kinfo, ty, _) -> + ret_succ_adding (accu ++ ty_size ty) (base kinfo +! word_size) + | IUnpack (kinfo, ty, _) -> + ret_succ_adding (accu ++ ty_size ty) (base kinfo +! word_size) + | IBlake2b (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISha256 (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISha512 (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISource (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISender (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISelf (kinfo, ty, s, _) -> + ret_succ_adding + (accu ++ ty_size ty) + (base kinfo +! (word_size *? 2) +! string_size s) + | ISelf_address (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAmount (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISapling_empty_state (kinfo, _m, _) -> + ret_succ_adding accu (base kinfo +! word_size +! sapling_memo_size_size) + | ISapling_verify_update (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IDig (kinfo, n, _, _) -> + ret_succ_adding + accu + (base kinfo +! (word_size *? 2) + +! stack_prefix_preservation_witness_size n) + | IDug (kinfo, n, _, _) -> + ret_succ_adding + accu + (base kinfo +! (word_size *? 2) + +! stack_prefix_preservation_witness_size n) + | IDipn (kinfo, n, _, _, _) -> + ret_succ_adding + accu + (base kinfo +! (word_size *? 2) + +! stack_prefix_preservation_witness_size n) + | IDropn (kinfo, n, _, _) -> + ret_succ_adding + accu + (base kinfo +! (word_size *? 2) + +! stack_prefix_preservation_witness_size n) + | IChainId (kinfo, _) -> ret_succ_adding accu (base kinfo) + | INever kinfo -> ret_succ_adding accu (kinfo_size kinfo) + | IVoting_power (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ITotal_voting_power (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IKeccak (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISha3 (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAdd_bls12_381_g1 (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAdd_bls12_381_g2 (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IAdd_bls12_381_fr (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMul_bls12_381_g1 (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMul_bls12_381_g2 (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMul_bls12_381_fr (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMul_bls12_381_z_fr (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IMul_bls12_381_fr_z (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IInt_bls12_381_fr (kinfo, _) -> ret_succ_adding accu (base kinfo) + | INeg_bls12_381_g1 (kinfo, _) -> ret_succ_adding accu (base kinfo) + | INeg_bls12_381_g2 (kinfo, _) -> ret_succ_adding accu (base kinfo) + | INeg_bls12_381_fr (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IPairing_check_bls12_381 (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IComb (kinfo, n, _, _) -> + ret_succ_adding + accu + (base kinfo +! (word_size *? 2) +! comb_gadt_witness_size n) + | IUncomb (kinfo, n, _, _) -> + ret_succ_adding + accu + (base kinfo +! (word_size *? 2) +! uncomb_gadt_witness_size n) + | IComb_get (kinfo, n, _, _) -> + ret_succ_adding + accu + (base kinfo +! (word_size *? 2) +! comb_get_gadt_witness_size n) + | IComb_set (kinfo, n, _, _) -> + ret_succ_adding + accu + (base kinfo +! (word_size *? 2) +! comb_set_gadt_witness_size n) + | IDup_n (kinfo, n, _, _) -> + ret_succ_adding + accu + (base kinfo +! (word_size *? 2) +! dup_n_gadt_witness_size n) + | ITicket (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IRead_ticket (kinfo, _) -> ret_succ_adding accu (base kinfo) + | ISplit_ticket (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IJoin_tickets (kinfo, cty, _) -> + ret_succ_adding + (accu ++ comparable_ty_size cty) + (base kinfo +! word_size) + | IOpen_chest (kinfo, _) -> ret_succ_adding accu (base kinfo) + | IHalt kinfo -> ret_succ_adding accu (h1w +! kinfo_size kinfo) + | ILog (_, _, _, _) -> + (* This instruction is ignored because it is only used for testing. *) + accu + in + kinstr_traverse t accu {apply} + +let rec kinstr_extra_size : type a s r f. (a, s, r, f) kinstr -> nodes_and_size + = + fun t -> + let ret_zero x = (Nodes.zero, x) in + let apply : + type a s r f. nodes_and_size -> (a, s, r, f) kinstr -> nodes_and_size = + fun accu t -> + let stack_prefix_preservation_witness_size n = ret_zero (!!24 *? n) in + let dup_n_gadt_witness_size n = ret_zero (!!16 *? n) in + let comb n = ret_zero (!!16 *? n) in + let if_join k = + let kinfo = Script_typed_ir.kinfo_of_kinstr k in + stack_ty_size kinfo.kstack_ty + in + let self_size = + match t with + (* Op n *) + | IDig (_, n, _, _) -> stack_prefix_preservation_witness_size n + | IDug (_, n, _, _) -> stack_prefix_preservation_witness_size n + | IDipn (_, n, _, _, _) -> stack_prefix_preservation_witness_size n + | IDropn (_, n, _, _) -> stack_prefix_preservation_witness_size n + | IComb (_, n, _, _) -> comb n + | IUncomb (_, n, _, _) -> comb n + | IComb_get (_, n, _, _) -> comb (n / 2) + | IComb_set (_, n, _, _) -> comb (n / 2) + | IDup_n (_, n, _, _) -> dup_n_gadt_witness_size n + (* Whole stack types after conditionals and loops. *) + | IIf {k; _} -> if_join k + | IIf_cons {k; _} -> if_join k + | IIf_none {k; _} -> if_join k + | IIf_left {k; _} -> if_join k + (* Every instruction whose elaboration uses [merge_types], + [check_item_ty], [comparable_of_ty], or [ty_of_comparable_ty] + to create a type that is embedded in the IR. *) + | IJoin_tickets (_, _, k) -> ( + let kinfo = Script_typed_ir.kinfo_of_kinstr k in + match kinfo.kstack_ty with Item_t (ty, _, _) -> ty_size ty) + | ITicket (_, k) -> ( + let kinfo = Script_typed_ir.kinfo_of_kinstr k in + match kinfo.kstack_ty with Item_t (ty, _, _) -> ty_size ty) + | IRead_ticket (_, k) -> ( + let kinfo = Script_typed_ir.kinfo_of_kinstr k in + match kinfo.kstack_ty with Item_t (ty, _, _) -> ty_size ty) + | ICons_list (_, k) -> ( + let kinfo = Script_typed_ir.kinfo_of_kinstr k in + match kinfo.kstack_ty with Item_t (ty, _, _) -> ty_size ty) + | IMap_update (_, k) -> ( + let kinfo = Script_typed_ir.kinfo_of_kinstr k in + match kinfo.kstack_ty with Item_t (ty, _, _) -> ty_size ty) + | IMap_get_and_update (_, k) -> ( + let kinfo = Script_typed_ir.kinfo_of_kinstr k in + match kinfo.kstack_ty with Item_t (ty, _, _) -> ty_size ty) + | IBig_map_get_and_update (_, k) -> ( + let kinfo = Script_typed_ir.kinfo_of_kinstr k in + match kinfo.kstack_ty with Item_t (ty, _, _) -> ty_size ty) + | IApply (_, ty, _) -> ty_size ty + | ICompare (_, ty, _) -> comparable_ty_size ty + | IList_iter (_, body, _) -> ( + let kinfo = Script_typed_ir.kinfo_of_kinstr body in + match kinfo.kstack_ty with Item_t (ty, _, _) -> ty_size ty) + | IList_map (_, body, _) -> ( + let kinfo = Script_typed_ir.kinfo_of_kinstr body in + match kinfo.kstack_ty with Item_t (ty, _, _) -> ty_size ty) + | ISet_iter (_, body, _) -> ( + let kinfo = Script_typed_ir.kinfo_of_kinstr body in + match kinfo.kstack_ty with Item_t (ty, _, _) -> ty_size ty) + | IMap_map (_, body, _) -> ( + let kinfo = Script_typed_ir.kinfo_of_kinstr body in + match kinfo.kstack_ty with Item_t (ty, _, _) -> ty_size ty) + | IMap_iter (_, body, _) -> ( + let kinfo = Script_typed_ir.kinfo_of_kinstr body in + match kinfo.kstack_ty with Item_t (ty, _, _) -> ty_size ty) + | ILambda (_, lambda, _) -> lambda_extra_size lambda + | ICreate_contract {lambda; _} -> lambda_extra_size lambda + | _ -> zero + in + ret_succ (accu ++ self_size) + in + kinstr_traverse t zero {apply} + +and lambda_extra_size : type i o. (i, o) lambda -> nodes_and_size = + fun (Lam ({kinstr; _}, _)) -> kinstr_extra_size kinstr + +let lambda_size lam = + (* + + The following formula has been obtained through a regression + over the corpus of mainnet contracts in Granada. + + *) + let (lambda_nodes, lambda_size) = + lambda_size ~count_lambda_nodes:true zero lam + in + let (lambda_extra_size_nodes, lambda_extra_size) = lambda_extra_size lam in + let size = (lambda_size *? 157 /? 100) +! (lambda_extra_size *? 18 /? 100) in + (Nodes.add lambda_nodes lambda_extra_size_nodes, size) + +let kinstr_size kinstr = + let (kinstr_extra_size_nodes, kinstr_extra_size) = kinstr_extra_size kinstr in + let (kinstr_nodes, kinstr_size) = + kinstr_size ~count_lambda_nodes:true zero kinstr + in + let size = (kinstr_size *? 157 /? 100) +! (kinstr_extra_size *? 18 /? 100) in + (Nodes.add kinstr_nodes kinstr_extra_size_nodes, size) + +let value_size ty x = value_size ~count_lambda_nodes:true zero (L ty) x diff --git a/src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size.mli b/src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size.mli new file mode 100644 index 000000000000..5cdbb052e0e1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size.mli @@ -0,0 +1,71 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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 overapproximation of memory footprint for + Michelson-related values. + + These overapproximations are used by the cache to evaluate its own + memory footprint and enforce declared limit over its size. + +*) + +(** [value_size ty v] returns an overapproximation of the size of the + in-memory representation of [v] of type [ty]. *) +val value_size : + 'a Script_typed_ir.ty -> 'a -> Cache_memory_helpers.nodes_and_size + +(** [ty_size ty] returns an overapproximation of the size of the + in-memory representation of type [ty]. *) +val ty_size : 'a Script_typed_ir.ty -> Cache_memory_helpers.nodes_and_size + +(** [comparable_ty_size cty] returns an overapproximation of the size + of the in-memory representation of comparable type [cty]. *) +val comparable_ty_size : + 'a Script_typed_ir.comparable_ty -> Cache_memory_helpers.nodes_and_size + +(** [lambda_size l] returns an overapproximation of the size of the + internal IR for the Michelson lambda abstraction [l]. *) +val lambda_size : + ('a, 'b) Script_typed_ir.lambda -> Cache_memory_helpers.nodes_and_size + +(** [kinstr_size i] returns an overapproximation of the size of the + internal IR [i]. *) +val kinstr_size : + ('a, 's, 'r, 'f) Script_typed_ir.kinstr -> Cache_memory_helpers.nodes_and_size + +(** [node_size root] returns the size of the in-memory representation + of [root] in bytes. This is an over-approximation of the memory + actually consumed by [root] since no sharing is taken into + account. *) +val node_size : Script_repr.node -> Cache_memory_helpers.nodes_and_size + +(** Pointwise addition (reexport from {!Cache_memory_helpers}) *) +val ( ++ ) : + Cache_memory_helpers.nodes_and_size -> + Cache_memory_helpers.nodes_and_size -> + Cache_memory_helpers.nodes_and_size + +(** Zero vector (reexport from {!Cache_memory_helpers}) *) +val zero : Cache_memory_helpers.nodes_and_size diff --git a/src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size_costs.ml b/src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size_costs.ml new file mode 100644 index 000000000000..b2e4a9af007c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size_costs.ml @@ -0,0 +1,34 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module S = Saturation_repr + +(** FIXME insert proper gas constants (the gas constant below was fitted on + a non-standard machine) *) +let nodes_cost ~nodes = + let open S in + let nodes = Cache_memory_helpers.Nodes.to_int nodes in + let coeff = safe_int 45 in + Gas_limit_repr.atomic_step_cost (mul coeff (S.safe_int nodes)) diff --git a/src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size_costs.mli b/src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size_costs.mli new file mode 100644 index 000000000000..9789e3d104af --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/script_typed_ir_size_costs.mli @@ -0,0 +1,28 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** [node_size_cost ~nodes] returns the cost of having called + a function in {!Script_typed_ir_size} that returned [nodes]. *) +val nodes_cost : nodes:Cache_memory_helpers.Nodes.t -> Gas_limit_repr.cost diff --git a/src/proto_011_PtHangzH/lib_protocol/seed_repr.ml b/src/proto_011_PtHangzH/lib_protocol/seed_repr.ml new file mode 100644 index 000000000000..cae0b6bf2844 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/seed_repr.ml @@ -0,0 +1,132 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Tezos Protocol Implementation - Random number generation *) + +type seed = B of State_hash.t + +type t = T of State_hash.t + +type sequence = S of State_hash.t + +type nonce = bytes + +let nonce_encoding = Data_encoding.Fixed.bytes Constants_repr.nonce_length + +let initial_seed = "Laissez-faire les proprietaires." + +let zero_bytes = Bytes.make Nonce_hash.size '\000' + +let state_hash_encoding = + let open Data_encoding in + conv State_hash.to_bytes State_hash.of_bytes_exn (Fixed.bytes Nonce_hash.size) + +let seed_encoding = + let open Data_encoding in + conv (fun (B b) -> b) (fun b -> B b) state_hash_encoding + +let empty = B (State_hash.hash_string [initial_seed]) + +let nonce (B state) nonce = + B (State_hash.hash_bytes [State_hash.to_bytes state; nonce]) + +let initialize_new (B state) append = + T (State_hash.hash_bytes (State_hash.to_bytes state :: zero_bytes :: append)) + +let xor_higher_bits i b = + let higher = TzEndian.get_int32 b 0 in + let r = Int32.logxor higher i in + let res = Bytes.copy b in + TzEndian.set_int32 res 0 r ; + res + +let sequence (T state) n = + State_hash.to_bytes state |> xor_higher_bits n |> fun b -> + S (State_hash.hash_bytes [b]) + +let take (S state) = + let b = State_hash.to_bytes state in + let h = State_hash.hash_bytes [b] in + (State_hash.to_bytes h, S h) + +let take_int32 s bound = + if Compare.Int32.(bound <= 0l) then invalid_arg "Seed_repr.take_int32" + (* FIXME *) + else + let rec loop s = + let (bytes, s) = take s in + let r = Int32.abs (TzEndian.get_int32 bytes 0) in + let drop_if_over = + Int32.sub Int32.max_int (Int32.rem Int32.max_int bound) + in + if Compare.Int32.(r >= drop_if_over) then loop s + else + let v = Int32.rem r bound in + (v, s) + in + loop s + +type error += Unexpected_nonce_length (* `Permanent *) + +let () = + register_error_kind + `Permanent + ~id:"unexpected_nonce_length" + ~title:"Unexpected nonce length" + ~description:"Nonce length is incorrect." + ~pp:(fun ppf () -> + Format.fprintf + ppf + "Nonce length is not %i bytes long as it should." + Constants_repr.nonce_length) + Data_encoding.empty + (function Unexpected_nonce_length -> Some () | _ -> None) + (fun () -> Unexpected_nonce_length) + +let make_nonce nonce = + if Compare.Int.(Bytes.length nonce <> Constants_repr.nonce_length) then + error Unexpected_nonce_length + else ok nonce + +let hash nonce = Nonce_hash.hash_bytes [nonce] + +let check_hash nonce hash = + Compare.Int.(Bytes.length nonce = Constants_repr.nonce_length) + && Nonce_hash.equal (Nonce_hash.hash_bytes [nonce]) hash + +let nonce_hash_key_part = Nonce_hash.to_path + +let initial_nonce_0 = zero_bytes + +let initial_nonce_hash_0 = hash initial_nonce_0 + +let deterministic_seed seed = nonce seed zero_bytes + +let initial_seeds n = + let[@coq_struct "i"] rec loop acc elt i = + if Compare.Int.(i = 1) then List.rev (elt :: acc) + else loop (elt :: acc) (deterministic_seed elt) (i - 1) + in + loop [] (B (State_hash.hash_bytes [])) n diff --git a/src/proto_011_PtHangzH/lib_protocol/seed_repr.mli b/src/proto_011_PtHangzH/lib_protocol/seed_repr.mli new file mode 100644 index 000000000000..a067ac9d2952 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/seed_repr.mli @@ -0,0 +1,100 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Tezos Protocol Implementation - Random number generation + + This is not expected to be a good cryptographic random number + generator. In particular this is supposed to be used in situations + where the seed is a globally known information. + + The only expected property is: It should be difficult to find a + seed such that the generated sequence is a given one. *) + +(** {2 Random Generation} *) + +(** The state of the random number generator *) +type t + +(** A random seed, to derive random sequences from *) +type seed + +(** A random sequence, to derive random values from *) +type sequence + +(** [initialize_new state ident] returns a new generator *) +val initialize_new : seed -> bytes list -> t + +(** [sequence state n] prepares the n-th sequence of a state *) +val sequence : t -> int32 -> sequence + +(** Generates the next random value in the sequence *) +val take : sequence -> bytes * sequence + +(** Generates the next random value as a bounded [int32] *) +val take_int32 : sequence -> int32 -> int32 * sequence + +(** {2 Predefined seeds} *) + +val empty : seed + +(** Returns a new seed by hashing the one passed with a constant. *) +val deterministic_seed : seed -> seed + +(** [initial_seeds n] generates the first [n] seeds for which there are no nonces. + The first seed is a constant value. The kth seed is the hash of seed (k-1) + concatenated with a constant. *) +val initial_seeds : int -> seed list + +(** {2 Entropy} *) + +(** A nonce for adding entropy to the generator *) +type nonce + +(** Add entropy to the seed generator *) +val nonce : seed -> nonce -> seed + +(** Use a byte sequence as a nonce *) +val make_nonce : bytes -> nonce tzresult + +(** Compute the has of a nonce *) +val hash : nonce -> Nonce_hash.t + +(** [check_hash nonce hash] is true if the nonce correspond to the hash *) +val check_hash : nonce -> Nonce_hash.t -> bool + +(** For using nonce hashes as keys in the hierarchical database *) +val nonce_hash_key_part : Nonce_hash.t -> string list -> string list + +(** {2 Predefined nonce} *) + +val initial_nonce_0 : nonce + +val initial_nonce_hash_0 : Nonce_hash.t + +(** {2 Serializers} *) + +val nonce_encoding : nonce Data_encoding.t + +val seed_encoding : seed Data_encoding.t diff --git a/src/proto_011_PtHangzH/lib_protocol/seed_storage.ml b/src/proto_011_PtHangzH/lib_protocol/seed_storage.ml new file mode 100644 index 000000000000..12a2aa4b4299 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/seed_storage.ml @@ -0,0 +1,132 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += + | Unknown of { + oldest : Cycle_repr.t; + cycle : Cycle_repr.t; + latest : Cycle_repr.t; + } + +(* `Permanent *) + +let () = + register_error_kind + `Permanent + ~id:"seed.unknown_seed" + ~title:"Unknown seed" + ~description:"The requested seed is not available" + ~pp:(fun ppf (oldest, cycle, latest) -> + if Cycle_repr.(cycle < oldest) then + Format.fprintf + ppf + "The seed for cycle %a has been cleared from the context (oldest \ + known seed is for cycle %a)" + Cycle_repr.pp + cycle + Cycle_repr.pp + oldest + else + Format.fprintf + ppf + "The seed for cycle %a has not been computed yet (latest known seed \ + is for cycle %a)" + Cycle_repr.pp + cycle + Cycle_repr.pp + latest) + Data_encoding.( + obj3 + (req "oldest" Cycle_repr.encoding) + (req "requested" Cycle_repr.encoding) + (req "latest" Cycle_repr.encoding)) + (function + | Unknown {oldest; cycle; latest} -> Some (oldest, cycle, latest) + | _ -> None) + (fun (oldest, cycle, latest) -> Unknown {oldest; cycle; latest}) + +let compute_for_cycle c ~revealed cycle = + match Cycle_repr.pred cycle with + | None -> assert false (* should not happen *) + | Some previous_cycle -> + let levels = Level_storage.levels_with_commitments_in_cycle c revealed in + let combine (c, random_seed, unrevealed) level = + Storage.Seed.Nonce.get c level >>=? function + | Revealed nonce -> + Storage.Seed.Nonce.remove_existing c level >|=? fun c -> + (c, Seed_repr.nonce random_seed nonce, unrevealed) + | Unrevealed u -> + Storage.Seed.Nonce.remove_existing c level >|=? fun c -> + (c, random_seed, u :: unrevealed) + in + Storage.Seed.For_cycle.get c previous_cycle >>=? fun prev_seed -> + let seed = Seed_repr.deterministic_seed prev_seed in + List.fold_left_es combine (c, seed, []) levels + >>=? fun (c, seed, unrevealed) -> + Storage.Seed.For_cycle.init c cycle seed >|=? fun c -> (c, unrevealed) + +let for_cycle ctxt cycle = + let preserved = Constants_storage.preserved_cycles ctxt in + let current_level = Level_storage.current ctxt in + let current_cycle = current_level.cycle in + let latest = + if Cycle_repr.(current_cycle = root) then + Cycle_repr.add current_cycle (preserved + 1) + else Cycle_repr.add current_cycle preserved + in + let oldest = + match Cycle_repr.sub current_cycle preserved with + | None -> Cycle_repr.root + | Some oldest -> oldest + in + error_unless + Cycle_repr.(oldest <= cycle && cycle <= latest) + (Unknown {oldest; cycle; latest}) + >>?= fun () -> Storage.Seed.For_cycle.get ctxt cycle + +let clear_cycle c cycle = Storage.Seed.For_cycle.remove_existing c cycle + +let init ctxt = + let preserved = Constants_storage.preserved_cycles ctxt in + List.fold_left_es + (fun (c, ctxt) seed -> + let cycle = Cycle_repr.of_int32_exn (Int32.of_int c) in + Storage.Seed.For_cycle.init ctxt cycle seed >|=? fun ctxt -> (c + 1, ctxt)) + (0, ctxt) + (Seed_repr.initial_seeds (preserved + 2)) + >|=? snd + +let cycle_end ctxt last_cycle = + let preserved = Constants_storage.preserved_cycles ctxt in + (match Cycle_repr.sub last_cycle preserved with + | None -> return ctxt + | Some cleared_cycle -> clear_cycle ctxt cleared_cycle) + >>=? fun ctxt -> + match Cycle_repr.pred last_cycle with + | None -> return (ctxt, []) + | Some revealed -> + (* cycle with revelations *) + let inited_seed_cycle = Cycle_repr.add last_cycle (preserved + 1) in + compute_for_cycle ctxt ~revealed inited_seed_cycle diff --git a/src/proto_011_PtHangzH/lib_protocol/seed_storage.mli b/src/proto_011_PtHangzH/lib_protocol/seed_storage.mli new file mode 100644 index 000000000000..37e87efed99b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/seed_storage.mli @@ -0,0 +1,47 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += + | Unknown of { + oldest : Cycle_repr.t; + cycle : Cycle_repr.t; + latest : Cycle_repr.t; + } + +(* `Permanent *) + +(** Generates the first [preserved_cycles+2] seeds for which + there are no nonces. *) +val init : Raw_context.t -> Raw_context.t tzresult Lwt.t + +val for_cycle : Raw_context.t -> Cycle_repr.t -> Seed_repr.seed tzresult Lwt.t + +(** If it is the end of the cycle, computes and stores the seed of cycle at + distance [preserved_cycle+2] in the future using the seed of the previous + cycle and the revelations of the current one. *) +val cycle_end : + Raw_context.t -> + Cycle_repr.t -> + (Raw_context.t * Nonce_storage.unrevealed list) tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/services_registration.ml b/src/proto_011_PtHangzH/lib_protocol/services_registration.ml new file mode 100644 index 000000000000..2bd4896b9b72 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/services_registration.ml @@ -0,0 +1,121 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +type rpc_context = { + block_hash : Block_hash.t; + block_header : Block_header.shell_header; + context : Alpha_context.t; +} + +let rpc_init ({block_hash; block_header; context} : Updater.rpc_context) = + let level = block_header.level in + let timestamp = block_header.timestamp in + let fitness = block_header.fitness in + Alpha_context.prepare + ~level + ~predecessor_timestamp:timestamp + ~timestamp + ~fitness + context + >|=? fun (context, _, _) -> {block_hash; block_header; context} + +let rpc_services = + ref (RPC_directory.empty : Updater.rpc_context RPC_directory.t) + +let register0_fullctxt ~chunked s f = + rpc_services := + RPC_directory.register ~chunked !rpc_services s (fun ctxt q i -> + rpc_init ctxt >>=? fun ctxt -> f ctxt q i) + +let register0 ~chunked s f = + register0_fullctxt ~chunked s (fun {context; _} -> f context) + +let register0_noctxt ~chunked s f = + rpc_services := + RPC_directory.register ~chunked !rpc_services s (fun _ q i -> f q i) + +let register1_fullctxt ~chunked s f = + rpc_services := + RPC_directory.register ~chunked !rpc_services s (fun (ctxt, arg) q i -> + rpc_init ctxt >>=? fun ctxt -> f ctxt arg q i) + +let register1 ~chunked s f = + register1_fullctxt ~chunked s (fun {context; _} x -> f context x) + +let register2_fullctxt ~chunked s f = + rpc_services := + RPC_directory.register + ~chunked + !rpc_services + s + (fun ((ctxt, arg1), arg2) q i -> + rpc_init ctxt >>=? fun ctxt -> f ctxt arg1 arg2 q i) + +let register2 ~chunked s f = + register2_fullctxt ~chunked s (fun {context; _} a1 a2 q i -> + f context a1 a2 q i) + +let opt_register0_fullctxt ~chunked s f = + rpc_services := + RPC_directory.opt_register ~chunked !rpc_services s (fun ctxt q i -> + rpc_init ctxt >>=? fun ctxt -> f ctxt q i) + +let opt_register0 ~chunked s f = + opt_register0_fullctxt ~chunked s (fun {context; _} -> f context) + +let opt_register1_fullctxt ~chunked s f = + rpc_services := + RPC_directory.opt_register ~chunked !rpc_services s (fun (ctxt, arg) q i -> + rpc_init ctxt >>=? fun ctxt -> f ctxt arg q i) + +let opt_register1 ~chunked s f = + opt_register1_fullctxt ~chunked s (fun {context; _} x -> f context x) + +let opt_register2_fullctxt ~chunked s f = + rpc_services := + RPC_directory.opt_register + ~chunked + !rpc_services + s + (fun ((ctxt, arg1), arg2) q i -> + rpc_init ctxt >>=? fun ctxt -> f ctxt arg1 arg2 q i) + +let opt_register2 ~chunked s f = + opt_register2_fullctxt ~chunked s (fun {context; _} a1 a2 q i -> + f context a1 a2 q i) + +let get_rpc_services () = + let p = + RPC_directory.map + (fun c -> + rpc_init c >|= function Error _ -> assert false | Ok c -> c.context) + (Storage_description.build_directory Alpha_context.description) + in + RPC_directory.register_dynamic_directory + !rpc_services + RPC_path.(open_root / "context" / "raw" / "json") + (fun _ -> Lwt.return p) diff --git a/src/proto_011_PtHangzH/lib_protocol/services_registration.mli b/src/proto_011_PtHangzH/lib_protocol/services_registration.mli new file mode 100644 index 000000000000..7c6df68ebd23 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/services_registration.mli @@ -0,0 +1,127 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Functions for RPC service registration, using [Updater.rpc_context] and + [RPC_service.t] from the Protocol Environment. + + This module is a frontend to a mutable service directory. The various + [register] functions update the directory as a side-effect. + + The [get_rpc_services] function returns the resulting [RPC_context]. It is + parameterized by [Updater.rpc_context] which acts as the service prefix (in + practice meaning this type will be passed to each handler). Hence, + Protocol RPC services provide a {i read-only} view of the Ledger state. + *) + +open Alpha_context + +type rpc_context = { + block_hash : Block_hash.t; + block_header : Block_header.shell_header; + context : t; +} + +val rpc_init : Updater.rpc_context -> rpc_context Error_monad.tzresult Lwt.t + +val register0 : + chunked:bool -> + ( [< RPC_service.meth], + Updater.rpc_context, + Updater.rpc_context, + 'a, + 'b, + 'c ) + RPC_service.t -> + (t -> 'a -> 'b -> 'c Error_monad.tzresult Lwt.t) -> + unit + +val register0_noctxt : + chunked:bool -> + ([< RPC_service.meth], Updater.rpc_context, 'a, 'b, 'c, 'd) RPC_service.t -> + ('b -> 'c -> 'd Error_monad.tzresult Lwt.t) -> + unit + +val register1 : + chunked:bool -> + ( [< RPC_service.meth], + Updater.rpc_context, + Updater.rpc_context * 'a, + 'b, + 'c, + 'd ) + RPC_service.t -> + (t -> 'a -> 'b -> 'c -> 'd Error_monad.tzresult Lwt.t) -> + unit + +val register2 : + chunked:bool -> + ( [< RPC_service.meth], + Updater.rpc_context, + (Updater.rpc_context * 'a) * 'b, + 'c, + 'd, + 'e ) + RPC_service.t -> + (t -> 'a -> 'b -> 'c -> 'd -> 'e Error_monad.tzresult Lwt.t) -> + unit + +val opt_register0 : + chunked:bool -> + ( [< RPC_service.meth], + Updater.rpc_context, + Updater.rpc_context, + 'a, + 'b, + 'c ) + RPC_service.t -> + (t -> 'a -> 'b -> 'c option Error_monad.tzresult Lwt.t) -> + unit + +val opt_register1 : + chunked:bool -> + ( [< RPC_service.meth], + Updater.rpc_context, + Updater.rpc_context * 'a, + 'b, + 'c, + 'd ) + RPC_service.t -> + (t -> 'a -> 'b -> 'c -> 'd option Error_monad.tzresult Lwt.t) -> + unit + +val opt_register2 : + chunked:bool -> + ( [< RPC_service.meth], + Updater.rpc_context, + (Updater.rpc_context * 'a) * 'b, + 'c, + 'd, + 'e ) + RPC_service.t -> + (t -> 'a -> 'b -> 'c -> 'd -> 'e option Error_monad.tzresult Lwt.t) -> + unit + +val get_rpc_services : unit -> Updater.rpc_context RPC_directory.directory diff --git a/src/proto_011_PtHangzH/lib_protocol/state_hash.ml b/src/proto_011_PtHangzH/lib_protocol/state_hash.ml new file mode 100644 index 000000000000..a39ce4a21127 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/state_hash.ml @@ -0,0 +1,44 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let random_state_hash = "\076\064\204" (* rng(53): never used... *) + +module H = + Blake2B.Make + (Base58) + (struct + let name = "random" + + let title = "A random generation state" + + let b58check_prefix = random_state_hash + + let size = None + end) + +include H +include Path_encoding.Make_hex (H) + +let () = Base58.check_encoded_prefix b58check_encoding "rng" 53 diff --git a/src/proto_011_PtHangzH/lib_protocol/state_hash.mli b/src/proto_011_PtHangzH/lib_protocol/state_hash.mli new file mode 100644 index 000000000000..7ae77f3a0c42 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/state_hash.mli @@ -0,0 +1,30 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** A specialized Blake2B implementation for hashing internal states of random + number generators. *) + +include S.HASH diff --git a/src/proto_011_PtHangzH/lib_protocol/storage.ml b/src/proto_011_PtHangzH/lib_protocol/storage.ml new file mode 100644 index 000000000000..eaab9bcb047d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/storage.ml @@ -0,0 +1,1329 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Storage_functors +open Storage_sigs + +module Encoding = struct + module UInt16 = struct + type t = int + + let encoding = Data_encoding.uint16 + end + + module Int32 = struct + type t = Int32.t + + let encoding = Data_encoding.int32 + end + + module Int64 = struct + type t = Int64.t + + let encoding = Data_encoding.int64 + end + + module Z = struct + type t = Z.t + + let encoding = Data_encoding.z + end +end + +module Int31_index : INDEX with type t = int = struct + type t = int + + let path_length = 1 + + let to_path c l = string_of_int c :: l + + let of_path = function [] | _ :: _ :: _ -> None | [c] -> int_of_string_opt c + + type 'a ipath = 'a * t + + let args = + Storage_description.One + { + rpc_arg = RPC_arg.int; + encoding = Data_encoding.int31; + compare = Compare.Int.compare; + } +end + +module Make_index (H : Storage_description.INDEX) : + INDEX with type t = H.t and type 'a ipath = 'a * H.t = struct + include H + + type 'a ipath = 'a * t + + let args = Storage_description.One {rpc_arg; encoding; compare} +end + +module type Simple_single_data_storage = sig + type value + + val get : Raw_context.t -> value tzresult Lwt.t + + val update : Raw_context.t -> value -> Raw_context.t tzresult Lwt.t + + val init : Raw_context.t -> value -> Raw_context.t tzresult Lwt.t +end + +module Block_priority : Simple_single_data_storage with type value = int = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["block_priority"] + end) + (Encoding.UInt16) + +(** Contracts handling *) + +module Contract = struct + module Raw_context = + Make_subcontext (Registered) (Raw_context) + (struct + let name = ["contracts"] + end) + + module Global_counter : Simple_single_data_storage with type value = Z.t = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["global_counter"] + end) + (Encoding.Z) + + module Indexed_context = + Make_indexed_subcontext + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["index"] + end)) + (Make_index (Contract_repr.Index)) + + let fold = Indexed_context.fold_keys + + let list = Indexed_context.keys + + module Balance = + Indexed_context.Make_map + (struct + let name = ["balance"] + end) + (Tez_repr) + + module Frozen_balance_index = + Make_indexed_subcontext + (Make_subcontext (Registered) (Indexed_context.Raw_context) + (struct + let name = ["frozen_balance"] + end)) + (Make_index (Cycle_repr.Index)) + + module Frozen_deposits = + Frozen_balance_index.Make_map + (struct + let name = ["deposits"] + end) + (Tez_repr) + + module Frozen_fees = + Frozen_balance_index.Make_map + (struct + let name = ["fees"] + end) + (Tez_repr) + + module Frozen_rewards = + Frozen_balance_index.Make_map + (struct + let name = ["rewards"] + end) + (Tez_repr) + + module Manager = + Indexed_context.Make_map + (struct + let name = ["manager"] + end) + (Manager_repr) + + module Delegate = + Indexed_context.Make_map + (struct + let name = ["delegate"] + end) + (Signature.Public_key_hash) + + module Inactive_delegate = + Indexed_context.Make_set + (Registered) + (struct + let name = ["inactive_delegate"] + end) + + module Delegate_desactivation = + Indexed_context.Make_map + (struct + let name = ["delegate_desactivation"] + end) + (Cycle_repr) + + module Delegated = + Make_data_set_storage + (Make_subcontext (Registered) (Indexed_context.Raw_context) + (struct + let name = ["delegated"] + end)) + (Make_index (Contract_repr.Index)) + + module Counter = + Indexed_context.Make_map + (struct + let name = ["counter"] + end) + (Encoding.Z) + + (* Consume gas for serialization and deserialization of expr in this + module *) + module Make_carbonated_map_expr (N : Storage_sigs.NAME) : + Storage_sigs.Non_iterable_indexed_carbonated_data_storage + with type key = Contract_repr.t + and type value = Script_repr.lazy_expr + and type t := Raw_context.t = struct + module I = + Indexed_context.Make_carbonated_map + (N) + (struct + type t = Script_repr.lazy_expr + + let encoding = Script_repr.lazy_expr_encoding + end) + + type context = I.context + + type key = I.key + + type value = I.value + + let mem = I.mem + + let remove_existing = I.remove_existing + + let remove = I.remove + + let consume_deserialize_gas ctxt value = + Raw_context.consume_gas ctxt (Script_repr.force_decode_cost value) + + let consume_serialize_gas ctxt value = + Raw_context.consume_gas ctxt (Script_repr.force_bytes_cost value) + + let get ctxt contract = + I.get ctxt contract >>=? fun (ctxt, value) -> + Lwt.return + (consume_deserialize_gas ctxt value >|? fun ctxt -> (ctxt, value)) + + let find ctxt contract = + I.find ctxt contract >>=? fun (ctxt, value_opt) -> + Lwt.return + @@ + match value_opt with + | None -> ok (ctxt, None) + | Some value -> + consume_deserialize_gas ctxt value >|? fun ctxt -> (ctxt, value_opt) + + let update ctxt contract value = + consume_serialize_gas ctxt value >>?= fun ctxt -> + I.update ctxt contract value + + let add_or_remove ctxt contract value_opt = + match value_opt with + | None -> I.add_or_remove ctxt contract None + | Some value -> + consume_serialize_gas ctxt value >>?= fun ctxt -> + I.add_or_remove ctxt contract value_opt + + let init ctxt contract value = + consume_serialize_gas ctxt value >>?= fun ctxt -> + I.init ctxt contract value + + let add ctxt contract value = + consume_serialize_gas ctxt value >>?= fun ctxt -> + I.add ctxt contract value + end + + module Code = Make_carbonated_map_expr (struct + let name = ["code"] + end) + + module Storage = Make_carbonated_map_expr (struct + let name = ["storage"] + end) + + module Paid_storage_space = + Indexed_context.Make_map + (struct + let name = ["paid_bytes"] + end) + (Encoding.Z) + + module Used_storage_space = + Indexed_context.Make_map + (struct + let name = ["used_bytes"] + end) + (Encoding.Z) + + module Roll_list = + Indexed_context.Make_map + (struct + let name = ["roll_list"] + end) + (Roll_repr) + + module Change = + Indexed_context.Make_map + (struct + let name = ["change"] + end) + (Tez_repr) +end + +module type NEXT = sig + type id + + val init : Raw_context.t -> Raw_context.t tzresult Lwt.t + + val incr : Raw_context.t -> (Raw_context.t * id) tzresult Lwt.t +end + +module Global_constants = struct + module Map = + Make_indexed_carbonated_data_storage + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["global_constant"] + end)) + (Make_index (Script_expr_hash)) + (struct + type t = Script_repr.expr + + let encoding = Script_repr.expr_encoding + end) +end + +(** Big maps handling *) + +module Big_map = struct + type id = Lazy_storage_kind.Big_map.Id.t + + module Raw_context = + Make_subcontext (Registered) (Raw_context) + (struct + let name = ["big_maps"] + end) + + module Next : NEXT with type id := id = struct + module Storage = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["next"] + end) + (Lazy_storage_kind.Big_map.Id) + + let incr ctxt = + Storage.get ctxt >>=? fun i -> + Storage.update ctxt (Lazy_storage_kind.Big_map.Id.next i) >|=? fun ctxt -> + (ctxt, i) + + let init ctxt = Storage.init ctxt Lazy_storage_kind.Big_map.Id.init + end + + module Index = Lazy_storage_kind.Big_map.Id + + module Indexed_context = + Make_indexed_subcontext + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["index"] + end)) + (Make_index (Index)) + + let rpc_arg = Index.rpc_arg + + let fold = Indexed_context.fold_keys + + let list = Indexed_context.keys + + let remove ctxt n = Indexed_context.remove ctxt n + + let copy ctxt ~from ~to_ = Indexed_context.copy ctxt ~from ~to_ + + type key = Raw_context.t * Index.t + + module Total_bytes = + Indexed_context.Make_map + (struct + let name = ["total_bytes"] + end) + (Encoding.Z) + + module Key_type = + Indexed_context.Make_map + (struct + let name = ["key_type"] + end) + (struct + type t = Script_repr.expr + + let encoding = Script_repr.expr_encoding + end) + + module Value_type = + Indexed_context.Make_map + (struct + let name = ["value_type"] + end) + (struct + type t = Script_repr.expr + + let encoding = Script_repr.expr_encoding + end) + + module Contents : + Non_iterable_indexed_carbonated_data_storage_with_values + with type key = Script_expr_hash.t + and type value = Script_repr.expr + and type t := key = struct + module I = + Storage_functors.Make_indexed_carbonated_data_storage + (Make_subcontext (Registered) (Indexed_context.Raw_context) + (struct + let name = ["contents"] + end)) + (Make_index (Script_expr_hash)) + (struct + type t = Script_repr.expr + + let encoding = Script_repr.expr_encoding + end) + + type context = I.context + + type key = I.key + + type value = I.value + + let mem = I.mem + + let remove_existing = I.remove_existing + + let remove = I.remove + + let update = I.update + + let add_or_remove = I.add_or_remove + + let init = I.init + + let add = I.add + + let list_values = I.list_values + + let consume_deserialize_gas ctxt value = + Raw_context.consume_gas ctxt (Script_repr.deserialized_cost value) + + let get ctxt contract = + I.get ctxt contract >>=? fun (ctxt, value) -> + Lwt.return + (consume_deserialize_gas ctxt value >|? fun ctxt -> (ctxt, value)) + + let find ctxt contract = + I.find ctxt contract >>=? fun (ctxt, value_opt) -> + Lwt.return + @@ + match value_opt with + | None -> ok (ctxt, None) + | Some value -> + consume_deserialize_gas ctxt value >|? fun ctxt -> (ctxt, value_opt) + end +end + +module Sapling = struct + type id = Lazy_storage_kind.Sapling_state.Id.t + + module Raw_context = + Make_subcontext (Registered) (Raw_context) + (struct + let name = ["sapling"] + end) + + module Next = struct + module Storage = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["next"] + end) + (Lazy_storage_kind.Sapling_state.Id) + + let incr ctxt = + Storage.get ctxt >>=? fun i -> + Storage.update ctxt (Lazy_storage_kind.Sapling_state.Id.next i) + >|=? fun ctxt -> (ctxt, i) + + let init ctxt = Storage.init ctxt Lazy_storage_kind.Sapling_state.Id.init + end + + module Index = Lazy_storage_kind.Sapling_state.Id + + let rpc_arg = Index.rpc_arg + + module Indexed_context = + Make_indexed_subcontext + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["index"] + end)) + (Make_index (Index)) + + let remove ctxt n = Indexed_context.remove ctxt n + + let copy ctxt ~from ~to_ = Indexed_context.copy ctxt ~from ~to_ + + module Total_bytes = + Indexed_context.Make_map + (struct + let name = ["total_bytes"] + end) + (Encoding.Z) + + module Commitments_size = + Make_single_data_storage (Registered) (Indexed_context.Raw_context) + (struct + let name = ["commitments_size"] + end) + (Encoding.Int64) + + module Memo_size = + Make_single_data_storage (Registered) (Indexed_context.Raw_context) + (struct + let name = ["memo_size"] + end) + (Sapling_repr.Memo_size) + + module Commitments : + Non_iterable_indexed_carbonated_data_storage + with type t := Raw_context.t * id + and type key = int64 + and type value = Sapling.Hash.t = + Make_indexed_carbonated_data_storage + (Make_subcontext (Registered) (Indexed_context.Raw_context) + (struct + let name = ["commitments"] + end)) + (Make_index (struct + type t = int64 + + let rpc_arg = + let construct = Int64.to_string in + let destruct hash = + Int64.of_string_opt hash + |> Result.of_option ~error:"Cannot parse node position" + in + RPC_arg.make + ~descr:"The position of a node in a sapling commitment tree" + ~name:"sapling_node_position" + ~construct + ~destruct + () + + let encoding = + Data_encoding.def + "sapling_node_position" + ~title:"Sapling node position" + ~description: + "The position of a node in a sapling commitment tree" + Data_encoding.int64 + + let compare = Compare.Int64.compare + + let path_length = 1 + + let to_path c l = Int64.to_string c :: l + + let of_path = function [c] -> Int64.of_string_opt c | _ -> None + end)) + (Sapling.Hash) + + let commitments_init ctx id = + Indexed_context.Raw_context.remove (ctx, id) ["commitments"] + >|= fun (ctx, _id) -> ctx + + module Ciphertexts : + Non_iterable_indexed_carbonated_data_storage + with type t := Raw_context.t * id + and type key = int64 + and type value = Sapling.Ciphertext.t = + Make_indexed_carbonated_data_storage + (Make_subcontext (Registered) (Indexed_context.Raw_context) + (struct + let name = ["ciphertexts"] + end)) + (Make_index (struct + type t = int64 + + let rpc_arg = + let construct = Int64.to_string in + let destruct hash = + Int64.of_string_opt hash + |> Result.of_option ~error:"Cannot parse ciphertext position" + in + RPC_arg.make + ~descr:"The position of a sapling ciphertext" + ~name:"sapling_ciphertext_position" + ~construct + ~destruct + () + + let encoding = + Data_encoding.def + "sapling_ciphertext_position" + ~title:"Sapling ciphertext position" + ~description:"The position of a sapling ciphertext" + Data_encoding.int64 + + let compare = Compare.Int64.compare + + let path_length = 1 + + let to_path c l = Int64.to_string c :: l + + let of_path = function [c] -> Int64.of_string_opt c | _ -> None + end)) + (Sapling.Ciphertext) + + let ciphertexts_init ctx id = + Indexed_context.Raw_context.remove (ctx, id) ["commitments"] + >|= fun (ctx, _id) -> ctx + + module Nullifiers_size = + Make_single_data_storage (Registered) (Indexed_context.Raw_context) + (struct + let name = ["nullifiers_size"] + end) + (Encoding.Int64) + + (* For sequential access when building a diff *) + module Nullifiers_ordered : + Non_iterable_indexed_data_storage + with type t := Raw_context.t * id + and type key = int64 + and type value = Sapling.Nullifier.t = + Make_indexed_data_storage + (Make_subcontext (Registered) (Indexed_context.Raw_context) + (struct + let name = ["nullifiers_ordered"] + end)) + (Make_index (struct + type t = int64 + + let rpc_arg = + let construct = Int64.to_string in + let destruct hash = + Int64.of_string_opt hash + |> Result.of_option ~error:"Cannot parse nullifier position" + in + RPC_arg.make + ~descr:"A sapling nullifier position" + ~name:"sapling_nullifier_position" + ~construct + ~destruct + () + + let encoding = + Data_encoding.def + "sapling_nullifier_position" + ~title:"Sapling nullifier position" + ~description:"Sapling nullifier position" + Data_encoding.int64 + + let compare = Compare.Int64.compare + + let path_length = 1 + + let to_path c l = Int64.to_string c :: l + + let of_path = function [c] -> Int64.of_string_opt c | _ -> None + end)) + (Sapling.Nullifier) + + (* Check membership in O(1) for verify_update *) + module Nullifiers_hashed = + Make_carbonated_data_set_storage + (Make_subcontext (Registered) (Indexed_context.Raw_context) + (struct + let name = ["nullifiers_hashed"] + end)) + (Make_index (struct + type t = Sapling.Nullifier.t + + let encoding = Sapling.Nullifier.encoding + + let of_string hexstring = + let b = Hex.to_bytes (`Hex hexstring) in + Data_encoding.Binary.of_bytes_opt encoding b + |> Result.of_option ~error:"Cannot parse sapling nullifier" + + let to_string nf = + let b = Data_encoding.Binary.to_bytes_exn encoding nf in + let (`Hex hexstring) = Hex.of_bytes b in + hexstring + + let rpc_arg = + RPC_arg.make + ~descr:"A sapling nullifier" + ~name:"sapling_nullifier" + ~construct:to_string + ~destruct:of_string + () + + let compare = Sapling.Nullifier.compare + + let path_length = 1 + + let to_path c l = to_string c :: l + + let of_path = function + | [c] -> Result.to_option (of_string c) + | _ -> None + end)) + + let nullifiers_init ctx id = + Nullifiers_size.add (ctx, id) Int64.zero >>= fun ctx -> + Indexed_context.Raw_context.remove (ctx, id) ["nullifiers_ordered"] + >>= fun (ctx, id) -> + Indexed_context.Raw_context.remove (ctx, id) ["nullifiers_hashed"] + >|= fun (ctx, _id) -> ctx + + module Roots : + Non_iterable_indexed_data_storage + with type t := Raw_context.t * id + and type key = int32 + and type value = Sapling.Hash.t = + Make_indexed_data_storage + (Make_subcontext (Registered) (Indexed_context.Raw_context) + (struct + let name = ["roots"] + end)) + (Make_index (struct + type t = int32 + + let rpc_arg = + let construct = Int32.to_string in + let destruct hash = + Int32.of_string_opt hash + |> Result.of_option ~error:"Cannot parse nullifier position" + in + RPC_arg.make + ~descr:"A sapling root" + ~name:"sapling_root" + ~construct + ~destruct + () + + let encoding = + Data_encoding.def + "sapling_root" + ~title:"Sapling root" + ~description:"Sapling root" + Data_encoding.int32 + + let compare = Compare.Int32.compare + + let path_length = 1 + + let to_path c l = Int32.to_string c :: l + + let of_path = function [c] -> Int32.of_string_opt c | _ -> None + end)) + (Sapling.Hash) + + module Roots_pos = + Make_single_data_storage (Registered) (Indexed_context.Raw_context) + (struct + let name = ["roots_pos"] + end) + (Encoding.Int32) + + module Roots_level = + Make_single_data_storage (Registered) (Indexed_context.Raw_context) + (struct + let name = ["roots_level"] + end) + (Raw_level_repr) +end + +module Public_key_hash = struct + open Signature + include Signature.Public_key_hash + module Path_Ed25519 = Path_encoding.Make_hex (Ed25519.Public_key_hash) + module Path_Secp256k1 = Path_encoding.Make_hex (Secp256k1.Public_key_hash) + module Path_P256 = Path_encoding.Make_hex (P256.Public_key_hash) + + let to_path (key : public_key_hash) l = + match key with + | Ed25519 h -> ( + match Path_Ed25519.to_path h l with + | [s] -> ["ed25519"; s] + | _ -> assert false) + | Secp256k1 h -> ( + match Path_Secp256k1.to_path h l with + | [s] -> ["secp256k1"; s] + | _ -> assert false) + | P256 h -> ( + match Path_P256.to_path h l with + | [s] -> ["p256"; s] + | _ -> assert false) + + let of_path : _ -> public_key_hash option = function + | "ed25519" :: rest -> ( + match Path_Ed25519.of_path rest with + | Some pkh -> Some (Ed25519 pkh) + | None -> None) + | "secp256k1" :: rest -> ( + match Path_Secp256k1.of_path rest with + | Some pkh -> Some (Secp256k1 pkh) + | None -> None) + | "p256" :: rest -> ( + match Path_P256.of_path rest with + | Some pkh -> Some (P256 pkh) + | None -> None) + | _ -> None + + let path_length = + let l1 = Path_Ed25519.path_length + and l2 = Path_Secp256k1.path_length + and l3 = Path_P256.path_length in + assert (match (l1, l2, l3) with (1, 1, 1) -> true | _ -> false) ; + 2 +end + +module Public_key_hash_index = Make_index (Public_key_hash) + +module Protocol_hash = struct + include Protocol_hash + include Path_encoding.Make_hex (Protocol_hash) +end + +module Delegates = + Make_data_set_storage + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["delegates"] + end)) + (Public_key_hash_index) + +module Active_delegates_with_rolls = + Make_data_set_storage + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["active_delegates_with_rolls"] + end)) + (Public_key_hash_index) + +module Delegates_with_frozen_balance_index = + Make_indexed_subcontext + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["delegates_with_frozen_balance"] + end)) + (Make_index (Cycle_repr.Index)) + +module Delegates_with_frozen_balance = + Make_data_set_storage + (Delegates_with_frozen_balance_index.Raw_context) + (Public_key_hash_index) + +(** Rolls *) + +module Cycle = struct + module Indexed_context = + Make_indexed_subcontext + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["cycle"] + end)) + (Make_index (Cycle_repr.Index)) + + module Last_roll = + Make_indexed_data_storage + (Make_subcontext (Registered) (Indexed_context.Raw_context) + (struct + let name = ["last_roll"] + end)) + (Int31_index) + (Roll_repr) + + module Roll_snapshot = + Indexed_context.Make_map + (struct + let name = ["roll_snapshot"] + end) + (Encoding.UInt16) + + type unrevealed_nonce = { + nonce_hash : Nonce_hash.t; + delegate : Signature.Public_key_hash.t; + rewards : Tez_repr.t; + fees : Tez_repr.t; + } + + type nonce_status = + | Unrevealed of unrevealed_nonce + | Revealed of Seed_repr.nonce + + let nonce_status_encoding = + let open Data_encoding in + union + [ + case + (Tag 0) + ~title:"Unrevealed" + (tup4 + Nonce_hash.encoding + Signature.Public_key_hash.encoding + Tez_repr.encoding + Tez_repr.encoding) + (function + | Unrevealed {nonce_hash; delegate; rewards; fees} -> + Some (nonce_hash, delegate, rewards, fees) + | _ -> None) + (fun (nonce_hash, delegate, rewards, fees) -> + Unrevealed {nonce_hash; delegate; rewards; fees}); + case + (Tag 1) + ~title:"Revealed" + Seed_repr.nonce_encoding + (function Revealed nonce -> Some nonce | _ -> None) + (fun nonce -> Revealed nonce); + ] + + module Nonce = + Make_indexed_data_storage + (Make_subcontext (Registered) (Indexed_context.Raw_context) + (struct + let name = ["nonces"] + end)) + (Make_index (Raw_level_repr.Index)) + (struct + type t = nonce_status + + let encoding = nonce_status_encoding + end) + + module Seed = + Indexed_context.Make_map + (struct + let name = ["random_seed"] + end) + (struct + type t = Seed_repr.seed + + let encoding = Seed_repr.seed_encoding + end) +end + +module Roll = struct + module Raw_context = + Make_subcontext (Registered) (Raw_context) + (struct + let name = ["rolls"] + end) + + module Indexed_context = + Make_indexed_subcontext + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["index"] + end)) + (Make_index (Roll_repr.Index)) + + module Next = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["next"] + end) + (Roll_repr) + + module Limbo = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["limbo"] + end) + (Roll_repr) + + module Delegate_roll_list = + Wrap_indexed_data_storage + (Contract.Roll_list) + (struct + type t = Signature.Public_key_hash.t + + let wrap = Contract_repr.implicit_contract + + let unwrap = Contract_repr.is_implicit + end) + + module Successor = + Indexed_context.Make_map + (struct + let name = ["successor"] + end) + (Roll_repr) + + module Delegate_change = + Wrap_indexed_data_storage + (Contract.Change) + (struct + type t = Signature.Public_key_hash.t + + let wrap = Contract_repr.implicit_contract + + let unwrap = Contract_repr.is_implicit + end) + + module Snapshoted_owner_index : INDEX with type t = Cycle_repr.t * int = + struct + type t = Cycle_repr.t * int + + let path_length = Cycle_repr.Index.path_length + 1 + + let to_path (c, n) s = Cycle_repr.Index.to_path c (string_of_int n :: s) + + let of_path l = + match Misc.take Cycle_repr.Index.path_length l with + | None | Some (_, ([] | _ :: _ :: _)) -> None + | Some (l1, [l2]) -> ( + match (Cycle_repr.Index.of_path l1, int_of_string_opt l2) with + | (None, _) | (_, None) -> None + | (Some c, Some i) -> Some (c, i)) + + type 'a ipath = ('a * Cycle_repr.t) * int + + let left_args = + Storage_description.One + { + rpc_arg = Cycle_repr.rpc_arg; + encoding = Cycle_repr.encoding; + compare = Cycle_repr.compare; + } + + let right_args = + Storage_description.One + { + rpc_arg = RPC_arg.int; + encoding = Data_encoding.int31; + compare = Compare.Int.compare; + } + + let args = Storage_description.(Pair (left_args, right_args)) + end + + module Owner = + Make_indexed_data_snapshotable_storage + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["owner"] + end)) + (Snapshoted_owner_index) + (Make_index (Roll_repr.Index)) + (Signature.Public_key) + + module Snapshot_for_cycle = Cycle.Roll_snapshot + module Last_for_snapshot = Cycle.Last_roll + + let clear = Indexed_context.clear +end + +(** Votes *) + +module Vote = struct + module Raw_context = + Make_subcontext (Registered) (Raw_context) + (struct + let name = ["votes"] + end) + + module Pred_period_kind = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["pred_period_kind"] + end) + (struct + type t = Voting_period_repr.kind + + let encoding = Voting_period_repr.kind_encoding + end) + + module Current_period = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["current_period"] + end) + (struct + type t = Voting_period_repr.t + + let encoding = Voting_period_repr.encoding + end) + + module Participation_ema = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["participation_ema"] + end) + (Encoding.Int32) + + module Current_proposal = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["current_proposal"] + end) + (Protocol_hash) + + module Listings_size = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["listings_size"] + end) + (Encoding.Int32) + + module Listings = + Make_indexed_data_storage + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["listings"] + end)) + (Public_key_hash_index) + (Encoding.Int32) + + module Proposals = + Make_data_set_storage + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["proposals"] + end)) + (Pair (Make_index (Protocol_hash)) (Public_key_hash_index)) + + module Proposals_count = + Make_indexed_data_storage + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["proposals_count"] + end)) + (Public_key_hash_index) + (Encoding.UInt16) + + module Ballots = + Make_indexed_data_storage + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["ballots"] + end)) + (Public_key_hash_index) + (struct + type t = Vote_repr.ballot + + let encoding = Vote_repr.ballot_encoding + end) +end + +module type FOR_CYCLE = sig + val init : + Raw_context.t -> + Cycle_repr.t -> + Seed_repr.seed -> + Raw_context.t tzresult Lwt.t + + val get : Raw_context.t -> Cycle_repr.t -> Seed_repr.seed tzresult Lwt.t + + val remove_existing : + Raw_context.t -> Cycle_repr.t -> Raw_context.t tzresult Lwt.t +end + +(** Seed *) + +module Seed = struct + type unrevealed_nonce = Cycle.unrevealed_nonce = { + nonce_hash : Nonce_hash.t; + delegate : Signature.Public_key_hash.t; + rewards : Tez_repr.t; + fees : Tez_repr.t; + } + + type nonce_status = Cycle.nonce_status = + | Unrevealed of unrevealed_nonce + | Revealed of Seed_repr.nonce + + module Nonce : + Non_iterable_indexed_data_storage + with type key := Level_repr.t + and type value := nonce_status + and type t := Raw_context.t = struct + open Level_repr + + type context = Raw_context.t + + let mem ctxt (l : Level_repr.t) = Cycle.Nonce.mem (ctxt, l.cycle) l.level + + let get ctxt (l : Level_repr.t) = Cycle.Nonce.get (ctxt, l.cycle) l.level + + let find ctxt (l : Level_repr.t) = Cycle.Nonce.find (ctxt, l.cycle) l.level + + let update ctxt (l : Level_repr.t) v = + Cycle.Nonce.update (ctxt, l.cycle) l.level v + + let init ctxt (l : Level_repr.t) v = + Cycle.Nonce.init (ctxt, l.cycle) l.level v + + let add ctxt (l : Level_repr.t) v = + Cycle.Nonce.add (ctxt, l.cycle) l.level v + + let add_or_remove ctxt (l : Level_repr.t) v = + Cycle.Nonce.add_or_remove (ctxt, l.cycle) l.level v + + let remove_existing ctxt (l : Level_repr.t) = + Cycle.Nonce.remove_existing (ctxt, l.cycle) l.level + + let remove ctxt (l : Level_repr.t) = + Cycle.Nonce.remove (ctxt, l.cycle) l.level + end + + module For_cycle : FOR_CYCLE = Cycle.Seed +end + +(** Commitments *) + +module Commitments = + Make_indexed_data_storage + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["commitments"] + end)) + (Make_index (Blinded_public_key_hash.Index)) + (Tez_repr) + +(** Ramp up security deposits... *) + +module Ramp_up = struct + module Rewards = + Make_indexed_data_storage + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["ramp_up"; "rewards"] + end)) + (Make_index (Cycle_repr.Index)) + (struct + type t = Tez_repr.t list * Tez_repr.t list + + let encoding = + Data_encoding.( + obj2 + (req "baking_reward_per_endorsement" (list Tez_repr.encoding)) + (req "endorsement_reward" (list Tez_repr.encoding))) + end) + + module Security_deposits = + Make_indexed_data_storage + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["ramp_up"; "deposits"] + end)) + (Make_index (Cycle_repr.Index)) + (struct + type t = Tez_repr.t * Tez_repr.t + + let encoding = Data_encoding.tup2 Tez_repr.encoding Tez_repr.encoding + end) +end + +module Pending_migration = struct + module Balance_updates = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["pending_migration_balance_updates"] + end) + (struct + type t = Receipt_repr.balance_updates + + let encoding = Receipt_repr.balance_updates_encoding + end) + + module Operation_results = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["pending_migration_operation_results"] + end) + (struct + type t = Migration_repr.origination_result list + + let encoding = Migration_repr.origination_result_list_encoding + end) + + let remove ctxt = + let balance_updates ctxt = + Balance_updates.find ctxt >>=? function + | Some balance_updates -> + Balance_updates.remove ctxt >>= fun ctxt -> + (* When applying balance updates in a migration, we must attach receipts. + The balance updates returned from here will be applied in the first + block of the new protocol. *) + return (ctxt, balance_updates) + | None -> return (ctxt, []) + in + let operation_results ctxt = + Operation_results.find ctxt >>=? function + | Some operation_results -> + Operation_results.remove ctxt >>= fun ctxt -> + return (ctxt, operation_results) + | None -> return (ctxt, []) + in + balance_updates ctxt >>=? fun (ctxt, balance_updates) -> + operation_results ctxt >>=? fun (ctxt, operation_results) -> + return (ctxt, balance_updates, operation_results) +end + +module Liquidity_baking = struct + module Escape_ema = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["liquidity_baking_escape_ema"] + end) + (Encoding.Int32) + + module Cpmm_address = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["liquidity_baking_cpmm_address"] + end) + (Contract_repr) +end diff --git a/src/proto_011_PtHangzH/lib_protocol/storage.mli b/src/proto_011_PtHangzH/lib_protocol/storage.mli new file mode 100644 index 000000000000..ac28bdc722dd --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/storage.mli @@ -0,0 +1,532 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Tezos Protocol Implementation - Typed storage + + This module hides the hierarchical (key x value) database under + pre-allocated typed accessors for all persistent entities of the + tezos context. + + This interface enforces no invariant on the contents of the + database. Its goal is to centralize all accessors in order to have + a complete view over the database contents and avoid key + collisions. *) + +open Storage_sigs + +module type Simple_single_data_storage = sig + type value + + val get : Raw_context.t -> value tzresult Lwt.t + + val update : Raw_context.t -> value -> Raw_context.t tzresult Lwt.t + + val init : Raw_context.t -> value -> Raw_context.t tzresult Lwt.t +end + +module Block_priority : Simple_single_data_storage with type value = int + +module Roll : sig + (** Storage from this submodule must only be accessed through the + module `Roll`. *) + + module Owner : + Indexed_data_snapshotable_storage + with type key = Roll_repr.t + and type snapshot = Cycle_repr.t * int + and type value = Signature.Public_key.t + and type t := Raw_context.t + + val clear : Raw_context.t -> Raw_context.t Lwt.t + + (** The next roll to be allocated. *) + module Next : + Single_data_storage + with type value = Roll_repr.t + and type t := Raw_context.t + + (** Rolls linked lists represent both account owned and free rolls. + All rolls belongs either to the limbo list or to an owned list. *) + + (** Head of the linked list of rolls in limbo *) + module Limbo : + Single_data_storage + with type value = Roll_repr.t + and type t := Raw_context.t + + (** Rolls associated to contracts, a linked list per contract *) + module Delegate_roll_list : + Indexed_data_storage + with type key = Signature.Public_key_hash.t + and type value = Roll_repr.t + and type t := Raw_context.t + + (** Use this to iter on a linked list of rolls *) + module Successor : + Indexed_data_storage + with type key = Roll_repr.t + and type value = Roll_repr.t + and type t := Raw_context.t + + (** The tez of a contract that are not assigned to rolls *) + module Delegate_change : + Indexed_data_storage + with type key = Signature.Public_key_hash.t + and type value = Tez_repr.t + and type t := Raw_context.t + + (** Index of the randomly selected roll snapshot of a given cycle. *) + module Snapshot_for_cycle : + Indexed_data_storage + with type key = Cycle_repr.t + and type value = int + and type t := Raw_context.t + + (** Last roll in the snapshoted roll allocation of a given cycle. *) + module Last_for_snapshot : + Indexed_data_storage + with type key = int + and type value = Roll_repr.t + and type t = Raw_context.t * Cycle_repr.t +end + +module Contract : sig + (** Storage from this submodule must only be accessed through the + module `Contract`. *) + + module Global_counter : Simple_single_data_storage with type value = Z.t + + (** The domain of alive contracts *) + val fold : + Raw_context.t -> + init:'a -> + f:(Contract_repr.t -> 'a -> 'a Lwt.t) -> + 'a Lwt.t + + val list : Raw_context.t -> Contract_repr.t list Lwt.t + + (** All the tez possessed by a contract, including rolls and change *) + module Balance : + Indexed_data_storage + with type key = Contract_repr.t + and type value = Tez_repr.t + and type t := Raw_context.t + + (** Frozen balance, see 'delegate_storage.mli' for more explanation. + Always update `Delegates_with_frozen_balance` accordingly. *) + module Frozen_deposits : + Indexed_data_storage + with type key = Cycle_repr.t + and type value = Tez_repr.t + and type t = Raw_context.t * Contract_repr.t + + module Frozen_fees : + Indexed_data_storage + with type key = Cycle_repr.t + and type value = Tez_repr.t + and type t = Raw_context.t * Contract_repr.t + + module Frozen_rewards : + Indexed_data_storage + with type key = Cycle_repr.t + and type value = Tez_repr.t + and type t = Raw_context.t * Contract_repr.t + + (** The manager of a contract *) + module Manager : + Indexed_data_storage + with type key = Contract_repr.t + and type value = Manager_repr.t + and type t := Raw_context.t + + (** The delegate of a contract, if any. *) + module Delegate : + Indexed_data_storage + with type key = Contract_repr.t + and type value = Signature.Public_key_hash.t + and type t := Raw_context.t + + (** All contracts (implicit and originated) that are delegated, if any *) + module Delegated : + Data_set_storage + with type elt = Contract_repr.t + and type t = Raw_context.t * Contract_repr.t + + module Inactive_delegate : + Data_set_storage with type elt = Contract_repr.t and type t = Raw_context.t + + (** The cycle where the delegate should be deactivated. *) + module Delegate_desactivation : + Indexed_data_storage + with type key = Contract_repr.t + and type value = Cycle_repr.t + and type t := Raw_context.t + + module Counter : + Indexed_data_storage + with type key = Contract_repr.t + and type value = Z.t + and type t := Raw_context.t + + module Code : + Non_iterable_indexed_carbonated_data_storage + with type key = Contract_repr.t + and type value = Script_repr.lazy_expr + and type t := Raw_context.t + + module Storage : + Non_iterable_indexed_carbonated_data_storage + with type key = Contract_repr.t + and type value = Script_repr.lazy_expr + and type t := Raw_context.t + + (** Current storage space in bytes. + Includes code, global storage and big map elements. *) + module Used_storage_space : + Indexed_data_storage + with type key = Contract_repr.t + and type value = Z.t + and type t := Raw_context.t + + (** Maximal space available without needing to burn new fees. *) + module Paid_storage_space : + Indexed_data_storage + with type key = Contract_repr.t + and type value = Z.t + and type t := Raw_context.t +end + +module Big_map : sig + type id = Lazy_storage_kind.Big_map.Id.t + + module Next : sig + val incr : Raw_context.t -> (Raw_context.t * id) tzresult Lwt.t + + val init : Raw_context.t -> Raw_context.t tzresult Lwt.t + end + + (** The domain of alive big maps *) + val fold : Raw_context.t -> init:'a -> f:(id -> 'a -> 'a Lwt.t) -> 'a Lwt.t + + val list : Raw_context.t -> id list Lwt.t + + val remove : Raw_context.t -> id -> Raw_context.t Lwt.t + + val copy : Raw_context.t -> from:id -> to_:id -> Raw_context.t tzresult Lwt.t + + type key = Raw_context.t * id + + val rpc_arg : id RPC_arg.t + + module Contents : sig + include + Non_iterable_indexed_carbonated_data_storage + with type key = Script_expr_hash.t + and type value = Script_repr.expr + and type t := key + + (** HACK *) + val list_values : + ?offset:int -> + ?length:int -> + Raw_context.t * id -> + (Raw_context.t * Script_repr.expr list) tzresult Lwt.t + end + + module Total_bytes : + Indexed_data_storage + with type key = id + and type value = Z.t + and type t := Raw_context.t + + module Key_type : + Indexed_data_storage + with type key = id + and type value = Script_repr.expr + and type t := Raw_context.t + + module Value_type : + Indexed_data_storage + with type key = id + and type value = Script_repr.expr + and type t := Raw_context.t +end + +module Sapling : sig + type id = Lazy_storage_kind.Sapling_state.Id.t + + val rpc_arg : id RPC_arg.t + + module Next : sig + val incr : Raw_context.t -> (Raw_context.t * id) tzresult Lwt.t + + val init : Raw_context.t -> Raw_context.t tzresult Lwt.t + end + + val copy : Raw_context.t -> from:id -> to_:id -> Raw_context.t tzresult Lwt.t + + val remove : Raw_context.t -> id -> Raw_context.t Lwt.t + + module Total_bytes : + Indexed_data_storage + with type key = id + and type value = Z.t + and type t := Raw_context.t + + (* Used by both Commitments and Ciphertexts *) + module Commitments_size : + Single_data_storage with type t := Raw_context.t * id and type value = int64 + + module Memo_size : + Single_data_storage with type t := Raw_context.t * id and type value = int + + module Commitments : + Non_iterable_indexed_carbonated_data_storage + with type t := Raw_context.t * id + and type key = int64 + and type value = Sapling.Hash.t + + val commitments_init : Raw_context.t -> id -> Raw_context.t Lwt.t + + module Ciphertexts : + Non_iterable_indexed_carbonated_data_storage + with type t := Raw_context.t * id + and type key = int64 + and type value = Sapling.Ciphertext.t + + val ciphertexts_init : Raw_context.t -> id -> Raw_context.t Lwt.t + + module Nullifiers_size : + Single_data_storage with type t := Raw_context.t * id and type value = int64 + + module Nullifiers_ordered : + Non_iterable_indexed_data_storage + with type t := Raw_context.t * id + and type key = int64 + and type value = Sapling.Nullifier.t + + module Nullifiers_hashed : + Carbonated_data_set_storage + with type t := Raw_context.t * id + and type elt = Sapling.Nullifier.t + + val nullifiers_init : Raw_context.t -> id -> Raw_context.t Lwt.t + + module Roots : + Non_iterable_indexed_data_storage + with type t := Raw_context.t * id + and type key = int32 + and type value = Sapling.Hash.t + + module Roots_pos : + Single_data_storage with type t := Raw_context.t * id and type value = int32 + + module Roots_level : + Single_data_storage + with type t := Raw_context.t * id + and type value = Raw_level_repr.t +end + +(** Set of all registered delegates. *) +module Delegates : + Data_set_storage + with type t := Raw_context.t + and type elt = Signature.Public_key_hash.t + +(** Set of all active delegates with rolls. *) +module Active_delegates_with_rolls : + Data_set_storage + with type t := Raw_context.t + and type elt = Signature.Public_key_hash.t + +(** Set of all the delegates with frozen rewards/bonds/fees for a given cycle. *) +module Delegates_with_frozen_balance : + Data_set_storage + with type t = Raw_context.t * Cycle_repr.t + and type elt = Signature.Public_key_hash.t + +(** Votes *) + +module Vote : sig + module Pred_period_kind : + Single_data_storage + with type value = Voting_period_repr.kind + and type t := Raw_context.t + + module Current_period : + Single_data_storage + with type value = Voting_period_repr.t + and type t := Raw_context.t + + (** Participation exponential moving average, in centile of percentage *) + module Participation_ema : + Single_data_storage with type value = int32 and type t := Raw_context.t + + module Current_proposal : + Single_data_storage + with type value = Protocol_hash.t + and type t := Raw_context.t + + (** Sum of all rolls of all delegates. *) + module Listings_size : + Single_data_storage with type value = int32 and type t := Raw_context.t + + (** Contains all delegates with their assigned number of rolls. *) + module Listings : + Indexed_data_storage + with type key = Signature.Public_key_hash.t + and type value = int32 + and type t := Raw_context.t + + (** Set of protocol proposal with corresponding proposer delegate *) + module Proposals : + Data_set_storage + with type elt = Protocol_hash.t * Signature.Public_key_hash.t + and type t := Raw_context.t + + (** Keeps for each delegate the number of proposed protocols *) + module Proposals_count : + Indexed_data_storage + with type key = Signature.Public_key_hash.t + and type value = int + and type t := Raw_context.t + + (** Contains for each delegate its ballot *) + module Ballots : + Indexed_data_storage + with type key = Signature.Public_key_hash.t + and type value = Vote_repr.ballot + and type t := Raw_context.t +end + +module type FOR_CYCLE = sig + val init : + Raw_context.t -> + Cycle_repr.t -> + Seed_repr.seed -> + Raw_context.t tzresult Lwt.t + + val get : Raw_context.t -> Cycle_repr.t -> Seed_repr.seed tzresult Lwt.t + + val remove_existing : + Raw_context.t -> Cycle_repr.t -> Raw_context.t tzresult Lwt.t +end + +(** Seed *) + +module Seed : sig + (** Storage from this submodule must only be accessed through the + module `Seed`. *) + + type unrevealed_nonce = { + nonce_hash : Nonce_hash.t; + delegate : Signature.Public_key_hash.t; + rewards : Tez_repr.t; + fees : Tez_repr.t; + } + + type nonce_status = + | Unrevealed of unrevealed_nonce + | Revealed of Seed_repr.nonce + + module Nonce : + Non_iterable_indexed_data_storage + with type key := Level_repr.t + and type value := nonce_status + and type t := Raw_context.t + + module For_cycle : FOR_CYCLE +end + +(** Commitments *) + +module Commitments : + Indexed_data_storage + with type key = Blinded_public_key_hash.t + and type value = Tez_repr.t + and type t := Raw_context.t + +(** Ramp up security deposits... *) + +module Ramp_up : sig + module Rewards : + Indexed_data_storage + with type key = Cycle_repr.t + and type value := Tez_repr.t list * Tez_repr.t list + (* baking rewards per endorsement * endorsement rewards *) + and type t := Raw_context.t + + module Security_deposits : + Indexed_data_storage + with type key = Cycle_repr.t + and type value = Tez_repr.t * Tez_repr.t + (* baking * endorsement *) + and type t := Raw_context.t +end + +module Pending_migration : sig + module Balance_updates : + Single_data_storage + with type value = Receipt_repr.balance_updates + and type t := Raw_context.t + + module Operation_results : + Single_data_storage + with type value = Migration_repr.origination_result list + and type t := Raw_context.t + + val remove : + Raw_context.t -> + (Raw_context.t + * Receipt_repr.balance_updates + * Migration_repr.origination_result list) + tzresult + Lwt.t +end + +module Liquidity_baking : sig + (** Exponential moving average (ema) of flags set in protocol_data.contents. + If at any block it's above the threshold set in constants, + liquidity baking permanently shuts off. **) + module Escape_ema : + Single_data_storage with type t := Raw_context.t and type value = Int32.t + + (** Constant product market maker contract that receives liquidity baking subsidy. **) + module Cpmm_address : + Single_data_storage + with type t := Raw_context.t + and type value = Contract_repr.t +end + +(** A map of [Script_repr.expr] values, indexed by their hash ([Script_expr_hash.t]). + Values from this map can be incorporated by any contract via the primitive + [Michelson_v1_primitives.H_constant]. *) +module Global_constants : sig + module Map : + Non_iterable_indexed_carbonated_data_storage + with type t := Raw_context.t + and type key = Script_expr_hash.t + and type value = Script_repr.expr +end diff --git a/src/proto_011_PtHangzH/lib_protocol/storage_costs.ml b/src/proto_011_PtHangzH/lib_protocol/storage_costs.ml new file mode 100644 index 000000000000..dae9e12456fe --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/storage_costs.ml @@ -0,0 +1,43 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* The model for read accesses is the following: + + cost(path_length, read_bytes) = 200_000 + 5000 * path_length + 2 * read_bytes +*) +let read_access ~path_length ~read_bytes = + let open Saturation_repr in + let base_cost = safe_int (200_000 + (5000 * path_length)) in + Gas_limit_repr.atomic_step_cost + (add base_cost (mul (safe_int 2) (safe_int read_bytes))) + +(* The model for write accesses is the following: + + cost(written_bytes) = 200_000 + 4 * written_bytes +*) +let write_access ~written_bytes = + let open Saturation_repr in + Gas_limit_repr.atomic_step_cost + (add (safe_int 200_000) (mul (safe_int 4) (safe_int written_bytes))) diff --git a/src/proto_011_PtHangzH/lib_protocol/storage_costs.mli b/src/proto_011_PtHangzH/lib_protocol/storage_costs.mli new file mode 100644 index 000000000000..0b91ce04eaae --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/storage_costs.mli @@ -0,0 +1,30 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Cost of reading [read_bytes] at a key of length [path_length]. *) +val read_access : path_length:int -> read_bytes:int -> Gas_limit_repr.cost + +(** Cost of performing a single write access, writing [written_bytes] bytes. *) +val write_access : written_bytes:int -> Gas_limit_repr.cost diff --git a/src/proto_011_PtHangzH/lib_protocol/storage_description.ml b/src/proto_011_PtHangzH/lib_protocol/storage_description.ml new file mode 100644 index 000000000000..72b91e8bd433 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/storage_description.ml @@ -0,0 +1,388 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +module StringMap = Map.Make (String) + +type 'key t = 'key desc_with_path + +(** [desc_with_path] describes a position in the storage. It's composed + [rev_path] which is the reverse path up to the position, and [dir] the + position's [description]. [rev_path] is only useful in case of an error to + print a descriptive message. [List.rev rev_path] is a storage's path that + contains no conflict and allows the registration of a [dir]'s storage. + NB: [rev_path] indicates the position in the tree, so once the node is + added, it won't change; whereas [dir] is mutable because when more subtrees + are added this may require updating it. *) +and 'key desc_with_path = { + rev_path : string list; + mutable dir : 'key description; +} + +and 'key description = + | Empty : 'key description + | Value : { + get : 'key -> 'a option tzresult Lwt.t; + encoding : 'a Data_encoding.t; + } + -> 'key description + | NamedDir : 'key t StringMap.t -> 'key description + | IndexedDir : { + arg : 'a RPC_arg.t; + arg_encoding : 'a Data_encoding.t; + list : 'key -> 'a list tzresult Lwt.t; + subdir : ('key * 'a) t; + } + -> 'key description + +let[@coq_struct "function_parameter"] rec pp : + type a. Format.formatter -> a t -> unit = + fun ppf {dir; _} -> + match dir with + | Empty -> Format.fprintf ppf "Empty" + | Value _e -> Format.fprintf ppf "Value" + | NamedDir map -> + Format.fprintf + ppf + "@[%a@]" + (Format.pp_print_list pp_item) + (StringMap.bindings map) + | IndexedDir {arg; subdir; _} -> + let name = Format.asprintf "<%s>" (RPC_arg.descr arg).name in + pp_item ppf (name, subdir) + +and[@coq_mutual_as_notation] pp_item : + type a. Format.formatter -> string * a t -> unit = + fun ppf (name, desc) -> Format.fprintf ppf "@[%s@ %a@]" name pp desc + +let pp_rev_path ppf path = + Format.fprintf + ppf + "[%a]" + Format.( + pp_print_list + ~pp_sep:(fun ppf () -> pp_print_string ppf " / ") + pp_print_string) + (List.rev path) + +let rec register_named_subcontext : type r. r t -> string list -> r t = + fun desc names -> + match (desc.dir, names) with + | (_, []) -> desc + | (Value _, _) | (IndexedDir _, _) -> + Format.kasprintf + invalid_arg + "Could not register a named subcontext at %a because of an existing %a." + pp_rev_path + desc.rev_path + pp + desc + | (Empty, name :: names) -> + let subdir = {rev_path = name :: desc.rev_path; dir = Empty} in + desc.dir <- NamedDir (StringMap.singleton name subdir) ; + register_named_subcontext subdir names + | (NamedDir map, name :: names) -> + let subdir = + match StringMap.find name map with + | Some subdir -> subdir + | None -> + let subdir = {rev_path = name :: desc.rev_path; dir = Empty} in + desc.dir <- NamedDir (StringMap.add name subdir map) ; + subdir + in + register_named_subcontext subdir names + +type (_, _, _) args = + | One : { + rpc_arg : 'a RPC_arg.t; + encoding : 'a Data_encoding.t; + compare : 'a -> 'a -> int; + } + -> ('key, 'a, 'key * 'a) args + | Pair : + ('key, 'a, 'inter_key) args * ('inter_key, 'b, 'sub_key) args + -> ('key, 'a * 'b, 'sub_key) args + +let rec unpack : type a b c. (a, b, c) args -> c -> a * b = function + | One _ -> fun x -> x + | Pair (l, r) -> + let unpack_l = unpack l in + let unpack_r = unpack r in + fun x -> + let (c, d) = unpack_r x in + let (b, a) = unpack_l c in + (b, (a, d)) + [@@coq_axiom_with_reason "gadt"] + +let rec pack : type a b c. (a, b, c) args -> a -> b -> c = function + | One _ -> fun b a -> (b, a) + | Pair (l, r) -> + let pack_l = pack l in + let pack_r = pack r in + fun b (a, d) -> + let c = pack_l b a in + pack_r c d + [@@coq_axiom_with_reason "gadt"] + +let rec compare : type a b c. (a, b, c) args -> b -> b -> int = function + | One {compare; _} -> compare + | Pair (l, r) -> ( + let compare_l = compare l in + let compare_r = compare r in + fun (a1, b1) (a2, b2) -> + match compare_l a1 a2 with 0 -> compare_r b1 b2 | x -> x) + [@@coq_axiom_with_reason "gadt"] + +let destutter equal l = + match l with + | [] -> [] + | (i, _) :: l -> + let rec loop acc i = function + | [] -> acc + | (j, _) :: l -> if equal i j then loop acc i l else loop (j :: acc) j l + in + loop [i] i l + +let rec register_indexed_subcontext : + type r a b. + r t -> list:(r -> a list tzresult Lwt.t) -> (r, a, b) args -> b t = + fun desc ~list path -> + match path with + | Pair (left, right) -> + let compare_left = compare left in + let equal_left x y = Compare.Int.(compare_left x y = 0) in + let list_left r = list r >|=? fun l -> destutter equal_left l in + let list_right r = + let (a, k) = unpack left r in + list a >|=? fun l -> + List.map snd (List.filter (fun (x, _) -> equal_left x k) l) + in + register_indexed_subcontext + (register_indexed_subcontext desc ~list:list_left left) + ~list:list_right + right + | One {rpc_arg = arg; encoding = arg_encoding; _} -> ( + match desc.dir with + | Value _ | NamedDir _ -> + Format.kasprintf + invalid_arg + "Could not register an indexed subcontext at %a because of an \ + existing %a." + pp_rev_path + desc.rev_path + pp + desc + | Empty -> + let subdir = + { + rev_path = + Format.sprintf "(Maybe of %s)" RPC_arg.(descr arg).name + :: desc.rev_path; + dir = Empty; + } + in + desc.dir <- IndexedDir {arg; arg_encoding; list; subdir} ; + subdir + | IndexedDir {arg = inner_arg; subdir; _} -> ( + match RPC_arg.eq arg inner_arg with + | None -> + Format.kasprintf + invalid_arg + "An indexed subcontext at %a already exists but has a \ + different argument: `%s` <> `%s`." + pp_rev_path + desc.rev_path + (RPC_arg.descr arg).name + (RPC_arg.descr inner_arg).name + | Some RPC_arg.Eq -> subdir)) + [@@coq_axiom_with_reason "gadt"] + +let register_value : + type a b. + a t -> get:(a -> b option tzresult Lwt.t) -> b Data_encoding.t -> unit = + fun desc ~get encoding -> + match desc.dir with + | Empty -> desc.dir <- Value {get; encoding} + | _ -> + Format.kasprintf + invalid_arg + "Could not register a value at %a because of an existing %a." + pp_rev_path + desc.rev_path + pp + desc + +let create () = {rev_path = []; dir = Empty} + +module type INDEX = sig + type t + + include Path_encoding.S with type t := t + + val rpc_arg : t RPC_arg.t + + val encoding : t Data_encoding.t + + val compare : t -> t -> int +end + +type _ handler = + | Handler : { + encoding : 'a Data_encoding.t; + get : 'key -> int -> 'a tzresult Lwt.t; + } + -> 'key handler + +type _ opt_handler = + | Opt_handler : { + encoding : 'a Data_encoding.t; + get : 'key -> int -> 'a option tzresult Lwt.t; + } + -> 'key opt_handler + +let rec combine_object = function + | [] -> + Handler {encoding = Data_encoding.unit; get = (fun _ _ -> return_unit)} + | (name, Opt_handler handler) :: fields -> + let (Handler handlers) = combine_object fields in + Handler + { + encoding = + Data_encoding.merge_objs + Data_encoding.(obj1 (opt name (dynamic_size handler.encoding))) + handlers.encoding; + get = + (fun k i -> + handler.get k i >>=? fun v1 -> + handlers.get k i >|=? fun v2 -> (v1, v2)); + } + [@@coq_axiom_with_reason "gadt"] + +type query = {depth : int} + +let depth_query = + let open RPC_query in + query (fun depth -> {depth}) + |+ field "depth" RPC_arg.int 0 (fun t -> t.depth) + |> seal + +let build_directory : type key. key t -> key RPC_directory.t = + fun dir -> + let rpc_dir = ref (RPC_directory.empty : key RPC_directory.t) in + let register : + type ikey. + chunked:bool -> (key, ikey) RPC_path.t -> ikey opt_handler -> unit = + fun ~chunked path (Opt_handler {encoding; get}) -> + let service = + RPC_service.get_service ~query:depth_query ~output:encoding path + in + rpc_dir := + RPC_directory.opt_register ~chunked !rpc_dir service (fun k q () -> + get k (q.depth + 1)) + in + let rec build_handler : + type ikey. ikey t -> (key, ikey) RPC_path.t -> ikey opt_handler = + fun desc path -> + match desc.dir with + | Empty -> + Opt_handler + {encoding = Data_encoding.unit; get = (fun _ _ -> return_none)} + | Value {get; encoding} -> + let handler = + Opt_handler + { + encoding; + get = + (fun k i -> if Compare.Int.(i < 0) then return_none else get k); + } + in + register ~chunked:true path handler ; + handler + | NamedDir map -> + let fields = StringMap.bindings map in + let fields = + List.map + (fun (name, dir) -> + (name, build_handler dir RPC_path.(path / name))) + fields + in + let (Handler handler) = combine_object fields in + let handler = + Opt_handler + { + encoding = handler.encoding; + get = + (fun k i -> + if Compare.Int.(i < 0) then return_none + else handler.get k (i - 1) >>=? fun v -> return_some v); + } + in + register ~chunked:true path handler ; + handler + | IndexedDir {arg; arg_encoding; list; subdir} -> + let (Opt_handler handler) = + build_handler subdir RPC_path.(path /: arg) + in + let encoding = + let open Data_encoding in + union + [ + case + (Tag 0) + ~title:"Leaf" + (dynamic_size arg_encoding) + (function (key, None) -> Some key | _ -> None) + (fun key -> (key, None)); + case + (Tag 1) + ~title:"Dir" + (tup2 + (dynamic_size arg_encoding) + (dynamic_size handler.encoding)) + (function (key, Some value) -> Some (key, value) | _ -> None) + (fun (key, value) -> (key, Some value)); + ] + in + let get k i = + if Compare.Int.(i < 0) then return_none + else if Compare.Int.(i = 0) then return_some [] + else + list k >>=? fun keys -> + List.map_es + (fun key -> + if Compare.Int.(i = 1) then return (key, None) + else handler.get (k, key) (i - 1) >|=? fun value -> (key, value)) + keys + >>=? fun values -> return_some values + in + let handler = + Opt_handler + {encoding = Data_encoding.(list (dynamic_size encoding)); get} + in + register ~chunked:true path handler ; + handler + in + ignore (build_handler dir RPC_path.open_root : key opt_handler) ; + !rpc_dir + [@@coq_axiom_with_reason "gadt"] diff --git a/src/proto_011_PtHangzH/lib_protocol/storage_description.mli b/src/proto_011_PtHangzH/lib_protocol/storage_description.mli new file mode 100644 index 000000000000..33e44cc39f13 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/storage_description.mli @@ -0,0 +1,93 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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 is responsible for building the description of the current state + of the storage, which is then used to build specification of the RPC + endpoints for accessing the storage. It produces [resto] [RPC_directory.t] + values, which can be used directly to construct the RPC endpoint tree. *) + +(** Typed description of the key-value context. *) +type 'key t + +(** Trivial display of the key-value context layout. *) +val pp : Format.formatter -> 'key t -> unit + +(** Export an RPC hierarchy for querying the context. There is one service + by possible path in the context. Services for "directory" are able to + aggregate in one JSON object the whole subtree. *) +val build_directory : 'key t -> 'key RPC_directory.t + +(** Create a empty context description, + keys will be registered by side effects. *) +val create : unit -> 'key t + +(** Register a single key accessor at a given path. *) +val register_value : + 'key t -> get:('key -> 'a option tzresult Lwt.t) -> 'a Data_encoding.t -> unit + +(** Return a description for a prefixed fragment of the given context. + All keys registered in the subcontext will be shared by the external + context *) +val register_named_subcontext : 'key t -> string list -> 'key t + +(** Description of an index as a sequence of `RPC_arg.t`. *) +type (_, _, _) args = + | One : { + rpc_arg : 'a RPC_arg.t; + encoding : 'a Data_encoding.t; + compare : 'a -> 'a -> int; + } + -> ('key, 'a, 'key * 'a) args + | Pair : + ('key, 'a, 'inter_key) args * ('inter_key, 'b, 'sub_key) args + -> ('key, 'a * 'b, 'sub_key) args + +(** Return a description for a indexed sub-context. + All keys registered in the subcontext will be shared by the external + context. One should provide a function to list all the registered + index in the context. *) +val register_indexed_subcontext : + 'key t -> + list:('key -> 'arg list tzresult Lwt.t) -> + ('key, 'arg, 'sub_key) args -> + 'sub_key t + +(** Helpers for manipulating and defining indexes. *) + +val pack : ('key, 'a, 'sub_key) args -> 'key -> 'a -> 'sub_key + +val unpack : ('key, 'a, 'sub_key) args -> 'sub_key -> 'key * 'a + +module type INDEX = sig + type t + + include Path_encoding.S with type t := t + + val rpc_arg : t RPC_arg.t + + val encoding : t Data_encoding.t + + val compare : t -> t -> int +end diff --git a/src/proto_011_PtHangzH/lib_protocol/storage_functors.ml b/src/proto_011_PtHangzH/lib_protocol/storage_functors.ml new file mode 100644 index 000000000000..ae6b79a5073d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/storage_functors.ml @@ -0,0 +1,1085 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Storage_sigs + +module Registered = struct + let ghost = false +end + +module Ghost = struct + let ghost = true +end + +module type ENCODER = sig + type t + + val of_bytes : key:(unit -> string list) -> bytes -> t tzresult + + val to_bytes : t -> bytes +end + +module Make_encoder (V : VALUE) : ENCODER with type t := V.t = struct + let of_bytes ~key b = + match Data_encoding.Binary.of_bytes_opt V.encoding b with + | None -> error (Raw_context.Storage_error (Corrupted_data (key ()))) + | Some v -> Ok v + + let to_bytes v = + match Data_encoding.Binary.to_bytes_opt V.encoding v with + | Some b -> b + | None -> Bytes.empty +end + +let len_name = "len" + +let data_name = "data" + +let encode_len_value bytes = + let length = Bytes.length bytes in + Data_encoding.(Binary.to_bytes_exn int31) length + +let decode_len_value key len = + match Data_encoding.(Binary.of_bytes_opt int31) len with + | None -> error (Raw_context.Storage_error (Corrupted_data key)) + | Some len -> ok len + +module Make_subcontext (R : REGISTER) (C : Raw_context.T) (N : NAME) : + Raw_context.T with type t = C.t = struct + type t = C.t + + let to_key k = N.name @ k + + let mem t k = C.mem t (to_key k) + + let mem_tree t k = C.mem_tree t (to_key k) + + let get t k = C.get t (to_key k) + + let get_tree t k = C.get_tree t (to_key k) + + let find t k = C.find t (to_key k) + + let find_tree t k = C.find_tree t (to_key k) + + let add t k v = C.add t (to_key k) v + + let add_tree t k v = C.add_tree t (to_key k) v + + let init t k v = C.init t (to_key k) v + + let init_tree t k v = C.init_tree t (to_key k) v + + let update t k v = C.update t (to_key k) v + + let update_tree t k v = C.update_tree t (to_key k) v + + let add_or_remove t k v = C.add_or_remove t (to_key k) v + + let add_or_remove_tree t k v = C.add_or_remove_tree t (to_key k) v + + let remove_existing t k = C.remove_existing t (to_key k) + + let remove_existing_tree t k = C.remove_existing_tree t (to_key k) + + let remove t k = C.remove t (to_key k) + + let list t ?offset ?length k = C.list t ?offset ?length (to_key k) + + let fold ?depth t k ~init ~f = C.fold ?depth t (to_key k) ~init ~f + + module Tree = C.Tree + + let project = C.project + + let absolute_key c k = C.absolute_key c (to_key k) + + type error += Block_quota_exceeded = C.Block_quota_exceeded + + type error += Operation_quota_exceeded = C.Operation_quota_exceeded + + let consume_gas = C.consume_gas + + let check_enough_gas = C.check_enough_gas + + let description = + let description = + if R.ghost then Storage_description.create () else C.description + in + Storage_description.register_named_subcontext description N.name +end + +module Make_single_data_storage + (R : REGISTER) + (C : Raw_context.T) + (N : NAME) + (V : VALUE) : Single_data_storage with type t = C.t and type value = V.t = +struct + type t = C.t + + type context = t + + type value = V.t + + let mem t = C.mem t N.name + + include Make_encoder (V) + + let get t = + C.get t N.name >>=? fun b -> + let key () = C.absolute_key t N.name in + Lwt.return (of_bytes ~key b) + + let find t = + C.find t N.name >|= function + | None -> ok_none + | Some b -> + let key () = C.absolute_key t N.name in + of_bytes ~key b >|? fun v -> Some v + + let init t v = C.init t N.name (to_bytes v) >|=? fun t -> C.project t + + let update t v = C.update t N.name (to_bytes v) >|=? fun t -> C.project t + + let add t v = C.add t N.name (to_bytes v) >|= fun t -> C.project t + + let add_or_remove t v = + C.add_or_remove t N.name (Option.map to_bytes v) >|= fun t -> C.project t + + let remove t = C.remove t N.name >|= fun t -> C.project t + + let remove_existing t = C.remove_existing t N.name >|=? fun t -> C.project t + + let () = + let open Storage_description in + let description = + if R.ghost then Storage_description.create () else C.description + in + register_value + ~get:find + (register_named_subcontext description N.name) + V.encoding + [@@coq_axiom_with_reason "stack overflow in Coq"] +end + +module type INDEX = sig + type t + + include Path_encoding.S with type t := t + + type 'a ipath + + val args : ('a, t, 'a ipath) Storage_description.args +end + +module Pair (I1 : INDEX) (I2 : INDEX) : INDEX with type t = I1.t * I2.t = struct + type t = I1.t * I2.t + + let path_length = I1.path_length + I2.path_length + + let to_path (x, y) l = I1.to_path x (I2.to_path y l) + + let of_path l = + match Misc.take I1.path_length l with + | None -> None + | Some (l1, l2) -> ( + match (I1.of_path l1, I2.of_path l2) with + | (Some x, Some y) -> Some (x, y) + | _ -> None) + + type 'a ipath = 'a I1.ipath I2.ipath + + let args = Storage_description.Pair (I1.args, I2.args) +end + +module Make_data_set_storage (C : Raw_context.T) (I : INDEX) : + Data_set_storage with type t = C.t and type elt = I.t = struct + type t = C.t + + type context = t + + type elt = I.t + + let inited = Bytes.of_string "inited" + + let mem s i = C.mem s (I.to_path i []) + + let add s i = C.add s (I.to_path i []) inited >|= fun t -> C.project t + + let remove s i = C.remove s (I.to_path i []) >|= fun t -> C.project t + + let clear s = C.remove s [] >|= fun t -> C.project t + + let fold s ~init ~f = + C.fold ~depth:(`Eq I.path_length) s [] ~init ~f:(fun file tree acc -> + match C.Tree.kind tree with + | `Value -> ( + match I.of_path file with None -> assert false | Some p -> f p acc) + | `Tree -> Lwt.return acc) + + let elements s = fold s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc)) + + let () = + let open Storage_description in + let unpack = unpack I.args in + register_value (* TODO fixme 'elements...' *) + ~get:(fun c -> + let (c, k) = unpack c in + mem c k >>= function true -> return_some true | false -> return_none) + (register_indexed_subcontext + ~list:(fun c -> elements c >|= ok) + C.description + I.args) + Data_encoding.bool + [@@coq_axiom_with_reason "stack overflow in Coq"] +end + +module Make_indexed_data_storage (C : Raw_context.T) (I : INDEX) (V : VALUE) : + Indexed_data_storage with type t = C.t and type key = I.t and type value = V.t = +struct + type t = C.t + + type context = t + + type key = I.t + + type value = V.t + + include Make_encoder (V) + + let mem s i = C.mem s (I.to_path i []) + + let get s i = + C.get s (I.to_path i []) >>=? fun b -> + let key () = C.absolute_key s (I.to_path i []) in + Lwt.return (of_bytes ~key b) + + let find s i = + C.find s (I.to_path i []) >|= function + | None -> ok_none + | Some b -> + let key () = C.absolute_key s (I.to_path i []) in + of_bytes ~key b >|? fun v -> Some v + + let update s i v = + C.update s (I.to_path i []) (to_bytes v) >|=? fun t -> C.project t + + let init s i v = + C.init s (I.to_path i []) (to_bytes v) >|=? fun t -> C.project t + + let add s i v = C.add s (I.to_path i []) (to_bytes v) >|= fun t -> C.project t + + let add_or_remove s i v = + C.add_or_remove s (I.to_path i []) (Option.map to_bytes v) >|= fun t -> + C.project t + + let remove s i = C.remove s (I.to_path i []) >|= fun t -> C.project t + + let remove_existing s i = + C.remove_existing s (I.to_path i []) >|=? fun t -> C.project t + + let clear s = C.remove s [] >|= fun t -> C.project t + + let fold s ~init ~f = + C.fold ~depth:(`Eq I.path_length) s [] ~init ~f:(fun file tree acc -> + C.Tree.to_value tree >>= function + | Some v -> ( + match I.of_path file with + | None -> assert false + | Some path -> ( + let key () = C.absolute_key s file in + match of_bytes ~key v with + | Ok v -> f path v acc + | Error _ -> Lwt.return acc)) + | None -> Lwt.return acc) + + let fold_keys s ~init ~f = fold s ~init ~f:(fun k _ acc -> f k acc) + + let bindings s = + fold s ~init:[] ~f:(fun p v acc -> Lwt.return ((p, v) :: acc)) + + let keys s = fold_keys s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc)) + + let () = + let open Storage_description in + let unpack = unpack I.args in + register_value + ~get:(fun c -> + let (c, k) = unpack c in + find c k) + (register_indexed_subcontext + ~list:(fun c -> keys c >|= ok) + C.description + I.args) + V.encoding + [@@coq_axiom_with_reason "stack overflow in Coq"] +end + +(* Internal-use-only version of {!Make_indexed_carbonated_data_storage} to + expose fold_keys_unaccounted *) +module Make_indexed_carbonated_data_storage_INTERNAL + (C : Raw_context.T) + (I : INDEX) + (V : VALUE) : + Non_iterable_indexed_carbonated_data_storage_INTERNAL + with type t = C.t + and type key = I.t + and type value = V.t = struct + type t = C.t + + type context = t + + type key = I.t + + type value = V.t + + include Make_encoder (V) + + let data_key i = I.to_path i [data_name] + + let len_key i = I.to_path i [len_name] + + let consume_mem_gas c key = + C.consume_gas + c + (Storage_costs.read_access ~path_length:(List.length key) ~read_bytes:0) + + let existing_size c i = + C.find c (len_key i) >|= function + | None -> ok (0, false) + | Some len -> decode_len_value (len_key i) len >|? fun len -> (len, true) + + let consume_read_gas get c i = + let len_key = len_key i in + get c len_key >>=? fun len -> + Lwt.return + ( decode_len_value len_key len >>? fun read_bytes -> + let cost = + Storage_costs.read_access + ~path_length:(List.length len_key) + ~read_bytes + in + C.consume_gas c cost ) + + (* For the future: here, we bill a generic cost for encoding the value + to bytes. It would be cleaner for users of this functor to provide + gas costs for the encoding. *) + let consume_serialize_write_gas set c i v = + let bytes = to_bytes v in + let len = Bytes.length bytes in + C.consume_gas c (Gas_limit_repr.alloc_mbytes_cost len) >>?= fun c -> + let cost = Storage_costs.write_access ~written_bytes:len in + C.consume_gas c cost >>?= fun c -> + set c (len_key i) (encode_len_value bytes) >|=? fun c -> (c, bytes) + + let consume_remove_gas del c i = + C.consume_gas c (Storage_costs.write_access ~written_bytes:0) >>?= fun c -> + del c (len_key i) + + let mem s i = + let key = data_key i in + consume_mem_gas s key >>?= fun s -> + C.mem s key >|= fun exists -> ok (C.project s, exists) + + let get_unprojected s i = + consume_read_gas C.get s i >>=? fun s -> + C.get s (data_key i) >>=? fun b -> + let key () = C.absolute_key s (data_key i) in + Lwt.return (of_bytes ~key b >|? fun v -> (s, v)) + + let get s i = get_unprojected s i >|=? fun (s, v) -> (C.project s, v) + + let find s i = + let key = data_key i in + consume_mem_gas s key >>?= fun s -> + C.mem s key >>= fun exists -> + if exists then get s i >|=? fun (s, v) -> (s, Some v) + else return (C.project s, None) + + let update s i v = + existing_size s i >>=? fun (prev_size, _) -> + consume_serialize_write_gas C.update s i v >>=? fun (s, bytes) -> + C.update s (data_key i) bytes >|=? fun t -> + let size_diff = Bytes.length bytes - prev_size in + (C.project t, size_diff) + + let init s i v = + consume_serialize_write_gas C.init s i v >>=? fun (s, bytes) -> + C.init s (data_key i) bytes >|=? fun t -> + let size = Bytes.length bytes in + (C.project t, size) + + let add s i v = + let add s i v = C.add s i v >|= ok in + existing_size s i >>=? fun (prev_size, existed) -> + consume_serialize_write_gas add s i v >>=? fun (s, bytes) -> + add s (data_key i) bytes >|=? fun t -> + let size_diff = Bytes.length bytes - prev_size in + (C.project t, size_diff, existed) + + let remove s i = + let remove s i = C.remove s i >|= ok in + existing_size s i >>=? fun (prev_size, existed) -> + consume_remove_gas remove s i >>=? fun s -> + remove s (data_key i) >|=? fun t -> (C.project t, prev_size, existed) + + let remove_existing s i = + existing_size s i >>=? fun (prev_size, _) -> + consume_remove_gas C.remove_existing s i >>=? fun s -> + C.remove_existing s (data_key i) >|=? fun t -> (C.project t, prev_size) + + let add_or_remove s i v = + match v with None -> remove s i | Some v -> add s i v + + (** Because big map values are not stored under some common key, + we have no choice but to fold over all nodes with a path of length + [I.path_length] to retrieve actual keys and then paginate. + + While this is inefficient and will traverse the whole tree ([O(n)]), there + currently isn't a better decent alternative. + + Once https://gitlab.com/tezos/tezos/-/merge_requests/2771 which flattens paths is done, + {!C.list} could be used instead here. *) + let list_values ?(offset = 0) ?(length = max_int) s = + let root = [] in + let depth = `Eq I.path_length in + C.fold + s + root + ~depth + ~init:(ok (s, [], offset, length)) + ~f:(fun file tree acc -> + match (C.Tree.kind tree, acc) with + | (`Tree, Ok (s, rev_values, offset, length)) -> ( + if Compare.Int.(length <= 0) then + (* Keep going until the end, we have no means of short-circuiting *) + Lwt.return acc + else if Compare.Int.(offset > 0) then + (* Offset (first element) not reached yet *) + let offset = pred offset in + Lwt.return (Ok (s, rev_values, offset, length)) + else + (* Nominal case *) + match I.of_path file with + | None -> assert false + | Some key -> + get_unprojected s key >|=? fun (s, value) -> + (s, value :: rev_values, 0, pred length)) + | _ -> Lwt.return acc) + >|=? fun (s, rev_values, _offset, _length) -> + (C.project s, List.rev rev_values) + + let fold_keys_unaccounted s ~init ~f = + C.fold ~depth:(`Eq I.path_length) s [] ~init ~f:(fun file tree acc -> + match C.Tree.kind tree with + | `Value -> ( + match List.rev file with + | last :: _ when Compare.String.(last = len_name) -> Lwt.return acc + | last :: rest when Compare.String.(last = data_name) -> ( + let file = List.rev rest in + match I.of_path file with + | None -> assert false + | Some path -> f path acc) + | _ -> assert false) + | `Tree -> Lwt.return acc) + + let keys_unaccounted s = + fold_keys_unaccounted s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc)) + + let () = + let open Storage_description in + let unpack = unpack I.args in + register_value (* TODO export consumed gas ?? *) + ~get:(fun c -> + let (c, k) = unpack c in + find c k >|=? fun (_, v) -> v) + (register_indexed_subcontext + ~list:(fun c -> keys_unaccounted c >|= ok) + C.description + I.args) + V.encoding + [@@coq_axiom_with_reason "stack overflow in Coq"] +end + +module Make_indexed_carbonated_data_storage : functor + (C : Raw_context.T) + (I : INDEX) + (V : VALUE) + -> + Non_iterable_indexed_carbonated_data_storage_with_values + with type t = C.t + and type key = I.t + and type value = V.t = + Make_indexed_carbonated_data_storage_INTERNAL + +module Make_carbonated_data_set_storage (C : Raw_context.T) (I : INDEX) : + Carbonated_data_set_storage with type t = C.t and type elt = I.t = struct + module V = struct + type t = unit + + let encoding = Data_encoding.unit + end + + module M = Make_indexed_carbonated_data_storage_INTERNAL (C) (I) (V) + + type t = M.t + + type context = t + + type elt = I.t + + let mem = M.mem + + let init s i = M.init s i () + + let remove s i = M.remove s i + + let fold_keys_unaccounted = M.fold_keys_unaccounted +end + +module Make_indexed_data_snapshotable_storage + (C : Raw_context.T) + (Snapshot_index : INDEX) + (I : INDEX) + (V : VALUE) : + Indexed_data_snapshotable_storage + with type t = C.t + and type snapshot = Snapshot_index.t + and type key = I.t + and type value = V.t = struct + type snapshot = Snapshot_index.t + + let data_name = ["current"] + + let snapshot_name = ["snapshot"] + + module C_data = + Make_subcontext (Registered) (C) + (struct + let name = data_name + end) + + module C_snapshot = + Make_subcontext (Registered) (C) + (struct + let name = snapshot_name + end) + + include Make_indexed_data_storage (C_data) (I) (V) + module Snapshot = + Make_indexed_data_storage (C_snapshot) (Pair (Snapshot_index) (I)) (V) + + let snapshot_path id = snapshot_name @ Snapshot_index.to_path id [] + + let snapshot_exists s id = C.mem_tree s (snapshot_path id) + + let err_missing_key key = Raw_context.storage_error (Missing_key (key, Copy)) + + let snapshot s id = + C.find_tree s data_name >>= function + | None -> Lwt.return (err_missing_key data_name) + | Some tree -> + C.add_tree s (snapshot_path id) tree >|= (fun t -> C.project t) >|= ok + + let delete_snapshot s id = + C.remove s (snapshot_path id) >|= fun t -> C.project t +end + +module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX) : + Indexed_raw_context + with type t = C.t + and type key = I.t + and type 'a ipath = 'a I.ipath = struct + type t = C.t + + type context = t + + type key = I.t + + type 'a ipath = 'a I.ipath + + let clear t = C.remove t [] >|= fun t -> C.project t + + let fold_keys t ~init ~f = + C.fold ~depth:(`Eq I.path_length) t [] ~init ~f:(fun path tree acc -> + match C.Tree.kind tree with + | `Tree -> ( + match I.of_path path with + | None -> assert false + | Some path -> f path acc) + | `Value -> Lwt.return acc) + + let keys t = fold_keys t ~init:[] ~f:(fun i acc -> Lwt.return (i :: acc)) + + let err_missing_key key = Raw_context.storage_error (Missing_key (key, Copy)) + + let copy t ~from ~to_ = + let from = I.to_path from [] in + let to_ = I.to_path to_ [] in + C.find_tree t from >>= function + | None -> Lwt.return (err_missing_key from) + | Some tree -> C.add_tree t to_ tree >|= ok + + let remove t k = C.remove t (I.to_path k []) + + let description = + Storage_description.register_indexed_subcontext + ~list:(fun c -> keys c >|= ok) + C.description + I.args + + let unpack = Storage_description.unpack I.args + + let pack = Storage_description.pack I.args + + module Raw_context : Raw_context.T with type t = C.t I.ipath = struct + type t = C.t I.ipath + + let to_key i k = I.to_path i k + + let mem c k = + let (t, i) = unpack c in + C.mem t (to_key i k) + + let mem_tree c k = + let (t, i) = unpack c in + C.mem_tree t (to_key i k) + + let get c k = + let (t, i) = unpack c in + C.get t (to_key i k) + + let get_tree c k = + let (t, i) = unpack c in + C.get_tree t (to_key i k) + + let find c k = + let (t, i) = unpack c in + C.find t (to_key i k) + + let find_tree c k = + let (t, i) = unpack c in + C.find_tree t (to_key i k) + + let list c ?offset ?length k = + let (t, i) = unpack c in + C.list t ?offset ?length (to_key i k) + + let init c k v = + let (t, i) = unpack c in + C.init t (to_key i k) v >|=? fun t -> pack t i + + let init_tree c k v = + let (t, i) = unpack c in + C.init_tree t (to_key i k) v >|=? fun t -> pack t i + + let update c k v = + let (t, i) = unpack c in + C.update t (to_key i k) v >|=? fun t -> pack t i + + let update_tree c k v = + let (t, i) = unpack c in + C.update_tree t (to_key i k) v >|=? fun t -> pack t i + + let add c k v = + let (t, i) = unpack c in + C.add t (to_key i k) v >|= fun t -> pack t i + + let add_tree c k v = + let (t, i) = unpack c in + C.add_tree t (to_key i k) v >|= fun t -> pack t i + + let add_or_remove c k v = + let (t, i) = unpack c in + C.add_or_remove t (to_key i k) v >|= fun t -> pack t i + + let add_or_remove_tree c k v = + let (t, i) = unpack c in + C.add_or_remove_tree t (to_key i k) v >|= fun t -> pack t i + + let remove_existing c k = + let (t, i) = unpack c in + C.remove_existing t (to_key i k) >|=? fun t -> pack t i + + let remove_existing_tree c k = + let (t, i) = unpack c in + C.remove_existing_tree t (to_key i k) >|=? fun t -> pack t i + + let remove c k = + let (t, i) = unpack c in + C.remove t (to_key i k) >|= fun t -> pack t i + + let fold ?depth c k ~init ~f = + let (t, i) = unpack c in + C.fold ?depth t (to_key i k) ~init ~f + + module Tree = struct + include C.Tree + + let empty c = + let (t, _) = unpack c in + C.Tree.empty t + end + + let project c = + let (t, _) = unpack c in + C.project t + + let absolute_key c k = + let (t, i) = unpack c in + C.absolute_key t (to_key i k) + + type error += Block_quota_exceeded = C.Block_quota_exceeded + + type error += Operation_quota_exceeded = C.Operation_quota_exceeded + + let consume_gas c g = + let (t, i) = unpack c in + C.consume_gas t g >>? fun t -> ok (pack t i) + + let check_enough_gas c g = + let (t, _i) = unpack c in + C.check_enough_gas t g + + let description = description + end + + module Make_set (R : REGISTER) (N : NAME) : + Data_set_storage with type t = t and type elt = key = struct + type t = C.t + + type context = t + + type elt = I.t + + let inited = Bytes.of_string "inited" + + let mem s i = Raw_context.mem (pack s i) N.name + + let add s i = + Raw_context.add (pack s i) N.name inited >|= fun c -> + let (s, _) = unpack c in + C.project s + + let remove s i = + Raw_context.remove (pack s i) N.name >|= fun c -> + let (s, _) = unpack c in + C.project s + + let clear s = + fold_keys s ~init:s ~f:(fun i s -> + Raw_context.remove (pack s i) N.name >|= fun c -> + let (s, _) = unpack c in + s) + >|= fun t -> C.project t + + let fold s ~init ~f = + fold_keys s ~init ~f:(fun i acc -> + mem s i >>= function true -> f i acc | false -> Lwt.return acc) + + let elements s = fold s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc)) + + let () = + let open Storage_description in + let unpack = unpack I.args in + let description = + if R.ghost then Storage_description.create () + else Raw_context.description + in + register_value + ~get:(fun c -> + let (c, k) = unpack c in + mem c k >>= function true -> return_some true | false -> return_none) + (register_named_subcontext description N.name) + Data_encoding.bool + [@@coq_axiom_with_reason "stack overflow in Coq"] + end + + module Make_map (N : NAME) (V : VALUE) : + Indexed_data_storage with type t = t and type key = key and type value = V.t = + struct + type t = C.t + + type context = t + + type key = I.t + + type value = V.t + + include Make_encoder (V) + + let mem s i = Raw_context.mem (pack s i) N.name + + let get s i = + Raw_context.get (pack s i) N.name >>=? fun b -> + let key () = Raw_context.absolute_key (pack s i) N.name in + Lwt.return (of_bytes ~key b) + + let find s i = + Raw_context.find (pack s i) N.name >|= function + | None -> ok_none + | Some b -> + let key () = Raw_context.absolute_key (pack s i) N.name in + of_bytes ~key b >|? fun v -> Some v + + let update s i v = + Raw_context.update (pack s i) N.name (to_bytes v) >|=? fun c -> + let (s, _) = unpack c in + C.project s + + let init s i v = + Raw_context.init (pack s i) N.name (to_bytes v) >|=? fun c -> + let (s, _) = unpack c in + C.project s + + let add s i v = + Raw_context.add (pack s i) N.name (to_bytes v) >|= fun c -> + let (s, _) = unpack c in + C.project s + + let add_or_remove s i v = + Raw_context.add_or_remove (pack s i) N.name (Option.map to_bytes v) + >|= fun c -> + let (s, _) = unpack c in + C.project s + + let remove s i = + Raw_context.remove (pack s i) N.name >|= fun c -> + let (s, _) = unpack c in + C.project s + + let remove_existing s i = + Raw_context.remove_existing (pack s i) N.name >|=? fun c -> + let (s, _) = unpack c in + C.project s + + let clear s = + fold_keys s ~init:s ~f:(fun i s -> + Raw_context.remove (pack s i) N.name >|= fun c -> + let (s, _) = unpack c in + s) + >|= fun t -> C.project t + + let fold s ~init ~f = + fold_keys s ~init ~f:(fun i acc -> + get s i >>= function Error _ -> Lwt.return acc | Ok v -> f i v acc) + + let bindings s = + fold s ~init:[] ~f:(fun p v acc -> Lwt.return ((p, v) :: acc)) + + let fold_keys s ~init ~f = + fold_keys s ~init ~f:(fun i acc -> + mem s i >>= function false -> Lwt.return acc | true -> f i acc) + + let keys s = fold_keys s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc)) + + let () = + let open Storage_description in + let unpack = unpack I.args in + register_value + ~get:(fun c -> + let (c, k) = unpack c in + find c k) + (register_named_subcontext Raw_context.description N.name) + V.encoding + [@@coq_axiom_with_reason "stack overflow in Coq"] + end + + module Make_carbonated_map (N : NAME) (V : VALUE) : + Non_iterable_indexed_carbonated_data_storage + with type t = t + and type key = key + and type value = V.t = struct + type t = C.t + + type context = t + + type key = I.t + + type value = V.t + + include Make_encoder (V) + + let len_name = len_name :: N.name + + let data_name = data_name :: N.name + + let path_length = List.length N.name + 1 + + let consume_mem_gas c = + Raw_context.consume_gas + c + (Storage_costs.read_access ~path_length ~read_bytes:0) + + let existing_size c = + Raw_context.find c len_name >|= function + | None -> ok (0, false) + | Some len -> decode_len_value len_name len >|? fun len -> (len, true) + + let consume_read_gas get c = + get c len_name >>=? fun len -> + Lwt.return + ( decode_len_value len_name len >>? fun read_bytes -> + Raw_context.consume_gas + c + (Storage_costs.read_access ~path_length ~read_bytes) ) + + let consume_write_gas set c v = + let bytes = to_bytes v in + let len = Bytes.length bytes in + Raw_context.consume_gas c (Storage_costs.write_access ~written_bytes:len) + >>?= fun c -> + set c len_name (encode_len_value bytes) >|=? fun c -> (c, bytes) + + let consume_remove_gas del c = + Raw_context.consume_gas c (Storage_costs.write_access ~written_bytes:0) + >>?= fun c -> del c len_name + + let mem s i = + consume_mem_gas (pack s i) >>?= fun c -> + Raw_context.mem c data_name >|= fun res -> ok (Raw_context.project c, res) + + let get s i = + consume_read_gas Raw_context.get (pack s i) >>=? fun c -> + Raw_context.get c data_name >>=? fun b -> + let key () = Raw_context.absolute_key c data_name in + Lwt.return (of_bytes ~key b >|? fun v -> (Raw_context.project c, v)) + + let find s i = + consume_mem_gas (pack s i) >>?= fun c -> + let (s, _) = unpack c in + Raw_context.mem (pack s i) data_name >>= fun exists -> + if exists then get s i >|=? fun (s, v) -> (s, Some v) + else return (C.project s, None) + + let update s i v = + existing_size (pack s i) >>=? fun (prev_size, _) -> + consume_write_gas Raw_context.update (pack s i) v >>=? fun (c, bytes) -> + Raw_context.update c data_name bytes >|=? fun c -> + let size_diff = Bytes.length bytes - prev_size in + (Raw_context.project c, size_diff) + + let init s i v = + consume_write_gas Raw_context.init (pack s i) v >>=? fun (c, bytes) -> + Raw_context.init c data_name bytes >|=? fun c -> + let size = Bytes.length bytes in + (Raw_context.project c, size) + + let add s i v = + let add c k v = Raw_context.add c k v >|= ok in + existing_size (pack s i) >>=? fun (prev_size, existed) -> + consume_write_gas add (pack s i) v >>=? fun (c, bytes) -> + add c data_name bytes >|=? fun c -> + let size_diff = Bytes.length bytes - prev_size in + (Raw_context.project c, size_diff, existed) + + let remove s i = + let remove c k = Raw_context.remove c k >|= ok in + existing_size (pack s i) >>=? fun (prev_size, existed) -> + consume_remove_gas remove (pack s i) >>=? fun c -> + remove c data_name >|=? fun c -> + (Raw_context.project c, prev_size, existed) + + let remove_existing s i = + existing_size (pack s i) >>=? fun (prev_size, _) -> + consume_remove_gas Raw_context.remove_existing (pack s i) >>=? fun c -> + Raw_context.remove_existing c data_name >|=? fun c -> + (Raw_context.project c, prev_size) + + let add_or_remove s i v = + match v with None -> remove s i | Some v -> add s i v + + let () = + let open Storage_description in + let unpack = unpack I.args in + register_value + ~get:(fun c -> + let (c, k) = unpack c in + find c k >|=? fun (_, v) -> v) + (register_named_subcontext Raw_context.description N.name) + V.encoding + [@@coq_axiom_with_reason "stack overflow in Coq"] + end +end + +module type WRAPPER = sig + type t + + type key + + val wrap : t -> key + + val unwrap : key -> t option +end + +module Wrap_indexed_data_storage + (C : Indexed_data_storage) + (K : WRAPPER with type key := C.key) : + Indexed_data_storage + with type t = C.t + and type key = K.t + and type value = C.value = struct + type t = C.t + + type context = C.t + + type key = K.t + + type value = C.value + + let mem ctxt k = C.mem ctxt (K.wrap k) + + let get ctxt k = C.get ctxt (K.wrap k) + + let find ctxt k = C.find ctxt (K.wrap k) + + let update ctxt k v = C.update ctxt (K.wrap k) v + + let init ctxt k v = C.init ctxt (K.wrap k) v + + let add ctxt k v = C.add ctxt (K.wrap k) v + + let add_or_remove ctxt k v = C.add_or_remove ctxt (K.wrap k) v + + let remove_existing ctxt k = C.remove_existing ctxt (K.wrap k) + + let remove ctxt k = C.remove ctxt (K.wrap k) + + let clear ctxt = C.clear ctxt + + let fold ctxt ~init ~f = + C.fold ctxt ~init ~f:(fun k v acc -> + match K.unwrap k with None -> Lwt.return acc | Some k -> f k v acc) + + let bindings s = + fold s ~init:[] ~f:(fun p v acc -> Lwt.return ((p, v) :: acc)) + + let fold_keys s ~init ~f = + C.fold_keys s ~init ~f:(fun k acc -> + match K.unwrap k with None -> Lwt.return acc | Some k -> f k acc) + + let keys s = fold_keys s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc)) +end diff --git a/src/proto_011_PtHangzH/lib_protocol/storage_functors.mli b/src/proto_011_PtHangzH/lib_protocol/storage_functors.mli new file mode 100644 index 000000000000..5b78bc8a1f7f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/storage_functors.mli @@ -0,0 +1,122 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Tezos Protocol Implementation - Typed storage builders. + + @see [Make_subcontext] + *) + +open Storage_sigs + +module Registered : REGISTER + +module Ghost : REGISTER + +(** Given a [Raw_context], return a new [Raw_context] that projects into + a given subtree. Similar to a {i functional lens}. + *) +module Make_subcontext (_ : REGISTER) (C : Raw_context.T) (_ : NAME) : + Raw_context.T with type t = C.t + +module Make_single_data_storage + (_ : REGISTER) + (C : Raw_context.T) + (_ : NAME) + (V : VALUE) : Single_data_storage with type t = C.t and type value = V.t + +(** A type that can be serialized as a [string list], and used + as a prefix in the typed datastore. + + Useful to implement storage of maps and sets. + *) +module type INDEX = sig + type t + + include Path_encoding.S with type t := t + + type 'a ipath + + val args : ('a, t, 'a ipath) Storage_description.args +end + +module Pair (I1 : INDEX) (I2 : INDEX) : INDEX with type t = I1.t * I2.t + +(** Create storage for a compound type. *) +module Make_data_set_storage (C : Raw_context.T) (I : INDEX) : + Data_set_storage with type t = C.t and type elt = I.t + +(** Like [Make_data_set_storage], adding tracking of storage cost. *) +module Make_carbonated_data_set_storage (C : Raw_context.T) (I : INDEX) : + Carbonated_data_set_storage with type t = C.t and type elt = I.t + +(** This functor creates storage for types with a notion of an index. *) +module Make_indexed_data_storage (C : Raw_context.T) (I : INDEX) (V : VALUE) : + Indexed_data_storage with type t = C.t and type key = I.t and type value = V.t + +(** Like [Make_indexed_data_storage], adding tracking of storage cost. *) +module Make_indexed_carbonated_data_storage + (C : Raw_context.T) + (I : INDEX) + (V : VALUE) : + Non_iterable_indexed_carbonated_data_storage_with_values + with type t = C.t + and type key = I.t + and type value = V.t + +module Make_indexed_data_snapshotable_storage + (C : Raw_context.T) + (Snapshot : INDEX) + (I : INDEX) + (V : VALUE) : + Indexed_data_snapshotable_storage + with type t = C.t + and type snapshot = Snapshot.t + and type key = I.t + and type value = V.t + +module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX) : + Indexed_raw_context + with type t = C.t + and type key = I.t + and type 'a ipath = 'a I.ipath + +module type WRAPPER = sig + type t + + type key + + val wrap : t -> key + + val unwrap : key -> t option +end + +module Wrap_indexed_data_storage + (C : Indexed_data_storage) + (K : WRAPPER with type key := C.key) : + Indexed_data_storage + with type t = C.t + and type key = K.t + and type value = C.value diff --git a/src/proto_011_PtHangzH/lib_protocol/storage_sigs.ml b/src/proto_011_PtHangzH/lib_protocol/storage_sigs.ml new file mode 100644 index 000000000000..7319971f3659 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/storage_sigs.ml @@ -0,0 +1,383 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2019-2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** {1 Entity Accessor Signatures} *) + +(** The generic signature of a single data accessor (a single value + bound to a specific key in the hierarchical (key x value) + database). *) +module type Single_data_storage = sig + type t + + type context = t + + (** The type of the value *) + type value + + (** Tells if the data is already defined *) + val mem : context -> bool Lwt.t + + (** Retrieve the value from the storage bucket ; returns a + {!Storage_error} if the key is not set or if the deserialisation + fails *) + val get : context -> value tzresult Lwt.t + + (** Retrieves the value from the storage bucket ; returns [None] if + the data is not initialized, or {!Storage_helpers.Storage_error} + if the deserialisation fails *) + val find : context -> value option tzresult Lwt.t + + (** Allocates the storage bucket and initializes it ; returns a + {!Storage_error Existing_key} if the bucket exists *) + val init : context -> value -> Raw_context.t tzresult Lwt.t + + (** Updates the content of the bucket ; returns a {!Storage_Error + Missing_key} if the value does not exists *) + val update : context -> value -> Raw_context.t tzresult Lwt.t + + (** Allocates the data and initializes it with a value ; just + updates it if the bucket exists *) + val add : context -> value -> Raw_context.t Lwt.t + + (** When the value is [Some v], allocates the data and initializes + it with [v] ; just updates it if the bucket exists. When the + value is [None], delete the storage bucket when the value ; does + nothing if the bucket does not exists. *) + val add_or_remove : context -> value option -> Raw_context.t Lwt.t + + (** Delete the storage bucket ; returns a {!Storage_error + Missing_key} if the bucket does not exists *) + val remove_existing : context -> Raw_context.t tzresult Lwt.t + + (** Removes the storage bucket and its contents ; does nothing if + the bucket does not exists *) + val remove : context -> Raw_context.t Lwt.t +end +[@@coq_precise_signature] + +(** Restricted version of {!Indexed_data_storage} w/o iterators. *) +module type Non_iterable_indexed_data_storage = sig + type t + + type context = t + + (** An abstract type for keys *) + type key + + (** The type of values *) + type value + + (** Tells if a given key is already bound to a storage bucket *) + val mem : context -> key -> bool Lwt.t + + (** Retrieve a value from the storage bucket at a given key ; + returns {!Storage_error Missing_key} if the key is not set ; + returns {!Storage_error Corrupted_data} if the deserialisation + fails. *) + val get : context -> key -> value tzresult Lwt.t + + (** Retrieve a value from the storage bucket at a given key ; + returns [None] if the value is not set ; returns {!Storage_error + Corrupted_data} if the deserialisation fails. *) + val find : context -> key -> value option tzresult Lwt.t + + (** Updates the content of a bucket ; returns A {!Storage_Error + Missing_key} if the value does not exists. *) + val update : context -> key -> value -> Raw_context.t tzresult Lwt.t + + (** Allocates a storage bucket at the given key and initializes it ; + returns a {!Storage_error Existing_key} if the bucket exists. *) + val init : context -> key -> value -> Raw_context.t tzresult Lwt.t + + (** Allocates a storage bucket at the given key and initializes it + with a value ; just updates it if the bucket exists. *) + val add : context -> key -> value -> Raw_context.t Lwt.t + + (** When the value is [Some v], allocates the data and initializes + it with [v] ; just updates it if the bucket exists. When the + value is [None], delete the storage bucket when the value ; does + nothing if the bucket does not exists. *) + val add_or_remove : context -> key -> value option -> Raw_context.t Lwt.t + + (** Delete a storage bucket and its contents ; returns a + {!Storage_error Missing_key} if the bucket does not exists. *) + val remove_existing : context -> key -> Raw_context.t tzresult Lwt.t + + (** Removes a storage bucket and its contents ; does nothing if the + bucket does not exists. *) + val remove : context -> key -> Raw_context.t Lwt.t +end +[@@coq_precise_signature] + +(** Variant of {!Non_iterable_indexed_data_storage} with gas accounting. *) +module type Non_iterable_indexed_carbonated_data_storage = sig + type t + + type context = t + + (** An abstract type for keys *) + type key + + (** The type of values *) + type value + + (** Tells if a given key is already bound to a storage bucket. + Consumes [Gas_repr.read_bytes_cost Z.zero]. *) + val mem : context -> key -> (Raw_context.t * bool) tzresult Lwt.t + + (** Retrieve a value from the storage bucket at a given key ; + returns {!Storage_error Missing_key} if the key is not set ; + returns {!Storage_error Corrupted_data} if the deserialisation + fails. + Consumes [Gas_repr.read_bytes_cost ]. *) + val get : context -> key -> (Raw_context.t * value) tzresult Lwt.t + + (** Retrieve a value from the storage bucket at a given key ; + returns [None] if the value is not set ; returns {!Storage_error + Corrupted_data} if the deserialisation fails. + Consumes [Gas_repr.read_bytes_cost ] if present + or [Gas_repr.read_bytes_cost Z.zero]. *) + val find : context -> key -> (Raw_context.t * value option) tzresult Lwt.t + + (** Updates the content of a bucket ; returns A {!Storage_Error + Missing_key} if the value does not exists. + Consumes serialization cost. + Consumes [Gas_repr.write_bytes_cost ]. + Returns the difference from the old to the new size. *) + val update : context -> key -> value -> (Raw_context.t * int) tzresult Lwt.t + + (** Allocates a storage bucket at the given key and initializes it ; + returns a {!Storage_error Existing_key} if the bucket exists. + Consumes serialization cost. + Consumes [Gas_repr.write_bytes_cost ]. + Returns the size. *) + val init : context -> key -> value -> (Raw_context.t * int) tzresult Lwt.t + + (** Allocates a storage bucket at the given key and initializes it + with a value ; just updates it if the bucket exists. + Consumes serialization cost. + Consumes [Gas_repr.write_bytes_cost ]. + Returns the difference from the old (maybe 0) to the new size, and a boolean + indicating if a value was already associated to this key. *) + val add : + context -> key -> value -> (Raw_context.t * int * bool) tzresult Lwt.t + + (** When the value is [Some v], allocates the data and initializes + it with [v] ; just updates it if the bucket exists. When the + value is [None], delete the storage bucket when the value ; does + nothing if the bucket does not exists. + Consumes serialization cost. + Consumes the same gas cost as either {!remove} or {!init_set}. + Returns the difference from the old (maybe 0) to the new size, and a boolean + indicating if a value was already associated to this key. *) + val add_or_remove : + context -> + key -> + value option -> + (Raw_context.t * int * bool) tzresult Lwt.t + + (** Delete a storage bucket and its contents ; returns a + {!Storage_error Missing_key} if the bucket does not exists. + Consumes [Gas_repr.write_bytes_cost Z.zero]. + Returns the freed size. *) + val remove_existing : context -> key -> (Raw_context.t * int) tzresult Lwt.t + + (** Removes a storage bucket and its contents ; does nothing if the + bucket does not exists. + Consumes [Gas_repr.write_bytes_cost Z.zero]. + Returns the freed size, and a boolean + indicating if a value was already associated to this key. *) + val remove : context -> key -> (Raw_context.t * int * bool) tzresult Lwt.t +end +[@@coq_precise_signature] + +module type Non_iterable_indexed_carbonated_data_storage_with_values = sig + include Non_iterable_indexed_carbonated_data_storage + + (* HACK *) + val list_values : + ?offset:int -> + ?length:int -> + t -> + (Raw_context.t * value list) tzresult Lwt.t +end + +module type Non_iterable_indexed_carbonated_data_storage_INTERNAL = sig + include Non_iterable_indexed_carbonated_data_storage_with_values + + val fold_keys_unaccounted : + context -> init:'a -> f:(key -> 'a -> 'a Lwt.t) -> 'a Lwt.t +end + +(** The generic signature of indexed data accessors (a set of values + of the same type indexed by keys of the same form in the + hierarchical (key x value) database). *) +module type Indexed_data_storage = sig + include Non_iterable_indexed_data_storage + + (** Empties all the keys and associated data. *) + val clear : context -> Raw_context.t Lwt.t + + (** Lists all the keys. *) + val keys : context -> key list Lwt.t + + (** Lists all the keys and associated data. *) + val bindings : context -> (key * value) list Lwt.t + + (** Iterates over all the keys and associated data. *) + val fold : + context -> init:'a -> f:(key -> value -> 'a -> 'a Lwt.t) -> 'a Lwt.t + + (** Iterate over all the keys. *) + val fold_keys : context -> init:'a -> f:(key -> 'a -> 'a Lwt.t) -> 'a Lwt.t +end + +module type Indexed_data_snapshotable_storage = sig + type snapshot + + type key + + include Indexed_data_storage with type key := key + + module Snapshot : + Indexed_data_storage + with type key = snapshot * key + and type value = value + and type t = t + + val snapshot_exists : context -> snapshot -> bool Lwt.t + + val snapshot : context -> snapshot -> Raw_context.t tzresult Lwt.t + + val delete_snapshot : context -> snapshot -> Raw_context.t Lwt.t +end + +(** The generic signature of a data set accessor (a set of values + bound to a specific key prefix in the hierarchical (key x value) + database). *) +module type Data_set_storage = sig + type t + + type context = t + + (** The type of elements. *) + type elt + + (** Tells if a elt is a member of the set *) + val mem : context -> elt -> bool Lwt.t + + (** Adds a elt is a member of the set *) + val add : context -> elt -> Raw_context.t Lwt.t + + (** Removes a elt of the set ; does nothing if not a member *) + val remove : context -> elt -> Raw_context.t Lwt.t + + (** Returns the elements of the set, deserialized in a list in no + particular order. *) + val elements : context -> elt list Lwt.t + + (** Iterates over the elements of the set. *) + val fold : context -> init:'a -> f:(elt -> 'a -> 'a Lwt.t) -> 'a Lwt.t + + (** Removes all elements in the set *) + val clear : context -> Raw_context.t Lwt.t +end + +(** Variant of {!Data_set_storage} with gas accounting. *) +module type Carbonated_data_set_storage = sig + type t + + type context = t + + (** The type of elements. *) + type elt + + (** Tells whether an elt is a member of the set. + Consumes [Gas_repr.read_bytes_cost Z.zero] *) + val mem : context -> elt -> (Raw_context.t * bool) tzresult Lwt.t + + (** Adds an elt as a member of the set. + Consumes [Gas_repr.write_bytes_cost ]. + Returns the the new size. *) + val init : context -> elt -> (Raw_context.t * int) tzresult Lwt.t + + (** Removes an elt from the set ; does nothing if not a member. + Consumes [Gas_repr.write_bytes_cost Z.zero]. + Returns the freed size, and a boolean + indicating if a value was already associated to this key. *) + val remove : context -> elt -> (Raw_context.t * int * bool) tzresult Lwt.t + + val fold_keys_unaccounted : + context -> init:'acc -> f:(elt -> 'acc -> 'acc Lwt.t) -> 'acc Lwt.t +end + +module type NAME = sig + val name : Raw_context.key +end + +module type VALUE = sig + type t + + val encoding : t Data_encoding.t +end + +module type REGISTER = sig + val ghost : bool +end + +module type Indexed_raw_context = sig + type t + + type context = t + + type key + + type 'a ipath + + val clear : context -> Raw_context.t Lwt.t + + val fold_keys : context -> init:'a -> f:(key -> 'a -> 'a Lwt.t) -> 'a Lwt.t + + val keys : context -> key list Lwt.t + + val remove : context -> key -> context Lwt.t + + val copy : context -> from:key -> to_:key -> context tzresult Lwt.t + + module Make_set (_ : REGISTER) (_ : NAME) : + Data_set_storage with type t = t and type elt = key + + module Make_map (_ : NAME) (V : VALUE) : + Indexed_data_storage with type t = t and type key = key and type value = V.t + + module Make_carbonated_map (_ : NAME) (V : VALUE) : + Non_iterable_indexed_carbonated_data_storage + with type t = t + and type key = key + and type value = V.t + + module Raw_context : Raw_context.T with type t = t ipath +end diff --git a/src/proto_011_PtHangzH/lib_protocol/test/.ocamlformat b/src/proto_011_PtHangzH/lib_protocol/test/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_protocol/test/contracts/big_interpreter_stack.tz b/src/proto_011_PtHangzH/lib_protocol/test/contracts/big_interpreter_stack.tz new file mode 100644 index 000000000000..24832df0827f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/contracts/big_interpreter_stack.tz @@ -0,0 +1,5 @@ +{ parameter unit ; + storage unit ; + code { CAR ; + { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { {} ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; } ; + NIL operation; PAIR } } diff --git a/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract.tz b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract.tz new file mode 100644 index 000000000000..155b71db7bb0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract.tz @@ -0,0 +1,69 @@ +# This contract manages a shielded pool with a 1 to 1 conversion with respect to +# the tez, updated by a sapling transaction. The second parameter is an optional +# implicit account used to claim funds when unshielding. +storage (sapling_state 8); +parameter (list (pair (sapling_transaction 8) (option key_hash) ) ); +code { # Stack manipulation + UNPAIR; + NIL operation; + SWAP; + DIP { SWAP}; + AMOUNT ; + SWAP ; + DIP {SWAP} ; + ITER { UNPAIR; + DIP { SWAP }; + # We verify the transaction and update the storage if the transaction is + # valid. The shielded transactions are handled here. + # The new state is pushed on top of the stack in addition to the balance + # of the transaction. If the rest of the script goes well, this state + # will be the new state of the smart contract. + SAPLING_VERIFY_UPDATE; + # In the case of an invalid transaction, we stop. + ASSERT_SOME; + UNPAIR; + # Convert the balance in mutez, keeping the signed + # balance on top of the stack and the balance in mutez as the second + # element + DUP; + DIP { ABS; # in case of negative balance i.e. shielding + PUSH mutez 1; + MUL; }; + # We have three cases now: unshielding, shielding and transfers. + # If the balance is strictly positive (i.e. unshielding), we send funds + # to the given address. + # If no address is given (see ASSERT_SOME), we stop + IFGT { + DIIP { ASSERT_SOME; + IMPLICIT_ACCOUNT }; + SWAP; + DIP { UNIT; + TRANSFER_TOKENS; + SWAP; + # Stack manipulation to order. The operations will consist of the + # TRANSFER_TOKEN operation. + DIP {CONS} ;}; + } + # If the balance is negative or 0 (i.e. shielding or transfer), + # we verify the amount transferred in the transaction is exactly the + # balance of the verify_update output. It does enforce the conversion + # 1-1 between mutez and shielded token. + # No operation is executed. + { + DIIP {SWAP}; + DIP {SWAP}; + SWAP; + SUB; + # As we transfer or shield token, an implicit account is not + # required. It is a good practice to verify. + # If an implicit account has been given, it might be an invalid + # operation or a call error. + DIIP { ASSERT_NONE;}; + SWAP; + }; + }; + DIP { + PUSH mutez 0; + ASSERT_CMPEQ;}; + SWAP; + PAIR} \ No newline at end of file diff --git a/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_double.tz b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_double.tz new file mode 100644 index 000000000000..89148c8c355f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_double.tz @@ -0,0 +1,33 @@ +storage (pair (sapling_state :left 8) (sapling_state :right 8) ); +parameter (pair bool (pair (sapling_transaction :left 8) (sapling_transaction :right 8)) ); +code { UNPAIR ; + UNPAIR ; + DIP {UNPAIR} ; + DIIIP {UNPAIR} ; + DIIP {SWAP} ; + IF { SAPLING_VERIFY_UPDATE ; + ASSERT_SOME ; + UNPAIR ; + DROP ; + DIP {DIP {DUP}; + SAPLING_VERIFY_UPDATE; + ASSERT_SOME ; + UNPAIR ; + DROP ; + DROP;}; + } + { DIP { DUP}; + SAPLING_VERIFY_UPDATE; + ASSERT_SOME; + UNPAIR; + DROP; + DROP ; + DIP { SAPLING_VERIFY_UPDATE ; + ASSERT_SOME ; + UNPAIR; + DROP ; + }}; + PAIR; + NIL operation; + PAIR; + } diff --git a/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_drop.tz b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_drop.tz new file mode 100644 index 000000000000..b7e1b3912ff9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_drop.tz @@ -0,0 +1,14 @@ +storage (unit); +parameter (list (sapling_transaction 8)); +code { UNPAIR ; + SAPLING_EMPTY_STATE 8; + SWAP ; + ITER { SAPLING_VERIFY_UPDATE ; + ASSERT_SOME ; + UNPAIR ; + DROP ; + } ; + DROP ; + NIL operation; + PAIR; + } diff --git a/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_send.tz b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_send.tz new file mode 100644 index 000000000000..6eedc9dbc619 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_send.tz @@ -0,0 +1,20 @@ +storage (unit); +parameter (pair (contract (or (sapling_transaction 8) (sapling_state 8))) (sapling_transaction 8)); +code { UNPAIR ; + UNPAIR; + SWAP ; + SAPLING_EMPTY_STATE 8; + SWAP ; + SAPLING_VERIFY_UPDATE ; + ASSERT_SOME ; + UNPAIR ; + DROP ; + PUSH mutez 0; + SWAP ; + RIGHT (sapling_transaction 8); + TRANSFER_TOKENS; + NIL operation; + SWAP; + CONS; + PAIR; + } diff --git a/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_state_as_arg.tz b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_state_as_arg.tz new file mode 100644 index 000000000000..e8a96df046ee --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_contract_state_as_arg.tz @@ -0,0 +1,18 @@ +storage (option (sapling_transaction 8)); +parameter (or (sapling_transaction 8) (sapling_state 8)); +code { UNPAIR ; + IF_LEFT + { + DIP {DROP;}; + SOME; + } + { DIP {ASSERT_SOME;}; + SWAP ; + SAPLING_VERIFY_UPDATE; + ASSERT_SOME; + DROP ; + NONE (sapling_transaction 8) ; + }; + NIL operation; + PAIR; + } diff --git a/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_push_sapling_state.tz b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_push_sapling_state.tz new file mode 100644 index 000000000000..8d1db432bf2e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_push_sapling_state.tz @@ -0,0 +1,11 @@ +# Attempt to use `PUSH sapling_state 0` where 0 is the ID of a sapling state. +# sapling_state is not allowed in the instruction PUSH. +parameter unit; +storage unit; +code { DROP; + PUSH (sapling_state 8) 0; + DROP; + PUSH unit Unit; + NIL operation; + PAIR; + } diff --git a/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_use_existing_state.tz b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_use_existing_state.tz new file mode 100644 index 000000000000..b637870653f8 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/contracts/sapling_use_existing_state.tz @@ -0,0 +1,12 @@ +parameter (pair (sapling_transaction 8) (sapling_state 8)); +storage (sapling_state 8); +code { UNPAIR; + UNPAIR; + DIIP { DROP }; + SAPLING_VERIFY_UPDATE; + ASSERT_SOME; + UNPAIR; + DROP; + NIL operation; + PAIR; + } diff --git a/src/proto_011_PtHangzH/lib_protocol/test/contracts/temp_big_maps.tz b/src/proto_011_PtHangzH/lib_protocol/test/contracts/temp_big_maps.tz new file mode 100644 index 000000000000..0a9162f8f982 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/contracts/temp_big_maps.tz @@ -0,0 +1,81 @@ +# Testing passing/originating with big maps from different sources +# This contract is used by test_temp_big_maps.ml + +# The left member of the parameter is either: +# - (Left True) to use a fresh big map +# - (Left False) to use the stored big map +# - (Right bigmap) to use the passed big map + +# The right member of the parameter is used to decide between: +# - passing the argument (positive value) +# - doing nothing (zero) +# - originating (negative value) + +parameter (pair (or bool (big_map int int)) int); +storage (big_map int int); +code + { # parameter * storage :: [] + UNPAIR; # parameter :: storage :: [] + UNPAIR; # parameter.fst :: parameter.snd :: storage :: [] + DIP { SWAP }; # parameter.fst :: storage :: parameter.snd :: [] + IF_LEFT + { # parameter.fst.Left :: storage :: parameter.snd :: [] + IF + { # storage :: parameter.snd :: [] + DROP; # parameter.snd :: [] + EMPTY_BIG_MAP int int; # empty_big_map :: parameter.snd :: [] + PUSH (option int) (Some 2); # Some 2 :: empty_big_map :: parameter.snd :: [] + PUSH int 1; # 1 :: Some 2 :: empty_big_map :: parameter.snd :: [] + UPDATE; # big_map { 1 -> 2 } :: parameter.snd :: [] + } + { # stored_big_map :: parameter.snd :: [] + } + } + { # parameter.fst.Right :: storage :: parameter.snd :: [] + DIP { DROP } # passed_big_map :: parameter.snd :: [] + }; + DUP; # big_map :: big_map :: parameter.snd :: [] + DIG 2; # parameter.snd :: big_map :: big_map :: [] + DUP; # parameter.snd :: parameter.snd :: big_map :: big_map :: [] + IFGT + { # parameter.snd :: big_map :: big_map :: [] + PUSH int -1; + ADD; # parameter.snd - 1 :: big_map :: big_map :: [] + SWAP; # big_map :: parameter.snd - 1 :: big_map :: [] + RIGHT bool ; # Right big_map :: parameter.snd - 1 :: big_map :: [] + PAIR; # Right big_map * (parameter.snd - 1) :: big_map :: [] + DIP { SELF; PUSH mutez 0; }; # Right big_map * (parameter.snd - 1) :: 0 mutez :: self :: big_map :: [] + TRANSFER_TOKENS; # transfer_tokens :: big_map :: [] + NIL operation; # nil_operation :: transfer_tokens :: big_map :: [] + SWAP; # transfer_tokens :: nil_operation :: big_map :: [] + CONS # list operation :: big_map :: [] + } + { # parameter.snd :: big_map :: big_map :: [] + IFEQ + { # big_map :: big_map :: [] + DROP; # big_map :: [] + NIL operation; # list operation :: big_map :: [] + } + { # big_map :: big_map :: [] + PUSH mutez 0; # 0 mutez :: big_map :: big_map :: [] + NONE key_hash; # None key_hash :: 0 mutez :: big_map :: big_map :: [] + CREATE_CONTRACT + { + parameter unit; + storage (big_map int int); + code + { + UNPAIR; + DROP; + NIL operation; + PAIR + } + }; # create_contract :: address :: big_map :: [] + DIP { DROP }; # create_contract :: big_map :: [] + NIL operation; # nil_operation :: create_contract :: big_map :: [] + SWAP; # create_contract :: nil_operation :: big_map :: [] + CONS # list operation :: big_map :: [] + }; + }; + PAIR # (list operation * big_map) :: [] + } diff --git a/src/proto_011_PtHangzH/lib_protocol/test/contracts/timelock.tz b/src/proto_011_PtHangzH/lib_protocol/test/contracts/timelock.tz new file mode 100644 index 000000000000..2ddad4258117 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/contracts/timelock.tz @@ -0,0 +1,31 @@ +# This contract takes a chest and chest key as parameter. +# It tries to open it and stores the resulting bytes if successful. +# Otherwise it stores some hardcoded bytes to test that we are in +# the expected branch +storage (bytes); +parameter (pair (chest_key) (chest)); +code { + UNPAIR; + DIP {DROP}; + UNPAIR; + DIIP {PUSH nat 1000}; + OPEN_CHEST; + IF_LEFT + { # successful case + NIL operation; + PAIR ; + } + { + IF + { # first type of failure + PUSH bytes 0x01; + NIL operation; + PAIR; + } + { # second type of failure + PUSH bytes 0x00; + NIL operation; + PAIR; + } + } + } diff --git a/src/proto_011_PtHangzH/lib_protocol/test/dune b/src/proto_011_PtHangzH/lib_protocol/test/dune new file mode 100644 index 000000000000..b7adb09deda7 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/dune @@ -0,0 +1,82 @@ +(executables + (names main + saturation_fuzzing + test_gas_properties + test_tez_repr + liquidity_baking_pbt + test_script_comparison) + (libraries tezos-base + tezos-micheline + tezos-protocol-environment + alcotest-lwt + tezos-test-helpers + qcheck-alcotest + tezos-011-PtHangzH-test-helpers + tezos-stdlib-unix + tezos-client-base + tezos-protocol-011-PtHangzH-parameters + tezos-base-test-helpers + tezos-sapling + astring + tezos-protocol-plugin-011-PtHangzH + tezos-benchmark + tezos-benchmark-011-PtHangzH) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_micheline + -open Tezos_client_011_PtHangzH + -open Tezos_protocol_011_PtHangzH + -open Tezos_protocol_plugin_011_PtHangzH + -open Tezos_protocol_environment_011_PtHangzH + -open Tezos_benchmark_011_PtHangzH + -open Tezos_benchmark_type_inference_011_PtHangzH + -open Tezos_011_PtHangzH_test_helpers + -open Tezos_base_test_helpers))) + +(rule + (copy %{lib:tezos-protocol-011-PtHangzH-parameters:test-parameters.json} + protocol_parameters.json)) + +; runs only the `Quick tests +(rule + (alias runtest_proto_011_PtHangzH) + (deps (glob_files contracts/*)) + (package tezos-protocol-011-PtHangzH-tests) + (action (run %{exe:main.exe} -q))) + +; runs both `Quick and `Slow tests +(rule + (alias runtest_slow) + (deps (glob_files contracts/*)) + (package tezos-protocol-011-PtHangzH-tests) + (action (run %{exe:main.exe}))) + +(rule + (alias runtest_saturation_fuzzing) + (package tezos-protocol-011-PtHangzH-tests) + (action (run %{exe:saturation_fuzzing.exe}))) + +(rule + (alias runtest_test_script_comparison) + (package tezos-protocol-011-PtHangzH-tests) + (action (run %{exe:test_script_comparison.exe}))) + +(rule + (alias runtest_test_tez_repr) + (package tezos-protocol-011-PtHangzH-tests) + (action (run %{exe:test_tez_repr.exe}))) + +(rule + (alias runtest_liquidity_baking_pbt) + (package tezos-protocol-011-PtHangzH-tests) + (action (run %{exe:liquidity_baking_pbt.exe}))) + +(rule + (alias runtest) + (package tezos-protocol-011-PtHangzH-tests) + (deps + (alias runtest_proto_011_PtHangzH) + (alias runtest_saturation_fuzzing) + (alias runtest_test_tez_repr) + (alias runtest_liquidity_baking_pbt) + (alias runtest_test_script_comparison)) + (action (progn))) diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/.ocamlformat b/src/proto_011_PtHangzH/lib_protocol/test/helpers/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/README.md b/src/proto_011_PtHangzH/lib_protocol/test/helpers/README.md new file mode 100644 index 000000000000..b071cfb4ec03 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/README.md @@ -0,0 +1,3 @@ +## Helpers to build unit/integration tests for the protocol + +The OPAM package `tezos-alpha-test-helpers` contains helpers to build unit/integration tests, like forging a block, a context, nonces, operations, etc. diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/account.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/account.ml new file mode 100644 index 000000000000..6d61af9c4e3f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/account.ml @@ -0,0 +1,113 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +type t = { + pkh : Signature.Public_key_hash.t; + pk : Signature.Public_key.t; + sk : Signature.Secret_key.t; +} + +type account = t + +let known_accounts = Signature.Public_key_hash.Table.create 17 + +let random_seed ~rng_state = + Bytes.init Hacl.Ed25519.sk_size (fun _i -> + Char.chr (Random.State.int rng_state 256)) + +let new_account ?seed () = + let (pkh, pk, sk) = Signature.generate_key ~algo:Ed25519 ?seed () in + let account = {pkh; pk; sk} in + Signature.Public_key_hash.Table.add known_accounts pkh account ; + account + +let add_account ({pkh; _} as account) = + Signature.Public_key_hash.Table.add known_accounts pkh account + +let activator_account = + let seed = random_seed ~rng_state:(Random.State.make [|0x1337533D|]) in + new_account ~seed () + +let find pkh = + match Signature.Public_key_hash.Table.find known_accounts pkh with + | Some k -> return k + | None -> failwith "Missing account: %a" Signature.Public_key_hash.pp pkh + +let find_alternate pkh = + let exception Found of t in + try + Signature.Public_key_hash.Table.iter + (fun pkh' account -> + if not (Signature.Public_key_hash.equal pkh pkh') then + raise (Found account)) + known_accounts ; + raise Not_found + with Found account -> account + +let dummy_account = + let seed = + random_seed ~rng_state:(Random.State.make [|0x1337533D; 0x1337533D|]) + in + new_account ~seed () + +let generate_accounts ?rng_state ?(initial_balances = []) n : (t * Tez.t) list = + Signature.Public_key_hash.Table.clear known_accounts ; + let default_amount = Tez.of_mutez_exn 4_000_000_000_000L in + let amount i = + match List.nth_opt initial_balances i with + | None -> default_amount + | Some a -> Tez.of_mutez_exn a + in + let rng_state = + match rng_state with + | None -> Random.State.make_self_init () + | Some state -> state + in + List.map + (fun i -> + let (pkh, pk, sk) = + Signature.generate_key ~algo:Ed25519 ~seed:(random_seed ~rng_state) () + in + let account = {pkh; pk; sk} in + Signature.Public_key_hash.Table.add known_accounts pkh account ; + (account, amount i)) + (0 -- (n - 1)) + +let commitment_secret = + Blinded_public_key_hash.activation_code_of_hex + "aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb" + +let new_commitment ?seed () = + let (pkh, pk, sk) = Signature.generate_key ?seed ~algo:Ed25519 () in + let unactivated_account = {pkh; pk; sk} in + let open Commitment in + let pkh = match pkh with Ed25519 pkh -> pkh | _ -> assert false in + let bpkh = Blinded_public_key_hash.of_ed25519_pkh commitment_secret pkh in + Lwt.return + ( (Environment.wrap_tzresult @@ Tez.(one *? 4_000L)) >|? fun amount -> + (unactivated_account, {blinded_public_key_hash = bpkh; amount}) ) diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/account.mli b/src/proto_011_PtHangzH/lib_protocol/test/helpers/account.mli new file mode 100644 index 000000000000..96c7cdb1132f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/account.mli @@ -0,0 +1,66 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +type t = { + pkh : Signature.Public_key_hash.t; + pk : Signature.Public_key.t; + sk : Signature.Secret_key.t; +} + +type account = t + +val known_accounts : t Signature.Public_key_hash.Table.t + +val activator_account : account + +val dummy_account : account + +val new_account : ?seed:Bytes.t -> unit -> account + +val add_account : t -> unit + +val find : Signature.Public_key_hash.t -> t tzresult Lwt.t + +val find_alternate : Signature.Public_key_hash.t -> t + +(** [generate_accounts ?initial_balances n] : generates [n] random + accounts with the initial balance of the [i]th account given by the + [i]th value in the list [initial_balances] or otherwise + 4.000.000.000 tz (if the list is too short); and add them to the + global account state *) + +val generate_accounts : + ?rng_state:Random.State.t -> + ?initial_balances:int64 list -> + int -> + (t * Tez.t) list + +val commitment_secret : Blinded_public_key_hash.activation_code + +val new_commitment : + ?seed:Bytes.t -> unit -> (account * Commitment.t) tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/assert.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/assert.ml new file mode 100644 index 000000000000..cc838aff92fb --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/assert.ml @@ -0,0 +1,167 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +let error ~loc v f = + match v with + | Error err when List.exists f err -> return_unit + | Ok _ -> failwith "Unexpected successful result (%s)" loc + | Error err -> failwith "@[Unexpected error (%s): %a@]" loc pp_print_error err + +let proto_error ~loc v f = + error ~loc v (function Environment.Ecoproto_error err -> f err | _ -> false) + +let equal ~loc (cmp : 'a -> 'a -> bool) msg pp a b = + if not (cmp a b) then + failwith "@[@[[%s]@] - @[%s : %a is not equal to %a@]@]" loc msg pp a pp b + else return_unit + +let not_equal ~loc (cmp : 'a -> 'a -> bool) msg pp a b = + if cmp a b then + failwith "@[@[[%s]@] - @[%s : %a is equal to %a@]@]" loc msg pp a pp b + else return_unit + +module Int32 = struct + include Int32 + + let pp pp v = Format.pp_print_int pp (Int32.to_int v) +end + +module Int64 = struct + include Int64 + + let pp pp v = Format.pp_print_int pp (Int64.to_int v) +end + +(* int *) +let equal_int ~loc (a : int) (b : int) = + equal ~loc ( = ) "Integers aren't equal" Format.pp_print_int a b + +(* int32 *) +let equal_int32 ~loc (a : int32) (b : int32) = + equal ~loc Int32.equal "int32s (%a and %a) aren't equal" Int32.pp a b + +let not_equal_int ~loc (a : int) (b : int) = + not_equal ~loc ( = ) "Integers are equal" Format.pp_print_int a b + +let leq_int ~loc (a : int) (b : int) = + if a > b then + failwith + "@[@[[%s]@] - @[Integers aren't less than or equal : %a is greater than \ + %a@]@]" + loc + Format.pp_print_int + a + Format.pp_print_int + b + else return_unit + +(* int64 *) +let equal_int64 ~loc (a : int64) (b : int64) = + equal + ~loc + ( = ) + "Integers aren't equal" + Format.pp_print_string + (Int64.to_string a) + (Int64.to_string b) + +let not_equal_int64 ~loc (a : int64) (b : int64) = + not_equal + ~loc + ( = ) + "Integers are equal" + Format.pp_print_string + (Int64.to_string a) + (Int64.to_string b) + +(* bool *) +let equal_bool ~loc (a : bool) (b : bool) = + equal ~loc ( = ) "Booleans aren't equal" Format.pp_print_bool a b + +let not_equal_bool ~loc (a : bool) (b : bool) = + not_equal ~loc ( = ) "Booleans are equal" Format.pp_print_bool a b + +(* tez *) +let equal_tez ~loc (a : Alpha_context.Tez.t) (b : Alpha_context.Tez.t) = + let open Alpha_context in + equal ~loc Tez.( = ) "Tez aren't equal" Tez.pp a b + +let not_equal_tez ~loc (a : Alpha_context.Tez.t) (b : Alpha_context.Tez.t) = + let open Alpha_context in + not_equal ~loc Tez.( = ) "Tez are equal" Tez.pp a b + +(* pkh *) +let equal_pkh ~loc (a : Signature.Public_key_hash.t) + (b : Signature.Public_key_hash.t) = + let module PKH = Signature.Public_key_hash in + equal ~loc PKH.equal "Public key hashes aren't equal" PKH.pp a b + +let not_equal_pkh ~loc (a : Signature.Public_key_hash.t) + (b : Signature.Public_key_hash.t) = + let module PKH = Signature.Public_key_hash in + not_equal ~loc PKH.equal "Public key hashes are equal" PKH.pp a b + +open Context + +(* Some asserts for account operations *) + +(** [balance_is b c amount] checks that the current balance of contract [c] is + [amount]. + Default balance type is [Main], pass [~kind] with [Deposit], [Fees] or + [Rewards] for the others. *) +let balance_is ~loc b contract ?(kind = Contract.Main) expected = + Contract.balance b contract ~kind >>=? fun balance -> + equal_tez ~loc balance expected + +(** [balance_was_operated ~operand b c old_balance amount] checks that the + current balance of contract [c] is [operand old_balance amount] and + returns the current balance. + Default balance type is [Main], pass [~kind] with [Deposit], [Fees] or + [Rewards] for the others. *) +let balance_was_operated ~operand ~loc b contract ?(kind = Contract.Main) + old_balance amount = + operand old_balance amount |> Environment.wrap_tzresult >>?= fun expected -> + balance_is ~loc b contract ~kind expected + +let balance_was_credited = + balance_was_operated ~operand:Alpha_context.Tez.( +? ) + +let balance_was_debited = balance_was_operated ~operand:Alpha_context.Tez.( -? ) + +(* debug *) + +let print_balances ctxt id = + Contract.balance ~kind:Main ctxt id >>=? fun main -> + Contract.balance ~kind:Deposit ctxt id >>=? fun deposit -> + Contract.balance ~kind:Fees ctxt id >>=? fun fees -> + Contract.balance ~kind:Rewards ctxt id >|=? fun rewards -> + Format.printf + "\nMain: %s\nDeposit: %s\nFees: %s\nRewards: %s\n" + (Alpha_context.Tez.to_string main) + (Alpha_context.Tez.to_string deposit) + (Alpha_context.Tez.to_string fees) + (Alpha_context.Tez.to_string rewards) diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/block.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/block.ml new file mode 100644 index 000000000000..73ca1f2993b4 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/block.ml @@ -0,0 +1,680 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +module Proto_Nonce = Nonce (* Renamed otherwise is masked by Alpha_context *) + +open Alpha_context + +(* This type collects a block and the context that results from its application *) +type t = { + hash : Block_hash.t; + header : Block_header.t; + operations : Operation.packed list; + context : Tezos_protocol_environment.Context.t; +} + +type block = t + +let rpc_context block = + { + Environment.Updater.block_hash = block.hash; + block_header = block.header.shell; + context = block.context; + } + +let rpc_ctxt = + new Environment.proto_rpc_context_of_directory + rpc_context + Plugin.RPC.rpc_services + +(******** Policies ***********) + +(* Policies are functions that take a block and return a tuple + [(account, level, timestamp)] for the [forge_header] function. *) + +(* This type is used only to provide a simpler interface to the exterior. *) +type baker_policy = + | By_priority of int + | By_account of public_key_hash + | Excluding of public_key_hash list + +let get_next_baker_by_priority priority block = + Plugin.RPC.Baking_rights.get + rpc_ctxt + ~all:true + ~max_priority:(priority + 1) + block + >|=? fun bakers -> + let {Plugin.RPC.Baking_rights.delegate = pkh; timestamp; _} = + WithExceptions.Option.get ~loc:__LOC__ + @@ List.find + (fun {Plugin.RPC.Baking_rights.priority = p; _} -> p = priority) + bakers + in + (pkh, priority, WithExceptions.Option.to_exn ~none:(Failure "") timestamp) + +let get_next_baker_by_account pkh block = + Plugin.RPC.Baking_rights.get rpc_ctxt ~delegates:[pkh] ~max_priority:256 block + >|=? fun bakers -> + let {Plugin.RPC.Baking_rights.delegate = pkh; timestamp; priority; _} = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bakers + in + (pkh, priority, WithExceptions.Option.to_exn ~none:(Failure "") timestamp) + +let get_next_baker_excluding excludes block = + Plugin.RPC.Baking_rights.get rpc_ctxt ~max_priority:256 block + >|=? fun bakers -> + let {Plugin.RPC.Baking_rights.delegate = pkh; timestamp; priority; _} = + WithExceptions.Option.get ~loc:__LOC__ + @@ List.find + (fun {Plugin.RPC.Baking_rights.delegate; _} -> + not + (List.mem ~equal:Signature.Public_key_hash.equal delegate excludes)) + bakers + in + (pkh, priority, WithExceptions.Option.to_exn ~none:(Failure "") timestamp) + +let dispatch_policy = function + | By_priority p -> get_next_baker_by_priority p + | By_account a -> get_next_baker_by_account a + | Excluding al -> get_next_baker_excluding al + +let get_next_baker ?(policy = By_priority 0) = dispatch_policy policy + +let compute_endorsement_powers ~block = + Plugin.RPC.Endorsing_rights.get rpc_ctxt block >|=? fun endorsing_rights -> + List.filter_map + (function + | {Plugin.RPC.Endorsing_rights.slots = top :: _ as slots; _} -> + Some (top, List.length slots) + | {Plugin.RPC.Endorsing_rights.slots = []; _} -> None) + endorsing_rights + +let get_endorsing_power block = + compute_endorsement_powers ~block >|=? fun endorsement_powers -> + List.fold_left + (fun sum -> function + | { + Alpha_context.protocol_data = + Operation_data + {contents = Single (Endorsement_with_slot {slot; _}); _}; + _; + } -> ( + match List.assoc ~equal:Compare.Int.equal slot endorsement_powers with + | None -> sum + | Some pow -> sum + pow) + | _ -> sum) + 0 + block.operations + +module Forge = struct + type header = { + baker : public_key_hash; + (* the signer of the block *) + shell : Block_header.shell_header; + contents : Block_header.contents; + } + + let default_proof_of_work_nonce = + Bytes.create Constants.proof_of_work_nonce_size + + let make_contents ?(proof_of_work_nonce = default_proof_of_work_nonce) + ?(liquidity_baking_escape_vote = false) ~priority ~seed_nonce_hash () = + Block_header. + { + priority; + proof_of_work_nonce; + seed_nonce_hash; + liquidity_baking_escape_vote; + } + + let make_shell ~level ~predecessor ~timestamp ~fitness ~operations_hash = + Tezos_base.Block_header. + { + level; + predecessor; + timestamp; + fitness; + operations_hash; + (* We don't care of the following values, only the shell validates them. *) + proto_level = 0; + validation_passes = 0; + context = Context_hash.zero; + } + + let set_seed_nonce_hash seed_nonce_hash {baker; shell; contents} = + {baker; shell; contents = {contents with seed_nonce_hash}} + + let set_baker baker header = {header with baker} + + let sign_header {baker; shell; contents} = + Account.find baker >|=? fun delegate -> + let unsigned_bytes = + Data_encoding.Binary.to_bytes_exn + Block_header.unsigned_encoding + (shell, contents) + in + let signature = + Signature.sign + ~watermark:Signature.(Block_header Chain_id.zero) + delegate.sk + unsigned_bytes + in + Block_header.{shell; protocol_data = {contents; signature}} + + let forge_header ?(policy = By_priority 0) ?timestamp ?(operations = []) + ?liquidity_baking_escape_vote pred = + dispatch_policy policy pred >>=? fun (pkh, priority, _timestamp) -> + Alpha_services.Delegate.Minimal_valid_time.get rpc_ctxt pred priority 0 + >>=? fun expected_timestamp -> + let timestamp = Option.value ~default:expected_timestamp timestamp in + let level = Int32.succ pred.header.shell.level in + (match Fitness.to_int64 pred.header.shell.fitness with + | Ok old_fitness -> + Fitness.from_int64 (Int64.add (Int64.of_int 1) old_fitness) + | Error _ -> assert false) + |> fun fitness -> + (Plugin.RPC.current_level ~offset:1l rpc_ctxt pred >|=? function + | {expected_commitment = true; _} -> Some (fst (Proto_Nonce.generate ())) + | {expected_commitment = false; _} -> None) + >|=? fun seed_nonce_hash -> + let hashes = List.map Operation.hash_packed operations in + let operations_hash = + Operation_list_list_hash.compute [Operation_list_hash.compute hashes] + in + let shell = + make_shell + ~level + ~predecessor:pred.hash + ~timestamp + ~fitness + ~operations_hash + in + let contents = + make_contents ~priority ~seed_nonce_hash ?liquidity_baking_escape_vote () + in + {baker = pkh; shell; contents} + + (* compatibility only, needed by incremental *) + let contents ?(proof_of_work_nonce = default_proof_of_work_nonce) + ?(priority = 0) ?seed_nonce_hash ?(liquidity_baking_escape_vote = false) + () = + { + Block_header.priority; + proof_of_work_nonce; + seed_nonce_hash; + liquidity_baking_escape_vote; + } +end + +(********* Genesis creation *************) + +(* Hard-coded context key *) +let protocol_param_key = ["protocol_parameters"] + +let check_constants_consistency constants = + let open Constants in + let {blocks_per_cycle; blocks_per_commitment; blocks_per_roll_snapshot; _} = + constants + in + Error_monad.unless (blocks_per_commitment <= blocks_per_cycle) (fun () -> + failwith + "Inconsistent constants : blocks per commitment must be less than \ + blocks per cycle") + >>=? fun () -> + Error_monad.unless (blocks_per_cycle >= blocks_per_roll_snapshot) (fun () -> + failwith + "Inconsistent constants : blocks per cycle must be superior than \ + blocks per roll snapshot") + >>=? fun () -> + let min_time_between_blocks = + match constants.time_between_blocks with + | first_time_between_blocks :: _ -> first_time_between_blocks + | [] -> + (* this constant is used in the Baking module *) + Period.one_minute + in + Error_monad.unless + Compare.Int64.( + Period.to_seconds min_time_between_blocks + >= Period.to_seconds constants.minimal_block_delay) + (fun () -> + failwith + "minimal_block_delay value (%Ld) should be smaller than \ + time_between_blocks[0] value (%Ld)" + (Period.to_seconds constants.minimal_block_delay) + (Period.to_seconds min_time_between_blocks)) + >>=? fun () -> + Error_monad.unless + Compare.Int.(constants.endorsers_per_block >= constants.initial_endorsers) + (fun () -> + failwith "initial_endorsers should be smaller than endorsers_per_block") + +let prepare_main_init_params ?bootstrap_contracts with_commitments constants + initial_accounts = + let open Tezos_protocol_011_PtHangzH_parameters in + let bootstrap_accounts = + List.map + (fun (Account.{pk; pkh; _}, amount) -> + Default_parameters.make_bootstrap_account (pkh, pk, amount)) + initial_accounts + in + let parameters = + Default_parameters.parameters_of_constants + ~bootstrap_accounts + ?bootstrap_contracts + ~with_commitments + constants + in + let json = Default_parameters.json_of_parameters parameters in + let proto_params = + Data_encoding.Binary.to_bytes_exn Data_encoding.json json + in + Tezos_protocol_environment.Context.( + let empty = Memory_context.empty in + add empty ["version"] (Bytes.of_string "genesis") >>= fun ctxt -> + add ctxt protocol_param_key proto_params) + +let initial_context ?(with_commitments = false) ?bootstrap_contracts constants + header initial_accounts = + prepare_main_init_params + ?bootstrap_contracts + with_commitments + constants + initial_accounts + >>= fun ctxt -> + Main.init ctxt header >|= Environment.wrap_tzresult >|=? fun {context; _} -> + context + +let initial_alpha_context ?(with_commitments = false) constants + (block_header : Block_header.shell_header) initial_accounts = + prepare_main_init_params with_commitments constants initial_accounts + >>= fun ctxt -> + let level = block_header.level in + let fitness = block_header.fitness in + let timestamp = block_header.timestamp in + let typecheck (ctxt : Alpha_context.context) (script : Alpha_context.Script.t) + = + let allow_forged_in_storage = + false + (* There should be no forged value in bootstrap contracts. *) + in + Script_ir_translator.parse_script + ctxt + ~legacy:false + ~allow_forged_in_storage + script + >>=? fun (Ex_script parsed_script, ctxt) -> + Script_ir_translator.extract_lazy_storage_diff + ctxt + Optimized + parsed_script.storage_type + parsed_script.storage + ~to_duplicate:Script_ir_translator.no_lazy_storage_id + ~to_update:Script_ir_translator.no_lazy_storage_id + ~temporary:false + >>=? fun (storage, lazy_storage_diff, ctxt) -> + Script_ir_translator.unparse_data + ctxt + Optimized + parsed_script.storage_type + storage + >|=? fun (storage, ctxt) -> + let storage = + Alpha_context.Script.lazy_expr (Micheline.strip_locations storage) + in + (({script with storage}, lazy_storage_diff), ctxt) + in + Alpha_context.prepare_first_block ~typecheck ~level ~timestamp ~fitness ctxt + >|= Environment.wrap_tzresult + +let genesis_with_parameters parameters = + let hash = + Block_hash.of_b58check_exn + "BLockGenesisGenesisGenesisGenesisGenesisCCCCCeZiLHU" + in + let shell = + Forge.make_shell + ~level:0l + ~predecessor:hash + ~timestamp:Time.Protocol.epoch + ~fitness:(Fitness.from_int64 0L) + ~operations_hash:Operation_list_list_hash.zero + in + let contents = Forge.make_contents ~priority:0 ~seed_nonce_hash:None () in + let open Tezos_protocol_011_PtHangzH_parameters in + let json = Default_parameters.json_of_parameters parameters in + let proto_params = + Data_encoding.Binary.to_bytes_exn Data_encoding.json json + in + Tezos_protocol_environment.Context.( + let empty = Memory_context.empty in + add empty ["version"] (Bytes.of_string "genesis") >>= fun ctxt -> + add ctxt protocol_param_key proto_params) + >>= fun ctxt -> + Main.init ctxt shell >|= Environment.wrap_tzresult >|=? fun {context; _} -> + { + hash; + header = {shell; protocol_data = {contents; signature = Signature.zero}}; + operations = []; + context; + } + +let validate_initial_accounts (initial_accounts : (Account.t * Tez.t) list) + tokens_per_roll = + if initial_accounts = [] then + Stdlib.failwith "Must have one account with a roll to bake" ; + (* Check there is at least one roll *) + Lwt.catch + (fun () -> + List.fold_left_es + (fun acc (_, amount) -> + Environment.wrap_tzresult @@ Tez.( +? ) acc amount >>?= fun acc -> + if acc >= tokens_per_roll then raise Exit else return acc) + Tez.zero + initial_accounts + >>=? fun _ -> + failwith "Insufficient tokens in initial accounts to create one roll") + (function Exit -> return_unit | exc -> raise exc) + +let prepare_initial_context_params ?endorsers_per_block ?initial_endorsers + ?time_between_blocks ?minimal_block_delay ?delay_per_missing_endorsement + ?min_proposal_quorum ?level ?cost_per_byte ?liquidity_baking_subsidy + initial_accounts = + let open Tezos_protocol_011_PtHangzH_parameters in + let constants = Default_parameters.constants_test in + let endorsers_per_block = + Option.value ~default:constants.endorsers_per_block endorsers_per_block + in + let initial_endorsers = + Option.value ~default:constants.initial_endorsers initial_endorsers + in + let min_proposal_quorum = + Option.value ~default:constants.min_proposal_quorum min_proposal_quorum + in + let time_between_blocks = + Option.value ~default:constants.time_between_blocks time_between_blocks + in + let minimal_block_delay = + Option.value ~default:constants.minimal_block_delay minimal_block_delay + in + let delay_per_missing_endorsement = + Option.value + ~default:constants.delay_per_missing_endorsement + delay_per_missing_endorsement + in + let cost_per_byte = + Option.value ~default:constants.cost_per_byte cost_per_byte + in + let liquidity_baking_subsidy = + Option.value + ~default:constants.liquidity_baking_subsidy + liquidity_baking_subsidy + in + let constants = + { + constants with + endorsers_per_block; + initial_endorsers; + min_proposal_quorum; + time_between_blocks; + minimal_block_delay; + delay_per_missing_endorsement; + cost_per_byte; + liquidity_baking_subsidy; + } + in + (* Check there is at least one roll *) + Lwt.catch + (fun () -> + List.fold_left_es + (fun acc (_, amount) -> + Environment.wrap_tzresult @@ Tez.( +? ) acc amount >>?= fun acc -> + if acc >= constants.tokens_per_roll then raise Exit else return acc) + Tez.zero + initial_accounts + >>=? fun _ -> + failwith "Insufficient tokens in initial accounts to create one roll") + (function Exit -> return_unit | exc -> raise exc) + >>=? fun () -> + check_constants_consistency constants >>=? fun () -> + let hash = + Block_hash.of_b58check_exn + "BLockGenesisGenesisGenesisGenesisGenesisCCCCCeZiLHU" + in + let shell = + Forge.make_shell + ~level:(Option.value ~default:0l level) + ~predecessor:hash + ~timestamp:Time.Protocol.epoch + ~fitness:(Fitness.from_int64 0L) + ~operations_hash:Operation_list_list_hash.zero + in + validate_initial_accounts initial_accounts constants.tokens_per_roll + (* Perhaps this could return a new type signifying its name *) + >|=? fun _initial_accounts -> (constants, shell, hash) + +(* if no parameter file is passed we check in the current directory + where the test is run *) +let genesis ?with_commitments ?endorsers_per_block ?initial_endorsers + ?min_proposal_quorum ?time_between_blocks ?minimal_block_delay + ?delay_per_missing_endorsement ?bootstrap_contracts ?level ?cost_per_byte + ?liquidity_baking_subsidy (initial_accounts : (Account.t * Tez.t) list) = + prepare_initial_context_params + ?endorsers_per_block + ?initial_endorsers + ?min_proposal_quorum + ?time_between_blocks + ?minimal_block_delay + ?delay_per_missing_endorsement + ?level + ?cost_per_byte + ?liquidity_baking_subsidy + initial_accounts + >>=? fun (constants, shell, hash) -> + initial_context + ?with_commitments + ?bootstrap_contracts + constants + shell + initial_accounts + >|=? fun context -> + let contents = Forge.make_contents ~priority:0 ~seed_nonce_hash:None () in + { + hash; + header = {shell; protocol_data = {contents; signature = Signature.zero}}; + operations = []; + context; + } + +let alpha_context ?with_commitments ?endorsers_per_block ?initial_endorsers + ?min_proposal_quorum (initial_accounts : (Account.t * Tez.t) list) = + prepare_initial_context_params + ?endorsers_per_block + ?initial_endorsers + ?min_proposal_quorum + initial_accounts + >>=? fun (constants, shell, _hash) -> + initial_alpha_context ?with_commitments constants shell initial_accounts + +(********* Baking *************) + +let apply_with_metadata header ?(operations = []) pred = + (let open Environment.Error_monad in + Main.begin_application + ~chain_id:Chain_id.zero + ~predecessor_context:pred.context + ~predecessor_fitness:pred.header.shell.fitness + ~predecessor_timestamp:pred.header.shell.timestamp + header + >>=? fun vstate -> + List.fold_left_es + (fun vstate op -> + apply_operation vstate op >|=? fun (state, _result) -> state) + vstate + operations + >>=? fun vstate -> + Main.finalize_block vstate (Some header.shell) + >|=? fun (validation, result) -> (validation.context, result)) + >|= Environment.wrap_tzresult + >|=? fun (context, result) -> + let hash = Block_header.hash header in + ({hash; header; operations; context}, result) + +let apply header ?(operations = []) pred = + apply_with_metadata header ~operations pred >>=? fun (t, _metadata) -> + return t + +let bake_with_metadata ?policy ?timestamp ?operation ?operations + ?liquidity_baking_escape_vote pred = + let operations = + match (operation, operations) with + | (Some op, Some ops) -> Some (op :: ops) + | (Some op, None) -> Some [op] + | (None, Some ops) -> Some ops + | (None, None) -> None + in + Forge.forge_header + ?timestamp + ?policy + ?operations + ?liquidity_baking_escape_vote + pred + >>=? fun header -> + Forge.sign_header header >>=? fun header -> + apply_with_metadata header ?operations pred + +let bake ?policy ?timestamp ?operation ?operations ?liquidity_baking_escape_vote + pred = + bake_with_metadata + ?policy + ?timestamp + ?operation + ?operations + ?liquidity_baking_escape_vote + pred + >>=? fun (t, _metadata) -> return t + +(********** Cycles ****************) + +(* This function is duplicated from Context to avoid a cyclic dependency *) +let get_constants b = Alpha_services.Constants.all rpc_ctxt b + +let bake_n ?policy ?liquidity_baking_escape_vote n b = + List.fold_left_es + (fun b _ -> bake ?policy ?liquidity_baking_escape_vote b) + b + (1 -- n) + +let bake_n_with_all_balance_updates ?policy ?liquidity_baking_escape_vote n b = + List.fold_left_es + (fun (b, balance_updates_rev) _ -> + bake_with_metadata ?policy ?liquidity_baking_escape_vote b + >>=? fun (b, metadata) -> + let balance_updates_rev = + List.rev_append metadata.balance_updates balance_updates_rev + in + let balance_updates_rev = + List.fold_left + (fun balance_updates_rev -> + let open Apply_results in + function + | Successful_manager_result (Reveal_result _) + | Successful_manager_result (Delegation_result _) -> + balance_updates_rev + | Successful_manager_result + (Transaction_result {balance_updates; _}) + | Successful_manager_result + (Origination_result {balance_updates; _}) + | Successful_manager_result + (Register_global_constant_result {balance_updates; _}) -> + List.rev_append balance_updates balance_updates_rev) + balance_updates_rev + metadata.implicit_operations_results + in + return (b, balance_updates_rev)) + (b, []) + (1 -- n) + >|=? fun (b, balance_updates_rev) -> (b, List.rev balance_updates_rev) + +let bake_n_with_origination_results ?policy n b = + List.fold_left_es + (fun (b, origination_results_rev) _ -> + bake_with_metadata ?policy b >>=? fun (b, metadata) -> + let origination_results_rev = + List.fold_left + (fun origination_results_rev -> + let open Apply_results in + function + | Successful_manager_result (Reveal_result _) + | Successful_manager_result (Delegation_result _) + | Successful_manager_result (Transaction_result _) + | Successful_manager_result (Register_global_constant_result _) -> + origination_results_rev + | Successful_manager_result (Origination_result x) -> + Origination_result x :: origination_results_rev) + origination_results_rev + metadata.implicit_operations_results + in + return (b, origination_results_rev)) + (b, []) + (1 -- n) + >|=? fun (b, origination_results_rev) -> (b, List.rev origination_results_rev) + +let bake_n_with_liquidity_baking_escape_ema ?policy + ?liquidity_baking_escape_vote n b = + List.fold_left_es + (fun (b, _escape_ema) _ -> + bake_with_metadata ?policy ?liquidity_baking_escape_vote b + >|=? fun (b, metadata) -> (b, metadata.liquidity_baking_escape_ema)) + (b, 0l) + (1 -- n) + +let bake_until_cycle_end ?policy b = + get_constants b >>=? fun Constants.{parametric = {blocks_per_cycle; _}; _} -> + let current_level = b.header.shell.level in + let current_level = Int32.rem current_level blocks_per_cycle in + let delta = Int32.sub blocks_per_cycle current_level in + bake_n ?policy (Int32.to_int delta) b + +let bake_until_n_cycle_end ?policy n b = + List.fold_left_es (fun b _ -> bake_until_cycle_end ?policy b) b (1 -- n) + +let current_cycle b = + get_constants b >>=? fun Constants.{parametric = {blocks_per_cycle; _}; _} -> + let current_level = b.header.shell.level in + let current_cycle = Int32.div current_level blocks_per_cycle in + let current_cycle = Cycle.add Cycle.root (Int32.to_int current_cycle) in + return current_cycle + +let bake_until_cycle ?policy cycle (b : t) = + let rec loop (b : t) = + current_cycle b >>=? fun current_cycle -> + if Cycle.equal cycle current_cycle then return b + else bake_until_cycle_end ?policy b >>=? fun b -> loop b + in + loop b diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/block.mli b/src/proto_011_PtHangzH/lib_protocol/test/helpers/block.mli new file mode 100644 index 000000000000..2712d4661506 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/block.mli @@ -0,0 +1,218 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +type t = { + hash : Block_hash.t; + header : Block_header.t; + operations : Operation.packed list; + context : Tezos_protocol_environment.Context.t; (** Resulting context *) +} + +type block = t + +val rpc_ctxt : t Environment.RPC_context.simple + +(** Policies to select the next baker: + - [By_priority p] selects the baker at priority [p] + - [By_account pkh] selects the first slot for baker [pkh] + - [Excluding pkhs] selects the first baker that doesn't belong to [pkhs] +*) +type baker_policy = + | By_priority of int + | By_account of public_key_hash + | Excluding of public_key_hash list + +(** Returns (account, priority, timestamp) of the next baker given + a policy, defaults to By_priority 0. *) +val get_next_baker : + ?policy:baker_policy -> + t -> + (public_key_hash * int * Time.Protocol.t) tzresult Lwt.t + +val get_endorsing_power : block -> int tzresult Lwt.t + +module Forge : sig + val contents : + ?proof_of_work_nonce:Bytes.t -> + ?priority:int -> + ?seed_nonce_hash:Nonce_hash.t -> + ?liquidity_baking_escape_vote:bool -> + unit -> + Block_header.contents + + type header + + (** Forges a correct header following the policy. + The header can then be modified and applied with [apply]. *) + val forge_header : + ?policy:baker_policy -> + ?timestamp:Timestamp.time -> + ?operations:Operation.packed list -> + ?liquidity_baking_escape_vote:bool -> + t -> + header tzresult Lwt.t + + (** Sets uniquely seed_nonce_hash of a header *) + val set_seed_nonce_hash : Nonce_hash.t option -> header -> header + + (** Sets the baker that will sign the header to an arbitrary pkh *) + val set_baker : public_key_hash -> header -> header + + (** Signs the header with the key of the baker configured in the header. + The header can no longer be modified, only applied. *) + val sign_header : header -> Block_header.block_header tzresult Lwt.t +end + +val check_constants_consistency : Constants.parametric -> unit tzresult Lwt.t + +(** [genesis accounts] : generates an initial block with the + given constants [] and initializes [accounts] with their + associated amounts. +*) +val genesis : + ?with_commitments:bool -> + ?endorsers_per_block:int -> + ?initial_endorsers:int -> + ?min_proposal_quorum:int32 -> + ?time_between_blocks:Period.t list -> + ?minimal_block_delay:Period.t -> + ?delay_per_missing_endorsement:Period.t -> + ?bootstrap_contracts:Parameters.bootstrap_contract list -> + ?level:int32 -> + ?cost_per_byte:Tez.t -> + ?liquidity_baking_subsidy:Tez.t -> + (Account.t * Tez.tez) list -> + block tzresult Lwt.t + +val genesis_with_parameters : Parameters.t -> block tzresult Lwt.t + +(** [alpha_context accounts] : instantiates an alpha_context with the + given constants [] and initializes [accounts] with their + associated amounts. +*) +val alpha_context : + ?with_commitments:bool -> + ?endorsers_per_block:int -> + ?initial_endorsers:int -> + ?min_proposal_quorum:int32 -> + (Account.t * Tez.tez) list -> + Alpha_context.t tzresult Lwt.t + +(** applies a signed header and its operations to a block and + obtains a new block *) +val apply : + Block_header.block_header -> + ?operations:Operation.packed list -> + t -> + t tzresult Lwt.t + +(** + [bake b] returns a block [b'] which has as predecessor block [b]. + Optional parameter [policy] allows to pick the next baker in several ways. + This function bundles together [forge_header], [sign_header] and [apply]. + These functions should be used instead of bake to craft unusual blocks for + testing together with setters for properties of the headers. + For examples see seed.ml or double_baking.ml +*) +val bake : + ?policy:baker_policy -> + ?timestamp:Timestamp.time -> + ?operation:Operation.packed -> + ?operations:Operation.packed list -> + ?liquidity_baking_escape_vote:bool -> + t -> + t tzresult Lwt.t + +(** Bakes [n] blocks. *) +val bake_n : + ?policy:baker_policy -> + ?liquidity_baking_escape_vote:bool -> + int -> + t -> + block tzresult Lwt.t + +(** Version of bake_n that returns a list of all balance updates included + in the metadata of baked blocks. **) +val bake_n_with_all_balance_updates : + ?policy:baker_policy -> + ?liquidity_baking_escape_vote:bool -> + int -> + t -> + (block * Alpha_context.Receipt.balance_updates) tzresult Lwt.t + +(** Version of bake_n that returns a list of all origination results + in the metadata of baked blocks. **) +val bake_n_with_origination_results : + ?policy:baker_policy -> + int -> + t -> + (block + * Alpha_context.Kind.origination + Apply_results.successful_manager_operation_result + list) + tzresult + Lwt.t + +(** Version of bake_n that returns the liquidity baking escape EMA after [n] blocks. **) +val bake_n_with_liquidity_baking_escape_ema : + ?policy:baker_policy -> + ?liquidity_baking_escape_vote:bool -> + int -> + t -> + (block * Alpha_context.Liquidity_baking.escape_ema) tzresult Lwt.t + +val current_cycle : t -> Cycle.t tzresult Lwt.t + +(** Given a block [b] at level [l] bakes enough blocks to complete a cycle, + that is [blocks_per_cycle - (l % blocks_per_cycle)]. *) +val bake_until_cycle_end : ?policy:baker_policy -> t -> t tzresult Lwt.t + +(** Bakes enough blocks to end [n] cycles. *) +val bake_until_n_cycle_end : + ?policy:baker_policy -> int -> t -> t tzresult Lwt.t + +(** Bakes enough blocks to reach the cycle. *) +val bake_until_cycle : ?policy:baker_policy -> Cycle.t -> t -> t tzresult Lwt.t + +(** Common util function to create parameters for [initial_context] function *) +val prepare_initial_context_params : + ?endorsers_per_block:int -> + ?initial_endorsers:int -> + ?time_between_blocks:Period.t list -> + ?minimal_block_delay:Period.t -> + ?delay_per_missing_endorsement:Period.t -> + ?min_proposal_quorum:int32 -> + ?level:int32 -> + ?cost_per_byte:Tez.t -> + ?liquidity_baking_subsidy:Tez.t -> + (Account.t * Tez.t) list -> + ( Constants.parametric * Block_header.shell_header * Block_hash.t, + tztrace ) + result + Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/context.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/context.ml new file mode 100644 index 000000000000..fced563d30e1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/context.ml @@ -0,0 +1,340 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +type t = B of Block.t | I of Incremental.t + +let branch = function B b -> b.hash | I i -> (Incremental.predecessor i).hash + +let level = function B b -> b.header.shell.level | I i -> Incremental.level i + +let get_level ctxt = + level ctxt |> Raw_level.of_int32 |> Environment.wrap_tzresult + +let rpc_ctxt = + object + method call_proto_service0 + : 'm 'q 'i 'o. + ( ([< RPC_service.meth] as 'm), + Environment.RPC_context.t, + Environment.RPC_context.t, + 'q, + 'i, + 'o ) + RPC_service.t -> + t -> + 'q -> + 'i -> + 'o tzresult Lwt.t = + fun s pr q i -> + match pr with + | B b -> Block.rpc_ctxt#call_proto_service0 s b q i + | I b -> Incremental.rpc_ctxt#call_proto_service0 s b q i + + method call_proto_service1 + : 'm 'a 'q 'i 'o. + ( ([< RPC_service.meth] as 'm), + Environment.RPC_context.t, + Environment.RPC_context.t * 'a, + 'q, + 'i, + 'o ) + RPC_service.t -> + t -> + 'a -> + 'q -> + 'i -> + 'o tzresult Lwt.t = + fun s pr a q i -> + match pr with + | B bl -> Block.rpc_ctxt#call_proto_service1 s bl a q i + | I bl -> Incremental.rpc_ctxt#call_proto_service1 s bl a q i + + method call_proto_service2 + : 'm 'a 'b 'q 'i 'o. + ( ([< RPC_service.meth] as 'm), + Environment.RPC_context.t, + (Environment.RPC_context.t * 'a) * 'b, + 'q, + 'i, + 'o ) + RPC_service.t -> + t -> + 'a -> + 'b -> + 'q -> + 'i -> + 'o tzresult Lwt.t = + fun s pr a b q i -> + match pr with + | B bl -> Block.rpc_ctxt#call_proto_service2 s bl a b q i + | I bl -> Incremental.rpc_ctxt#call_proto_service2 s bl a b q i + + method call_proto_service3 + : 'm 'a 'b 'c 'q 'i 'o. + ( ([< RPC_service.meth] as 'm), + Environment.RPC_context.t, + ((Environment.RPC_context.t * 'a) * 'b) * 'c, + 'q, + 'i, + 'o ) + RPC_service.t -> + t -> + 'a -> + 'b -> + 'c -> + 'q -> + 'i -> + 'o tzresult Lwt.t = + fun s pr a b c q i -> + match pr with + | B bl -> Block.rpc_ctxt#call_proto_service3 s bl a b c q i + | I bl -> Incremental.rpc_ctxt#call_proto_service3 s bl a b c q i + end + +let get_endorsers ctxt = Plugin.RPC.Endorsing_rights.get rpc_ctxt ctxt + +let get_endorser ctxt = + Plugin.RPC.Endorsing_rights.get rpc_ctxt ctxt >|=? fun endorsers -> + let endorser = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd endorsers in + (endorser.delegate, endorser.slots) + +let get_voting_power = Alpha_services.Delegate.voting_power rpc_ctxt + +let get_total_voting_power = Alpha_services.Voting.total_voting_power rpc_ctxt + +let get_bakers ctxt = + Plugin.RPC.Baking_rights.get ~max_priority:256 rpc_ctxt ctxt + >|=? fun bakers -> + List.map (fun p -> p.Plugin.RPC.Baking_rights.delegate) bakers + +let get_seed_nonce_hash ctxt = + let header = + match ctxt with B {header; _} -> header | I i -> Incremental.header i + in + match header.protocol_data.contents.seed_nonce_hash with + | None -> failwith "No committed nonce" + | Some hash -> return hash + +let get_seed ctxt = Alpha_services.Seed.get rpc_ctxt ctxt + +let get_constants ctxt = Alpha_services.Constants.all rpc_ctxt ctxt + +let get_minimal_valid_time ctxt ~priority ~endorsing_power = + Alpha_services.Delegate.Minimal_valid_time.get + rpc_ctxt + ctxt + priority + endorsing_power + +let rec reward_for_priority reward_per_prio prio = + match reward_per_prio with + | [] -> + (* Empty reward list in parameters means no rewards *) + Tez.zero + | [last] -> last + | first :: rest -> + if Compare.Int.(prio <= 0) then first + else reward_for_priority rest (pred prio) + +let get_baking_reward ctxt ~priority ~endorsing_power = + get_constants ctxt + >>=? fun {Constants.parametric = {baking_reward_per_endorsement; _}; _} -> + let reward_per_endorsement = + reward_for_priority baking_reward_per_endorsement priority + in + Lwt.return + (Environment.wrap_tzresult + Tez.(reward_per_endorsement *? Int64.of_int endorsing_power)) + +let get_endorsing_reward ctxt ~priority ~endorsing_power = + get_constants ctxt + >>=? fun {Constants.parametric = {endorsement_reward; _}; _} -> + let reward_per_endorsement = + reward_for_priority endorsement_reward priority + in + Lwt.return + (Environment.wrap_tzresult + Tez.(reward_per_endorsement *? Int64.of_int endorsing_power)) + +let get_liquidity_baking_subsidy ctxt = + get_constants ctxt + >>=? fun {Constants.parametric = {liquidity_baking_subsidy; _}; _} -> + return liquidity_baking_subsidy + +let get_liquidity_baking_cpmm_address ctxt = + Alpha_services.Liquidity_baking.get_cpmm_address rpc_ctxt ctxt + +(* Voting *) + +module Vote = struct + let get_ballots ctxt = Alpha_services.Voting.ballots rpc_ctxt ctxt + + let get_ballot_list ctxt = Alpha_services.Voting.ballot_list rpc_ctxt ctxt + + let get_current_period ctxt = + Alpha_services.Voting.current_period rpc_ctxt ctxt + + let get_current_quorum ctxt = + Alpha_services.Voting.current_quorum rpc_ctxt ctxt + + let get_listings ctxt = Alpha_services.Voting.listings rpc_ctxt ctxt + + let get_proposals ctxt = Alpha_services.Voting.proposals rpc_ctxt ctxt + + let get_current_proposal ctxt = + Alpha_services.Voting.current_proposal rpc_ctxt ctxt + + let get_protocol (b : Block.t) = + Tezos_protocol_environment.Context.get_protocol b.context + + let get_participation_ema (b : Block.t) = + Environment.Context.find b.context ["votes"; "participation_ema"] + >|= function + | None -> assert false + | Some bytes -> ok (TzEndian.get_int32 bytes 0) + + let set_participation_ema (b : Block.t) ema = + let bytes = Bytes.make 4 '\000' in + TzEndian.set_int32 bytes 0 ema ; + Environment.Context.add b.context ["votes"; "participation_ema"] bytes + >|= fun context -> {b with context} +end + +module Contract = struct + let pp = Alpha_context.Contract.pp + + let equal a b = Alpha_context.Contract.compare a b = 0 + + let pkh c = + Alpha_context.Contract.is_implicit c |> function + | Some p -> return p + | None -> failwith "pkh: only for implicit contracts" + + type balance_kind = Main | Deposit | Fees | Rewards + + let balance ?(kind = Main) ctxt contract = + match kind with + | Main -> Alpha_services.Contract.balance rpc_ctxt ctxt contract + | _ -> ( + match Alpha_context.Contract.is_implicit contract with + | None -> + invalid_arg + "get_balance: no frozen accounts for an originated contract." + | Some pkh -> + Alpha_services.Delegate.frozen_balance_by_cycle rpc_ctxt ctxt pkh + >>=? fun map -> + Lwt.return + @@ Cycle.Map.fold_e + (fun _cycle {Delegate.deposit; fees; rewards} acc -> + match kind with + | Deposit -> Test_tez.Tez.(acc +? deposit) + | Fees -> Test_tez.Tez.(acc +? fees) + | Rewards -> Test_tez.Tez.(acc +? rewards) + | _ -> assert false) + map + Tez.zero) + + let counter ctxt contract = + match Contract.is_implicit contract with + | None -> invalid_arg "Helpers.Context.counter" + | Some mgr -> Alpha_services.Contract.counter rpc_ctxt ctxt mgr + + let manager _ contract = + match Contract.is_implicit contract with + | None -> invalid_arg "Helpers.Context.manager" + | Some pkh -> Account.find pkh + + let is_manager_key_revealed ctxt contract = + match Contract.is_implicit contract with + | None -> invalid_arg "Helpers.Context.is_manager_key_revealed" + | Some mgr -> + Alpha_services.Contract.manager_key rpc_ctxt ctxt mgr >|=? fun res -> + res <> None + + let delegate ctxt contract = + Alpha_services.Contract.delegate rpc_ctxt ctxt contract + + let delegate_opt ctxt contract = + Alpha_services.Contract.delegate_opt rpc_ctxt ctxt contract + + let storage ctxt contract = + Alpha_services.Contract.storage rpc_ctxt ctxt contract + + let script ctxt contract = + Alpha_services.Contract.script rpc_ctxt ctxt contract + >>=? fun {code; storage = _} -> + match Data_encoding.force_decode code with + | Some v -> return v + | None -> invalid_arg "Cannot force lazy script" + + let script_hash ctxt contract = + script ctxt contract >>=? fun script -> + let bytes = Data_encoding.Binary.to_bytes_exn Script.expr_encoding script in + return @@ Script_expr_hash.hash_bytes [bytes] +end + +module Delegate = struct + type info = Delegate_services.info = { + balance : Tez.t; + frozen_balance : Tez.t; + frozen_balance_by_cycle : Delegate.frozen_balance Cycle.Map.t; + staking_balance : Tez.t; + delegated_contracts : Alpha_context.Contract.t list; + delegated_balance : Tez.t; + deactivated : bool; + grace_period : Cycle.t; + voting_power : int32; + } + + let info ctxt pkh = Alpha_services.Delegate.info rpc_ctxt ctxt pkh +end + +let init ?rng_state ?endorsers_per_block ?with_commitments + ?(initial_balances = []) ?initial_endorsers ?min_proposal_quorum + ?time_between_blocks ?minimal_block_delay ?delay_per_missing_endorsement + ?bootstrap_contracts ?level ?cost_per_byte ?liquidity_baking_subsidy n = + let accounts = Account.generate_accounts ?rng_state ~initial_balances n in + let contracts = + List.map + (fun (a, _) -> Alpha_context.Contract.implicit_contract Account.(a.pkh)) + accounts + in + Block.genesis + ?endorsers_per_block + ?with_commitments + ?initial_endorsers + ?min_proposal_quorum + ?time_between_blocks + ?minimal_block_delay + ?delay_per_missing_endorsement + ?bootstrap_contracts + ?level + ?cost_per_byte + ?liquidity_baking_subsidy + accounts + >|=? fun blk -> (blk, contracts) diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/context.mli b/src/proto_011_PtHangzH/lib_protocol/test/helpers/context.mli new file mode 100644 index 000000000000..10c6d3e1db93 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/context.mli @@ -0,0 +1,157 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Environment + +type t = B of Block.t | I of Incremental.t + +val branch : t -> Block_hash.t + +val get_level : t -> Raw_level.t tzresult + +val get_endorsers : t -> Plugin.RPC.Endorsing_rights.t list tzresult Lwt.t + +val get_endorser : t -> (public_key_hash * int list) tzresult Lwt.t + +val get_voting_power : + t -> public_key_hash -> int32 Environment.Error_monad.shell_tzresult Lwt.t + +val get_total_voting_power : + t -> int32 Environment.Error_monad.shell_tzresult Lwt.t + +val get_bakers : t -> public_key_hash list tzresult Lwt.t + +val get_seed_nonce_hash : t -> Nonce_hash.t tzresult Lwt.t + +(** Returns the seed of the cycle to which the block belongs to. *) +val get_seed : t -> Seed.seed tzresult Lwt.t + +(** Returns all the constants of the protocol *) +val get_constants : t -> Constants.t tzresult Lwt.t + +val get_minimal_valid_time : + t -> priority:int -> endorsing_power:int -> Time.t tzresult Lwt.t + +val get_baking_reward : + t -> priority:int -> endorsing_power:int -> Tez.t tzresult Lwt.t + +val get_endorsing_reward : + t -> priority:int -> endorsing_power:int -> Tez.t tzresult Lwt.t + +val get_liquidity_baking_subsidy : t -> Tez.t tzresult Lwt.t + +val get_liquidity_baking_cpmm_address : t -> Contract.t tzresult Lwt.t + +module Vote : sig + val get_ballots : t -> Vote.ballots tzresult Lwt.t + + val get_ballot_list : + t -> (Signature.Public_key_hash.t * Vote.ballot) list tzresult Lwt.t + + val get_current_period : t -> Voting_period.info tzresult Lwt.t + + val get_current_quorum : t -> int32 tzresult Lwt.t + + val get_participation_ema : Block.t -> int32 tzresult Lwt.t + + val get_listings : + t -> (Signature.Public_key_hash.t * int32) list tzresult Lwt.t + + val get_proposals : t -> int32 Protocol_hash.Map.t tzresult Lwt.t + + val get_current_proposal : t -> Protocol_hash.t option tzresult Lwt.t + + val get_protocol : Block.t -> Protocol_hash.t Lwt.t + + val set_participation_ema : Block.t -> int32 -> Block.t Lwt.t +end + +module Contract : sig + val pp : Format.formatter -> Contract.t -> unit + + val equal : Contract.t -> Contract.t -> bool + + val pkh : Contract.t -> public_key_hash tzresult Lwt.t + + type balance_kind = Main | Deposit | Fees | Rewards + + (** Returns the balance of a contract, by default the main balance. + If the contract is implicit the frozen balances are available too: + deposit, fees or rewards. *) + val balance : ?kind:balance_kind -> t -> Contract.t -> Tez.t tzresult Lwt.t + + val counter : t -> Contract.t -> Z.t tzresult Lwt.t + + val manager : t -> Contract.t -> Account.t tzresult Lwt.t + + val is_manager_key_revealed : t -> Contract.t -> bool tzresult Lwt.t + + val delegate : t -> Contract.t -> public_key_hash tzresult Lwt.t + + val delegate_opt : t -> Contract.t -> public_key_hash option tzresult Lwt.t + + val storage : t -> Contract.t -> Script.expr tzresult Lwt.t + + val script : t -> Contract.t -> Script.expr tzresult Lwt.t + + val script_hash : t -> Contract.t -> Script_expr_hash.t tzresult Lwt.t +end + +module Delegate : sig + type info = Delegate_services.info = { + balance : Tez.t; + frozen_balance : Tez.t; + frozen_balance_by_cycle : Delegate.frozen_balance Cycle.Map.t; + staking_balance : Tez.t; + delegated_contracts : Alpha_context.Contract.t list; + delegated_balance : Tez.t; + deactivated : bool; + grace_period : Cycle.t; + voting_power : int32; + } + + val info : t -> public_key_hash -> Delegate_services.info tzresult Lwt.t +end + +(** [init n] : returns an initial block with [n] initialized accounts + and the associated implicit contracts *) +val init : + ?rng_state:Random.State.t -> + ?endorsers_per_block:int -> + ?with_commitments:bool -> + ?initial_balances:int64 list -> + ?initial_endorsers:int -> + ?min_proposal_quorum:int32 -> + ?time_between_blocks:Period.t list -> + ?minimal_block_delay:Period.t -> + ?delay_per_missing_endorsement:Period.t -> + ?bootstrap_contracts:Parameters.bootstrap_contract list -> + ?level:int32 -> + ?cost_per_byte:Tez.t -> + ?liquidity_baking_subsidy:Tez.t -> + int -> + (Block.t * Alpha_context.Contract.t list) tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/contract_helpers.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/contract_helpers.ml new file mode 100644 index 000000000000..76b31fe23c62 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/contract_helpers.ml @@ -0,0 +1,73 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(** Initializes 2 addresses to do only operations plus one that will be + used to bake. *) +let init () = + Context.init 3 >|=? fun (b, contracts) -> + let (src0, src1, src2) = + match contracts with + | src0 :: src1 :: src2 :: _ -> (src0, src1, src2) + | _ -> assert false + in + let baker = + match Alpha_context.Contract.is_implicit src0 with + | Some v -> v + | None -> assert false + in + (b, baker, src1, src2) + +(** Parses a Michelson contract from string. *) +let toplevel_from_string str = + let (ast, errs) = Michelson_v1_parser.parse_toplevel ~check:true str in + match errs with [] -> ast.expanded | _ -> Stdlib.failwith "parse toplevel" + +(** Parses a Michelson expression from string, useful for call parameters. *) +let expression_from_string str = + let (ast, errs) = Michelson_v1_parser.parse_expression ~check:true str in + match errs with [] -> ast.expanded | _ -> Stdlib.failwith "parse expression" + +(** Returns a block in which the contract is originated. *) +let originate_contract file storage src b baker = + let load_file f = + let ic = open_in f in + let res = really_input_string ic (in_channel_length ic) in + close_in ic ; + res + in + let contract_string = load_file file in + let code = toplevel_from_string contract_string in + let storage = expression_from_string storage in + let script = + Alpha_context.Script.{code = lazy_expr code; storage = lazy_expr storage} + in + Op.origination (B b) src ~fee:(Test_tez.Tez.of_int 10) ~script + >>=? fun (operation, dst) -> + Incremental.begin_construction ~policy:Block.(By_account baker) b + >>=? fun incr -> + Incremental.add_operation incr operation >>=? fun incr -> + Incremental.finalize_block incr >|=? fun b -> (dst, b) diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/cpmm_logic.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/cpmm_logic.ml new file mode 100644 index 000000000000..a1d4d8027c58 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/cpmm_logic.ml @@ -0,0 +1,102 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +(** This is a simulation of the CPMM contract, as implemented in mligo + in [src/proto_alpha/lib_protocol/contracts/cpmm.mligo]. The + interested reader should look for comments in this file to gain a + better understanding of the contract logic. *) +module Simulate_raw = struct + let mutez_to_natural t = Z.of_int64 (Tez.to_mutez t) + + let natural_to_mutez n = Tez.of_mutez_exn (Z.to_int64 n) + + let addLiquidity ~tokenPool ~xtzPool ~lqtTotal ~amount = + let xtzPool = mutez_to_natural xtzPool in + let nat_amount = mutez_to_natural amount in + let lqt_minted = Z.(nat_amount * lqtTotal / xtzPool) in + let tokens_deposited = Z.(cdiv (nat_amount * tokenPool) xtzPool) in + (lqt_minted, tokens_deposited) + + let removeLiquidity ~tokenPool ~xtzPool ~lqtTotal ~lqtBurned = + let xtz_withdrawn = + natural_to_mutez Z.(lqtBurned * mutez_to_natural xtzPool / lqtTotal) + in + let tokens_withdrawn = Z.(lqtBurned * tokenPool / lqtTotal) in + (xtz_withdrawn, tokens_withdrawn) + + let tokenToXtz ~tokenPool ~xtzPool ~tokensSold = + let fee = Z.of_int 999 in + let xtz_bought_nat = + Z.( + tokensSold * fee * mutez_to_natural xtzPool + / ((tokenPool * of_int 1000) + (tokensSold * fee))) + in + let bought = Z.(xtz_bought_nat * of_int 999 / of_int 1000) in + (natural_to_mutez bought, xtz_bought_nat) + + let xtzToToken ~tokenPool ~xtzPool ~amount = + let fee = Z.of_int 999 in + let xtzPool = mutez_to_natural xtzPool in + let nat_amount = mutez_to_natural amount in + let amount_net_burn = Z.(nat_amount * Z.of_int 999 / Z.of_int 1000) in + let tokens_bought = + Z.( + amount_net_burn * fee * tokenPool + / ((xtzPool * Z.of_int 1000) + (amount_net_burn * fee))) + in + (tokens_bought, amount_net_burn) + + let tokenToToken ~tokenPool ~xtzPool ~tokensSold = + let fee = Z.of_int 999 in + let xtz_bought_nat = + Z.( + tokensSold * fee * mutez_to_natural xtzPool + / ((tokenPool * of_int 1000) + (tokensSold * fee))) + in + let xtz_bought_net_burn = Z.(xtz_bought_nat * of_int 999 / of_int 1000) in + (natural_to_mutez xtz_bought_net_burn, xtz_bought_nat) +end + +module Simulate = struct + open Cpmm_repr.Storage + + let addLiquidity {tokenPool; xtzPool; lqtTotal; _} amount = + Simulate_raw.addLiquidity ~xtzPool ~tokenPool ~lqtTotal ~amount + + let removeLiquidity {tokenPool; xtzPool; lqtTotal; _} lqtBurned = + Simulate_raw.removeLiquidity ~tokenPool ~xtzPool ~lqtTotal ~lqtBurned + + let tokenToXtz {tokenPool; xtzPool; _} tokensSold = + Simulate_raw.tokenToXtz ~tokenPool ~xtzPool ~tokensSold + + let xtzToToken {tokenPool; xtzPool; _} amount = + Simulate_raw.xtzToToken ~tokenPool ~xtzPool ~amount + + let tokenToToken {tokenPool; xtzPool; _} tokensSold = + Simulate_raw.tokenToToken ~tokenPool ~xtzPool ~tokensSold +end diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/cpmm_repr.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/cpmm_repr.ml new file mode 100644 index 000000000000..5ec22503b0eb --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/cpmm_repr.ml @@ -0,0 +1,384 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Expr_common + +(* // ============================================================================= + * // Storage + * // ============================================================================= *) + +module Storage = struct + type t = { + tokenPool : Z.t; + xtzPool : Tez.t; + lqtTotal : Z.t; + tokenAddress : Contract.t; + lqtAddress : Contract.t; + } + + let zero : t = + { + tokenPool = Z.zero; + xtzPool = Tez.zero; + lqtTotal = Z.zero; + tokenAddress = + Contract.originated_contract + (Contract.initial_origination_nonce Operation_hash.zero); + lqtAddress = + Contract.originated_contract + (Contract.initial_origination_nonce Operation_hash.zero); + } + + let to_string {tokenPool; xtzPool; lqtTotal; tokenAddress; lqtAddress} = + Format.asprintf + "{tokenPool : %a; xtzPool : %s; lqtTotal : %a; tokenAddress : %s; \ + lqtAddress : %s;}" + Z.pp_print + tokenPool + (Int64.to_string @@ Tez.to_mutez xtzPool) + Z.pp_print + lqtTotal + (Contract.to_b58check tokenAddress) + (Contract.to_b58check lqtAddress) + + let pp fmt s = Format.fprintf fmt "%s" (to_string s) + + let eq s s' = s = s' + + let to_expr : + loc:'a -> + t -> + ('a, Michelson_v1_primitives.prim) Tezos_micheline.Micheline.node = + fun ~loc {tokenPool; xtzPool; lqtTotal; tokenAddress; lqtAddress} -> + comb + ~loc + [ + int ~loc tokenPool; + mutez ~loc xtzPool; + int ~loc lqtTotal; + address_string ~loc tokenAddress; + address_string ~loc lqtAddress; + ] + + let to_michelson_string e = + let e = to_expr ~loc:0 e in + Format.asprintf + "%a" + Michelson_v1_printer.print_expr + (Micheline.strip_locations e) + + type exn += Invalid_storage_expr of string + + (** Note: parses a storage unparsed in readable mode (as + e.g. returned by [Alpha_services.Contract.storage]), so that + contracts are represented by strings. *) + let of_expr_exn : + ('a, Michelson_v1_primitives.prim) Tezos_micheline.Micheline.node -> t = + function + | Tezos_micheline.Micheline.Prim + ( _, + Script.D_Pair, + [ + Tezos_micheline.Micheline.Int (_, tokenPool); + Tezos_micheline.Micheline.Int (_, xtzPool); + Tezos_micheline.Micheline.Int (_, lqtTotal); + Tezos_micheline.Micheline.String (_, tokenAddress); + Tezos_micheline.Micheline.String (_, lqtAddress); + ], + [] ) -> + let xtzPool = Tez.of_mutez_exn (Z.to_int64 xtzPool) in + let tokenAddress = address_of_string_exn tokenAddress in + let lqtAddress = address_of_string_exn lqtAddress in + {tokenPool; xtzPool; lqtTotal; tokenAddress; lqtAddress} + | e -> + let canonical = Micheline.strip_locations e in + let msg = + Format.asprintf + "Not a valid CPMM storage: %s /// %a" + (try + Michelson_v1_printer.micheline_string_of_expression + ~zero_loc:true + canonical + with Z.Overflow -> + "Cannot represent as micheline due to overflowing Z -> int") + Michelson_v1_printer.print_expr + canonical + in + raise (Invalid_storage_expr msg) + + let get (ctxt : Context.t) ~(contract : Contract.t) : t tzresult Lwt.t = + Context.Contract.storage ctxt contract >|=? Micheline.root >|=? of_expr_exn + + let of_tuple (tokenPool, xtzPool, lqtTotal, tokenAddress, lqtAddress) = + {tokenPool; xtzPool; lqtTotal; tokenAddress; lqtAddress} + + let to_tuple {tokenPool; xtzPool; lqtTotal; tokenAddress; lqtAddress} = + (tokenPool, xtzPool, lqtTotal, tokenAddress, lqtAddress) + + let valid {tokenPool; xtzPool; lqtTotal; _} = + tokenPool > Z.zero && lqtTotal > Z.zero && Tez.(xtzPool > Tez.zero) +end + +module Parameter = struct + (* // ============================================================================= + * // Entrypoints + * // ============================================================================= *) + + type add_liquidity = { + owner : Contract.t; + minLqtMinted : Z.t; + maxTokensDeposited : Z.t; + deadline : Script_timestamp.t; + } + + type remove_liquidity = { + to_ : Contract.t; + (* recipient of the liquidity redemption *) + lqtBurned : Z.t; + (* amount of lqt owned by sender to burn *) + minXtzWithdrawn : Tez.t; + (* minimum amount of Tez.t to withdraw *) + minTokensWithdrawn : Z.t; + (* minimum amount of tokens to withdraw *) + deadline : Script_timestamp.t; + (* the time before which the request must be completed *) + } + + type token_to_token = { + outputDexterContract : Contract.t; + minTokensBought : Z.t; + to_ : Contract.t; + tokensSold : Z.t; + deadline : Script_timestamp.t; + } + + type token_to_xtz = { + to_ : Contract.t; + tokensSold : Z.t; + minXtzBought : Tez.t; + deadline : Script_timestamp.t; + } + + type xtz_to_token = { + to_ : Contract.t; + minTokensBought : Z.t; + deadline : Script_timestamp.t; + } + + type t = + | AddLiquidity of add_liquidity + | Default of unit + | RemoveLiquidity of remove_liquidity + | TokenToToken of token_to_token + | TokenToXtz of token_to_xtz + | XtzToToken of xtz_to_token + + let addLiquidity p = AddLiquidity p + + let default p = Default p + + let removeLiquidity p = RemoveLiquidity p + + let tokenToToken p = TokenToToken p + + let tokenToXtz p = TokenToXtz p + + let xtzToToken p = XtzToToken p + + let add_liquidity_to_string : add_liquidity -> string = + fun {owner; minLqtMinted; maxTokensDeposited; deadline} -> + Format.asprintf + "{owner : %s; minLqtMinted : %a; maxTokensDeposited : %a; deadline : %s }" + (Contract.to_b58check owner) + Z.pp_print + minLqtMinted + Z.pp_print + maxTokensDeposited + (Script_timestamp.to_string deadline) + + let remove_liquidity_to_string : remove_liquidity -> string = + fun {to_; lqtBurned; minXtzWithdrawn; minTokensWithdrawn; deadline} -> + Format.asprintf + "{owner : %s; lqtBurned : %a; minXtzWithdrawn : %s; minTokensWithdrawn : \ + %a; deadline : %s }" + (Contract.to_b58check to_) + Z.pp_print + lqtBurned + (Int64.to_string @@ Tez.to_mutez minXtzWithdrawn) + Z.pp_print + minTokensWithdrawn + (Script_timestamp.to_string deadline) + + let token_to_token_to_string : token_to_token -> string = + fun {outputDexterContract; minTokensBought; to_; tokensSold; deadline} -> + Format.asprintf + "{outputDexterContract : %s; minTokensBought : %a; to_ : %s; tokensSold \ + : %a; deadline : %s }" + (Contract.to_b58check outputDexterContract) + Z.pp_print + minTokensBought + (Contract.to_b58check to_) + Z.pp_print + tokensSold + (Script_timestamp.to_string deadline) + + let token_to_xtz_to_string : token_to_xtz -> string = + fun {to_; tokensSold; minXtzBought; deadline} -> + Format.asprintf + "{to_ : %s; tokensSold : %a; minXtzBought : %s; deadline : %s }" + (Contract.to_b58check to_) + Z.pp_print + tokensSold + (Int64.to_string @@ Tez.to_mutez minXtzBought) + (Script_timestamp.to_string deadline) + + let xtz_to_token_to_string : xtz_to_token -> string = + fun {to_; minTokensBought; deadline} -> + Format.asprintf + "{to_ : %s; minTokensBought : %a; deadline : %s }" + (Contract.to_b58check to_) + Z.pp_print + minTokensBought + (Script_timestamp.to_string deadline) + + let to_string : t -> string = function + | AddLiquidity p -> + Format.asprintf "AddLiquidity %s" (add_liquidity_to_string p) + | Default () -> "Default ()" + | RemoveLiquidity p -> + Format.asprintf "RemoveLiquidity %s" (remove_liquidity_to_string p) + | TokenToToken p -> + Format.asprintf "TokenToToken (%s)" (token_to_token_to_string p) + | TokenToXtz p -> + Format.asprintf "TokenToXtz (%s)" (token_to_xtz_to_string p) + | XtzToToken p -> + Format.asprintf "XtzToToken (%s)" (xtz_to_token_to_string p) + + let entrypoint_of_parameter : t -> string = function + | AddLiquidity _ -> "addLiquidity" + | Default _ -> "default" + | RemoveLiquidity _ -> "removeLiquidity" + | TokenToToken _ -> "tokenToToken" + | TokenToXtz _ -> "tokenToXtz" + | XtzToToken _ -> "xtzToToken" + + let pp fmt s = Format.fprintf fmt "%s" (to_string s) + + let eq s s' = s = s' + + let to_expr_rooted : + loc:'a -> + t -> + ('a, Michelson_v1_primitives.prim) Tezos_micheline.Micheline.node = + fun ~loc -> function + | AddLiquidity {owner; minLqtMinted; maxTokensDeposited; deadline} -> + comb + ~loc + [ + address_string ~loc owner; + int ~loc minLqtMinted; + int ~loc maxTokensDeposited; + timestamp ~loc deadline; + ] + | Default () -> unit ~loc + | RemoveLiquidity + {to_; lqtBurned; minXtzWithdrawn; minTokensWithdrawn; deadline} -> + comb + ~loc + [ + address_string ~loc to_; + int ~loc lqtBurned; + mutez ~loc minXtzWithdrawn; + int ~loc minTokensWithdrawn; + timestamp ~loc deadline; + ] + | TokenToToken + {outputDexterContract; minTokensBought; to_; tokensSold; deadline} -> + comb + ~loc + [ + address_string ~loc outputDexterContract; + int ~loc minTokensBought; + address_string ~loc to_; + int ~loc tokensSold; + timestamp ~loc deadline; + ] + | TokenToXtz {to_; tokensSold; minXtzBought; deadline} -> + comb + ~loc + [ + address_string ~loc to_; + int ~loc tokensSold; + mutez ~loc minXtzBought; + timestamp ~loc deadline; + ] + | XtzToToken {to_; minTokensBought; deadline} -> + comb + ~loc + [ + address_string ~loc to_; + int ~loc minTokensBought; + timestamp ~loc deadline; + ] + + let to_expr : + loc:'a -> + t -> + ('a, Michelson_v1_primitives.prim) Tezos_micheline.Micheline.node = + fun ~loc p -> + let rooted = to_expr_rooted ~loc p in + match p with + | AddLiquidity _ -> left ~loc @@ left ~loc @@ left ~loc rooted + | Default () -> left ~loc @@ left ~loc @@ right ~loc rooted + | RemoveLiquidity _ -> left ~loc @@ right ~loc @@ left ~loc rooted + | TokenToToken _ -> left ~loc @@ right ~loc @@ right ~loc rooted + | TokenToXtz _ -> right ~loc @@ left ~loc rooted + | XtzToToken _ -> right ~loc @@ right ~loc rooted + + let to_michelson_string e = + let e = to_expr ~loc:0 e in + Format.asprintf + "%a" + Michelson_v1_printer.print_expr + (Micheline.strip_locations e) +end + +let transaction (ctxt : Context.t) ~(contract : Contract.t) ~(src : Contract.t) + ?(amount = Tez.zero) (parameters : Parameter.t) = + let entrypoint = Parameter.entrypoint_of_parameter parameters in + let rooted_param_lazy = + parameters + |> Parameter.to_expr_rooted ~loc:0 + |> Micheline.strip_locations |> Alpha_context.Script.lazy_expr + in + Op.transaction + ctxt + src + contract + amount + ~entrypoint + ~parameters:rooted_param_lazy diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/dune b/src/proto_011_PtHangzH/lib_protocol/test/helpers/dune new file mode 100644 index 000000000000..97290d7d2cd1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/dune @@ -0,0 +1,24 @@ +(library + (name tezos_011_PtHangzH_test_helpers) + (instrumentation (backend bisect_ppx)) + (public_name tezos-011-PtHangzH-test-helpers) + (libraries alcotest-lwt + qcheck-alcotest + tezos-test-helpers + tezos-base + tezos-micheline + tezos-stdlib-unix + tezos-shell-services + tezos-protocol-environment + tezos-protocol-011-PtHangzH + tezos-protocol-011-PtHangzH-parameters + tezos-client-011-PtHangzH + tezos-protocol-plugin-011-PtHangzH) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_micheline + -open Tezos_stdlib_unix + -open Tezos_protocol_011_PtHangzH + -open Tezos_client_011_PtHangzH + -open Tezos_protocol_plugin_011_PtHangzH + -open Tezos_protocol_environment_011_PtHangzH + -open Tezos_shell_services))) diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/dune-project b/src/proto_011_PtHangzH/lib_protocol/test/helpers/dune-project new file mode 100644 index 000000000000..b26f68e03670 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/dune-project @@ -0,0 +1,3 @@ +(lang dune 2.7) +(formatting (enabled_for ocaml)) +(name tezos-alpha-test-helpers) diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/expr.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/expr.ml new file mode 100644 index 000000000000..3b3b656e29fb --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/expr.ml @@ -0,0 +1,40 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +exception Expression_from_string + +let from_string str : Script.expr = + let (ast, errs) = Michelson_v1_parser.parse_expression ~check:false str in + (match errs with + | [] -> () + | lst -> + Format.printf "expr_from_string: %a\n" Error_monad.pp_print_error lst ; + raise Expression_from_string) ; + ast.expanded + +let to_string c = Fmt.str "%a" Michelson_v1_printer.print_expr c diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/expr_common.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/expr_common.ml new file mode 100644 index 000000000000..1dd79eeba539 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/expr_common.ml @@ -0,0 +1,82 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +(* From OCaml values to Micheline expressions *) + +let seq ~loc l = Tezos_micheline.Micheline.Seq (loc, l) + +let pair ~loc a b = + Tezos_micheline.Micheline.Prim (loc, Script.D_Pair, [a; b], []) + +let comb ~loc es = Tezos_micheline.Micheline.Prim (loc, Script.D_Pair, es, []) + +let none ~loc () = Tezos_micheline.Micheline.Prim (loc, Script.D_None, [], []) + +let some ~loc a = Tezos_micheline.Micheline.Prim (loc, Script.D_Some, [a], []) + +let left ~loc a = Tezos_micheline.Micheline.Prim (loc, Script.D_Left, [a], []) + +let right ~loc b = Tezos_micheline.Micheline.Prim (loc, Script.D_Right, [b], []) + +let unit ~loc = Tezos_micheline.Micheline.Prim (loc, Script.D_Unit, [], []) + +let int ~loc i = Tezos_micheline.Micheline.Int (loc, i) + +let bytes ~loc s = Tezos_micheline.Micheline.Bytes (loc, s) + +let string ~loc s = Tezos_micheline.Micheline.String (loc, s) + +let mutez ~loc m = int ~loc (Z.of_int64 (Tez.to_mutez m)) + +(* Translate a timestamp to a Micheline expression in optimized + form *) +let timestamp ~loc ts = int ~loc (Script_timestamp.to_zint ts) + +let address ~loc adr = + bytes ~loc @@ Data_encoding.Binary.to_bytes_exn Contract.encoding adr + +let address_string ~loc adr = string ~loc @@ Contract.to_b58check adr + +let big_map_id ~loc id = int ~loc @@ Big_map.Id.unparse_to_z id + +(* From Micheline expressions to OCaml values *) + +let timestamp_of_zint zint = Script_timestamp.of_zint zint + +let public_key_of_bytes_exn b = + Data_encoding.Binary.of_bytes_exn Signature.Public_key.encoding b + +let address_of_bytes_exn b = + Data_encoding.Binary.of_bytes_exn Contract.encoding b + +type exn += Invalid_address_expr of string + +let address_of_string_exn s = + match Contract.of_b58check s with + | Ok c -> c + | Error _ -> raise @@ Invalid_address_expr s diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/incremental.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/incremental.ml new file mode 100644 index 000000000000..27dbc726cb3c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/incremental.ml @@ -0,0 +1,209 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +type t = { + predecessor : Block.t; + state : validation_state; + rev_operations : Operation.packed list; + rev_tickets : operation_receipt list; + header : Block_header.t; + delegate : Account.t; +} + +type incremental = t + +let predecessor {predecessor; _} = predecessor + +let header {header; _} = header + +let rev_tickets {rev_tickets; _} = rev_tickets + +let validation_state {state; _} = state + +let level st = st.header.shell.level + +let rpc_context st = + let result = Alpha_context.finalize st.state.ctxt in + { + Environment.Updater.block_hash = Block_hash.zero; + block_header = {st.header.shell with fitness = result.fitness}; + context = result.context; + } + +let rpc_ctxt = + new Environment.proto_rpc_context_of_directory rpc_context rpc_services + +let alpha_ctxt st = st.state.ctxt + +let begin_construction ?(priority = 0) ?timestamp ?seed_nonce_hash + ?(policy = Block.By_priority priority) (predecessor : Block.t) = + Block.get_next_baker ~policy predecessor + >>=? fun (delegate, priority, _timestamp) -> + Alpha_services.Delegate.Minimal_valid_time.get + Block.rpc_ctxt + predecessor + priority + 0 + >>=? fun real_timestamp -> + Account.find delegate >>=? fun delegate -> + let timestamp = Option.value ~default:real_timestamp timestamp in + let contents = Block.Forge.contents ~priority ?seed_nonce_hash () in + let protocol_data = {Block_header.contents; signature = Signature.zero} in + let header = + { + Block_header.shell = + { + predecessor = predecessor.hash; + proto_level = predecessor.header.shell.proto_level; + validation_passes = predecessor.header.shell.validation_passes; + fitness = predecessor.header.shell.fitness; + timestamp; + level = predecessor.header.shell.level; + context = Context_hash.zero; + operations_hash = Operation_list_list_hash.zero; + }; + protocol_data = {contents; signature = Signature.zero}; + } + in + begin_construction + ~chain_id:Chain_id.zero + ~predecessor_context:predecessor.context + ~predecessor_timestamp:predecessor.header.shell.timestamp + ~predecessor_fitness:predecessor.header.shell.fitness + ~predecessor_level:predecessor.header.shell.level + ~predecessor:predecessor.hash + ~timestamp + ~protocol_data + () + >|= fun state -> + Environment.wrap_tzresult state >|? fun state -> + {predecessor; state; rev_operations = []; rev_tickets = []; header; delegate} + +let detect_script_failure : + type kind. kind Apply_results.operation_metadata -> _ = + let rec detect_script_failure : + type kind. kind Apply_results.contents_result_list -> _ = + let open Apply_results in + let detect_script_failure_single (type kind) + (Manager_operation_result + {operation_result; internal_operation_results; _} : + kind Kind.manager Apply_results.contents_result) = + let detect_script_failure (type kind) + (result : kind manager_operation_result) = + match result with + | Applied _ -> Ok () + | Skipped _ -> assert false + | Backtracked (_, None) -> + (* there must be another error for this to happen *) + Ok () + | Backtracked (_, Some errs) -> Error (Environment.wrap_tztrace errs) + | Failed (_, errs) -> Error (Environment.wrap_tztrace errs) + in + List.fold_left + (fun acc (Internal_operation_result (_, r)) -> + acc >>? fun () -> detect_script_failure r) + (detect_script_failure operation_result) + internal_operation_results + in + function + | Single_result (Manager_operation_result _ as res) -> + detect_script_failure_single res + | Single_result _ -> Ok () + | Cons_result (res, rest) -> + detect_script_failure_single res >>? fun () -> + detect_script_failure rest + in + fun {contents} -> detect_script_failure contents + +let add_operation ?expect_apply_failure ?expect_failure st op = + let open Apply_results in + apply_operation st.state op >|= Environment.wrap_tzresult >>= fun result -> + match (expect_apply_failure, result) with + | (Some _, Ok _) -> failwith "Error expected while adding operation" + | (Some f, Error err) -> f err >|=? fun () -> st + | (None, result) -> ( + result >>?= fun result -> + match result with + | (state, (Operation_metadata result as metadata)) -> + detect_script_failure result |> fun result -> + (match expect_failure with + | None -> Lwt.return result + | Some f -> ( + match result with + | Ok _ -> failwith "Error expected while adding operation" + | Error e -> f e)) + >|=? fun () -> + { + st with + state; + rev_operations = op :: st.rev_operations; + rev_tickets = metadata :: st.rev_tickets; + } + | (state, (No_operation_metadata as metadata)) -> + return + { + st with + state; + rev_operations = op :: st.rev_operations; + rev_tickets = metadata :: st.rev_tickets; + }) + +let finalize_block st = + let operations = List.rev st.rev_operations in + let operations_hash = + Operation_list_list_hash.compute + [Operation_list_hash.compute (List.map Operation.hash_packed operations)] + in + let shell_header = + { + st.header.shell with + level = Int32.succ st.header.shell.level; + operations_hash; + } + in + finalize_block st.state (Some shell_header) >|= fun x -> + Environment.wrap_tzresult x >|? fun (result, _) -> + let operations = List.rev st.rev_operations in + let operations_hash = + Operation_list_list_hash.compute + [Operation_list_hash.compute (List.map Operation.hash_packed operations)] + in + let header = + { + st.header with + shell = + { + st.header.shell with + level = Int32.succ st.header.shell.level; + operations_hash; + fitness = result.fitness; + }; + } + in + let hash = Block_header.hash header in + {Block.hash; header; operations; context = result.context} diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/incremental.mli b/src/proto_011_PtHangzH/lib_protocol/test/helpers/incremental.mli new file mode 100644 index 000000000000..6d32852544ba --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/incremental.mli @@ -0,0 +1,62 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +type t + +type incremental = t + +val predecessor : incremental -> Block.t + +val header : incremental -> Block_header.t + +val rev_tickets : incremental -> operation_receipt list + +val validation_state : incremental -> validation_state + +val level : incremental -> int32 + +val begin_construction : + ?priority:int -> + ?timestamp:Time.Protocol.t -> + ?seed_nonce_hash:Nonce_hash.t -> + ?policy:Block.baker_policy -> + Block.t -> + incremental tzresult Lwt.t + +val add_operation : + ?expect_apply_failure:(error list -> unit tzresult Lwt.t) -> + ?expect_failure:(error list -> unit tzresult Lwt.t) -> + incremental -> + Operation.packed -> + incremental tzresult Lwt.t + +val finalize_block : incremental -> Block.t tzresult Lwt.t + +val rpc_ctxt : incremental Environment.RPC_context.simple + +val alpha_ctxt : incremental -> Alpha_context.context diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_generator.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_generator.ml new file mode 100644 index 000000000000..878d6f4aaa82 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_generator.ml @@ -0,0 +1,351 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Liquidity_baking_machine +open QCheck.Gen +open Lib_test + +let total_xtz = 32_000_000_000_000L + +let ten_subsidies = 25_000_000L + +let rec remove_last_element = function + | [_] -> [] + | x :: rst -> x :: remove_last_element rst + | [] -> raise (Invalid_argument "remove_last_element") + +(** Try to shrink a list by removing elements from the tail of said + list. + + The elements themselves are not shrinked. *) +let shrink_list_spine_tail : 'a list QCheck.Shrink.t = + let rec shrinked_list = function + | [] -> [] + | l -> + let l = remove_last_element l in + l :: shrinked_list l + in + fun l -> QCheck.Iter.of_list (shrinked_list l) + +let gen_balances : int64 -> int -> int -> balances QCheck.Gen.t = + fun max_xtz max_tzbtc max_liquidity -> + let+ xtz = Qcheck_helpers.int64_strictly_positive_gen max_xtz + and+ tzbtc = Qcheck_helpers.int_strictly_positive_gen max_tzbtc + and+ liquidity = Qcheck_helpers.int_strictly_positive_gen max_liquidity in + {xtz; tzbtc; liquidity} + +let gen_specs : int -> int -> specs QCheck.Gen.t = + fun total_tzbtc total_liquidity -> + (* 1. We pick a random number to decide how many implicit account we + will set-up in the specs. Note that there will be one more + implicit accounts, the [Holder], that we will use to reach the + expected balances for the CPMM and the implicit accounts. *) + let* accounts_numbers = int_range 10 20 in + (* 2. To keep the generator simpler, we do not try to strictly reach + the [total_tzbtc] and [total_liquidity] value, but rather we + compute maxima for the implicit accounts balances from + them. *) + (* 2.1. We divide a fraction of the [total_xtz] that we need to + share to the implicit accounts. The rationale is to provide + a large amount to xtz to [Holder], so that we do not have to + worry about it being “rich enough.” *) + let max_xtz = Int64.(div total_xtz (of_int (50 * accounts_numbers))) in + (* 2.2. We divide [total_tzbtc] between the implicit accounts *and* + the CPMM contract. *) + let max_tzbtc = total_tzbtc / (accounts_numbers + 1) in + (* 2.2. We divide [total_liquidity] between the implicit accounts only. *) + let max_liquidity = total_liquidity / accounts_numbers in + let+ cpmm_balance = gen_balances max_xtz max_tzbtc 1 + and+ accounts_balances = + list_repeat accounts_numbers (gen_balances max_xtz max_tzbtc max_liquidity) + in + { + cpmm_min_xtz_balance = cpmm_balance.xtz; + cpmm_min_tzbtc_balance = cpmm_balance.tzbtc; + accounts_balances; + } + +let arb_specs : tzbtc -> liquidity -> specs QCheck.arbitrary = + fun total_tzbtc total_liquidity -> + QCheck.make + ~print:(fun specs -> Format.asprintf "%a" pp_specs specs) + (gen_specs total_tzbtc total_liquidity) + +type 'a optgen = 'a option QCheck.Gen.t + +let ( let*? ) (m : 'a optgen) (f : 'a -> 'b optgen) = + let* x = m in + match x with None -> return None | Some x -> f x + +(** [genopt_oneof l] tries to generate a value using the generators of + [l], one at a time. + + First, the list [l] is randomized, then each generator is + tried. The first one to return a result (not [None]) is picked. If + all generators returns [None], the generators tries again with the + whole list (at most 100 times). If no generator of [l] is able to + return a result, then [genopt_oneof l] returns [None]. *) +let genopt_oneof (l : 'a optgen list) : 'a optgen = + let* l = QCheck.Gen.shuffle_l l in + let rec aux n = function + | [] -> if n = 0 then pure None else aux (n - 1) l + | g :: l -> ( + let* x = g in + match x with None -> aux n l | Some x -> pure @@ Some x) + in + aux 100 l + +let genopt_account ?choice ?(filter = Fun.const true) env : contract_id optgen = + let l = + List.filter + filter + (Option.fold ~none:env.implicit_accounts ~some:(fun x -> [x]) choice) + in + if l = [] then return None else map Option.some (oneofl l) + +let genopt_account_with_tzbtc ?choice ?(min = 1) env state = + genopt_account + ?choice + ~filter:(fun a -> SymbolicMachine.get_tzbtc_balance a env state >= min) + env + +let genopt_account_with_xtz ?choice ?(min = 1L) env state = + genopt_account + ?choice + ~filter:(fun a -> SymbolicMachine.get_xtz_balance a state >= min) + env + +let genopt_account_with_liquidity ?choice ?(min = 1) env state = + genopt_account + ?choice + ~filter:(fun a -> SymbolicMachine.get_liquidity_balance a env state >= min) + env + +let genopt_step_tzbtc_to_xtz : + ?source:contract_id -> + ?destination:contract_id -> + contract_id env -> + SymbolicMachine.t -> + contract_id step optgen = + fun ?source ?destination env state -> + let*? source = genopt_account_with_tzbtc ?choice:source env state in + let*? destination = genopt_account ?choice:destination env in + let+ tzbtc_deposit = + Qcheck_helpers.int_strictly_positive_gen + (SymbolicMachine.get_tzbtc_balance source env state) + in + (* See note (2) *) + if + SymbolicMachine.get_tzbtc_balance env.cpmm_contract env state + < Int.max_int - tzbtc_deposit + then Some (SellTzBTC {source; destination; tzbtc_deposit}) + else None + +let genopt_step_xtz_to_tzbtc : + ?source:contract_id -> + ?destination:contract_id -> + contract_id env -> + SymbolicMachine.t -> + contract_id step optgen = + fun ?source ?destination env state -> + let*? source = genopt_account_with_xtz ?choice:source env state in + let*? destination = genopt_account ?choice:destination env in + let+ xtz_deposit = + map + Int64.of_int + (int_range + 1 + (Int64.to_int @@ SymbolicMachine.get_xtz_balance source state)) + in + (* See note (2) *) + if + SymbolicMachine.get_xtz_balance env.cpmm_contract state + < Int64.(sub max_int (add ten_subsidies xtz_deposit)) + then Some (BuyTzBTC {source; destination; xtz_deposit}) + else None + +let genopt_step_add_liquidity : + ?source:contract_id -> + ?destination:contract_id -> + contract_id env -> + SymbolicMachine.t -> + contract_id step optgen = + fun ?source ?destination env state -> + let rec find_xtz_deposit candidate max_tzbtc_deposit = + let tzbtc_deposit = + SymbolicMachine.predict_required_tzbtc_deposit candidate env state + in + if tzbtc_deposit <= max_tzbtc_deposit then candidate + else find_xtz_deposit (Int64.div candidate 2L) max_tzbtc_deposit + in + let*? source = genopt_account_with_xtz ?choice:source env state in + let*? destination = genopt_account ?choice:destination env in + let source_xtz_pool = SymbolicMachine.get_xtz_balance source state in + (* the source needs at least one xtz *) + if 1L < source_xtz_pool then + let+ candidate = + Qcheck_helpers.int64_strictly_positive_gen source_xtz_pool + in + let xtz_deposit = + find_xtz_deposit + candidate + (SymbolicMachine.get_tzbtc_balance source env state) + in + (* See note (2) *) + if + SymbolicMachine.get_xtz_balance env.cpmm_contract state + < Int64.(sub max_int (add ten_subsidies xtz_deposit)) + then Some (AddLiquidity {source; destination; xtz_deposit}) + else None + else pure None + +let genopt_step_remove_liquidity : + ?source:contract_id -> + ?destination:contract_id -> + contract_id env -> + SymbolicMachine.t -> + contract_id step optgen = + fun ?source ?destination env state -> + let*? source = genopt_account_with_liquidity ?choice:source env state in + let*? destination = genopt_account ?choice:destination env in + let lqt_available = SymbolicMachine.get_liquidity_balance source env state in + if 1 < lqt_available then + let+ lqt_burned = + int_range 1 (SymbolicMachine.get_liquidity_balance source env state) + in + Some (RemoveLiquidity {source; destination; lqt_burned}) + else return None + +let genopt_step : + ?source:contract_id -> + ?destination:contract_id -> + contract_id env -> + SymbolicMachine.t -> + contract_id step optgen = + fun ?source ?destination env state -> + genopt_oneof + [ + genopt_step_tzbtc_to_xtz env state ?source ?destination; + genopt_step_xtz_to_tzbtc env state ?source ?destination; + genopt_step_add_liquidity env state ?source ?destination; + genopt_step_remove_liquidity env state ?source ?destination; + ] + +let rec gen_steps : + ?source:contract_id -> + ?destination:contract_id -> + contract_id env -> + SymbolicMachine.t -> + int -> + contract_id step list QCheck.Gen.t = + fun ?source ?destination env state size -> + if size <= 0 then return [] + else + let* h = genopt_step ?source ?destination env state in + match h with + | None -> pure [] + | Some h -> + let state = SymbolicMachine.step h env state in + let* rst = gen_steps ?source ?destination env state (size - 1) in + pure (h :: rst) + +let gen_scenario : + tzbtc -> liquidity -> int -> (specs * contract_id step list) QCheck.Gen.t = + fun total_tzbtc total_liquidity size -> + let* specs = gen_specs total_tzbtc total_liquidity in + let (state, env) = SymbolicMachine.build specs in + let+ scenario = gen_steps env state size in + (specs, scenario) + +let pp_scenario fmt (specs, steps) = + Format.( + fprintf + fmt + "@[{@ @[ @[specs@ = %a;@]@ @[steps@ = @[[ \ + %a]@]@]@]}@]" + pp_specs + specs + (pp_print_list + ~pp_sep:(fun fmt _ -> fprintf fmt "@ ; ") + (pp_step pp_contract_id)) + steps) + +let arb_scenario : + tzbtc -> + liquidity -> + int -> + (specs * contract_id step list) QCheck.arbitrary = + fun total_tzbtc total_liquidity size -> + QCheck.make + ~print:(Format.asprintf "%a" pp_scenario) + ~shrink:(fun (specs, steps) -> + (* See note (1) *) + QCheck.Iter.pair (QCheck.Iter.return specs) (shrink_list_spine_tail steps)) + (gen_scenario total_tzbtc total_liquidity size) + +let gen_adversary_scenario : + tzbtc -> + liquidity -> + int -> + (specs * contract_id * contract_id step list) QCheck.Gen.t = + fun total_tzbtc total_liquidity size -> + let* specs = gen_specs total_tzbtc total_liquidity in + let (state, env) = SymbolicMachine.build ~subsidy:0L specs in + let* c = oneofl env.implicit_accounts in + let+ scenario = gen_steps ~source:c ~destination:c env state size in + (specs, c, scenario) + +let arb_adversary_scenario : + tzbtc -> + liquidity -> + int -> + (specs * contract_id * contract_id step list) QCheck.arbitrary = + fun total_tzbtc total_liquidity size -> + QCheck.make + ~print:(fun (specs, _, steps) -> + Format.asprintf "%a" pp_scenario (specs, steps)) + ~shrink:(fun (specs, c, steps) -> + (* see note (1) *) + QCheck.Iter.triple + (QCheck.Iter.return specs) + (QCheck.Iter.return c) + (shrink_list_spine_tail steps)) + (gen_adversary_scenario total_tzbtc total_liquidity size) + +(* -------------------------------------------------------------------------- *) + +(* Note (1) + + We shrink a valid scenario by removing steps from its tails, + because a prefix of a valid scenario remains a valid + scenario. Removing a random element of a scenario could lead to an + invalid scenario. *) + +(* Note (2) + + If we are not being careful, it is possible to provoke an overflow + in the xtzPool and tzbtcPool. We try to avoid that as much as + possible by being very careful with the steps that are likely to + add xtz to the contract. *) diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_generator.mli b/src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_generator.mli new file mode 100644 index 000000000000..c0f1a9811438 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_generator.mli @@ -0,0 +1,77 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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 a set of abstractions to reason about the + so-called “liquidity baking” feature[1]. + + [1]: https://gitlab.com/tezos/tzip/-/blob/master/drafts/current/draft-liquidity_baking.md + + We remind that this feature is built upon three smart contracts: + (1) a CPMM contract initially based on Dexter 2, and (2) two + tokens contracts. + + Our purpose for Liquidity Baking is to easily express and test + invariants regarding the execution of these contracts. To that + end, we have introduced a set of dedicated types to describe + arbitrary contexts in terms of account balances (see + [Liquidity_baking_machine.specs]), along with [build] functions + that turn a description of a context into concrete states. + + In this module, we provide QCheck generators which allow to + construct arbitrary specifications for states, and so-called + scenarios ({i i.e.}, sequences of entrypoint calls). *) + +open Liquidity_baking_machine + +(** [arb_specs max_tzbtc max_liquidity] constructs arbitrary Liquidity + Baking [specs] for an initial state, where at most [max_tzbtc] and + [max_liquidity] are shared among an arbitrary number of implicit + accounts. *) +val arb_specs : tzbtc -> liquidity -> specs QCheck.arbitrary + +(** [arb_scenario max_tzbtc max_liquidity size] constructs arbitrary + Liquidity Baking [specs] with a semantics similar to [arb_specs], along with sequences of {b valid} + scenarios ({i i.e.}, sequences of entrypoint calls) of length + [size]. By valid, we mean that running the scenario using a + Liquidity baking machine initialized with the [specs] should + succeed. *) +val arb_scenario : + tzbtc -> liquidity -> int -> (specs * contract_id step list) QCheck.arbitrary + +(** [arb_adversary_scenario max_tzbtc max_liquidity size] constructs + arbitrary scenarios that can be used to challenge the “no global + gain” property of Liquidity Baking. + + The key idea of this property is the following: a given contract + cannot profit from Liquidity Baking if they are the only one to + interact with the CPMM (in the absence of subsidies). The scenario + generated by [arb_adversary_scenario] only consists in [step] + performed by one contract. This contract is identified by the + [contract_id] returned by this function. *) +val arb_adversary_scenario : + tzbtc -> + liquidity -> + int -> + (specs * contract_id * contract_id step list) QCheck.arbitrary diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_machine.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_machine.ml new file mode 100644 index 000000000000..174b85d05174 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_machine.ml @@ -0,0 +1,1324 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Test_tez + +(** To implement the interface of this module, as described and + documented in the related MLI file, we rely on the OCaml module + system. More precisely, most of the implementation of the two + public machines ([ValidationMachine] and [SymbolicMachine]) is + derived by means of functors. + + The machines provide two key functions which can be used in a + test suite: + + - [M.build specs] which allows to construct an initial state of + a machine [M] that satisfies the properties described by + [specs] (along with the so-called “environment” of the + machine) + - [M.step s env state] (resp. [M.run]) which allows to execute a + so-called scenario [step] (resp. a sequence of [step]s, {i + i.e.}, a complete scenario) by the machine [M] from the state + [state]. + + The module is organized as follows: + + 1. We introduce the necessary abstractions we later use to + specify the properties the initial state of a given machine + needs to satisfy (most notably the [specs] type). + 2. Then, we introduce the [step] type, which describes the + various actions we can make a machine perform as part of a + more complete scenario. + 3. We introduce the [MACHINE] module type which lists the + necessary types and functions we need to derive a machine + capable of executing scenarios, and the [Machine.Make] + functor that we can use to derive such a machine + automatically. + 4. We introduce the [MACHINE_WITH_INIT] module type which is a + superset of [MACHINE], extended with an [init] function + (analogous to {! Context.init}) to create an initial, mostly + blank state, and the [MachineBuilder.Make] functor that we + can use to derive a machine with a [build] function. + 5. We construct the [ConcreteMachine], that allows to + asynchronously execute scenarios against the Tezos + blockchain. + 6. We implement the [AbstractMachine.Make] functor, which we + can use to construct machines that can simulate the + execution scenarios completely off-chains, by reimplementing + the LB features logic in pure OCaml. + 7. We use [AbstractMachine.Make] to create the [SymbolicMachine]. + 8. We use the [AbstractMachine.Make] functor in conjuction with + the [ConcreteMachine] to introduce the [ValidationMachine]. + + _ + / \ A warning for developers willing to modify this module: + / | \ dealing with the subsidy of the Liquidity Baking (LB) + / · \ feature is probably the main source of complexity and + /_______\ fragility of this module. + + At several places (marked with a /!\ note), we need to predict the + xtz pool of the CPMM contract, in order to compute the amount of + tzBTC token it will provide or request. To make this prediction, + we need to determine how many blocks have been/will be baked. This + means that each time we modify the code of the machine functors, + we will probably have to modify the code marked with /!\ too. + + To reduce the potential to get things wrong, we have introduced + constants to prevent the use of “magic numbers” (numbers whose + meaning cannot be guessed only by looking at the formula). The + value of these constants is not statically checked, so pay extra + attention before modifying them. + + Ideally, we could probably compute these magic numbers using a + dedicated machine, whose purpose would be to count the number of + call to the [bake] function. For the sake of simplicity, we do not + do it currently. *) + +(** The number of blocks baked in order to execute the {! + AddLiquidity} step. *) +let blocks_per_add_liquidity_step = 2L + +(** The number of blocks baked by the [init] function. *) +let blocks_during_init = 3L + +(** The number of blocks baked by the [mint_tzbtc] functions *) +let blocks_per_mint_tzbtc = 1L + +(** A timestamp “far in the future” which should not be exceeded when + running tests. *) +let far_future = Alpha_context.Script_timestamp.of_zint (Z.of_int 42_000) +(* Hypothesis: the tests start at timestamp 0, and 42000 is + “big enough.” *) + +(* --------------------------------------------------------------------------- *) + +(** {1 Miscellaneous Helpers} *) + +let is_implicit_exn account = + match Contract.is_implicit account with Some k -> k | _ -> assert false + +module List_helpers = struct + let rec zip l r = + match (l, r) with + | (xl :: rstl, xr :: rstr) -> (xl, xr) :: zip rstl rstr + | _ -> [] + + let nth_exn l n = + match List.nth l n with + | Some x -> x + | _ -> raise (Invalid_argument "nth_exn") + + let assoc_exn c l = + match List.assoc ~equal:( = ) c l with + | Some x -> x + | _ -> raise (Invalid_argument "assoc_exn") +end + +(* --------------------------------------------------------------------------- *) + +(** {1 Characterizing Initial Machines States} *) + +(** In order to run so-called scenarios against our machines, we first + need to characterize their initial state. *) + +type xtz = int64 + +type tzbtc = int + +type liquidity = int + +type balances = {xtz : xtz; tzbtc : tzbtc; liquidity : liquidity} + +let pp_balances fmt b = + Format.fprintf + fmt + "@[{xtz = %a; tzbtc = %d; liquidity = %d}@]" + Tez.pp + (Tez.of_mutez_exn b.xtz) + b.tzbtc + b.liquidity + +let xtz {xtz; _} = xtz + +type specs = { + cpmm_min_xtz_balance : xtz; + cpmm_min_tzbtc_balance : tzbtc; + accounts_balances : balances list; +} + +let pp_specs fmt specs = + Format.( + fprintf + fmt + "@[{@ @[cpmm = {min_xtz = %a; min_tzbtc = %d}@ @[accounts = \ + [@ %a@ ]@]@]@ }@]" + Tez.pp + (Tez.of_mutez_exn specs.cpmm_min_xtz_balance) + specs.cpmm_min_tzbtc_balance + (pp_print_list ~pp_sep:pp_print_space pp_balances) + specs.accounts_balances) + +(* --------------------------------------------------------------------------- *) + +(** {1 Scenario [step] }*) + +type 'a step = + | SellTzBTC of {source : 'a; destination : 'a; tzbtc_deposit : tzbtc} + | BuyTzBTC of {source : 'a; destination : 'a; xtz_deposit : xtz} + | AddLiquidity of {source : 'a; destination : 'a; xtz_deposit : xtz} + | RemoveLiquidity of {source : 'a; destination : 'a; lqt_burned : liquidity} + +let pp_step pp_contract fmt = function + | SellTzBTC p -> + Format.( + fprintf + fmt + "@[SellTzBTC(%a, %dtz₿, %a)@]" + pp_contract + p.source + p.tzbtc_deposit + pp_contract + p.destination) + | BuyTzBTC p -> + Format.( + fprintf + fmt + "@[BuyTzBTC(%a, %aꜩ, %a)@]" + pp_contract + p.source + Tez.pp + (Tez.of_mutez_exn p.xtz_deposit) + pp_contract + p.destination) + | AddLiquidity p -> + Format.( + fprintf + fmt + "@[AddLiquidity(%a, %aꜩ, %a)@]" + pp_contract + p.source + Tez.pp + (Tez.of_mutez_exn p.xtz_deposit) + pp_contract + p.destination) + | RemoveLiquidity p -> + Format.( + fprintf + fmt + "@[RemoveLiquidity(%a, %d lqt, %a)@]" + pp_contract + p.source + p.lqt_burned + pp_contract + p.destination) + +type contract_id = + | Cpmm + | Holder + | TzBTC + | TzBTCAdmin + | Liquidity + | LiquidityAdmin + | ImplicitAccount of int + +let contract_id_to_string = function + | Holder -> "holder" + | Cpmm -> "cpmm" + | TzBTC -> "tzbtc" + | TzBTCAdmin -> "tzbtc_admin" + | Liquidity -> "lqt" + | LiquidityAdmin -> "lqt_admin" + | ImplicitAccount i -> Format.sprintf "#%d" i + +let pp_contract_id fmt c = Format.(fprintf fmt "[%s]" (contract_id_to_string c)) + +(* --------------------------------------------------------------------------- *) + +(** {1 Machines} *) + +(** {2 Machine Environment} *) + +type 'a env = { + cpmm_contract : 'a; + tzbtc_contract : 'a; + tzbtc_admin : 'a; + liquidity_contract : 'a; + liquidity_admin : 'a; + implicit_accounts : 'a list; + holder : 'a; + subsidy : xtz; +} + +let refine_contract env = function + | Cpmm -> env.cpmm_contract + | TzBTC -> env.tzbtc_contract + | TzBTCAdmin -> env.tzbtc_admin + | Liquidity -> env.liquidity_contract + | LiquidityAdmin -> env.liquidity_admin + | Holder -> env.holder + | ImplicitAccount i -> List_helpers.nth_exn env.implicit_accounts i + +let refine_step env step = + match step with + | SellTzBTC p -> + SellTzBTC + { + p with + source = refine_contract env p.source; + destination = refine_contract env p.destination; + } + | BuyTzBTC p -> + BuyTzBTC + { + p with + source = refine_contract env p.source; + destination = refine_contract env p.destination; + } + | AddLiquidity p -> + AddLiquidity + { + p with + source = refine_contract env p.source; + destination = refine_contract env p.destination; + } + | RemoveLiquidity p -> + RemoveLiquidity + { + p with + source = refine_contract env p.source; + destination = refine_contract env p.destination; + } + +(** {2 Machine Module Type} *) + +module type MACHINE = sig + type 'a m + + type contract + + type t + + type operation + + val pp_contract : Format.formatter -> contract -> unit + + val ( >>= ) : 'a m -> ('a -> 'b m) -> 'b m + + val fold_m : ('a -> 'b -> 'a m) -> 'a -> 'b list -> 'a m + + val pure : 'a -> 'a m + + val get_balances : contract -> contract env -> t -> balances m + + val get_xtz_balance : contract -> t -> xtz m + + val get_tzbtc_balance : contract -> contract env -> t -> tzbtc m + + val get_liquidity_balance : contract -> contract env -> t -> liquidity m + + val get_cpmm_total_liquidity : contract env -> t -> liquidity m + + val bake : + invariant:(contract env -> t -> bool m) -> + baker:contract -> + operation list -> + contract env -> + t -> + t m + + val transaction : src:contract -> contract -> xtz -> t -> operation m + + val token_to_xtz : + src:contract -> contract -> tzbtc -> contract env -> t -> operation m + + val xtz_to_token : + src:contract -> contract -> xtz -> contract env -> t -> operation m + + (* [mint_or_burn_tzbtc contract amount env state] will construct an + operation to credit or remove [amount] tzbtc tokens to [contract] *) + val mint_or_burn_tzbtc : + contract -> liquidity -> contract env -> t -> operation m + + (** [approve_tzbtc contract amount env state] will construct an + operation to authorize the CPMM contract to spend [amount] tzbtc + on behalf of [contract] *) + val approve_tzbtc : contract -> tzbtc -> contract env -> t -> operation m + + val add_liquidity : + src:contract -> contract -> xtz -> tzbtc -> contract env -> t -> operation m + + val remove_liquidity : + src:contract -> contract -> liquidity -> contract env -> t -> operation m + + val reveal : Account.t -> t -> operation m +end + +(** {2 Tezos Constants} *) + +let default_subsidy = + let open Tezos_protocol_011_PtHangzH_parameters in + Tez.to_mutez @@ Default_parameters.constants_test.liquidity_baking_subsidy + +let security_deposit = 640_000_000L + +(* When calling [Context.init] with a list of initial balances, the + sum of these balances should be equal to this constant. *) +let total_xtz = 32_000_000_000_000L + +let tzbtc_admin_account : Account.t = + { + pkh = + Signature.Public_key_hash.of_b58check_exn + "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"; + pk = + Signature.Public_key.of_b58check_exn + "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav"; + sk = + Signature.Secret_key.of_b58check_exn + "edsk3gUfUPyBSfrS9CCgmCiQsTCHGkviBDusMxDJstFtojtc1zcpsh"; + } + +let cpmm_initial_balance = {xtz = 100L; tzbtc = 1; liquidity = 0} + +let cpmm_initial_liquidity_supply = 100 + +(** {2 Machine Functor} *) + +module Machine = struct + module Make (S : MACHINE) = struct + open S + + let mint_tzbtc destination ~invariant amount env state = + mint_or_burn_tzbtc destination amount env state >>= fun op -> + bake ~invariant ~baker:env.holder [op] env state + + let add_liquidity ~invariant src dst xtz_deposit tzbtc_deposit env state = + approve_tzbtc src tzbtc_deposit env state >>= fun lqt_op -> + bake ~invariant ~baker:env.holder [lqt_op] env state >>= fun state -> + add_liquidity ~src dst xtz_deposit tzbtc_deposit env state + >>= fun cpmm_op -> bake ~invariant ~baker:env.holder [cpmm_op] env state + + let remove_liquidity ~invariant src dst lqt_burned env state = + remove_liquidity ~src dst lqt_burned env state >>= fun cpmm_op -> + bake ~invariant ~baker:env.holder [cpmm_op] env state + + let sell_tzbtc ~invariant src dst tzbtc_deposit env state = + approve_tzbtc src tzbtc_deposit env state >>= fun tzbtc_op -> + bake ~invariant ~baker:env.holder [tzbtc_op] env state >>= fun state -> + token_to_xtz ~src dst tzbtc_deposit env state >>= fun cpmm_op -> + bake ~invariant ~baker:env.holder [cpmm_op] env state + + let buy_tzbtc ~invariant src dst xtz_deposit env state = + xtz_to_token ~src dst xtz_deposit env state >>= fun cpmm_op -> + bake ~invariant ~baker:env.holder [cpmm_op] env state + + let check_state_satisfies_specs (env : S.contract env) (state : S.t) + (specs : specs) = + let implicit_accounts_targets = + List_helpers.zip env.implicit_accounts specs.accounts_balances + in + fold_m + (fun _ acc -> + let expected = List_helpers.assoc_exn acc implicit_accounts_targets in + get_balances acc env state >>= fun amount -> + assert (expected = amount) ; + pure ()) + () + env.implicit_accounts + >>= fun _ -> + get_tzbtc_balance env.cpmm_contract env state + >>= fun cpmm_tzbtc_balance -> + assert (specs.cpmm_min_tzbtc_balance <= cpmm_tzbtc_balance) ; + get_xtz_balance env.cpmm_contract state >>= fun current_cpmm_xtz -> + assert ( + Int64.(to_int specs.cpmm_min_xtz_balance <= to_int @@ current_cpmm_xtz)) ; + pure () + + (** [predict_required_tzbtc_deposit xtz_deposit env state] + predicts the tzbtc deposit which will be required by the CPMM + contract for a deposit of [xtz_deposit]. + + This function is used by the machines to make the according + call to the [approve] entrypoint of the TzBTC contract. *) + let predict_required_tzbtc_deposit xtz_deposit env state = + get_xtz_balance env.cpmm_contract state >>= fun xtzPool -> + (* /!\ We need to take into accounts the number of blocks baked + to actually call the [add_liquidity] entry point of the + CPMM. *) + let xtzPool = + Tez.of_mutez_exn + Int64.(add xtzPool (mul blocks_per_add_liquidity_step env.subsidy)) + in + get_tzbtc_balance env.cpmm_contract env state >>= fun tokenPool -> + let tokenPool = Z.of_int tokenPool in + get_cpmm_total_liquidity env state >>= fun lqtTotal -> + let lqtTotal = Z.of_int lqtTotal in + let amount = Tez.of_mutez_exn xtz_deposit in + let (_, tokens_deposited) = + Cpmm_logic.Simulate_raw.addLiquidity + ~tokenPool + ~xtzPool + ~lqtTotal + ~amount + in + pure (Z.to_int tokens_deposited) + + let step ?(invariant = fun _ _ -> pure true) s env state = + match s with + | SellTzBTC {source; destination; tzbtc_deposit} -> + sell_tzbtc ~invariant source destination tzbtc_deposit env state + | BuyTzBTC {source; destination; xtz_deposit} -> + buy_tzbtc ~invariant source destination xtz_deposit env state + | AddLiquidity {source; destination; xtz_deposit} -> + predict_required_tzbtc_deposit xtz_deposit env state + >>= fun tzbtc_deposit -> + add_liquidity + ~invariant + source + destination + xtz_deposit + tzbtc_deposit + env + state + | RemoveLiquidity {source; destination; lqt_burned} -> + remove_liquidity ~invariant source destination lqt_burned env state + + let run ?(invariant = fun _ _ -> pure true) scenario env state = + fold_m + (fun state s -> step ~invariant (refine_step env s) env state) + state + scenario + end +end + +let initial_xtz_repartition accounts_balances = + let distributed_xtz = List.fold_left Int64.add 0L accounts_balances in + let bootstrap1_xtz = Int64.sub total_xtz distributed_xtz in + let initial_balances = bootstrap1_xtz :: accounts_balances in + let n = List.length initial_balances in + (n, initial_balances) + +(* --------------------------------------------------------------------------- *) + +(** {1 Machines with a [build] Function} *) + +module type MACHINE_WITH_INIT = sig + include MACHINE + + (** [init balances] will create an “initial” state wherein the + [balances] have been distributed to [n] implicit contracts ([n] + being the size of the [balances] list). This function also + creates a [holder] implicit account which has the rest of the + xtz liquidity (the test framework forces the sum of xtz balances + to be equal to [total_xtz]). [init] also accepts an optional + argument [subsidy] to modify the default value of the subsidy + minted by the protocol in favor of the CPMM. *) + val init : + invariant:(contract env -> t -> bool m) -> + ?subsidy:xtz -> + xtz list -> + (t * contract env) m +end + +(** [initial_xtz_pool] balances predicts the value of the CPMM’s xtz + pool just before we start using the [add_liquidity] entrypoint to + provide to each implicit accounts the necessary liquidity + tokens. *) +let initial_xtz_pool balances subsidy = + (* /!\ In addition to the initial CPMM balances, we need to take + into account the subsidies of each block baked before this + point, which currently consist in: + + - One call to the [init] function + - One call to the [mint_tzbtc] function per implicit + accounts + + If the [build] function changes, this functions needs to be + updated accordingly. *) + Int64.( + add + cpmm_initial_balance.xtz + (mul + (add + blocks_during_init + (mul blocks_per_mint_tzbtc (of_int @@ List.length balances))) + subsidy)) + +(** [predict_initial_balances xtz_pool tzbtc_pool lqt_total balances] + evaluates the extra xtz and tzbtc tokens to add to each balance of + the list [balances] so that the related implicit accounts can call + the [add_liquidity] entrypoint in order to have the required + liquidity token. + + For instance, for a balance [b] such that [b.liquidity = 10], we + compute [xtz_etra] and [tzbtc_extra] so that the implicit account + will be able to buy [10] liquidity tokens, and replace [b] with + [{b with xtz = b.xtz + xtz_extra; tzbtc = b.tzbtc + tzbtc_extra}] + in the returned list. + + The implementation of this function is made more complex than it + should due to the mechanism of subsidy of LB. In particular, it is + depends on the number of block baked to buy liquidities. *) +let predict_initial_balances balances subsidy = + let open Z in + let subsidy_z = of_int64 subsidy in + (* Due to the roundness of [Z.( / )], it is not straightforward to + find the inverse of the equation used to compute the number of + liquidity tokens bought with the [add_liquidity] entrypoint. To + find the suitable number of xtz to propose in order to buy + [liquidity_target], we naively search for the correct + solution. We compute a [xtz_candidate] by ignoring the roundness + of [Z.( / )], then increment it until it works. *) + let find_xtz_extra xtz_pool lqt_total liquidity_target = + let rec aux xtz_candidate = + let liquidity_z = xtz_candidate * lqt_total / xtz_pool in + if liquidity_z = liquidity_target then xtz_candidate + else aux (xtz_candidate + Z.one) + in + let xtz_extra_candidate = liquidity_target * xtz_pool / lqt_total in + aux xtz_extra_candidate + in + let rec predict_initial_balances xtz_pool tzbtc_pool lqt_total = function + | {xtz; tzbtc; liquidity} :: rst -> + (* balance inputs *) + (* /!\ We compute two blocks per [add_liquidity] entrypoint, + hence the two subsidies *) + let xtz_pool = + xtz_pool + (Z.of_int64 blocks_per_add_liquidity_step * subsidy_z) + in + let xtz_z = of_int64 xtz in + let tzbtc_z = of_int tzbtc in + let liquidity_z = of_int liquidity in + (* compute extra for being able to buy liquidity tokens *) + let xtz_extra = find_xtz_extra xtz_pool lqt_total liquidity_z in + let tzbtc_extra = cdiv (xtz_extra * tzbtc_pool) xtz_pool in + (* compute new balances *) + let xtz = to_int64 (xtz_z + xtz_extra) in + let tzbtc = to_int (tzbtc_z + tzbtc_extra) in + let liquidity = to_int liquidity_z in + (* new pools *) + let xtz_pool' = xtz_pool + xtz_extra in + let tzbtc_pool' = tzbtc_pool + tzbtc_extra in + let lqt_total' = lqt_total + liquidity_z in + (* recursion time *) + {xtz; tzbtc; liquidity} + :: predict_initial_balances xtz_pool' tzbtc_pool' lqt_total' rst + | [] -> [] + in + predict_initial_balances + (of_int64 @@ initial_xtz_pool balances subsidy) + (of_int cpmm_initial_balance.tzbtc) + (of_int cpmm_initial_liquidity_supply) + balances + +module MachineBuilder = struct + module Make (S : MACHINE_WITH_INIT) = struct + open S + include Machine.Make (S) + + let build : + ?invariant:(S.contract env -> S.t -> bool m) -> + ?subsidy:xtz -> + specs -> + (S.t * S.contract env) m = + fun ?(invariant = fun _ _ -> pure true) + ?(subsidy = default_subsidy) + ({cpmm_min_xtz_balance; accounts_balances; cpmm_min_tzbtc_balance} as + specs) -> + let accounts_balances_with_extra = + predict_initial_balances accounts_balances subsidy + in + let xtz_balances_with_extra = List.map xtz accounts_balances_with_extra in + (* 1. Create an initial context *) + init ~invariant ~subsidy xtz_balances_with_extra >>= fun (state, env) -> + invariant env state >>= fun cond -> + assert cond ; + (* 2. Provide the initial tzBTC liquidities to implicit accounts *) + let accounts = + List_helpers.zip + env.implicit_accounts + (List_helpers.zip accounts_balances accounts_balances_with_extra) + in + fold_m + (fun state (address, (_, balances)) -> + mint_tzbtc ~invariant address balances.tzbtc env state) + state + accounts + >>= fun state -> + (* 3. Make implicit accounts buy liquidities *) + fold_m + (fun state (address, (target_balances, balances_with_extra)) -> + let xtz = Int64.sub balances_with_extra.xtz target_balances.xtz in + let tzbtc = balances_with_extra.tzbtc - target_balances.tzbtc in + add_liquidity ~invariant address address xtz tzbtc env state) + state + accounts + >>= fun state -> + (* 4. Provide any missing tzbtc tokens to [cpmm_contract], if necessary *) + get_tzbtc_balance env.cpmm_contract env state + >>= fun current_cpmm_tzbtc_balance -> + let tzbtc_missing = cpmm_min_tzbtc_balance - current_cpmm_tzbtc_balance in + (if 0 < tzbtc_missing then + (* 4.1. Provide the tokens to the [bootstrap1] account, as a + temporary holder for CPMM missing tzBTC balance *) + mint_tzbtc ~invariant env.holder tzbtc_missing env state >>= fun state -> + (* 4.1. Make [bootstrap1] buy some xtz against the appropriate + amount of tzbtc *) + sell_tzbtc ~invariant env.holder env.holder tzbtc_missing env state + else pure state) + >>= fun state -> + (* 5. Provide any missing xtz tokens to [cpmm_contract], if necessary *) + get_xtz_balance env.cpmm_contract state + >>= fun current_cpmm_xtz_balance -> + let xtz_missing = + Int64.sub cpmm_min_xtz_balance current_cpmm_xtz_balance + in + (if 0L < xtz_missing then + transaction ~src:env.holder env.cpmm_contract xtz_missing state + >>= fun op -> bake ~invariant ~baker:env.holder [op] env state + else pure state) + >>= fun state -> + check_state_satisfies_specs env state specs >>= fun _ -> pure (state, env) + end +end + +(* --------------------------------------------------------------------------- *) + +module ConcreteBaseMachine : + MACHINE_WITH_INIT + with type 'a m = 'a tzresult Lwt.t + and type contract = Contract.t + and type t = Block.t = struct + type 'a m = 'a tzresult Lwt.t + + type contract = Contract.t + + type operation = packed_operation + + type t = Block.t + + let pp_contract = Contract.pp + + let ( >>= ) = ( >>=? ) + + let fold_m = Environment.List.fold_left_es + + let pure = Error_monad.return + + let get_xtz_balance contract blk = + Context.Contract.balance (B blk) contract >>= fun x -> + pure @@ Tez.to_mutez x + + let get_tzbtc_balance contract env blk = + Lqt_fa12_repr.Storage.getBalance_opt + (B blk) + ~contract:env.tzbtc_contract + (contract, "default") + >>=? fun mamount -> + pure (Option.value (Option.map Z.to_int mamount) ~default:0) + + let get_liquidity_balance contract env blk = + Lqt_fa12_repr.Storage.getBalance_opt + (B blk) + ~contract:env.liquidity_contract + (contract, "default") + >>=? fun mamount -> + pure (Option.value (Option.map Z.to_int mamount) ~default:0) + + let get_cpmm_total_liquidity env blk = + Cpmm_repr.Storage.get (B blk) ~contract:env.cpmm_contract + >>=? fun cpmm_storage -> pure @@ Z.to_int cpmm_storage.lqtTotal + + let get_balances contract env blk = + get_xtz_balance contract blk >>= fun xtz -> + get_tzbtc_balance contract env blk >>= fun tzbtc -> + get_liquidity_balance contract env blk >>= fun liquidity -> + pure {xtz; tzbtc; liquidity} + + let bake ~invariant ~baker ops env blk = + Incremental.begin_construction + ~policy:(Block.By_account (is_implicit_exn baker)) + blk + >>= fun incr -> + fold_m Incremental.add_operation incr ops >>= fun incr -> + Incremental.finalize_block incr >>= fun blk -> + invariant env blk >>= fun cond -> + assert cond ; + return blk + + let reveal (account : Account.t) blk = Op.revelation (B blk) account.pk + + let transaction ~src dst amount blk = + Op.transaction (B blk) src dst (Tez.of_mutez_exn amount) + + let token_to_xtz ~src dst tzbtc_deposit env blk = + Cpmm_repr.transaction + (B blk) + ~src + ~contract:env.cpmm_contract + (Cpmm_repr.Parameter.TokenToXtz + { + to_ = dst; + minXtzBought = Test_tez.Tez.zero; + tokensSold = Z.of_int tzbtc_deposit; + deadline = far_future; + }) + + let xtz_to_token ~src dst amount env blk = + Cpmm_repr.transaction + (B blk) + ~src + ~contract:env.cpmm_contract + (Cpmm_repr.Parameter.XtzToToken + {to_ = dst; minTokensBought = Z.zero; deadline = far_future}) + ~amount:(Tez.of_mutez_exn amount) + + let approve_tzbtc src tzbtc env blk = + let maxTokensDeposited = Z.of_int tzbtc in + Lqt_fa12_repr.transaction + (B blk) + ~src + ~contract:env.tzbtc_contract + (Lqt_fa12_repr.Parameter.Approve + {spender = env.cpmm_contract; value = maxTokensDeposited}) + + let mint_or_burn_tzbtc target amount env blk = + let quantity = Z.of_int amount in + let ctxt = Context.B blk in + Lqt_fa12_repr.transaction + ctxt + ~src:env.tzbtc_admin + ~contract:env.tzbtc_contract + (Lqt_fa12_repr.Parameter.mintOrBurn {target; quantity}) + + let add_liquidity ~src dst xtz_deposit tzbtc_deposit env blk = + let amount = Tez.of_mutez_exn xtz_deposit in + let maxTokensDeposited = Z.of_int tzbtc_deposit in + Cpmm_repr.transaction + (B blk) + ~src + ~contract:env.cpmm_contract + ~amount + (Cpmm_repr.Parameter.AddLiquidity + { + owner = dst; + maxTokensDeposited; + minLqtMinted = Z.zero; + deadline = far_future; + }) + + let remove_liquidity ~src dst lqt_burned env blk = + let lqtBurned = Z.of_int lqt_burned in + Cpmm_repr.transaction + (B blk) + ~src + ~contract:env.cpmm_contract + (Cpmm_repr.Parameter.RemoveLiquidity + { + to_ = dst; + lqtBurned; + minXtzWithdrawn = Tez.zero; + minTokensWithdrawn = Z.zero; + deadline = far_future; + }) + + let reveal_tzbtc_admin ~invariant env state = + Account.add_account tzbtc_admin_account ; + transaction ~src:env.holder env.tzbtc_admin 1L state >>= fun op1 -> + bake ~invariant ~baker:env.holder [op1] env state >>= fun state -> + reveal tzbtc_admin_account state >>= fun op2 -> + bake ~invariant ~baker:env.holder [op2] env state + + let init ~invariant ?subsidy accounts_balances = + let liquidity_baking_subsidy = Option.map Tez.of_mutez_exn subsidy in + let (n, initial_balances) = initial_xtz_repartition accounts_balances in + Context.init + n + ~initial_balances + ~cost_per_byte:Tez.zero + ?liquidity_baking_subsidy + >>= function + | (blk, holder :: accounts) -> + let ctxt = Context.B blk in + Context.get_liquidity_baking_cpmm_address ctxt >>= fun cpmm_contract -> + Context.Contract.storage ctxt cpmm_contract >>= fun storage -> + let storage = Cpmm_repr.Storage.of_expr_exn (Micheline.root storage) in + let tzbtc_contract = storage.tokenAddress in + let liquidity_contract = storage.lqtAddress in + Context.Contract.storage ctxt tzbtc_contract >>= fun storage -> + let storage = + Lqt_fa12_repr.Storage.of_expr_exn (Micheline.root storage) + in + let tzbtc_admin = storage.admin in + Context.Contract.storage ctxt liquidity_contract >>= fun storage -> + let storage = + Lqt_fa12_repr.Storage.of_expr_exn (Micheline.root storage) + in + let liquidity_admin = storage.admin in + Context.get_liquidity_baking_subsidy (B blk) >>=? fun subsidy -> + let env = + { + cpmm_contract; + tzbtc_contract; + tzbtc_admin; + liquidity_contract; + liquidity_admin; + implicit_accounts = accounts; + holder; + subsidy = Tez.to_mutez subsidy; + } + in + reveal_tzbtc_admin ~invariant:(fun _ _ -> pure true) env blk + >>= fun blk -> + mint_or_burn_tzbtc env.cpmm_contract cpmm_initial_balance.tzbtc env blk + >>= fun op -> + bake ~invariant:(fun _ _ -> pure true) ~baker:env.holder [op] env blk + >>= fun blk -> + (* We did not check the invariant before, because the CPMM + contract was in an inconsistent state. More precisely, it + was supposed to hold tzbtc tokens, while in practice it was + not. This was solved by the last call to [bake]. *) + invariant env blk >>= fun cond -> + assert cond ; + pure (blk, env) + | _ -> assert false +end + +module ConcreteMachine = struct + include ConcreteBaseMachine + include Machine.Make (ConcreteBaseMachine) + include MachineBuilder.Make (ConcreteBaseMachine) +end + +(* --------------------------------------------------------------------------- *) + +(** {1 Abstract Machines} *) + +type 'a state = { + cpmm_total_liquidity : liquidity; + accounts_balances : ('a * balances) list; +} + +let refine_state env state = + { + cpmm_total_liquidity = state.cpmm_total_liquidity; + accounts_balances = + List.map + (fun (c, b) -> (refine_contract env c, b)) + state.accounts_balances; + } + +let update_balances account f state = + match List.assoc ~equal:( = ) account state.accounts_balances with + | Some b -> + { + state with + accounts_balances = + (account, f b) + :: List.remove_assoc ~equal:( = ) account state.accounts_balances; + } + | _ -> assert false + +let update_xtz_balance account f = + update_balances account (fun b -> {b with xtz = f b.xtz}) + +let update_tzbtc_balance account f = + update_balances account (fun b -> {b with tzbtc = f b.tzbtc}) + +let update_liquidity_balance account f = + update_balances account (fun b -> {b with liquidity = f b.liquidity}) + +let transfer_xtz_balance src dest d st = + update_xtz_balance src (fun b -> Int64.sub b d) st + |> update_xtz_balance dest (fun b -> Int64.add b d) + +let transfer_tzbtc_balance src dest d st = + update_tzbtc_balance src (fun b -> b - d) st + |> update_tzbtc_balance dest (fun b -> d + b) + +module AbstractMachine = struct + module type C = sig + type t + + val pp : Format.formatter -> t -> unit + end + + module Make (C : C) : + MACHINE with type 'a m = 'a and type contract = C.t and type t = C.t state = + struct + type 'a m = 'a + + type contract = C.t + + type t = C.t state + + type operation = t -> t + + let pp_contract = C.pp + + let ( >>= ) x f = f x + + let pure = Fun.id + + let fold_m = List.fold_left + + let get_balances account state = + match List.assoc ~equal:( = ) account state.accounts_balances with + | Some x -> x + | _ -> assert false + + let get_xtz_balance account state = (get_balances account state).xtz + + let get_tzbtc_balance account _env state = + (get_balances account state).tzbtc + + let get_liquidity_balance account _env state = + (get_balances account state).liquidity + + let get_balances account _env state = get_balances account state + + let get_cpmm_total_liquidity _env state = state.cpmm_total_liquidity + + let reveal _pk _state state = state + + let transaction ~src dst amount _ state = + transfer_xtz_balance src dst amount state + + let xtz_bought tzbtc env state = + let xtzPool = + Tez.of_mutez_exn @@ get_xtz_balance env.cpmm_contract state + in + let tokenPool = + Z.of_int @@ get_tzbtc_balance env.cpmm_contract env state + in + let tokensSold = Z.of_int tzbtc in + let (xtz_bought, xtz_net_bought) = + Cpmm_logic.Simulate_raw.tokenToXtz ~xtzPool ~tokenPool ~tokensSold + in + (Z.to_int64 xtz_net_bought, Tez.to_mutez xtz_bought) + + let token_to_xtz ~src dst amount env _ state = + let (xtz_bought, xtz_net_bought) = xtz_bought amount env state in + state + |> transfer_tzbtc_balance src env.cpmm_contract amount + |> update_xtz_balance env.cpmm_contract (fun b -> Int64.sub b xtz_bought) + |> update_xtz_balance dst (Int64.add xtz_net_bought) + + let tzbtc_bought env state amount = + let xtzPool = + Tez.of_mutez_exn @@ get_xtz_balance env.cpmm_contract state + in + let tokenPool = + Z.of_int @@ get_tzbtc_balance env.cpmm_contract env state + in + let amount = Tez.of_mutez_exn amount in + let (tzbtc_bought, xtz_earnt) = + Cpmm_logic.Simulate_raw.xtzToToken ~xtzPool ~tokenPool ~amount + in + (Z.to_int tzbtc_bought, Z.to_int64 xtz_earnt) + + let xtz_to_token ~src dst amount env _ state = + let (tzbtc_bought, xtz_earnt) = tzbtc_bought env state amount in + update_xtz_balance src (fun b -> Int64.sub b amount) state + |> update_xtz_balance env.cpmm_contract (Int64.add xtz_earnt) + |> transfer_tzbtc_balance env.cpmm_contract dst tzbtc_bought + + let mint_or_burn_tzbtc target amount _ _ = + update_tzbtc_balance target (( + ) amount) + + let approve_tzbtc _contract _amount _env _state = Fun.id + + let add_liquidity ~src dst xtz_deposit _tzbtc_deposit env _ state = + let xtzPool = + Tez.of_mutez_exn (get_xtz_balance env.cpmm_contract state) + in + let tokenPool = + Z.of_int (get_tzbtc_balance env.cpmm_contract env state) + in + let lqtTotal = Z.of_int state.cpmm_total_liquidity in + let amount = Tez.of_mutez_exn xtz_deposit in + let (lqt_minted, tokens_deposited) = + Cpmm_logic.Simulate_raw.addLiquidity + ~tokenPool + ~xtzPool + ~lqtTotal + ~amount + in + let lqt_minted = Z.to_int lqt_minted in + let tokens_deposited = Z.to_int tokens_deposited in + let state = + transfer_xtz_balance src env.cpmm_contract xtz_deposit state + |> transfer_tzbtc_balance src env.cpmm_contract tokens_deposited + |> update_liquidity_balance dst (( + ) lqt_minted) + in + { + state with + cpmm_total_liquidity = state.cpmm_total_liquidity + lqt_minted; + } + + let remove_liquidity ~src dst lqt_burned env _ state = + let xtzPool = + Tez.of_mutez_exn (get_xtz_balance env.cpmm_contract state) + in + let tokenPool = + Z.of_int (get_tzbtc_balance env.cpmm_contract env state) + in + let lqtTotal = Z.of_int state.cpmm_total_liquidity in + let lqtBurned = Z.of_int lqt_burned in + let (xtz_withdrawn, tokens_withdrawn) = + Cpmm_logic.Simulate_raw.removeLiquidity + ~tokenPool + ~xtzPool + ~lqtTotal + ~lqtBurned + in + let xtz_withdrawn = Tez.to_mutez xtz_withdrawn in + let tokens_withdrawn = Z.to_int tokens_withdrawn in + let state = + update_xtz_balance dst (fun b -> Int64.add b xtz_withdrawn) state + |> update_tzbtc_balance dst (( + ) tokens_withdrawn) + |> update_liquidity_balance src (fun b -> b - lqt_burned) + |> update_xtz_balance env.cpmm_contract (fun b -> + Int64.sub b xtz_withdrawn) + |> update_tzbtc_balance env.cpmm_contract (fun b -> + b - tokens_withdrawn) + in + { + state with + cpmm_total_liquidity = state.cpmm_total_liquidity - lqt_burned; + } + + (* Ideally, we should also deal with the release of security + deposit, but since our tests are not long enough for this to + happen, we omit this aspect of the simulation. *) + let bake ~invariant ~baker operations env state = + let state = + update_xtz_balance env.cpmm_contract (Int64.add env.subsidy) state + |> (fun state -> List.fold_left ( |> ) state operations) + |> update_xtz_balance baker (fun b -> Int64.sub b security_deposit) + in + assert (invariant env state) ; + state + end +end + +(* --------------------------------------------------------------------------- *) + +(** {1 Symbolic Machine} *) + +module SymbolicBaseMachine : + MACHINE_WITH_INIT + with type 'a m = 'a + and type contract = contract_id + and type t = contract_id state = struct + include AbstractMachine.Make (struct + type t = contract_id + + let pp = pp_contract_id + end) + + let init ~invariant:_ ?(subsidy = default_subsidy) accounts_balances = + let (_, initial_balances) = initial_xtz_repartition accounts_balances in + match initial_balances with + | holder_xtz :: accounts -> + let xtz_cpmm = + Int64.(add cpmm_initial_balance.xtz (mul blocks_during_init subsidy)) + in + ( { + cpmm_total_liquidity = cpmm_initial_liquidity_supply; + accounts_balances = + (Cpmm, {cpmm_initial_balance with xtz = xtz_cpmm}) + :: + (Holder, {xtz = holder_xtz; tzbtc = 0; liquidity = 0}) + :: + (TzBTCAdmin, {xtz = 0L; tzbtc = 0; liquidity = 0}) + :: + List.mapi + (fun i xtz -> + (ImplicitAccount i, {xtz; tzbtc = 0; liquidity = 0})) + accounts; + }, + { + cpmm_contract = Cpmm; + tzbtc_contract = TzBTC; + tzbtc_admin = TzBTCAdmin; + liquidity_contract = Liquidity; + liquidity_admin = LiquidityAdmin; + implicit_accounts = + List.mapi (fun i _ -> ImplicitAccount i) accounts; + holder = Holder; + subsidy; + } ) + | [] -> assert false +end + +module SymbolicMachine = struct + include SymbolicBaseMachine + include Machine.Make (SymbolicBaseMachine) + include MachineBuilder.Make (SymbolicBaseMachine) +end + +(* --------------------------------------------------------------------------- *) + +(** {1 Validation Machine} *) + +module ValidationBaseMachine : + MACHINE_WITH_INIT + with type 'a m = 'a ConcreteBaseMachine.m + and type t = ConcreteBaseMachine.t * Contract.t state + and type contract = Contract.t = struct + module GhostMachine = AbstractMachine.Make (struct + type t = Contract.t + + let pp = Contract.pp + end) + + type 'a m = 'a ConcreteBaseMachine.m + + type t = ConcreteBaseMachine.t * GhostMachine.t + + type contract = Contract.t + + type operation = ConcreteBaseMachine.operation * GhostMachine.operation + + let pp_contract = Contract.pp + + let ( >>= ) = ConcreteBaseMachine.( >>= ) + + let fold_m = ConcreteBaseMachine.fold_m + + let pure = ConcreteBaseMachine.pure + + let get_balances contract env (_, state) = + pure (GhostMachine.get_balances contract env state) + + let get_xtz_balance contract (_, state) = + pure (GhostMachine.get_xtz_balance contract state) + + let get_tzbtc_balance contract env (_, state) = + pure (GhostMachine.get_tzbtc_balance contract env state) + + let get_liquidity_balance contract env (_, state) = + pure (GhostMachine.get_liquidity_balance contract env state) + + let get_cpmm_total_liquidity env (_, state) = + pure (GhostMachine.get_cpmm_total_liquidity env state) + + let bake ~invariant ~baker ops env (blk, state) = + let cops = List.map fst ops in + let rops = List.map snd ops in + ConcreteBaseMachine.( + bake ~invariant:(fun _ _ -> pure true) ~baker cops env blk) + >>= fun blk -> + let state = + GhostMachine.bake ~invariant:(fun _ _ -> true) ~baker rops env state + in + invariant env (blk, state) >>= fun cond -> + assert cond ; + pure (blk, state) + + let transaction ~src dst xtz (blk, state) = + ConcreteBaseMachine.transaction ~src dst xtz blk >>= fun cop -> + pure (cop, GhostMachine.transaction ~src dst xtz state) + + let token_to_xtz ~src dst tzbtc env (blk, state) = + ConcreteBaseMachine.token_to_xtz ~src dst tzbtc env blk >>= fun cop -> + pure (cop, GhostMachine.token_to_xtz ~src dst tzbtc env state) + + let xtz_to_token ~src dst xtz env (blk, state) = + ConcreteBaseMachine.xtz_to_token ~src dst xtz env blk >>= fun cop -> + pure (cop, GhostMachine.xtz_to_token ~src dst xtz env state) + + let mint_or_burn_tzbtc dst tzbtc env (blk, state) = + ConcreteBaseMachine.mint_or_burn_tzbtc dst tzbtc env blk >>= fun cop -> + pure (cop, GhostMachine.mint_or_burn_tzbtc dst tzbtc env state) + + let approve_tzbtc dst tzbtc env (blk, state) = + ConcreteBaseMachine.approve_tzbtc dst tzbtc env blk >>= fun cop -> + pure (cop, GhostMachine.approve_tzbtc dst tzbtc env state) + + let add_liquidity ~src dst xtz_deposit tzbtc_deposit env (blk, state) = + ConcreteBaseMachine.add_liquidity ~src dst xtz_deposit tzbtc_deposit env blk + >>= fun cop -> + pure + ( cop, + GhostMachine.add_liquidity ~src dst xtz_deposit tzbtc_deposit env state + ) + + let remove_liquidity ~src dst lqt_burned env (blk, state) = + ConcreteBaseMachine.remove_liquidity ~src dst lqt_burned env blk + >>= fun cop -> + pure (cop, GhostMachine.remove_liquidity ~src dst lqt_burned env state) + + let reveal account (blk, state) = + ConcreteBaseMachine.reveal account blk >>= fun cop -> + pure (cop, GhostMachine.reveal account state) + + let init ~invariant ?subsidy balances = + ConcreteBaseMachine.init + ~invariant:(fun _ _ -> return true) + ?subsidy + balances + >>= fun (blk, env) -> + let (state, _) = + SymbolicBaseMachine.init ~invariant:(fun _ _ -> true) ?subsidy balances + in + let state = refine_state env state in + invariant env (blk, state) >>= fun cond -> + assert cond ; + pure ((blk, state), env) +end + +module ValidationMachine = struct + include ValidationBaseMachine + include Machine.Make (ValidationBaseMachine) + include MachineBuilder.Make (ValidationBaseMachine) + + module Symbolic = struct + let get_xtz_balance = get_xtz_balance + + let get_tzbtc_balance = get_tzbtc_balance + + let get_liquidity_balance = get_liquidity_balance + + let get_cpmm_total_liquidity = get_cpmm_total_liquidity + end + + module Concrete = struct + let get_xtz_balance contract (blk, _) = + ConcreteMachine.get_xtz_balance contract blk + + let get_tzbtc_balance contract env (blk, _) = + ConcreteMachine.get_tzbtc_balance contract env blk + + let get_liquidity_balance contract env (blk, _) = + ConcreteMachine.get_liquidity_balance contract env blk + + let get_cpmm_total_liquidity env (blk, _) = + ConcreteMachine.get_cpmm_total_liquidity env blk + end +end diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_machine.mli b/src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_machine.mli new file mode 100644 index 000000000000..76107f8b4d61 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/liquidity_baking_machine.mli @@ -0,0 +1,387 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +(** This module provides the means to test extensively the Liquidity + Baking (LB) feature. We recall that this feature is built upon + three smart contracts: (1) a CPMM contract initially based on + Dexter 2, and (2) two tokens contracts. Our objective is to run + “scenarios” consisting in interleaved, realistic calls to these + contracts, and to assert these scenarios do not yield any + undesirable behaviors. + + To that end, three “machines” are provided. + + - The {! SymbolicMachine} allows to simulate scenarios involving + the LB feature completely off-chain. It can be seen as an + abstraction of the concrete implementation provided by the Tezos + node. + - The {! ConcreteMachine } allows to execute scenarios on-chain. + - The {! ValidationMachine } combines the two previously mentioned + machines. In other words, the {! ValidationMachine} makes the {! + SymbolicMachine} and the [ConcreteMachine] execute the same + scenarios, and asserts they remain synchronized after each baked + block. + + The {! ValidationMachine} allows to (1) validate the {! + SymbolicMachine} ({i i.e.,} the reimplementation of the LB + contracts logic) against the real implementation provided by + Tezos, {b and} the contracts originated by the protocol correctly + implement the LB logic, as implemented by the {! SymbolicMachine}. + That is, the {! ValidationMachine} reports desynchronization of + the two machines, but cannot explain this desynchronization. *) + +(** {1 Machine State Characterization} *) + +type xtz = int64 + +type tzbtc = int + +type liquidity = int + +(** As far as liquidity baking is concerned, an account can hold three + kinds of tokens: [xtz], [tzbtc], and [liquidity]. *) +type balances = {xtz : xtz; tzbtc : tzbtc; liquidity : liquidity} + +val pp_balances : Format.formatter -> balances -> unit + +(** A value of type [specs] allows to specify an initial state of a + “machine”. + + In a nutshell, it consists in specifying the minimal balances of + the CPMM contracts and a set of implicit contracts. The two + machines provided by this module has a [build] function which + turns a [specs] into a consistent initial state for this + machine. *) +type specs = { + cpmm_min_xtz_balance : xtz; + cpmm_min_tzbtc_balance : tzbtc; + accounts_balances : balances list; +} + +val pp_specs : Format.formatter -> specs -> unit + +(** A value of type ['a env] (where ['a] is the type of contract + identifiers) summarizes the different contracts involved in the LB + feature. + + Values of type [env] are constructed by the [build] function of + the machines. *) +type 'a env = private { + cpmm_contract : 'a; + tzbtc_contract : 'a; + tzbtc_admin : 'a; + liquidity_contract : 'a; + liquidity_admin : 'a; + implicit_accounts : 'a list; + holder : 'a; + subsidy : xtz; +} + +(** A value of type ['a step] (where ['a] is the type used to identify + contracts) describes a consistent sequence of LB smart contract + calls. + + For instance, [SellTzBTC] consists in approving an allowance in + the [TzBTC] contract, then calling the [token_to_xtz] entry point + of the [CPMM]. *) +type 'a step = + | SellTzBTC of {source : 'a; destination : 'a; tzbtc_deposit : tzbtc} + | BuyTzBTC of {source : 'a; destination : 'a; xtz_deposit : xtz} + | AddLiquidity of {source : 'a; destination : 'a; xtz_deposit : xtz} + | RemoveLiquidity of {source : 'a; destination : 'a; lqt_burned : liquidity} + +val pp_step : + (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a step -> unit + +(** A summary of the state of a machine, parameterized by the type of + contract identifier. *) +type 'a state = { + cpmm_total_liquidity : liquidity; + accounts_balances : ('a * balances) list; +} + +(** {1 The Symbolic Machine} *) + +(** In the {! SymbolicMachine}, a contract is identified by a symbolic + value. *) +type contract_id = + | Cpmm + | Holder + | TzBTC + | TzBTCAdmin + | Liquidity + | LiquidityAdmin + (* We use integers to distinguish between implicit account because + this integer has the extra benefit of being the index of the + related account in [env.implicit_accounts]. *) + | ImplicitAccount of int + +val pp_contract_id : Format.formatter -> contract_id -> unit + +module SymbolicMachine : sig + (** The state of the {! SymbolicMachine}. *) + type t = contract_id state + + (** [get_xtz_balance c state] returns the amount of mutez owned by + [c] in [state]. *) + val get_xtz_balance : contract_id -> t -> xtz + + (** [get_tzbtc_balance c env state] returns the amount of TzBTC + owned by [c] in [state], according to the [TzBTC] contract. *) + val get_tzbtc_balance : contract_id -> contract_id env -> t -> tzbtc + + (** [get_liquidity_balance c env state] returns the amount of + liquidity token owned by [c] in [state], according to the + [Liquidity] contract. *) + val get_liquidity_balance : contract_id -> contract_id env -> t -> liquidity + + (** [get_cpmm_total_liquidity env state] fetches the current amount + of liquidity tokens distributed by the CPMM contract from the + state [state]. *) + val get_cpmm_total_liquidity : contract_id env -> t -> liquidity + + (** [predict_required_tzbtc_deposit xtz_deposit env state] predicts + the deposit in TzBTC which will be required by the CPMM contract + when executing a step [AddLiquidity] with [xtz_deposit] from + [state]. *) + val predict_required_tzbtc_deposit : xtz -> contract_id env -> t -> tzbtc + + (** [build specs] computes (1) an initial state for the {! + SymbolicMachine}, and (2) the environment associated to this + state. + + The machine enforces the resulting state is consistent with the + [specs] given as inputs, and raises an [Assert_failure] + exception if it does not. + + One can use the optional argument [subsidy] to set the subsidy + amount to a given value (by default, we use the same as the main + chain). Additionally, the [invariant] optional argument can be + used to verify that a given invariant holds at the end of the + initialization. *) + val build : + ?invariant:(contract_id env -> t -> bool) -> + ?subsidy:xtz -> + specs -> + t * contract_id env + + (** [step s env state] executes a single step [s] from [state]. + + The [invariant] optional argument can be used to verify that a + given invariant holds after each baked block. *) + val step : + ?invariant:(contract_id env -> t -> bool) -> + contract_id step -> + contract_id env -> + t -> + t + + (** [run steps env state] executes a list of steps from [state]. + + The [invariant] optional argument can be used to verify that a + given invariant holds after each baked block. *) + val run : + ?invariant:(contract_id env -> t -> bool) -> + contract_id step list -> + contract_id env -> + t -> + t +end + +(** A machine that can execute scenarios onchain. *) +module ConcreteMachine : sig + (** The state of the {! ConcreteMachine}. *) + type t = Block.t + + (** [get_xtz_balance c state] returns the amount of mutez owned by + [c] in [state]. *) + val get_xtz_balance : Contract.t -> t -> xtz tzresult Lwt.t + + (** [get_tzbtc_balance c env state] returns the amount of TzBTC + owned by [c] in [state], according to the [TzBTC] contract. *) + val get_tzbtc_balance : + Contract.t -> Contract.t env -> t -> tzbtc tzresult Lwt.t + + (** [get_liquidity_balance c env state] returns the amount of + liquidity token owned by [c] in [state], according to the + [Liquidity] contract. *) + val get_liquidity_balance : + Contract.t -> Contract.t env -> t -> liquidity tzresult Lwt.t + + (** [get_cpmm_total_liquidity env state] fetches the current amount + of liquidity tokens distributed by the CPMM contract from the + state [state]. *) + val get_cpmm_total_liquidity : Contract.t env -> t -> liquidity tzresult Lwt.t + + (** [build specs] asynchronously computes (1) an initial block for + the {! ConcreteMachine}, and (2) the environment associated to + this block. + + The machine enforces the resulting state is consistent with the + [specs] given as inputs, and raises an [Assert_failure] + exception if it does not. It also enforces that the machines + used underneath remain in sync. + + One can use the optional argument [subsidy] to set the subsidy + amount to a given value (by default, we use the same as the main + chain). Additionally, the [invariant] optional argument can be + used to verify that a given invariant holds at the end of the + initialization. *) + val build : + ?invariant:(Contract.t env -> t -> bool tzresult Lwt.t) -> + ?subsidy:xtz -> + specs -> + (t * Contract.t env) tzresult Lwt.t + + (** [step s env state] asynchronously executes a single step [s] + from [state]. + + The [invariant] optional argument can be used to verify that a + given invariant holds after each baked block. *) + val step : + ?invariant:(Contract.t env -> t -> bool tzresult Lwt.t) -> + Contract.t step -> + Contract.t env -> + t -> + t tzresult Lwt.t + + (** [run lss env state] asynchronously executes a list of steps from + [state]. + + The [invariant] optional argument can be used to verify that a + given invariant holds after each baked block. *) + val run : + ?invariant:(Contract.t env -> t -> bool tzresult Lwt.t) -> + contract_id step list -> + Contract.t env -> + t -> + t tzresult Lwt.t +end + +module ValidationMachine : sig + (** The state of the {! ValidationMachine}. *) + type t = ConcreteMachine.t * Contract.t state + + module Symbolic : sig + (** A collections of functions to introspect the symbolic part of + the [ValidationMachine] state. *) + + (** [get_xtz_balance c state] returns the amount of mutez owned by + [c] in the symbolic part of [state]. *) + val get_xtz_balance : Contract.t -> t -> xtz tzresult Lwt.t + + (** [get_tzbtc_balance c env state] returns the amount of TzBTC + owned by [c] in the symbolic part of [state], according to the + [TzBTC] contract. *) + val get_tzbtc_balance : + Contract.t -> Contract.t env -> t -> tzbtc tzresult Lwt.t + + (** [get_liquidity_balance c env state] returns the amount of + liquidity token owned by [c] in the symbolic part of [state], + according to the [Liquidity] contract. *) + val get_liquidity_balance : + Contract.t -> Contract.t env -> t -> liquidity tzresult Lwt.t + + (** [get_cpmm_total_liquidity env state] fetches the   current + amount of liquidity tokens distributed by the CPMM   contract + using the symbolic part of the state [state]. *) + val get_cpmm_total_liquidity : + Contract.t env -> t -> liquidity tzresult Lwt.t + end + + module Concrete : sig + (** A collections of functions to introspect the concrete part of + the [ValidationMachine] state. *) + + (** [get_xtz_balance c state] returns the amount of mutez owned by + [c] in the concrete part of [state]. *) + val get_xtz_balance : Contract.t -> t -> xtz tzresult Lwt.t + + (** [get_tzbtc_balance c env state] returns the amount of TzBTC + owned by [c] in the concrete part of [state], according to the + [TzBTC] contract. *) + val get_tzbtc_balance : + Contract.t -> Contract.t env -> t -> tzbtc tzresult Lwt.t + + (** [get_liquidity_balance c env state] returns the amount of + liquidity token owned by [c] in the concrete part of [state], + according to the [Liquidity] contract. *) + val get_liquidity_balance : + Contract.t -> Contract.t env -> t -> liquidity tzresult Lwt.t + + (** [get_cpmm_total_liquidity env state] fetches the current + amount of liquidity tokens distributed by the CPMM contract + using the concrete part of the state [state]. *) + val get_cpmm_total_liquidity : + Contract.t env -> t -> liquidity tzresult Lwt.t + end + + (** [build specs] asynchronously computes (1) an initial state for + the {! ValidationMachine}, and (2) the environment associated to + this state. + + The machine enforces the resulting state is consistent with the + [specs] given as inputs, and raises an [Assert_failure] + exception if it does not. It also enforces that the machines + used underneath remain in sync. + + One can use the optional argument [subsidy] to set the subsidy + amount to a given value (by default, we use the same as the main + chain). Additionally, the [invariant] optional argument can be + used to verify that a given invariant holds at the end of the + initialization. *) + val build : + ?invariant:(Contract.t env -> t -> bool tzresult Lwt.t) -> + ?subsidy:xtz -> + specs -> + (t * Contract.t env) tzresult Lwt.t + + (** [step s env state] asynchronously executes a single step [s] + from [state]. + + The [invariant] optional argument can be used to verify that a + given invariant holds after each baked block. *) + val step : + ?invariant:(Contract.t env -> t -> bool tzresult Lwt.t) -> + Contract.t step -> + Contract.t env -> + t -> + t tzresult Lwt.t + + (** [run lss env state] asynchronously executes a list of steps from + [state]. + + The [invariant] optional argument can be used to verify that a + given invariant holds after each baked block. *) + val run : + ?invariant:(Contract.t env -> t -> bool tzresult Lwt.t) -> + contract_id step list -> + Contract.t env -> + t -> + t tzresult Lwt.t +end diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/lqt_fa12_repr.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/lqt_fa12_repr.ml new file mode 100644 index 000000000000..937dfb8297b2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/lqt_fa12_repr.ml @@ -0,0 +1,252 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Expr_common + +module Parameter = struct + (* // ============================================================================= + * // Entrypoints + * // ============================================================================= *) + + (* Note: in the lqt_fa12 contract, [value] is a nat. Hence, it + should always be positive *) + type approve = {spender : Contract.t; value : Z.t} + + type mintOrBurn = {quantity : Z.t; target : Contract.t} + + (* Note: this wrapper does not implement a reprensentation for the + entrypoints transfer, getAllowance, getBalance, getTotalSupply, + as they are not used as of yet. *) + type t = Approve of approve | MintOrBurn of mintOrBurn + + let approve p = + assert (Z.lt Z.zero p.value || Z.equal Z.zero p.value) ; + Approve p + + let mintOrBurn p = MintOrBurn p + + let approve_to_string {spender; value} = + Format.asprintf + "{ spender: %a; value: %a }" + Contract.pp + spender + Z.pp_print + value + + let mint_or_burn_to_string {quantity; target} = + Format.asprintf + "{ quantity: %a; target: %a }" + Z.pp_print + quantity + Contract.pp + target + + let to_string : t -> string = function + | Approve p -> Format.asprintf "Approve %s" (approve_to_string p) + | MintOrBurn p -> Format.asprintf "MintOrBurn %s" (mint_or_burn_to_string p) + + let entrypoint_of_parameter : t -> string = function + | Approve _ -> "approve" + | MintOrBurn _ -> "mintOrBurn" + + let pp fmt s = Format.fprintf fmt "%s" (to_string s) + + let eq s s' = s = s' + + let to_expr_rooted : + loc:'a -> + t -> + ('a, Michelson_v1_primitives.prim) Tezos_micheline.Micheline.node = + fun ~loc -> function + | MintOrBurn {quantity; target} -> + comb ~loc [int ~loc quantity; address_string ~loc target] + | Approve {spender; value} -> + comb ~loc [address_string ~loc spender; int ~loc value] + + let to_expr : + loc:'a -> + t -> + ('a, Michelson_v1_primitives.prim) Tezos_micheline.Micheline.node = + fun ~loc p -> + let rooted = to_expr_rooted ~loc p in + match p with + | MintOrBurn _ -> right ~loc @@ left ~loc rooted + | Approve _ -> left ~loc @@ left ~loc @@ left ~loc rooted + + let to_michelson_string e = + let e = to_expr ~loc:0 e in + Format.asprintf + "%a" + Michelson_v1_printer.print_expr + (Micheline.strip_locations e) +end + +(* // ============================================================================= + * // Storage + * // ============================================================================= *) + +module Storage = struct + let pp_big_map_id fmt v = Z.pp_print fmt (Big_map.Id.unparse_to_z v) + + type t = { + tokens : Big_map.Id.t; + allowances : Big_map.Id.t; + admin : Contract.t; + totalSupply : Z.t; + } + + let pp {tokens; allowances; admin; totalSupply} = + Format.asprintf + "{ tokens: %a; allowances: %a; admin: %a; totalSupply: %a}" + Z.pp_print + (Big_map.Id.unparse_to_z tokens) + Z.pp_print + (Big_map.Id.unparse_to_z allowances) + Contract.pp + admin + Z.pp_print + totalSupply + + let null : t = + { + tokens = Big_map.Id.parse_z Z.zero; + allowances = Big_map.Id.parse_z Z.one; + admin = Contract.implicit_contract Signature.Public_key_hash.zero; + totalSupply = Z.zero; + } + + let eq s s' = s = s' + + let to_expr : + loc:'a -> + t -> + ('a, Michelson_v1_primitives.prim) Tezos_micheline.Micheline.node = + fun ~loc {tokens; allowances; admin; totalSupply} -> + comb + ~loc + [ + big_map_id ~loc tokens; + big_map_id ~loc allowances; + address_string ~loc admin; + int ~loc totalSupply; + ] + + let to_michelson_string e = + let e = to_expr ~loc:0 e in + Format.asprintf + "%a" + Michelson_v1_printer.print_expr + (Micheline.strip_locations e) + + type exn += Invalid_storage_expr of string + + (** Note: parses a storage unparsed in readable mode (as + e.g. returned by [Alpha_services.Contract.storage]), so that + contracts are represented by strings. *) + let of_expr_exn : + ('a, Michelson_v1_primitives.prim) Tezos_micheline.Micheline.node -> t = + function + | Tezos_micheline.Micheline.Prim + ( _, + Script.D_Pair, + [ + Tezos_micheline.Micheline.Int (_, tokens); + Tezos_micheline.Micheline.Int (_, allowances); + Tezos_micheline.Micheline.String (_, admin); + Tezos_micheline.Micheline.Int (_, totalSupply); + ], + [] ) -> + let tokens = Big_map.Id.parse_z tokens in + let allowances = Big_map.Id.parse_z allowances in + let admin = address_of_string_exn admin in + {tokens; allowances; admin; totalSupply} + | e -> + let canonical = Micheline.strip_locations e in + let msg = + Format.asprintf + "Not a valid LQT_FA1.2 storage: %s /// %a" + (try + Michelson_v1_printer.micheline_string_of_expression + ~zero_loc:true + canonical + with Z.Overflow -> + "Cannot represent as micheline due to overflowing Z -> int") + Michelson_v1_printer.print_expr + canonical + in + raise (Invalid_storage_expr msg) + + let get (ctxt : Context.t) ~(contract : Contract.t) : t tzresult Lwt.t = + Context.Contract.storage ctxt contract >|=? Micheline.root >|=? of_expr_exn + + let get_alpha_context (ctxt : Context.t) : Alpha_context.t tzresult Lwt.t = + (match ctxt with + | B b -> + (* can perhaps be retrieved through Raw_context.prepare ? *) + Incremental.begin_construction b + | I i -> return i) + >|=? Incremental.alpha_ctxt + + let getBalance_opt (ctxt : Context.t) ~(contract : Contract.t) + (owner : Script_typed_ir.address) = + get ctxt ~contract >>=? fun storage -> + let tokens = storage.tokens in + get_alpha_context ctxt >>=? fun ctxt -> + Script_ir_translator.hash_data + ctxt + Script_typed_ir.(address_t ~annot:None) + owner + >|= Environment.wrap_tzresult + >>=? fun (address_hash, ctxt) -> + Big_map.get_opt ctxt tokens address_hash >|= Environment.wrap_tzresult + >>=? function + | (_, Some canonical) -> ( + match Tezos_micheline.Micheline.root canonical with + | Tezos_micheline.Micheline.Int (_, amount) -> return @@ Some amount + | _ -> assert false) + | (_, None) -> return @@ None + + let getBalance (ctxt : Context.t) ~(contract : Contract.t) + (owner : Script_typed_ir.address) = + getBalance_opt ctxt ~contract owner >|=? Option.value ~default:Z.zero +end + +let transaction (ctxt : Context.t) ~(contract : Contract.t) ~(src : Contract.t) + ?(amount = Tez.zero) (parameters : Parameter.t) = + let entrypoint = Parameter.entrypoint_of_parameter parameters in + let rooted_param_lazy = + parameters + |> Parameter.to_expr_rooted ~loc:0 + |> Micheline.strip_locations |> Alpha_context.Script.lazy_expr + in + Op.transaction + ctxt + src + contract + amount + ~entrypoint + ~parameters:rooted_param_lazy diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/nonce.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/nonce.ml new file mode 100644 index 000000000000..695cdcdbbec9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/nonce.ml @@ -0,0 +1,35 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc.< contact@tezos.com > *) +(* *) +(* All rights reserved.No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +open Protocol + +module Table = Hashtbl.Make (struct + type t = Nonce_hash.t + + let hash h = Int32.to_int (TzEndian.get_int32 (Nonce_hash.to_bytes h) 0) + + let equal = Nonce_hash.equal +end) + +let known_nonces = Table.create 17 + +let generate () = + match + Alpha_context.Nonce.of_bytes + @@ Rand.generate Alpha_context.Constants.nonce_length + with + | Ok nonce -> + let hash = Alpha_context.Nonce.hash nonce in + Table.add known_nonces hash nonce ; + (hash, nonce) + | Error _ -> assert false + +let forget_all () = Table.clear known_nonces + +let get hash = Table.find known_nonces hash diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/nonce.mli b/src/proto_011_PtHangzH/lib_protocol/test/helpers/nonce.mli new file mode 100644 index 000000000000..8a8b258b0658 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/nonce.mli @@ -0,0 +1,33 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(** Returns a fresh nonce and its corresponding hash (and stores them). *) +val generate : unit -> Nonce_hash.t * Alpha_context.Nonce.t + +val get : Nonce_hash.t -> Alpha_context.Nonce.t option + +val forget_all : unit -> unit diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/op.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/op.ml new file mode 100644 index 000000000000..cb3eb6e091c6 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/op.ml @@ -0,0 +1,417 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +let sign ?(watermark = Signature.Generic_operation) sk ctxt contents = + let branch = Context.branch ctxt in + let unsigned = + Data_encoding.Binary.to_bytes_exn + Operation.unsigned_encoding + ({branch}, Contents_list contents) + in + let signature = Some (Signature.sign ~watermark sk unsigned) in + ({shell = {branch}; protocol_data = {contents; signature}} : _ Operation.t) + +let endorsement ?delegate ?level ctxt ?(signing_context = ctxt) () = + (match delegate with + | None -> Context.get_endorser ctxt >|=? fun (delegate, _slots) -> delegate + | Some delegate -> return delegate) + >>=? fun delegate_pkh -> + Account.find delegate_pkh >>=? fun delegate -> + Lwt.return + ( (match level with + | None -> Context.get_level ctxt + | Some level -> ok level) + >|? fun level -> + let op = Single (Endorsement {level}) in + sign + ~watermark:Signature.(Endorsement Chain_id.zero) + delegate.sk + signing_context + op ) + +let endorsement_with_slot ?delegate ?level ctxt ?(signing_context = ctxt) () = + (match delegate with None -> Context.get_endorser ctxt | Some v -> return v) + >>=? fun (delegate_pkh, slots) -> + let slot = WithExceptions.Option.get ~loc:__LOC__ (List.hd slots) in + Account.find delegate_pkh >>=? fun delegate -> + Lwt.return + ( (match level with + | None -> Context.get_level ctxt + | Some level -> ok level) + >|? fun level -> + let op = Single (Endorsement {level}) in + let endorsement = + sign + ~watermark:Signature.(Endorsement Chain_id.zero) + delegate.sk + signing_context + op + in + ({ + shell = endorsement.shell; + protocol_data = + { + contents = Single (Endorsement_with_slot {endorsement; slot}); + signature = None; + }; + } + : Kind.endorsement_with_slot Operation.t) ) + +let sign ?watermark sk ctxt (Contents_list contents) = + Operation.pack (sign ?watermark sk ctxt contents) + +let combine_operations ?public_key ?counter ?spurious_operation ~source ctxt + (packed_operations : packed_operation list) = + assert (match packed_operations with [] -> false | _ :: _ -> true) ; + (* Hypothesis : each operation must have the same branch (is this really true?) *) + let {Tezos_base.Operation.branch} = + (WithExceptions.Option.get ~loc:__LOC__ @@ List.hd packed_operations).shell + in + assert ( + List.for_all + (fun {shell = {Tezos_base.Operation.branch = b; _}; _} -> + Block_hash.(branch = b)) + packed_operations) ; + (* TODO? : check signatures consistency *) + let unpacked_operations = + List.map + (function + | {Alpha_context.protocol_data = Operation_data {contents; _}; _} -> ( + match Contents_list contents with + | Contents_list (Single o) -> Contents o + | Contents_list + (Cons (Manager_operation {operation = Reveal _; _}, Single o)) + -> + Contents o + | _ -> (* TODO : decent error *) assert false)) + packed_operations + in + (match counter with + | Some counter -> return counter + | None -> Context.Contract.counter ctxt source) + >>=? fun counter -> + (* We increment the counter *) + let counter = Z.succ counter in + Context.Contract.manager ctxt source >>=? fun account -> + let public_key = Option.value ~default:account.pk public_key in + (Context.Contract.is_manager_key_revealed ctxt source >|=? function + | false -> + let reveal_op = + Manager_operation + { + source = Signature.Public_key.hash public_key; + fee = Tez.zero; + counter; + operation = Reveal public_key; + gas_limit = Gas.Arith.integral_of_int_exn 10_000; + storage_limit = Z.zero; + } + in + (Some (Contents reveal_op), Z.succ counter) + | true -> (None, counter)) + >>=? fun (manager_op, counter) -> + (* Update counters and transform into a contents_list *) + let operations = + List.fold_left + (fun (counter, acc) -> function + | Contents (Manager_operation m) -> + ( Z.succ counter, + Contents (Manager_operation {m with counter}) :: acc ) + | x -> (counter, x :: acc)) + (counter, match manager_op with None -> [] | Some op -> [op]) + unpacked_operations + |> snd |> List.rev + in + (* patch a random operation with a corrupted pkh *) + let operations = + match spurious_operation with + | None -> operations + | Some op -> ( + let op = + match op with + | {protocol_data; shell = _} -> ( + match protocol_data with + | Operation_data {contents; _} -> ( + match contents with + | Cons _ -> assert false + | Single op -> Alpha_context.Contents op)) + in + (* Select where to insert spurious op *) + let legit_ops = List.length operations in + let index = Random.int legit_ops in + match List.split_n index operations with + | (preserved_prefix, preserved_suffix) -> + preserved_prefix @ op :: preserved_suffix) + in + Environment.wrap_tzresult @@ Operation.of_list operations + >>?= fun operations -> return @@ sign account.sk ctxt operations + +let manager_operation ?counter ?(fee = Tez.zero) ?gas_limit ?storage_limit + ?public_key ~source ctxt operation = + (match counter with + | Some counter -> return counter + | None -> Context.Contract.counter ctxt source) + >>=? fun counter -> + Context.get_constants ctxt >>=? fun c -> + let gas_limit = + let default = c.parametric.hard_gas_limit_per_operation in + Option.value ~default gas_limit + in + let storage_limit = + Option.value + ~default:c.parametric.hard_storage_limit_per_operation + storage_limit + in + Context.Contract.manager ctxt source >>=? fun account -> + let public_key = Option.value ~default:account.pk public_key in + let counter = Z.succ counter in + Context.Contract.is_manager_key_revealed ctxt source >|=? function + | true -> + let op = + Manager_operation + { + source = Signature.Public_key.hash public_key; + fee; + counter; + operation; + gas_limit; + storage_limit; + } + in + Contents_list (Single op) + | false -> + let op_reveal = + Manager_operation + { + source = Signature.Public_key.hash public_key; + fee = Tez.zero; + counter; + operation = Reveal public_key; + gas_limit = Gas.Arith.integral_of_int_exn 10000; + storage_limit = Z.zero; + } + in + let op = + Manager_operation + { + source = Signature.Public_key.hash public_key; + fee; + counter = Z.succ counter; + operation; + gas_limit; + storage_limit; + } + in + Contents_list (Cons (op_reveal, Single op)) + +let revelation ?(fee = Tez.zero) ctxt public_key = + let pkh = Signature.Public_key.hash public_key in + let source = Contract.implicit_contract pkh in + Context.Contract.counter ctxt source >>=? fun counter -> + Context.Contract.manager ctxt source >|=? fun account -> + let counter = Z.succ counter in + let sop = + Contents_list + (Single + (Manager_operation + { + source = Signature.Public_key.hash public_key; + fee; + counter; + operation = Reveal public_key; + gas_limit = Gas.Arith.integral_of_int_exn 10000; + storage_limit = Z.zero; + })) + in + sign account.sk ctxt sop + +let failing_noop ctxt source arbitrary = + let op = Contents_list (Single (Failing_noop arbitrary)) in + Account.find source >>=? fun account -> return @@ sign account.sk ctxt op + +let originated_contract op = + let nonce = Contract.initial_origination_nonce (Operation.hash_packed op) in + Contract.originated_contract nonce + +exception Impossible + +let origination ?counter ?delegate ~script ?(preorigination = None) ?public_key + ?credit ?fee ?gas_limit ?storage_limit ctxt source = + Context.Contract.manager ctxt source >>=? fun account -> + let default_credit = Tez.of_mutez @@ Int64.of_int 1000001 in + let default_credit = + WithExceptions.Option.to_exn ~none:Impossible default_credit + in + let credit = Option.value ~default:default_credit credit in + let operation = Origination {delegate; script; credit; preorigination} in + manager_operation + ?counter + ?public_key + ?fee + ?gas_limit + ?storage_limit + ~source + ctxt + operation + >|=? fun sop -> + let op = sign account.sk ctxt sop in + (op, originated_contract op) + +let register_global_constant ?counter ?public_key ?fee ?gas_limit ?storage_limit + ctxt ~source ~value = + Context.Contract.manager ctxt source >>=? fun account -> + let operation = Register_global_constant {value} in + manager_operation + ?counter + ?public_key + ?fee + ?gas_limit + ?storage_limit + ~source + ctxt + operation + >|=? fun sop -> sign account.sk ctxt sop + +let miss_signed_endorsement ?level ctxt = + (match level with None -> Context.get_level ctxt | Some level -> ok level) + >>?= fun level -> + Context.get_endorser ctxt >>=? fun (real_delegate_pkh, _slots) -> + let delegate = Account.find_alternate real_delegate_pkh in + endorsement ~delegate:delegate.pkh ~level ctxt () + +let transaction ?counter ?fee ?gas_limit ?storage_limit + ?(parameters = Script.unit_parameter) ?(entrypoint = "default") ctxt + (src : Contract.t) (dst : Contract.t) (amount : Tez.t) = + let top = Transaction {amount; parameters; destination = dst; entrypoint} in + manager_operation ?counter ?fee ?gas_limit ?storage_limit ~source:src ctxt top + >>=? fun sop -> + Context.Contract.manager ctxt src >|=? fun account -> sign account.sk ctxt sop + +let delegation ?fee ctxt source dst = + let top = Delegation dst in + manager_operation + ?fee + ~gas_limit:(Gas.Arith.integral_of_int_exn 1000) + ~source + ctxt + top + >>=? fun sop -> + Context.Contract.manager ctxt source >|=? fun account -> + sign account.sk ctxt sop + +let activation ctxt (pkh : Signature.Public_key_hash.t) activation_code = + (match pkh with + | Ed25519 edpkh -> return edpkh + | _ -> + failwith + "Wrong public key hash : %a - Commitments must be activated with an \ + Ed25519 encrypted public key hash" + Signature.Public_key_hash.pp + pkh) + >|=? fun id -> + let contents = Single (Activate_account {id; activation_code}) in + let branch = Context.branch ctxt in + { + shell = {branch}; + protocol_data = Operation_data {contents; signature = None}; + } + +let double_endorsement ctxt op1 op2 ~slot = + let contents = Single (Double_endorsement_evidence {op1; op2; slot}) in + let branch = Context.branch ctxt in + { + shell = {branch}; + protocol_data = Operation_data {contents; signature = None}; + } + +let double_baking ctxt bh1 bh2 = + let contents = Single (Double_baking_evidence {bh1; bh2}) in + let branch = Context.branch ctxt in + { + shell = {branch}; + protocol_data = Operation_data {contents; signature = None}; + } + +let seed_nonce_revelation ctxt level nonce = + { + shell = {branch = Context.branch ctxt}; + protocol_data = + Operation_data + { + contents = Single (Seed_nonce_revelation {level; nonce}); + signature = None; + }; + } + +let proposals ctxt (pkh : Contract.t) proposals = + Context.Contract.pkh pkh >>=? fun source -> + Context.Vote.get_current_period ctxt + >>=? fun {voting_period = {index; _}; _} -> + let op = Proposals {source; period = index; proposals} in + Account.find source >|=? fun account -> + sign account.sk ctxt (Contents_list (Single op)) + +let ballot ctxt (pkh : Contract.t) proposal ballot = + Context.Contract.pkh pkh >>=? fun source -> + Context.Vote.get_current_period ctxt + >>=? fun {voting_period = {index; _}; _} -> + let op = Ballot {source; period = index; proposal; ballot} in + Account.find source >|=? fun account -> + sign account.sk ctxt (Contents_list (Single op)) + +let dummy_script = + let open Micheline in + Script. + { + code = + lazy_expr + (strip_locations + (Seq + ( 0, + [ + Prim (0, K_parameter, [Prim (0, T_unit, [], [])], []); + Prim (0, K_storage, [Prim (0, T_unit, [], [])], []); + Prim + ( 0, + K_code, + [ + Seq + ( 0, + [ + Prim (0, I_CDR, [], []); + Prim + (0, I_NIL, [Prim (0, T_operation, [], [])], []); + Prim (0, I_PAIR, [], []); + ] ); + ], + [] ); + ] ))); + storage = lazy_expr (strip_locations (Prim (0, D_Unit, [], []))); + } + +let dummy_script_cost = Test_tez.Tez.of_mutez_exn 9_500L diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/op.mli b/src/proto_011_PtHangzH/lib_protocol/test/helpers/op.mli new file mode 100644 index 000000000000..4c446504c43e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/op.mli @@ -0,0 +1,152 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +val endorsement : + ?delegate:public_key_hash -> + ?level:Raw_level.t -> + Context.t -> + ?signing_context:Context.t -> + unit -> + Kind.endorsement Operation.t tzresult Lwt.t + +val endorsement_with_slot : + ?delegate:public_key_hash * int list -> + ?level:Raw_level.t -> + Context.t -> + ?signing_context:Context.t -> + unit -> + Kind.endorsement_with_slot Operation.t tzresult Lwt.t + +val miss_signed_endorsement : + ?level:Raw_level.t -> Context.t -> Kind.endorsement Operation.t tzresult Lwt.t + +val transaction : + ?counter:Z.t -> + ?fee:Tez.tez -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + ?parameters:Script.lazy_expr -> + ?entrypoint:string -> + Context.t -> + Contract.t -> + Contract.t -> + Tez.t -> + Operation.packed tzresult Lwt.t + +val delegation : + ?fee:Tez.tez -> + Context.t -> + Contract.t -> + public_key_hash option -> + Operation.packed tzresult Lwt.t + +val revelation : + ?fee:Tez.tez -> Context.t -> public_key -> Operation.packed tzresult Lwt.t + +val failing_noop : + Context.t -> public_key_hash -> string -> Operation.packed tzresult Lwt.t + +val origination : + ?counter:Z.t -> + ?delegate:public_key_hash -> + script:Script.t -> + ?preorigination:Contract.contract option -> + ?public_key:public_key -> + ?credit:Tez.tez -> + ?fee:Tez.tez -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + Context.t -> + Contract.contract -> + (Operation.packed * Contract.contract) tzresult Lwt.t + +val originated_contract : Operation.packed -> Contract.contract + +val register_global_constant : + ?counter:Z.t -> + ?public_key:Signature.public_key -> + ?fee:Test_tez.Tez.tez -> + ?gas_limit:Tezos_raw_protocol_011_PtHangzH.Alpha_context.Gas.Arith.integral -> + ?storage_limit:Z.t -> + Context.t -> + (* Account doing the registration *) + source:Contract.t -> + (* Micheline value to be registered *) + value:Protocol.Alpha_context.Script.lazy_expr -> + (Protocol.operation, tztrace) result Lwt.t + +val double_endorsement : + Context.t -> + Kind.endorsement Operation.t -> + Kind.endorsement Operation.t -> + slot:int -> + Operation.packed + +val double_baking : + Context.t -> + Block_header.block_header -> + Block_header.block_header -> + Operation.packed + +val activation : + Context.t -> + Signature.Public_key_hash.t -> + Blinded_public_key_hash.activation_code -> + Operation.packed tzresult Lwt.t + +val combine_operations : + ?public_key:public_key -> + ?counter:counter -> + ?spurious_operation:packed_operation -> + source:Contract.t -> + Context.t -> + packed_operation list -> + packed_operation tzresult Lwt.t + +(** Reveals a seed_nonce that was previously committed at a certain level *) +val seed_nonce_revelation : + Context.t -> Raw_level.t -> Nonce.t -> Operation.packed + +(** Propose a list of protocol hashes during the approval voting *) +val proposals : + Context.t -> + Contract.t -> + Protocol_hash.t list -> + Operation.packed tzresult Lwt.t + +(** Cast a vote yay, nay or pass *) +val ballot : + Context.t -> + Contract.t -> + Protocol_hash.t -> + Vote.ballot -> + Operation.packed tzresult Lwt.t + +val dummy_script : Script.t + +val dummy_script_cost : Test_tez.Tez.t diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/rewards.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/rewards.ml new file mode 100644 index 000000000000..bc9c833a8221 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/rewards.ml @@ -0,0 +1,1641 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2019--2021 Nomadic Labs, *) +(* Copyright (c) 2019 Cryptium Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** The tables are precomputed using this the following formulas: + +let max_endos = 256 +let max_reward = 40 + +let r = 0.5 +let a = 3. +let b = 1.5 + +let ( -- ) i j = List.init (j - i + 1) (fun x -> x + i) + +let baking_rewards = + let reward p e = + let r_aux = + if p = 0 then + r *. (float_of_int max_reward) + else + a + in + let r = r_aux /. (float_of_int max_endos) in + let r = 1_000_000. *. r in + Float.to_int ((float_of_int e) *. (ceil r)) in + + let ps = 0 -- 2 in + let es = 0 -- max_endos in + + List.map (fun p -> + List.map (fun e -> + reward p e + ) es |> Array.of_list + ) ps |> Array.of_list + + +let endorsing_rewards = + let reward p e = + let r_aux = + (1. -. r) *. + (float_of_int max_reward) /. + (float_of_int max_endos) in + let r = if p = 0 then r_aux else r_aux /. b in + let r = 1_000_000. *. r in + Float.to_int ((float_of_int e) *. (floor r)) in + + let ps = 0 -- 2 in + let es = 0 -- max_endos in + + List.map (fun p -> + List.map (fun e -> + reward p e + ) es |> Array.of_list + ) ps |> Array.of_list + + *) + +let baking_rewards : int array array = + [| + [| + 0; + 78125; + 156250; + 234375; + 312500; + 390625; + 468750; + 546875; + 625000; + 703125; + 781250; + 859375; + 937500; + 1015625; + 1093750; + 1171875; + 1250000; + 1328125; + 1406250; + 1484375; + 1562500; + 1640625; + 1718750; + 1796875; + 1875000; + 1953125; + 2031250; + 2109375; + 2187500; + 2265625; + 2343750; + 2421875; + 2500000; + 2578125; + 2656250; + 2734375; + 2812500; + 2890625; + 2968750; + 3046875; + 3125000; + 3203125; + 3281250; + 3359375; + 3437500; + 3515625; + 3593750; + 3671875; + 3750000; + 3828125; + 3906250; + 3984375; + 4062500; + 4140625; + 4218750; + 4296875; + 4375000; + 4453125; + 4531250; + 4609375; + 4687500; + 4765625; + 4843750; + 4921875; + 5000000; + 5078125; + 5156250; + 5234375; + 5312500; + 5390625; + 5468750; + 5546875; + 5625000; + 5703125; + 5781250; + 5859375; + 5937500; + 6015625; + 6093750; + 6171875; + 6250000; + 6328125; + 6406250; + 6484375; + 6562500; + 6640625; + 6718750; + 6796875; + 6875000; + 6953125; + 7031250; + 7109375; + 7187500; + 7265625; + 7343750; + 7421875; + 7500000; + 7578125; + 7656250; + 7734375; + 7812500; + 7890625; + 7968750; + 8046875; + 8125000; + 8203125; + 8281250; + 8359375; + 8437500; + 8515625; + 8593750; + 8671875; + 8750000; + 8828125; + 8906250; + 8984375; + 9062500; + 9140625; + 9218750; + 9296875; + 9375000; + 9453125; + 9531250; + 9609375; + 9687500; + 9765625; + 9843750; + 9921875; + 10000000; + 10078125; + 10156250; + 10234375; + 10312500; + 10390625; + 10468750; + 10546875; + 10625000; + 10703125; + 10781250; + 10859375; + 10937500; + 11015625; + 11093750; + 11171875; + 11250000; + 11328125; + 11406250; + 11484375; + 11562500; + 11640625; + 11718750; + 11796875; + 11875000; + 11953125; + 12031250; + 12109375; + 12187500; + 12265625; + 12343750; + 12421875; + 12500000; + 12578125; + 12656250; + 12734375; + 12812500; + 12890625; + 12968750; + 13046875; + 13125000; + 13203125; + 13281250; + 13359375; + 13437500; + 13515625; + 13593750; + 13671875; + 13750000; + 13828125; + 13906250; + 13984375; + 14062500; + 14140625; + 14218750; + 14296875; + 14375000; + 14453125; + 14531250; + 14609375; + 14687500; + 14765625; + 14843750; + 14921875; + 15000000; + 15078125; + 15156250; + 15234375; + 15312500; + 15390625; + 15468750; + 15546875; + 15625000; + 15703125; + 15781250; + 15859375; + 15937500; + 16015625; + 16093750; + 16171875; + 16250000; + 16328125; + 16406250; + 16484375; + 16562500; + 16640625; + 16718750; + 16796875; + 16875000; + 16953125; + 17031250; + 17109375; + 17187500; + 17265625; + 17343750; + 17421875; + 17500000; + 17578125; + 17656250; + 17734375; + 17812500; + 17890625; + 17968750; + 18046875; + 18125000; + 18203125; + 18281250; + 18359375; + 18437500; + 18515625; + 18593750; + 18671875; + 18750000; + 18828125; + 18906250; + 18984375; + 19062500; + 19140625; + 19218750; + 19296875; + 19375000; + 19453125; + 19531250; + 19609375; + 19687500; + 19765625; + 19843750; + 19921875; + 20000000; + |]; + [| + 0; + 11719; + 23438; + 35157; + 46876; + 58595; + 70314; + 82033; + 93752; + 105471; + 117190; + 128909; + 140628; + 152347; + 164066; + 175785; + 187504; + 199223; + 210942; + 222661; + 234380; + 246099; + 257818; + 269537; + 281256; + 292975; + 304694; + 316413; + 328132; + 339851; + 351570; + 363289; + 375008; + 386727; + 398446; + 410165; + 421884; + 433603; + 445322; + 457041; + 468760; + 480479; + 492198; + 503917; + 515636; + 527355; + 539074; + 550793; + 562512; + 574231; + 585950; + 597669; + 609388; + 621107; + 632826; + 644545; + 656264; + 667983; + 679702; + 691421; + 703140; + 714859; + 726578; + 738297; + 750016; + 761735; + 773454; + 785173; + 796892; + 808611; + 820330; + 832049; + 843768; + 855487; + 867206; + 878925; + 890644; + 902363; + 914082; + 925801; + 937520; + 949239; + 960958; + 972677; + 984396; + 996115; + 1007834; + 1019553; + 1031272; + 1042991; + 1054710; + 1066429; + 1078148; + 1089867; + 1101586; + 1113305; + 1125024; + 1136743; + 1148462; + 1160181; + 1171900; + 1183619; + 1195338; + 1207057; + 1218776; + 1230495; + 1242214; + 1253933; + 1265652; + 1277371; + 1289090; + 1300809; + 1312528; + 1324247; + 1335966; + 1347685; + 1359404; + 1371123; + 1382842; + 1394561; + 1406280; + 1417999; + 1429718; + 1441437; + 1453156; + 1464875; + 1476594; + 1488313; + 1500032; + 1511751; + 1523470; + 1535189; + 1546908; + 1558627; + 1570346; + 1582065; + 1593784; + 1605503; + 1617222; + 1628941; + 1640660; + 1652379; + 1664098; + 1675817; + 1687536; + 1699255; + 1710974; + 1722693; + 1734412; + 1746131; + 1757850; + 1769569; + 1781288; + 1793007; + 1804726; + 1816445; + 1828164; + 1839883; + 1851602; + 1863321; + 1875040; + 1886759; + 1898478; + 1910197; + 1921916; + 1933635; + 1945354; + 1957073; + 1968792; + 1980511; + 1992230; + 2003949; + 2015668; + 2027387; + 2039106; + 2050825; + 2062544; + 2074263; + 2085982; + 2097701; + 2109420; + 2121139; + 2132858; + 2144577; + 2156296; + 2168015; + 2179734; + 2191453; + 2203172; + 2214891; + 2226610; + 2238329; + 2250048; + 2261767; + 2273486; + 2285205; + 2296924; + 2308643; + 2320362; + 2332081; + 2343800; + 2355519; + 2367238; + 2378957; + 2390676; + 2402395; + 2414114; + 2425833; + 2437552; + 2449271; + 2460990; + 2472709; + 2484428; + 2496147; + 2507866; + 2519585; + 2531304; + 2543023; + 2554742; + 2566461; + 2578180; + 2589899; + 2601618; + 2613337; + 2625056; + 2636775; + 2648494; + 2660213; + 2671932; + 2683651; + 2695370; + 2707089; + 2718808; + 2730527; + 2742246; + 2753965; + 2765684; + 2777403; + 2789122; + 2800841; + 2812560; + 2824279; + 2835998; + 2847717; + 2859436; + 2871155; + 2882874; + 2894593; + 2906312; + 2918031; + 2929750; + 2941469; + 2953188; + 2964907; + 2976626; + 2988345; + 3000064; + |]; + [| + 0; + 11719; + 23438; + 35157; + 46876; + 58595; + 70314; + 82033; + 93752; + 105471; + 117190; + 128909; + 140628; + 152347; + 164066; + 175785; + 187504; + 199223; + 210942; + 222661; + 234380; + 246099; + 257818; + 269537; + 281256; + 292975; + 304694; + 316413; + 328132; + 339851; + 351570; + 363289; + 375008; + 386727; + 398446; + 410165; + 421884; + 433603; + 445322; + 457041; + 468760; + 480479; + 492198; + 503917; + 515636; + 527355; + 539074; + 550793; + 562512; + 574231; + 585950; + 597669; + 609388; + 621107; + 632826; + 644545; + 656264; + 667983; + 679702; + 691421; + 703140; + 714859; + 726578; + 738297; + 750016; + 761735; + 773454; + 785173; + 796892; + 808611; + 820330; + 832049; + 843768; + 855487; + 867206; + 878925; + 890644; + 902363; + 914082; + 925801; + 937520; + 949239; + 960958; + 972677; + 984396; + 996115; + 1007834; + 1019553; + 1031272; + 1042991; + 1054710; + 1066429; + 1078148; + 1089867; + 1101586; + 1113305; + 1125024; + 1136743; + 1148462; + 1160181; + 1171900; + 1183619; + 1195338; + 1207057; + 1218776; + 1230495; + 1242214; + 1253933; + 1265652; + 1277371; + 1289090; + 1300809; + 1312528; + 1324247; + 1335966; + 1347685; + 1359404; + 1371123; + 1382842; + 1394561; + 1406280; + 1417999; + 1429718; + 1441437; + 1453156; + 1464875; + 1476594; + 1488313; + 1500032; + 1511751; + 1523470; + 1535189; + 1546908; + 1558627; + 1570346; + 1582065; + 1593784; + 1605503; + 1617222; + 1628941; + 1640660; + 1652379; + 1664098; + 1675817; + 1687536; + 1699255; + 1710974; + 1722693; + 1734412; + 1746131; + 1757850; + 1769569; + 1781288; + 1793007; + 1804726; + 1816445; + 1828164; + 1839883; + 1851602; + 1863321; + 1875040; + 1886759; + 1898478; + 1910197; + 1921916; + 1933635; + 1945354; + 1957073; + 1968792; + 1980511; + 1992230; + 2003949; + 2015668; + 2027387; + 2039106; + 2050825; + 2062544; + 2074263; + 2085982; + 2097701; + 2109420; + 2121139; + 2132858; + 2144577; + 2156296; + 2168015; + 2179734; + 2191453; + 2203172; + 2214891; + 2226610; + 2238329; + 2250048; + 2261767; + 2273486; + 2285205; + 2296924; + 2308643; + 2320362; + 2332081; + 2343800; + 2355519; + 2367238; + 2378957; + 2390676; + 2402395; + 2414114; + 2425833; + 2437552; + 2449271; + 2460990; + 2472709; + 2484428; + 2496147; + 2507866; + 2519585; + 2531304; + 2543023; + 2554742; + 2566461; + 2578180; + 2589899; + 2601618; + 2613337; + 2625056; + 2636775; + 2648494; + 2660213; + 2671932; + 2683651; + 2695370; + 2707089; + 2718808; + 2730527; + 2742246; + 2753965; + 2765684; + 2777403; + 2789122; + 2800841; + 2812560; + 2824279; + 2835998; + 2847717; + 2859436; + 2871155; + 2882874; + 2894593; + 2906312; + 2918031; + 2929750; + 2941469; + 2953188; + 2964907; + 2976626; + 2988345; + 3000064; + |]; + |] + +let endorsing_rewards : int array array = + [| + [| + 0; + 78125; + 156250; + 234375; + 312500; + 390625; + 468750; + 546875; + 625000; + 703125; + 781250; + 859375; + 937500; + 1015625; + 1093750; + 1171875; + 1250000; + 1328125; + 1406250; + 1484375; + 1562500; + 1640625; + 1718750; + 1796875; + 1875000; + 1953125; + 2031250; + 2109375; + 2187500; + 2265625; + 2343750; + 2421875; + 2500000; + 2578125; + 2656250; + 2734375; + 2812500; + 2890625; + 2968750; + 3046875; + 3125000; + 3203125; + 3281250; + 3359375; + 3437500; + 3515625; + 3593750; + 3671875; + 3750000; + 3828125; + 3906250; + 3984375; + 4062500; + 4140625; + 4218750; + 4296875; + 4375000; + 4453125; + 4531250; + 4609375; + 4687500; + 4765625; + 4843750; + 4921875; + 5000000; + 5078125; + 5156250; + 5234375; + 5312500; + 5390625; + 5468750; + 5546875; + 5625000; + 5703125; + 5781250; + 5859375; + 5937500; + 6015625; + 6093750; + 6171875; + 6250000; + 6328125; + 6406250; + 6484375; + 6562500; + 6640625; + 6718750; + 6796875; + 6875000; + 6953125; + 7031250; + 7109375; + 7187500; + 7265625; + 7343750; + 7421875; + 7500000; + 7578125; + 7656250; + 7734375; + 7812500; + 7890625; + 7968750; + 8046875; + 8125000; + 8203125; + 8281250; + 8359375; + 8437500; + 8515625; + 8593750; + 8671875; + 8750000; + 8828125; + 8906250; + 8984375; + 9062500; + 9140625; + 9218750; + 9296875; + 9375000; + 9453125; + 9531250; + 9609375; + 9687500; + 9765625; + 9843750; + 9921875; + 10000000; + 10078125; + 10156250; + 10234375; + 10312500; + 10390625; + 10468750; + 10546875; + 10625000; + 10703125; + 10781250; + 10859375; + 10937500; + 11015625; + 11093750; + 11171875; + 11250000; + 11328125; + 11406250; + 11484375; + 11562500; + 11640625; + 11718750; + 11796875; + 11875000; + 11953125; + 12031250; + 12109375; + 12187500; + 12265625; + 12343750; + 12421875; + 12500000; + 12578125; + 12656250; + 12734375; + 12812500; + 12890625; + 12968750; + 13046875; + 13125000; + 13203125; + 13281250; + 13359375; + 13437500; + 13515625; + 13593750; + 13671875; + 13750000; + 13828125; + 13906250; + 13984375; + 14062500; + 14140625; + 14218750; + 14296875; + 14375000; + 14453125; + 14531250; + 14609375; + 14687500; + 14765625; + 14843750; + 14921875; + 15000000; + 15078125; + 15156250; + 15234375; + 15312500; + 15390625; + 15468750; + 15546875; + 15625000; + 15703125; + 15781250; + 15859375; + 15937500; + 16015625; + 16093750; + 16171875; + 16250000; + 16328125; + 16406250; + 16484375; + 16562500; + 16640625; + 16718750; + 16796875; + 16875000; + 16953125; + 17031250; + 17109375; + 17187500; + 17265625; + 17343750; + 17421875; + 17500000; + 17578125; + 17656250; + 17734375; + 17812500; + 17890625; + 17968750; + 18046875; + 18125000; + 18203125; + 18281250; + 18359375; + 18437500; + 18515625; + 18593750; + 18671875; + 18750000; + 18828125; + 18906250; + 18984375; + 19062500; + 19140625; + 19218750; + 19296875; + 19375000; + 19453125; + 19531250; + 19609375; + 19687500; + 19765625; + 19843750; + 19921875; + 20000000; + |]; + [| + 0; + 52083; + 104166; + 156249; + 208332; + 260415; + 312498; + 364581; + 416664; + 468747; + 520830; + 572913; + 624996; + 677079; + 729162; + 781245; + 833328; + 885411; + 937494; + 989577; + 1041660; + 1093743; + 1145826; + 1197909; + 1249992; + 1302075; + 1354158; + 1406241; + 1458324; + 1510407; + 1562490; + 1614573; + 1666656; + 1718739; + 1770822; + 1822905; + 1874988; + 1927071; + 1979154; + 2031237; + 2083320; + 2135403; + 2187486; + 2239569; + 2291652; + 2343735; + 2395818; + 2447901; + 2499984; + 2552067; + 2604150; + 2656233; + 2708316; + 2760399; + 2812482; + 2864565; + 2916648; + 2968731; + 3020814; + 3072897; + 3124980; + 3177063; + 3229146; + 3281229; + 3333312; + 3385395; + 3437478; + 3489561; + 3541644; + 3593727; + 3645810; + 3697893; + 3749976; + 3802059; + 3854142; + 3906225; + 3958308; + 4010391; + 4062474; + 4114557; + 4166640; + 4218723; + 4270806; + 4322889; + 4374972; + 4427055; + 4479138; + 4531221; + 4583304; + 4635387; + 4687470; + 4739553; + 4791636; + 4843719; + 4895802; + 4947885; + 4999968; + 5052051; + 5104134; + 5156217; + 5208300; + 5260383; + 5312466; + 5364549; + 5416632; + 5468715; + 5520798; + 5572881; + 5624964; + 5677047; + 5729130; + 5781213; + 5833296; + 5885379; + 5937462; + 5989545; + 6041628; + 6093711; + 6145794; + 6197877; + 6249960; + 6302043; + 6354126; + 6406209; + 6458292; + 6510375; + 6562458; + 6614541; + 6666624; + 6718707; + 6770790; + 6822873; + 6874956; + 6927039; + 6979122; + 7031205; + 7083288; + 7135371; + 7187454; + 7239537; + 7291620; + 7343703; + 7395786; + 7447869; + 7499952; + 7552035; + 7604118; + 7656201; + 7708284; + 7760367; + 7812450; + 7864533; + 7916616; + 7968699; + 8020782; + 8072865; + 8124948; + 8177031; + 8229114; + 8281197; + 8333280; + 8385363; + 8437446; + 8489529; + 8541612; + 8593695; + 8645778; + 8697861; + 8749944; + 8802027; + 8854110; + 8906193; + 8958276; + 9010359; + 9062442; + 9114525; + 9166608; + 9218691; + 9270774; + 9322857; + 9374940; + 9427023; + 9479106; + 9531189; + 9583272; + 9635355; + 9687438; + 9739521; + 9791604; + 9843687; + 9895770; + 9947853; + 9999936; + 10052019; + 10104102; + 10156185; + 10208268; + 10260351; + 10312434; + 10364517; + 10416600; + 10468683; + 10520766; + 10572849; + 10624932; + 10677015; + 10729098; + 10781181; + 10833264; + 10885347; + 10937430; + 10989513; + 11041596; + 11093679; + 11145762; + 11197845; + 11249928; + 11302011; + 11354094; + 11406177; + 11458260; + 11510343; + 11562426; + 11614509; + 11666592; + 11718675; + 11770758; + 11822841; + 11874924; + 11927007; + 11979090; + 12031173; + 12083256; + 12135339; + 12187422; + 12239505; + 12291588; + 12343671; + 12395754; + 12447837; + 12499920; + 12552003; + 12604086; + 12656169; + 12708252; + 12760335; + 12812418; + 12864501; + 12916584; + 12968667; + 13020750; + 13072833; + 13124916; + 13176999; + 13229082; + 13281165; + 13333248; + |]; + [| + 0; + 52083; + 104166; + 156249; + 208332; + 260415; + 312498; + 364581; + 416664; + 468747; + 520830; + 572913; + 624996; + 677079; + 729162; + 781245; + 833328; + 885411; + 937494; + 989577; + 1041660; + 1093743; + 1145826; + 1197909; + 1249992; + 1302075; + 1354158; + 1406241; + 1458324; + 1510407; + 1562490; + 1614573; + 1666656; + 1718739; + 1770822; + 1822905; + 1874988; + 1927071; + 1979154; + 2031237; + 2083320; + 2135403; + 2187486; + 2239569; + 2291652; + 2343735; + 2395818; + 2447901; + 2499984; + 2552067; + 2604150; + 2656233; + 2708316; + 2760399; + 2812482; + 2864565; + 2916648; + 2968731; + 3020814; + 3072897; + 3124980; + 3177063; + 3229146; + 3281229; + 3333312; + 3385395; + 3437478; + 3489561; + 3541644; + 3593727; + 3645810; + 3697893; + 3749976; + 3802059; + 3854142; + 3906225; + 3958308; + 4010391; + 4062474; + 4114557; + 4166640; + 4218723; + 4270806; + 4322889; + 4374972; + 4427055; + 4479138; + 4531221; + 4583304; + 4635387; + 4687470; + 4739553; + 4791636; + 4843719; + 4895802; + 4947885; + 4999968; + 5052051; + 5104134; + 5156217; + 5208300; + 5260383; + 5312466; + 5364549; + 5416632; + 5468715; + 5520798; + 5572881; + 5624964; + 5677047; + 5729130; + 5781213; + 5833296; + 5885379; + 5937462; + 5989545; + 6041628; + 6093711; + 6145794; + 6197877; + 6249960; + 6302043; + 6354126; + 6406209; + 6458292; + 6510375; + 6562458; + 6614541; + 6666624; + 6718707; + 6770790; + 6822873; + 6874956; + 6927039; + 6979122; + 7031205; + 7083288; + 7135371; + 7187454; + 7239537; + 7291620; + 7343703; + 7395786; + 7447869; + 7499952; + 7552035; + 7604118; + 7656201; + 7708284; + 7760367; + 7812450; + 7864533; + 7916616; + 7968699; + 8020782; + 8072865; + 8124948; + 8177031; + 8229114; + 8281197; + 8333280; + 8385363; + 8437446; + 8489529; + 8541612; + 8593695; + 8645778; + 8697861; + 8749944; + 8802027; + 8854110; + 8906193; + 8958276; + 9010359; + 9062442; + 9114525; + 9166608; + 9218691; + 9270774; + 9322857; + 9374940; + 9427023; + 9479106; + 9531189; + 9583272; + 9635355; + 9687438; + 9739521; + 9791604; + 9843687; + 9895770; + 9947853; + 9999936; + 10052019; + 10104102; + 10156185; + 10208268; + 10260351; + 10312434; + 10364517; + 10416600; + 10468683; + 10520766; + 10572849; + 10624932; + 10677015; + 10729098; + 10781181; + 10833264; + 10885347; + 10937430; + 10989513; + 11041596; + 11093679; + 11145762; + 11197845; + 11249928; + 11302011; + 11354094; + 11406177; + 11458260; + 11510343; + 11562426; + 11614509; + 11666592; + 11718675; + 11770758; + 11822841; + 11874924; + 11927007; + 11979090; + 12031173; + 12083256; + 12135339; + 12187422; + 12239505; + 12291588; + 12343671; + 12395754; + 12447837; + 12499920; + 12552003; + 12604086; + 12656169; + 12708252; + 12760335; + 12812418; + 12864501; + 12916584; + 12968667; + 13020750; + 13072833; + 13124916; + 13176999; + 13229082; + 13281165; + 13333248; + |]; + |] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/sapling_helpers.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/sapling_helpers.ml new file mode 100644 index 000000000000..65dd37f8b52b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/sapling_helpers.ml @@ -0,0 +1,383 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020-2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +module Common = struct + let memo_size_of_int i = + match Alpha_context.Sapling.Memo_size.parse_z @@ Z.of_int i with + | Ok memo_size -> memo_size + | Error _ -> assert false + + let int_of_memo_size ms = + Alpha_context.Sapling.Memo_size.unparse_to_z ms |> Z.to_int + + let wrap e = Lwt.return (Environment.wrap_tzresult e) + + let assert_true res = res >|=? fun res -> assert res + + let assert_false res = res >|=? fun res -> assert (not res) + + let assert_some res = res >|=? function Some s -> s | None -> assert false + + let assert_none res = + res >>=? function Some _ -> assert false | None -> return_unit + + let assert_error res = + res >>= function Ok _ -> assert false | Error _ -> return_unit + + let print ?(prefix = "") e v = + Printf.printf + "%s: %s\n" + prefix + Data_encoding.(Json.to_string (Json.construct e v)) + + let to_hex x encoding = + Hex.show (Hex.of_bytes Data_encoding.Binary.(to_bytes_exn encoding x)) + + let randomized_byte ?pos v encoding = + let bytes = Data_encoding.Binary.(to_bytes_exn encoding v) in + let rec aux () = + let random_char = Random.int 256 |> char_of_int in + let pos = Option.value ~default:(Random.int (Bytes.length bytes)) pos in + if random_char = Bytes.get bytes pos then aux () + else Bytes.set bytes pos random_char + in + aux () ; + Data_encoding.Binary.(of_bytes_exn encoding bytes) + + type wallet = { + sk : Tezos_sapling.Core.Wallet.Spending_key.t; + vk : Tezos_sapling.Core.Wallet.Viewing_key.t; + } + + let wallet_gen () = + let sk = + Tezos_sapling.Core.Wallet.Spending_key.of_seed + (Tezos_crypto.Hacl.Rand.gen 32) + in + let vk = Tezos_sapling.Core.Wallet.Viewing_key.of_sk sk in + {sk; vk} + + let gen_addr n vk = + let rec aux n index res = + if Compare.Int.( <= ) n 0 then res + else + let (new_index, new_addr) = + Tezos_sapling.Core.Client.Viewing_key.new_address vk index + in + aux (n - 1) new_index (new_addr :: res) + in + aux n Tezos_sapling.Core.Client.Viewing_key.default_index [] + + let gen_nf () = + let {vk; _} = wallet_gen () in + let addr = + snd + @@ Tezos_sapling.Core.Wallet.Viewing_key.(new_address vk default_index) + in + let amount = 10L in + let rcm = Tezos_sapling.Core.Client.Rcm.random () in + let position = 10L in + Tezos_sapling.Core.Client.Nullifier.compute addr vk ~amount rcm ~position + + let gen_cm_cipher ~memo_size () = + let open Tezos_sapling.Core.Client in + let {vk; _} = wallet_gen () in + let addr = + snd + @@ Tezos_sapling.Core.Wallet.Viewing_key.(new_address vk default_index) + in + let amount = 10L in + let rcm = Tezos_sapling.Core.Client.Rcm.random () in + let cm = Commitment.compute addr ~amount rcm in + let cipher = + let payload_enc = + Data_encoding.Binary.to_bytes_exn + Data_encoding.bytes + (Hacl.Rand.gen (memo_size + 4 + 16 + 11 + 32 + 8)) + in + Data_encoding.Binary.of_bytes_exn + Ciphertext.encoding + (Bytes.concat + Bytes.empty + [ + Bytes.create (32 + 32); + payload_enc; + Bytes.create (24 + 64 + 16 + 24); + ]) + in + (cm, cipher) + + (* rebuilds from empty at each call *) + let client_state_of_diff ~memo_size (root, diff) = + let open Alpha_context.Sapling in + let cs = + Tezos_sapling.Storage.add + (Tezos_sapling.Storage.empty ~memo_size) + diff.commitments_and_ciphertexts + in + assert (Tezos_sapling.Storage.get_root cs = root) ; + List.fold_left + (fun s nf -> Tezos_sapling.Storage.add_nullifier s nf) + cs + diff.nullifiers +end + +module Alpha_context_helpers = struct + include Common + + let init () = + Context.init 1 >>=? fun (b, _) -> + Alpha_context.prepare + b.context + ~level:b.header.shell.level + ~predecessor_timestamp:b.header.shell.timestamp + ~timestamp:b.header.shell.timestamp + ~fitness:b.header.shell.fitness + >>= wrap + >|=? fun (ctxt, _, _) -> ctxt + + (* takes a state obtained from Sapling.empty_state or Sapling.state_from_id and + passed through Sapling.verify_update *) + let finalize ctx = + let open Alpha_context in + let open Sapling in + function + | {id = None; diff; memo_size} -> + Sapling.fresh ~temporary:false ctx >>= wrap >>=? fun (ctx, id) -> + let init = Lazy_storage.Alloc {memo_size} in + let lazy_storage_diff = Lazy_storage.Update {init; updates = diff} in + let diffs = [Lazy_storage.make Sapling_state id lazy_storage_diff] in + Lazy_storage.apply ctx diffs >>= wrap >|=? fun (ctx, _added_size) -> + (ctx, id) + | {id = Some id; diff; _} -> + let init = Lazy_storage.Existing in + let lazy_storage_diff = Lazy_storage.Update {init; updates = diff} in + let diffs = [Lazy_storage.make Sapling_state id lazy_storage_diff] in + Lazy_storage.apply ctx diffs >>= wrap >|=? fun (ctx, _added_size) -> + (ctx, id) + + (* disk only version *) + let verify_update ctx ?memo_size ?id vt = + let anti_replay = "anti-replay" in + (match id with + | None -> + (match memo_size with + | None -> ( + match vt.Environment.Sapling.UTXO.outputs with + | [] -> failwith "Can't infer memo_size from empty outputs" + | output :: _ -> + return + @@ Environment.Sapling.Ciphertext.get_memo_size + output.ciphertext) + | Some memo_size -> return memo_size) + >>=? fun memo_size -> + let memo_size = memo_size_of_int memo_size in + let vs = Alpha_context.Sapling.empty_state ~memo_size () in + return (vs, ctx) + | Some id -> + (* Storage.Sapling.Roots.get (Obj.magic ctx, id) 0l *) + (* >>= wrap *) + (* >>=? fun (_, root) -> *) + (* print ~prefix:"verify: " Environment.Sapling.Hash.encoding root ; *) + Alpha_context.Sapling.state_from_id ctx id >>= wrap) + >>=? fun (vs, ctx) -> + Alpha_context.Sapling.verify_update ctx vs vt anti_replay >>= wrap + >>=? fun (ctx, res) -> + match res with + | None -> return_none + | Some (_balance, vs) -> + finalize ctx vs >>=? fun (ctx, id) -> + let ectx = (Alpha_context.finalize ctx).context in + (* bump the level *) + Alpha_context.prepare + ectx + ~level: + Alpha_context.( + Raw_level.to_int32 Level.((succ ctx (current ctx)).level)) + ~predecessor_timestamp:(Time.Protocol.of_seconds Int64.zero) + ~timestamp:(Time.Protocol.of_seconds Int64.zero) + ~fitness:(Fitness_repr.from_int64 Int64.zero) + >>= wrap + >|=? fun (ctx, _, _) -> Some (ctx, id) + + let transfer_inputs_outputs w cs is = + (* Tezos_sapling.Storage.size cs *) + (* |> fun (a, b) -> *) + (* Printf.printf "%Ld %Ld" a b ; *) + let inputs = + List.map + (fun i -> + Tezos_sapling.Forge.Input.get cs (Int64.of_int i) w.vk + |> WithExceptions.Option.get ~loc:__LOC__ + |> snd) + is + in + let addr = + snd + @@ Tezos_sapling.Core.Wallet.Viewing_key.(new_address w.vk default_index) + in + let memo_size = Tezos_sapling.Storage.get_memo_size cs in + let o = + Tezos_sapling.Forge.make_output addr 1000000L (Bytes.create memo_size) + in + (inputs, [o]) + + let transfer w cs is = + let anti_replay = "anti-replay" in + let (ins, outs) = transfer_inputs_outputs w cs is in + (* change the wallet of this last line *) + Tezos_sapling.Forge.forge_transaction ins outs w.sk anti_replay cs + + let client_state_alpha ctx id = + Alpha_context.Sapling.get_diff ctx id () >>= wrap >>=? fun diff -> + Alpha_context.Sapling.state_from_id ctx id >>= wrap + >|=? fun ({memo_size; _}, _ctx) -> + let memo_size = int_of_memo_size memo_size in + client_state_of_diff ~memo_size diff +end + +(* + Interpreter level +*) + +module Interpreter_helpers = struct + include Common + include Contract_helpers + + (** Returns a block in which the contract is originated. + Also returns the associated anti-replay string and KT1 address. *) + let originate_contract file storage src b baker = + originate_contract file storage src b baker >|=? fun (dst, b) -> + let anti_replay = + Format.asprintf + "%a%a" + Alpha_context.Contract.pp + dst + Chain_id.pp + Chain_id.zero + in + (dst, b, anti_replay) + + let hex_shield ~memo_size wallet anti_replay = + let ps = Tezos_sapling.Storage.empty ~memo_size in + let addr = + snd + @@ Tezos_sapling.Core.Wallet.Viewing_key.( + new_address wallet.vk default_index) + in + let output = + Tezos_sapling.Forge.make_output addr 15L (Bytes.create memo_size) + in + let pt = + Tezos_sapling.Forge.forge_transaction [] [output] wallet.sk anti_replay ps + in + let hex_string = + "0x" + ^ Hex.show + (Hex.of_bytes + Data_encoding.Binary.( + to_bytes_exn + Tezos_sapling.Core.Client.UTXO.transaction_encoding + pt)) + in + hex_string + + (* Make a transaction and sync a local client state. [to_exclude] is the list + of addresses that cannot bake the block*) + let transac_and_sync ~memo_size block parameters amount src dst baker = + Test_tez.Tez.(one_mutez *? Int64.of_int amount) >>?= fun amount_tez -> + let fee = Test_tez.Tez.of_int 10 in + Op.transaction ~fee (B block) src dst amount_tez ~parameters + >>=? fun operation -> + Incremental.begin_construction ~policy:Block.(By_account baker) block + >>=? fun incr -> + Incremental.add_operation incr operation >>=? fun incr -> + Incremental.finalize_block incr >>=? fun block -> + Alpha_services.Contract.single_sapling_get_diff + Block.rpc_ctxt + block + dst + ~offset_commitment:0L + ~offset_nullifier:0L + () + >|=? fun diff -> + let state = client_state_of_diff ~memo_size diff in + (block, state) + + (* Returns a list of printed shield transactions and their total amount. *) + let shield ~memo_size sk number_transac vk printer anti_replay = + let state = Tezos_sapling.Storage.empty ~memo_size in + let rec aux number_transac number_outputs index amount_output total res = + if Compare.Int.(number_transac <= 0) then (res, total) + else + let (new_index, new_addr) = + Tezos_sapling.Core.Wallet.Viewing_key.(new_address vk index) + in + let outputs = + List.init ~when_negative_length:() number_outputs (fun _ -> + Tezos_sapling.Forge.make_output + new_addr + amount_output + (Bytes.create memo_size)) + |> function + | Error () -> assert false (* conditional above guards against this *) + | Ok outputs -> outputs + in + let tr_hex = + to_hex + (Tezos_sapling.Forge.forge_transaction + ~number_dummy_inputs:0 + ~number_dummy_outputs:0 + [] + outputs + sk + anti_replay + state) + Tezos_sapling.Core.Client.UTXO.transaction_encoding + in + aux + (number_transac - 1) + (number_outputs + 1) + new_index + (Int64.add 20L amount_output) + (total + (number_outputs * Int64.to_int amount_output)) + (printer tr_hex :: res) + in + aux + number_transac + 2 + Tezos_sapling.Core.Wallet.Viewing_key.default_index + 20L + 0 + [] + + (* This fails if the operation is not correct wrt the block *) + let next_block block operation = + Incremental.begin_construction block >>=? fun incr -> + Incremental.add_operation incr operation >>=? fun incr -> + Incremental.finalize_block incr +end diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_big_map.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_big_map.ml new file mode 100644 index 000000000000..8573cafd1818 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_big_map.ml @@ -0,0 +1,30 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Trili Tech, *) +(* *) +(* 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. *) + +let update k v m ctxt = Protocol.Script_ir_translator.big_map_update ctxt k v m + +let of_list key_ty ty xs ctxt = + List.fold_left_es + (fun (bm, ctxt) (k, v) -> update k (Some v) bm ctxt) + (Protocol.Script_ir_translator.empty_big_map key_ty ty, ctxt) + xs diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_big_map.mli b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_big_map.mli new file mode 100644 index 000000000000..d3875195820a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_big_map.mli @@ -0,0 +1,44 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Trili Tech, *) +(* *) +(* 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. *) + +(** Update a big map. See [Script_typed_ir.big_map_get_and_update] for details. *) +val update : + 'key -> + 'value option -> + ('key, 'value) Protocol.Script_typed_ir.big_map -> + Protocol.Alpha_context.t -> + (('key, 'value) Protocol.Script_typed_ir.big_map * Protocol.Alpha_context.t) + Protocol.Environment.Error_monad.tzresult + Lwt.t + +(** Convert a list to a [Script_big_map]. If the list contains duplicate keys, + the first occurence is used. + *) +val of_list : + 'key Protocol.Script_typed_ir.comparable_ty -> + 'value Protocol.Script_typed_ir.ty -> + ('key * 'value) list -> + Protocol.Alpha_context.t -> + (('key, 'value) Protocol.Script_typed_ir.big_map * Protocol.Alpha_context.t) + Protocol.Environment.Error_monad.tzresult + Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_list.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_list.ml new file mode 100644 index 000000000000..b224d784226b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_list.ml @@ -0,0 +1,29 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol.Script_typed_ir (* For record fields *) + +let of_list xs = {elements = xs; length = List.length xs} diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_list.mli b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_list.mli new file mode 100644 index 000000000000..fecdbe0072c1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_list.mli @@ -0,0 +1,28 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Convert a standard list to a Script IR list. *) +val of_list : 'a list -> 'a Protocol.Script_typed_ir.boxed_list diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_map.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_map.ml new file mode 100644 index 000000000000..5b780f7ac8e2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_map.ml @@ -0,0 +1,36 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let of_list : + type k v. + k Protocol.Script_typed_ir.comparable_ty -> + (k * v) list -> + (k, v) Protocol.Script_typed_ir.map = + fun ty1 xs -> + List.fold_left + (fun rs (k, v) -> Protocol.Script_map.update k (Some v) rs) + (Protocol.Script_map.empty ty1) + xs diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_map.mli b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_map.mli new file mode 100644 index 000000000000..e81cf5956c93 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_map.mli @@ -0,0 +1,31 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Trili Tech *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Convert a list to a [Script_map]. If the list contains duplicate keys, + the last occurence is used. *) +val of_list : + 'k Protocol.Script_typed_ir.comparable_ty -> + ('k * 'v) list -> + ('k, 'v) Protocol.Script_typed_ir.map diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_set.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_set.ml new file mode 100644 index 000000000000..b02d082465a4 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_set.ml @@ -0,0 +1,31 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let of_list ty1 xs = + List.fold_left + (fun rs k -> Protocol.Script_set.update k true rs) + (Protocol.Script_set.empty ty1) + xs diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_set.mli b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_set.mli new file mode 100644 index 000000000000..7df70020e3b3 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/script_set.mli @@ -0,0 +1,32 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Convert a list to a Script IR set. If the list contains duplicates, + the last occurence is used. *) +val of_list : + 'a Protocol.Script_typed_ir.comparable_ty -> + 'a list -> + 'a Protocol.Script_typed_ir.set diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/test_global_constants.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/test_global_constants.ml new file mode 100644 index 000000000000..84039ceeb4ff --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/test_global_constants.ml @@ -0,0 +1,327 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Micheline +open Michelson_v1_primitives + +let create_context () = + let accounts = Account.generate_accounts 2 in + Block.alpha_context accounts + +let expr_to_hash expr = + let lexpr = Script_repr.lazy_expr expr in + Script_repr.force_bytes lexpr >|? fun b -> Script_expr_hash.hash_bytes [b] + +let assert_expr_equal loc = + Assert.equal + ~loc + ( = ) + "Michelson Expressions Not Equal" + Michelson_v1_printer.print_expr + +let assert_proto_error_id loc id result = + let test err = + (Error_monad.find_info_of_error err).id + = "proto." ^ Protocol.name ^ "." ^ id + in + Assert.error ~loc result test + +let assert_ok_lwt x = + match Lwt_main.run x with + | Ok x -> x + | Error _ -> raise @@ Failure "Called assert_ok_lwt on Error" + +let assert_ok = function + | Ok x -> x + | Error _ -> raise @@ Failure "Called assert_ok on Error" + +(** Filters out values that would cause [register] *) +let assume_expr_not_too_large expr = + let node = root expr in + QCheck.assume @@ not + @@ Global_constants_storage.Internal_for_tests.node_too_large node + +module Generators = struct + let context_arbitrary = + QCheck.make @@ QCheck.Gen.return (create_context () |> assert_ok_lwt) + + let prims = + [ + K_parameter; + K_storage; + K_code; + D_False; + D_Elt; + D_Left; + D_None; + D_Pair; + D_Right; + D_Some; + D_True; + D_Unit; + I_PACK; + I_UNPACK; + I_BLAKE2B; + I_SHA256; + I_SHA512; + I_ABS; + I_ADD; + I_AMOUNT; + I_AND; + I_BALANCE; + I_CAR; + I_CDR; + I_CHAIN_ID; + I_CHECK_SIGNATURE; + I_COMPARE; + I_CONCAT; + I_CONS; + I_CREATE_ACCOUNT; + I_CREATE_CONTRACT; + I_IMPLICIT_ACCOUNT; + I_DIP; + I_DROP; + I_DUP; + I_EDIV; + I_EMPTY_BIG_MAP; + I_EMPTY_MAP; + I_EMPTY_SET; + I_EQ; + I_EXEC; + I_APPLY; + I_FAILWITH; + I_GE; + I_GET; + I_GET_AND_UPDATE; + I_GT; + I_HASH_KEY; + I_IF; + I_IF_CONS; + I_IF_LEFT; + I_IF_NONE; + I_INT; + I_LAMBDA; + I_LE; + I_LEFT; + I_LEVEL; + I_LOOP; + I_LSL; + I_LSR; + I_LT; + I_MAP; + I_MEM; + I_MUL; + I_NEG; + I_NEQ; + I_NIL; + I_NONE; + I_NOT; + I_NOW; + I_OR; + I_PAIR; + I_UNPAIR; + I_PUSH; + I_RIGHT; + I_SIZE; + I_SOME; + I_SOURCE; + I_SENDER; + I_SELF; + I_SELF_ADDRESS; + I_SLICE; + I_STEPS_TO_QUOTA; + I_SUB; + I_SWAP; + I_TRANSFER_TOKENS; + I_SET_DELEGATE; + I_UNIT; + I_UPDATE; + I_XOR; + I_ITER; + I_LOOP_LEFT; + I_ADDRESS; + I_CONTRACT; + I_ISNAT; + I_CAST; + I_RENAME; + I_SAPLING_EMPTY_STATE; + I_SAPLING_VERIFY_UPDATE; + I_DIG; + I_DUG; + I_NEVER; + I_VOTING_POWER; + I_TOTAL_VOTING_POWER; + I_KECCAK; + I_SHA3; + I_PAIRING_CHECK; + I_TICKET; + I_READ_TICKET; + I_SPLIT_TICKET; + I_JOIN_TICKETS; + T_bool; + T_contract; + T_int; + T_key; + T_key_hash; + T_lambda; + T_list; + T_map; + T_big_map; + T_nat; + T_option; + T_or; + T_pair; + T_set; + T_signature; + T_string; + T_bytes; + T_mutez; + T_timestamp; + T_unit; + T_operation; + T_address; + T_sapling_transaction; + T_sapling_state; + T_chain_id; + T_never; + T_bls12_381_g1; + T_bls12_381_g2; + T_bls12_381_fr; + T_ticket; + H_constant; + ] + + let prim_gen = QCheck.Gen.oneofl prims + + let prims_without_constants_gen = + QCheck.Gen.oneofl (List.filter (fun x -> x != H_constant) prims) + + let z_gen = QCheck.Gen.map Z.of_int QCheck.Gen.int + + let micheline_node_gen l_gen p_gen annot_gen : + ('l, 'p) Micheline.node QCheck.Gen.t = + let open Micheline in + let open QCheck.Gen in + fix + (fun self () -> + frequency + [ + (3, map (fun (l, x) -> Int (l, x)) (pair l_gen z_gen)); + (3, map (fun (l, x) -> String (l, x)) (pair l_gen string)); + ( 3, + map + (fun (l, x) -> Bytes (l, Bytes.of_string x)) + (pair l_gen string) ); + ( 1, + map + (fun (l, p, args, annot) -> Prim (l, p, args, annot)) + (quad + l_gen + p_gen + (list_size (int_bound 10) (self ())) + annot_gen) ); + ( 1, + map + (fun (l, args) -> Seq (l, args)) + (pair l_gen (list_size (int_bound 10) (self ()))) ); + ]) + () + + let rec replace_with_constant : + Script.node -> int -> Script.node * Script.node option = + fun node loc -> + let open Michelson_v1_primitives in + let open Micheline in + let rec loop : Script.node list -> Script.node list * Script.node option = + function + | [] -> ([], None) + | hd :: tl -> ( + match replace_with_constant hd loc with + | (node, Some x) -> (node :: tl, Some x) + | (_, None) -> + let (l, x) = loop tl in + (hd :: l, x)) + in + match node with + | (Int (l, _) | String (l, _) | Bytes (l, _)) as node -> + if l = loc then + let hash = + node |> strip_locations |> expr_to_hash |> assert_ok + |> Script_expr_hash.to_b58check + in + (Prim (-1, H_constant, [String (-1, hash)], []), Some node) + else (node, None) + | Prim (l, prim, args, annot) as node -> + if l = loc then + let hash = + node |> strip_locations |> expr_to_hash |> assert_ok + |> Script_expr_hash.to_b58check + in + (Prim (-1, H_constant, [String (-1, hash)], []), Some node) + else + let (result, x) = loop args in + (Prim (l, prim, result, annot), x) + | Seq (l, args) as node -> + if l = loc then + let hash = + node |> strip_locations |> expr_to_hash |> assert_ok + |> Script_expr_hash.to_b58check + in + (Prim (-1, H_constant, [String (-1, hash)], []), Some node) + else + let (result, x) = loop args in + (Seq (l, result), x) + + let micheline_gen p_gen annot_gen = + QCheck.Gen.map + Micheline.strip_locations + (micheline_node_gen (QCheck.Gen.return (-1)) p_gen annot_gen) + + let canonical_without_constant_gen = + QCheck.Gen.map + strip_locations + (micheline_node_gen + (QCheck.Gen.return (-1)) + prims_without_constants_gen + (QCheck.Gen.return [])) + + let canonical_without_constant_arbitrary = + QCheck.make canonical_without_constant_gen + + let canonical_with_constant_gen = + let open QCheck.Gen in + canonical_without_constant_gen >>= fun expr -> + let size = Script_repr.micheline_nodes (root expr) in + 0 -- (size - 1) >|= fun loc -> + match replace_with_constant (root expr) loc with + | (_, None) -> assert false + | (node, Some replaced_node) -> + (expr, strip_locations node, strip_locations replaced_node) + + let canonical_with_constant_arbitrary = + QCheck.make canonical_with_constant_gen +end diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/test_tez.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/test_tez.ml new file mode 100644 index 000000000000..8802f4a840d5 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/test_tez.ml @@ -0,0 +1,59 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context +open Environment + +(* This module is mostly to wrap the errors from the protocol *) +module Tez = struct + include Tez + + let ( +? ) t1 t2 = t1 +? t2 |> wrap_tzresult + + let ( -? ) t1 t2 = t1 -? t2 |> wrap_tzresult + + let ( *? ) t1 t2 = t1 *? t2 |> wrap_tzresult + + let ( /? ) t1 t2 = t1 /? t2 |> wrap_tzresult + + let ( + ) t1 t2 = + match t1 +? t2 with + | Ok r -> r + | Error _ -> Pervasives.failwith "adding tez" + + let of_int x = + match Tez.of_mutez (Int64.mul (Int64.of_int x) 1_000_000L) with + | None -> invalid_arg "tez_of_int" + | Some x -> x + + let of_mutez_exn x = + match Tez.of_mutez x with None -> invalid_arg "tez_of_mutez" | Some x -> x + + let to_mutez = Tez.to_mutez + + let max_tez = + match Tez.of_mutez Int64.max_int with None -> assert false | Some p -> p +end diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/testable.ml b/src/proto_011_PtHangzH/lib_protocol/test/helpers/testable.ml new file mode 100644 index 000000000000..79cc1d89ff8a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/testable.ml @@ -0,0 +1,38 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let contract : Protocol.Alpha_context.Contract.t Alcotest.testable = + let open Protocol in + let open Alpha_context in + Alcotest.testable Contract.pp Contract.( = ) + +let script_expr : Protocol.Alpha_context.Script.expr Alcotest.testable = + Alcotest.testable Michelson_v1_printer.print_expr ( = ) + +let trace : tztrace Alcotest.testable = Alcotest.testable pp_print_error ( = ) + +let protocol_error : Environment.Error_monad.error Alcotest.testable = + let open Environment.Error_monad in + Alcotest.testable pp ( = ) diff --git a/src/proto_011_PtHangzH/lib_protocol/test/helpers/tezos-011-PtHangzH-test-helpers.opam b/src/proto_011_PtHangzH/lib_protocol/test/helpers/tezos-011-PtHangzH-test-helpers.opam new file mode 100644 index 000000000000..7598b11786bf --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/helpers/tezos-011-PtHangzH-test-helpers.opam @@ -0,0 +1,25 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-base" + "tezos-stdlib-unix" + "tezos-shell-services" + "tezos-protocol-environment" + "tezos-protocol-011-PtHangzH" + "tezos-protocol-011-PtHangzH-parameters" + "tezos-client-011-PtHangzH" + "tezos-test-helpers" + "alcotest-lwt" + "qcheck-alcotest" +] +build: [ + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: protocol testing framework" diff --git a/src/proto_011_PtHangzH/lib_protocol/test/liquidity_baking_pbt.ml b/src/proto_011_PtHangzH/lib_protocol/test/liquidity_baking_pbt.ml new file mode 100644 index 000000000000..3389fd9eee8c --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/liquidity_baking_pbt.ml @@ -0,0 +1,300 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: pbt for liquidity baking + Invocation: [QCHECK_SEED=] dune exec src/proto_alpha/lib_protocol/test/liquidity_baking_pbt.exe + Subject: Test liquidity baking contracts using randomly generated inputs. +*) + +open Protocol +open Alpha_context +open Test_tez +open Liquidity_baking_machine + +(** We use the “machines” provided by the {! Liquidity_baking_machine} + module. Because using the [ConcreteMachine] (hence, the {! + ValidationMachine} too) is slow, we implement the following + test-suit architecture: + + - One {v QCheck v}-based test is used to validate consistency of + the {! SymbolicMachine} wrt. the [ConcreteMachine], thanks to + the {! ValidationMachine}. + - The rest of the tests use the {! SymbolicMachine} in order to be + more effective. *) + +(** [all_true l] waits for all promises of [l], and returns [true] iff + they all resolve to [true]. *) +let all_true = List.for_all_ep Fun.id + +let extract_qcheck_tzresult : unit tzresult Lwt.t -> bool = + fun p -> + match Lwt_main.run p with + | Ok () -> true + | Error err -> QCheck.Test.fail_reportf "@\n%a@." pp_print_error err + +let rec run_and_check check scenarios env state = + match scenarios with + | step :: rst -> + let state' = SymbolicMachine.step step env state in + assert (check state state') ; + run_and_check check rst env state' + | [] -> state + +let one_balance_decreases c env state state' = + let xtz = SymbolicMachine.get_xtz_balance c state in + let tzbtc = SymbolicMachine.get_tzbtc_balance c env state in + let lqt = SymbolicMachine.get_liquidity_balance c env state in + let xtz' = SymbolicMachine.get_xtz_balance c state' in + let tzbtc' = SymbolicMachine.get_tzbtc_balance c env state' in + let lqt' = SymbolicMachine.get_liquidity_balance c env state' in + xtz' < xtz || tzbtc' < tzbtc || lqt' < lqt + || (xtz' = xtz && tzbtc' = tzbtc && lqt' = lqt) + +let get_float_balances env state = + let xtz = + Int64.to_float @@ SymbolicMachine.get_xtz_balance env.cpmm_contract state + in + let tzbtc = + Int.to_float + @@ SymbolicMachine.get_tzbtc_balance env.cpmm_contract env state + in + let lqt = + Int.to_float @@ SymbolicMachine.get_cpmm_total_liquidity env state + in + (xtz, tzbtc, lqt) + +(** [is_remove_liquidity_consistent env state state'] returns [true] + iff, when the liquidity pool decreased in [state'], then the + fraction of tzbtc and xtz returned to the liquidity provider is + lesser or equal than the fraction of lqt burnt. *) +let is_remove_liquidity_consistent env state state' = + let (xtz, tzbtc, lqt) = get_float_balances env state in + let (xtz', tzbtc', lqt') = get_float_balances env state' in + if lqt' < lqt then + let flqt = (lqt -. lqt') /. lqt in + let fxtz = (xtz -. xtz') /. xtz in + let ftzbtc = (tzbtc -. tzbtc') /. tzbtc in + fxtz <= flqt && ftzbtc <= flqt + else true + +(** [is_share_price_increasing env state state'] returns [true] iff + the product of supplies (tzbtc, and xtz) increases. + + See https://blog.nomadic-labs.com/progress-report-on-the-verification-of-liquidity-baking-smart-contracts.html#evolution-of-the-product-of-supplies *) +let is_share_price_increasing env state state' = + let (xtz, tzbtc, lqt) = get_float_balances env state in + let (xtz', tzbtc', lqt') = get_float_balances env state' in + xtz *. tzbtc /. (lqt *. lqt) <= xtz' *. tzbtc' /. (lqt' *. lqt') + +(** [positive_pools env state] returns [true] iff the three pools of + the CPMM (as identified in [env]) are strictly positive in + [state]. *) +let positive_pools env state = + let xtz = SymbolicMachine.get_xtz_balance env.cpmm_contract state in + let tzbtc = SymbolicMachine.get_tzbtc_balance env.cpmm_contract env state in + let lqt = SymbolicMachine.get_cpmm_total_liquidity env state in + 0L < xtz && 0 < tzbtc && 0 < lqt + +(** [validate_xtz_balance c env (blk, state)] returns [true] iff the + tez balance for the contract [c] is the same in [blk] and in + [state]. *) +let validate_xtz_balance : + Contract.t -> ValidationMachine.t -> bool tzresult Lwt.t = + fun contract state -> + ValidationMachine.Symbolic.get_xtz_balance contract state >>=? fun expected -> + ValidationMachine.Concrete.get_xtz_balance contract state >>=? fun amount -> + return (amount = expected) + +(** [validate_tzbtc_balance c env (blk, state)] returns [true] iff the + tzbtc balance for the contract [c] is the same in [blk] and in + [state]. *) +let validate_tzbtc_balance : + Contract.t -> Contract.t env -> ValidationMachine.t -> bool tzresult Lwt.t = + fun contract env state -> + ValidationMachine.Symbolic.get_tzbtc_balance contract env state + >>=? fun expected -> + ValidationMachine.Concrete.get_tzbtc_balance contract env state + >>=? fun amount -> return (expected = amount) + +(** [validate_liquidity_balance c env (blk, state)] returns [true] if + the contract [c] holds the same amount of liquidity in [blk] and + [state]. *) +let validate_liquidity_balance : + Contract.t -> Contract.t env -> ValidationMachine.t -> bool tzresult Lwt.t = + fun contract env state -> + ValidationMachine.Symbolic.get_liquidity_balance contract env state + >>=? fun expected -> + ValidationMachine.Concrete.get_liquidity_balance contract env state + >>=? fun amount -> return (expected = amount) + +(** [validate_balances c env (blk, state)] returns true iff the + contract [c] holds the same amount of tez, tzbtc and liquidity in + [blk] and [state]. *) +let validate_balances : + Contract.t -> Contract.t env -> ValidationMachine.t -> bool tzresult Lwt.t = + fun contract env combined_state -> + all_true + [ + validate_xtz_balance contract combined_state; + validate_tzbtc_balance contract env combined_state; + validate_liquidity_balance contract env combined_state; + ] + +(** [validate_cpmm_total_liquidity env state] returns true iff the + CPMM has distributed the same amount of liquidity tokens in its + concrete and symbolic parts of [state]. *) +let validate_cpmm_total_liquidity env state = + ValidationMachine.Concrete.get_cpmm_total_liquidity env state + >>=? fun concrete_cpmm_total_liquidity -> + ValidationMachine.Symbolic.get_cpmm_total_liquidity env state + >>=? fun ghost_cpmm_total_liquidity -> + return (concrete_cpmm_total_liquidity = ghost_cpmm_total_liquidity) + +(** [validate_consistency env (blk, state)] checks if the accounts in + [env] (the CPMM and the implicit accounts) share the same balances + in [blk] and [state]. *) +let validate_consistency : + Contract.t env -> ValidationMachine.t -> bool tzresult Lwt.t = + (* We do not try to validate the xtz balance of [holder] in this + function. Indeed, they are hard to predict due to allocation + fees, and security deposits. *) + fun env state -> + all_true + (validate_cpmm_total_liquidity env state + :: + validate_balances env.cpmm_contract env state + :: + List.map + (fun account -> validate_balances account env state) + env.implicit_accounts) + +(** [validate_storage env blk] returns [true] iff the storage of the + CPMM contract is consistent wrt. to its actual balances (tez, + tzbtc, and liquidity). *) +let validate_storage : + Contract.t env -> ConcreteMachine.t -> bool tzresult Lwt.t = + fun env blk -> + Cpmm_repr.Storage.get (B blk) ~contract:env.cpmm_contract + >>=? fun cpmm_storage -> + all_true + [ + (* 1. Check the CPMM's [xtzPool] is equal to the actual CPMM balance *) + ( ConcreteMachine.get_xtz_balance env.cpmm_contract blk + >>=? fun cpmm_xtz -> return (cpmm_xtz = Tez.to_mutez cpmm_storage.xtzPool) + ); + (* 2. Check the CPMM’s [lqtTotal] is correct wrt. liquidity contract *) + ( Lqt_fa12_repr.Storage.get (B blk) ~contract:env.liquidity_contract + >>=? fun liquidity_storage -> + return (cpmm_storage.lqtTotal = liquidity_storage.totalSupply) ); + (* 3. Check the CPMM’s [tokenPool] is correct *) + ( ConcreteMachine.get_tzbtc_balance env.cpmm_contract env blk + >>=? fun cpmm_tzbtc -> + return (Z.to_int cpmm_storage.tokenPool = cpmm_tzbtc) ); + ] + +(** [machine_validation_tests] is a list of asynchronous tests aiming + at asserting the correctness and consistencies of the machines + themselves. *) +let machine_validation_tests = + [ + QCheck.Test.make + ~count:10 + ~name:"Concrete/Symbolic Consistency" + (Liquidity_baking_generator.arb_scenario 1_000_000 1_000_000 10) + (fun (specs, scenario) -> + extract_qcheck_tzresult + (let invariant = validate_consistency in + ValidationMachine.build ~invariant specs >>=? fun (state, env) -> + ValidationMachine.run ~invariant scenario env state >>=? fun _ -> + return_unit)); + QCheck.Test.make + ~count:10 + ~name:"Storage consistency" + (Liquidity_baking_generator.arb_scenario 1_000_000 1_000_000 10) + (fun (specs, scenario) -> + extract_qcheck_tzresult + (let invariant = validate_storage in + ConcreteMachine.build ~invariant specs >>=? fun (state, env) -> + ConcreteMachine.run ~invariant scenario env state >>=? fun _ -> + return_unit)); + QCheck.Test.make + ~count:100_000 + ~name:"Positive pools" + (Liquidity_baking_generator.arb_scenario 1_000_000 1_000_000 50) + (fun (specs, scenario) -> + extract_qcheck_tzresult + (let invariant = positive_pools in + let (state, env) = SymbolicMachine.build ~invariant specs in + let _ = SymbolicMachine.run ~invariant scenario env state in + return_unit)); + ] + +(** [economic_tests] is a list of asynchronous tests aiming at + asserting the good economic properties of the Liquidity Baking + feature. *) +let economic_tests = + [ + QCheck.Test.make + ~count:100_000 + ~name:"No global gain" + (Liquidity_baking_generator.arb_adversary_scenario 1_000_000 1_000_000 50) + (fun (specs, attacker, scenario) -> + let (state, env) = SymbolicMachine.build ~subsidy:0L specs in + let _ = + run_and_check (one_balance_decreases attacker env) scenario env state + in + true); + QCheck.Test.make + ~count:100_000 + ~name:"Remove liquidities is consistent" + (Liquidity_baking_generator.arb_scenario 1_000_000 1_000_000 50) + (fun (specs, scenario) -> + let (state, env) = SymbolicMachine.build ~subsidy:0L specs in + let _ = + run_and_check (is_remove_liquidity_consistent env) scenario env state + in + true); + QCheck.Test.make + ~count:100_000 + ~name:"Share price only increases" + (Liquidity_baking_generator.arb_scenario 1_000_000 1_000_000 50) + (fun (specs, scenario) -> + let (state, env) = SymbolicMachine.build ~subsidy:0L specs in + let _ = + run_and_check (is_share_price_increasing env) scenario env state + in + true); + ] + +let _ = + let open Lib_test.Qcheck_helpers in + Alcotest.run + "Liquidity baking PBT" + [ + ("Machines Cross-Validation", qcheck_wrap machine_validation_tests); + ("Economic Properties", qcheck_wrap economic_tests); + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/main.ml b/src/proto_011_PtHangzH/lib_protocol/test/main.ml new file mode 100644 index 000000000000..028381e7ab9a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/main.ml @@ -0,0 +1,72 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol + Invocation: dune build @src/proto_alpha/lib_protocol/runtest + Subject: Entrypoint +*) + +let () = + Alcotest_lwt.run + "protocol_011_PtHangzH" + [ + ("transfer", Test_transfer.tests); + ("origination", Test_origination.tests); + ("activation", Test_activation.tests); + ("revelation", Test_reveal.tests); + ("baking module", Test_baking_module.tests); + ("endorsement", Test_endorsement.tests); + ("double endorsement", Test_double_endorsement.tests); + ("double baking", Test_double_baking.tests); + ("seed", Test_seed.tests); + ("baking", Test_baking.tests); + ("delegation", Test_delegation.tests); + ("rolls", Test_rolls.tests); + ("combined", Test_combined_operations.tests); + ("qty", Test_qty.tests); + ("voting", Test_voting.tests); + ("interpretation", Test_interpretation.tests); + ("typechecking", Test_typechecking.tests); + ("fixed point computation", Test_fixed_point.tests); + ("gas levels", Test_gas_levels.tests); + ("saturation arithmetic", Test_saturation.tests); + ("gas cost functions", Test_gas_costs.tests); + ("lazy storage diff", Test_lazy_storage_diff.tests); + ("global table of constants", Test_global_constants_storage.tests); + ("sapling", Test_sapling.tests); + ("helpers rpcs", Test_helpers_rpcs.tests); + ("failing_noop operation", Test_failing_noop.tests); + ("storage description", Test_storage.tests); + ("time", Test_time_repr.tests); + ("constants", Test_constants.tests); + ("level module", Test_level_module.tests); + ("liquidity baking", Test_liquidity_baking.tests); + ("temp big maps", Test_temp_big_maps.tests); + ("timelock", Test_timelock.tests); + ("script typed ir size", Test_script_typed_ir_size.tests); + ] + |> Lwt_main.run diff --git a/src/proto_011_PtHangzH/lib_protocol/test/saturation_fuzzing.ml b/src/proto_011_PtHangzH/lib_protocol/test/saturation_fuzzing.ml new file mode 100644 index 000000000000..88672c7527c3 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/saturation_fuzzing.ml @@ -0,0 +1,183 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol Library + Invocation: dune build @src/proto_alpha/lib_protocol/runtest_saturation_fuzzing + Subject: Operations in Saturation_repr +*) + +open Protocol.Saturation_repr +open Lib_test.Qcheck_helpers + +(** A generator that returns a [t] that cannot be [saturated] *) +let unsatured_arb = of_option_arb @@ QCheck.map of_int_opt QCheck.int + +(** The general generator for [t]: generates both unsaturated values + and [saturated]. *) +let t_arb : may_saturate t QCheck.arbitrary = + QCheck.frequency [(1, QCheck.always saturated); (4, unsatured_arb)] + +(* Test. + * Tests that [add] commutes. + *) +let test_add_commutes = + QCheck.Test.make + ~name:"t1 + t2 = t2 + t1" + (QCheck.pair t_arb t_arb) + (fun (t1, t2) -> + let t1_plus_t2 = add t1 t2 in + let t2_plus_t1 = add t2 t1 in + qcheck_eq ~pp t1_plus_t2 t2_plus_t1) + +(* Test. + * Tests that [mul] commutes. + *) +let test_mul_commutes = + QCheck.Test.make + ~name:"t1 * t2 = t2 * t1" + (QCheck.pair t_arb t_arb) + (fun (t1, t2) -> + let t1_times_t2 = mul t1 t2 in + let t2_times_t1 = mul t2 t1 in + qcheck_eq ~pp t1_times_t2 t2_times_t1) + +(* Test. + * Tests that [zero] is neutral for [add]. + *) +let test_add_zero = + QCheck.Test.make ~name:"t + 0 = t" t_arb (fun t -> + let t_plus_zero = add t zero in + qcheck_eq' ~pp ~expected:t ~actual:t_plus_zero ()) + +(* Test. + * Tests that t1 + t2 >= t1 + *) +let test_add_neq = + QCheck.Test.make + ~name:"t1 + t2 >= t1" + (QCheck.pair t_arb t_arb) + (fun (t1, t2) -> + let t1_plus_t2 = add t1 t2 in + t1_plus_t2 >= t1) + +(* Test. + * Tests that 1 is neutral for [mul]. + *) +let test_mul_one = + let one = safe_int 1 in + QCheck.Test.make ~name:"t * 1 = t" t_arb (fun t -> + let t_times_one = mul t one in + qcheck_eq' ~pp ~expected:t ~actual:t_times_one ()) + +(* Test. + * Tests that [t] times [0] equals [0]. + *) +let test_mul_zero = + QCheck.Test.make ~name:"t * 0 = 0" t_arb (fun t -> + let t_times_zero = mul t zero in + qcheck_eq' ~pp ~expected:zero ~actual:t_times_zero ()) + +(* Test. + * Tests that [t] [sub] [zero] equals [t]. + *) +let test_sub_zero = + QCheck.Test.make ~name:"t - 0 = t" t_arb (fun t -> + let t_sub_zero = sub t zero in + qcheck_eq' ~pp ~expected:t ~actual:t_sub_zero ()) + +(* Test. + * Tests that [t] [sub] [t] equals [zero]. + *) +let test_sub_itself = + QCheck.Test.make ~name:"t - t = 0" t_arb (fun t -> + let t_sub_t = sub t t in + qcheck_eq' ~pp ~expected:zero ~actual:t_sub_t ()) + +(* Test. + * Tests that t1 - t2 <= t1 + *) +let test_sub_neq = + QCheck.Test.make + ~name:"t1 - t2 <= t1" + (QCheck.pair t_arb t_arb) + (fun (t1, t2) -> + let t1_minus_t2 = sub t1 t2 in + t1_minus_t2 <= t1) + +(* Test. + * Tests that (t1 + t2) - t2 <= t1 + *) +let test_add_sub = + QCheck.Test.make + ~name:"(t1 + t2) - t2 <= t1" + (QCheck.pair t_arb t_arb) + (fun (t1, t2) -> + let lhs = sub (add t1 t2) t2 in + lhs <= t1) + +(* Test. + * Tests that (t1 - t2) + t2 >= t1 + *) +let test_sub_add = + QCheck.Test.make + ~name:"(t1 - t2) + t2 >= t1" + (QCheck.pair t_arb t_arb) + (fun (t1, t2) -> + let lhs = add (sub t1 t2) t2 in + lhs >= t1) + +(* Test. + * Tests that [saturated] >= t + *) +let test_leq_saturated = + QCheck.Test.make ~name:"t <= saturated" t_arb (fun t -> saturated >= t) + +(* Test. + * Tests that [zero] <= t + *) +let test_geq_zero = QCheck.Test.make ~name:"t >= 0" t_arb (fun t -> zero <= t) + +let tests_add = [test_add_commutes; test_add_zero; test_add_neq] + +let tests_mul = [test_mul_commutes; test_mul_one; test_mul_zero] + +let tests_sub = [test_sub_zero; test_sub_itself; test_sub_neq] + +let tests_add_sub = [test_add_sub; test_sub_add] + +let tests_boundaries = [test_leq_saturated; test_geq_zero] + +let tests = + Alcotest.run + "Saturation" + [ + ("add", qcheck_wrap tests_add); + ("mul", qcheck_wrap tests_mul); + ("sub", qcheck_wrap tests_sub); + ("add and sub", qcheck_wrap tests_add_sub); + ("<= and >=", qcheck_wrap tests_boundaries); + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_activation.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_activation.ml new file mode 100644 index 000000000000..5bce68bc6b03 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_activation.ml @@ -0,0 +1,584 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (activation) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^activation$" + Subject: The activation operation creates an implicit contract from a + registered commitment present in the context. It is + parametrized by a public key hash (pkh) and a secret. + + The commitments are composed of : + - a blinded pkh that can be revealed by the secret ; + - an amount. + + The commitments and the secrets are generated from + /scripts/create_genesis/create_genesis.py and should be + coherent. +*) + +open Protocol +open Alpha_context +open Test_tez + +(* Generated commitments and secrets *) + +(* Commitments are hard-coded in {Tezos_proto_alpha_parameters.Default_parameters} *) + +(* let commitments = + * List.map (fun (bpkh, a) -> + * Commitment_repr.{ + * blinded_public_key_hash=Blinded_public_key_hash.of_b58check_exn bpkh ; + * amount = Tez_repr.of_mutez_exn (Int64.of_string a)} + * ) + * [ ( "btz1bRL4X5BWo2Fj4EsBdUwexXqgTf75uf1qa", "23932454669343" ) ; + * ( "btz1SxjV1syBgftgKy721czKi3arVkVwYUFSv", "72954577464032" ) ; + * ( "btz1LtoNCjiW23txBTenALaf5H6NKF1L3c1gw", "217487035428349" ) ; + * ( "btz1SUd3mMhEBcWudrn8u361MVAec4WYCcFoy", "4092742372031" ) ; + * ( "btz1MvBXf4orko1tsGmzkjLbpYSgnwUjEe81r", "17590039016550" ) ; + * ( "btz1LoDZ3zsjgG3k3cqTpUMc9bsXbchu9qMXT", "26322312350555" ) ; + * ( "btz1RMfq456hFV5AeDiZcQuZhoMv2dMpb9hpP", "244951387881443" ) ; + * ( "btz1Y9roTh4A7PsMBkp8AgdVFrqUDNaBE59y1", "80065050465525" ) ; + * ( "btz1Q1N2ePwhVw5ED3aaRVek6EBzYs1GDkSVD", "3569618927693" ) ; + * ( "btz1VFFVsVMYHd5WfaDTAt92BeQYGK8Ri4eLy", "9034781424478" ) ; + * ] *) + +type secret_account = { + account : public_key_hash; + activation_code : Blinded_public_key_hash.activation_code; + amount : Tez.t; +} + +let secrets () = + (* Exported from proto_alpha client - TODO : remove when relocated to lib_crypto *) + let read_key mnemonic email password = + match Tezos_client_base.Bip39.of_words mnemonic with + | None -> assert false + | Some t -> + (* TODO: unicode normalization (NFKD)... *) + let passphrase = Bytes.(cat (of_string email) (of_string password)) in + let sk = Tezos_client_base.Bip39.to_seed ~passphrase t in + let sk = Bytes.sub sk 0 32 in + let sk : Signature.Secret_key.t = + Ed25519 + (Data_encoding.Binary.of_bytes_exn Ed25519.Secret_key.encoding sk) + in + let pk = Signature.Secret_key.to_public_key sk in + let pkh = Signature.Public_key.hash pk in + (pkh, pk, sk) + in + List.map + (fun (mnemonic, secret, amount, pkh, password, email) -> + let (pkh', pk, sk) = read_key mnemonic email password in + let pkh = Signature.Public_key_hash.of_b58check_exn pkh in + assert (Signature.Public_key_hash.equal pkh pkh') ; + let account = Account.{pkh; pk; sk} in + Account.add_account account ; + { + account = account.pkh; + activation_code = Blinded_public_key_hash.activation_code_of_hex secret; + amount = + WithExceptions.Option.to_exn + ~none:(Invalid_argument "tez conversion") + (Tez.of_mutez (Int64.of_string amount)); + }) + [ + ( [ + "envelope"; + "hospital"; + "mind"; + "sunset"; + "cancel"; + "muscle"; + "leisure"; + "thumb"; + "wine"; + "market"; + "exit"; + "lucky"; + "style"; + "picnic"; + "success"; + ], + "0f39ed0b656509c2ecec4771712d9cddefe2afac", + "23932454669343", + "tz1MawerETND6bqJqx8GV3YHUrvMBCDasRBF", + "z0eZHQQGKt", + "cjgfoqmk.wpxnvnup@tezos.example.org" ); + ( [ + "flag"; + "quote"; + "will"; + "valley"; + "mouse"; + "chat"; + "hold"; + "prosper"; + "silk"; + "tent"; + "cruel"; + "cause"; + "demise"; + "bottom"; + "practice"; + ], + "41f98b15efc63fa893d61d7d6eee4a2ce9427ac4", + "72954577464032", + "tz1X4maqF9tC1Yn4jULjHRAyzjAtc25Z68TX", + "MHErskWPE6", + "oklmcktr.ztljnpzc@tezos.example.org" ); + ( [ + "library"; + "away"; + "inside"; + "paper"; + "wise"; + "focus"; + "sweet"; + "expose"; + "require"; + "change"; + "stove"; + "planet"; + "zone"; + "reflect"; + "finger"; + ], + "411dfef031eeecc506de71c9df9f8e44297cf5ba", + "217487035428348", + "tz1SWBY7rWMutEuWS54Pt33MkzAS6eWkUuTc", + "0AO6BzQNfN", + "ctgnkvqm.kvtiybky@tezos.example.org" ); + ( [ + "cruel"; + "fluid"; + "damage"; + "demand"; + "mimic"; + "above"; + "village"; + "alpha"; + "vendor"; + "staff"; + "absent"; + "uniform"; + "fire"; + "asthma"; + "milk"; + ], + "08d7d355bc3391d12d140780b39717d9f46fcf87", + "4092742372031", + "tz1amUjiZaevaxQy5wKn4SSRvVoERCip3nZS", + "9kbZ7fR6im", + "bnyxxzqr.tdszcvqb@tezos.example.org" ); + ( [ + "opera"; + "divorce"; + "easy"; + "myself"; + "idea"; + "aim"; + "dash"; + "scout"; + "case"; + "resource"; + "vote"; + "humor"; + "ticket"; + "client"; + "edge"; + ], + "9b7cad042fba557618bdc4b62837c5f125b50e56", + "17590039016550", + "tz1Zaee3QBtD4ErY1SzqUvyYTrENrExu6yQM", + "suxT5H09yY", + "iilkhohu.otnyuvna@tezos.example.org" ); + ( [ + "token"; + "similar"; + "ginger"; + "tongue"; + "gun"; + "sort"; + "piano"; + "month"; + "hotel"; + "vote"; + "undo"; + "success"; + "hobby"; + "shell"; + "cart"; + ], + "124c0ca217f11ffc6c7b76a743d867c8932e5afd", + "26322312350555", + "tz1geDUUhfXK1EMj7VQdRjug1MoFe6gHWnCU", + "4odVdLykaa", + "kwhlglvr.slriitzy@tezos.example.org" ); + ( [ + "shield"; + "warrior"; + "gorilla"; + "birth"; + "steak"; + "neither"; + "feel"; + "only"; + "liberty"; + "float"; + "oven"; + "extend"; + "pulse"; + "suffer"; + "vapor"; + ], + "ac7a2125beea68caf5266a647f24dce9fea018a7", + "244951387881443", + "tz1h3nY7jcZciJgAwRhWcrEwqfVp7VQoffur", + "A6yeMqBFG8", + "lvrmlbyj.yczltcxn@tezos.example.org" ); + ( [ + "waste"; + "open"; + "scan"; + "tip"; + "subway"; + "dance"; + "rent"; + "copper"; + "garlic"; + "laundry"; + "defense"; + "clerk"; + "another"; + "staff"; + "liar"; + ], + "2b3e94be133a960fa0ef87f6c0922c19f9d87ca2", + "80065050465525", + "tz1VzL4Xrb3fL3ckvqCWy6bdGMzU2w9eoRqs", + "oVZqpq60sk", + "rfodmrha.zzdndvyk@tezos.example.org" ); + ( [ + "fiber"; + "next"; + "property"; + "cradle"; + "silk"; + "obey"; + "gossip"; + "push"; + "key"; + "second"; + "across"; + "minimum"; + "nice"; + "boil"; + "age"; + ], + "dac31640199f2babc157aadc0021cd71128ca9ea", + "3569618927693", + "tz1RUHg536oRKhPLFfttcB5gSWAhh4E9TWjX", + "FfytQTTVbu", + "owecikdy.gxnyttya@tezos.example.org" ); + ( [ + "print"; + "labor"; + "budget"; + "speak"; + "poem"; + "diet"; + "chunk"; + "eternal"; + "book"; + "saddle"; + "pioneer"; + "ankle"; + "happy"; + "only"; + "exclude"; + ], + "bb841227f250a066eb8429e56937ad504d7b34dd", + "9034781424478", + "tz1M1LFbgctcPWxstrao9aLr2ECW1fV4pH5u", + "zknAl3lrX2", + "ettilrvh.zsrqrbud@tezos.example.org" ); + ] + +(** Helper: Create a genesis block with predefined commitments, + accounts and balances. *) +let activation_init () = + Context.init ~with_commitments:true 1 >|=? fun (b, cs) -> + secrets () |> fun ss -> (b, cs, ss) + +(** Verify the genesis block created by [activation_init] can be + baked. *) +let test_simple_init_with_commitments () = + activation_init () >>=? fun (blk, _contracts, _secrets) -> + Block.bake blk >>=? fun _ -> return_unit + +(** A single activation *) +let test_single_activation () = + activation_init () >>=? fun (blk, _contracts, secrets) -> + let ({account; activation_code; amount = expected_amount; _} as _first_one) = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd secrets + in + (* Contract does not exist *) + Assert.balance_is + ~loc:__LOC__ + (B blk) + (Contract.implicit_contract account) + Tez.zero + >>=? fun () -> + Op.activation (B blk) account activation_code >>=? fun operation -> + Block.bake ~operation blk >>=? fun blk -> + (* Contract does exist *) + Assert.balance_is + ~loc:__LOC__ + (B blk) + (Contract.implicit_contract account) + expected_amount + +(** 10 activations, one per bake. *) +let test_multi_activation_1 () = + activation_init () >>=? fun (blk, _contracts, secrets) -> + List.fold_left_es + (fun blk {account; activation_code; amount = expected_amount; _} -> + Op.activation (B blk) account activation_code >>=? fun operation -> + Block.bake ~operation blk >>=? fun blk -> + Assert.balance_is + ~loc:__LOC__ + (B blk) + (Contract.implicit_contract account) + expected_amount + >|=? fun () -> blk) + blk + secrets + >>=? fun _ -> return_unit + +(** All of the 10 activations occur in one bake. *) +let test_multi_activation_2 () = + activation_init () >>=? fun (blk, _contracts, secrets) -> + List.fold_left_es + (fun ops {account; activation_code; _} -> + Op.activation (B blk) account activation_code >|=? fun op -> op :: ops) + [] + secrets + >>=? fun ops -> + Block.bake ~operations:ops blk >>=? fun blk -> + List.iter_es + (fun {account; amount = expected_amount; _} -> + (* Contract does exist *) + Assert.balance_is + ~loc:__LOC__ + (B blk) + (Contract.implicit_contract account) + expected_amount) + secrets + +(** Transfer with activated account. *) +let test_activation_and_transfer () = + activation_init () >>=? fun (blk, contracts, secrets) -> + let ({account; activation_code; _} as _first_one) = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd secrets + in + let bootstrap_contract = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd contracts + in + let first_contract = Contract.implicit_contract account in + Op.activation (B blk) account activation_code >>=? fun operation -> + Block.bake ~operation blk >>=? fun blk -> + Context.Contract.balance (B blk) bootstrap_contract >>=? fun amount -> + Tez.( /? ) amount 2L >>?= fun half_amount -> + Context.Contract.balance (B blk) first_contract + >>=? fun activated_amount_before -> + Op.transaction (B blk) bootstrap_contract first_contract half_amount + >>=? fun operation -> + Block.bake ~operation blk >>=? fun blk -> + Assert.balance_was_credited + ~loc:__LOC__ + (B blk) + (Contract.implicit_contract account) + activated_amount_before + half_amount + +(** Transfer to an unactivated account and then activating it. *) +let test_transfer_to_unactivated_then_activate () = + activation_init () >>=? fun (blk, contracts, secrets) -> + let ({account; activation_code; amount} as _first_one) = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd secrets + in + let bootstrap_contract = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd contracts + in + let unactivated_commitment_contract = Contract.implicit_contract account in + Context.Contract.balance (B blk) bootstrap_contract >>=? fun b_amount -> + Tez.( /? ) b_amount 2L >>?= fun b_half_amount -> + Incremental.begin_construction blk >>=? fun inc -> + Op.transaction + (I inc) + bootstrap_contract + unactivated_commitment_contract + b_half_amount + >>=? fun op -> + Incremental.add_operation inc op >>=? fun inc -> + Op.activation (I inc) account activation_code >>=? fun op' -> + Incremental.add_operation inc op' >>=? fun inc -> + Incremental.finalize_block inc >>=? fun blk2 -> + Assert.balance_was_credited + ~loc:__LOC__ + (B blk2) + (Contract.implicit_contract account) + amount + b_half_amount + +(****************************************************************) +(* The following test scenarios are supposed to raise errors. *) +(****************************************************************) + +(** Invalid pkh activation: expected to fail as the context does not + contain any commitment. *) +let test_invalid_activation_with_no_commitments () = + Context.init 1 >>=? fun (blk, _) -> + let secrets = secrets () in + let ({account; activation_code; _} as _first_one) = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd secrets + in + Op.activation (B blk) account activation_code >>=? fun operation -> + Block.bake ~operation blk >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Invalid_activation _ -> true + | _ -> false) + +(** Wrong activation: wrong secret given in the operation. *) +let test_invalid_activation_wrong_secret () = + activation_init () >>=? fun (blk, _, secrets) -> + let ({account; _} as _first_one) = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth secrets 0 + in + let ({activation_code; _} as _second_one) = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth secrets 1 + in + Op.activation (B blk) account activation_code >>=? fun operation -> + Block.bake ~operation blk >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Invalid_activation _ -> true + | _ -> false) + +(** Invalid pkh activation : expected to fail as the context does not + contain an associated commitment. *) +let test_invalid_activation_inexistent_pkh () = + activation_init () >>=? fun (blk, _, secrets) -> + let ({activation_code; _} as _first_one) = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd secrets + in + let inexistent_pkh = + Signature.Public_key_hash.of_b58check_exn + "tz1PeQHGKPWSpNoozvxgqLN9TFsj6rDqNV3o" + in + Op.activation (B blk) inexistent_pkh activation_code >>=? fun operation -> + Block.bake ~operation blk >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Invalid_activation _ -> true + | _ -> false) + +(** Invalid pkh activation : expected to fail as the commitment has + already been claimed. *) +let test_invalid_double_activation () = + activation_init () >>=? fun (blk, _, secrets) -> + let ({account; activation_code; _} as _first_one) = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd secrets + in + Incremental.begin_construction blk >>=? fun inc -> + Op.activation (I inc) account activation_code >>=? fun op -> + Incremental.add_operation inc op >>=? fun inc -> + Op.activation (I inc) account activation_code >>=? fun op' -> + Incremental.add_operation inc op' >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Invalid_activation _ -> true + | _ -> false) + +(** Transfer from an unactivated commitment account. *) +let test_invalid_transfer_from_unactivated_account () = + activation_init () >>=? fun (blk, contracts, secrets) -> + let ({account; _} as _first_one) = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd secrets + in + let bootstrap_contract = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd contracts + in + let unactivated_commitment_contract = Contract.implicit_contract account in + (* No activation *) + Op.transaction + (B blk) + unactivated_commitment_contract + bootstrap_contract + Tez.one + >>=? fun operation -> + Block.bake ~operation blk >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Contract_storage.Empty_implicit_contract pkh -> + if pkh = account then true else false + | _ -> false) + +let tests = + [ + Tztest.tztest + "init with commitments" + `Quick + test_simple_init_with_commitments; + Tztest.tztest "single activation" `Quick test_single_activation; + Tztest.tztest "multi-activation one-by-one" `Quick test_multi_activation_1; + Tztest.tztest + "multi-activation all at a time" + `Quick + test_multi_activation_2; + Tztest.tztest "activation and transfer" `Quick test_activation_and_transfer; + Tztest.tztest + "transfer to unactivated account then activate" + `Quick + test_transfer_to_unactivated_then_activate; + Tztest.tztest + "invalid activation with no commitments" + `Quick + test_invalid_activation_with_no_commitments; + Tztest.tztest + "invalid activation with commitments" + `Quick + test_invalid_activation_inexistent_pkh; + Tztest.tztest + "invalid double activation" + `Quick + test_invalid_double_activation; + Tztest.tztest + "wrong activation code" + `Quick + test_invalid_activation_wrong_secret; + Tztest.tztest + "invalid transfer from unactivated account" + `Quick + test_invalid_transfer_from_unactivated_account; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_baking.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_baking.ml new file mode 100644 index 000000000000..f125046ba7ef --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_baking.ml @@ -0,0 +1,286 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (baking) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^baking$" + Subject: Rewards and bakers. Tests based on RPCs. +*) + +open Protocol +open Alpha_context + +(** Verify the level is correctly computed when the first cycle is + passed and after baking a certain fixed number of blocks (10 for + the moment). The result should be [blocks_per_cycle + 10] where + [blocks_per_cycle] comes from the constants of the selected + protocol. + + IMPROVEMENTS: + - Randomize the number of cycle. + - Randomize the number of accounts created at the beginning + - Randomize the blocks per cycle. + - Randomize the number of blocks baked after the n cycles baked + previously. *) +let test_cycle () = + Context.init 5 >>=? fun (b, _) -> + Context.get_constants (B b) >>=? fun csts -> + let blocks_per_cycle = csts.parametric.blocks_per_cycle in + let pp fmt x = Format.fprintf fmt "%ld" x in + Block.bake b >>=? fun b -> + Block.bake_until_cycle_end b >>=? fun b -> + Context.get_level (B b) >>?= fun curr_level -> + Assert.equal + ~loc:__LOC__ + Int32.equal + "not the right level" + pp + (Alpha_context.Raw_level.to_int32 curr_level) + blocks_per_cycle + >>=? fun () -> + Context.get_level (B b) >>?= fun l -> + Block.bake_n 10 b >>=? fun b -> + Context.get_level (B b) >>?= fun curr_level -> + Assert.equal + ~loc:__LOC__ + Int32.equal + "not the right level" + pp + (Alpha_context.Raw_level.to_int32 curr_level) + (Int32.add (Alpha_context.Raw_level.to_int32 l) 10l) + +(** After baking and/or endorsing a block, the baker and the endorsers + get their reward. *) +let test_rewards_retrieval () = + let endorsers_per_block = 32 in + (* we want to have sufficient accounts so that find_block succeeds *) + Context.init (endorsers_per_block * 10) ~endorsers_per_block + >>=? fun (b, _) -> + Context.get_constants (B b) + >>=? fun Constants. + { + parametric = + { + endorsers_per_block; + block_security_deposit; + endorsement_security_deposit; + _; + }; + _; + } -> + (* find block with endorsers_per_block different endorsers *) + let open Plugin.RPC.Endorsing_rights in + let rec find_block b = + Context.get_endorsers (B b) >>=? fun endorsers -> + if List.compare_length_with endorsers endorsers_per_block = 0 then return b + else Block.bake b >>=? fun b -> find_block b + in + let balance_update delegate before after = + Context.Delegate.info (B before) delegate >>=? fun info_before -> + Context.Delegate.info (B after) delegate >>=? fun info_after -> + Lwt.return + Test_tez.Tez.(info_after.frozen_balance -? info_before.frozen_balance) + in + find_block b >>=? fun good_b -> + Context.get_endorsers (B good_b) >>=? fun endorsers -> + (* test 3 different priorities, too long otherwise *) + let block_priorities = 0 -- 2 in + let included_endorsements = 0 -- endorsers_per_block in + let ranges = List.product block_priorities included_endorsements in + List.iter_es + (fun (priority, endorsing_power) -> + (* bake block at given priority and with given endorsing_power *) + let real_endorsers = List.sub endorsers endorsing_power in + List.map_ep + (fun endorser -> + Op.endorsement_with_slot + ~delegate:(endorser.delegate, endorser.slots) + (B good_b) + () + >|=? fun operation -> Operation.pack operation) + real_endorsers + >>=? fun operations -> + let policy = Block.By_priority priority in + Block.get_next_baker ~policy good_b >>=? fun (baker, _, _) -> + Block.bake ~policy ~operations good_b >>=? fun b -> + Context.get_baking_reward (B b) ~priority ~endorsing_power + >>=? fun baking_reward -> + Test_tez.Tez.(block_security_deposit +? baking_reward) + >>?= fun baking_frozen_balance -> + Context.get_endorsing_reward (B b) ~priority ~endorsing_power:1 + >>=? fun endorsing_reward -> + Test_tez.Tez.(endorsement_security_deposit +? endorsing_reward) + >>?= fun endorsing_frozen_balance -> + let baker_is_not_an_endorser = + List.for_all (fun endorser -> endorser.delegate <> baker) real_endorsers + in + Test_tez.Tez.(baking_frozen_balance +? endorsing_frozen_balance) + >>?= fun accumulated_frozen_balance -> + (* check the baker was rewarded the right amount *) + balance_update baker good_b b >>=? fun baker_frozen_balance -> + (if baker_is_not_an_endorser then + Assert.equal_tez ~loc:__LOC__ baker_frozen_balance baking_frozen_balance + else + Assert.equal_tez + ~loc:__LOC__ + baker_frozen_balance + accumulated_frozen_balance) + >>=? fun () -> + (* check the each endorser was rewarded the right amount *) + List.iter_ep + (fun endorser -> + balance_update endorser.delegate good_b b + >>=? fun endorser_frozen_balance -> + if baker <> endorser.delegate then + Assert.equal_tez + ~loc:__LOC__ + endorser_frozen_balance + endorsing_frozen_balance + else + Assert.equal_tez + ~loc:__LOC__ + endorser_frozen_balance + accumulated_frozen_balance) + real_endorsers) + ranges + +(** Checks the baking and endorsing rewards formulas against a precomputed + table. *) +let test_rewards_formulas () = + Context.init 1 >>=? fun (b, _) -> + Context.get_constants (B b) + >>=? fun Constants.{parametric = {endorsers_per_block; _}; _} -> + let block_priorities = 0 -- 2 in + let included_endorsements = 0 -- endorsers_per_block in + let ranges = List.product block_priorities included_endorsements in + List.iter_ep + (fun (priority, endorsing_power) -> + Context.get_baking_reward (B b) ~priority ~endorsing_power + >>=? fun reward -> + let expected_reward = + Test_tez.Tez.of_mutez_exn + (Int64.of_int Rewards.baking_rewards.(priority).(endorsing_power)) + in + Assert.equal_tez ~loc:__LOC__ reward expected_reward >>=? fun () -> + Context.get_endorsing_reward (B b) ~priority ~endorsing_power + >>=? fun reward -> + let expected_reward = + Test_tez.Tez.of_mutez_exn + (Int64.of_int Rewards.endorsing_rewards.(priority).(endorsing_power)) + in + Assert.equal_tez ~loc:__LOC__ reward expected_reward >>=? fun () -> + return_unit) + ranges + +let wrap e = Lwt.return (Environment.wrap_tzresult e) + +(** Check that the rewards formulas from Context are equivalent with + the ones from Baking. *) +let test_rewards_formulas_equivalence () = + Context.init 1 >>=? fun (b, _) -> + Context.get_constants (B b) + >>=? fun Constants.{parametric = {endorsers_per_block; _}; _} -> + Alpha_context.prepare + b.context + ~level:b.header.shell.level + ~predecessor_timestamp:b.header.shell.timestamp + ~timestamp:b.header.shell.timestamp + ~fitness:b.header.shell.fitness + >>= wrap + >>=? fun (ctxt, _, _) -> + let block_priorities = 0 -- 64 in + let endorsing_power = 0 -- endorsers_per_block in + let ranges = List.product block_priorities endorsing_power in + List.iter_ep + (fun (block_priority, endorsing_power) -> + Baking.baking_reward + ctxt + ~block_priority + ~included_endorsements:endorsing_power + |> wrap + >>=? fun reward1 -> + Context.get_baking_reward (B b) ~priority:block_priority ~endorsing_power + >>=? fun reward2 -> + Assert.equal_tez ~loc:__LOC__ reward1 reward2 >>=? fun () -> + Baking.endorsing_reward ctxt ~block_priority endorsing_power |> wrap + >>=? fun reward1 -> + Context.get_endorsing_reward + (B b) + ~priority:block_priority + ~endorsing_power + >>=? fun reward2 -> Assert.equal_tez ~loc:__LOC__ reward1 reward2) + ranges + +(** Test baking [n] cycles in a raw works smoothly. *) +let test_bake_n_cycles n () = + let open Block in + let policy = By_priority 0 in + Context.init 1 >>=? fun (block, _contracts) -> + Block.bake_until_n_cycle_end ~policy n block >>=? fun _block -> return () + +(** Check the voting power is constant between cycles when number of + rolls are constant and in presence of one account. *) +let test_voting_power_cache () = + let open Block in + let policy = By_priority 0 in + Context.init 1 >>=? fun (block, _contracts) -> + Context.get_bakers (B block) >>=? fun bakers -> + let baker = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bakers in + let assert_voting_power n block = + let ctxt = Context.B block in + Context.get_voting_power ctxt baker >>=? fun voting_power -> + Assert.equal_int ~loc:__LOC__ n (Int32.to_int voting_power) + in + assert_voting_power 500 block >>=? fun () -> + Block.bake_until_n_cycle_end ~policy 2 block >>=? fun block -> + assert_voting_power 500 block >>=? fun () -> + Block.bake_until_n_cycle_end ~policy 5 block >>=? fun block -> + assert_voting_power 500 block >>=? fun () -> + Block.bake_until_n_cycle_end ~policy 1 block >>=? fun block -> + assert_voting_power 500 block + +let tests = + [ + Tztest.tztest "cycle" `Quick test_cycle; + Tztest.tztest + "test rewards are correctly accounted for" + `Slow + test_rewards_retrieval; + Tztest.tztest + "test rewards formula for various input values" + `Quick + test_rewards_formulas; + Tztest.tztest + "check equivalence of rewards formulas" + `Quick + test_rewards_formulas_equivalence; + Tztest.tztest + "test_bake_n_cycles for 12 cycles" + `Quick + (test_bake_n_cycles 12); + Tztest.tztest "voting_power" `Quick test_voting_power_cache; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_baking_module.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_baking_module.ml new file mode 100644 index 000000000000..36768906af6e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_baking_module.ml @@ -0,0 +1,175 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (baking) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^baking module$" + Subject: some functions in the Baking module +*) + +open Protocol +open Alpha_context + +let minimal_time ~bd ~dp ~md ~p = if p = 0 then md else bd + (p * dp) + +let emmystar_delay ~te ~ie ~md ~bd ~dp ~de ~p ~e = + if p = 0 && e >= 3 * te / 5 then md else bd + (p * dp) + (de * max 0 (ie - e)) + +(* We test with three sets of constants: + - the test constants, which are the default ones in this test framework + - the mainnet constants + - the sandbox constants + For the last two, the values are picked manually, which means these + values may get out of sync with the real values. + (Actually, there are currently only two sets of relevant constants, as + the values of the relevant test and sandbox constants coincide.) *) +let test_minimal_time () = + Context.init 1 >>=? fun (b, _) -> + Context.get_constants (B b) >>=? fun constants -> + let bd = + Stdlib.List.hd constants.parametric.time_between_blocks + |> Period.to_seconds |> Int64.to_int + in + let dp = + Stdlib.List.nth constants.parametric.time_between_blocks 1 + |> Period.to_seconds |> Int64.to_int + in + let md = + constants.parametric.minimal_block_delay |> Period.to_seconds + |> Int64.to_int + in + let prio_range = [0; 1; 2; 3] in + let bd_dp_range = [(bd, dp); (60, 40)] in + let md_range = [md; 30] in + let range = + List.product prio_range (Stdlib.List.combine bd_dp_range md_range) + in + List.iter_es + (fun (priority, ((bd, dp), md)) -> + Context.init + ~time_between_blocks: + [ + Period.of_seconds_exn (Int64.of_int bd); + Period.of_seconds_exn (Int64.of_int dp); + ] + ~minimal_block_delay:(Period.of_seconds_exn (Int64.of_int md)) + 1 + >>=? fun (b, _) -> + Context.get_constants (B b) >>=? fun constants -> + Baking.minimal_time + constants.parametric + ~priority + b.header.shell.timestamp + |> Environment.wrap_tzresult + >>?= fun ts -> + let expected_ts = + Time.Protocol.add + b.header.shell.timestamp + (Int64.of_int (minimal_time ~bd ~dp ~md ~p:priority)) + in + Assert.equal_int64 + ~loc:__LOC__ + (Time.Protocol.to_seconds ts) + (Time.Protocol.to_seconds expected_ts)) + range + +(* Same comment as for the previous test. *) +let test_minimal_valid_time () = + Context.init 1 >>=? fun (b, _) -> + Context.get_constants (B b) >>=? fun constants -> + let md = + constants.parametric.minimal_block_delay |> Period.to_seconds + |> Int64.to_int + in + let bd = + Stdlib.List.nth constants.parametric.time_between_blocks 0 + |> Period.to_seconds |> Int64.to_int + in + let dp = + Stdlib.List.nth constants.parametric.time_between_blocks 1 + |> Period.to_seconds |> Int64.to_int + in + let de = + constants.parametric.delay_per_missing_endorsement |> Period.to_seconds + |> Int64.to_int + in + let te_range = [constants.parametric.endorsers_per_block] in + let ie_range = [constants.parametric.initial_endorsers; 192] in + let md_range = [md; 30] in + let bd_dp_range = [(bd, dp); (60, 40)] in + let de_range = [de; 8] in + let p_range = 0 -- 2 in + let e_range = 0 -- constants.parametric.endorsers_per_block in + let range = + List.product + p_range + (List.product + e_range + (List.product + te_range + (Stdlib.List.combine + ie_range + (Stdlib.List.combine + md_range + (Stdlib.List.combine bd_dp_range de_range))))) + in + List.iter_es + (fun (p, (e, (te, (ie, (md, ((bd, dp), de)))))) -> + Context.init + ~endorsers_per_block:te + ~time_between_blocks: + [ + Period.of_seconds_exn (Int64.of_int bd); + Period.of_seconds_exn (Int64.of_int dp); + ] + ~minimal_block_delay:(Period.of_seconds_exn (Int64.of_int md)) + ~initial_endorsers:ie + ~delay_per_missing_endorsement:(Period.of_seconds_exn (Int64.of_int de)) + 1 + >>=? fun (b, _) -> + Context.get_constants (B b) >>=? fun constants -> + Baking.minimal_valid_time + constants.parametric + ~priority:p + ~endorsing_power:e + ~predecessor_timestamp:b.header.shell.timestamp + |> Environment.wrap_tzresult + >>?= fun timestamp -> + let delay = emmystar_delay ~te ~ie ~md ~bd ~dp ~de ~p ~e in + let expected_timestamp = + Time.Protocol.add b.header.shell.timestamp (Int64.of_int delay) + in + Assert.equal_int64 + ~loc:__LOC__ + (Time.Protocol.to_seconds timestamp) + (Time.Protocol.to_seconds expected_timestamp)) + range + +let tests = + [ + Tztest.tztest "minimal time" `Quick test_minimal_time; + Tztest.tztest "minimal valid time" `Quick test_minimal_valid_time; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_combined_operations.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_combined_operations.ml new file mode 100644 index 000000000000..08483a744acc --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_combined_operations.ml @@ -0,0 +1,332 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (combined operations) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^combined$" + Subject: Multiple operations can be grouped in one ensuring their + deterministic application. + + If an invalid operation is present in this group of + operations, the previously applied operations are + backtracked leaving the context unchanged and the + following operations are skipped. Fees attributed to the + operations are collected by the baker nonetheless. + + Only manager operations are allowed in multiple transactions. + They must all belong to the same manager as there is only one + signature. +*) + +open Protocol +open Test_tez + +let ten_tez = Tez.of_int 10 + +let gas_limit = Alpha_context.Gas.Arith.integral_of_int_exn 3000 + +(** Groups ten transactions between the same parties. *) +let test_multiple_transfers () = + Context.init 3 >>=? fun (blk, contracts) -> + let (c1, c2, c3) = + match contracts with [c1; c2; c3] -> (c1, c2, c3) | _ -> assert false + in + List.map_es + (fun _ -> Op.transaction ~gas_limit (B blk) c1 c2 Tez.one) + (1 -- 10) + >>=? fun ops -> + Op.combine_operations ~source:c1 (B blk) ops >>=? fun operation -> + Context.Contract.balance (B blk) c1 >>=? fun c1_old_balance -> + Context.Contract.balance (B blk) c2 >>=? fun c2_old_balance -> + Context.Contract.pkh c3 >>=? fun baker_pkh -> + Block.bake ~policy:(By_account baker_pkh) ~operation blk >>=? fun blk -> + Assert.balance_was_debited + ~loc:__LOC__ + (B blk) + c1 + c1_old_balance + (Tez.of_int 10) + >>=? fun () -> + Assert.balance_was_credited + ~loc:__LOC__ + (B blk) + c2 + c2_old_balance + (Tez.of_int 10) + >>=? fun () -> return_unit + +(** Groups ten delegated originations. *) +let test_multiple_origination_and_delegation () = + Context.init 2 >>=? fun (blk, contracts) -> + let (c1, c2) = + match contracts with [c1; c2] -> (c1, c2) | _ -> assert false + in + let n = 10 in + Context.get_constants (B blk) + >>=? fun {parametric = {origination_size; cost_per_byte; _}; _} -> + Context.Contract.pkh c2 >>=? fun delegate_pkh -> + (* Deploy n smart contracts with dummy scripts from c1 *) + List.map_es + (fun i -> + Op.origination + ~gas_limit + ~delegate:delegate_pkh + ~counter:(Z.of_int i) + ~fee:Tez.zero + ~script:Op.dummy_script + ~credit:(Tez.of_int 10) + (B blk) + c1) + (1 -- n) + >>=? fun originations -> + (* These computed originated contracts are not the ones really created *) + (* We will extract them from the tickets *) + let (originations_operations, _) = List.split originations in + Op.combine_operations ~source:c1 (B blk) originations_operations + >>=? fun operation -> + Context.Contract.balance (B blk) c1 >>=? fun c1_old_balance -> + Incremental.begin_construction blk >>=? fun inc -> + Incremental.add_operation inc operation >>=? fun inc -> + (* To retrieve the originated contracts, it is easier to extract them + from the tickets. Else, we could (could we ?) hash each combined + operation individually. *) + let tickets = Incremental.rev_tickets inc in + let open Apply_results in + let tickets = + List.fold_left + (fun acc -> function + | No_operation_metadata -> assert false + | Operation_metadata {contents} -> + to_list (Contents_result_list contents) @ acc) + [] + tickets + |> List.rev + in + let new_contracts = + List.map + (function + | Contents_result + (Manager_operation_result + { + operation_result = + Applied (Origination_result {originated_contracts = [h]; _}); + _; + }) -> + h + | _ -> assert false) + tickets + in + (* Previous balance - (Credit (n * 10tz) + Origination cost (n tz)) *) + Tez.(cost_per_byte *? Int64.of_int origination_size) + >>?= fun origination_burn -> + Tez.(origination_burn *? Int64.of_int n) >>?= fun origination_total_cost -> + Tez.( *? ) Op.dummy_script_cost 10L + >>? Tez.( +? ) (Tez.of_int (10 * n)) + >>? Tez.( +? ) origination_total_cost + >>?= fun total_cost -> + Assert.balance_was_debited ~loc:__LOC__ (I inc) c1 c1_old_balance total_cost + >>=? fun () -> + List.iter_es + (fun c -> Assert.balance_is ~loc:__LOC__ (I inc) c (Tez.of_int 10)) + new_contracts + +let expect_balance_too_low = function + | Environment.Ecoproto_error (Contract_storage.Balance_too_low _) :: _ -> + return_unit + | _ -> + failwith + "Contract should not have a sufficient balance : operation expected to \ + fail." + +(** Groups three operations, the middle one failing. + Checks that the receipt is consistent. + Variant without fees. *) +let test_failing_operation_in_the_middle () = + Context.init 2 >>=? fun (blk, contracts) -> + let (c1, c2) = + match contracts with [c1; c2] -> (c1, c2) | _ -> assert false + in + Op.transaction ~gas_limit ~fee:Tez.zero (B blk) c1 c2 Tez.one >>=? fun op1 -> + Op.transaction ~gas_limit ~fee:Tez.zero (B blk) c1 c2 Tez.max_tez + >>=? fun op2 -> + Op.transaction ~gas_limit ~fee:Tez.zero (B blk) c1 c2 Tez.one >>=? fun op3 -> + let operations = [op1; op2; op3] in + Op.combine_operations ~source:c1 (B blk) operations >>=? fun operation -> + Context.Contract.balance (B blk) c1 >>=? fun c1_old_balance -> + Context.Contract.balance (B blk) c2 >>=? fun c2_old_balance -> + Incremental.begin_construction blk >>=? fun inc -> + Incremental.add_operation ~expect_failure:expect_balance_too_low inc operation + >>=? fun inc -> + let tickets = Incremental.rev_tickets inc in + let open Apply_results in + let tickets = + List.fold_left + (fun acc -> function + | No_operation_metadata -> assert false + | Operation_metadata {contents} -> + to_list (Contents_result_list contents) @ acc) + [] + tickets + in + (match tickets with + | Contents_result + (Manager_operation_result {operation_result = Backtracked _; _}) + :: Contents_result + (Manager_operation_result {operation_result = Failed (_, trace); _}) + :: Contents_result + (Manager_operation_result {operation_result = Skipped _; _}) + :: _ -> + let trace_string = + Format.asprintf "%a" Environment.Error_monad.pp_trace trace + in + let expect = + Format.asprintf "Balance of contract %a too low" Context.Contract.pp c1 + in + assert (Astring.String.is_infix ~affix:expect trace_string) + | _ -> assert false) ; + Assert.balance_is ~loc:__LOC__ (I inc) c1 c1_old_balance >>=? fun () -> + Assert.balance_is ~loc:__LOC__ (I inc) c2 c2_old_balance >>=? fun () -> + return_unit + +(** Groups three operations, the middle one failing. + Checks that the receipt is consistent. + Variant with fees, that should be spent even in case of failure. *) +let test_failing_operation_in_the_middle_with_fees () = + Context.init 2 >>=? fun (blk, contracts) -> + let (c1, c2) = + match contracts with [c1; c2] -> (c1, c2) | _ -> assert false + in + Op.transaction ~fee:Tez.one (B blk) c1 c2 Tez.one >>=? fun op1 -> + Op.transaction ~fee:Tez.one (B blk) c1 c2 Tez.max_tez >>=? fun op2 -> + Op.transaction ~fee:Tez.one (B blk) c1 c2 Tez.one >>=? fun op3 -> + let operations = [op1; op2; op3] in + Op.combine_operations ~source:c1 (B blk) operations >>=? fun operation -> + Context.Contract.balance (B blk) c1 >>=? fun c1_old_balance -> + Context.Contract.balance (B blk) c2 >>=? fun c2_old_balance -> + Incremental.begin_construction blk >>=? fun inc -> + Incremental.add_operation ~expect_failure:expect_balance_too_low inc operation + >>=? fun inc -> + let tickets = Incremental.rev_tickets inc in + let open Apply_results in + let tickets = + List.fold_left + (fun acc -> function + | No_operation_metadata -> assert false + | Operation_metadata {contents} -> + to_list (Contents_result_list contents) @ acc) + [] + tickets + in + (match tickets with + | Contents_result + (Manager_operation_result {operation_result = Backtracked _; _}) + :: Contents_result + (Manager_operation_result {operation_result = Failed (_, trace); _}) + :: Contents_result + (Manager_operation_result {operation_result = Skipped _; _}) + :: _ -> + let trace_string = + Format.asprintf "%a" Environment.Error_monad.pp_trace trace + in + let expect = + Format.asprintf "Balance of contract %a too low" Context.Contract.pp c1 + in + assert (Astring.String.is_infix ~affix:expect trace_string) + | _ -> assert false) ; + (* In the presence of a failure, all the fees are collected. Even for skipped operations. *) + Assert.balance_was_debited + ~loc:__LOC__ + (I inc) + c1 + c1_old_balance + (Tez.of_int 3) + >>=? fun () -> + Assert.balance_is ~loc:__LOC__ (I inc) c2 c2_old_balance >>=? fun () -> + return_unit + +let expect_wrong_signature list = + if + List.exists + (function + | Environment.Ecoproto_error Apply.Inconsistent_sources -> true + | _ -> false) + list + then return_unit + else + failwith + "Packed operation has invalid source in the middle : operation expected \ + to fail." + +let test_wrong_signature_in_the_middle () = + Context.init 2 >>=? function + | (_, []) | (_, [_]) -> assert false + | (blk, c1 :: c2 :: _) -> + Op.transaction ~gas_limit ~fee:Tez.one (B blk) c1 c2 Tez.one + >>=? fun op1 -> + Op.transaction ~gas_limit ~fee:Tez.one (B blk) c2 c1 Tez.one + >>=? fun op2 -> + Incremental.begin_construction blk >>=? fun inc -> + (* Make legit transfers, performing reveals *) + Incremental.add_operation inc op1 >>=? fun inc -> + Incremental.add_operation inc op2 >>=? fun inc -> + (* Cook transactions for actual test *) + Op.transaction ~gas_limit ~fee:Tez.one (I inc) c1 c2 Tez.one + >>=? fun op1 -> + Op.transaction ~gas_limit ~fee:Tez.one (I inc) c1 c2 Tez.one + >>=? fun op2 -> + Op.transaction ~gas_limit ~fee:Tez.one (I inc) c1 c2 Tez.one + >>=? fun op3 -> + Op.transaction ~gas_limit ~fee:Tez.one (I inc) c2 c1 Tez.one + >>=? fun spurious_operation -> + let operations = [op1; op2; op3] in + Op.combine_operations ~spurious_operation ~source:c1 (I inc) operations + >>=? fun operation -> + Incremental.add_operation + ~expect_apply_failure:expect_wrong_signature + inc + operation + >>=? fun _inc -> return_unit + +let tests = + [ + Tztest.tztest "multiple transfers" `Quick test_multiple_transfers; + Tztest.tztest + "multiple originations and delegations" + `Quick + test_multiple_origination_and_delegation; + Tztest.tztest + "Failing operation in the middle" + `Quick + test_failing_operation_in_the_middle; + Tztest.tztest + "Failing operation in the middle (with fees)" + `Quick + test_failing_operation_in_the_middle_with_fees; + Tztest.tztest + "Failing operation (wrong manager in the middle of a pack)" + `Quick + test_wrong_signature_in_the_middle; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_constants.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_constants.ml new file mode 100644 index 000000000000..7b6b3d72672f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_constants.ml @@ -0,0 +1,94 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (baking) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^constants$" + Subject: the consistency of parametric constants + *) + +open Test_tez + +let test_constants_consistency () = + let open Tezos_protocol_011_PtHangzH_parameters.Default_parameters in + List.iter_es + Block.check_constants_consistency + [constants_mainnet; constants_sandbox; constants_test] + +let test_max_operations_ttl () = + let open Protocol in + (* max_operations_ttl is hard-coded for mainnet to avoid any + recomputation and is not reconfigured for other networks. *) + let minimal_block_delay = + Tezos_protocol_011_PtHangzH_parameters.Default_parameters.constants_mainnet + .minimal_block_delay + in + let time_between_blocks = + Tezos_protocol_011_PtHangzH_parameters.Default_parameters.constants_mainnet + .time_between_blocks + in + Context.init ~time_between_blocks ~minimal_block_delay 1 >>=? fun (b, _) -> + Context.get_constants (Context.B b) >>=? fun constants -> + Environment.wrap_tzresult + (Alpha_context.Period.mult + (Int32.of_int Alpha_context.max_operations_ttl) + constants.parametric.minimal_block_delay) + >>?= fun result -> + Assert.equal + ~loc:__LOC__ + (fun x y -> Alpha_context.Period.compare x y = 0) + "max_operations_ttl" + Alpha_context.Period.pp + Alpha_context.Period.one_hour + result + +(* Test that the amount of the liquidity baking subsidy is 1/16th of total rewards + of a fully-endorsed block with priority zero. *) +let liquidity_baking_subsidy_param () = + Context.init 1 >>=? fun (blk, _contracts) -> + Context.get_constants (B blk) >>=? fun csts -> + let hd l = Option.value_fe ~error:(fun () -> assert false) (List.hd l) in + hd csts.parametric.baking_reward_per_endorsement + >>?= fun baking_reward_per_endorsement -> + hd csts.parametric.endorsement_reward >>?= fun endorsement_reward -> + let endorsers_per_block = csts.parametric.endorsers_per_block in + let actual_subsidy = csts.parametric.liquidity_baking_subsidy in + Tez.(baking_reward_per_endorsement +? endorsement_reward) + >>?= fun total_reward -> + Tez.(mul_exn total_reward endorsers_per_block /? 16L) + >>?= fun expected_subsidy -> + Assert.equal_tez ~loc:__LOC__ actual_subsidy expected_subsidy + +let tests = + [ + Tztest.tztest "constants consistency" `Quick test_constants_consistency; + Tztest.tztest "max_operations_ttl" `Quick test_max_operations_ttl; + Tztest.tztest + "test liquidity_baking_subsidy parameter is 1/16th of total baking \ + rewards" + `Quick + liquidity_baking_subsidy_param; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_delegation.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_delegation.ml new file mode 100644 index 000000000000..8bb63bf2ebb6 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_delegation.ml @@ -0,0 +1,1561 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (delegation) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^delegation$" + Subject: - Properties on bootstrap contracts (self-delegation, + cannot delete/change their delegate (as opposed to contracts + not-being-delegate which can do these), bootstrap manager + as delegate during origination). + - Properties on delegation depending on whether delegate + keys registration, through origination and delegation. +*) + +open Protocol +open Alpha_context +open Test_tez + +(*****************************************************************************) +(* Bootstrap contracts + ------------------- + Bootstrap contracts are heavily used in other tests. It is helpful to test + some properties of these contracts, so we can correctly interpret the other + tests that use them. *) +(*****************************************************************************) + +let expect_error err = function + | err0 :: _ when err = err0 -> return_unit + | _ -> failwith "Unexpected successful result" + +let expect_alpha_error err = expect_error (Environment.Ecoproto_error err) + +let expect_no_change_registered_delegate_pkh pkh = function + | Environment.Ecoproto_error (Delegate_storage.No_deletion pkh0) :: _ + when pkh0 = pkh -> + return_unit + | _ -> failwith "Delegate can not be deleted and operation should fail." + +(** Bootstrap contracts delegate to themselves. *) +let bootstrap_manager_is_bootstrap_delegate () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + let bootstrap0 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + Context.Contract.delegate (B b) bootstrap0 >>=? fun delegate0 -> + Context.Contract.manager (B b) bootstrap0 >>=? fun manager0 -> + Assert.equal_pkh ~loc:__LOC__ delegate0 manager0.pkh + +(** Bootstrap contracts cannot change their delegate. *) +let bootstrap_delegate_cannot_change ~fee () = + Context.init 2 >>=? fun (b, bootstrap_contracts) -> + let bootstrap0 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth bootstrap_contracts 0 + in + let bootstrap1 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth bootstrap_contracts 1 + in + Context.Contract.pkh bootstrap0 >>=? fun pkh1 -> + Incremental.begin_construction b ~policy:(Block.Excluding [pkh1]) + >>=? fun i -> + Context.Contract.manager (I i) bootstrap1 >>=? fun manager1 -> + Context.Contract.balance (I i) bootstrap0 >>=? fun balance0 -> + Context.Contract.delegate (I i) bootstrap0 >>=? fun delegate0 -> + (* change delegation to bootstrap1 *) + Op.delegation ~fee (I i) bootstrap0 (Some manager1.pkh) + >>=? fun set_delegate -> + if fee > balance0 then + Incremental.add_operation i set_delegate >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + Incremental.add_operation + ~expect_failure:(expect_no_change_registered_delegate_pkh delegate0) + i + set_delegate + >>=? fun i -> + Incremental.finalize_block i >>=? fun b -> + (* bootstrap0 still has same delegate *) + Context.Contract.delegate (B b) bootstrap0 >>=? fun delegate0_after -> + Assert.equal_pkh ~loc:__LOC__ delegate0_after delegate0 >>=? fun () -> + (* fee has been debited *) + Assert.balance_was_debited ~loc:__LOC__ (B b) bootstrap0 balance0 fee + +(** Bootstrap contracts cannot delete their delegation. *) +let bootstrap_delegate_cannot_be_removed ~fee () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + Incremental.begin_construction b >>=? fun i -> + Context.Contract.balance (I i) bootstrap >>=? fun balance -> + Context.Contract.delegate (I i) bootstrap >>=? fun delegate -> + Context.Contract.manager (I i) bootstrap >>=? fun manager -> + (* remove delegation *) + Op.delegation ~fee (I i) bootstrap None >>=? fun set_delegate -> + if fee > balance then + Incremental.add_operation i set_delegate >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + Incremental.add_operation + ~expect_failure:(expect_no_change_registered_delegate_pkh manager.pkh) + i + set_delegate + >>=? fun i -> + (* delegate has not changed *) + Context.Contract.delegate (I i) bootstrap >>=? fun delegate_after -> + Assert.equal_pkh ~loc:__LOC__ delegate delegate_after >>=? fun () -> + (* fee has been debited *) + Assert.balance_was_debited ~loc:__LOC__ (I i) bootstrap balance fee + +(** Contracts not registered as delegate can change their + delegation. *) +let delegate_can_be_changed_from_unregistered_contract ~fee () = + Context.init 2 >>=? fun (b, bootstrap_contracts) -> + let bootstrap0 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let bootstrap1 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth bootstrap_contracts 1 + in + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let unregistered = Contract.implicit_contract unregistered_pkh in + Incremental.begin_construction b >>=? fun i -> + Context.Contract.manager (I i) bootstrap0 >>=? fun manager0 -> + Context.Contract.manager (I i) bootstrap1 >>=? fun manager1 -> + let credit = Tez.of_int 10 in + Op.transaction ~fee:Tez.zero (I i) bootstrap0 unregistered credit + >>=? fun credit_contract -> + Context.Contract.balance (I i) bootstrap0 >>=? fun balance -> + Incremental.add_operation i credit_contract >>=? fun i -> + (* delegate to bootstrap0 *) + Op.delegation ~fee:Tez.zero (I i) unregistered (Some manager0.pkh) + >>=? fun set_delegate -> + Incremental.add_operation i set_delegate >>=? fun i -> + Context.Contract.delegate (I i) unregistered >>=? fun delegate -> + Assert.equal_pkh ~loc:__LOC__ delegate manager0.pkh >>=? fun () -> + (* change delegation to bootstrap1 *) + Op.delegation ~fee (I i) unregistered (Some manager1.pkh) + >>=? fun change_delegate -> + if fee > balance then + Incremental.add_operation i change_delegate >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + Incremental.add_operation i change_delegate >>=? fun i -> + (* delegate has changed *) + Context.Contract.delegate (I i) unregistered >>=? fun delegate_after -> + Assert.equal_pkh ~loc:__LOC__ delegate_after manager1.pkh >>=? fun () -> + (* fee has been debited *) + Assert.balance_was_debited ~loc:__LOC__ (I i) unregistered credit fee + +(** Contracts not registered as delegate can delete their + delegation. *) +let delegate_can_be_removed_from_unregistered_contract ~fee () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let unregistered = Contract.implicit_contract unregistered_pkh in + Incremental.begin_construction b >>=? fun i -> + Context.Contract.manager (I i) bootstrap >>=? fun manager -> + let credit = Tez.of_int 10 in + Op.transaction ~fee:Tez.zero (I i) bootstrap unregistered credit + >>=? fun credit_contract -> + Context.Contract.balance (I i) bootstrap >>=? fun balance -> + Incremental.add_operation i credit_contract >>=? fun i -> + (* delegate to bootstrap *) + Op.delegation ~fee:Tez.zero (I i) unregistered (Some manager.pkh) + >>=? fun set_delegate -> + Incremental.add_operation i set_delegate >>=? fun i -> + Context.Contract.delegate (I i) unregistered >>=? fun delegate -> + Assert.equal_pkh ~loc:__LOC__ delegate manager.pkh >>=? fun () -> + (* remove delegation *) + Op.delegation ~fee (I i) unregistered None >>=? fun delete_delegate -> + if fee > balance then + Incremental.add_operation i delete_delegate >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + Incremental.add_operation i delete_delegate >>=? fun i -> + (* the delegate has been removed *) + (Context.Contract.delegate_opt (I i) unregistered >>=? function + | None -> return_unit + | Some _ -> failwith "Expected delegate to be removed") + >>=? fun () -> + (* fee has been debited *) + Assert.balance_was_debited ~loc:__LOC__ (I i) unregistered credit fee + +(** Bootstrap keys are already registered as delegate keys. *) +let bootstrap_manager_already_registered_delegate ~fee () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + Context.Contract.manager (I i) bootstrap >>=? fun manager -> + let pkh = manager.pkh in + let impl_contract = Contract.implicit_contract pkh in + Context.Contract.balance (I i) impl_contract >>=? fun balance -> + Op.delegation ~fee (I i) impl_contract (Some pkh) >>=? fun sec_reg -> + if fee > balance then + Incremental.add_operation i sec_reg >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + Incremental.add_operation + ~expect_failure:(function + | Environment.Ecoproto_error Delegate_storage.Active_delegate :: _ -> + return_unit + | _ -> failwith "Delegate is already active and operation should fail.") + i + sec_reg + >>=? fun i -> + (* fee has been debited *) + Assert.balance_was_debited ~loc:__LOC__ (I i) impl_contract balance fee + +(** Bootstrap manager can be set as delegate of an originated contract + (through origination operation). *) +let delegate_to_bootstrap_by_origination ~fee () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + Context.Contract.manager (I i) bootstrap >>=? fun manager -> + Context.Contract.balance (I i) bootstrap >>=? fun balance -> + (* originate a contract with bootstrap's manager as delegate *) + Op.origination + ~fee + ~credit:Tez.zero + ~delegate:manager.pkh + (I i) + bootstrap + ~script:Op.dummy_script + >>=? fun (op, orig_contract) -> + Context.get_constants (I i) + >>=? fun {parametric = {origination_size; cost_per_byte; _}; _} -> + (* 0.257tz *) + Tez.(cost_per_byte *? Int64.of_int origination_size) + >>?= fun origination_burn -> + Tez.( +? ) fee origination_burn >>? Tez.( +? ) Op.dummy_script_cost + >>?= fun total_fee -> + if fee > balance then + Incremental.add_operation i op >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else if total_fee > balance && balance >= fee then + (* origination did not proceed; fee has been debited *) + Incremental.add_operation + i + ~expect_failure:(function + | Environment.Ecoproto_error (Contract.Balance_too_low _) :: _ -> + return_unit + | _ -> + failwith + "Not enough balance for origination burn: operation should fail.") + op + >>=? fun i -> + (* fee was taken *) + Assert.balance_was_debited ~loc:__LOC__ (I i) bootstrap balance fee + >>=? fun () -> + (* originated contract has not been created *) + Context.Contract.balance (I i) orig_contract >>= fun err -> + Assert.error ~loc:__LOC__ err (function + | RPC_context.Not_found _ -> true + | _ -> false) + else + (* bootstrap is delegate, fee + origination burn have been debited *) + Incremental.add_operation i op >>=? fun i -> + Context.Contract.delegate (I i) orig_contract >>=? fun delegate -> + Assert.equal_pkh ~loc:__LOC__ delegate manager.pkh >>=? fun () -> + Assert.balance_was_debited ~loc:__LOC__ (I i) bootstrap balance total_fee + +let tests_bootstrap_contracts = + [ + Tztest.tztest + "bootstrap contracts delegate to themselves" + `Quick + bootstrap_manager_is_bootstrap_delegate; + Tztest.tztest + "bootstrap contracts can change their delegate (small fee)" + `Quick + (bootstrap_delegate_cannot_change ~fee:Tez.one_mutez); + Tztest.tztest + "bootstrap contracts can change their delegate (max fee)" + `Quick + (bootstrap_delegate_cannot_change ~fee:Tez.max_tez); + Tztest.tztest + "bootstrap contracts cannot remove their delegation (small fee)" + `Quick + (bootstrap_delegate_cannot_be_removed ~fee:Tez.one_mutez); + Tztest.tztest + "bootstrap contracts cannot remove their delegation (max fee)" + `Quick + (bootstrap_delegate_cannot_be_removed ~fee:Tez.max_tez); + Tztest.tztest + "contracts not registered as delegate can remove their delegation (small \ + fee)" + `Quick + (delegate_can_be_changed_from_unregistered_contract ~fee:Tez.one_mutez); + Tztest.tztest + "contracts not registered as delegate can remove their delegation (max \ + fee)" + `Quick + (delegate_can_be_changed_from_unregistered_contract ~fee:Tez.max_tez); + Tztest.tztest + "contracts not registered as delegate can remove their delegation (small \ + fee)" + `Quick + (delegate_can_be_removed_from_unregistered_contract ~fee:Tez.one_mutez); + Tztest.tztest + "contracts not registered as delegate can remove their delegation (max \ + fee)" + `Quick + (delegate_can_be_removed_from_unregistered_contract ~fee:Tez.max_tez); + Tztest.tztest + "bootstrap keys are already registered as delegate keys (small fee)" + `Quick + (bootstrap_manager_already_registered_delegate ~fee:Tez.one_mutez); + Tztest.tztest + "bootstrap keys are already registered as delegate keys (max fee)" + `Quick + (bootstrap_manager_already_registered_delegate ~fee:Tez.max_tez); + Tztest.tztest + "bootstrap manager can be delegate (init origination, small fee)" + `Quick + (delegate_to_bootstrap_by_origination ~fee:Tez.one_mutez); + (* balance enough for fee but not for fee + origination burn + dummy script storage cost *) + Tztest.tztest + "bootstrap manager can be delegate (init origination, edge case)" + `Quick + (delegate_to_bootstrap_by_origination + ~fee:(Tez.of_mutez_exn 3_999_999_705_000L)); + (* fee bigger than bootstrap's initial balance*) + Tztest.tztest + "bootstrap manager can be delegate (init origination, large fee)" + `Quick + (delegate_to_bootstrap_by_origination ~fee:(Tez.of_int 10_000_000)); + ] + +(*****************************************************************************) +(* Delegate registration + --------------------- + A delegate is a pkh. Delegates must be registered. Registration is + done via the self-delegation of the implicit contract corresponding + to the pkh. The implicit contract must be credited when the + self-delegation is done. Furthermore, trying to register an already + registered key raises an error. + + In this series of tests, we verify that + 1- unregistered delegate keys cannot be delegated to, + 2- registered keys can be delegated to, + 3- registering an already registered key raises an error. + + We consider three scenarios for setting a delegate: + - through origination, + - through delegation when the implicit contract has no delegate yet, + - through delegation when the implicit contract already has a delegate. + + We also test that emptying the implicit contract linked to a + registered delegate key does not unregister the delegate key. + + Valid registration + ------------------ + Unregistered key: + - contract not credited and no self-delegation, + - contract credited but no self-delegation, + - contract not credited and self-delegation. + + Not credited: + - no credit operation + - credit operation of 1μꜩ and then debit operation of 1μꜩ *) +(*****************************************************************************) + +(* Part A. + Unregistered delegate keys cannot be used for delegation + + Two main series of tests: without self-delegation and with a failed attempt at self-delegation: + + 1/ no self-delegation + a/ no credit + - no token transfer + - credit of 1μꜩ and then debit of 1μꜩ + b/ with credit of 1μꜩ. + For every scenario, we try three different ways of delegating: + - through origination (init origination) + - through delegation when no delegate was assigned (init delegation) + - through delegation when a delegate was assigned (switch delegation). + + 2/ Self-delegation fails if the contract has no credit. We try the + two possibilities of 1a for non-credited contracts. *) + +let expect_unregistered_key pkh = function + | Environment.Ecoproto_error (Roll_storage.Unregistered_delegate pkh0) :: _ + when pkh = pkh0 -> + return_unit + | _ -> failwith "Delegate key is not registered: operation should fail." + +(* Part A. Section 1. + No self-delegation. *) + +(** No token transfer, no self-delegation. Originated account. If + fees are higher than balance, [Balance_too_low] is + raised. Otherwise, it checks the correct exception is raised + (unregistered key), and the fees are still debited. Using RPCs, we + verify the contract has not been originated. *) +let test_unregistered_delegate_key_init_origination ~fee () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + (* origination with delegate argument *) + Op.origination + ~fee + ~delegate:unregistered_pkh + (I i) + bootstrap + ~script:Op.dummy_script + >>=? fun (op, orig_contract) -> + Context.get_constants (I i) + >>=? fun {parametric = {origination_size; cost_per_byte; _}; _} -> + Tez.(cost_per_byte *? Int64.of_int origination_size) + >>?= fun origination_burn -> + Tez.( +? ) fee origination_burn >>?= fun _total_fee -> + (* FIXME unused variable *) + Context.Contract.balance (I i) bootstrap >>=? fun balance -> + if fee > balance then + Incremental.add_operation i op >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + (* origination did not proceed; fee has been debited *) + Incremental.add_operation + ~expect_failure:(expect_unregistered_key unregistered_pkh) + i + op + >>=? fun i -> + Assert.balance_was_debited ~loc:__LOC__ (I i) bootstrap balance fee + >>=? fun () -> + (* originated contract has not been created *) + Context.Contract.balance (I i) orig_contract >>= fun err -> + Assert.error ~loc:__LOC__ err (function + | RPC_context.Not_found _ -> true + | _ -> false) + +(** Delegation when delegate key is not assigned. Delegate account is + initialized. If fees are higher than initial credit (10 tez), + [Balance_too_low] is raised. Otherwise, fees are still debited. The + implicit contract has no delegate. *) +let test_unregistered_delegate_key_init_delegation ~fee () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let impl_contract = Contract.implicit_contract unregistered_pkh in + let unregistered_delegate_account = Account.new_account () in + let unregistered_delegate_pkh = Account.(unregistered_delegate_account.pkh) in + (* initial credit for the delegated contract *) + let credit = Tez.of_int 10 in + Op.transaction ~fee:Tez.zero (I i) bootstrap impl_contract credit + >>=? fun credit_contract -> + Incremental.add_operation i credit_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract credit >>=? fun _ -> + (* try to delegate *) + Op.delegation ~fee (I i) impl_contract (Some unregistered_delegate_pkh) + >>=? fun delegate_op -> + if fee > credit then + Incremental.add_operation i delegate_op >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + (* fee has been debited; no delegate *) + Incremental.add_operation + i + ~expect_failure:(expect_unregistered_key unregistered_delegate_pkh) + delegate_op + >>=? fun i -> + Assert.balance_was_debited ~loc:__LOC__ (I i) impl_contract credit fee + >>=? fun () -> + (* implicit contract has no delegate *) + Context.Contract.delegate (I i) impl_contract >>= fun err -> + Assert.error ~loc:__LOC__ err (function + | RPC_context.Not_found _ -> true + | _ -> false) + +(** Re-delegation when a delegate key was already assigned. If fees + are higher than initial credit (10 tez), [Balance_too_low] is + raised. Otherwise, fees are not debited and the implicit contract + delegate remains unchanged. *) +let test_unregistered_delegate_key_switch_delegation ~fee () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let bootstrap_pkh = + Contract.is_implicit bootstrap |> WithExceptions.Option.get ~loc:__LOC__ + in + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let impl_contract = Contract.implicit_contract unregistered_pkh in + let unregistered_delegate_account = Account.new_account () in + let unregistered_delegate_pkh = Account.(unregistered_delegate_account.pkh) in + (* initial credit for the delegated contract *) + let credit = Tez.of_int 10 in + Op.transaction ~fee:Tez.zero (I i) bootstrap impl_contract credit + >>=? fun init_credit -> + Incremental.add_operation i init_credit >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract credit >>=? fun _ -> + (* set and check the initial delegate *) + Op.delegation ~fee:Tez.zero (I i) impl_contract (Some bootstrap_pkh) + >>=? fun delegate_op -> + Incremental.add_operation i delegate_op >>=? fun i -> + Context.Contract.delegate (I i) bootstrap >>=? fun delegate_pkh -> + Assert.equal_pkh ~loc:__LOC__ bootstrap_pkh delegate_pkh >>=? fun () -> + (* try to delegate *) + Op.delegation ~fee (I i) impl_contract (Some unregistered_delegate_pkh) + >>=? fun delegate_op -> + if fee > credit then + Incremental.add_operation i delegate_op >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + (* fee has been debited; no delegate *) + Incremental.add_operation + i + ~expect_failure:(expect_unregistered_key unregistered_delegate_pkh) + delegate_op + >>=? fun i -> + Assert.balance_was_debited ~loc:__LOC__ (I i) impl_contract credit fee + >>=? fun () -> + (* implicit contract delegate has not changed *) + Context.Contract.delegate (I i) bootstrap >>=? fun delegate_pkh_after -> + Assert.equal_pkh ~loc:__LOC__ delegate_pkh delegate_pkh_after + +(** Same as [unregistered_delegate_key_init_origination] and credits + [amount], no self-delegation. *) +let test_unregistered_delegate_key_init_origination_credit ~fee ~amount () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let impl_contract = Contract.implicit_contract unregistered_pkh in + (* credit + check balance *) + Op.transaction ~fee:Tez.zero (I i) bootstrap impl_contract amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract amount >>=? fun _ -> + (* origination with delegate argument *) + Context.Contract.balance (I i) bootstrap >>=? fun balance -> + Op.origination + ~fee + ~delegate:unregistered_pkh + (I i) + bootstrap + ~script:Op.dummy_script + >>=? fun (op, orig_contract) -> + if fee > balance then + Incremental.add_operation i op >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + (* origination not done, fee taken *) + Incremental.add_operation + ~expect_failure:(expect_unregistered_key unregistered_pkh) + i + op + >>=? fun i -> + Assert.balance_was_debited ~loc:__LOC__ (I i) bootstrap balance fee + >>=? fun () -> + Context.Contract.balance (I i) orig_contract >>= fun err -> + Assert.error ~loc:__LOC__ err (function + | RPC_context.Not_found _ -> true + | _ -> false) + +(** Same as [unregistered_delegate_key_init_delegation] and credits + the amount [amount] of the implicit contract. *) +let test_unregistered_delegate_key_init_delegation_credit ~fee ~amount () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let impl_contract = Contract.implicit_contract unregistered_pkh in + let unregistered_delegate_account = Account.new_account () in + let unregistered_delegate_pkh = Account.(unregistered_delegate_account.pkh) in + (* credit + check balance *) + Op.transaction ~fee:Tez.zero (I i) bootstrap impl_contract amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract amount >>=? fun _ -> + (* initial credit for the delegated contract *) + let credit = Tez.of_int 10 in + Tez.(credit +? amount) >>?= fun balance -> + Op.transaction ~fee:Tez.zero (I i) bootstrap impl_contract credit + >>=? fun init_credit -> + Incremental.add_operation i init_credit >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract balance >>=? fun _ -> + (* try to delegate *) + Op.delegation ~fee (I i) impl_contract (Some unregistered_delegate_pkh) + >>=? fun delegate_op -> + if fee > credit then + Incremental.add_operation i delegate_op >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + (* fee has been taken, no delegate for contract *) + Incremental.add_operation + ~expect_failure:(expect_unregistered_key unregistered_delegate_pkh) + i + delegate_op + >>=? fun i -> + Assert.balance_was_debited ~loc:__LOC__ (I i) impl_contract balance fee + >>=? fun () -> + Context.Contract.delegate (I i) impl_contract >>= fun err -> + Assert.error ~loc:__LOC__ err (function + | RPC_context.Not_found _ -> true + | _ -> false) + +(** Same as in [unregistered_delegate_key_switch_delegation] and + credits the amount [amount] to the implicit contract. *) +let test_unregistered_delegate_key_switch_delegation_credit ~fee ~amount () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let bootstrap_pkh = + Contract.is_implicit bootstrap |> WithExceptions.Option.get ~loc:__LOC__ + in + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let impl_contract = Contract.implicit_contract unregistered_pkh in + let unregistered_delegate_account = Account.new_account () in + let unregistered_delegate_pkh = Account.(unregistered_delegate_account.pkh) in + (* credit + check balance *) + Op.transaction ~fee:Tez.zero (I i) bootstrap impl_contract amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract amount >>=? fun _ -> + (* initial credit for the delegated contract *) + let credit = Tez.of_int 10 in + Tez.(credit +? amount) >>?= fun balance -> + Op.transaction ~fee:Tez.zero (I i) bootstrap impl_contract credit + >>=? fun init_credit -> + Incremental.add_operation i init_credit >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract balance >>=? fun _ -> + (* set and check the initial delegate *) + Op.delegation ~fee:Tez.zero (I i) impl_contract (Some bootstrap_pkh) + >>=? fun delegate_op -> + Incremental.add_operation i delegate_op >>=? fun i -> + Context.Contract.delegate (I i) bootstrap >>=? fun delegate_pkh -> + Assert.equal_pkh ~loc:__LOC__ bootstrap_pkh delegate_pkh >>=? fun () -> + (* switch delegate through delegation *) + Op.delegation ~fee (I i) impl_contract (Some unregistered_delegate_pkh) + >>=? fun delegate_op -> + if fee > credit then + Incremental.add_operation i delegate_op >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + (* fee has been taken, delegate for contract has not changed *) + Incremental.add_operation + ~expect_failure:(expect_unregistered_key unregistered_delegate_pkh) + i + delegate_op + >>=? fun i -> + Assert.balance_was_debited ~loc:__LOC__ (I i) impl_contract balance fee + >>=? fun () -> + Context.Contract.delegate (I i) impl_contract >>=? fun delegate -> + Assert.not_equal_pkh ~loc:__LOC__ delegate unregistered_delegate_pkh + >>=? fun () -> Assert.equal_pkh ~loc:__LOC__ delegate bootstrap_pkh + +(** A credit of some amount followed by a debit of the same amount, + no self-delegation. *) +let test_unregistered_delegate_key_init_origination_credit_debit ~fee ~amount () + = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let impl_contract = Contract.implicit_contract unregistered_pkh in + (* credit + check balance *) + Op.transaction (I i) bootstrap impl_contract amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract amount >>=? fun _ -> + (* debit + check balance *) + Op.transaction (I i) impl_contract bootstrap amount >>=? fun debit_contract -> + Incremental.add_operation i debit_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract Tez.zero >>=? fun _ -> + (* origination with delegate argument *) + Context.Contract.balance (I i) bootstrap >>=? fun balance -> + Op.origination + ~fee + ~delegate:unregistered_pkh + (I i) + bootstrap + ~script:Op.dummy_script + >>=? fun (op, orig_contract) -> + if fee > balance then + Incremental.add_operation i op >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + (* fee taken, origination not processed *) + Incremental.add_operation + ~expect_failure:(expect_unregistered_key unregistered_pkh) + i + op + >>=? fun i -> + Assert.balance_was_debited ~loc:__LOC__ (I i) bootstrap balance fee + >>=? fun () -> + Context.Contract.balance (I i) orig_contract >>= fun err -> + Assert.error ~loc:__LOC__ err (function + | RPC_context.Not_found _ -> true + | _ -> false) + +(** Same as in [unregistered_delegate_key_init_delegation] but credits + then debits the amount [amount] to the implicit contract. *) +let test_unregistered_delegate_key_init_delegation_credit_debit ~amount ~fee () + = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let impl_contract = Contract.implicit_contract unregistered_pkh in + let unregistered_delegate_account = Account.new_account () in + let unregistered_delegate_pkh = Account.(unregistered_delegate_account.pkh) in + (* credit + check balance *) + Op.transaction ~fee:Tez.zero (I i) bootstrap impl_contract amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract amount >>=? fun _ -> + (* debit + check balance *) + Op.transaction ~fee:Tez.zero (I i) impl_contract bootstrap amount + >>=? fun debit_contract -> + Incremental.add_operation i debit_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract Tez.zero >>=? fun _ -> + (* initial credit for the delegated contract *) + let credit = Tez.of_int 10 in + Op.transaction ~fee:Tez.zero (I i) bootstrap impl_contract credit + >>=? fun credit_contract -> + Incremental.add_operation i credit_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract credit >>=? fun _ -> + (* try to delegate *) + Op.delegation ~fee (I i) impl_contract (Some unregistered_delegate_pkh) + >>=? fun delegate_op -> + if fee > credit then + Incremental.add_operation i delegate_op >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + (* fee has been taken, no delegate for contract *) + Incremental.add_operation + ~expect_failure:(expect_unregistered_key unregistered_delegate_pkh) + i + delegate_op + >>=? fun i -> + Assert.balance_was_debited ~loc:__LOC__ (I i) impl_contract credit fee + >>=? fun () -> + Context.Contract.delegate (I i) impl_contract >>= fun err -> + Assert.error ~loc:__LOC__ err (function + | RPC_context.Not_found _ -> true + | _ -> false) + +(** Same as in [unregistered_delegate_key_switch_delegation] but + credits then debits the amount [amount] to the implicit contract. *) +let test_unregistered_delegate_key_switch_delegation_credit_debit ~fee ~amount + () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let bootstrap_pkh = + Contract.is_implicit bootstrap |> WithExceptions.Option.get ~loc:__LOC__ + in + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let impl_contract = Contract.implicit_contract unregistered_pkh in + let unregistered_delegate_account = Account.new_account () in + let unregistered_delegate_pkh = Account.(unregistered_delegate_account.pkh) in + (* credit + check balance *) + Op.transaction ~fee:Tez.zero (I i) bootstrap impl_contract amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract amount >>=? fun _ -> + (* debit + check balance *) + Op.transaction (I i) impl_contract bootstrap amount >>=? fun debit_contract -> + Incremental.add_operation i debit_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract Tez.zero >>=? fun _ -> + (* delegation - initial credit for the delegated contract *) + let credit = Tez.of_int 10 in + Op.transaction ~fee:Tez.zero (I i) bootstrap impl_contract credit + >>=? fun credit_contract -> + Incremental.add_operation i credit_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract credit >>=? fun _ -> + (* set and check the initial delegate *) + Op.delegation ~fee:Tez.zero (I i) impl_contract (Some bootstrap_pkh) + >>=? fun delegate_op -> + Incremental.add_operation i delegate_op >>=? fun i -> + Context.Contract.delegate (I i) bootstrap >>=? fun delegate_pkh -> + Assert.equal_pkh ~loc:__LOC__ bootstrap_pkh delegate_pkh >>=? fun () -> + (* switch delegate through delegation *) + Op.delegation (I i) ~fee impl_contract (Some unregistered_delegate_pkh) + >>=? fun delegate_op -> + if fee > credit then + Incremental.add_operation i delegate_op >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + (* fee has been taken, delegate for contract has not changed *) + Incremental.add_operation + ~expect_failure:(expect_unregistered_key unregistered_delegate_pkh) + i + delegate_op + >>=? fun i -> + Assert.balance_was_debited ~loc:__LOC__ (I i) impl_contract credit fee + >>=? fun () -> + Context.Contract.delegate (I i) impl_contract >>=? fun delegate -> + Assert.not_equal_pkh ~loc:__LOC__ delegate unregistered_delegate_pkh + +(* Part A. Section 2. + Self-delegation to an empty contract fails. *) + +(** Self-delegation with zero-balance contract should fail. *) +let test_failed_self_delegation_no_transaction () = + Context.init 1 >>=? fun (b, _) -> + Incremental.begin_construction b >>=? fun i -> + let account = Account.new_account () in + let unregistered_pkh = Account.(account.pkh) in + let impl_contract = Contract.implicit_contract unregistered_pkh in + (* check balance *) + Context.Contract.balance (I i) impl_contract >>=? fun balance -> + Assert.equal_tez ~loc:__LOC__ Tez.zero balance >>=? fun _ -> + (* self delegation fails *) + Op.delegation (I i) impl_contract (Some unregistered_pkh) + >>=? fun self_delegation -> + Incremental.add_operation i self_delegation >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Empty_implicit_contract pkh -> + if pkh = unregistered_pkh then true else false + | _ -> false) + +(** Implicit contract is credited then debited of same amount (i.e., + is emptied). Self-delegation fails. *) +let test_failed_self_delegation_emptied_implicit_contract amount () = + (* create an implicit contract *) + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let account = Account.new_account () in + let unregistered_pkh = Account.(account.pkh) in + let impl_contract = Contract.implicit_contract unregistered_pkh in + (* credit implicit contract and check balance *) + Op.transaction (I i) bootstrap impl_contract amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract amount >>=? fun _ -> + (* empty implicit contract and check balance *) + Op.transaction (I i) impl_contract bootstrap amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract Tez.zero >>=? fun _ -> + (* self delegation fails *) + Op.delegation (I i) impl_contract (Some unregistered_pkh) + >>=? fun self_delegation -> + Incremental.add_operation i self_delegation >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Empty_implicit_contract pkh -> + if pkh = unregistered_pkh then true else false + | _ -> false) + +(** Implicit contract is credited with a non-zero quantity [amount] + tz, then it is delegated. The operation of debit of [amount] tz + should fail as the contract is already delegated. *) +let test_emptying_delegated_implicit_contract_fails amount () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + Context.Contract.manager (I i) bootstrap >>=? fun bootstrap_manager -> + let account = Account.new_account () in + let unregistered_pkh = Account.(account.pkh) in + let impl_contract = Contract.implicit_contract unregistered_pkh in + (* credit unregistered implicit contract and check balance *) + Op.transaction (I i) bootstrap impl_contract amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract amount >>=? fun _ -> + (* delegate the contract to the bootstrap *) + Op.delegation (I i) impl_contract (Some bootstrap_manager.pkh) + >>=? fun delegation -> + Incremental.add_operation i delegation >>=? fun i -> + (* empty implicit contract and expect error since the contract is delegated *) + Op.transaction (I i) impl_contract bootstrap amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Empty_implicit_delegated_contract _ -> true + | _ -> false) + +(* Part B. + - Valid registration: + - Credit implicit contract with some ꜩ + verification of balance + - Self delegation + verification + - Empty contract + verification of balance + verification of not being erased / self-delegation + - Create delegator implicit contract w first implicit contract as delegate + verification of delegation. *) + +(** Initialized account is credited of [amount] tz, then + self-delegated. *) +let test_valid_delegate_registration_init_delegation_credit amount () = + (* create an implicit contract *) + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let delegate_account = Account.new_account () in + let delegate_pkh = Account.(delegate_account.pkh) in + let impl_contract = Contract.implicit_contract delegate_pkh in + (* credit > 0ꜩ + check balance *) + Op.transaction (I i) bootstrap impl_contract amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract amount >>=? fun _ -> + (* self delegation + verification *) + Op.delegation (I i) impl_contract (Some delegate_pkh) + >>=? fun self_delegation -> + Incremental.add_operation i self_delegation >>=? fun i -> + Context.Contract.delegate (I i) impl_contract >>=? fun delegate -> + Assert.equal_pkh ~loc:__LOC__ delegate delegate_pkh >>=? fun _ -> + (* create an implicit contract with no delegate *) + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let delegator = Contract.implicit_contract unregistered_pkh in + Op.transaction ~fee:Tez.zero (I i) bootstrap delegator Tez.one + >>=? fun credit_contract -> + Incremental.add_operation i credit_contract >>=? fun i -> + (* check no delegate for delegator contract *) + Context.Contract.delegate (I i) delegator >>= fun err -> + Assert.error ~loc:__LOC__ err (function + | RPC_context.Not_found _ -> true + | _ -> false) + >>=? fun _ -> + (* delegation to the newly registered key *) + Op.delegation (I i) delegator (Some delegate_account.pkh) + >>=? fun delegation -> + Incremental.add_operation i delegation >>=? fun i -> + (* check delegation *) + Context.Contract.delegate (I i) delegator >>=? fun delegator_delegate -> + Assert.equal_pkh ~loc:__LOC__ delegator_delegate delegate_pkh + +(** Create an implicit contract, credits with [amount] + tz. Self-delegates. Create another implicit contract with + bootstrap as delegate. Re-delegate it to the first implicit + contract. *) +let test_valid_delegate_registration_switch_delegation_credit amount () = + (* create an implicit contract *) + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let delegate_account = Account.new_account () in + let delegate_pkh = Account.(delegate_account.pkh) in + let impl_contract = Contract.implicit_contract delegate_pkh in + (* credit > 0ꜩ + check balance *) + Op.transaction (I i) bootstrap impl_contract amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract amount >>=? fun _ -> + (* self delegation + verification *) + Op.delegation (I i) impl_contract (Some delegate_pkh) + >>=? fun self_delegation -> + Incremental.add_operation i self_delegation >>=? fun i -> + Context.Contract.delegate (I i) impl_contract >>=? fun delegate -> + Assert.equal_pkh ~loc:__LOC__ delegate delegate_pkh >>=? fun _ -> + (* create an implicit contract with bootstrap's account as delegate *) + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let delegator = Contract.implicit_contract unregistered_pkh in + Op.transaction ~fee:Tez.zero (I i) bootstrap delegator Tez.one + >>=? fun credit_contract -> + Incremental.add_operation i credit_contract >>=? fun i -> + Context.Contract.manager (I i) bootstrap >>=? fun bootstrap_manager -> + Op.delegation (I i) delegator (Some bootstrap_manager.pkh) + >>=? fun delegation -> + Incremental.add_operation i delegation >>=? fun i -> + (* test delegate of new contract is bootstrap *) + Context.Contract.delegate (I i) delegator >>=? fun delegator_delegate -> + Assert.equal_pkh ~loc:__LOC__ delegator_delegate bootstrap_manager.pkh + >>=? fun _ -> + (* delegation with newly registered key *) + Op.delegation (I i) delegator (Some delegate_account.pkh) + >>=? fun delegation -> + Incremental.add_operation i delegation >>=? fun i -> + Context.Contract.delegate (I i) delegator >>=? fun delegator_delegate -> + Assert.equal_pkh ~loc:__LOC__ delegator_delegate delegate_pkh + +(** Create an implicit contract. *) +let test_valid_delegate_registration_init_delegation_credit_debit amount () = + (* create an implicit contract *) + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let delegate_account = Account.new_account () in + let delegate_pkh = Account.(delegate_account.pkh) in + let impl_contract = Contract.implicit_contract delegate_pkh in + (* credit > 0ꜩ+ check balance *) + Op.transaction (I i) bootstrap impl_contract amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract amount >>=? fun _ -> + (* self delegation + verification *) + Op.delegation (I i) impl_contract (Some delegate_pkh) + >>=? fun self_delegation -> + Incremental.add_operation i self_delegation >>=? fun i -> + Context.Contract.delegate (I i) impl_contract >>=? fun delegate -> + Assert.equal_pkh ~loc:__LOC__ delegate_pkh delegate >>=? fun _ -> + (* empty implicit contracts are usually deleted but they are kept if + they were registered as delegates. we empty the contract in + order to verify this. *) + Op.transaction (I i) impl_contract bootstrap amount >>=? fun empty_contract -> + Incremental.add_operation i empty_contract >>=? fun i -> + (* impl_contract is empty *) + Assert.balance_is ~loc:__LOC__ (I i) impl_contract Tez.zero >>=? fun _ -> + (* verify self-delegation after contract is emptied *) + Context.Contract.delegate (I i) impl_contract >>=? fun delegate -> + Assert.equal_pkh ~loc:__LOC__ delegate_pkh delegate >>=? fun _ -> + (* create an implicit contract with no delegate *) + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let delegator = Contract.implicit_contract unregistered_pkh in + Op.transaction ~fee:Tez.zero (I i) bootstrap delegator Tez.one + >>=? fun credit_contract -> + Incremental.add_operation i credit_contract >>=? fun i -> + (* check no delegate for delegator contract *) + Context.Contract.delegate (I i) delegator >>= fun err -> + Assert.error ~loc:__LOC__ err (function + | RPC_context.Not_found _ -> true + | _ -> false) + >>=? fun _ -> + (* delegation to the newly registered key *) + Op.delegation (I i) delegator (Some delegate_account.pkh) + >>=? fun delegation -> + Incremental.add_operation i delegation >>=? fun i -> + (* check delegation *) + Context.Contract.delegate (I i) delegator >>=? fun delegator_delegate -> + Assert.equal_pkh ~loc:__LOC__ delegator_delegate delegate_pkh + +(** A created implicit contract is credited with [amount] tz, then is + self-delegated. It is emptied (fund back into bootstrap), and + should remain existing (as registered as delegate). Another created + implicit contract is delegated to bootstrap, then should be able to + be re-delegated to the latter contract. *) +let test_valid_delegate_registration_switch_delegation_credit_debit amount () = + (* create an implicit contract *) + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let delegate_account = Account.new_account () in + let delegate_pkh = Account.(delegate_account.pkh) in + let impl_contract = Contract.implicit_contract delegate_pkh in + (* credit > 0ꜩ + check balance *) + Op.transaction (I i) bootstrap impl_contract amount + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract amount >>=? fun _ -> + (* self delegation + verification *) + Op.delegation (I i) impl_contract (Some delegate_pkh) + >>=? fun self_delegation -> + Incremental.add_operation i self_delegation >>=? fun i -> + Context.Contract.delegate (I i) impl_contract >>=? fun delegate -> + Assert.equal_pkh ~loc:__LOC__ delegate_pkh delegate >>=? fun _ -> + (* empty implicit contracts are usually deleted but they are kept if + they were registered as delegates. we empty the contract in + order to verify this. *) + Op.transaction (I i) impl_contract bootstrap amount >>=? fun empty_contract -> + Incremental.add_operation i empty_contract >>=? fun i -> + (* impl_contract is empty *) + Assert.balance_is ~loc:__LOC__ (I i) impl_contract Tez.zero >>=? fun _ -> + (* create an implicit contract with bootstrap's account as delegate *) + let unregistered_account = Account.new_account () in + let unregistered_pkh = Account.(unregistered_account.pkh) in + let delegator = Contract.implicit_contract unregistered_pkh in + Op.transaction ~fee:Tez.zero (I i) bootstrap delegator Tez.one + >>=? fun credit_contract -> + Incremental.add_operation i credit_contract >>=? fun i -> + Context.Contract.manager (I i) bootstrap >>=? fun bootstrap_manager -> + Op.delegation (I i) delegator (Some bootstrap_manager.pkh) + >>=? fun delegation -> + Incremental.add_operation i delegation >>=? fun i -> + (* test delegate of new contract is bootstrap *) + Context.Contract.delegate (I i) delegator >>=? fun delegator_delegate -> + Assert.equal_pkh ~loc:__LOC__ delegator_delegate bootstrap_manager.pkh + >>=? fun _ -> + (* delegation with newly registered key *) + Op.delegation (I i) delegator (Some delegate_account.pkh) + >>=? fun delegation -> + Incremental.add_operation i delegation >>=? fun i -> + Context.Contract.delegate (I i) delegator >>=? fun delegator_delegate -> + Assert.equal_pkh ~loc:__LOC__ delegator_delegate delegate_pkh + +(* Part C. + A second self-delegation should raise an [Active_delegate] error. *) + +(** Second self-delegation should fail with implicit contract with + some credit. *) +let test_double_registration () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let account = Account.new_account () in + let pkh = Account.(account.pkh) in + let impl_contract = Contract.implicit_contract pkh in + (* credit 1μꜩ+ check balance *) + Op.transaction (I i) bootstrap impl_contract Tez.one_mutez + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract Tez.one_mutez >>=? fun _ -> + (* self-delegation *) + Op.delegation (I i) impl_contract (Some pkh) >>=? fun self_delegation -> + Incremental.add_operation i self_delegation >>=? fun i -> + (* second self-delegation *) + Op.delegation (I i) impl_contract (Some pkh) >>=? fun second_registration -> + Incremental.add_operation i second_registration >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Delegate_storage.Active_delegate -> true + | _ -> false) + +(** Second self-delegation should fail with implicit contract emptied + after first self-delegation. *) +let test_double_registration_when_empty () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let account = Account.new_account () in + let pkh = Account.(account.pkh) in + let impl_contract = Contract.implicit_contract pkh in + (* credit 1μꜩ+ check balance *) + Op.transaction (I i) bootstrap impl_contract Tez.one_mutez + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract Tez.one_mutez >>=? fun _ -> + (* self delegation *) + Op.delegation (I i) impl_contract (Some pkh) >>=? fun self_delegation -> + Incremental.add_operation i self_delegation >>=? fun i -> + (* empty the delegate account *) + Op.transaction (I i) impl_contract bootstrap Tez.one_mutez + >>=? fun empty_contract -> + Incremental.add_operation i empty_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract Tez.zero >>=? fun _ -> + (* second self-delegation *) + Op.delegation (I i) impl_contract (Some pkh) >>=? fun second_registration -> + Incremental.add_operation i second_registration >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Delegate_storage.Active_delegate -> true + | _ -> false) + +(** Second self-delegation should fail with implicit contract emptied + then credited back after first self-delegation. *) +let test_double_registration_when_recredited () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let account = Account.new_account () in + let pkh = Account.(account.pkh) in + let impl_contract = Contract.implicit_contract pkh in + (* credit 1μꜩ+ check balance *) + Op.transaction (I i) bootstrap impl_contract Tez.one_mutez + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract Tez.one_mutez >>=? fun _ -> + (* self delegation *) + Op.delegation (I i) impl_contract (Some pkh) >>=? fun self_delegation -> + Incremental.add_operation i self_delegation >>=? fun i -> + (* empty the delegate account *) + Op.transaction (I i) impl_contract bootstrap Tez.one_mutez + >>=? fun empty_contract -> + Incremental.add_operation i empty_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract Tez.zero >>=? fun _ -> + (* credit 1μꜩ+ check balance *) + Op.transaction (I i) bootstrap impl_contract Tez.one_mutez + >>=? fun create_contract -> + Incremental.add_operation i create_contract >>=? fun i -> + Assert.balance_is ~loc:__LOC__ (I i) impl_contract Tez.one_mutez >>=? fun _ -> + (* second self-delegation *) + Op.delegation (I i) impl_contract (Some pkh) >>=? fun second_registration -> + Incremental.add_operation i second_registration >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Delegate_storage.Active_delegate -> true + | _ -> false) + +(** Self-delegation on unrevealed contract. *) +let test_unregistered_and_unrevealed_self_delegate_key_init_delegation ~fee () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let {Account.pkh; _} = Account.new_account () in + let {Account.pkh = delegate_pkh; _} = Account.new_account () in + let contract = Alpha_context.Contract.implicit_contract pkh in + Op.transaction (I i) bootstrap contract (Tez.of_int 10) >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + Op.delegation ~fee (I i) contract (Some delegate_pkh) >>=? fun op -> + Context.Contract.balance (I i) contract >>=? fun balance -> + if fee > balance then + Incremental.add_operation i op >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + (* origination did not proceed; fee has been debited *) + Incremental.add_operation + ~expect_failure:(expect_unregistered_key delegate_pkh) + i + op + >>=? fun i -> + Assert.balance_was_debited ~loc:__LOC__ (I i) contract balance fee + +(** Self-delegation on revealed but not registered contract. *) +let test_unregistered_and_revealed_self_delegate_key_init_delegation ~fee () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let {Account.pkh; pk; _} = Account.new_account () in + let {Account.pkh = delegate_pkh; _} = Account.new_account () in + let contract = Alpha_context.Contract.implicit_contract pkh in + Op.transaction (I i) bootstrap contract (Tez.of_int 10) >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + Op.revelation (I i) pk >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + Op.delegation ~fee (I i) contract (Some delegate_pkh) >>=? fun op -> + Context.Contract.balance (I i) contract >>=? fun balance -> + if fee > balance then + Incremental.add_operation i op >>= fun err -> + Assert.proto_error ~loc:__LOC__ err (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + else + (* origination did not proceed; fee has been debited *) + Incremental.add_operation + ~expect_failure:(expect_unregistered_key delegate_pkh) + i + op + >>=? fun i -> + Assert.balance_was_debited ~loc:__LOC__ (I i) contract balance fee + +(** Self-delegation on revealed and registered contract. *) +let test_registered_self_delegate_key_init_delegation () = + Context.init 1 >>=? fun (b, bootstrap_contracts) -> + Incremental.begin_construction b >>=? fun i -> + let bootstrap = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bootstrap_contracts + in + let {Account.pkh; _} = Account.new_account () in + let {Account.pkh = delegate_pkh; pk = delegate_pk; _} = + Account.new_account () + in + let contract = Alpha_context.Contract.implicit_contract pkh in + let delegate_contract = + Alpha_context.Contract.implicit_contract delegate_pkh + in + Op.transaction (I i) bootstrap contract (Tez.of_int 10) >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + Op.transaction (I i) bootstrap delegate_contract (Tez.of_int 1) >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + Op.revelation (I i) delegate_pk >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + Op.delegation (I i) delegate_contract (Some delegate_pkh) >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + Op.delegation (I i) contract (Some delegate_pkh) >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + Context.Contract.delegate (I i) contract >>=? fun delegate -> + Assert.equal_pkh ~loc:__LOC__ delegate delegate_pkh >>=? fun () -> return_unit + +let tests_delegate_registration = + [ + (*** unregistered delegate key: no self-delegation ***) + (* no token transfer, no self-delegation *) + Tztest.tztest + "unregistered delegate key (origination, small fee)" + `Quick + (test_unregistered_delegate_key_init_origination ~fee:Tez.one_mutez); + Tztest.tztest + "unregistered delegate key (origination, edge case fee)" + `Quick + (test_unregistered_delegate_key_init_origination + ~fee:(Tez.of_int 3_999_488)); + Tztest.tztest + "unregistered delegate key (origination, large fee)" + `Quick + (test_unregistered_delegate_key_init_origination + ~fee:(Tez.of_int 10_000_000)); + Tztest.tztest + "unregistered delegate key (init with delegation, small fee)" + `Quick + (test_unregistered_delegate_key_init_delegation ~fee:Tez.one_mutez); + Tztest.tztest + "unregistered delegate key (init with delegation, max fee)" + `Quick + (test_unregistered_delegate_key_init_delegation ~fee:Tez.max_tez); + Tztest.tztest + "unregistered delegate key (switch with delegation, small fee)" + `Quick + (test_unregistered_delegate_key_switch_delegation ~fee:Tez.one_mutez); + Tztest.tztest + "unregistered delegate key (switch with delegation, max fee)" + `Quick + (test_unregistered_delegate_key_switch_delegation ~fee:Tez.max_tez); + (* credit/debit 1μꜩ, no self-delegation *) + Tztest.tztest + "unregistered delegate key - credit/debit 1μꜩ (origination, small fee)" + `Quick + (test_unregistered_delegate_key_init_origination_credit_debit + ~fee:Tez.one_mutez + ~amount:Tez.one_mutez); + Tztest.tztest + "unregistered delegate key - credit/debit 1μꜩ (origination, large fee)" + `Quick + (test_unregistered_delegate_key_init_origination_credit_debit + ~fee:Tez.max_tez + ~amount:Tez.one_mutez); + Tztest.tztest + "unregistered delegate key - credit/debit 1μꜩ (init with delegation, \ + small fee)" + `Quick + (test_unregistered_delegate_key_init_delegation_credit_debit + ~amount:Tez.one_mutez + ~fee:Tez.one_mutez); + Tztest.tztest + "unregistered delegate key - credit/debit 1μꜩ (init with delegation, \ + large fee)" + `Quick + (test_unregistered_delegate_key_init_delegation_credit_debit + ~amount:Tez.one_mutez + ~fee:Tez.max_tez); + Tztest.tztest + "unregistered delegate key - credit/debit 1μꜩ (switch with \ + delegation, small fee)" + `Quick + (test_unregistered_delegate_key_switch_delegation_credit_debit + ~amount:Tez.one_mutez + ~fee:Tez.one_mutez); + Tztest.tztest + "unregistered delegate key - credit/debit 1μꜩ (switch with \ + delegation, large fee)" + `Quick + (test_unregistered_delegate_key_switch_delegation_credit_debit + ~amount:Tez.one_mutez + ~fee:Tez.max_tez); + (* credit 1μꜩ, no self-delegation *) + Tztest.tztest + "unregistered delegate key - credit 1μꜩ (origination, small fee)" + `Quick + (test_unregistered_delegate_key_init_origination_credit + ~fee:Tez.one_mutez + ~amount:Tez.one_mutez); + Tztest.tztest + "unregistered delegate key - credit 1μꜩ (origination, edge case fee)" + `Quick + (test_unregistered_delegate_key_init_origination_credit + ~fee:(Tez.of_int 3_999_488) + ~amount:Tez.one_mutez); + Tztest.tztest + "unregistered delegate key - credit 1μꜩ (origination, large fee)" + `Quick + (test_unregistered_delegate_key_init_origination_credit + ~fee:(Tez.of_int 10_000_000) + ~amount:Tez.one_mutez); + Tztest.tztest + "unregistered delegate key - credit 1μꜩ (init with delegation, small \ + fee)" + `Quick + (test_unregistered_delegate_key_init_delegation_credit + ~amount:Tez.one_mutez + ~fee:Tez.one_mutez); + Tztest.tztest + "unregistered delegate key - credit 1μꜩ (init with delegation, large \ + fee)" + `Quick + (test_unregistered_delegate_key_init_delegation_credit + ~amount:Tez.one_mutez + ~fee:Tez.max_tez); + Tztest.tztest + "unregistered delegate key - credit 1μꜩ (switch with delegation, \ + small fee)" + `Quick + (test_unregistered_delegate_key_switch_delegation_credit + ~amount:Tez.one_mutez + ~fee:Tez.one_mutez); + Tztest.tztest + "unregistered delegate key - credit 1μꜩ (switch with delegation, \ + large fee)" + `Quick + (test_unregistered_delegate_key_switch_delegation_credit + ~amount:Tez.one_mutez + ~fee:Tez.max_tez); + (* self delegation on unrevealed and unregistered contract *) + Tztest.tztest + "unregistered and unrevealed self-delegation (small fee)" + `Quick + (test_unregistered_and_unrevealed_self_delegate_key_init_delegation + ~fee:Tez.one_mutez); + Tztest.tztest + "unregistered and unrevealed self-delegation (large fee)" + `Quick + (test_unregistered_and_unrevealed_self_delegate_key_init_delegation + ~fee:Tez.max_tez); + (* self delegation on unregistered contract *) + Tztest.tztest + "unregistered and revealed self-delegation (small fee)" + `Quick + (test_unregistered_and_revealed_self_delegate_key_init_delegation + ~fee:Tez.one_mutez); + Tztest.tztest + "unregistered and revealed self-delegation large fee)" + `Quick + (test_unregistered_and_revealed_self_delegate_key_init_delegation + ~fee:Tez.max_tez); + (* self delegation on registered contract *) + Tztest.tztest + "registered and revealed self-delegation" + `Quick + test_registered_self_delegate_key_init_delegation; + (*** unregistered delegate key: failed self-delegation ***) + (* no token transfer, self-delegation *) + Tztest.tztest + "failed self-delegation: no transaction" + `Quick + test_failed_self_delegation_no_transaction; + (* credit 1μtz, debit 1μtz, self-delegation *) + Tztest.tztest + "failed self-delegation: credit & debit 1μꜩ" + `Quick + (test_failed_self_delegation_emptied_implicit_contract Tez.one_mutez); + (* credit 1μtz, delegate, debit 1μtz *) + Tztest.tztest + "empty delegated contract is not deleted: credit 1μꜩ, delegate & \ + debit 1μꜩ" + `Quick + (test_emptying_delegated_implicit_contract_fails Tez.one_mutez); + (*** valid registration ***) + (* valid registration: credit 1 μꜩ, self delegation *) + Tztest.tztest + "valid delegate registration: credit 1μꜩ, self delegation (init with \ + delegation)" + `Quick + (test_valid_delegate_registration_init_delegation_credit Tez.one_mutez); + Tztest.tztest + "valid delegate registration: credit 1μꜩ, self delegation (switch \ + with delegation)" + `Quick + (test_valid_delegate_registration_switch_delegation_credit Tez.one_mutez); + (* valid registration: credit 1 μꜩ, self delegation, debit 1μꜩ *) + Tztest.tztest + "valid delegate registration: credit 1μꜩ, self delegation, debit \ + 1μꜩ (init with delegation)" + `Quick + (test_valid_delegate_registration_init_delegation_credit_debit + Tez.one_mutez); + Tztest.tztest + "valid delegate registration: credit 1μꜩ, self delegation, debit \ + 1μꜩ (switch with delegation)" + `Quick + (test_valid_delegate_registration_switch_delegation_credit_debit + Tez.one_mutez); + (*** double registration ***) + Tztest.tztest "double registration" `Quick test_double_registration; + Tztest.tztest + "double registration when delegate account is emptied" + `Quick + test_double_registration_when_empty; + Tztest.tztest + "double registration when delegate account is emptied and then recredited" + `Quick + test_double_registration_when_recredited; + ] + +(******************************************************************************) +(* Main *) +(******************************************************************************) + +let tests = tests_bootstrap_contracts @ tests_delegate_registration diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_double_baking.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_double_baking.ml new file mode 100644 index 000000000000..4f9ea355a116 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_double_baking.ml @@ -0,0 +1,197 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (double baking) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^double baking$" + Subject: Double baking evidence operation may happen when a baker + baked two different blocks on the same level. +*) + +open Protocol +open Alpha_context + +(****************************************************************) +(* Utility functions *) +(****************************************************************) + +let get_hd_hd = function x :: y :: _ -> (x, y) | _ -> assert false + +let get_first_different_baker baker bakers = + WithExceptions.Option.get ~loc:__LOC__ + @@ List.find + (fun baker' -> Signature.Public_key_hash.( <> ) baker baker') + bakers + +let get_first_different_bakers ctxt = + Context.get_bakers ctxt >|=? function + | [] | [_] -> assert false + | baker_1 :: other_bakers -> + (baker_1, get_first_different_baker baker_1 other_bakers) + +let get_first_different_endorsers ctxt = + Context.get_endorsers ctxt >|=? fun endorsers -> get_hd_hd endorsers + +(** Bake two block at the same level using the same policy (i.e. same + baker). *) +let block_fork ?policy contracts b = + let (contract_a, contract_b) = get_hd_hd contracts in + Op.transaction (B b) contract_a contract_b Alpha_context.Tez.one_cent + >>=? fun operation -> + Block.bake ?policy ~operation b >>=? fun blk_a -> + Block.bake ?policy b >|=? fun blk_b -> (blk_a, blk_b) + +(****************************************************************) +(* Tests *) +(****************************************************************) + +(** Simple scenario where two blocks are baked by a same baker and + exposed by a double baking evidence operation. *) +let test_valid_double_baking_evidence () = + Context.init 2 >>=? fun (b, contracts) -> + Context.get_bakers (B b) >>=? fun bakers -> + let priority_0_baker = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd bakers + in + block_fork ~policy:(By_priority 0) contracts b >>=? fun (blk_a, blk_b) -> + Op.double_baking (B blk_a) blk_a.header blk_b.header |> fun operation -> + Block.bake ~policy:(Excluding [priority_0_baker]) ~operation blk_a + >>=? fun blk -> + (* Check that the frozen deposit, the fees and rewards are removed *) + List.iter_es + (fun kind -> + let contract = + Alpha_context.Contract.implicit_contract priority_0_baker + in + Assert.balance_is ~loc:__LOC__ (B blk) contract ~kind Tez.zero) + [Deposit; Fees; Rewards] + +(****************************************************************) +(* The following test scenarios are supposed to raise errors. *) +(****************************************************************) + +(** Check that a double baking operation fails if it exposes the same two + blocks. *) +let test_same_blocks () = + Context.init 2 >>=? fun (b, _contracts) -> + Block.bake b >>=? fun ba -> + Op.double_baking (B ba) ba.header ba.header |> fun operation -> + Block.bake ~operation ba >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Invalid_double_baking_evidence _ -> true + | _ -> false) + >>=? fun () -> return_unit + +(** Check that a double baking operation exposing two blocks with + different levels fails. *) +let test_different_levels () = + Context.init 2 >>=? fun (b, contracts) -> + block_fork ~policy:(By_priority 0) contracts b >>=? fun (blk_a, blk_b) -> + Block.bake blk_b >>=? fun blk_b_2 -> + Op.double_baking (B blk_a) blk_a.header blk_b_2.header |> fun operation -> + Block.bake ~operation blk_a >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Invalid_double_baking_evidence _ -> true + | _ -> false) + +(** Check that a double baking operation exposing two yet-to-be-baked + blocks fails. *) +let test_too_early_double_baking_evidence () = + Context.init 2 >>=? fun (b, contracts) -> + block_fork ~policy:(By_priority 0) contracts b >>=? fun (blk_a, blk_b) -> + Op.double_baking (B b) blk_a.header blk_b.header |> fun operation -> + Block.bake ~operation b >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Too_early_double_baking_evidence _ -> true + | _ -> false) + +(** Check that after [preserved_cycles + 1], it is not possible to + create a double baking operation anymore. *) +let test_too_late_double_baking_evidence () = + Context.init 2 >>=? fun (b, contracts) -> + Context.get_constants (B b) + >>=? fun Constants.{parametric = {preserved_cycles; _}; _} -> + block_fork ~policy:(By_priority 0) contracts b >>=? fun (blk_a, blk_b) -> + List.fold_left_es + (fun blk _ -> Block.bake_until_cycle_end blk) + blk_a + (1 -- (preserved_cycles + 1)) + >>=? fun blk -> + Op.double_baking (B blk) blk_a.header blk_b.header |> fun operation -> + Block.bake ~operation blk >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Outdated_double_baking_evidence _ -> true + | _ -> false) + +(** Check that an invalid double baking evidence that exposes two + block baking with same level made by different bakers fails. *) +let test_different_delegates () = + Context.init 2 >>=? fun (b, _) -> + get_first_different_bakers (B b) >>=? fun (baker_1, baker_2) -> + Block.bake ~policy:(By_account baker_1) b >>=? fun blk_a -> + Block.bake ~policy:(By_account baker_2) b >>=? fun blk_b -> + Op.double_baking (B blk_a) blk_a.header blk_b.header |> fun operation -> + Block.bake ~operation blk_a >>= fun e -> + Assert.proto_error ~loc:__LOC__ e (function + | Apply.Inconsistent_double_baking_evidence _ -> true + | _ -> false) + +(** Baker_2 bakes a block but baker signs it. *) +let test_wrong_signer () = + let header_custom_signer baker baker_2 b = + Block.Forge.forge_header ~policy:(By_account baker_2) b >>=? fun header -> + Block.Forge.set_baker baker header |> Block.Forge.sign_header + in + Context.init 2 >>=? fun (b, _) -> + get_first_different_bakers (B b) >>=? fun (baker_1, baker_2) -> + Block.bake ~policy:(By_account baker_1) b >>=? fun blk_a -> + header_custom_signer baker_1 baker_2 b >>=? fun header_b -> + Op.double_baking (B blk_a) blk_a.header header_b |> fun operation -> + Block.bake ~operation blk_a >>= fun e -> + Assert.proto_error ~loc:__LOC__ e (function + | Baking.Invalid_block_signature _ -> true + | _ -> false) + +let tests = + [ + Tztest.tztest + "valid double baking evidence" + `Quick + test_valid_double_baking_evidence; + (* Should fail*) + Tztest.tztest "same blocks" `Quick test_same_blocks; + Tztest.tztest "different levels" `Quick test_different_levels; + Tztest.tztest + "too early double baking evidence" + `Quick + test_too_early_double_baking_evidence; + Tztest.tztest + "too late double baking evidence" + `Quick + test_too_late_double_baking_evidence; + Tztest.tztest "different delegates" `Quick test_different_delegates; + Tztest.tztest "wrong delegate" `Quick test_wrong_signer; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_double_endorsement.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_double_endorsement.ml new file mode 100644 index 000000000000..05d457f05ca8 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_double_endorsement.ml @@ -0,0 +1,239 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (double endorsement) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^double endorsement$" + Subject: Double endorsement evidence operation may happen when an + endorser endorsed two different blocks on the same level. +*) + +open Protocol +open Alpha_context + +(****************************************************************) +(* Utility functions *) +(****************************************************************) + +let get_hd_hd = function x :: y :: _ -> (x, y) | _ -> assert false + +let get_first_different_baker baker bakers = + WithExceptions.Option.get ~loc:__LOC__ + @@ List.find + (fun baker' -> Signature.Public_key_hash.( <> ) baker baker') + bakers + +let get_first_different_bakers ctxt = + Context.get_bakers ctxt >|=? function + | [] -> assert false + | baker_1 :: other_bakers -> + (baker_1, get_first_different_baker baker_1 other_bakers) + +let get_first_different_endorsers ctxt = + Context.get_endorsers ctxt >|=? fun endorsers -> get_hd_hd endorsers + +let block_fork b = + get_first_different_bakers (B b) >>=? fun (baker_1, baker_2) -> + Block.bake ~policy:(By_account baker_1) b >>=? fun blk_a -> + Block.bake ~policy:(By_account baker_2) b >|=? fun blk_b -> (blk_a, blk_b) + +(****************************************************************) +(* Tests *) +(****************************************************************) + +(** Simple scenario where two endorsements are made from the same + delegate and exposed by a double_endorsement operation. Also verify + that punishment is operated. *) +let test_valid_double_endorsement_evidence () = + Context.init 2 >>=? fun (b, _) -> + block_fork b >>=? fun (blk_a, blk_b) -> + Context.get_endorser (B blk_a) >>=? fun (delegate, slots) -> + Op.endorsement ~delegate (B blk_a) () >>=? fun endorsement_a -> + Op.endorsement ~delegate (B blk_b) () >>=? fun endorsement_b -> + Op.endorsement_with_slot ~delegate:(delegate, slots) (B blk_a) () + >>=? fun endorsement_with_slot_a -> + Block.bake ~operations:[Operation.pack endorsement_with_slot_a] blk_a + >>=? fun blk_a -> + (* Block.bake ~operations:[endorsement_b] blk_b >>=? fun _ -> *) + Op.double_endorsement + (B blk_a) + endorsement_a + endorsement_b + ~slot:(WithExceptions.Option.get ~loc:__LOC__ (List.hd slots)) + |> fun operation -> + (* Bake with someone different than the bad endorser *) + Context.get_bakers (B blk_a) >>=? fun bakers -> + get_first_different_baker delegate bakers |> fun baker -> + Block.bake ~policy:(By_account baker) ~operation blk_a >>=? fun blk -> + (* Check that the frozen deposit, the fees and rewards are removed *) + List.iter_es + (fun kind -> + let contract = Alpha_context.Contract.implicit_contract delegate in + Assert.balance_is ~loc:__LOC__ (B blk) contract ~kind Tez.zero) + [Deposit; Fees; Rewards] + +(****************************************************************) +(* The following test scenarios are supposed to raise errors. *) +(****************************************************************) + +(** Check that an invalid double endorsement operation that exposes a + valid endorsement fails. *) +let test_invalid_double_endorsement () = + Context.init 10 >>=? fun (b, _) -> + Block.bake b >>=? fun b -> + Op.endorsement (B b) () >>=? fun endorsement -> + Op.endorsement_with_slot (B b) () >>=? fun endorsement_with_slot -> + Block.bake ~operation:(Operation.pack endorsement_with_slot) b >>=? fun b -> + Op.double_endorsement (B b) endorsement endorsement ~slot:0 + |> fun operation -> + Block.bake ~operation b >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Invalid_double_endorsement_evidence -> true + | _ -> false) + +(** Check that a double endorsement added at the same time as a double + endorsement operation fails. *) +let test_too_early_double_endorsement_evidence () = + Context.init 2 >>=? fun (b, _) -> + block_fork b >>=? fun (blk_a, blk_b) -> + Context.get_endorser (B blk_a) >>=? fun (delegate, slots) -> + Op.endorsement ~delegate (B blk_a) () >>=? fun endorsement_a -> + Op.endorsement ~delegate (B blk_b) () >>=? fun endorsement_b -> + Op.double_endorsement + (B b) + endorsement_a + endorsement_b + ~slot:(WithExceptions.Option.get ~loc:__LOC__ (List.hd slots)) + |> fun operation -> + Block.bake ~operation b >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Too_early_double_endorsement_evidence _ -> true + | _ -> false) + +(** Check that after [preserved_cycles + 1], it is not possible + to create a double_endorsement anymore. *) +let test_too_late_double_endorsement_evidence () = + Context.init 2 >>=? fun (b, _) -> + Context.get_constants (B b) + >>=? fun Constants.{parametric = {preserved_cycles; _}; _} -> + block_fork b >>=? fun (blk_a, blk_b) -> + Context.get_endorser (B blk_a) >>=? fun (delegate, slots) -> + Op.endorsement ~delegate (B blk_a) () >>=? fun endorsement_a -> + Op.endorsement ~delegate (B blk_b) () >>=? fun endorsement_b -> + List.fold_left_es + (fun blk _ -> Block.bake_until_cycle_end blk) + blk_a + (1 -- (preserved_cycles + 1)) + >>=? fun blk -> + Op.double_endorsement + (B blk) + endorsement_a + endorsement_b + ~slot:(WithExceptions.Option.get ~loc:__LOC__ (List.hd slots)) + |> fun operation -> + Block.bake ~operation blk >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Outdated_double_endorsement_evidence _ -> true + | _ -> false) + +(** Check that an invalid double endorsement evidence that exposes two + endorsements made by two different endorsers fails. *) +let test_different_delegates () = + Context.init 2 >>=? fun (b, _) -> + Block.bake b >>=? fun b -> + block_fork b >>=? fun (blk_a, blk_b) -> + Context.get_endorser (B blk_a) >>=? fun (endorser_a, _a_slots) -> + get_first_different_endorsers (B blk_b) + >>=? fun (endorser_b1c, endorser_b2c) -> + let (endorser_b, b_slots) = + if Signature.Public_key_hash.( = ) endorser_a endorser_b1c.delegate then + (endorser_b2c.delegate, endorser_b2c.slots) + else (endorser_b1c.delegate, endorser_b1c.slots) + in + Op.endorsement ~delegate:endorser_a (B blk_a) () >>=? fun e_a -> + Op.endorsement ~delegate:endorser_b (B blk_b) () >>=? fun e_b -> + Op.endorsement_with_slot ~delegate:(endorser_b, b_slots) (B blk_b) () + >>=? fun e_ws_b -> + Block.bake ~operation:(Operation.pack e_ws_b) blk_b >>=? fun _ -> + Op.double_endorsement + (B blk_b) + e_a + e_b + ~slot:(WithExceptions.Option.get ~loc:__LOC__ (List.hd b_slots)) + |> fun operation -> + Block.bake ~operation blk_b >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Baking.Unexpected_endorsement -> true + | _ -> false) + +(** Check that a double endorsement evidence that exposes a ill-formed + endorsement fails. *) +let test_wrong_delegate () = + Context.init ~endorsers_per_block:1 2 >>=? fun (b, contracts) -> + List.map_es (Context.Contract.manager (B b)) contracts >>=? fun accounts -> + let (account_1, account_2) = get_hd_hd accounts in + let pkh1 = account_1.Account.pkh in + let pkh2 = account_2.Account.pkh in + block_fork b >>=? fun (blk_a, blk_b) -> + Context.get_endorser (B blk_a) >>=? fun (endorser_a, a_slots) -> + Op.endorsement ~delegate:endorser_a (B blk_a) () >>=? fun endorsement_a -> + Context.get_endorser (B blk_b) >>=? fun (endorser_b, _b_slots) -> + let delegate = + if Signature.Public_key_hash.equal pkh1 endorser_b then pkh2 else pkh1 + in + Op.endorsement ~delegate (B blk_b) () >>=? fun endorsement_b -> + Op.double_endorsement + (B blk_b) + endorsement_a + endorsement_b + ~slot:(WithExceptions.Option.get ~loc:__LOC__ (List.hd a_slots)) + |> fun operation -> + Block.bake ~operation blk_b >>= fun e -> + Assert.proto_error ~loc:__LOC__ e (function + | Baking.Unexpected_endorsement -> true + | _ -> false) + +let tests = + [ + Tztest.tztest + "valid double endorsement evidence" + `Quick + test_valid_double_endorsement_evidence; + Tztest.tztest + "invalid double endorsement evidence" + `Quick + test_invalid_double_endorsement; + Tztest.tztest + "too early double endorsement evidence" + `Quick + test_too_early_double_endorsement_evidence; + Tztest.tztest + "too late double endorsement evidence" + `Quick + test_too_late_double_endorsement_evidence; + Tztest.tztest "different delegates" `Quick test_different_delegates; + Tztest.tztest "wrong delegate" `Quick test_wrong_delegate; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_endorsement.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_endorsement.ml new file mode 100644 index 000000000000..728effbbbc9a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_endorsement.ml @@ -0,0 +1,684 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (endorsement) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^endorsement$" + Subject: Endorsing a block adds an extra layer of confidence to the + Tezos' PoS algorithm. The block endorsing operation must be + included in the following block. Each endorser possesses a + number of slots corresponding to their priority. After + [preserved_cycles], a reward is given to the endorser. This + reward depends on the priority of the block that contains + the endorsements. +*) + +open Protocol +open Alpha_context +open Test_tez + +(****************************************************************) +(* Utility functions *) +(****************************************************************) + +let get_hd_hd = function x :: y :: _ -> (x, y) | _ -> assert false + +let get_expected_reward ctxt ~priority ~baker ~endorsing_power = + (if baker then Context.get_baking_reward ctxt ~priority ~endorsing_power + else return (Test_tez.Tez.of_int 0)) + >>=? fun baking_reward -> + Context.get_endorsing_reward ctxt ~priority ~endorsing_power + >>=? fun endorsing_reward -> + Test_tez.Tez.(endorsing_reward +? baking_reward) >>?= fun reward -> + return reward + +let get_expected_deposit ctxt ~baker ~endorsing_power = + Context.get_constants ctxt + >>=? fun Constants. + { + parametric = + {endorsement_security_deposit; block_security_deposit; _}; + _; + } -> + let open Environment in + let open Tez in + let baking_deposit = if baker then block_security_deposit else of_int 0 in + endorsement_security_deposit *? Int64.of_int endorsing_power + >>?= fun endorsement_deposit -> + endorsement_deposit +? baking_deposit >>?= fun deposit -> return deposit + +(* [baker] is true if the [pkh] has also baked the current block, in + which case corresponding deposit and reward should be adjusted *) +let assert_endorser_balance_consistency ~loc ?(priority = 0) ?(baker = false) + ~endorsing_power ctxt pkh initial_balance = + let contract = Contract.implicit_contract pkh in + get_expected_reward ctxt ~priority ~baker ~endorsing_power >>=? fun reward -> + get_expected_deposit ctxt ~baker ~endorsing_power >>=? fun deposit -> + Assert.balance_was_debited ~loc ctxt contract initial_balance deposit + >>=? fun () -> + Context.Contract.balance ~kind:Rewards ctxt contract + >>=? fun reward_balance -> + Assert.equal_tez ~loc reward_balance reward >>=? fun () -> + Context.Contract.balance ~kind:Deposit ctxt contract + >>=? fun deposit_balance -> Assert.equal_tez ~loc deposit_balance deposit + +let delegates_with_slots endorsers = + List.map + (fun (endorser : Plugin.RPC.Endorsing_rights.t) -> + (endorser.delegate, endorser.slots)) + endorsers + +let endorsing_power endorsers = + List.fold_left + (fun sum (endorser : Plugin.RPC.Endorsing_rights.t) -> + sum + List.length endorser.slots) + 0 + endorsers + +(****************************************************************) +(* Tests *) +(****************************************************************) + +(** Apply a single endorsement from the slot 0 endorser. *) +let test_simple_endorsement () = + Context.init 5 >>=? fun (b, _) -> + Context.get_endorser (B b) >>=? fun (delegate, slots) -> + Op.endorsement_with_slot ~delegate:(delegate, slots) (B b) () >>=? fun op -> + Context.Contract.balance (B b) (Contract.implicit_contract delegate) + >>=? fun initial_balance -> + let policy = Block.Excluding [delegate] in + Block.get_next_baker ~policy b >>=? fun (_, priority, _) -> + Block.bake ~policy ~operations:[Operation.pack op] b >>=? fun b2 -> + assert_endorser_balance_consistency + ~loc:__LOC__ + (B b2) + ~priority + ~endorsing_power:(List.length slots) + delegate + initial_balance + +(** Apply a maximum number of endorsements. An endorser can be + selected twice. *) +let test_max_endorsement () = + let endorsers_per_block = 16 in + Context.init ~endorsers_per_block 32 >>=? fun (b, _) -> + Context.get_endorsers (B b) >>=? fun endorsers -> + Assert.equal_int + ~loc:__LOC__ + (List.length + (List.concat + (List.map + (fun {Plugin.RPC.Endorsing_rights.slots; _} -> slots) + endorsers))) + endorsers_per_block + >>=? fun () -> + List.fold_left_es + (fun (delegates, ops, balances) (endorser : Plugin.RPC.Endorsing_rights.t) -> + let delegate = endorser.delegate in + Context.Contract.balance (B b) (Contract.implicit_contract delegate) + >>=? fun balance -> + Op.endorsement_with_slot ~delegate:(delegate, endorser.slots) (B b) () + >|=? fun op -> + ( delegate :: delegates, + Operation.pack op :: ops, + (List.length endorser.slots, balance) :: balances )) + ([], [], []) + endorsers + >>=? fun (delegates, ops, previous_balances) -> + Block.bake ~policy:(Excluding delegates) ~operations:(List.rev ops) b + >>=? fun b -> + (* One account can endorse more than one time per level, we must + check that the bonds are summed up *) + List.iter2_es + ~when_different_lengths:(TzTrace.make (Exn (Failure __LOC__))) + (fun endorser_account (endorsing_power, previous_balance) -> + assert_endorser_balance_consistency + ~loc:__LOC__ + (B b) + ~endorsing_power + endorser_account + previous_balance) + delegates + previous_balances + +(** Check that every endorsers' balances are consistent with different + priorities. *) +let test_consistent_priorities () = + let priorities = 0 -- 64 in + Context.init 64 >>=? fun (b, _) -> + List.fold_left_es + (fun (b, used_pkhes) priority -> + (* Choose an endorser that has not baked nor endorsed before *) + Context.get_endorsers (B b) >>=? fun endorsers -> + let endorser = + List.find_opt + (fun (e : Plugin.RPC.Endorsing_rights.t) -> + not (Signature.Public_key_hash.Set.mem e.delegate used_pkhes)) + endorsers + in + match endorser with + | None -> + return (b, used_pkhes) (* not enough fresh endorsers; we "stop" *) + | Some endorser -> + Context.Contract.balance + (B b) + (Contract.implicit_contract endorser.delegate) + >>=? fun balance -> + Op.endorsement_with_slot + ~delegate:(endorser.delegate, endorser.slots) + (B b) + () + >>=? fun operation -> + let operation = Operation.pack operation in + Block.get_next_baker ~policy:(By_priority priority) b + >>=? fun (baker, _, _) -> + let used_pkhes = Signature.Public_key_hash.Set.add baker used_pkhes in + let used_pkhes = + Signature.Public_key_hash.Set.add endorser.delegate used_pkhes + in + (* Bake with a specific priority *) + Block.bake ~policy:(By_priority priority) ~operation b >>=? fun b -> + let is_baker = + Signature.Public_key_hash.(baker = endorser.delegate) + in + assert_endorser_balance_consistency + ~loc:__LOC__ + ~priority + ~baker:is_baker + (B b) + ~endorsing_power:(List.length endorser.slots) + endorser.delegate + balance + >|=? fun () -> (b, used_pkhes)) + (b, Signature.Public_key_hash.Set.empty) + priorities + >>=? fun _b -> return_unit + +(** Check that after [preserved_cycles] number of cycles the endorser + gets his reward. *) +let test_reward_retrieval () = + Context.init 5 >>=? fun (b, _) -> + Context.get_constants (B b) + >>=? fun Constants.{parametric = {preserved_cycles; _}; _} -> + Context.get_endorser (B b) >>=? fun (endorser, slots) -> + Context.Contract.balance (B b) (Contract.implicit_contract endorser) + >>=? fun balance -> + Op.endorsement_with_slot ~delegate:(endorser, slots) (B b) () + >>=? fun operation -> + let operation = Operation.pack operation in + let policy = Block.Excluding [endorser] in + Block.get_next_baker ~policy b >>=? fun (_, priority, _) -> + Block.bake ~policy ~operation b >>=? fun b -> + (* Bake (preserved_cycles + 1) cycles *) + List.fold_left_es + (fun b _ -> Block.bake_until_cycle_end ~policy:(Excluding [endorser]) b) + b + (0 -- preserved_cycles) + >>=? fun b -> + get_expected_reward + (B b) + ~priority + ~baker:false + ~endorsing_power:(List.length slots) + >>=? fun reward -> + Assert.balance_was_credited + ~loc:__LOC__ + (B b) + (Contract.implicit_contract endorser) + balance + reward + +(** Check that after [preserved_cycles] number of cycles endorsers get + their reward. Two endorsers are used and they endorse in different + cycles. *) +let test_reward_retrieval_two_endorsers () = + Context.init 5 >>=? fun (b, _) -> + Context.get_constants (B b) + >>=? fun Constants. + { + parametric = {preserved_cycles; endorsement_security_deposit; _}; + _; + } -> + Context.get_endorsers (B b) >>=? fun endorsers -> + let (endorser1, endorser2) = get_hd_hd endorsers in + Context.Contract.balance (B b) (Contract.implicit_contract endorser1.delegate) + >>=? fun balance1 -> + Context.Contract.balance (B b) (Contract.implicit_contract endorser2.delegate) + >>=? fun balance2 -> + Tez.( + endorsement_security_deposit *? Int64.of_int (List.length endorser1.slots)) + >>?= fun security_deposit1 -> + (* endorser1 endorses the genesis block in cycle 0 *) + Op.endorsement_with_slot + ~delegate:(endorser1.delegate, endorser1.slots) + (B b) + () + >>=? fun operation1 -> + let policy = Block.Excluding [endorser1.delegate; endorser2.delegate] in + Block.get_next_baker ~policy b >>=? fun (_, priority, _) -> + Context.get_endorsing_reward + (B b) + ~priority + ~endorsing_power:(List.length endorser1.slots) + >>=? fun reward1 -> + (* bake next block, include endorsement of endorser1 *) + Block.bake ~policy ~operation:(Operation.pack operation1) b >>=? fun b -> + Assert.balance_was_debited + ~loc:__LOC__ + (B b) + (Contract.implicit_contract endorser1.delegate) + balance1 + security_deposit1 + >>=? fun () -> + Assert.balance_is + ~loc:__LOC__ + (B b) + (Contract.implicit_contract endorser2.delegate) + balance2 + >>=? fun () -> + (* complete cycle 0 *) + Block.bake_until_cycle_end ~policy b >>=? fun b -> + Assert.balance_was_debited + ~loc:__LOC__ + (B b) + (Contract.implicit_contract endorser1.delegate) + balance1 + security_deposit1 + >>=? fun () -> + Assert.balance_is + ~loc:__LOC__ + (B b) + (Contract.implicit_contract endorser2.delegate) + balance2 + >>=? fun () -> + (* get the slots of endorser2 for the current block *) + Context.get_endorsers (B b) >>=? fun endorsers -> + let same_endorser2 endorser = + Signature.Public_key_hash.( + endorser.Plugin.RPC.Endorsing_rights.delegate = endorser2.delegate) + in + let endorser2 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.find same_endorser2 endorsers + in + (* No exception raised: in sandboxed mode endorsers do not change between blocks *) + Tez.( + endorsement_security_deposit *? Int64.of_int (List.length endorser2.slots)) + >>?= fun security_deposit2 -> + (* endorser2 endorses the last block in cycle 0 *) + Op.endorsement_with_slot + ~delegate:(endorser2.delegate, endorser2.slots) + (B b) + () + >>=? fun operation2 -> + (* bake first block in cycle 1, include endorsement of endorser2 *) + Block.bake ~policy ~operation:(Operation.pack operation2) b >>=? fun b -> + let priority = b.header.protocol_data.contents.priority in + Context.get_endorsing_reward + (B b) + ~priority + ~endorsing_power:(List.length endorser2.slots) + >>=? fun reward2 -> + Assert.balance_was_debited + ~loc:__LOC__ + (B b) + (Contract.implicit_contract endorser1.delegate) + balance1 + security_deposit1 + >>=? fun () -> + Assert.balance_was_debited + ~loc:__LOC__ + (B b) + (Contract.implicit_contract endorser2.delegate) + balance2 + security_deposit2 + >>=? fun () -> + (* bake [preserved_cycles] number of cycles *) + List.fold_left_es + (fun b _ -> + Assert.balance_was_debited + ~loc:__LOC__ + (B b) + (Contract.implicit_contract endorser1.delegate) + balance1 + security_deposit1 + >>=? fun () -> + Assert.balance_was_debited + ~loc:__LOC__ + (B b) + (Contract.implicit_contract endorser2.delegate) + balance2 + security_deposit2 + >>=? fun () -> Block.bake_until_cycle_end ~policy b) + b + (1 -- preserved_cycles) + >>=? fun b -> + Assert.balance_was_credited + ~loc:__LOC__ + (B b) + (Contract.implicit_contract endorser1.delegate) + balance1 + reward1 + >>=? fun () -> + Assert.balance_was_debited + ~loc:__LOC__ + (B b) + (Contract.implicit_contract endorser2.delegate) + balance2 + security_deposit2 + >>=? fun () -> + (* bake cycle [preserved_cycle + 1] *) + Block.bake_until_cycle_end ~policy b >>=? fun b -> + Assert.balance_was_credited + ~loc:__LOC__ + (B b) + (Contract.implicit_contract endorser1.delegate) + balance1 + reward1 + >>=? fun () -> + Assert.balance_was_credited + ~loc:__LOC__ + (B b) + (Contract.implicit_contract endorser2.delegate) + balance2 + reward2 + +(****************************************************************) +(* The following test scenarios are supposed to raise errors. *) +(****************************************************************) + +(** Apply an endorsement without its slot bearing wrapper. *) +let test_unwrapped_endorsement () = + Context.init 5 >>=? fun (b, _) -> + Context.get_endorser (B b) >>=? fun (delegate, _slots) -> + Op.endorsement ~delegate (B b) () >>=? fun op -> + let policy = Block.Excluding [delegate] in + Block.bake ~policy ~operations:[Operation.pack op] b >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Unwrapped_endorsement -> true + | _ -> false) + +(** Apply an endorsement with an invalid slot in its slot bearing wrapper. *) +let test_bad_slot_wrapper () = + Context.init 5 >>=? fun (b, _) -> + Context.get_endorser (B b) >>=? fun (delegate, _slots) -> + Op.endorsement_with_slot ~delegate:(delegate, [2000]) (B b) () >>=? fun op -> + let policy = Block.Excluding [delegate] in + Block.bake ~policy ~operations:[Operation.pack op] b >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Baking.Invalid_endorsement_slot _ -> true + | _ -> false) + +(** Apply an endorsement with a negative slot in its slot bearing wrapper. *) +let test_neg_slot_wrapper () = + Context.init 5 >>=? fun (b, _) -> + Context.get_endorser (B b) >>=? fun (delegate, _slots) -> + Op.endorsement_with_slot ~delegate:(delegate, [-1]) (B b) () >>=? fun op -> + let policy = Block.Excluding [delegate] in + Lwt.catch + (fun () -> + Block.bake ~policy ~operations:[Operation.pack op] b >>= fun _ -> + failwith + "negative slot wrapper should not be accepted by the binary format") + (function + | Data_encoding.Binary.Write_error _ -> return_unit | e -> Lwt.fail e) + +(** Apply an endorsement with a non-normalized slot in its slot bearing wrapper. *) +let test_non_normalized_slot_wrapper () = + Context.init 5 >>=? fun (b, _) -> + Context.get_endorsers (B b) >>=? fun endorsers -> + (* find an endorsers with more than 1 slot *) + let endorser = + WithExceptions.Option.get ~loc:__LOC__ + @@ List.find + (fun endorser -> + List.length endorser.Plugin.RPC.Endorsing_rights.slots > 1) + endorsers + in + let (delegate, slots) = (endorser.delegate, endorser.slots) in + (* the first slot should be the smallest slot *) + Assert.equal_int + ~loc:__LOC__ + (WithExceptions.Option.get ~loc:__LOC__ @@ List.hd endorser.slots) + (WithExceptions.Option.get ~loc:__LOC__ + @@ List.hd (List.sort compare endorser.slots)) + >>=? fun () -> + Op.endorsement_with_slot ~delegate:(delegate, List.rev slots) (B b) () + >>=? fun op -> + let policy = Block.Excluding [delegate] in + Block.bake ~policy ~operations:[Operation.pack op] b >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Baking.Unexpected_endorsement_slot _ -> true + | _ -> false) + +(** Wrong endorsement predecessor : apply an endorsement with an + incorrect block predecessor. *) +let test_wrong_endorsement_predecessor () = + Context.init 5 >>=? fun (b, _) -> + Block.bake b >>=? fun b' -> + Op.endorsement_with_slot ~signing_context:(B b) (B b') () + >>=? fun operation -> + let operation = Operation.pack operation in + Block.bake ~operation b' >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Wrong_endorsement_predecessor _ -> true + | _ -> false) + +(** Invalid_endorsement_level: apply an endorsement with an incorrect + level (i.e. the predecessor level). *) +let test_invalid_endorsement_level () = + Context.init 5 >>=? fun (b, _) -> + Context.get_level (B b) >>?= fun genesis_level -> + Block.bake b >>=? fun b' -> + Context.get_endorser (B b) >>=? fun (genesis_endorser, slots) -> + Op.endorsement_with_slot + ~delegate:(genesis_endorser, slots) + ~signing_context:(B b') + ~level:genesis_level + (B b') + () + >>=? fun operation -> + let operation = Operation.pack operation in + Block.bake ~operation b' >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Invalid_endorsement_level -> true + | _ -> false) + +(** Duplicate endorsement : apply an endorsement that has already been + done. *) +let test_duplicate_endorsement () = + Context.init 5 >>=? fun (b, _) -> + Incremental.begin_construction b >>=? fun inc -> + Op.endorsement_with_slot (B b) () >>=? fun operation -> + let operation = Operation.pack operation in + Incremental.add_operation inc operation >>=? fun inc -> + Op.endorsement_with_slot (B b) () >>=? fun operation -> + let operation = Operation.pack operation in + Incremental.add_operation inc operation >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Duplicate_endorsement _ -> true + | _ -> false) + +(** Apply a single endorsement from the slot 0 endorser. *) +let test_not_enough_for_deposit () = + Context.init 5 ~endorsers_per_block:1 >>=? fun (b_init, contracts) -> + List.map_es + (fun c -> Context.Contract.manager (B b_init) c >|=? fun m -> (m, c)) + contracts + >>=? fun managers -> + Block.bake b_init >>=? fun b -> + (* retrieve the level 2's endorser *) + Context.get_endorser (B b) >>=? fun (endorser, slots) -> + let (_, contract_other_than_endorser) = + WithExceptions.Option.get ~loc:__LOC__ + @@ List.find + (fun (c, _) -> + not (Signature.Public_key_hash.equal c.Account.pkh endorser)) + managers + in + let (_, contract_of_endorser) = + WithExceptions.Option.get ~loc:__LOC__ + @@ List.find + (fun (c, _) -> Signature.Public_key_hash.equal c.Account.pkh endorser) + managers + in + Context.Contract.balance (B b) (Contract.implicit_contract endorser) + >>=? fun initial_balance -> + (* Empty the future endorser account *) + Op.transaction + (B b_init) + contract_of_endorser + contract_other_than_endorser + initial_balance + >>=? fun op_trans -> + Block.bake ~operation:op_trans b_init >>=? fun b -> + (* Endorse with a zero balance *) + Op.endorsement_with_slot ~delegate:(endorser, slots) (B b) () + >>=? fun op_endo -> + Block.bake + ~policy:(Excluding [endorser]) + ~operation:(Operation.pack op_endo) + b + >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Delegate_storage.Balance_too_low_for_deposit _ -> true + | _ -> false) + +(** Check that a block with not enough endorsement cannot be baked. *) +let test_endorsement_threshold () = + let initial_endorsers = 28 in + let num_accounts = 100 in + Context.init ~initial_endorsers num_accounts >>=? fun (b, _) -> + Context.get_endorsers (B b) >>=? fun endorsers -> + let num_endorsers = List.length endorsers in + (* we try to bake with more and more endorsers, but at each + iteration with a timestamp smaller than required *) + List.iter_es + (fun i -> + (* the priority is chosen rather arbitrarily *) + let priority = num_endorsers - i in + let crt_endorsers = List.take_n i endorsers in + let endorsing_power = endorsing_power crt_endorsers in + let delegates = delegates_with_slots crt_endorsers in + List.map_es + (fun x -> Op.endorsement_with_slot ~delegate:x (B b) ()) + delegates + >>=? fun ops -> + Context.get_minimal_valid_time (B b) ~priority ~endorsing_power + >>=? fun timestamp -> + (* decrease the timestamp by one second *) + let seconds = + Int64.(sub (of_string (Timestamp.to_seconds_string timestamp)) 1L) + in + match Timestamp.of_seconds_string (Int64.to_string seconds) with + | None -> failwith "timestamp to/from string manipulation failed" + | Some timestamp -> + Block.bake + ~timestamp + ~policy:(By_priority priority) + ~operations:(List.map Operation.pack ops) + b + >>= fun b2 -> + Assert.proto_error ~loc:__LOC__ b2 (function + | Baking.Timestamp_too_early _ -> true + | _ -> false)) + (0 -- (num_endorsers - 1)) + >>=? fun () -> + (* we bake with all endorsers endorsing, at the right time *) + let priority = 0 in + let endorsing_power = endorsing_power endorsers in + let delegates = delegates_with_slots endorsers in + List.map_es + (fun delegate -> Op.endorsement_with_slot ~delegate (B b) ()) + delegates + >>=? fun ops -> + Context.get_minimal_valid_time (B b) ~priority ~endorsing_power + >>=? fun timestamp -> + Block.bake + ~policy:(By_priority priority) + ~timestamp + ~operations:(List.map Operation.pack ops) + b + >>= fun _ -> return_unit + +(** Fitness gap *) +let test_fitness_gap () = + let num_accounts = 5 in + Context.init num_accounts >>=? fun (b, _) -> + (match Fitness_repr.to_int64 b.header.shell.fitness with + | Ok fitness -> Int64.to_int fitness + | Error _ -> assert false) + |> fun fitness -> + Context.get_endorser (B b) >>=? fun (delegate, slots) -> + Op.endorsement_with_slot ~delegate:(delegate, slots) (B b) () >>=? fun op -> + (* bake at priority 0 succeed thanks to enough endorsements *) + Block.bake ~policy:(By_priority 0) ~operations:[Operation.pack op] b + >>=? fun b -> + (match Fitness_repr.to_int64 b.header.shell.fitness with + | Ok new_fitness -> Int64.to_int new_fitness - fitness + | Error _ -> assert false) + |> fun res -> + (* in Emmy+, the fitness increases by 1, so the difference between + the fitness at level 1 and at level 0 is 1, independently if the + number fo endorsements (here 1) *) + Assert.equal_int ~loc:__LOC__ res 1 >>=? fun () -> return_unit + +let tests = + [ + Tztest.tztest "Simple endorsement" `Quick test_simple_endorsement; + Tztest.tztest "Unwrapped endorsement" `Quick test_unwrapped_endorsement; + Tztest.tztest + "Endorsement wrapped with invalid slot" + `Quick + test_bad_slot_wrapper; + Tztest.tztest + "Endorsement wrapped with slot -1" + `Quick + test_neg_slot_wrapper; + Tztest.tztest + "Endorsement wrapped with non-normalized slot" + `Quick + test_non_normalized_slot_wrapper; + Tztest.tztest "Maximum endorsement" `Quick test_max_endorsement; + Tztest.tztest "Consistent priorities" `Quick test_consistent_priorities; + Tztest.tztest "Reward retrieval" `Quick test_reward_retrieval; + Tztest.tztest + "Reward retrieval two endorsers" + `Quick + test_reward_retrieval_two_endorsers; + Tztest.tztest "Endorsement threshold" `Quick test_endorsement_threshold; + Tztest.tztest "Fitness gap" `Quick test_fitness_gap; + (* Fail scenarios *) + Tztest.tztest + "Wrong endorsement predecessor" + `Quick + test_wrong_endorsement_predecessor; + Tztest.tztest + "Invalid endorsement level" + `Quick + test_invalid_endorsement_level; + Tztest.tztest "Duplicate endorsement" `Quick test_duplicate_endorsement; + Tztest.tztest "Not enough for deposit" `Quick test_not_enough_for_deposit; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_failing_noop.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_failing_noop.ml new file mode 100644 index 000000000000..ce4c2a69697a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_failing_noop.ml @@ -0,0 +1,62 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe\ + -- test "^failing_noop$" + Subject: The Failing_noop operation was added bearing in mind the + possibility for the end user to sign arbitrary bytes, + encapsulate in the operation, with the absolute garanty that + the signed bytes can't be used for something against the + user's will. The Failing_noop operation always fails when + applied. + *) + +open Protocol +open Alpha_context + +let register_one_contract () = + Context.init 1 >>=? fun (b, contracts) -> + let contract = + List.nth contracts 0 |> WithExceptions.Option.get ~loc:__LOC__ + in + return (b, contract) + +(** try to apply a failing_noop and assert that the operation fails *) +let failing_noop_must_fail_when_injected () = + register_one_contract () >>=? fun (blk, contract) -> + Contract.is_implicit contract |> function + | None -> Alcotest.fail "only implicit accounts can sign" + | Some source -> + Op.failing_noop (B blk) source "tezos" >>=? fun operation -> + Block.bake ~operation blk >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Apply.Failing_noop_error -> true + | _ -> false) + +let tests = + [Tztest.tztest "injection fails" `Quick failing_noop_must_fail_when_injected] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_fixed_point.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_fixed_point.ml new file mode 100644 index 000000000000..c4f44f70acf5 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_fixed_point.ml @@ -0,0 +1,174 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (fixed-point decimals) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^fixed point computation$" + Subject: On fixed-point decimal numbers. +*) + +open Protocol + +exception Fixed_point_test_error of string + +let err x = Exn (Fixed_point_test_error x) + +module type Arith = sig + type t + + val zero : t + + val equal : t -> t -> bool + + val random : unit -> t + + val add : t -> t -> t + + val sub : t -> t -> t +end + +let n = Z.of_int 42 + +let n' = Z.of_int 43 + +let basic_arith name (module A : Arith) = + let err msg = err (Format.asprintf "%s test: %s" name msg) in + let x = A.random () in + fail_unless A.(add zero x = x) (err "zero is neutral for +") >>=? fun () -> + let x = A.random () in + let y = A.random () in + fail_unless A.(add x y = add y x) (err "addition is commutative") + >>=? fun () -> + let x = A.random () in + fail_unless + A.(sub (add zero x) x = zero) + (err "addition and subtraction cancel") + >>=? fun () -> + let x = A.random () in + let y = A.random () in + let z = A.random () in + fail_unless + A.(add x (add y z) = add (add x y) z) + (err "addition is associative") + +let arith_from_integral : (module Fixed_point_repr.Full) -> (module Arith) = + fun (module FP) -> + let module Arith = struct + type t = FP.integral + + let zero = FP.zero + + let equal = FP.equal + + let random () = FP.integral_of_int_exn (Random.int 898987) + + let add = FP.add + + let sub = FP.sub + end in + (module Arith) + +let arith_from_fp : (module Fixed_point_repr.Full) -> (module Arith) = + fun (module FP) -> + let module Arith = struct + type t = FP.fp + + let zero = FP.zero + + let equal = FP.equal + + let random () = FP.unsafe_fp (Z.of_int (Random.int 898987)) + + let add = FP.add + + let sub = FP.sub + end in + (module Arith) + +let integral_tests () = + let module FP = Gas_limit_repr.Arith in + (* test roundtrips *) + fail_unless (FP.(integral_to_z (integral_exn n)) = n) (err "roundtrip > 0") + >>=? fun () -> + fail_unless + (FP.(integral_to_z (integral_exn Z.zero)) = Z.zero) + (err "roundtrip = 0") + >>=? fun () -> + (* test ceil/floor on integral *) + fail_unless + FP.(ceil (fp (integral_exn n)) = integral_exn n) + (err "integral;fp;ceil = integral") + >>=? fun () -> + fail_unless + FP.(floor (fp (integral_exn n)) = integral_exn n) + (err "integral;fp;floor = integral") + >>=? fun () -> + fail_unless + (Format.asprintf "%a" FP.pp FP.(fp (integral_exn n)) + = Format.asprintf "%a" FP.pp_integral (FP.integral_exn n)) + (err "pp_integral(integral) = pp(fp(integral))") + >>=? fun () -> basic_arith "integral arith" (arith_from_integral (module FP)) + +let fp_nonzero () = + let decimals = 3 in + let module FP = Gas_limit_repr.Arith in + let prefix msg = Format.asprintf "(%d decimals) %s" decimals msg in + let err msg = err (prefix msg) in + basic_arith (prefix "integral arith") (arith_from_integral (module FP)) + >>=? fun () -> + basic_arith (prefix "fp arith") (arith_from_fp (module FP)) >>=? fun () -> + let epsilon = FP.unsafe_fp Z.one in + fail_unless FP.(ceil epsilon = integral_exn Z.one) (err "ceil eps = 1") + >>=? fun () -> + fail_unless FP.(floor epsilon = integral_exn Z.zero) (err "floor eps = 1") + >>=? fun () -> + let x = Z.of_int (Random.int 980812) in + fail_unless + FP.( + ceil (add (fp (integral_exn x)) (unsafe_fp Z.one)) + = integral_exn (Z.succ x)) + (err "ceil (x + eps) = x + 1") + +let fp_pp () = + let module FP = Gas_limit_repr.Arith in + let prefix msg = Format.asprintf "(%d decimals) %s" 3 msg in + let err msg = err (prefix msg) in + let epsilon = FP.unsafe_fp Z.one in + let ( =:= ) x expected = Format.asprintf "%a" FP.pp x = expected in + fail_unless (epsilon =:= "0.001") (err "eps = 0.001") >>=? fun () -> + fail_unless (FP.unsafe_fp (Z.of_int 1000) =:= "1") (err "1.000 = 1") + >>=? fun () -> + fail_unless (FP.unsafe_fp (Z.of_int 1001) =:= "1.001") (err "1.001") + >>=? fun () -> + fail_unless (FP.unsafe_fp (Z.of_int 10001) =:= "10.001") (err "10.001") + >>=? fun () -> fail_unless (FP.zero =:= "0") (err "0") + +let tests = + [ + Tztest.tztest "Integral tests (3 decimals)" `Quick integral_tests; + Tztest.tztest "FP tests (3 decimals)" `Quick fp_nonzero; + Tztest.tztest "FP pp tests (3 decimals)" `Quick fp_pp; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_gas_costs.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_gas_costs.ml new file mode 100644 index 000000000000..7d392321380a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_gas_costs.ml @@ -0,0 +1,289 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (gas costs) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^gas cost functions$" + Subject: Gas costs + Current limitations: for maps, sets & compare, we only test + integer comparable keys. +*) + +open Protocol +module S = Saturation_repr + +let dummy_list = Script_list.(cons 42 empty) + +let forty_two = Alpha_context.Script_int.of_int 42 + +let forty_two_n = Alpha_context.Script_int.abs forty_two + +let dummy_set = + let open Script_set in + update forty_two true (empty Script_typed_ir.(int_key ~annot:None)) + +let dummy_map = + let open Script_map in + update + forty_two + (Some forty_two) + (empty Script_typed_ir.(int_key ~annot:None)) + +let dummy_timestamp = Alpha_context.Script_timestamp.of_zint (Z.of_int 42) + +let dummy_pk = + Signature.Public_key.of_b58check_exn + "edpkuFrRoDSEbJYgxRtLx2ps82UdaYc1WwfS9sE11yhauZt5DgCHbU" + +let dummy_bytes = Bytes.of_string "dummy" + +let dummy_string = + match Alpha_context.Script_string.of_string "dummy" with + | Ok s -> s + | Error _ -> assert false + +let free = ["balance"; "bool"; "parsing_unit"; "unparsing_unit"] + +(* /!\ The compiler will only complain if costs are _removed_ /!\*) +let all_interpreter_costs = + let open Michelson_v1_gas.Cost_of.Interpreter in + [ + ("drop", drop); + ("dup", dup); + ("swap", swap); + ("cons_some", cons_some); + ("cons_none", cons_none); + ("if_none", if_none); + ("cons_pair", cons_pair); + ("car", car); + ("cdr", cdr); + ("cons_left", cons_left); + ("cons_right", cons_right); + ("if_left", if_left); + ("cons_list", cons_list); + ("nil", nil); + ("if_cons", if_cons); + ("list_map", list_map dummy_list); + ("list_size", list_size); + ("list_iter", list_iter dummy_list); + ("empty_set", empty_set); + ("set_iter", set_iter dummy_set); + ("set_mem", set_mem forty_two dummy_set); + ("set_update", set_update forty_two dummy_set); + ("set_size", set_size); + ("empty_map", empty_map); + ("map_map", map_map dummy_map); + ("map_iter", map_iter dummy_map); + ("map_mem", map_mem forty_two dummy_map); + ("map_get", map_get forty_two dummy_map); + ("map_update", map_update forty_two dummy_map); + ("map_size", map_size); + ("add_seconds_timestamp", add_seconds_timestamp forty_two dummy_timestamp); + ("sub_timestamp_seconds", sub_timestamp_seconds dummy_timestamp forty_two); + ("diff_timestamps", diff_timestamps dummy_timestamp dummy_timestamp); + ("concat_string_pair", concat_string_pair dummy_string dummy_string); + ("slice_string", slice_string dummy_string); + ("string_size", string_size); + ("concat_bytes_pair", concat_bytes_pair dummy_bytes dummy_bytes); + ("slice_bytes", slice_bytes dummy_bytes); + ("bytes_size", bytes_size); + ("add_tez", add_tez); + ("sub_tez", sub_tez); + ("mul_teznat", mul_teznat); + ("bool_or", bool_or); + ("bool_and", bool_and); + ("bool_xor", bool_xor); + ("bool_not", bool_not); + ("is_nat", is_nat); + ("abs_int", abs_int forty_two); + ("int_nat", int_nat); + ("neg_int", neg_int forty_two); + ("neg_nat", neg_nat forty_two_n); + ("add_intint", add_intint forty_two forty_two); + ("sub_int", sub_int forty_two forty_two); + ("mul_intint", mul_intint forty_two forty_two); + ("ediv_teznat", ediv_teznat Alpha_context.Tez.fifty_cents forty_two); + ("ediv_tez", ediv_tez); + ("ediv_intint", ediv_intint forty_two (Alpha_context.Script_int.of_int 1)); + ("eq", eq); + ("lsl_nat", lsl_nat forty_two); + ("lsr_nat", lsr_nat forty_two); + ("or_nat", or_nat forty_two forty_two); + ("and_nat", and_nat forty_two forty_two); + ("xor_nat", xor_nat forty_two forty_two); + ("not_int", not_int forty_two); + ("not_nat", not_nat forty_two); + ("if_", if_); + ("loop", loop); + ("loop_left", loop_left); + ("dip", dip); + ("check_signature", check_signature dummy_pk dummy_bytes); + ("blake2b", blake2b dummy_bytes); + ("sha256", sha256 dummy_bytes); + ("sha512", sha512 dummy_bytes); + ("dign", dign 42); + ("dugn", dugn 42); + ("dipn", dipn 42); + ("dropn", dropn 42); + ("neq", neq); + ( "compare", + compare Script_typed_ir.(int_key ~annot:None) forty_two forty_two ); + ( "concat_string_precheck", + concat_string_precheck Script_list.(cons "42" empty) ); + ("concat_string", concat_string (S.safe_int 42)); + ("concat_bytes", concat_bytes (S.safe_int 42)); + ("exec", exec); + ("apply", apply); + ("lambda", lambda); + ("address", address); + ("contract", contract); + ("transfer_tokens", transfer_tokens); + ("implicit_account", implicit_account); + ("create_contract", create_contract); + ("set_delegate", set_delegate); + (* balance is free *) + ("balance", balance); + ("level", level); + ("now", now); + ("hash_key", hash_key dummy_pk); + ("source", source); + ("sender", sender); + ("self", self); + ("self_address", self_address); + ("amount", amount); + ("chain_id", chain_id); + ("unpack_failed", unpack_failed (Bytes.of_string "dummy")); + ] + +(* /!\ The compiler will only complain if costs are _removed_ /!\*) +let all_parsing_costs = + let open Michelson_v1_gas.Cost_of.Typechecking in + [ + ("public_key_optimized", public_key_optimized); + ("public_key_readable", public_key_readable); + ("key_hash_optimized", key_hash_optimized); + ("key_hash_readable", key_hash_readable); + ("signature_optimized", signature_optimized); + ("signature_readable", signature_readable); + ("chain_id_optimized", chain_id_optimized); + ("chain_id_readable", chain_id_readable); + ("address_optimized", address_optimized); + ("contract_optimized", contract_optimized); + ("contract_readable", contract_readable); + ("check_printable", check_printable "dummy"); + ("merge_cycle", merge_cycle); + ("parse_type_cycle", parse_type_cycle); + ("parse_instr_cycle", parse_instr_cycle); + ("parse_data_cycle", parse_data_cycle); + ("bool", bool); + ("parsing_unit", unit); + ("timestamp_readable", timestamp_readable); + ("contract", contract); + ("contract_exists", contract_exists); + ("proof_argument", proof_argument 42); + ] + +(* /!\ The compiler will only complain if costs are _removed_ /!\*) +let all_unparsing_costs = + let open Michelson_v1_gas.Cost_of.Unparsing in + [ + ("public_key_optimized", public_key_optimized); + ("public_key_readable", public_key_readable); + ("key_hash_optimized", key_hash_optimized); + ("key_hash_readable", key_hash_readable); + ("signature_optimized", signature_optimized); + ("signature_readable", signature_readable); + ("chain_id_optimized", chain_id_optimized); + ("chain_id_readable", chain_id_readable); + ("timestamp_readable", timestamp_readable); + ("address_optimized", address_optimized); + ("contract_optimized", contract_optimized); + ("contract_readable", contract_readable); + ("unparse_type_cycle", unparse_type_cycle); + ("unparse_instr_cycle", unparse_instr_cycle); + ("unparse_data_cycle", unparse_data_cycle); + ("unparsing_unit", unit); + ("contract", contract); + ("operation", operation dummy_bytes); + ] + +(* /!\ The compiler will only complain if costs are _removed_ /!\*) +let all_io_costs = + let open Storage_costs in + [ + ("read_access 0 0", read_access ~path_length:0 ~read_bytes:0); + ("read_access 1 0", read_access ~path_length:1 ~read_bytes:0); + ("read_access 0 1", read_access ~path_length:0 ~read_bytes:1); + ("read_access 1 1", read_access ~path_length:1 ~read_bytes:1); + ("write_access 0", write_access ~written_bytes:0); + ("write_access 1", write_access ~written_bytes:1); + ] + +(* Here we're using knowledge of the internal representation of costs to + cast them to S ... *) +let cast_cost_to_s (c : Alpha_context.Gas.cost) : _ S.t = + Data_encoding.Binary.to_bytes_exn Alpha_context.Gas.cost_encoding c + |> Data_encoding.Binary.of_bytes_exn S.n_encoding + +(** Checks that all costs are positive values. *) +let test_cost_reprs_are_all_positive list () = + List.iter_es + (fun (cost_name, cost) -> + if S.(cost > S.zero) then return_unit + else if S.equal cost S.zero && List.mem ~equal:String.equal cost_name free + then return_unit + else + fail + (Exn + (Failure (Format.asprintf "Gas cost test \"%s\" failed" cost_name)))) + list + +(** Checks that all costs are positive values. *) +let test_costs_are_all_positive list () = + let list = + List.map (fun (cost_name, cost) -> (cost_name, cast_cost_to_s cost)) list + in + test_cost_reprs_are_all_positive list () + +let tests = + [ + Tztest.tztest + "Positivity of interpreter costs" + `Quick + (test_costs_are_all_positive all_interpreter_costs); + Tztest.tztest + "Positivity of typechecking costs" + `Quick + (test_costs_are_all_positive all_parsing_costs); + Tztest.tztest + "Positivity of unparsing costs" + `Quick + (test_costs_are_all_positive all_unparsing_costs); + Tztest.tztest + "Positivity of io costs" + `Quick + (test_cost_reprs_are_all_positive all_io_costs); + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_gas_levels.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_gas_levels.ml new file mode 100644 index 000000000000..ae0edf77f727 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_gas_levels.ml @@ -0,0 +1,483 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (Gas levels) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^gas levels$" + Subject: On gas consumption and exhaustion. +*) + +open Protocol +open Raw_context +module S = Saturation_repr + +(* This value is supposed to be larger than the block gas level limit + but not saturated. *) +let opg = max_int / 10000 + +exception Gas_levels_test_error of string + +let err x = Exn (Gas_levels_test_error x) + +let succeed x = match x with Ok _ -> true | _ -> false + +let failed x = not (succeed x) + +let dummy_context () = + Context.init 1 >>=? fun (block, _) -> + Raw_context.prepare + ~level:Int32.zero + ~predecessor_timestamp:Time.Protocol.epoch + ~timestamp:Time.Protocol.epoch + ~fitness:[] + (block.context : Environment_context.Context.t) + >|= Environment.wrap_tzresult + +let consume_gas_lwt context gas = + Lwt.return (consume_gas context (S.safe_int gas)) + >|= Environment.wrap_tzresult + +let consume_gas_limit_in_block_lwt context gas = + Lwt.return (consume_gas_limit_in_block context gas) + >|= Environment.wrap_tzresult + +let test_detect_gas_exhaustion_in_fresh_context () = + dummy_context () >>=? fun context -> + fail_unless + (consume_gas context (S.safe_int opg) |> succeed) + (err "In a fresh context, gas consumption is unlimited.") + +(** Create a context with a given block gas level, capped at the + hard gas limit per block *) +let make_context remaining_block_gas = + let open Gas_limit_repr in + dummy_context () >>=? fun context -> + let hard_limit = Arith.fp (constants context).hard_gas_limit_per_operation in + let hard_limit_block = + Arith.fp (constants context).hard_gas_limit_per_block + in + let block_gas = Arith.(unsafe_fp (Z.of_int remaining_block_gas)) in + let rec aux context to_consume = + (* Because of saturated arithmetic, [to_consume] should never be negative. *) + assert (Arith.(to_consume >= zero)) ; + if Arith.(to_consume = zero) then return context + else if Arith.(to_consume <= hard_limit) then + consume_gas_limit_in_block_lwt context to_consume + else + consume_gas_limit_in_block_lwt context hard_limit >>=? fun context -> + aux context (Arith.sub to_consume hard_limit) + in + aux context Arith.(sub hard_limit_block block_gas) + +(** Test operation gas exhaustion. Should pass when remaining gas is 0, + and fail when it goes over *) +let test_detect_gas_exhaustion_when_operation_gas_hits_zero () = + let gas_op = 100000 in + dummy_context () >>=? fun context -> + set_gas_limit context (Gas_limit_repr.Arith.unsafe_fp (Z.of_int gas_op)) + |> fun context -> + fail_unless + (consume_gas context (S.safe_int gas_op) |> succeed) + (err "Succeed when consuming exactly the remaining operation gas.") + >>=? fun () -> + fail_unless + (consume_gas context (S.safe_int (gas_op + 1)) |> failed) + (err "Fail when consuming more than the remaining operation gas.") + +(** Test block gas exhaustion *) +let test_detect_gas_exhaustion_when_block_gas_hits_zero () = + let gas k = Gas_limit_repr.Arith.unsafe_fp (Z.of_int k) in + let remaining_gas = gas 100000 and too_much = gas (100000 + 1) in + make_context 100000 >>=? fun context -> + fail_unless + (consume_gas_limit_in_block context remaining_gas |> succeed) + (err "Succeed when consuming exactly the remaining block gas.") + >>=? fun () -> + fail_unless + (consume_gas_limit_in_block context too_much |> failed) + (err "Fail when consuming more than the remaining block gas.") + +(** Test invalid gas limit. Should fail when limit is above the hard gas limit per + operation *) +let test_detect_gas_limit_consumption_above_hard_gas_operation_limit () = + dummy_context () >>=? fun context -> + fail_unless + (consume_gas_limit_in_block + context + (Gas_limit_repr.Arith.unsafe_fp (Z.of_int opg)) + |> failed) + (err + "Fail when consuming gas above the hard limit per operation in the \ + block.") + +(** For a given [context], check if its levels match those given in [block_level] and + [operation_level] *) +let check_context_levels context block_level operation_level = + let op_check = + match gas_level context with + | Unaccounted -> true + | Limited {remaining} -> + Gas_limit_repr.Arith.(unsafe_fp (Z.of_int operation_level) = remaining) + in + let block_check = + Gas_limit_repr.Arith.( + unsafe_fp (Z.of_int block_level) = block_gas_level context) + in + fail_unless + (op_check || block_check) + (err "Unexpected block and operation gas levels") + >>=? fun () -> + fail_unless op_check (err "Unexpected operation gas level") >>=? fun () -> + fail_unless block_check (err "Unexpected block gas level") + +let monitor remaining_block_gas initial_operation_level consumed_gas () = + let op_limit = + Gas_limit_repr.Arith.unsafe_fp (Z.of_int initial_operation_level) + in + make_context remaining_block_gas >>=? fun context -> + consume_gas_limit_in_block_lwt context op_limit >>=? fun context -> + set_gas_limit context op_limit |> fun context -> + consume_gas_lwt context consumed_gas >>=? fun context -> + check_context_levels + context + (remaining_block_gas - initial_operation_level) + (initial_operation_level - consumed_gas) + +let test_monitor_gas_level = monitor 1000 100 10 + +(** Test cas consumption mode switching (limited -> unlimited) *) +let test_set_gas_unlimited () = + let init_block_gas = 100000 in + let op_limit_int = 10000 in + let op_limit = Gas_limit_repr.Arith.unsafe_fp (Z.of_int op_limit_int) in + make_context init_block_gas >>=? fun context -> + set_gas_limit context op_limit |> set_gas_unlimited |> fun context -> + consume_gas_lwt context opg >>=? fun context -> + check_context_levels context init_block_gas (-1) + +(** Test cas consumption mode switching (unlimited -> limited) *) +let test_set_gas_limited () = + let init_block_gas = 100000 in + let op_limit_int = 10000 in + let op_limit = Gas_limit_repr.Arith.unsafe_fp (Z.of_int op_limit_int) in + let op_gas = 100 in + make_context init_block_gas >>=? fun context -> + set_gas_unlimited context |> fun context -> + set_gas_limit context op_limit |> fun context -> + consume_gas_lwt context op_gas >>=? fun context -> + check_context_levels context init_block_gas (op_limit_int - op_gas) + +(*** Tests with blocks ***) + +let apply_with_gas header ?(operations = []) (pred : Block.t) = + let open Alpha_context in + (let open Environment.Error_monad in + begin_application + ~chain_id:Chain_id.zero + ~predecessor_context:pred.context + ~predecessor_fitness:pred.header.shell.fitness + ~predecessor_timestamp:pred.header.shell.timestamp + header + >>=? fun vstate -> + List.fold_left_es + (fun vstate op -> + apply_operation vstate op >|=? fun (state, _result) -> state) + vstate + operations + >>=? fun vstate -> + finalize_block vstate (Some header.shell) >|=? fun (validation, result) -> + (validation.context, result.consumed_gas)) + >|= Environment.wrap_tzresult + >|=? fun (context, consumed_gas) -> + let hash = Block_header.hash header in + ({Block.hash; header; operations; context}, consumed_gas) + +let bake_with_gas ?policy ?timestamp ?operation ?operations pred = + let operations = + match (operation, operations) with + | (Some op, Some ops) -> Some (op :: ops) + | (Some op, None) -> Some [op] + | (None, Some ops) -> Some ops + | (None, None) -> None + in + Block.Forge.forge_header ?timestamp ?policy ?operations pred + >>=? fun header -> + Block.Forge.sign_header header >>=? fun header -> + apply_with_gas header ?operations pred + +let check_consumed_gas consumed expected = + fail_unless + Alpha_context.Gas.Arith.(consumed = expected) + (err + (Format.asprintf + "Gas discrepancy: consumed gas : %a | expected : %a\n" + Alpha_context.Gas.Arith.pp + consumed + Alpha_context.Gas.Arith.pp + expected)) + +let lazy_unit = + Alpha_context.Script.lazy_expr + (Sapling_helpers.Interpreter_helpers.expression_from_string "Unit") + +let prepare_origination block source script = + let code = Sapling_helpers.Interpreter_helpers.toplevel_from_string script in + let script = + Alpha_context.Script.{code = lazy_expr code; storage = lazy_unit} + in + Op.origination (B block) source ~script + +let originate_contract block source script = + prepare_origination block source script >>=? fun (operation, dst) -> + Block.bake ~operation block >>=? fun block -> return (block, dst) + +let init_block to_originate = + Context.init 1 >>=? fun (block, contracts) -> + let src = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd contracts in + (*** originate contracts ***) + let rec full_originate block originated = function + | [] -> return (block, List.rev originated) + | h :: t -> + originate_contract block src h >>=? fun (block, ct) -> + full_originate block (ct :: originated) t + in + full_originate block [] to_originate >>=? fun (block, originated) -> + return (block, src, originated) + +let nil_contract = + "parameter unit;\n\ + storage unit;\n\ + code {\n\ + \ DROP;\n\ + \ UNIT; NIL operation; PAIR\n\ + \ }\n" + +let fail_contract = "parameter unit; storage unit; code { FAIL }" + +let loop_contract = + "parameter unit;\n\ + storage unit;\n\ + code {\n\ + \ DROP;\n\ + \ PUSH bool True;\n\ + \ LOOP {\n\ + \ PUSH string \"GASGASGAS\";\n\ + \ PACK;\n\ + \ SHA3;\n\ + \ DROP;\n\ + \ PUSH bool True\n\ + \ };\n\ + \ UNIT; NIL operation; PAIR\n\ + \ }\n" + +let block_with_one_origination contract = + init_block [contract] >>=? fun (block, src, originated) -> + match originated with [dst] -> return (block, src, dst) | _ -> assert false + +let full_block () = + init_block [nil_contract; fail_contract; loop_contract] + >>=? fun (block, src, originated) -> + let (dst_nil, dst_fail, dst_loop) = + match originated with [c1; c2; c3] -> (c1, c2, c3) | _ -> assert false + in + return (block, src, dst_nil, dst_fail, dst_loop) + +(** Combine a list of operations into an operation list. Also returns + the sum of their gas limits.*) +let combine_operations_with_gas ?counter block src list_dst = + let rec make_op_list full_gas op_list = function + | [] -> return (full_gas, List.rev op_list) + | (dst, gas_limit) :: t -> + Op.transaction ~gas_limit (B block) src dst Alpha_context.Tez.zero + >>=? fun op -> + make_op_list + (Alpha_context.Gas.Arith.add full_gas gas_limit) + (op :: op_list) + t + in + make_op_list Alpha_context.Gas.Arith.zero [] list_dst + >>=? fun (full_gas, op_list) -> + Op.combine_operations ?counter ~source:src (B block) op_list + >>=? fun operation -> return (operation, full_gas) + +(** Applies [combine_operations_with_gas] to lists in a list, then bake a block + with this list of operations. Also returns the sum of all gas limits *) +let bake_operations_with_gas ?counter block src list_list_dst = + let counter = Option.value ~default:Z.zero counter in + let rec make_list full_gas op_list counter = function + | [] -> return (full_gas, List.rev op_list) + | list_dst :: t -> + let n = Z.of_int (List.length list_dst) in + combine_operations_with_gas ~counter block src list_dst + >>=? fun (op, gas) -> + make_list + (Alpha_context.Gas.Arith.add full_gas gas) + (op :: op_list) + (Z.add counter n) + t + in + make_list Alpha_context.Gas.Arith.zero [] counter list_list_dst + >>=? fun (gas_limit_total, operations) -> + bake_with_gas ~operations block >>=? fun (block, consumed_gas) -> + return (block, consumed_gas, gas_limit_total) + +let basic_gas_sampler () = + Alpha_context.Gas.Arith.integral_of_int_exn (100 + Random.int 900) + +let generic_test_block_one_origination contract gas_sampler structure = + block_with_one_origination contract >>=? fun (block, src, dst) -> + let lld = List.map (List.map (fun _ -> (dst, gas_sampler ()))) structure in + bake_operations_with_gas ~counter:Z.one block src lld + >>=? fun (_block, consumed_gas, gas_limit_total) -> + check_consumed_gas consumed_gas gas_limit_total + +let make_batch_test_block_one_origination name contract gas_sampler = + let test = generic_test_block_one_origination contract gas_sampler in + let test_one_operation () = test [[()]] in + let test_one_operation_list () = test [[(); (); ()]] in + let test_many_single_operations () = test [[()]; [()]; [()]] in + let test_mixed_operations () = test [[(); ()]; [()]; [(); (); ()]] in + let app_n = List.map (fun (x, y) -> (x ^ " with contract " ^ name, y)) in + app_n + [ + ("Test bake one operation", test_one_operation); + ("Test bake one operation list", test_one_operation_list); + ("Test multiple single operations", test_many_single_operations); + ("Test both lists and single operations", test_mixed_operations); + ] + +(** Tests the consumption of all gas in a block, should pass *) +let test_consume_exactly_all_block_gas () = + block_with_one_origination nil_contract >>=? fun (block, src, dst) -> + (* assumptions: + hard gas limit per operation = 1040000 + hard gas limit per block = 5200000 + *) + let lld = + List.map + (fun _ -> [(dst, Alpha_context.Gas.Arith.integral_of_int_exn 1040000)]) + [1; 1; 1; 1; 1] + in + bake_operations_with_gas ~counter:Z.one block src lld >>=? fun _ -> return () + +(** Tests the consumption of more than the block gas level with many single + operations, should fail *) +let test_malformed_block_max_limit_reached () = + block_with_one_origination nil_contract >>=? fun (block, src, dst) -> + (* assumptions: + hard gas limit per operation = 1040000 + hard gas limit per block = 5200000 + *) + let lld = + [(dst, Alpha_context.Gas.Arith.integral_of_int_exn 1)] + :: + List.map + (fun _ -> [(dst, Alpha_context.Gas.Arith.integral_of_int_exn 1040000)]) + [1; 1; 1; 1; 1] + in + bake_operations_with_gas ~counter:Z.one block src lld >>= function + | Error _ -> return_unit + | Ok _ -> + fail + (err + "Invalid block: sum of operation gas limits exceeds hard gas limit \ + per block") + +(** Tests the consumption of more than the block gas level with one big + operation list, should fail *) +let test_malformed_block_max_limit_reached' () = + block_with_one_origination nil_contract >>=? fun (block, src, dst) -> + (* assumptions: + hard gas limit per operation = 1040000 + hard gas limit per block = 5200000 + *) + let lld = + [ + (dst, Alpha_context.Gas.Arith.integral_of_int_exn 1) + :: + List.map + (fun _ -> (dst, Alpha_context.Gas.Arith.integral_of_int_exn 1040000)) + [1; 1; 1; 1; 1]; + ] + in + bake_operations_with_gas ~counter:Z.one block src lld >>= function + | Error _ -> return_unit + | Ok _ -> + fail + (err + "Invalid block: sum of gas limits in operation list exceeds hard \ + gas limit per block") + +let test_block_mixed_operations () = + full_block () >>=? fun (block, src, dst_nil, dst_fail, dst_loop) -> + let l = [[dst_nil]; [dst_nil; dst_fail; dst_nil]; [dst_loop]; [dst_nil]] in + let lld = List.map (List.map (fun x -> (x, basic_gas_sampler ()))) l in + bake_operations_with_gas ~counter:(Z.of_int 3) block src lld + >>=? fun (_block, consumed_gas, gas_limit_total) -> + check_consumed_gas consumed_gas gas_limit_total + +let quick (what, how) = Tztest.tztest what `Quick how + +let tests = + List.map + quick + ([ + ( "Detect gas exhaustion in fresh context", + test_detect_gas_exhaustion_in_fresh_context ); + ( "Detect gas exhaustion when operation gas as hits zero", + test_detect_gas_exhaustion_when_operation_gas_hits_zero ); + ( "Detect gas exhaustion when block gas as hits zero", + test_detect_gas_exhaustion_when_block_gas_hits_zero ); + ( "Detect gas limit consumption when it is above the hard gas operation \ + limit", + test_detect_gas_limit_consumption_above_hard_gas_operation_limit ); + ( "Each new operation impacts block gas level, each gas consumption \ + impacts operation gas level", + test_monitor_gas_level ); + ( "Switches operation gas consumption from limited to unlimited", + test_set_gas_unlimited ); + ( "Switches operation gas consumption from unlimited to limited", + test_set_gas_limited ); + ( "Accepts a block that consumes all of its gas", + test_consume_exactly_all_block_gas ); + ( "Detect when the sum of all operation gas limits exceeds the hard gas \ + limit per block", + test_malformed_block_max_limit_reached ); + ( "Detect when gas limit of operation list exceeds the hard gas limit \ + per block", + test_malformed_block_max_limit_reached' ); + ( "Test the gas consumption of various operations", + test_block_mixed_operations ); + ] + @ make_batch_test_block_one_origination "nil" nil_contract basic_gas_sampler + @ make_batch_test_block_one_origination + "fail" + fail_contract + basic_gas_sampler + @ make_batch_test_block_one_origination + "infinite loop" + loop_contract + basic_gas_sampler) diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_gas_properties.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_gas_properties.ml new file mode 100644 index 000000000000..9e0c1a32c05d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_gas_properties.ml @@ -0,0 +1,139 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (gas properties) + Invocation: dune exec src/proto_alpha/lib_protocol/test/test_gas_properties.exe + Subject: Arithmetic properties around gas. +*) + +open Protocol +open Lib_test.Qcheck_helpers + +(** Extract a Tezos result for compatibility with QCheck. *) +let extract_qcheck_result = function + | Ok pure_result -> pure_result + | Error err -> + Format.printf "@\n%a@." Environment.Error_monad.pp_trace err ; + false + +(** [Gas.free] is the neutral element of gas addition: [any_cost +@ Gas.free = Gas.free +@ any_cost = any_cost]. *) +let test_free_neutral (start, any_cost) = + let open Alpha_context in + extract_qcheck_result + ( Gas.consume start Gas.free >>? fun free_first -> + Gas.consume free_first any_cost >>? fun branch1 -> + Gas.consume start any_cost >>? fun cost_first -> + Gas.consume cost_first Gas.free >|? fun branch2 -> + let equal_consumption_from_start t1 t2 = + Gas.Arith.( + qcheck_eq + ~pp + ~eq:equal + (Gas.consumed ~since:start ~until:t1) + (Gas.consumed ~since:start ~until:t2)) + in + equal_consumption_from_start branch1 branch2 + && equal_consumption_from_start branch1 cost_first ) + +(** Consuming [Gas.free] is equivalent to consuming nothing. *) +let test_free_consumption start = + let open Alpha_context in + extract_qcheck_result + ( Gas.consume start Gas.free >|? fun after_empty_consumption -> + Gas.Arith.( + qcheck_eq + ~pp + ~eq:equal + (Gas.consumed ~since:start ~until:after_empty_consumption) + zero) ) + +(** Consuming [cost1] then [cost2] is equivalent to consuming + [Gas.(cost1 +@ cost2)]. *) +let test_consume_commutes (start, cost1, cost2) = + let open Alpha_context in + extract_qcheck_result + ( Gas.consume start cost1 >>? fun after_cost1 -> + Gas.consume after_cost1 cost2 >>? fun branch1 -> + Gas.consume start Gas.(cost1 +@ cost2) >|? fun branch2 -> + Gas.Arith.( + qcheck_eq + ~pp + ~eq:equal + (Gas.consumed ~since:start ~until:branch1) + (Gas.consumed ~since:start ~until:branch2)) ) + +(** Arbitrary context with a gas limit of 100_000_000. *) +let context_arb : Alpha_context.t QCheck.arbitrary = + QCheck.always + (Lwt_main.run + ( Context.init 1 >>=? fun (b, _contracts) -> + Incremental.begin_construction b >|=? fun inc -> + let state = Incremental.validation_state inc in + Alpha_context.Gas.set_limit + state.ctxt + Alpha_context.Gas.Arith.(fp (integral_of_int_exn 100_000_000)) ) + |> function + | Ok a -> a + | Error _ -> assert false) + +(** This arbitrary could be improved (pretty printer and shrinker) if there was a way to convert a [cost] back to an [int]. Otherwise one needs to write a custom [arbitrary] instance, but I wanted to stick to the former design of this test for the time being. *) +let gas_cost_arb : Alpha_context.Gas.cost QCheck.arbitrary = + let open Alpha_context.Gas in + let open QCheck in + let rand = 0 -- 1000 in + let safe_rand = map Saturation_repr.safe_int rand in + choose + [ + map atomic_step_cost safe_rand; + map step_cost safe_rand; + map alloc_cost safe_rand; + map alloc_bytes_cost rand; + map alloc_mbytes_cost rand; + map read_bytes_cost rand; + map write_bytes_cost rand; + ] + +let tests = + [ + QCheck.Test.make + ~count:1000 + ~name:"Consuming commutes" + QCheck.(triple context_arb gas_cost_arb gas_cost_arb) + test_consume_commutes; + QCheck.Test.make + ~count:1000 + ~name:"Consuming [free] consumes nothing" + context_arb + test_free_consumption; + QCheck.Test.make + ~count:1000 + ~name:"[free] is the neutral element of Gas addition" + QCheck.(pair context_arb gas_cost_arb) + test_free_neutral; + ] + +let () = Alcotest.run "gas properties" [("gas properties", qcheck_wrap tests)] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_global_constants_storage.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_global_constants_storage.ml new file mode 100644 index 000000000000..e9c1f74cefc7 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_global_constants_storage.ml @@ -0,0 +1,138 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) +open Protocol +open Alpha_context +open Test_transfer + +(** Testing + ------- + Component: Protocol (global table of constants) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe \ + -- test "^global table of constants$" + Subject: This module tests that the global table of constants + can be written to and read from across blocks. +*) + +let get_next_context b = + Incremental.begin_construction b >>=? fun b -> + return (Incremental.alpha_ctxt b) + +let assert_expr_equal loc = + Assert.equal + ~loc + ( = ) + "Michelson Expressions Not Equal" + Michelson_v1_printer.print_expr + +let assert_proto_error_id loc id result = + let test err = + (Error_monad.find_info_of_error err).id + = "proto." ^ Protocol.name ^ "." ^ id + in + Assert.error ~loc result test + +let expr_to_hash expr = + let lexpr = Script_repr.lazy_expr @@ Expr.from_string expr in + Script_repr.force_bytes lexpr >|? fun b -> Script_expr_hash.hash_bytes [b] + +(* This test has a long wind-up, but is very simple: it just asserts + that values written to the global table of constants persist across + blocks. *) +let get_happy_path () = + register_two_contracts () >>=? fun (b, alice, bob) -> + Incremental.begin_construction b >>=? fun b -> + let expr_str = "Pair 3 7" in + let expr = Expr.from_string expr_str in + Environment.wrap_tzresult @@ expr_to_hash expr_str >>?= fun hash -> + Op.register_global_constant + (I b) + ~source:alice + ~value:(Script_repr.lazy_expr expr) + >>=? fun op -> + Incremental.add_operation b op >>=? fun b -> + Incremental.finalize_block b >>=? fun b -> + let assert_unchanged b = + get_next_context b >>=? fun context -> + Global_constants_storage.get context hash >|= Environment.wrap_tzresult + >>=? fun (_, result_expr) -> + assert_expr_equal __LOC__ expr result_expr >|=? fun _ -> b + in + assert_unchanged b >>=? fun b -> + let do_many_transfers b = + Incremental.begin_construction b >>=? fun b -> + n_transactions 10 b alice bob (Tez.of_mutez_exn 1000L) >>=? fun b -> + Incremental.finalize_block b >>=? fun b -> assert_unchanged b + in + do_many_transfers b >>=? do_many_transfers >>=? do_many_transfers >>= fun _ -> + Lwt.return_ok () + +(* Blocks that include a registration of a bad expression should + fail. *) +let test_registration_of_bad_expr_fails () = + register_two_contracts () >>=? fun (b, alice, _) -> + Incremental.begin_construction b >>=? fun b -> + (* To produce the failure, we attempt to register an expression with + a malformed hash. *) + let expr = Expr.from_string "Pair 1 (constant \"foo\")" in + Op.register_global_constant + (I b) + ~source:alice + ~value:(Script_repr.lazy_expr expr) + >>=? fun op -> + Incremental.add_operation b op + >>= assert_proto_error_id __LOC__ "Badly_formed_constant_expression" + +(* You cannot register the same expression twice. *) +let test_no_double_register () = + register_two_contracts () >>=? fun (b, alice, _) -> + Incremental.begin_construction b >>=? fun b -> + let expr = Expr.from_string "Pair 1 2" in + Op.register_global_constant + (I b) + ~source:alice + ~value:(Script_repr.lazy_expr expr) + >>=? fun op -> + Incremental.add_operation b op >>=? fun b -> + (* Register the same expression again *) + Op.register_global_constant + (I b) + ~source:alice + ~value:(Script_repr.lazy_expr expr) + >>=? fun op -> + Incremental.add_operation b op + >>= assert_proto_error_id __LOC__ "Expression_already_registered" + +let tests = + [ + Tztest.tztest "Multiple blocks happy path" `Quick get_happy_path; + Tztest.tztest + "Bad register global operations fail when added to the block" + `Quick + test_registration_of_bad_expr_fails; + Tztest.tztest + "You cannot register the same expression twice." + `Quick + test_no_double_register; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_helpers_rpcs.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_helpers_rpcs.ml new file mode 100644 index 000000000000..a0bde0cd1c1e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_helpers_rpcs.ml @@ -0,0 +1,69 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (Helpers RPCs) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^helpers rpcs$" + Subject: On RPCs. +*) + +open Protocol +open Alpha_context + +(* Test the baking_rights RPC. + Future levels or cycles are not tested because it's hard in this framework, + using only RPCs, to fabricate them. *) +let test_baking_rights () = + Context.init 2 >>=? fun (b, contracts) -> + let open Plugin.RPC.Baking_rights in + (* default max_priority returns 65 results *) + get Block.rpc_ctxt b ~all:true >>=? fun rights -> + assert (List.length rights = 65) ; + (* arbitrary max_priority *) + let max_priority = 15 in + get Block.rpc_ctxt b ~all:true ~max_priority >>=? fun rights -> + assert (List.length rights = max_priority + 1) ; + (* filtering by delegate *) + let d = + Option.bind (List.nth contracts 0) Contract.is_implicit + |> WithExceptions.Option.get ~loc:__LOC__ + in + get Block.rpc_ctxt b ~all:true ~delegates:[d] >>=? fun rights -> + assert (List.for_all (fun {delegate; _} -> delegate = d) rights) ; + (* filtering by cycle *) + Plugin.RPC.current_level Block.rpc_ctxt b >>=? fun {cycle; _} -> + get Block.rpc_ctxt b ~all:true ~cycles:[cycle] >>=? fun rights -> + Plugin.RPC.levels_in_current_cycle Block.rpc_ctxt b >>=? fun (first, last) -> + assert ( + List.for_all (fun {level; _} -> level >= first && level <= last) rights) ; + (* filtering by level *) + Plugin.RPC.current_level Block.rpc_ctxt b >>=? fun {level; _} -> + get Block.rpc_ctxt b ~all:true ~levels:[level] >>=? fun rights -> + let espected_level = level in + assert (List.for_all (fun {level; _} -> level = espected_level) rights) ; + return_unit + +let tests = [Tztest.tztest "baking_rights" `Quick test_baking_rights] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_interpretation.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_interpretation.ml new file mode 100644 index 000000000000..e3d45e2aee47 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_interpretation.ml @@ -0,0 +1,246 @@ +(** Testing + ------- + Component: Protocol (interpretation) + Dependencies: src/proto_alpha/lib_protocol/script_interpreter.ml + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^interpretation$" + Subject: Interpretation of Michelson scripts +*) + +open Protocol +open Alpha_context +open Script_interpreter + +let ( >>=?? ) x y = + x >>= function + | Ok s -> y s + | Error err -> Lwt.return @@ Error (Environment.wrap_tztrace err) + +let ( >>??= ) x y = + match x with + | Ok s -> y s + | Error err -> Lwt.return @@ Error (Environment.wrap_tztrace err) + +let test_context () = + Context.init 3 >>=? fun (b, _cs) -> + Incremental.begin_construction b >>=? fun v -> + return (Incremental.alpha_ctxt v) + +let default_source = Contract.implicit_contract Signature.Public_key_hash.zero + +let default_step_constants = + { + source = default_source; + payer = default_source; + self = default_source; + amount = Tez.zero; + chain_id = Chain_id.zero; + } + +(** Helper function that parses and types a script, its initial storage and + parameters from strings. It then executes the typed script with the storage + and parameter and returns the result. *) +let run_script ctx ?(step_constants = default_step_constants) contract + ?(entrypoint = "default") ~storage ~parameter () = + let contract_expr = Expr.from_string contract in + let storage_expr = Expr.from_string storage in + let parameter_expr = Expr.from_string parameter in + let script = + Script.{code = lazy_expr contract_expr; storage = lazy_expr storage_expr} + in + Script_interpreter.execute + ctx + Readable + step_constants + ~script + ~cached_script:None + ~entrypoint + ~parameter:parameter_expr + ~internal:false + >>=?? fun res -> return res + +let logger = + Script_typed_ir. + { + log_interp = (fun _ _ _ _ _ -> ()); + log_entry = (fun _ _ _ _ _ -> ()); + log_exit = (fun _ _ _ _ _ -> ()); + log_control = (fun _ -> ()); + get_log = (fun () -> Lwt.return (Ok None)); + } + +let run_step ctxt code accu stack = + let open Script_interpreter in + step None ctxt default_step_constants code accu stack + >>=? fun ((_, _, ctxt') as r) -> + step (Some logger) ctxt default_step_constants code accu stack + >>=? fun (_, _, ctxt'') -> + if Gas.(remaining_operation_gas ctxt' <> remaining_operation_gas ctxt'') then + Alcotest.failf "Logging should not have an impact on gas consumption." ; + return r + +(** Runs a script with an ill-typed parameter and verifies that a + Bad_contract_parameter error is returned. *) +let test_bad_contract_parameter () = + test_context () >>=? fun ctx -> + (* Run script with a parameter of wrong type *) + run_script + ctx + "{parameter unit; storage unit; code { CAR; NIL operation; PAIR }}" + ~storage:"Unit" + ~parameter:"0" + () + >>= function + | Ok _ -> Alcotest.fail "expected an error" + | Error (Environment.Ecoproto_error (Bad_contract_parameter source') :: _) -> + Alcotest.(check Testable.contract) + "incorrect field in Bad_contract_parameter" + default_source + source' ; + return_unit + | Error errs -> + Alcotest.failf "Unexpected error: %a" Error_monad.pp_print_error errs + +let test_multiplication_close_to_overflow_passes () = + test_context () >>=? fun ctx -> + (* Get sure that multiplication deals with numbers between 2^62 and + 2^63 without overflowing *) + run_script + ctx + "{parameter unit;storage unit;code {DROP; PUSH mutez 2944023901536524477; \ + PUSH nat 2; MUL; DROP; UNIT; NIL operation; PAIR}}" + ~storage:"Unit" + ~parameter:"Unit" + () + >>= function + | Ok _ -> return_unit + | Error errs -> + Alcotest.failf "Unexpected error: %a" Error_monad.pp_print_error errs + +let read_file filename = + let ch = open_in filename in + let s = really_input_string ch (in_channel_length ch) in + close_in ch ; + s + +(* Confront the Michelson interpreter to deep recursions. *) +let test_stack_overflow () = + let open Script_typed_ir in + test_context () >>=? fun ctxt -> + let stack = Bot_t in + let descr kinstr = {kloc = 0; kbef = stack; kaft = stack; kinstr} in + let kinfo = {iloc = -1; kstack_ty = stack} in + let kinfo' = + {iloc = -1; kstack_ty = Item_t (bool_t ~annot:None, stack, None)} + in + let enorme_et_seq n = + let rec aux n acc = + if n = 0 then acc + else aux (n - 1) (IConst (kinfo, true, IDrop (kinfo', acc))) + in + aux n (IHalt kinfo) + in + run_step ctxt (descr (enorme_et_seq 1_000_000)) EmptyCell EmptyCell + >>= function + | Ok _ -> return_unit + | Error trace -> + let trace_string = + Format.asprintf "%a" Environment.Error_monad.pp_trace trace + in + Alcotest.failf "Unexpected error (%s) at %s" trace_string __LOC__ + +let test_stack_overflow_in_lwt () = + let open Script_typed_ir in + test_context () >>=? fun ctxt -> + let stack = Bot_t in + let item ty s = Item_t (ty, s, None) in + let unit_t = unit_t ~annot:None in + let unit_k = unit_key ~annot:None in + let bool_t = bool_t ~annot:None in + big_map_t (-1) unit_k unit_t ~annot:None >>??= fun big_map_t -> + let descr kinstr = {kloc = 0; kbef = stack; kaft = stack; kinstr} in + let kinfo s = {iloc = -1; kstack_ty = s} in + let stack1 = item big_map_t Bot_t in + let stack2 = item big_map_t (item big_map_t Bot_t) in + let stack3 = item unit_t stack2 in + let stack4 = item bool_t stack1 in + let push_empty_big_map k = IEmpty_big_map (kinfo stack, unit_k, unit_t, k) in + let large_mem_seq n = + let rec aux n acc = + if n = 0 then acc + else + aux + (n - 1) + (IDup + ( kinfo stack1, + IConst + ( kinfo stack2, + (), + IBig_map_mem (kinfo stack3, IDrop (kinfo stack4, acc)) ) )) + in + aux n (IDrop (kinfo stack1, IHalt (kinfo stack))) + in + let script = push_empty_big_map (large_mem_seq 1_000_000) in + run_step ctxt (descr script) EmptyCell EmptyCell >>= function + | Ok _ -> return_unit + | Error trace -> + let trace_string = + Format.asprintf "%a" Environment.Error_monad.pp_trace trace + in + Alcotest.failf "Unexpected error (%s) at %s" trace_string __LOC__ + +(** Test the encoding/decoding of script_interpreter.ml specific errors *) +let test_json_roundtrip name testable enc v = + let v' = + Data_encoding.Json.destruct enc (Data_encoding.Json.construct enc v) + in + Alcotest.check + testable + (Format.asprintf "round trip should not change value of %s" name) + v + v' ; + return_unit + +(** Encoding/decoding of script_interpreter.ml specific errors. *) +let test_json_roundtrip_err name e () = + test_json_roundtrip + name + Testable.protocol_error + Environment.Error_monad.error_encoding + e + +let error_encoding_tests = + let contract_zero = + Contract.implicit_contract Signature.Public_key_hash.zero + in + let script_expr_int = Micheline.strip_locations (Micheline.Int (0, Z.zero)) in + List.map + (fun (name, e) -> + Tztest.tztest + (Format.asprintf "test error encoding: %s" name) + `Quick + (test_json_roundtrip_err name e)) + [ + ("Reject", Reject (0, script_expr_int, None)); + ("Overflow", Overflow (0, None)); + ( "Runtime_contract_error", + Runtime_contract_error (contract_zero, script_expr_int) ); + ("Bad_contract_parameter", Bad_contract_parameter contract_zero); + ("Cannot_serialize_failure", Cannot_serialize_failure); + ("Cannot_serialize_storage", Cannot_serialize_storage); + ] + +let tests = + [ + Tztest.tztest "test bad contract error" `Quick test_bad_contract_parameter; + Tztest.tztest "check robustness overflow error" `Slow test_stack_overflow; + Tztest.tztest + "check robustness overflow error in lwt" + `Slow + test_stack_overflow_in_lwt; + Tztest.tztest + "test multiplication no illegitimate overflow" + `Quick + test_multiplication_close_to_overflow_passes; + Tztest.tztest "test stack overflow error" `Slow test_stack_overflow; + ] + @ error_encoding_tests diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_lazy_storage_diff.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_lazy_storage_diff.ml new file mode 100644 index 000000000000..cd55c3228f92 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_lazy_storage_diff.ml @@ -0,0 +1,141 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol + +(** Generation of input data *) + +let ids = + [|1; 42; 1337; 1984|] |> Array.map Z.of_int + |> Array.map Lazy_storage_kind.Big_map.Id.parse_z + +let strs = [|"0"; "True"; "nat"; "bool"|] + +let exprs = strs |> Array.map Expr.from_string + +let hashes = + strs |> Array.map (fun x -> [x]) |> Array.map Script_expr_hash.hash_string + +let updates_len_existing = [1; 2; 3] + +let updates_len_other = 0 :: updates_len_existing + +let gen_inits idx : + (( Lazy_storage_kind.Big_map.Id.t, + Lazy_storage_kind.Big_map.alloc ) + Lazy_storage_diff.init + * int list) + list = + [ + (Existing, updates_len_existing); + (Copy {src = ids.(idx - 1)}, updates_len_other); + ( Alloc {key_type = exprs.(idx); value_type = exprs.(idx - 1)}, + updates_len_other ); + ] + +let gen_update_list idx : Lazy_storage_kind.Big_map.update list = + [None; Some exprs.(idx)] + |> List.map (fun value -> + Lazy_storage_kind.Big_map. + {key = exprs.(idx); key_hash = hashes.(idx); value}) + +let rec gen_updates updates_len : Lazy_storage_kind.Big_map.updates list = + if updates_len = 0 then [] + else + gen_updates (updates_len - 1) + |> List.map (fun suffix -> + gen_update_list updates_len + |> List.map (fun prefix -> prefix :: suffix)) + |> List.flatten + +let gen_updates_list updates_lens : Lazy_storage_kind.Big_map.updates list = + updates_lens |> List.map gen_updates |> List.flatten + +let gen_diffs idx : + ( Lazy_storage_kind.Big_map.Id.t, + Lazy_storage_kind.Big_map.alloc, + Lazy_storage_kind.Big_map.updates ) + Lazy_storage_diff.diff + list = + let open Lazy_storage_diff in + Remove + :: + (gen_inits idx + |> List.map (fun (init, updates_lens) -> + gen_updates_list updates_lens + |> List.map (fun updates -> Update {init; updates})) + |> List.flatten) + +let gen_diffs_items idx : Lazy_storage_diff.diffs_item list = + let id = ids.(idx) in + gen_diffs idx |> List.map (fun diff -> Lazy_storage_diff.make Big_map id diff) + +let rec gen_diffs_list len : Lazy_storage_diff.diffs list = + if len = 0 then [] + else + gen_diffs_list (len - 1) + |> List.map (fun suffix -> + gen_diffs_items len |> List.map (fun prefix -> prefix :: suffix)) + |> List.flatten + +let diffs_list_lens = [0; 1; 2; 3] + +let diffs_list : Lazy_storage_diff.diffs list = + diffs_list_lens |> List.map gen_diffs_list |> List.flatten + +(** Properties to check *) + +let conversion_roundtrip lazy_storage_diff = + let legacy_big_map_diff = + Contract_storage.Legacy_big_map_diff.of_lazy_storage_diff lazy_storage_diff + in + let reconverted = + Contract_storage.Legacy_big_map_diff.to_lazy_storage_diff + legacy_big_map_diff + in + assert (Stdlib.( = ) reconverted lazy_storage_diff) + +let encoding_roundtrip lazy_storage_diff = + let encoded = + Data_encoding.Binary.to_bytes_exn + Lazy_storage_diff.encoding + lazy_storage_diff + in + match Data_encoding.Binary.of_bytes Lazy_storage_diff.encoding encoded with + | Ok decoded -> assert (Stdlib.( = ) decoded lazy_storage_diff) + | Error _ -> Stdlib.failwith "Decoding failed" + +(** Iterator and test definitions *) + +let on_diffs f () = + List.iter f diffs_list ; + return_unit + +(* Marked Slow because they take 5 to 10 seconds and are unlikely to change *) +let tests = + [ + Tztest.tztest "conversion roundtrip" `Slow (on_diffs conversion_roundtrip); + Tztest.tztest "encoding roundtrip" `Slow (on_diffs encoding_roundtrip); + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_level_module.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_level_module.ml new file mode 100644 index 000000000000..64546a24a264 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_level_module.ml @@ -0,0 +1,275 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (baking) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^level module$" + Subject: some functions in the Level module +*) + +open Protocol + +let test_create_cycle_eras () = + let empty_cycle_eras = + Level_repr.create_cycle_eras [] |> Environment.wrap_tzresult + in + Assert.proto_error ~loc:__LOC__ empty_cycle_eras (function + | Level_repr.Invalid_cycle_eras -> true + | _ -> false) + >>=? fun () -> + let increasing_first_levels = + [ + Level_repr. + { + first_level = Raw_level_repr.of_int32_exn 1l; + first_cycle = Cycle_repr.succ Cycle_repr.root; + blocks_per_cycle = 8l; + blocks_per_commitment = 2l; + }; + { + first_level = Raw_level_repr.of_int32_exn 9l; + first_cycle = Cycle_repr.root; + blocks_per_cycle = 8l; + blocks_per_commitment = 2l; + }; + ] + |> Level_repr.create_cycle_eras |> Environment.wrap_tzresult + in + Assert.proto_error ~loc:__LOC__ increasing_first_levels (function + | Level_repr.Invalid_cycle_eras -> true + | _ -> false) + >>=? fun () -> + let increasing_first_cycles = + [ + Level_repr. + { + first_level = Raw_level_repr.of_int32_exn 9l; + first_cycle = Cycle_repr.root; + blocks_per_cycle = 8l; + blocks_per_commitment = 2l; + }; + { + first_level = Raw_level_repr.of_int32_exn 1l; + first_cycle = Cycle_repr.succ Cycle_repr.root; + blocks_per_cycle = 8l; + blocks_per_commitment = 2l; + }; + ] + |> Level_repr.create_cycle_eras |> Environment.wrap_tzresult + in + Assert.proto_error ~loc:__LOC__ increasing_first_cycles (function + | Level_repr.Invalid_cycle_eras -> true + | _ -> false) + +let test_case_1 = + ( [ + Level_repr. + { + first_level = Raw_level_repr.of_int32_exn 1l; + first_cycle = Cycle_repr.root; + blocks_per_cycle = 8l; + blocks_per_commitment = 2l; + }; + ], + [ + (1, (1, 0, 0, 0, false)); + (2, (2, 1, 0, 1, true)); + (3, (3, 2, 0, 2, false)); + (8, (8, 7, 0, 7, true)); + (9, (9, 8, 1, 0, false)); + (16, (16, 15, 1, 7, true)); + (17, (17, 16, 2, 0, false)); + (64, (64, 63, 7, 7, true)); + (65, (65, 64, 8, 0, false)); + ] ) + +let test_case_2 = + ( List.rev + [ + Level_repr. + { + first_level = Raw_level_repr.of_int32_exn 1l; + first_cycle = Cycle_repr.root; + blocks_per_cycle = 8l; + blocks_per_commitment = 2l; + }; + { + first_level = Raw_level_repr.of_int32_exn 17l; + first_cycle = Cycle_repr.of_int32_exn 2l; + blocks_per_cycle = 16l; + blocks_per_commitment = 4l; + }; + ], + [ + (1, (1, 0, 0, 0, false)); + (2, (2, 1, 0, 1, true)); + (3, (3, 2, 0, 2, false)); + (8, (8, 7, 0, 7, true)); + (9, (9, 8, 1, 0, false)); + (16, (16, 15, 1, 7, true)); + (17, (17, 16, 2, 0, false)); + (32, (32, 31, 2, 15, true)); + (33, (33, 32, 3, 0, false)); + (64, (64, 63, 4, 15, true)); + (65, (65, 64, 5, 0, false)); + ] ) + +let test_case_3 = + ( List.rev + [ + Level_repr. + { + first_level = Raw_level_repr.of_int32_exn 1l; + first_cycle = Cycle_repr.root; + blocks_per_cycle = 8l; + blocks_per_commitment = 2l; + }; + { + first_level = Raw_level_repr.of_int32_exn 17l; + first_cycle = Cycle_repr.of_int32_exn 2l; + blocks_per_cycle = 16l; + blocks_per_commitment = 4l; + }; + { + first_level = Raw_level_repr.of_int32_exn 49l; + first_cycle = Cycle_repr.of_int32_exn 4l; + blocks_per_cycle = 6l; + blocks_per_commitment = 3l; + }; + ], + [ + (1, (1, 0, 0, 0, false)); + (2, (2, 1, 0, 1, true)); + (3, (3, 2, 0, 2, false)); + (8, (8, 7, 0, 7, true)); + (9, (9, 8, 1, 0, false)); + (16, (16, 15, 1, 7, true)); + (17, (17, 16, 2, 0, false)); + (32, (32, 31, 2, 15, true)); + (33, (33, 32, 3, 0, false)); + (48, (48, 47, 3, 15, true)); + (49, (49, 48, 4, 0, false)); + (64, (64, 63, 6, 3, false)); + (65, (65, 64, 6, 4, false)); + (66, (66, 65, 6, 5, true)); + (67, (67, 66, 7, 0, false)); + ] ) + +let test_level_from_raw () = + List.iter_es + (fun (cycle_eras, test_cases) -> + List.iter_es + (fun ( input_level, + ( level, + level_position, + cycle, + cycle_position, + expected_commitment ) ) -> + let raw_level = + Raw_level_repr.of_int32_exn (Int32.of_int input_level) + in + Level_repr.create_cycle_eras cycle_eras |> Environment.wrap_tzresult + >>?= fun cycle_eras -> + let level_from_raw = + Protocol.Level_repr.from_raw ~cycle_eras raw_level + in + Assert.equal_int + ~loc:__LOC__ + (Int32.to_int (Raw_level_repr.to_int32 level_from_raw.level)) + level + >>=? fun () -> + Assert.equal_int + ~loc:__LOC__ + (Int32.to_int level_from_raw.level_position) + level_position + >>=? fun () -> + Assert.equal_int + ~loc:__LOC__ + (Int32.to_int (Cycle_repr.to_int32 level_from_raw.cycle)) + cycle + >>=? fun () -> + Assert.equal_int + ~loc:__LOC__ + (Int32.to_int level_from_raw.cycle_position) + cycle_position + >>=? fun () -> + Assert.equal_bool + ~loc:__LOC__ + level_from_raw.expected_commitment + expected_commitment + >>=? fun () -> + let offset = + Int32.neg (Int32.add Int32.one (Int32.of_int input_level)) + in + let res = + Level_repr.from_raw_with_offset ~cycle_eras ~offset raw_level + in + Assert.proto_error + ~loc:__LOC__ + (Environment.wrap_tzresult res) + (fun err -> + let error_info = + Error_monad.find_info_of_error (Environment.wrap_tzerror err) + in + error_info.title = "Negative sum of level and offset")) + test_cases) + [test_case_1; test_case_2; test_case_3] + +let test_first_level_in_cycle () = + let cycle_eras = fst test_case_3 in + let test_cases = + (* cycle, level *) + [ + (0l, 1); + (1l, 9); + (2l, 17); + (3l, 33); + (4l, 49); + (5l, 55); + (6l, 61); + (7l, 67); + ] + in + let f (input_cycle, level) = + Level_repr.create_cycle_eras cycle_eras |> Environment.wrap_tzresult + >>?= fun cycle_eras -> + let input_cycle = Cycle_repr.of_int32_exn input_cycle in + let level_res = + Level_repr.first_level_in_cycle_from_eras ~cycle_eras input_cycle + in + Assert.equal_int + ~loc:__LOC__ + (Int32.to_int (Raw_level_repr.to_int32 level_res.level)) + level + in + List.iter_es f test_cases + +let tests = + [ + Tztest.tztest "create_cycle_eras" `Quick test_create_cycle_eras; + Tztest.tztest "level_from_raw" `Quick test_level_from_raw; + Tztest.tztest "first_level_in_cycle" `Quick test_first_level_in_cycle; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_liquidity_baking.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_liquidity_baking.ml new file mode 100644 index 000000000000..80d86ec82c63 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_liquidity_baking.ml @@ -0,0 +1,527 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Tocqueville Group, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: liquidity baking + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^liquidity baking$" + Subject: Test liquidity baking subsidies, CPMM storage updates, + sunset shut off, and escape hatch shut off. +*) + +open Liquidity_baking_machine +open Protocol +open Test_tez + +let generate_init_state () = + let cpmm_min_xtz_balance = 10_000_000L in + let cpmm_min_tzbtc_balance = 100_000 in + let accounts_balances = + [ + {xtz = 1_000_000L; tzbtc = 1; liquidity = 100}; + {xtz = 1_000L; tzbtc = 1000; liquidity = 100}; + {xtz = 40_000_000L; tzbtc = 350000; liquidity = 300}; + ] + in + ValidationMachine.build + {cpmm_min_xtz_balance; cpmm_min_tzbtc_balance; accounts_balances} + >>=? fun _ -> return_unit + +(* The script hash of + + https://gitlab.com/dexter2tz/dexter2tz/-/blob/d98643881fe14996803997f1283e84ebd2067e35/dexter.liquidity_baking.mligo.tz + +*) +let expected_cpmm_hash = + Script_expr_hash.of_b58check_exn + "exprvEBYbxZruLZ9aUDEC9cUxn5KUj361xsaZXGfCxogFoKQ1er9Np" + +(* The script hash of + + https://gitlab.com/dexter2tz/dexter2tz/-/blob/d98643881fe14996803997f1283e84ebd2067e35/lqt_fa12.mligo.tz + +*) +let expected_lqt_hash = + Script_expr_hash.of_b58check_exn + "exprufAK15C2FCbxGLCEVXFe26p3eQdYuwZRk1morJUwy9NBUmEZVB" + +(* Test that the scripts of the Liquidity Baking contracts (CPMM and LQT) have the expected hashes. *) +let liquidity_baking_origination () = + Context.init 1 >>=? fun (blk, _contracts) -> + Context.get_liquidity_baking_cpmm_address (B blk) >>=? fun cpmm_address -> + Context.Contract.script_hash (B blk) cpmm_address >>=? fun cpmm_hash -> + Lwt.return @@ Environment.wrap_tzresult + @@ Alpha_context.Contract.of_b58check "KT1AafHA1C1vk959wvHWBispY9Y2f3fxBUUo" + >>=? fun lqt_address -> + Context.Contract.script_hash (B blk) lqt_address >>=? fun lqt_hash -> + Assert.equal + ~loc:__LOC__ + Script_expr_hash.equal + "Unexpected CPMM script." + Script_expr_hash.pp + cpmm_hash + expected_cpmm_hash + >>=? fun () -> + Assert.equal + ~loc:__LOC__ + Script_expr_hash.equal + "Unexpected LQT script." + Script_expr_hash.pp + lqt_hash + expected_lqt_hash + >>=? fun () -> return_unit + +(* Test that the CPMM address in storage is correct *) +let liquidity_baking_cpmm_address () = + Context.init 1 >>=? fun (blk, _contracts) -> + Context.get_liquidity_baking_cpmm_address (B blk) >>=? fun liquidity_baking -> + Assert.equal + ~loc:__LOC__ + String.equal + "CPMM address in storage is incorrect" + Format.pp_print_string + (Alpha_context.Contract.to_b58check liquidity_baking) + "KT1TxqZ8QtKvLu3V3JH7Gx58n7Co8pgtpQU5" + >>=? fun () -> return_unit + +(* Test that after [n] blocks, the liquidity baking CPMM contract is credited [n] times the subsidy amount. *) +let liquidity_baking_subsidies n () = + Context.init 1 >>=? fun (blk, _contracts) -> + Context.get_liquidity_baking_cpmm_address (B blk) >>=? fun liquidity_baking -> + Context.Contract.balance (B blk) liquidity_baking >>=? fun old_balance -> + Block.bake_n n blk >>=? fun blk -> + Context.get_liquidity_baking_subsidy (B blk) + >>=? fun liquidity_baking_subsidy -> + Tez.(liquidity_baking_subsidy *? Int64.(of_int n)) >>?= fun expected_credit -> + Assert.balance_was_credited + ~loc:__LOC__ + (B blk) + liquidity_baking + old_balance + expected_credit + >>=? fun () -> return_unit + +(* Test that [n] blocks after the liquidity baking sunset, the subsidy is not applied anymore. + More precisely, after the sunset, the total amount credited to the subsidy is only proportional + to the sunset level and in particular it does not depend on [n]. *) +let liquidity_baking_sunset_level n () = + Context.init 1 >>=? fun (blk, _contracts) -> + Context.get_liquidity_baking_cpmm_address (B blk) >>=? fun liquidity_baking -> + Context.get_constants (B blk) >>=? fun csts -> + let sunset = csts.parametric.liquidity_baking_sunset_level in + Context.Contract.balance (B blk) liquidity_baking >>=? fun old_balance -> + Block.bake_n (Int32.to_int sunset + n) blk >>=? fun blk -> + Context.get_liquidity_baking_subsidy (B blk) + >>=? fun liquidity_baking_subsidy -> + Tez.(liquidity_baking_subsidy *? Int64.(sub (of_int32 sunset) 1L)) + >>?= fun expected_credit -> + Assert.balance_was_credited + ~loc:__LOC__ + (B blk) + liquidity_baking + old_balance + expected_credit + >>=? fun () -> return_unit + +(* Test that subsidy shuts off at correct escape level alternating baking [n_vote_false] blocks with liquidity_baking_escape_vote = false and [n_vote_true] blocks with it true followed by [bake_after_escape] blocks with it false. *) +(* Escape level is roughly 2*(log(1-1/(2*percent_flagging)) / log(0.999)) *) +let liquidity_baking_escape_hatch n_vote_false n_vote_true escape_level + bake_after_escape () = + Context.init 1 >>=? fun (blk, _contracts) -> + Context.get_liquidity_baking_cpmm_address (B blk) >>=? fun liquidity_baking -> + Context.Contract.balance (B blk) liquidity_baking >>=? fun old_balance -> + let rec bake_escaping blk i = + if i < escape_level then + Block.bake_n n_vote_false blk >>=? fun blk -> + Block.bake_n ~liquidity_baking_escape_vote:true n_vote_true blk + >>=? fun blk -> bake_escaping blk (i + n_vote_false + n_vote_true) + else return blk + in + bake_escaping blk 0 >>=? fun blk -> + Block.bake_n bake_after_escape blk >>=? fun blk -> + Context.get_liquidity_baking_subsidy (B blk) + >>=? fun liquidity_baking_subsidy -> + Tez.(liquidity_baking_subsidy *? Int64.of_int escape_level) + >>?= fun expected_balance -> + Assert.balance_was_credited + ~loc:__LOC__ + (B blk) + liquidity_baking + old_balance + expected_balance + >>=? fun () -> return_unit + +(* 100% of blocks have liquidity_baking_escape_vote = true *) +let liquidity_baking_escape_hatch_100 n () = + liquidity_baking_escape_hatch 0 1 1387 n () + +(* 80% of blocks have liquidity_baking_escape_vote = true *) +let liquidity_baking_escape_hatch_80 n () = + liquidity_baking_escape_hatch 1 4 1964 n () + +(* 60% of blocks have liquidity_baking_escape_vote = true *) +let liquidity_baking_escape_hatch_60 n () = + liquidity_baking_escape_hatch 2 3 3590 n () + +(* 50% of blocks have liquidity_baking_escape_vote = true. + Escape hatch should not be activated. *) +let liquidity_baking_escape_hatch_50 n () = + Context.init 1 >>=? fun (blk, _contracts) -> + Context.get_liquidity_baking_cpmm_address (B blk) >>=? fun liquidity_baking -> + Context.get_constants (B blk) >>=? fun csts -> + let sunset = csts.parametric.liquidity_baking_sunset_level in + Context.Contract.balance (B blk) liquidity_baking >>=? fun old_balance -> + let rec bake_50_percent_escaping blk i = + if i < Int32.to_int sunset + n then + Block.bake blk >>=? fun blk -> + Block.bake ~liquidity_baking_escape_vote:true blk >>=? fun blk -> + bake_50_percent_escaping blk (i + 2) + else return blk + in + bake_50_percent_escaping blk 0 >>=? fun blk -> + Context.get_liquidity_baking_subsidy (B blk) + >>=? fun liquidity_baking_subsidy -> + Tez.(liquidity_baking_subsidy *? Int64.(sub (of_int32 sunset) 1L)) + >>?= fun expected_balance -> + Assert.balance_was_credited + ~loc:__LOC__ + (B blk) + liquidity_baking + old_balance + expected_balance + >>=? fun () -> return_unit + +(* Test that the escape EMA in block metadata is correct. *) +let liquidity_baking_escape_ema n_vote_false n_vote_true escape_level + bake_after_escape expected_escape_ema () = + Context.init 1 >>=? fun (blk, _contracts) -> + let rec bake_escaping blk i = + if i < escape_level then + Block.bake_n n_vote_false blk >>=? fun blk -> + Block.bake_n ~liquidity_baking_escape_vote:true n_vote_true blk + >>=? fun blk -> bake_escaping blk (i + n_vote_false + n_vote_true) + else return blk + in + bake_escaping blk 0 >>=? fun blk -> + (* We only need to return the escape EMA at the end. *) + Block.bake_n_with_liquidity_baking_escape_ema bake_after_escape blk + >>=? fun (_blk, escape_ema) -> + Assert.leq_int ~loc:__LOC__ (Int32.to_int escape_ema) expected_escape_ema + >>=? fun () -> return_unit + +(* With no bakers setting the escape vote, EMA should be zero. *) +let liquidity_baking_escape_ema_zero () = + liquidity_baking_escape_ema 0 0 0 100 0 () + +(* The EMA should be not much over the threshold after the escape hatch has been activated. We add 50_000 to the constant to give room for the last update. *) +let liquidity_baking_escape_ema_threshold () = + liquidity_baking_escape_ema 0 1 1387 1 1_050_000 () + +let liquidity_baking_storage n () = + Context.init 1 >>=? fun (blk, _contracts) -> + Context.get_liquidity_baking_cpmm_address (B blk) >>=? fun liquidity_baking -> + Context.get_liquidity_baking_subsidy (B blk) >>=? fun subsidy -> + let expected_storage = + Expr.from_string + (Printf.sprintf + "Pair 1\n\ + \ %d\n\ + \ 100\n\ + \ \"KT1VqarPDicMFn1ejmQqqshUkUXTCTXwmkCN\"\n\ + \ \"KT1AafHA1C1vk959wvHWBispY9Y2f3fxBUUo\"" + (100 + (n * Int64.to_int (Tez.to_mutez subsidy)))) + in + Block.bake_n n blk >>=? fun blk -> + Context.Contract.storage (B blk) liquidity_baking >>=? fun storage -> + let to_string expr = + Format.asprintf "%a" Michelson_v1_printer.print_expr expr + in + Assert.equal + ~loc:__LOC__ + String.equal + "Storage isn't equal" + Format.pp_print_string + (to_string storage) + (to_string expected_storage) + >>=? fun () -> return_unit + +let liquidity_baking_balance_update () = + Context.init 1 >>=? fun (blk, _contracts) -> + Context.get_liquidity_baking_cpmm_address (B blk) >>=? fun liquidity_baking -> + Context.get_constants (B blk) >>=? fun csts -> + let sunset = csts.parametric.liquidity_baking_sunset_level in + let subsidy = csts.parametric.liquidity_baking_subsidy in + Block.bake_n_with_all_balance_updates Int32.(to_int (add sunset 100l)) blk + >>=? fun (_blk, balance_updates) -> + let liquidity_baking_updates = + List.filter + (fun el -> + match el with + | ( Alpha_context.Receipt.Contract contract, + Alpha_context.Receipt.Credited _, + Alpha_context.Receipt.Subsidy ) -> + Alpha_context.Contract.(contract = liquidity_baking) + | _ -> false) + balance_updates + in + List.fold_left_e + (fun accum (_, update, _) -> + match update with + | Alpha_context.Receipt.Credited x -> Tez.(accum +? x) + | Alpha_context.Receipt.Debited _ -> assert false) + Tez.(of_int 0) + liquidity_baking_updates + >>?= fun credits -> + Assert.equal_int + ~loc:__LOC__ + (Int64.to_int (Tez.to_mutez credits)) + ((Int32.to_int sunset - 1) * Int64.to_int (Tez.to_mutez subsidy)) + >>=? fun () -> return_unit + +let get_cpmm_result results = + match results with + | cpmm_result :: _results -> cpmm_result + | _ -> assert false + +let get_lqt_result results = + match results with + | _cpmm_result :: lqt_result :: _results -> lqt_result + | _ -> assert false + +let get_address_in_result result = + match result with + | Apply_results.Origination_result {originated_contracts; _} -> ( + match originated_contracts with [c] -> c | _ -> assert false) + +let get_balance_update_in_result result = + match result with + | Apply_results.Origination_result {balance_updates; _} -> ( + match balance_updates with + | [(Contract _, Credited balance, Protocol_migration)] -> balance + | _ -> assert false) + +let liquidity_baking_origination_result_cpmm_address () = + Context.init 1 >>=? fun (blk, _contracts) -> + Context.get_liquidity_baking_cpmm_address (B blk) + >>=? fun cpmm_address_in_storage -> + Block.bake_n_with_origination_results 1 blk + >>=? fun (_blk, origination_results) -> + let result = get_cpmm_result origination_results in + let address = get_address_in_result result in + Assert.equal + ~loc:__LOC__ + Context.Contract.equal + "CPMM address in storage is not the same as in origination result" + Context.Contract.pp + address + cpmm_address_in_storage + >>=? fun () -> return_unit + +let liquidity_baking_origination_result_cpmm_balance () = + Context.init 1 >>=? fun (blk, _contracts) -> + Block.bake_n_with_origination_results 1 blk + >>=? fun (_blk, origination_results) -> + let result = get_cpmm_result origination_results in + let balance_update = get_balance_update_in_result result in + Assert.equal_tez ~loc:__LOC__ balance_update Tez.(of_mutez_exn 100L) + >>=? fun () -> return_unit + +let liquidity_baking_origination_result_lqt_address () = + Context.init 1 >>=? fun (blk, _contracts) -> + Block.bake_n_with_origination_results 1 blk + >>=? fun (_blk, origination_results) -> + let result = get_lqt_result origination_results in + let address = get_address_in_result result in + Assert.equal + ~loc:__LOC__ + String.equal + "LQT address in origination result is incorrect" + Format.pp_print_string + (Alpha_context.Contract.to_b58check address) + "KT1AafHA1C1vk959wvHWBispY9Y2f3fxBUUo" + >>=? fun () -> return_unit + +let liquidity_baking_origination_result_lqt_balance () = + Context.init 1 >>=? fun (blk, _contracts) -> + Block.bake_n_with_origination_results 1 blk + >>=? fun (_blk, origination_results) -> + let result = get_lqt_result origination_results in + let balance_update = get_balance_update_in_result result in + Assert.equal_tez ~loc:__LOC__ balance_update Tez.zero >>=? fun () -> + return_unit + +(* Test that with no contract at the tzBTC address and the level low enough to indicate we're not on mainnet, three contracts are originated in stitching. *) +let liquidity_baking_origination_test_migration () = + Context.init 1 >>=? fun (blk, _contracts) -> + Block.bake_n_with_origination_results 1 blk + >>=? fun (_blk, origination_results) -> + let num_results = List.length origination_results in + Assert.equal_int ~loc:__LOC__ num_results 3 + +(* Test that with no contract at the tzBTC address and the level high enough to indicate we could be on mainnet, no contracts are originated in stitching. *) +let liquidity_baking_origination_no_tzBTC_mainnet_migration () = + Context.init 1 ~level:1_437_862l >>=? fun (blk, _contracts) -> + (* By baking a bit we also check that the subsidy application with no CPMM present does nothing rather than stopping the chain.*) + Block.bake_n_with_origination_results 64 blk + >>=? fun (_blk, origination_results) -> + let num_results = List.length origination_results in + Assert.equal_int ~loc:__LOC__ num_results 0 + +let tests = + [ + Tztest.tztest + "test liquidity baking script hashes" + `Quick + liquidity_baking_origination; + Tztest.tztest + "test liquidity baking cpmm is originated at the expected address" + `Quick + liquidity_baking_cpmm_address; + Tztest.tztest "Init Context" `Quick generate_init_state; + Tztest.tztest + "test liquidity baking subsidy is correct" + `Quick + (liquidity_baking_subsidies 64); + Tztest.tztest + "test liquidity baking shuts off at sunset level when baking one block \ + longer" + `Quick + (liquidity_baking_sunset_level 1); + Tztest.tztest + "test liquidity baking shuts off at sunset level when baking two blocks \ + longer" + `Quick + (liquidity_baking_sunset_level 2); + Tztest.tztest + "test liquidity baking shuts off at sunset level when baking 100 blocks \ + longer" + `Quick + (liquidity_baking_sunset_level 100); + Tztest.tztest + "test liquidity baking escape hatch with 100% of bakers flagging when \ + baking one block longer" + `Quick + (liquidity_baking_escape_hatch_100 1); + Tztest.tztest + "test liquidity baking escape hatch with 100% of bakers flagging when \ + baking two blocks longer" + `Quick + (liquidity_baking_escape_hatch_100 2); + Tztest.tztest + "test liquidity baking escape hatch with 100% of bakers flagging when \ + baking 100 blocks longer" + `Quick + (liquidity_baking_escape_hatch_100 100); + Tztest.tztest + "test liquidity baking escape hatch with 80% of bakers flagging when \ + baking one block longer" + `Quick + (liquidity_baking_escape_hatch_80 1); + Tztest.tztest + "test liquidity baking escape hatch with 80% of bakers flagging when \ + baking two blocks longer" + `Quick + (liquidity_baking_escape_hatch_80 2); + Tztest.tztest + "test liquidity baking escape hatch with 80% of bakers flagging when \ + baking 100 blocks longer" + `Quick + (liquidity_baking_escape_hatch_80 100); + Tztest.tztest + "test liquidity baking escape hatch with 60% of bakers flagging when \ + baking one block longer" + `Quick + (liquidity_baking_escape_hatch_60 1); + Tztest.tztest + "test liquidity baking escape hatch with 60% of bakers flagging when \ + baking two blocks longer" + `Quick + (liquidity_baking_escape_hatch_60 2); + Tztest.tztest + "test liquidity baking escape hatch with 60% of bakers flagging when \ + baking 100 blocks longer" + `Quick + (liquidity_baking_escape_hatch_60 100); + Tztest.tztest + "test liquidity baking shuts off at sunset level with escape hatch at \ + 50% and baking one block longer" + `Quick + (liquidity_baking_escape_hatch_50 1); + Tztest.tztest + "test liquidity baking shuts off at sunset level with escape hatch at \ + 50% and baking two blocks longer" + `Quick + (liquidity_baking_escape_hatch_50 2); + Tztest.tztest + "test liquidity baking shuts off at sunset level with escape hatch at \ + 50% and baking 100 blocks longer" + `Quick + (liquidity_baking_escape_hatch_50 100); + Tztest.tztest + "test liquidity baking escape ema in block metadata is zero with no \ + bakers flagging." + `Quick + liquidity_baking_escape_ema_zero; + Tztest.tztest + "test liquidity baking escape ema is equal to the threshold after the \ + escape hatch has been activated" + `Quick + liquidity_baking_escape_ema_threshold; + Tztest.tztest + "test liquidity baking storage is updated" + `Quick + (liquidity_baking_storage 64); + Tztest.tztest + "test liquidity baking balance updates" + `Quick + liquidity_baking_balance_update; + Tztest.tztest + "test liquidity baking CPMM address in storage matches address in the \ + origination result" + `Quick + liquidity_baking_origination_result_cpmm_address; + Tztest.tztest + "test liquidity baking CPMM balance in origination result is 100 mutez" + `Quick + liquidity_baking_origination_result_cpmm_balance; + Tztest.tztest + "test liquidity baking LQT contract is originated at expected address" + `Quick + liquidity_baking_origination_result_lqt_address; + Tztest.tztest + "test liquidity baking LQT balance in origination result is 0 mutez" + `Quick + liquidity_baking_origination_result_lqt_balance; + Tztest.tztest + "test liquidity baking originates three contracts when tzBTC does not \ + exist and level indicates we are not on mainnet" + `Quick + liquidity_baking_origination_test_migration; + Tztest.tztest + "test liquidity baking originates three contracts when tzBTC does not \ + exist and level indicates we might be on mainnet" + `Quick + liquidity_baking_origination_no_tzBTC_mainnet_migration; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_origination.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_origination.ml new file mode 100644 index 000000000000..5131562c6738 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_origination.ml @@ -0,0 +1,239 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (origination) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^origination$" + Subject: On originating contracts. +*) + +open Protocol +open Test_tez + +let ten_tez = Tez.of_int 10 + +(** [register_origination fee credit spendable delegatable] takes four + optional parameter: fee for the fee need to be paid if set to + create an originated contract; credit is the amount of tez that + send to this originated contract; spendable default is set to true + meaning that this contract is spendable; delegatable default is + set to true meaning that this contract is able to delegate. *) +let register_origination ?(fee = Tez.zero) ?(credit = Tez.zero) () = + Context.init 1 >>=? fun (b, contracts) -> + let source = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd contracts in + Context.Contract.balance (B b) source >>=? fun source_balance -> + Op.origination (B b) source ~fee ~credit ~script:Op.dummy_script + >>=? fun (operation, originated) -> + Block.bake ~operation b >>=? fun b -> + (* fee + credit + block security deposit were debited from source *) + Context.get_constants (B b) + >>=? fun { + parametric = + {origination_size; cost_per_byte; block_security_deposit; _}; + _; + } -> + Tez.(cost_per_byte *? Int64.of_int origination_size) + >>?= fun origination_burn -> + Tez.( +? ) credit block_security_deposit + >>? Tez.( +? ) fee + >>? Tez.( +? ) origination_burn + >>? Tez.( +? ) Op.dummy_script_cost + >>?= fun total_fee -> + Assert.balance_was_debited ~loc:__LOC__ (B b) source source_balance total_fee + >>=? fun () -> + (* originated contract has been credited *) + Assert.balance_was_credited ~loc:__LOC__ (B b) originated Tez.zero credit + >|=? fun () -> + (* TODO spendable or not and delegatable or not if relevant for some + test. Not the case at the moment, cf. uses of + register_origination *) + (b, source, originated) + +(* [test_origination_balances fee credit spendable delegatable] + takes four optional parameter: fee is the fee that pay if require to create + an originated contract; credit is the amount of tez that will send to this + contract; delegatable default is set to true meaning that this contract is + able to delegate. + This function will create a contract, get the balance of this contract, call + the origination operation to create a new originated contract from this + contract with all the possible fees; and check the balance before/after + originated operation valid. + - the source contract has payed all the fees + - the originated has been credited correctly *) +let test_origination_balances ~loc:_ ?(fee = Tez.zero) ?(credit = Tez.zero) () = + Context.init 1 >>=? fun (b, contracts) -> + let contract = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd contracts in + Context.Contract.balance (B b) contract >>=? fun balance -> + Op.origination (B b) contract ~fee ~credit ~script:Op.dummy_script + >>=? fun (operation, new_contract) -> + (* The possible fees are: a given credit, an origination burn fee + (constants_repr.default.origination_burn = 257 mtez), + a fee that is paid when creating an originate contract. + + We also take into account a block security deposit. Note that it + is not related to origination but to the baking done in the + tests.*) + Context.get_constants (B b) + >>=? fun { + parametric = + {origination_size; cost_per_byte; block_security_deposit; _}; + _; + } -> + Tez.(cost_per_byte *? Int64.of_int origination_size) + >>?= fun origination_burn -> + Tez.( +? ) credit block_security_deposit + >>? Tez.( +? ) fee + >>? Tez.( +? ) origination_burn + >>? Tez.( +? ) Op.dummy_script_cost + >>?= fun total_fee -> + Block.bake ~operation b >>=? fun b -> + (* check that after the block has been baked the source contract + was debited all the fees *) + Assert.balance_was_debited ~loc:__LOC__ (B b) contract balance total_fee + >>=? fun _ -> + (* check the balance of the originate contract is equal to credit *) + Assert.balance_is ~loc:__LOC__ (B b) new_contract credit + +(******************************************************) +(* Tests *) +(******************************************************) + +(** compute half of the balance and divided it by nth times *) + +let two_nth_of_balance incr contract nth = + Context.Contract.balance (I incr) contract >>=? fun balance -> + Lwt.return (Tez.( /? ) balance nth >>? fun res -> Tez.( *? ) res 2L) + +(** Basic test. A contract is created as well as the newly originated + contract (called from origination operation). The balance + before/after are checked. *) +let test_balances_simple () = test_origination_balances ~loc:__LOC__ () + +(** Same as [balances_simple] but credits 10 tez to the originated + contract (no fees). *) +let test_balances_credit () = + test_origination_balances ~loc:__LOC__ ~credit:ten_tez () + +(** Same as [balances_credit] with 10 tez fees. *) +let test_balances_credit_fee () = + test_origination_balances ~loc:__LOC__ ~credit:(Tez.of_int 2) ~fee:ten_tez () + +(** Ask source contract to pay a fee when originating a contract. *) +let test_pay_fee () = + register_origination ~credit:(Tez.of_int 2) ~fee:ten_tez () + >>=? fun (_b, _contract, _new_contract) -> return_unit + +(******************************************************) +(** Errors *) + +(******************************************************) + +(** Create an originate contract where the contract does not have + enough tez to pay for the fee. *) +let test_not_tez_in_contract_to_pay_fee () = + Context.init 2 >>=? fun (b, contracts) -> + let contract_1 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + let contract_2 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 1 + in + Incremental.begin_construction b >>=? fun inc -> + (* transfer everything but one tez from 1 to 2 and check balance of 1 *) + Context.Contract.balance (I inc) contract_1 >>=? fun balance -> + Tez.( -? ) balance Tez.one >>?= fun amount -> + Op.transaction (I inc) contract_1 contract_2 amount >>=? fun operation -> + Incremental.add_operation inc operation >>=? fun inc -> + Assert.balance_was_debited ~loc:__LOC__ (I inc) contract_1 balance amount + >>=? fun _ -> + (* use this source contract to create an originate contract where it requires + to pay a fee and add an amount of credit into this new contract *) + Op.origination + (I inc) + ~fee:ten_tez + ~credit:Tez.one + contract_1 + ~script:Op.dummy_script + >>=? fun (op, _) -> + Incremental.add_operation inc op >>= fun inc -> + Assert.proto_error ~loc:__LOC__ inc (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + +(* Set the endorser of the block as manager/delegate of the originated + account. *) +let register_contract_get_endorser () = + Context.init 1 >>=? fun (b, contracts) -> + let contract = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd contracts in + Incremental.begin_construction b >>=? fun inc -> + Context.get_endorser (I inc) >|=? fun (account_endorser, _slots) -> + (inc, contract, account_endorser) + +(* Create multiple originated contracts and ask contract to pay the fee. *) +let n_originations n ?credit ?fee () = + List.fold_left_es + (fun new_contracts _ -> + register_origination ?fee ?credit () + >|=? fun (_b, _source, new_contract) -> new_contract :: new_contracts) + [] + (1 -- n) + +(** Create 100 originations. *) +let test_multiple_originations () = + n_originations 100 ~credit:(Tez.of_int 2) ~fee:ten_tez () + >>=? fun contracts -> + Assert.equal_int ~loc:__LOC__ (List.length contracts) 100 + +(** Cannot originate two contracts with the same context's counter. *) +let test_counter () = + Context.init 1 >>=? fun (b, contracts) -> + let contract = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd contracts in + Incremental.begin_construction b >>=? fun inc -> + Op.origination (I inc) ~credit:Tez.one contract ~script:Op.dummy_script + >>=? fun (op1, _) -> + Op.origination (I inc) ~credit:Tez.one contract ~script:Op.dummy_script + >>=? fun (op2, _) -> + Incremental.add_operation inc op1 >>=? fun inc -> + Incremental.add_operation inc op2 >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Contract_storage.Counter_in_the_past _ -> true + | _ -> false) + +(******************************************************) + +let tests = + [ + Tztest.tztest "balances_simple" `Quick test_balances_simple; + Tztest.tztest "balances_credit" `Quick test_balances_credit; + Tztest.tztest "balances_credit_fee" `Quick test_balances_credit_fee; + Tztest.tztest "pay_fee" `Quick test_pay_fee; + Tztest.tztest + "not enough tez in contract to pay fee" + `Quick + test_not_tez_in_contract_to_pay_fee; + Tztest.tztest "multiple originations" `Quick test_multiple_originations; + Tztest.tztest "counter" `Quick test_counter; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_qty.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_qty.ml new file mode 100644 index 000000000000..7ed70cd368ee --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_qty.ml @@ -0,0 +1,159 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (quantities) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^qty$" + Subject: On tez quantities. +*) + +open Protocol + +let known_ok_tez_literals = + [ + (0L, "0"); + (10L, "0.00001"); + (100L, "0.0001"); + (1_000L, "0.001"); + (10_000L, "0.01"); + (100_000L, "0.1"); + (1_000_000L, "1"); + (10_000_000L, "10"); + (100_000_000L, "100"); + (1_000_000_000L, "1000"); + (10_000_000_000L, "10000"); + (100_000_000_000L, "100000"); + (1_000_000_000_000L, "1000000"); + (1_000_000_000_001L, "1000000.000001"); + (1_000_000_000_010L, "1000000.00001"); + (1_000_000_000_100L, "1000000.0001"); + (1_000_000_001_000L, "1000000.001"); + (1_000_000_010_000L, "1000000.01"); + (1_000_000_100_000L, "1000000.1"); + (123_123_123_123_123_123L, "123123123123.123123"); + (999_999_999_999_999_999L, "999999999999.999999"); + ] + +let known_bad_tez_literals = + [ + "10000."; + "100,."; + "100,"; + "1,0000"; + "0.0000,1"; + "0.00,1"; + "0,1"; + "HAHA"; + "0.000,000,1"; + "0.0000000"; + "9,999,999,999,999.999,999"; + ] + +let fail expected given msg = + Format.kasprintf + Stdlib.failwith + "@[%s@ expected: %s@ got: %s@]" + msg + expected + given + +let fail_msg fmt = Format.kasprintf (fail "" "") fmt + +let default_printer _ = "" + +(** Literals which are supposed to be parsed correctly. *) +let test_known_tez_literals () = + List.iter + (fun (v, s) -> + let vv = Tez_repr.of_mutez v in + let vs = Tez_repr.of_string s in + let vs' = + Tez_repr.of_string (String.concat "" (String.split_on_char ',' s)) + in + let vv = + match vv with None -> fail_msg "could not unopt %Ld" v | Some vv -> vv + in + let vs = + match vs with None -> fail_msg "could not unopt %s" s | Some vs -> vs + in + let vs' = + match vs' with + | None -> fail_msg "could not unopt %s" s + | Some vs' -> vs' + in + assert (vv = vs) ; + assert (vv = vs') ; + assert (Tez_repr.to_string vv = s)) + known_ok_tez_literals ; + List.iter + (fun s -> + let vs = Tez_repr.of_string s in + assert (vs = None)) + known_bad_tez_literals ; + return_unit + +(** Randomly generated tez value which is printed into a string then + parsed again for their equality. *) +let test_random_tez_literals () = + for _ = 0 to 100_000 do + let v = Random.int64 12L in + let vv = Tez_repr.of_mutez v in + let vv = + match vv with None -> fail_msg "could not unopt %Ld" v | Some vv -> vv + in + let s = Tez_repr.to_string vv in + let vs = Tez_repr.of_string s in + let s' = String.concat "" (String.split_on_char ',' s) in + let vs' = Tez_repr.of_string s' in + assert (vs <> None) ; + assert (vs' <> None) ; + (match vs with + | None -> assert false + | Some vs -> + let rev = Tez_repr.to_int64 vs in + assert (v = rev)) ; + match vs' with + | None -> assert false + | Some vs' -> + let rev = Tez_repr.to_int64 vs' in + assert (v = rev) + done ; + return_unit + +let tests = + [ + ("tez-literals", fun _ -> test_known_tez_literals ()); + ("rnd-tez-literals", fun _ -> test_random_tez_literals ()); + ] + +let wrap (n, f) = + Alcotest_lwt.test_case n `Quick (fun _ () -> + f () >|= function + | Ok () -> () + | Error error -> + Format.kasprintf Stdlib.failwith "%a" pp_print_error error) + +let tests = List.map wrap tests diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_reveal.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_reveal.ml new file mode 100644 index 000000000000..e1a96b4daa46 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_reveal.ml @@ -0,0 +1,108 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (revelation) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^revelation$" + Subject: On the reveal operation. +*) + +(** Test for the [Reveal] operation. *) + +open Protocol +open Test_tez + +let ten_tez = Tez.of_int 10 + +let test_simple_reveal () = + Context.init 1 >>=? fun (blk, contracts) -> + let c = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd contracts in + let new_c = Account.new_account () in + let new_contract = Alpha_context.Contract.implicit_contract new_c.pkh in + (* Create the contract *) + Op.transaction (B blk) c new_contract Tez.one >>=? fun operation -> + Block.bake blk ~operation >>=? fun blk -> + (Context.Contract.is_manager_key_revealed (B blk) new_contract >|=? function + | true -> Stdlib.failwith "Unexpected revelation" + | false -> ()) + >>=? fun () -> + (* Reveal the contract *) + Op.revelation (B blk) new_c.pk >>=? fun operation -> + Block.bake blk ~operation >>=? fun blk -> + Context.Contract.is_manager_key_revealed (B blk) new_contract >|=? function + | true -> () + | false -> Stdlib.failwith "New contract revelation failed." + +let test_empty_account_on_reveal () = + Context.init 1 >>=? fun (blk, contracts) -> + let c = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd contracts in + let new_c = Account.new_account () in + let new_contract = Alpha_context.Contract.implicit_contract new_c.pkh in + let amount = Tez.one_mutez in + (* Create the contract *) + Op.transaction (B blk) c new_contract amount >>=? fun operation -> + Block.bake blk ~operation >>=? fun blk -> + (Context.Contract.is_manager_key_revealed (B blk) new_contract >|=? function + | true -> Stdlib.failwith "Unexpected revelation" + | false -> ()) + >>=? fun () -> + (* Reveal the contract *) + Op.revelation ~fee:amount (B blk) new_c.pk >>=? fun operation -> + Incremental.begin_construction blk >>=? fun inc -> + Incremental.add_operation inc operation >>=? fun _ -> + Block.bake blk ~operation >>=? fun blk -> + Context.Contract.is_manager_key_revealed (B blk) new_contract >|=? function + | false -> () + | true -> Stdlib.failwith "Empty account still exists and is revealed." + +let test_not_enough_found_for_reveal () = + Context.init 1 >>=? fun (blk, contracts) -> + let c = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd contracts in + let new_c = Account.new_account () in + let new_contract = Alpha_context.Contract.implicit_contract new_c.pkh in + (* Create the contract *) + Op.transaction (B blk) c new_contract Tez.one_mutez >>=? fun operation -> + Block.bake blk ~operation >>=? fun blk -> + (Context.Contract.is_manager_key_revealed (B blk) new_contract >|=? function + | true -> Stdlib.failwith "Unexpected revelation" + | false -> ()) + >>=? fun () -> + (* Reveal the contract *) + Op.revelation ~fee:Tez.fifty_cents (B blk) new_c.pk >>=? fun operation -> + Block.bake blk ~operation >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Contract_storage.Balance_too_low _ -> true + | _ -> false) + +let tests = + [ + Tztest.tztest "simple reveal" `Quick test_simple_reveal; + Tztest.tztest "empty account on reveal" `Quick test_empty_account_on_reveal; + Tztest.tztest + "not enough found for reveal" + `Quick + test_not_enough_found_for_reveal; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_rolls.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_rolls.ml new file mode 100644 index 000000000000..60e67b75f1dc --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_rolls.ml @@ -0,0 +1,306 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (rolls) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^rolls$" + Subject: On rolls and baking rights. + A delegate has baking rights provided that it has at least + more than [token_per_rolls] tz of staking balance. This + balance corresponds to the quantity of tez that have been + delegated to it for baking rights. After a given number of + cycles where it has not made use of its baking rights, its + account will be deactivated for baker selection. To bake + again, it will have to re-activate its account. +*) + +open Protocol +open Alpha_context +open Test_tez + +let account_pair = function [a1; a2] -> (a1, a2) | _ -> assert false + +let wrap e = Lwt.return (Environment.wrap_tzresult e) + +(** Baking rights consistency. Assert that the number of rolls for + [account]'s pkh - equals to the number of expected rolls, i.e., + staking balance of [account] / (token_per_roll). As of protocol + version 007, token_per_roll = 8000. Note that the consistency is + verified against the value in the context, i.e. we are testing + Storage.Roll.Delegate_roll_list. We do not use RPCs here. *) +let check_rolls (b : Block.t) (account : Account.t) = + Context.get_constants (B b) >>=? fun constants -> + Context.Delegate.info (B b) account.pkh >>=? fun {staking_balance; _} -> + let token_per_roll = constants.parametric.tokens_per_roll in + let expected_rolls = + Int64.div (Tez.to_mutez staking_balance) (Tez.to_mutez token_per_roll) + in + Raw_context.prepare + b.context + ~level:b.header.shell.level + ~predecessor_timestamp:b.header.shell.timestamp + ~timestamp:b.header.shell.timestamp + ~fitness:b.header.shell.fitness + >>= wrap + >>=? fun ctxt -> + Roll_storage.count_rolls ctxt account.pkh >>= wrap >>=? fun rolls -> + Assert.equal_int ~loc:__LOC__ rolls (Int64.to_int expected_rolls) + +let check_no_rolls (b : Block.t) (account : Account.t) = + Raw_context.prepare + b.context + ~level:b.header.shell.level + ~predecessor_timestamp:b.header.shell.timestamp + ~timestamp:b.header.shell.timestamp + ~fitness:b.header.shell.fitness + >>= wrap + >>=? fun ctxt -> + Roll_storage.count_rolls ctxt account.pkh >>= wrap >>=? fun rolls -> + Assert.equal_int ~loc:__LOC__ rolls 0 + +(** Create a block with two initialized contracts/accounts. Assert + that the first account has a staking balance that is equal to its + own balance, and that its staking rights are consistent + (check_rolls). *) +let test_simple_staking_rights () = + Context.init 2 >>=? fun (b, accounts) -> + let (a1, _a2) = account_pair accounts in + Context.Contract.balance (B b) a1 >>=? fun balance -> + Context.Contract.manager (B b) a1 >>=? fun m1 -> + Context.Delegate.info (B b) m1.pkh >>=? fun info -> + Assert.equal_tez ~loc:__LOC__ balance info.staking_balance >>=? fun () -> + check_rolls b m1 + +(** Create a block with two initialized contracts/accounts. Bake + five blocks. Assert that the staking balance of the first account + equals to its balance. Then both accounts have consistent staking + rights. *) +let test_simple_staking_rights_after_baking () = + Context.init 2 >>=? fun (b, accounts) -> + let (a1, a2) = account_pair accounts in + Context.Contract.balance (B b) a1 >>=? fun balance -> + Context.Contract.manager (B b) a1 >>=? fun m1 -> + Context.Contract.manager (B b) a2 >>=? fun m2 -> + Block.bake_n ~policy:(By_account m2.pkh) 5 b >>=? fun b -> + Context.Delegate.info (B b) m1.pkh >>=? fun info -> + Assert.equal_tez ~loc:__LOC__ balance info.staking_balance >>=? fun () -> + check_rolls b m1 >>=? fun () -> check_rolls b m2 + +let frozen_deposit (info : Context.Delegate.info) = + Cycle.Map.fold + (fun _ {Delegate.deposit; _} acc -> Test_tez.Tez.(deposit + acc)) + info.frozen_balance_by_cycle + Tez.zero + +let check_activate_staking_balance ~loc ~deactivated b (a, (m : Account.t)) = + Context.Delegate.info (B b) m.pkh >>=? fun info -> + Assert.equal_bool ~loc info.deactivated deactivated >>=? fun () -> + Context.Contract.balance (B b) a >>=? fun balance -> + let deposit = frozen_deposit info in + Assert.equal_tez ~loc Test_tez.Tez.(balance + deposit) info.staking_balance + +let run_until_deactivation () = + Context.init 2 >>=? fun (b, accounts) -> + let (a1, a2) = account_pair accounts in + Context.Contract.balance (B b) a1 >>=? fun balance_start -> + Context.Contract.manager (B b) a1 >>=? fun m1 -> + Context.Contract.manager (B b) a2 >>=? fun m2 -> + check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b (a1, m1) + >>=? fun () -> + Context.Delegate.info (B b) m1.pkh >>=? fun info -> + Block.bake_until_cycle ~policy:(By_account m2.pkh) info.grace_period b + >>=? fun b -> + check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b (a1, m1) + >>=? fun () -> + Block.bake_until_cycle_end ~policy:(By_account m2.pkh) b >>=? fun b -> + check_activate_staking_balance ~loc:__LOC__ ~deactivated:true b (a1, m1) + >|=? fun () -> (b, ((a1, m1), balance_start), (a2, m2)) + +(** From an initialized block with two contracts/accounts, the first + one is active then deactivated. After baking, check that the + account is active again. Baking rights are ensured. *) +let test_deactivation_then_bake () = + run_until_deactivation () + >>=? fun ( b, + ( ((_deactivated_contract, deactivated_account) as deactivated), + _start_balance ), + (_a2, _m2) ) -> + Block.bake ~policy:(By_account deactivated_account.pkh) b >>=? fun b -> + check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b deactivated + >>=? fun () -> check_rolls b deactivated_account + +(** A deactivated account, after baking with self-delegation, is + active again. Preservation of its balance is tested. Baking rights + are ensured. *) +let test_deactivation_then_self_delegation () = + run_until_deactivation () + >>=? fun ( b, + ( ((deactivated_contract, deactivated_account) as deactivated), + start_balance ), + (_a2, m2) ) -> + Op.delegation (B b) deactivated_contract (Some deactivated_account.pkh) + >>=? fun self_delegation -> + Block.bake ~policy:(By_account m2.pkh) b ~operation:self_delegation + >>=? fun b -> + check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b deactivated + >>=? fun () -> + Context.Contract.balance (B b) deactivated_contract >>=? fun balance -> + Assert.equal_tez ~loc:__LOC__ start_balance balance >>=? fun () -> + check_rolls b deactivated_account + +(** A deactivated account, which is emptied (into a newly created sink + account), then self-delegated, becomes activated. Its balance is + zero. Baking rights are ensured. *) +let test_deactivation_then_empty_then_self_delegation () = + run_until_deactivation () + >>=? fun ( b, + ( ((deactivated_contract, deactivated_account) as deactivated), + _start_balance ), + (_a2, m2) ) -> + (* empty the contract *) + Context.Contract.balance (B b) deactivated_contract >>=? fun balance -> + let sink_account = Account.new_account () in + let sink_contract = Contract.implicit_contract sink_account.pkh in + Context.get_constants (B b) + >>=? fun {parametric = {origination_size; cost_per_byte; _}; _} -> + Tez.(cost_per_byte *? Int64.of_int origination_size) + >>?= fun origination_burn -> + let amount = + match Tez.(balance -? origination_burn) with + | Ok r -> r + | Error _ -> assert false + in + Op.transaction (B b) deactivated_contract sink_contract amount + >>=? fun empty_contract -> + Block.bake ~policy:(By_account m2.pkh) ~operation:empty_contract b + >>=? fun b -> + (* self delegation *) + Op.delegation (B b) deactivated_contract (Some deactivated_account.pkh) + >>=? fun self_delegation -> + Block.bake ~policy:(By_account m2.pkh) ~operation:self_delegation b + >>=? fun b -> + check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b deactivated + >>=? fun () -> + Context.Contract.balance (B b) deactivated_contract >>=? fun balance -> + Assert.equal_tez ~loc:__LOC__ Tez.zero balance >>=? fun () -> + check_rolls b deactivated_account + +(** A deactivated account, which is emptied, then self-delegated, then + re-credited of the sunk amount, becomes active again. Staking + rights remain consistent. *) +let test_deactivation_then_empty_then_self_delegation_then_recredit () = + run_until_deactivation () + >>=? fun ( b, + ( ((deactivated_contract, deactivated_account) as deactivated), + balance ), + (_a2, m2) ) -> + (* empty the contract *) + let sink_account = Account.new_account () in + let sink_contract = Contract.implicit_contract sink_account.pkh in + Context.get_constants (B b) + >>=? fun {parametric = {origination_size; cost_per_byte; _}; _} -> + Tez.(cost_per_byte *? Int64.of_int origination_size) + >>?= fun origination_burn -> + let amount = + match Tez.(balance -? origination_burn) with + | Ok r -> r + | Error _ -> assert false + in + Op.transaction (B b) deactivated_contract sink_contract amount + >>=? fun empty_contract -> + Block.bake ~policy:(By_account m2.pkh) ~operation:empty_contract b + >>=? fun b -> + (* self delegation *) + Op.delegation (B b) deactivated_contract (Some deactivated_account.pkh) + >>=? fun self_delegation -> + Block.bake ~policy:(By_account m2.pkh) ~operation:self_delegation b + >>=? fun b -> + (* recredit *) + Op.transaction (B b) sink_contract deactivated_contract amount + >>=? fun recredit_contract -> + Block.bake ~policy:(By_account m2.pkh) ~operation:recredit_contract b + >>=? fun b -> + check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b deactivated + >>=? fun () -> + Context.Contract.balance (B b) deactivated_contract >>=? fun balance -> + Assert.equal_tez ~loc:__LOC__ amount balance >>=? fun () -> + check_rolls b deactivated_account + +(** Initialize a block with two contracts/accounts. A third new + account is also created. The first account is self-delegated. First + account sends to third one the amount of 0.5 tez. The third account + has no delegate and is consistent for baking rights. Then, it is + self-delegated and is supposed to be activated. Again, consistency + for baking rights are preserved for the first and third accounts. *) +let test_delegation () = + Context.init 2 >>=? fun (b, accounts) -> + let (a1, a2) = account_pair accounts in + let m3 = Account.new_account () in + Account.add_account m3 ; + Context.Contract.manager (B b) a1 >>=? fun m1 -> + Context.Contract.manager (B b) a2 >>=? fun m2 -> + let a3 = Contract.implicit_contract m3.pkh in + Context.Contract.delegate_opt (B b) a1 >>=? fun delegate -> + (match delegate with + | None -> assert false + | Some pkh -> assert (Signature.Public_key_hash.equal pkh m1.pkh)) ; + Op.transaction (B b) a1 a3 Tez.fifty_cents >>=? fun transact -> + Block.bake ~policy:(By_account m2.pkh) b ~operation:transact >>=? fun b -> + Context.Contract.delegate_opt (B b) a3 >>=? fun delegate -> + (match delegate with None -> () | Some _ -> assert false) ; + check_no_rolls b m3 >>=? fun () -> + Op.delegation (B b) a3 (Some m3.pkh) >>=? fun delegation -> + Block.bake ~policy:(By_account m2.pkh) b ~operation:delegation >>=? fun b -> + Context.Contract.delegate_opt (B b) a3 >>=? fun delegate -> + (match delegate with + | None -> assert false + | Some pkh -> assert (Signature.Public_key_hash.equal pkh m3.pkh)) ; + check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b (a3, m3) + >>=? fun () -> + check_rolls b m3 >>=? fun () -> check_rolls b m1 + +let tests = + [ + Tztest.tztest "simple staking rights" `Quick test_simple_staking_rights; + Tztest.tztest + "simple staking rights after baking" + `Quick + test_simple_staking_rights_after_baking; + Tztest.tztest "deactivation then bake" `Quick test_deactivation_then_bake; + Tztest.tztest + "deactivation then self delegation" + `Quick + test_deactivation_then_self_delegation; + Tztest.tztest + "deactivation then empty then self delegation" + `Quick + test_deactivation_then_empty_then_self_delegation; + Tztest.tztest + "deactivation then empty then self delegation then recredit" + `Quick + test_deactivation_then_empty_then_self_delegation_then_recredit; + Tztest.tztest "delegation" `Quick test_delegation; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_sapling.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_sapling.ml new file mode 100644 index 000000000000..6b30a694cdd1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_sapling.ml @@ -0,0 +1,1136 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (Sapling) + Invocation: cd src/proto_alpha/lib_protocol/test + dune exec ./main.exe -- test "^sapling$" + Subject: On the privacy-preserving library Sapling +*) + +open Protocol + +let ( >>??= ) x y = + match x with + | Ok s -> y s + | Error err -> Lwt.return @@ Error (Environment.wrap_tztrace err) + +module Raw_context_tests = struct + open Sapling_helpers.Common + + (* This test adds to the first 100 positions in the commitments tree the + constant value `uncommitted` for which we know the corresponding root and + tests that the returned root is as expected. *) + let commitments_add_uncommitted () = + Context.init 1 >>=? fun (b, _) -> + Raw_context.prepare + b.context + ~level:b.header.shell.level + ~predecessor_timestamp:b.header.shell.timestamp + ~timestamp:b.header.shell.timestamp + ~fitness:b.header.shell.fitness + >>= wrap + >>=? fun ctx -> + let module H = Tezos_sapling.Core.Client.Hash in + let cm = H.uncommitted ~height:0 in + let expected_root = H.uncommitted ~height:32 in + Lazy_storage_diff.fresh Lazy_storage_kind.Sapling_state ~temporary:false ctx + >>= wrap + >>=? fun (ctx, id) -> + Sapling_storage.init ctx id ~memo_size:0 >>= wrap >>=? fun ctx -> + List.fold_left_es + (fun ctx pos -> + Sapling_storage.Commitments.get_root ctx id >>= wrap + >>=? fun (ctx, root) -> + assert (root = expected_root) ; + Sapling_storage.Commitments.add + ctx + id + [H.to_commitment cm] + (Int64.of_int pos) + >>= wrap + >>=? fun (ctx, _size) -> + Sapling_storage.Commitments.get_root ctx id >>= wrap + >|=? fun (ctx, root) -> + assert (root = expected_root) ; + ctx) + ctx + (0 -- 99) + >>=? fun _ctx -> return_unit + + (* Nullifiers don't check for duplicates are it's done by verify_update, + however committing to disk twice the same nf causes a storage error by + trying to initialize the same key twice. *) + let nullifier_double () = + Context.init 1 >>=? fun (b, _) -> + Raw_context.prepare + b.context + ~level:b.header.shell.level + ~predecessor_timestamp:b.header.shell.timestamp + ~timestamp:b.header.shell.timestamp + ~fitness:b.header.shell.fitness + >>= wrap + >>=? fun ctx -> + Lazy_storage_diff.fresh Lazy_storage_kind.Sapling_state ~temporary:false ctx + >>= wrap + >>=? fun (ctx, id) -> + Sapling_storage.init ctx id ~memo_size:0 >>= wrap >>=? fun ctx -> + let nf = gen_nf () in + let open Sapling_storage in + let state = + {id = Some id; diff = Sapling_storage.empty_diff; memo_size = 0} + in + let state = nullifiers_add state nf in + let state = nullifiers_add state nf in + assert (List.length state.diff.nullifiers = 2) ; + Sapling_storage.Nullifiers.size ctx id >>= wrap >>=? fun disk_size -> + assert (disk_size = 0L) ; + Sapling_storage.apply_diff ctx id state.diff |> assert_error + + (* In this test we add two lists of nullifiers to the state, one is applied to + the context (committed to disk) and one is kept in kept in a diff (only in + memory). We then check that nullifier_mem answers true for those two lists + and false for a third one. *) + let nullifier_test () = + Context.init 1 >>=? fun (b, _) -> + Raw_context.prepare + b.context + ~level:b.header.shell.level + ~predecessor_timestamp:b.header.shell.timestamp + ~timestamp:b.header.shell.timestamp + ~fitness:b.header.shell.fitness + >>= wrap + >>=? fun ctx -> + Lazy_storage_diff.fresh Lazy_storage_kind.Sapling_state ~temporary:false ctx + >>= wrap + >>=? fun (ctx, id) -> + Sapling_storage.init ctx id ~memo_size:0 >>= wrap >>=? fun ctx -> + let nf_list_ctx = + List.init ~when_negative_length:() 10 (fun _ -> gen_nf ()) |> function + | Error () -> assert false (* 10 > 0 *) + | Ok nf_list_ctx -> nf_list_ctx + in + let state = + List.fold_left + (fun state nf -> Sapling_storage.nullifiers_add state nf) + {id = Some id; diff = Sapling_storage.empty_diff; memo_size = 0} + nf_list_ctx + in + Sapling_storage.apply_diff ctx id state.diff >>= wrap >>=? fun (ctx, _) -> + let nf_list_diff = + List.init ~when_negative_length:() 10 (fun _ -> gen_nf ()) |> function + | Error () -> assert false (* 10 > 0 *) + | Ok nf_list_diff -> nf_list_diff + in + let state = + List.fold_left + (fun state nf -> Sapling_storage.nullifiers_add state nf) + state + nf_list_diff + in + List.iter_ep + (fun nf -> + Sapling_storage.nullifiers_mem ctx state nf >>= wrap + >>=? fun (_, bool) -> + assert bool ; + return_unit) + (nf_list_ctx @ nf_list_diff) + >>=? fun () -> + let nf_list_absent = + List.init 10 ~when_negative_length:() (fun _ -> gen_nf ()) |> function + | Error () -> assert false (* 10 > 0 *) + | Ok nf_list_absent -> nf_list_absent + in + List.iter_ep + (fun nf -> + Sapling_storage.nullifiers_mem ctx state nf >>= wrap + >>=? fun (_, bool) -> + assert (not bool) ; + return_unit) + nf_list_absent + + (* This test applies a diff with tuples of ciphertext, commitment. Then it + checks the result of get_from with different indexes. *) + let cm_cipher_test () = + Random.self_init () ; + let memo_size = Random.int 200 in + Context.init 1 >>=? fun (b, _) -> + Raw_context.prepare + b.context + ~level:b.header.shell.level + ~predecessor_timestamp:b.header.shell.timestamp + ~timestamp:b.header.shell.timestamp + ~fitness:b.header.shell.fitness + >>= wrap + >>=? fun ctx -> + Lazy_storage_diff.fresh Lazy_storage_kind.Sapling_state ~temporary:false ctx + >>= wrap + >>=? fun (ctx, id) -> + Sapling_storage.init ctx id ~memo_size >>= wrap >>=? fun ctx -> + Sapling_storage.state_from_id ctx id >>= wrap >>=? fun (diff, ctx) -> + let list_added = + List.init ~when_negative_length:() 10 (fun _ -> + gen_cm_cipher ~memo_size ()) + |> function + | Error () -> assert false (* 10 > 0 *) + | Ok list_added -> list_added + in + let state = Sapling_storage.add diff list_added in + Sapling_storage.apply_diff ctx id state.diff >>= wrap >>=? fun (ctx, _) -> + let rec test_from from until expected = + if from > until then return_unit + else + Sapling_storage.Ciphertexts.get_from ctx id from >>= wrap + >>=? fun (ctx, result) -> + let expected_cipher = List.map snd expected in + assert (result = expected_cipher) ; + Sapling_storage.Commitments.get_from ctx id from >>= wrap + >>=? fun result -> + let expected_cm = List.map fst expected in + assert (result = expected_cm) ; + test_from + (Int64.succ from) + until + (WithExceptions.Option.get ~loc:__LOC__ @@ List.tl expected) + in + test_from 0L 9L list_added + + (* This test tests the insertion of a list vs inserting one by one. + It does so by checking the equality of the roots. *) + let list_insertion_test () = + Random.self_init () ; + let memo_size = Random.int 200 in + Context.init 1 >>=? fun (b, _) -> + Raw_context.prepare + b.context + ~level:b.header.shell.level + ~predecessor_timestamp:b.header.shell.timestamp + ~timestamp:b.header.shell.timestamp + ~fitness:b.header.shell.fitness + >>= wrap + >>=? fun ctx -> + Lazy_storage_diff.fresh Lazy_storage_kind.Sapling_state ~temporary:false ctx + >>= wrap + >>=? fun (ctx, id_one_by_one) -> + Sapling_storage.init ctx id_one_by_one ~memo_size >>= wrap >>=? fun ctx -> + let list_to_add = + fst @@ List.split + @@ (List.init ~when_negative_length:() 33 (fun _ -> + gen_cm_cipher ~memo_size ()) + |> function + | Error () -> assert false (* 33 > 0 *) + | Ok r -> r) + in + let rec test counter ctx = + if counter >= 32 then return_unit + else + (* add a single cm to the existing tree *) + Sapling_storage.Commitments.add + ctx + id_one_by_one + [ + WithExceptions.Option.get ~loc:__LOC__ + @@ List.nth list_to_add counter; + ] + (Int64.of_int counter) + >>= wrap + (* create a new tree and add a list of cms *) + >>=? fun (ctx, _size) -> + Lazy_storage_diff.fresh + Lazy_storage_kind.Sapling_state + ~temporary:false + ctx + >>= wrap + >>=? fun (ctx, id_all_at_once) -> + Sapling_storage.init ctx id_all_at_once ~memo_size >>= wrap + >>=? fun ctx -> + Sapling_storage.Commitments.add + ctx + id_all_at_once + (List.init ~when_negative_length:() (counter + 1) (fun i -> + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth list_to_add i) + |> function + | Error () -> assert false (* counter >= 0*) + | Ok r -> r) + 0L + >>= wrap + >>=? fun (ctx, _size) -> + Sapling_storage.Commitments.get_root ctx id_one_by_one >>= wrap + >>=? fun (ctx, root_one_by_one) -> + Sapling_storage.Commitments.get_root ctx id_all_at_once >>= wrap + >>=? fun (ctx, root_all_at_once) -> + assert (root_all_at_once = root_one_by_one) ; + test (counter + 1) ctx + in + test 0 ctx + + (* This test adds 10 more roots the maximum capacity, all at different + levels, and checks that all but the first 10 are stored. + Then it adds one in the diff and checks it is stored. + Then it adds 10 at the same level and check that only the last one is + stored. *) + let root_test () = + let open Tezos_sapling.Core in + let gen_root () = + Data_encoding.Binary.of_bytes_exn + Validator.Hash.encoding + (Hacl.Rand.gen 32) + in + let roots_ctx = + List.init + ~when_negative_length:() + (Int32.to_int Sapling_storage.Roots.size + 10) + (fun _ -> gen_root ()) + |> function + | Error () -> assert false (* size >= 0 *) + | Ok roots_ctx -> roots_ctx + in + Context.init 1 >>=? fun (b, _) -> + Raw_context.prepare + b.context + ~level:b.header.shell.level + ~predecessor_timestamp:b.header.shell.timestamp + ~timestamp:b.header.shell.timestamp + ~fitness:b.header.shell.fitness + >>= wrap + >>=? fun ctx -> + Lazy_storage_diff.fresh Lazy_storage_kind.Sapling_state ~temporary:false ctx + >>= wrap + >>=? fun (ctx, id) -> + Sapling_storage.init ctx id ~memo_size:0 >>= wrap >>=? fun ctx -> + (* Add one root per level to the context *) + List.fold_left_es + (fun (ctx, cnt) root -> + Sapling_storage.Roots.add ctx id root >>= wrap >>=? fun ctx -> + (* Very low level way to "bake" a block. It would be better to use the + helpers functions but they complicate the access to the raw_context. *) + Raw_context.prepare + ~level:(Int32.add b.header.shell.level cnt) + ~predecessor_timestamp:b.header.shell.timestamp + ~timestamp:b.header.shell.timestamp + ~fitness:b.header.shell.fitness + (Raw_context.recover ctx) + >>= wrap + >|=? fun ctx -> (ctx, Int32.succ cnt)) + (ctx, 0l) + roots_ctx + >>=? fun (ctx, _) -> + (* Check mem on all the roots in the context. *) + let state = + Sapling_storage. + {id = Some id; diff = Sapling_storage.empty_diff; memo_size = 0} + in + List.fold_left_es + (fun i root -> + Sapling_storage.root_mem ctx state root >>= wrap >|=? fun bool -> + assert (if i < 10 then not bool else bool) ; + i + 1) + 0 + roots_ctx + >>=? fun _ -> + (* Add roots w/o increasing the level *) + let roots_same_level = + List.init ~when_negative_length:() 10 (fun _ -> gen_root ()) |> function + | Error () -> assert false (* 10 > 0 *) + | Ok roots_same_level -> roots_same_level + in + List.fold_left_es + (fun ctx root -> Sapling_storage.Roots.add ctx id root >>= wrap) + ctx + roots_same_level + >>=? fun ctx -> + List.fold_left_es + (fun (i, ctx) root -> + Sapling_storage.root_mem ctx state root >>= wrap >|=? fun bool -> + assert (if i < 9 then not bool else bool) ; + (i + 1, ctx)) + (0, ctx) + roots_same_level + >>=? fun _ -> return_unit + + let test_get_memo_size () = + Context.init 1 >>=? fun (b, _) -> + Raw_context.prepare + b.context + ~level:b.header.shell.level + ~predecessor_timestamp:b.header.shell.timestamp + ~timestamp:b.header.shell.timestamp + ~fitness:b.header.shell.fitness + >>= wrap + >>=? fun ctx -> + Lazy_storage_diff.fresh Lazy_storage_kind.Sapling_state ~temporary:false ctx + >>= wrap + >>=? fun (ctx, id) -> + Sapling_storage.init ctx id ~memo_size:0 >>= wrap >>=? fun ctx -> + Sapling_storage.get_memo_size ctx id >>= wrap >|=? fun memo_size -> + assert (memo_size = 0) +end + +module Alpha_context_tests = struct + open Sapling_helpers.Alpha_context_helpers + + (* Create a transaction with memo_size 1, test that is validates with a newly + created empty_state with memo_size 1 and does not with memo_size 0. *) + let test_verify_memo () = + init () >>=? fun ctx -> + let sk = + Tezos_sapling.Core.Wallet.Spending_key.of_seed + (Tezos_crypto.Hacl.Rand.gen 32) + in + let vt = + let ps = Tezos_sapling.Storage.empty ~memo_size:0 in + (* the dummy output will have memo_size 0 *) + Tezos_sapling.Forge.forge_transaction + ~number_dummy_outputs:1 + [] + [] + sk + "anti-replay" + ps + in + verify_update ctx vt ~memo_size:0 |> assert_some >>=? fun _ -> + verify_update ctx vt ~memo_size:1 |> assert_none + + (* Bench the proving and validation time of shielding and transferring several + tokens. *) + let test_bench_phases () = + init () >>=? fun ctx -> + let rounds = 5 in + Printf.printf "\nrounds: %d\n" rounds ; + let w = wallet_gen () in + let cs = Tezos_sapling.Storage.empty ~memo_size:8 in + (* one verify_update to get the id *) + let vt = transfer w cs [] in + verify_update ctx vt |> assert_some >>=? fun (ctx, id) -> + client_state_alpha ctx id >>=? fun cs -> + let start = Unix.gettimeofday () in + let vts = List.map (fun _ -> transfer w cs []) (1 -- rounds) in + let ctime_shields = Unix.gettimeofday () -. start in + Printf.printf "client_shields %f\n" ctime_shields ; + let start = Unix.gettimeofday () in + List.fold_left_es + (fun ctx vt -> + verify_update ctx ~id vt |> assert_some >|=? fun (ctx, _id) -> ctx) + ctx + vts + >>=? fun ctx -> + let vtime_shields = Unix.gettimeofday () -. start in + Printf.printf "valdtr_shields %f\n" vtime_shields ; + client_state_alpha ctx id >>=? fun cs -> + let start = Unix.gettimeofday () in + let vts = List.map (fun i -> transfer w cs [i]) (1 -- rounds) in + let ctime_transfers = Unix.gettimeofday () -. start in + Printf.printf "client_txs %f\n" ctime_transfers ; + let start = Unix.gettimeofday () in + List.fold_left_es + (fun ctx vt -> + verify_update ctx ~id vt |> assert_some >|=? fun (ctx, _id) -> ctx) + ctx + vts + >|=? fun _ctx -> + let vtime_transfers = Unix.gettimeofday () -. start in + Printf.printf "valdtr_txs %f\n" vtime_transfers + + (* Transfer several times the same token. *) + let test_bench_fold_over_same_token () = + init () >>=? fun ctx -> + let rounds = 5 in + let w = wallet_gen () in + let cs = Tezos_sapling.Storage.empty ~memo_size:8 in + (* one verify_update to get the id *) + let vt = transfer w cs [] in + verify_update ctx vt |> assert_some >>=? fun (ctx, id) -> + let rec loop cnt ctx = + if cnt >= rounds then return_unit + else + (* inefficient: re-synch from scratch at each round *) + client_state_alpha ctx id >>=? fun cs -> + let vt = transfer w cs [cnt] in + verify_update ctx ~id vt |> assert_some >>=? fun (ctx, _id) -> + loop (cnt + 1) ctx + in + loop 0 ctx + + (* + The following tests trigger all the branches of + Sapling_validator.verify_update. + The function performs several checks and returns None in case of failure. + During development the function was modified to throw a different exception + for each of its checks so to be sure that they were reached. + *) + + (* Test that double spending the same input fails the nf check. *) + let test_double_spend_same_input () = + init () >>=? fun ctx -> + let w = wallet_gen () in + let cs = Tezos_sapling.Storage.empty ~memo_size:8 in + (* one verify_update to get the id *) + let vt = transfer w cs [] in + verify_update ctx vt |> assert_some >>=? fun (ctx, id) -> + client_state_alpha ctx id >>=? fun cs -> + let vt = transfer w cs [0] in + verify_update ctx ~id vt |> assert_some >>=? fun (_ctx, id) -> + let vt = transfer w cs [0; 0] in + verify_update ctx ~id vt |> assert_none + + let test_verifyupdate_one_transaction () = + init () >>=? fun ctx -> + let w = wallet_gen () in + let cs = Tezos_sapling.Storage.empty ~memo_size:8 in + let vt = transfer w cs [] in + verify_update ctx vt |> assert_some >>=? fun (ctx, id) -> + client_state_alpha ctx id >>=? fun cs -> + let vt = transfer w cs [0] in + (* fails sig check because of wrong balance *) + let vt_broken = + Tezos_sapling.Core.Validator.UTXO. + {vt with balance = Int64.(succ vt.balance)} + in + verify_update ctx ~id vt_broken |> assert_none >>=? fun () -> + (* randomize one output to fail check outputs *) + (* don't randomize the ciphertext as it is not part of the proof *) + let open Tezos_sapling.Core.Client.UTXO in + let o = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd vt.outputs in + let o_wrong_cm = + { + o with + cm = randomized_byte o.cm Tezos_sapling.Core.Client.Commitment.encoding; + } + in + let vt_broken = + Tezos_sapling.Core.Validator.UTXO.{vt with outputs = [o_wrong_cm]} + in + verify_update ctx ~id vt_broken |> assert_none >>=? fun () -> + (* position inside the cv *) + let pos = Random.int 32 in + let o_wrong_cv = + { + o with + ciphertext = + randomized_byte + ~pos + o.ciphertext + Tezos_sapling.Core.Client.Ciphertext.encoding; + } + in + let vt_broken = + Tezos_sapling.Core.Validator.UTXO.{vt with outputs = [o_wrong_cv]} + in + verify_update ctx ~id vt_broken |> assert_none + + let test_verifyupdate_two_transactions () = + init () >>=? fun ctx -> + let w = wallet_gen () in + let cs = Tezos_sapling.Storage.empty ~memo_size:8 in + (* generate the first storage *) + let vt = transfer w cs [] in + verify_update ctx vt |> assert_some >>=? fun (ctx, id1) -> + client_state_alpha ctx id1 >>=? fun cs1 -> + let vt1 = transfer w cs1 [0] in + (* generate the second storage *) + let vt = transfer w cs [] in + verify_update ctx vt |> assert_some >>=? fun (ctx, id2) -> + client_state_alpha ctx id2 >>=? fun cs2 -> + let vt2 = transfer w cs2 [0] in + (* fail root check *) + verify_update ctx ~id:id1 vt2 |> assert_none >>=? fun () -> + (* Swap the root so that it passes the root_mem check but fails + the input check *) + let vt1_broken = + Tezos_sapling.Core.Validator.UTXO.{vt2 with root = vt1.root} + in + verify_update ctx ~id:id1 vt1_broken |> assert_none >>=? fun () -> + (* fail the sig check *) + let vt1_broken = + Tezos_sapling.Core.Validator.UTXO.{vt1 with outputs = vt2.outputs} + in + verify_update ctx ~id:id1 vt1_broken |> assert_none +end + +module Interpreter_tests = struct + open Sapling_helpers.Interpreter_helpers + + let parameters_of_list transactions = + let string = "{ " ^ String.concat " ; " transactions ^ " }" in + Alpha_context.Script.(lazy_expr (expression_from_string string)) + + (* In this test we use a contract which takes a list of transactions, applies + all of them, and assert all of them are correct. It also enforces a 1-to-1 + conversion with mutez by asking an amount to shield and asking for a pkh to + unshield. + We create 2 keys a and b. We originate the contract, then do two lists of + shield for a, then transfers several outputs to b while unshielding, then + transfer all of b inputs to a while adding dummy inputs and outputs. + At last we fail we make a failing transaction. *) + let test_shielded_tez () = + init () >>=? fun (b, baker, src0, src1) -> + let memo_size = 8 in + originate_contract "contracts/sapling_contract.tz" "{ }" src0 b baker + >>=? fun (dst, b, anti_replay) -> + let wa = wallet_gen () in + let (list_transac, total) = + shield + ~memo_size + wa.sk + 4 + wa.vk + (Format.sprintf "Pair 0x%s None") + anti_replay + in + let parameters = parameters_of_list list_transac in + (* a does a list of shield transaction *) + transac_and_sync ~memo_size b parameters total src0 dst baker + >>=? fun (b, _state) -> + (* we shield again on another block, forging with the empty state *) + let (list_transac, total) = + shield + ~memo_size + wa.sk + 4 + wa.vk + (Format.sprintf "Pair 0x%s None") + anti_replay + in + let parameters = parameters_of_list list_transac in + (* a does a list of shield transaction *) + transac_and_sync ~memo_size b parameters total src0 dst baker + >>=? fun (b, state) -> + (* address that will receive an unshield *) + Context.Contract.balance (B b) src1 >>=? fun balance_before_shield -> + let wb = wallet_gen () in + let list_addr = gen_addr 15 wb.vk in + let list_forge_input = + List.init ~when_negative_length:() 14 (fun pos_int -> + let pos = Int64.of_int pos_int in + let forge_input = + snd + (Tezos_sapling.Forge.Input.get state pos wa.vk + |> WithExceptions.Option.get ~loc:__LOC__) + in + forge_input) + |> function + | Error () -> assert false (* 14 > 0 *) + | Ok list_forge_input -> list_forge_input + in + let list_forge_output = + List.map + (fun addr -> Tezos_sapling.Forge.make_output addr 1L (Bytes.create 8)) + list_addr + in + let hex_transac = + to_hex + (Tezos_sapling.Forge.forge_transaction + ~number_dummy_inputs:0 + ~number_dummy_outputs:0 + list_forge_input + list_forge_output + wa.sk + anti_replay + state) + Tezos_sapling.Core.Client.UTXO.transaction_encoding + in + let hex_pkh = + to_hex + (Alpha_context.Contract.is_implicit src1 + |> WithExceptions.Option.get ~loc:__LOC__) + Signature.Public_key_hash.encoding + in + let string = + Format.sprintf "{Pair 0x%s (Some 0x%s) }" hex_transac hex_pkh + in + let parameters = + Alpha_context.Script.(lazy_expr (expression_from_string string)) + in + (* a transfers to b and unshield some money to src_2 (the pkh) *) + transac_and_sync ~memo_size b parameters 0 src0 dst baker + >>=? fun (b, state) -> + Context.Contract.balance (B b) src1 >>=? fun balance_after_shield -> + let diff = + Int64.sub + (Test_tez.Tez.to_mutez balance_after_shield) + (Test_tez.Tez.to_mutez balance_before_shield) + in + (* The inputs total [total] mutez and 15 of those are transfered in shielded tez *) + assert (Int64.equal diff (Int64.of_int (total - 15))) ; + let list_forge_input = + List.init ~when_negative_length:() 15 (fun i -> + let pos = Int64.of_int (i + 14 + 14) in + let forge_input = + snd + (Tezos_sapling.Forge.Input.get state pos wb.vk + |> WithExceptions.Option.get ~loc:__LOC__) + in + forge_input) + |> function + | Error () -> assert false (* 14 > 0 *) + | Ok list_forge_input -> list_forge_input + in + let addr_a = + snd + @@ Tezos_sapling.Core.Client.Viewing_key.new_address + wa.vk + Tezos_sapling.Core.Client.Viewing_key.default_index + in + let output = Tezos_sapling.Forge.make_output addr_a 15L (Bytes.create 8) in + let hex_transac = + to_hex + (Tezos_sapling.Forge.forge_transaction + ~number_dummy_inputs:2 + ~number_dummy_outputs:2 + list_forge_input + [output] + wb.sk + anti_replay + state) + Tezos_sapling.Core.Client.UTXO.transaction_encoding + in + let string = Format.sprintf "{Pair 0x%s None }" hex_transac in + let parameters = + Alpha_context.Script.(lazy_expr (expression_from_string string)) + in + (* b transfers to a with dummy inputs and outputs *) + transac_and_sync ~memo_size b parameters 0 src0 dst baker + >>=? fun (b, _state) -> + (* Here we fail by doing the same transaction again*) + Incremental.begin_construction b >>=? fun incr -> + let fee = Test_tez.Tez.of_int 10 in + Op.transaction ~fee (B b) src0 dst Test_tez.Tez.zero ~parameters + >>=? fun operation -> + Incremental.add_operation (* TODO make more precise *) + ~expect_failure:(fun _ -> return_unit) + incr + operation + >>=? fun _incr -> return_unit + + let test_push_sapling_state_should_be_forbidden () = + init () + (* Originating a contract to get a sapling_state with ID 0, used in the next contract *) + >>=? + fun (block, baker, src, _) -> + originate_contract "contracts/sapling_contract.tz" "{ }" src block baker + >>=? fun _ -> + (* Originating the next contract should fail *) + originate_contract + "contracts/sapling_push_sapling_state.tz" + "{ }" + src + block + baker + >>= function + | Error + [ + Environment.Ecoproto_error (Script_tc_errors.Ill_typed_contract _); + Environment.Ecoproto_error + (Script_tc_errors.Unexpected_lazy_storage _); + ] -> + return_unit + | _ -> assert false + + let test_use_state_from_other_contract_and_transact () = + (* + Attempt to use a sapling state of a contract A in a contract B + *) + init () (* Originating the contracts *) >>=? fun (block, baker, src, _) -> + let memo_size = 8 in + (* originate_contract "contracts/sapling_contract.tz" "{ }" src block baker + >>=? fun (_shielded_pool_contract_address, block, _anti_replay_shielded_pool) + -> *) + originate_contract + "contracts/sapling_use_existing_state.tz" + "{ }" + src + block + baker + >>=? fun (existing_state_contract_address, block, anti_replay_2) -> + (* we create one shielding transaction and transform it in Micheline to use + it as a parameter + *) + let wa = wallet_gen () in + let (transactions, _total) = + shield + ~memo_size + wa.sk + 1 + wa.vk + (Format.sprintf "(Pair 0x%s 0)") + anti_replay_2 + in + let transaction = + WithExceptions.Option.get ~loc:__LOC__ @@ List.hd transactions + in + let parameters = + Alpha_context.Script.(lazy_expr (expression_from_string transaction)) + in + transac_and_sync + ~memo_size + block + parameters + 0 + src + existing_state_contract_address + baker + >|= function + | Ok _ -> Alcotest.failf "Unexpected operations success" + | Error errs -> + assert ( + List.exists + (function + | Environment.Ecoproto_error + (Tezos_raw_protocol_011_PtHangzH.Script_tc_errors + .Unexpected_forged_value _) -> + true + | _ -> false) + errs) ; + Result.return_unit + + (* In this test we do two transactions in one block and same two in two block. + We check that the sate is the same expect for roots. + The second transaction is possible only if the first one is done. *) + let test_transac_and_block () = + init () >>=? fun (b, baker, src, _) -> + let memo_size = 8 in + originate_contract "contracts/sapling_contract.tz" "{ }" src b baker + >>=? fun (dst, block_start, anti_replay) -> + let {sk; vk} = wallet_gen () in + let hex_transac_1 = hex_shield ~memo_size {sk; vk} anti_replay in + let string_1 = Format.sprintf "{Pair %s None }" hex_transac_1 in + let parameters_1 = + Alpha_context.Script.(lazy_expr (expression_from_string string_1)) + in + transac_and_sync ~memo_size block_start parameters_1 15 src dst baker + >>=? fun (block_1, state) -> + let intermediary_root = Tezos_sapling.Storage.get_root state in + let addr = + snd + @@ Tezos_sapling.Core.Wallet.Viewing_key.(new_address vk default_index) + in + let output = Tezos_sapling.Forge.make_output addr 15L (Bytes.create 8) in + let hex_transac_2 = + "0x" + ^ to_hex + (Tezos_sapling.Forge.forge_transaction + [ + snd + (Tezos_sapling.Forge.Input.get state 0L vk + |> WithExceptions.Option.get ~loc:__LOC__); + ] + [output] + sk + anti_replay + state) + Tezos_sapling.Core.Client.UTXO.transaction_encoding + in + let string_2 = Format.sprintf "{Pair %s None }" hex_transac_2 in + let parameters_2 = + Alpha_context.Script.(lazy_expr (expression_from_string string_2)) + in + transac_and_sync ~memo_size block_1 parameters_2 0 src dst baker + >>=? fun (block_1, state_1) -> + let final_root = Tezos_sapling.Storage.get_root state_1 in + Alpha_services.Contract.single_sapling_get_diff + Block.rpc_ctxt + block_1 + dst + ~offset_commitment:0L + ~offset_nullifier:0L + () + >>=? fun (_root, diff_1) -> + let fee = Test_tez.Tez.of_int 10 in + Test_tez.Tez.(one_mutez *? Int64.of_int 15) >>?= fun amount_tez -> + Op.transaction + ~fee + (B block_start) + src + dst + amount_tez + ~parameters:parameters_1 + >>=? fun operation -> + Incremental.begin_construction block_start >>=? fun incr -> + Incremental.add_operation incr operation >>=? fun incr -> + (* We need to manually get the counter here *) + let ctx = Incremental.alpha_ctxt incr in + let pkh = + Alpha_context.Contract.is_implicit src + |> WithExceptions.Option.get ~loc:__LOC__ + in + Alpha_context.Contract.get_counter ctx pkh >>= wrap >>=? fun counter -> + Op.transaction + ~counter + ~fee + (B block_start) + src + dst + Test_tez.Tez.zero + ~parameters:parameters_2 + >>=? fun operation -> + Incremental.add_operation incr operation >>=? fun incr -> + Incremental.finalize_block incr >>=? fun block_2 -> + Alpha_services.Contract.single_sapling_get_diff + Block.rpc_ctxt + block_2 + dst + ~offset_commitment:0L + ~offset_nullifier:0L + () + >>=? fun (_root, diff_2) -> + (* We check that the same transactions have passed *) + assert (diff_1 = diff_2) ; + let is_root_in block dst root = + Incremental.begin_construction block >>=? fun incr -> + let ctx_2 = Incremental.alpha_ctxt incr in + Alpha_services.Contract.script Block.rpc_ctxt block dst >>=? fun script -> + let ctx_without_gas_2 = Alpha_context.Gas.set_unlimited ctx_2 in + Script_ir_translator.parse_script + ctx_without_gas_2 + ~legacy:true + ~allow_forged_in_storage:true + script + >>= wrap + >>=? fun (Ex_script script, ctxt) -> + Script_ir_translator.get_single_sapling_state + ctxt + script.storage_type + script.storage + |> wrap + >>=? fun (id, _ctx_2) -> + let single_id = WithExceptions.Option.get ~loc:__LOC__ id in + let id = + Lazy_storage_kind.Sapling_state.Id.parse_z + @@ Alpha_context.Sapling.Id.unparse_to_z single_id + in + Raw_context.prepare + block.context + ~level:block.header.shell.level + ~predecessor_timestamp:block.header.shell.timestamp + ~timestamp:block.header.shell.timestamp + ~fitness:block.header.shell.fitness + >>= wrap + >>=? fun raw_ctx -> Sapling_storage.Roots.mem raw_ctx id root >>= wrap + in + (* We check that the second state did not store the root in between + transactions. *) + is_root_in block_2 dst intermediary_root |> assert_false >>=? fun () -> + (* We check that the second state did store the final root. *) + is_root_in block_2 dst final_root |> assert_true >>=? fun () -> + (* We check that the first state did store the final root. *) + is_root_in block_1 dst final_root |> assert_true >>=? fun () -> + (* We check that the first state did store the root in between transactions. *) + is_root_in block_1 dst intermediary_root |> assert_true + + (* In this test we try a contract which creates an empty sapling state on the + fly. It then applies a list of transactions, checks they are correct and + drops the result. We make several shields in the same list (since the state + is drop). *) + let test_drop () = + init () >>=? fun (b, baker, src, _) -> + originate_contract "contracts/sapling_contract_drop.tz" "Unit" src b baker + >>=? fun (dst, b, anti_replay) -> + let {sk; vk} = wallet_gen () in + let (list_transac, _total) = + shield ~memo_size:8 sk 4 vk (Format.sprintf "0x%s") anti_replay + in + let parameters = parameters_of_list list_transac in + Op.transaction + ~fee:(Test_tez.Tez.of_int 10) + (B b) + src + dst + Test_tez.Tez.zero + ~parameters + >>=? fun operation -> + next_block b operation >>=? fun _b -> return_unit + + (* We use a contrac with two states. Its parameter is two transactions and a + bool. The two transactions are tested valid against the two states, but + only one state according to the bool is updated. + We do two transactions shielding to different keys in the two states. + At each transactions both are applied but only state is updated. + We then check that the first state is updated in the correct way. *) + let test_double () = + init () >>=? fun (b, baker, src, _) -> + let memo_size = 8 in + originate_contract + "contracts/sapling_contract_double.tz" + "(Pair { } { })" + src + b + baker + >>=? fun (dst, b, anti_replay) -> + let wa = wallet_gen () in + let hex_transac_1 = hex_shield ~memo_size wa anti_replay in + let wb = wallet_gen () in + let hex_transac_2 = hex_shield ~memo_size wb anti_replay in + let str_1 = + "(Pair True (Pair " ^ hex_transac_1 ^ " " ^ hex_transac_2 ^ "))" + in + let str_2 = + "(Pair False (Pair " ^ hex_transac_2 ^ " " ^ hex_transac_1 ^ "))" + in + (* transac 1 is applied to state_1*) + let parameters_1 = + Alpha_context.Script.(lazy_expr (expression_from_string str_1)) + in + (* tranasc_2 is applied to state_2*) + let parameters_2 = + Alpha_context.Script.(lazy_expr (expression_from_string str_2)) + in + let fee = Test_tez.Tez.of_int 10 in + Op.transaction ~fee (B b) src dst Test_tez.Tez.zero ~parameters:parameters_1 + >>=? fun operation -> + next_block b operation >>=? fun b -> + Op.transaction ~fee (B b) src dst Test_tez.Tez.zero ~parameters:parameters_2 + >>=? fun operation -> + next_block b operation >>=? fun b -> + Incremental.begin_construction b >>=? fun incr -> + let ctx = Incremental.alpha_ctxt incr in + let ctx_without_gas = Alpha_context.Gas.set_unlimited ctx in + Alpha_services.Contract.storage Block.rpc_ctxt b dst >>=? fun storage -> + let storage_lazy_expr = Alpha_context.Script.lazy_expr storage in + + (let memo_size = memo_size_of_int memo_size in + let open Script_typed_ir in + let state_ty = sapling_state_t ~memo_size ~annot:None in + pair_t (-1) (state_ty, None, None) (state_ty, None, None) ~annot:None) + >>??= fun tytype -> + Script_ir_translator.parse_storage + ctx_without_gas + ~legacy:true + ~allow_forged:true + tytype + ~storage:storage_lazy_expr + >>= wrap + >>=? fun ((state_1, state_2), _ctx) -> + (*Only works when diff is empty*) + let local_state_from_disk disk_state ctx = + let id = + Alpha_context.Sapling.(disk_state.id) + |> WithExceptions.Option.get ~loc:__LOC__ + in + Alpha_context.Sapling.get_diff + ctx + id + ~offset_commitment:0L + ~offset_nullifier:0L + () + >>= wrap + >|=? fun diff -> client_state_of_diff ~memo_size diff + in + local_state_from_disk state_1 ctx >>=? fun state_1 -> + local_state_from_disk state_2 ctx >|=? fun state_2 -> + (* we check that first state contains 15 to addr_1 but not 15 to addr_2*) + assert (Option.is_some @@ Tezos_sapling.Forge.Input.get state_1 0L wa.vk) ; + assert (Option.is_some @@ Tezos_sapling.Forge.Input.get state_2 0L wa.vk) ; + assert (Option.is_none @@ Tezos_sapling.Forge.Input.get state_1 0L wb.vk) ; + assert (Option.is_none @@ Tezos_sapling.Forge.Input.get state_2 0L wb.vk) + + let test_state_as_arg () = + init () >>=? fun (b, baker, src, _) -> + originate_contract + "contracts/sapling_contract_state_as_arg.tz" + "None" + src + b + baker + >>=? fun (dst, b, anti_replay) -> + originate_contract "contracts/sapling_contract_send.tz" "Unit" src b baker + >>=? fun (dst_2, b, anti_replay_2) -> + let w = wallet_gen () in + let hex_transac_1 = hex_shield ~memo_size:8 w anti_replay in + let string = "Left " ^ hex_transac_1 in + let parameters = + Alpha_context.Script.(lazy_expr (expression_from_string string)) + in + let fee = Test_tez.Tez.of_int 10 in + Op.transaction ~fee (B b) src dst Test_tez.Tez.zero ~parameters + >>=? fun operation -> + next_block b operation >>=? fun b -> + let contract = "0x" ^ to_hex dst Alpha_context.Contract.encoding in + let hex_transac_2 = hex_shield ~memo_size:8 w anti_replay_2 in + let string = "(Pair " ^ contract ^ " " ^ hex_transac_2 ^ ")" in + let parameters = + Alpha_context.Script.(lazy_expr (expression_from_string string)) + in + Op.transaction ~fee (B b) src dst_2 Test_tez.Tez.zero ~parameters + >>=? fun operation -> + next_block b operation >>=? fun _b -> return_unit +end + +let tests = + [ + Tztest.tztest + "commitments_add_uncommitted" + `Quick + Raw_context_tests.commitments_add_uncommitted; + Tztest.tztest "nullifier_double" `Quick Raw_context_tests.nullifier_double; + Tztest.tztest "nullifier_test" `Quick Raw_context_tests.nullifier_test; + Tztest.tztest "cm_cipher_test" `Quick Raw_context_tests.cm_cipher_test; + Tztest.tztest + "list_insertion_test" + `Quick + Raw_context_tests.list_insertion_test; + Tztest.tztest "root" `Quick Raw_context_tests.root_test; + Tztest.tztest + "test_get_memo_size" + `Quick + Raw_context_tests.test_get_memo_size; + Tztest.tztest "test_verify_memo" `Quick Alpha_context_tests.test_verify_memo; + Tztest.tztest + "test_bench_phases" + `Slow + Alpha_context_tests.test_bench_phases; + Tztest.tztest + "test_bench_fold_over_same_token" + `Slow + Alpha_context_tests.test_bench_fold_over_same_token; + Tztest.tztest + "test_double_spend_same_input" + `Quick + Alpha_context_tests.test_double_spend_same_input; + Tztest.tztest + "test_verifyupdate_one_transaction" + `Quick + Alpha_context_tests.test_verifyupdate_one_transaction; + Tztest.tztest + "test_verifyupdate_two_transactions" + `Quick + Alpha_context_tests.test_verifyupdate_two_transactions; + Tztest.tztest "test_shielded_tez" `Quick Interpreter_tests.test_shielded_tez; + Tztest.tztest + "test use state from other contract and transact" + `Quick + Interpreter_tests.test_use_state_from_other_contract_and_transact; + Tztest.tztest + "Instruction PUSH sapling_state 0 should be forbidden" + `Quick + Interpreter_tests.test_push_sapling_state_should_be_forbidden; + Tztest.tztest + "test_transac_and_block" + `Quick + Interpreter_tests.test_transac_and_block; + Tztest.tztest "test_drop" `Quick Interpreter_tests.test_drop; + Tztest.tztest "test_double" `Quick Interpreter_tests.test_double; + Tztest.tztest "test_state_as_arg" `Quick Interpreter_tests.test_state_as_arg; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_saturation.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_saturation.ml new file mode 100644 index 000000000000..9d2da374b9d5 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_saturation.ml @@ -0,0 +1,217 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (saturated arithmetic) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe \ + -- test "^saturation arithmetic$" + Subject: The gas is represented using saturated arithmetic. + These unit tests check that saturated arithmetic operations + are correctly implemented. +*) + +open Protocol + +let valid (z : _ Saturation_repr.t) = + let x = z |> Saturation_repr.to_int in + x >= 0 && x < max_int + +exception Saturating_test_error of string + +let err x = Exn (Saturating_test_error x) + +let small_enough (z : _ Saturation_repr.t) = + Saturation_repr.(Compare.Int.((z |> to_int) land 0x7fffffff80000000 = 0)) + +let ok_int x = + match Saturation_repr.of_int_opt x with None -> assert false | Some x -> x + +let n = ok_int 123123 + +let m = ok_int 377337 + +let add () = + Saturation_repr.( + fail_unless + (add saturated (ok_int 1) = saturated) + (err "saturated + 1 <> saturated") + >>=? fun () -> + fail_unless (add zero n = n) (err "zero + n <> n") >>=? fun () -> + fail_unless (add n zero = n) (err "n + zero <> n") >>=? fun () -> + let r = add n m in + fail_unless + (valid r && r = ok_int ((n |> to_int) + (m |> to_int))) + (err "add does not behave like + on small numbers.")) + +let sub () = + Saturation_repr.( + fail_unless (sub zero n = zero) (err "zero - n <> zero") >>=? fun () -> + let n = max n m and m = min n m in + let r = sub n m in + fail_unless + (valid r && r = ok_int ((n |> to_int) - (m |> to_int))) + (err "sub does not behave like - on small numbers.")) + +let mul_safe_of_int x = + Saturation_repr.( + match mul_safe (ok_int x) with Some x -> x | None -> assert false) + +let n' = mul_safe_of_int 1000 + +let m' = mul_safe_of_int 10000 + +let mul_fast () = + Saturation_repr.( + fail_unless (mul_fast zero n' = zero) (err "mul_fast zero x <> zero") + >>=? fun () -> + fail_unless (mul_fast n' zero = zero) (err "mul_fast x zero <> zero") + >>=? fun () -> + let r = mul_fast n' m' in + fail_unless + (valid r && r = ok_int ((n' |> to_int) * (m' |> to_int))) + (err "mul_fast does not behave like * on small numbers.")) + +let scale_fast () = + Saturation_repr.( + fail_unless (scale_fast zero n = zero) (err "scale_fast zero x <> zero") + >>=? fun () -> + fail_unless (scale_fast n' zero = zero) (err "scale_fast x zero <> zero") + >>=? fun () -> + fail_unless + (scale_fast n' saturated = saturated) + (err "scale_fast x saturated <> saturated") + >>=? fun () -> + let r = scale_fast n' m in + fail_unless + (valid r && r = ok_int ((n' |> to_int) * (m |> to_int))) + (err "mul_fast does not behave like * on small numbers.")) + +let mul () = + Saturation_repr.( + fail_unless + (mul saturated saturated = saturated) + (err "saturated * saturated <> saturated") + >>=? fun () -> + fail_unless (mul zero saturated = zero) (err "zero * saturated <> zero") + >>=? fun () -> + fail_unless (mul saturated zero = zero) (err "saturated * zero <> zero") + >>=? fun () -> + let max_squared = ok_int (1 lsl 31) in + let r = mul max_squared max_squared in + fail_unless (r = saturated) (err "2 ^ 31 * 2 ^ 31 should be saturated") + >>=? fun () -> + let safe_squared = ok_int ((1 lsl 31) - 1) in + let r = mul safe_squared safe_squared in + fail_unless + (valid r && r <> saturated) + (err "(2 ^ 31 - 1) * (2 ^ 31 - 1) should not be saturated") + >>=? fun () -> + let r = mul n m in + fail_unless + (valid r && r = ok_int ((n |> to_int) * (m |> to_int))) + (err "mul does not behave like * on small numbers.")) + +let shift_left () = + Saturation_repr.( + let must_saturate flag (k, v) = + fail_unless + (Bool.equal flag (shift_left k v = saturated)) + (err + (Printf.sprintf + "shift_left %d %d %s saturated" + (k |> to_int) + v + (if flag then "<>" else "="))) + in + List.iter_es + (must_saturate true) + [(saturated, 1); (shift_right saturated 1, 2); (ok_int 1, 62)] + >>=? fun () -> + List.iter_es + (must_saturate false) + [ + (ok_int 1, 0); + (ok_int 1, 31); + (ok_int 1, 61); + (ok_int 0, 99); + (ok_int ((1 lsl 62) - 2), 0); + ]) + +let of_z_opt () = + fail_unless + (Saturation_repr.(of_z_opt (Z.succ (Z.of_int max_int))) = None) + (err + "of_z_opt should saturate when given a z integer greater than max_int.") + >>=? fun () -> + fail_unless + (Saturation_repr.(of_z_opt (Z.pred Z.zero)) = None) + (err "of_z_opt should fail on a z negative integer.") + >>=? fun () -> + fail_unless + (Saturation_repr.(of_z_opt (Z.of_int min_int)) = None) + (err "of_z_opt should fail on a z negative integer.") + +let encoding encoder () = + let check_encode_decode x = + Data_encoding.Binary.( + match to_bytes encoder (ok_int x) with + | Error _ -> + fail (err (Printf.sprintf "Problem during binary encoding of %d" x)) + | Ok bytes -> ( + match of_bytes encoder bytes with + | Error _ -> + fail + (err (Printf.sprintf "Problem during binary decoding of %d" x)) + | Ok x' -> + fail_unless + (ok_int x = x') + (err + (Printf.sprintf + "decode (encode %d) = %d <> %d" + x + (x' :> int) + x)))) + in + join_ep (List.map check_encode_decode [0; 7373737373; max_int - 1]) + +let tests = + [ + Tztest.tztest "Addition" `Quick add; + Tztest.tztest "Subtraction" `Quick sub; + Tztest.tztest "Multiplication" `Quick mul; + Tztest.tztest "Multiplication (fast version)" `Quick mul_fast; + Tztest.tztest "Shift left" `Quick shift_left; + Tztest.tztest "Scale fast" `Quick scale_fast; + Tztest.tztest "Conversion from Z" `Quick of_z_opt; + Tztest.tztest + "Encoding through z" + `Quick + (encoding Saturation_repr.z_encoding); + Tztest.tztest + "Encoding through n" + `Quick + (encoding Saturation_repr.n_encoding); + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_script_comparison.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_script_comparison.ml new file mode 100644 index 000000000000..ca96818a119e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_script_comparison.ml @@ -0,0 +1,365 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Script_comparison + Invocation: dune build @src/proto_alpha/lib_protocol/runtest_test_script_comparison + Subject: PBT of the Script_comparable.compare_comparable function. +*) + +open Protocol +open Alpha_context +open Script_typed_ir +open Lib_test.Qcheck_helpers + +(* Reference implementation *) + +let normalize_compare c = + let open Compare.Int in + if c > 0 then 1 else if c < 0 then -1 else 0 + +(* This reference implementation of the Michelson comparison function is a + simplified version of the Script_ir_translator.compare_comparable function + that was used in the Florence protocol, before a refactoring broke it in + Granada. *) +let rec reference_compare_comparable : type a. a comparable_ty -> a -> a -> int + = + fun ty x y -> + match (ty, x, y) with + | (Unit_key _, (), ()) -> 0 + | (Never_key _, _, _) -> . + | (Signature_key _, x, y) -> normalize_compare @@ Signature.compare x y + | (String_key _, x, y) -> normalize_compare @@ Script_string.compare x y + | (Bool_key _, x, y) -> normalize_compare @@ Compare.Bool.compare x y + | (Mutez_key _, x, y) -> normalize_compare @@ Tez.compare x y + | (Key_hash_key _, x, y) -> + normalize_compare @@ Signature.Public_key_hash.compare x y + | (Key_key _, x, y) -> normalize_compare @@ Signature.Public_key.compare x y + | (Int_key _, x, y) -> normalize_compare @@ Script_int.compare x y + | (Nat_key _, x, y) -> normalize_compare @@ Script_int.compare x y + | (Timestamp_key _, x, y) -> normalize_compare @@ Script_timestamp.compare x y + | (Address_key _, x, y) -> + normalize_compare @@ Script_comparable.compare_address x y + | (Bytes_key _, x, y) -> normalize_compare @@ Compare.Bytes.compare x y + | (Chain_id_key _, x, y) -> normalize_compare @@ Chain_id.compare x y + | (Pair_key ((tl, _), (tr, _), _), (lx, rx), (ly, ry)) -> + let cl = reference_compare_comparable tl lx ly in + if Compare.Int.(cl = 0) then reference_compare_comparable tr rx ry else cl + | (Union_key ((tl, _), _, _), L x, L y) -> reference_compare_comparable tl x y + | (Union_key _, L _, R _) -> -1 + | (Union_key _, R _, L _) -> 1 + | (Union_key (_, (tr, _), _), R x, R y) -> reference_compare_comparable tr x y + | (Option_key _, None, None) -> 0 + | (Option_key _, None, Some _) -> -1 + | (Option_key _, Some _, None) -> 1 + | (Option_key (t, _), Some x, Some y) -> reference_compare_comparable t x y + +(* Generation of one to three values of the same comparable type. *) + +type ex_comparable_data = + | Ex_comparable_data : 'a comparable_ty * 'a -> ex_comparable_data + +type ex_comparable_data_2 = + | Ex_comparable_data_2 : 'a comparable_ty * 'a * 'a -> ex_comparable_data_2 + +type ex_comparable_data_3 = + | Ex_comparable_data_3 : + 'a comparable_ty * 'a * 'a * 'a + -> ex_comparable_data_3 + +(* We use the Michelson samplers from lib_benchmark and turn them into QCheck + generators *) +module Parameters : Michelson_samplers_parameters.S = struct + let atom_size_range : Tezos_benchmark.Base_samplers.range = + {min = 0; max = 10} + + let type_size : Tezos_benchmark.Base_samplers.range = {min = 1; max = 1000} + + let other_size : Tezos_benchmark.Base_samplers.range = {min = 0; max = 100} + + let parameters : Michelson_samplers_parameters.t = + { + int_size = atom_size_range; + string_size = atom_size_range; + bytes_size = atom_size_range; + stack_size = other_size; + type_size; + list_size = other_size; + set_size = other_size; + map_size = other_size; + } + + let size = 1000 + + let algo = `Default +end + +module Samplers : Michelson_samplers.S = Michelson_samplers.Make (Parameters) + +let ex_comparable_data_sampler : + ex_comparable_data Tezos_benchmark.Base_samplers.sampler = + fun random_state -> + let size = + Tezos_benchmark.Base_samplers.sample_in_interval + ~range:{min = 1; max = 20} + random_state + in + let (Ex_comparable_ty ty) = + Samplers.Random_type.m_comparable_type ~size random_state + in + let x = Samplers.Random_value.comparable ty random_state in + Ex_comparable_data (ty, x) + +let ex_comparable_data_2_sampler : + ex_comparable_data_2 Tezos_benchmark.Base_samplers.sampler = + fun random_state -> + let size = + Tezos_benchmark.Base_samplers.sample_in_interval + ~range:{min = 1; max = 20} + random_state + in + let (Ex_comparable_ty ty) = + Samplers.Random_type.m_comparable_type ~size random_state + in + let x = Samplers.Random_value.comparable ty random_state in + let y = Samplers.Random_value.comparable ty random_state in + Ex_comparable_data_2 (ty, x, y) + +let ex_comparable_data_3_sampler : + ex_comparable_data_3 Tezos_benchmark.Base_samplers.sampler = + fun random_state -> + let size = + Tezos_benchmark.Base_samplers.sample_in_interval + ~range:{min = 1; max = 20} + random_state + in + let (Ex_comparable_ty ty) = + Samplers.Random_type.m_comparable_type ~size random_state + in + let x = Samplers.Random_value.comparable ty random_state in + let y = Samplers.Random_value.comparable ty random_state in + let z = Samplers.Random_value.comparable ty random_state in + Ex_comparable_data_3 (ty, x, y, z) + +let comparable_data_generator : ex_comparable_data QCheck.Gen.t = + ex_comparable_data_sampler + +let comparable_data_2_generator : ex_comparable_data_2 QCheck.Gen.t = + ex_comparable_data_2_sampler + +let comparable_data_3_generator : ex_comparable_data_3 QCheck.Gen.t = + ex_comparable_data_3_sampler + +let comparable_data_arbitrary : ex_comparable_data QCheck.arbitrary = + QCheck.make comparable_data_generator + +let comparable_data_2_arbitrary : ex_comparable_data_2 QCheck.arbitrary = + QCheck.make comparable_data_2_generator + +let comparable_data_3_arbitrary : ex_comparable_data_3 QCheck.arbitrary = + QCheck.make comparable_data_3_generator + +(* We need a context because packing (used in one of the tests) and unparsing + (used for pretty-printing error messages) Michelson data are carbonated + operations. But since we don't care about gas consumption here we use the + same value of type context everywhere instead of threading it through the + error monad. *) + +let assert_ok = function Ok x -> x | Error _ -> assert false + +let assert_return x = assert_ok (Lwt_main.run x) + +let ctxt = + assert_return + ( Context.init 3 >>=? fun (b, _cs) -> + Incremental.begin_construction b >>=? fun v -> + return (Incremental.alpha_ctxt v) ) + +let unparse_comparable_ty ty = + Micheline.strip_locations + (fst + (assert_ok + Script_ir_translator.(unparse_ty ctxt (ty_of_comparable_ty ty)))) + +let unparse_comparable_data ty x = + Micheline.strip_locations + (fst + (assert_return + Script_ir_translator.( + unparse_data ctxt Readable (ty_of_comparable_ty ty) x))) + +let pack_comparable_data ty x = + fst + (assert_return + Script_ir_translator.(pack_data ctxt (ty_of_comparable_ty ty) x)) + +let unpack_comparable_data ty bytes = + let ty = Script_ir_translator.ty_of_comparable_ty ty in + fst (assert_return (Script_interpreter_defs.unpack ctxt ~ty ~bytes)) + +let pp_comparable_ty fmt ty = + Michelson_v1_printer.print_expr fmt (unparse_comparable_ty ty) + +let pp_comparable_data ty fmt x = + Michelson_v1_printer.print_expr fmt (unparse_comparable_data ty x) + +let pp ty x y pp_c fmt c = + Format.fprintf + fmt + "Compare(ty=%a, %a, %a) = %a" + pp_comparable_ty + ty + (pp_comparable_data ty) + x + (pp_comparable_data ty) + y + pp_c + c + +let compare_through_pack ty x y = + Bytes.compare (pack_comparable_data ty x) (pack_comparable_data ty y) = 0 + +let qcheck_compare_comparable ~expected ty x y = + qcheck_eq + ~pp:(pp ty x y Format.pp_print_int) + expected + (Script_comparable.compare_comparable ty x y) + +let qcheck_compare_comparable_eq ~expected ty x y = + qcheck_eq + ~pp:(pp ty x y Format.pp_print_bool) + expected + (Script_comparable.compare_comparable ty x y = 0) + +(* Test. + * Tests that compare_comparable returns the same values than the reference + * implementation. + *) +let test_compatible_with_reference = + QCheck.Test.make + ~name:"compatible_with_reference" + comparable_data_2_arbitrary + (fun (Ex_comparable_data_2 (ty, x, y)) -> + qcheck_compare_comparable + ~expected:(reference_compare_comparable ty x y) + ty + x + y) + +(* Test. + * Tests that compare_comparable returns 0 iff packing then comparing the + * resulting bytes returns 0. + *) +let test_compatible_with_packing = + QCheck.Test.make + ~name:"compatible_with_packing" + comparable_data_2_arbitrary + (fun (Ex_comparable_data_2 (ty, x, y)) -> + qcheck_compare_comparable_eq + ~expected:(compare_through_pack ty x y) + ty + x + y) + +(* Test. + * Tests that compare_comparable is reflexive. + *) +let test_reflexivity = + QCheck.Test.make + ~name:"reflexivity" + comparable_data_arbitrary + (fun (Ex_comparable_data (ty, x)) -> + qcheck_compare_comparable ~expected:0 ty x x) + +(* Test. + * Tests that compare_comparable is symmetric. + *) +let test_symmetry = + QCheck.Test.make + ~name:"symmetry" + comparable_data_2_arbitrary + (fun (Ex_comparable_data_2 (ty, x, y)) -> + qcheck_compare_comparable + ~expected:(-Script_comparable.compare_comparable ty x y) + ty + y + x) + +(* Test. + * Tests that compare_comparable is transitive. + *) +let test_transitivity = + QCheck.Test.make + ~name:"transitivity" + comparable_data_3_arbitrary + (fun (Ex_comparable_data_3 (ty, x, y, z)) -> + let cxy = Script_comparable.compare_comparable ty x y in + let cyz = Script_comparable.compare_comparable ty y z in + match (cxy, cyz) with + | (0, n) | (n, 0) -> qcheck_compare_comparable ~expected:n ty x z + | (-1, -1) -> qcheck_compare_comparable ~expected:(-1) ty x z + | (1, 1) -> qcheck_compare_comparable ~expected:1 ty x z + | _ -> QCheck.assume_fail ()) + +(* Test. + * Tests the round-trip property for PACK and UNPACK (modulo compare_comparable). + *) +let test_pack_unpack = + QCheck.Test.make + ~count: + 100_000 + (* We run this test on many more cases than the default (100) because this + is a very important property. Packing and then unpacking happens each + time data is sent from a contract to another and also each time storage + is saved at the end of a smart contract call and restored at the next + call of the same contract. Also, injectivity of packing (which is a + direct consequence of this) is an important property for big maps + (because the keys are packed and then hashed). *) + ~name:"pack_unpack" + comparable_data_arbitrary + (fun (Ex_comparable_data (ty, x)) -> + let oty = + match option_key (-1) ty ~annot:None with + | Ok ty -> ty + | Error _ -> assert false + in + qcheck_eq + ~cmp:(Script_comparable.compare_comparable oty) + ~pp:(pp_comparable_data oty) + (Some x) + (unpack_comparable_data ty (pack_comparable_data ty x))) + +let tests = + Alcotest.run + "Script_comparison" + [ + ("compatible_with_reference", qcheck_wrap [test_compatible_with_reference]); + ("compatible_with_packing", qcheck_wrap [test_compatible_with_packing]); + ("reflexivity", qcheck_wrap [test_reflexivity]); + ("symmetry", qcheck_wrap [test_symmetry]); + ("transitivity", qcheck_wrap [test_transitivity]); + ("pack_unpack", qcheck_wrap [test_pack_unpack]); + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_script_typed_ir_size.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_script_typed_ir_size.ml new file mode 100644 index 000000000000..26ab34703bd2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_script_typed_ir_size.ml @@ -0,0 +1,429 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (script typed IR size) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe \ + -- test "^script typed ir size$" + Subject: Script_typed_ir computes good approximation of values' sizes +*) + +open Protocol + +(* + Helpers + ------- +*) + +exception Script_typed_ir_test_error of string + +let err x = Exn (Script_typed_ir_test_error x) + +let wrap e = Lwt.return (Environment.wrap_tzresult e) + +let iter_n_es n f = + let rec aux k = if k = n then return () else f k >>=? fun () -> aux (k + 1) in + aux 0 + +(* + + We use Snoop's samplers to test that our good approximation of + Michelson values' sizes is indeed a good approximation and that it + is never too far from the reality. + + Architecture: + ------------- + + - module [Samplers] provides samplers for values of type [ty], + [comparable_ty], [code] and any value whose types is dynamically + representable with a [ty]. + + - module [Tests] defines the actual testing procedures and reports + error using [Printers]. + +*) + +module Samplers = struct + let parameters = + let open Michelson_samplers_parameters in + let size = {Tezos_benchmark.Base_samplers.min = 4; max = 32} in + { + int_size = size; + string_size = size; + bytes_size = size; + stack_size = size; + type_size = size; + list_size = size; + set_size = size; + map_size = size; + } + + include Michelson_samplers.Make (struct + let parameters = parameters + + let size = 10 + + let algo = `Default + end) + + let random_state = Random.State.make [|37; 73; 17; 71; 42|] + + let sample_ty () = Random_type.m_type ~size:10 random_state + + let sample_cty () = Random_type.m_comparable_type ~size:10 random_state + + let sample_value ty = Random_value.value ty random_state + + module Full = Michelson_samplers_base.Make_full (struct + let parameters = parameters + + let algo = `Default + + let size = 16 + end) + + module Gen = Generators.Code (struct + module Samplers = Full + + let rng_state = random_state + + let target_size = 500 + + let verbosity = `Silent + end) + + let generator = Gen.generator ~burn_in:(500 * 7) + + let base_type_to_michelson_type (typ : Type.Base.t) = + let typ = Mikhailsky.map_var (fun _ -> Mikhailsky.unit_ty) typ in + Mikhailsky.to_michelson typ + + (* Convert a Mikhailsky stack to a list of Micheline-encoded types *) + let rec stack_type_to_michelson_type_list (typ : Type.Stack.t) = + let node = typ.node in + match node with + | Type.Stack.Stack_var_t _ -> + Stdlib.failwith "stack_type_to_michelson_type_list: bug found" + | Type.Stack.Empty_t -> [] + | Type.Stack.Item_t (ty, tl) -> + base_type_to_michelson_type ty :: stack_type_to_michelson_type_list tl + + (* Convert a Micheline-encoded type to its internal GADT format. *) + let michelson_type_to_ex_ty (typ : Protocol.Alpha_context.Script.expr) + (ctxt : Protocol.Alpha_context.t) = + Protocol.Script_ir_translator.parse_ty + ctxt + ~legacy:false + ~allow_lazy_storage:false + ~allow_operation:false + ~allow_contract:false + ~allow_ticket:false + (Micheline.root typ) + |> Protocol.Environment.wrap_tzresult + |> function + | Ok t -> t + | Error errs -> + Format.eprintf "%a@." pp_print_error errs ; + raise (Failure "Test_helpers.michelson_type_to_ex_ty: error") + + let base_type_to_ex_ty ty = + michelson_type_to_ex_ty (base_type_to_michelson_type ty) + + (* Convert a list of Micheline-encoded Michelson types to the + internal GADT format. *) + let rec michelson_type_list_to_ex_stack_ty + (stack_ty : Protocol.Alpha_context.Script.expr list) ctxt = + let open Protocol.Script_ir_translator in + let open Protocol.Script_typed_ir in + match stack_ty with + | [] -> (Ex_stack_ty Bot_t, ctxt) + | hd :: tl -> ( + let (ex_ty, ctxt) = michelson_type_to_ex_ty hd ctxt in + match ex_ty with + | Ex_ty ty -> ( + let (ex_stack_ty, ctxt) = + michelson_type_list_to_ex_stack_ty tl ctxt + in + match ex_stack_ty with + | Ex_stack_ty tl -> (Ex_stack_ty (Item_t (ty, tl, None)), ctxt))) + + type exdescr = + | Ex_descr : ('a, 's, 'r, 'f) Script_ir_translator.descr -> exdescr + + let sample_ir_code () = + let (sample, (bef, _)) = StaTz.Stats.sample_gen generator in + let accounts = Account.generate_accounts 1 in + Block.alpha_context accounts >>=? fun ctxt -> + let code = Micheline.root sample in + let stack = stack_type_to_michelson_type_list bef in + let (Ex_stack_ty bef, _) = michelson_type_list_to_ex_stack_ty stack ctxt in + Script_ir_translator.(parse_instr Lambda ctxt ~legacy:true code bef) + >>= wrap + >>=? fun (ir_code, _) -> + match ir_code with + | Script_ir_translator.Typed ir_code -> return (sample, Ex_descr ir_code) + | _ -> assert false +end + +module Printers = struct + let string_of_something f = + Lwt_main.run + (let accounts = Account.generate_accounts 1 in + Block.alpha_context accounts >>=? fun ctxt -> + f ctxt >>= wrap >>=? fun node -> + let printable = + Micheline_printer.printable + Protocol.Michelson_v1_primitives.string_of_prim + node + in + let b = Buffer.create 13 in + let fmt = Format.formatter_of_buffer b in + Format.fprintf fmt "@[%a@]@." Micheline_printer.print_expr printable ; + return @@ Buffer.contents b) + |> function + | Ok s -> s + | Error (errs : tztrace) -> + Format.eprintf "@[Error: %a@]" pp_print_error errs ; + exit 1 + + let string_of_value : type a. a Script_typed_ir.ty -> a -> string = + fun ty v -> + string_of_something @@ fun ctxt -> + Script_ir_translator.( + unparse_data ctxt Readable ty v >>=? fun (node, _) -> + return @@ Micheline.strip_locations node) + + let string_of_ty ty = + string_of_something @@ fun ctxt -> + Lwt.return + @@ Script_ir_translator.( + unparse_ty ctxt ty >>? fun (node, _) -> + Ok (Micheline.strip_locations node)) + + let string_of_code code = string_of_something @@ fun _ -> return code + + let string_of_comparable_ty cty = + string_of_ty (Script_ir_translator.ty_of_comparable_ty cty) +end + +module Tests = struct + let footprint v = 8 * Obj.(reachable_words (repr v)) + + let stats = Stdlib.Hashtbl.create 13 + + let remember what vsize rsize = Stdlib.Hashtbl.add stats what (vsize, rsize) + + let check_good_approximation kind ratio what vsize x = + let rsize = footprint x in + let vsize = Saturation_repr.to_int vsize in + remember kind vsize rsize ; + fail_unless + (rsize = 0 || (vsize >= rsize / ratio && vsize <= rsize * ratio)) + (err + (Printf.sprintf + "Computed size for %s is not a good approximation (%d ~/~ %d)" + what + vsize + rsize)) + + let check_in_range what w (v, error) = + let lower_bound = v -. error and upper_bound = v +. error in + fail_unless + (lower_bound <= w && w <= upper_bound) + (err + (Printf.sprintf + "For %s: %f not in [%f; %f]" + what + w + lower_bound + upper_bound)) + + let check_stats what ~expected_mean ~expected_stddev ~expected_ratios = + let entries = Stdlib.Hashtbl.find_all stats what in + let nentries = float_of_int @@ List.length entries in + let ratios = + List.map + (fun (vsize, rsize) -> + (1. +. float_of_int vsize) /. (1. +. float_of_int rsize)) + entries + in + let sum = List.fold_left (fun accu r -> accu +. r) 0. ratios in + let mean = sum /. nentries in + let sqr x = x *. x in + let stddev = + sqrt + (List.fold_left (fun accu r -> accu +. sqr (r -. mean)) 0. ratios + /. nentries) + in + let entries_min = List.fold_left min max_float ratios in + let entries_max = List.fold_left max min_float ratios in + check_in_range (what ^ ":mean") mean expected_mean >>=? fun () -> + check_in_range (what ^ ":stddev") stddev expected_stddev >>=? fun () -> + check_in_range (what ^ ":min") entries_min expected_ratios >>=? fun () -> + check_in_range (what ^ ":max") entries_max expected_ratios + + let ty_size nsamples = + iter_n_es nsamples @@ fun i -> + match Samplers.sample_ty () with + | Ex_ty ty -> + check_good_approximation + "ty_size" + 2 + (Printf.sprintf "type #%d `%s'" i (Printers.string_of_ty ty)) + (snd (Script_typed_ir_size.ty_size ty)) + ty + | exception _ -> return () + + let check_ty_size_stats () = + check_stats + "ty_size" + ~expected_mean:(1., 0.01) + ~expected_stddev:(0., 0.01) + ~expected_ratios:(1., 0.05) + + let comparable_ty_size nsamples = + iter_n_es nsamples @@ fun i -> + match Samplers.sample_cty () with + | Ex_comparable_ty cty -> + check_good_approximation + "comparable_ty_size" + 2 + (Printf.sprintf + "comparable type #%d `%s'" + i + (Printers.string_of_comparable_ty cty)) + (snd (Script_typed_ir_size.comparable_ty_size cty)) + cty + | exception _ -> return () + + let check_comparable_ty_size_stats () = + check_stats + "comparable_ty_size" + ~expected_mean:(1., 0.01) + ~expected_stddev:(0., 0.01) + ~expected_ratios:(1., 0.05) + + let contains_exceptions ty = + let apply : type a. bool -> a Script_typed_ir.ty -> bool = + fun accu -> function + (* Boxed sets and maps point to a shared first class module. + This is an overapproximation that we want to ignore in + the tests. *) + | Set_t _ | Map_t _ + (* We also want to avoid interferences between testing + [lambda_size] and [value_size]. *) + | Lambda_t _ | Contract_t _ -> + true + | _ -> accu + in + Script_typed_ir.ty_traverse + ty + false + {apply; apply_comparable = (fun accu _ -> accu)} + + let value_size nsamples = + iter_n_es nsamples @@ fun i -> + match Samplers.sample_ty () with + | Ex_ty ty when not (contains_exceptions ty) -> ( + match Samplers.sample_value ty with + | v -> + check_good_approximation + "value_size" + 3 + (Printf.sprintf + "value #%d `%s' of type `%s'" + i + (Printers.string_of_value ty v) + (Printers.string_of_ty ty)) + (snd (Script_typed_ir_size.value_size ty v)) + v + | exception _ -> return ()) + | _ | (exception _) -> return () + + let check_value_size_stats () = + check_stats + "value_size" + ~expected_mean:(1., 0.2) + ~expected_stddev:(0., 0.2) + ~expected_ratios:(1., 3.) + + let lambda_size nsamples = + iter_n_es nsamples @@ fun i -> + Samplers.sample_ir_code () >>=? fun (code, Samplers.Ex_descr icode) -> + let kinstr = (Script_ir_translator.close_descr icode).kinstr in + check_good_approximation + "lambda_size" + 3 + (Printf.sprintf "code #%d `%s'" i (Printers.string_of_code code)) + (snd (Script_typed_ir_size.kinstr_size kinstr)) + kinstr + + let check_lambda_size_stats () = + check_stats + "lambda_size" + ~expected_mean:(1., 0.2) + ~expected_stddev:(0., 0.1) + ~expected_ratios:(1., 0.4) +end + +let tests = + let open Tztest in + Tests. + [ + tztest "lambda size is a good approximation (fast)" `Quick (fun () -> + lambda_size 50); + tztest "ty size is a good approximation (fast)" `Quick (fun () -> + ty_size 50); + tztest "value size is a good approximation (fast)" `Quick (fun () -> + value_size 50); + tztest + "comparable ty size is a good approximation (fast)" + `Quick + (fun () -> comparable_ty_size 50); + tztest "lambda size is a good approximation" `Slow (fun () -> + lambda_size 2000); + tztest "value size is a good approximation" `Slow (fun () -> + value_size 1000); + tztest "ty size is a good approximation" `Slow (fun () -> ty_size 1000); + tztest "comparable ty size is a good approximation" `Slow (fun () -> + comparable_ty_size 1000); + tztest + "statistics about ty size are satisfying" + `Quick + check_ty_size_stats; + tztest + "statistics about comparable ty size are satisfying" + `Quick + check_comparable_ty_size_stats; + tztest + "statistics about value size are satisfying" + `Quick + check_value_size_stats; + tztest + "statistics about lambda size are satisfying" + `Quick + check_lambda_size_stats; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_seed.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_seed.ml new file mode 100644 index 000000000000..da125db73aa7 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_seed.ml @@ -0,0 +1,460 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (seed) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^seed$" + Subject: - seed_nonce_hash included in some blocks + - revelation operation of seed_nonce that should correspond + to each seed_nonce_hash +*) + +open Protocol +open Test_tez + +(** Baking [blocks_per_commitment] blocks without a [seed_nonce_hash] + commitment fails with [Invalid_commitment]. *) +let test_no_commitment () = + Context.init 5 >>=? fun (b, _) -> + Context.get_constants (B b) + >>=? fun {parametric = {blocks_per_commitment; _}; _} -> + let blocks_per_commitment = Int32.to_int blocks_per_commitment in + (* Bake normally until before the commitment *) + Block.bake_n (blocks_per_commitment - 2) b >>=? fun b -> + (* Forge a block with empty commitment and apply it *) + Block.Forge.forge_header b >>=? fun header -> + Block.Forge.set_seed_nonce_hash None header |> Block.Forge.sign_header + >>=? fun header -> + Block.apply header b >>= fun e -> + Assert.proto_error ~loc:__LOC__ e (function + | Apply.Invalid_commitment _ -> true + | _ -> false) + +let baking_reward ctxt (b : Block.t) = + let priority = b.header.protocol_data.contents.priority in + Block.get_endorsing_power b >>=? fun endorsing_power -> + Context.get_baking_reward ctxt ~priority ~endorsing_power + +(** Choose a baker, denote it by id. In the first cycle, make id bake only once. + Check that: + - after id bakes with a commitment the bond is frozen and the reward + allocated + - when id reveals the nonce too early, there's an error + - when id reveals at the right time but the wrong value, there's an error + - when another baker reveals correctly, it receives the tip + - revealing twice produces an error + - after [preserved cycles] a committer that correctly revealed + receives back the bond and the reward. *) +let test_revelation_early_wrong_right_twice () = + let open Assert in + Context.init 5 >>=? fun (b, _) -> + Context.get_constants (B b) >>=? fun csts -> + let bond = csts.parametric.block_security_deposit in + let tip = csts.parametric.seed_nonce_revelation_tip in + let blocks_per_commitment = + Int32.to_int csts.parametric.blocks_per_commitment + in + let preserved_cycles = csts.parametric.preserved_cycles in + (* get the pkh of a baker *) + Block.get_next_baker b >>=? fun (pkh, _, _) -> + let id = Alpha_context.Contract.implicit_contract pkh in + let policy = Block.Excluding [pkh] in + (* bake until commitment, excluding id *) + Block.bake_n ~policy (blocks_per_commitment - 2) b >>=? fun b -> + Context.Contract.balance ~kind:Main (B b) id >>=? fun bal_main -> + Context.Contract.balance ~kind:Deposit (B b) id >>=? fun bal_deposit -> + Context.Contract.balance ~kind:Rewards (B b) id >>=? fun bal_rewards -> + (* the baker [id] will include a seed_nonce commitment *) + Block.bake ~policy:(Block.By_account pkh) b >>=? fun b -> + Context.get_level (B b) >>?= fun level_commitment -> + Context.get_seed_nonce_hash (B b) >>=? fun committed_hash -> + baking_reward (B b) b >>=? fun reward -> + (* test that the bond was frozen and the reward allocated *) + balance_was_debited ~loc:__LOC__ (B b) id bal_main bond >>=? fun () -> + balance_was_credited ~loc:__LOC__ (B b) id ~kind:Deposit bal_deposit bond + >>=? fun () -> + balance_was_credited ~loc:__LOC__ (B b) id ~kind:Rewards bal_rewards reward + >>=? fun () -> + (* test that revealing too early produces an error *) + Op.seed_nonce_revelation + (B b) + level_commitment + (WithExceptions.Option.to_exn ~none:Not_found @@ Nonce.get committed_hash) + |> fun operation -> + Block.bake ~policy ~operation b >>= fun e -> + let expected = function + | Nonce_storage.Too_early_revelation -> true + | _ -> false + in + Assert.proto_error ~loc:__LOC__ e expected >>=? fun () -> + (* finish the cycle excluding the committing baker, id *) + Block.bake_until_cycle_end ~policy b >>=? fun b -> + (* test that revealing at the right time but the wrong value produces an error *) + let (wrong_hash, _) = Nonce.generate () in + Op.seed_nonce_revelation + (B b) + level_commitment + (WithExceptions.Option.to_exn ~none:Not_found @@ Nonce.get wrong_hash) + |> fun operation -> + Block.bake ~operation b >>= fun e -> + Assert.proto_error ~loc:__LOC__ e (function + | Nonce_storage.Inconsistent_nonce -> true + | _ -> false) + >>=? fun () -> + (* reveals correctly *) + Op.seed_nonce_revelation + (B b) + level_commitment + (WithExceptions.Option.to_exn ~none:Not_found @@ Nonce.get committed_hash) + |> fun operation -> + Block.get_next_baker ~policy b >>=? fun (baker_pkh, _, _) -> + let baker = Alpha_context.Contract.implicit_contract baker_pkh in + Context.Contract.balance ~kind:Main (B b) baker >>=? fun baker_bal_main -> + Context.Contract.balance ~kind:Deposit (B b) baker + >>=? fun baker_bal_deposit -> + Context.Contract.balance ~kind:Rewards (B b) baker + >>=? fun baker_bal_rewards -> + (* bake the operation in a block *) + Block.bake ~policy ~operation b >>=? fun b -> + baking_reward (B b) b >>=? fun baker_reward -> + (* test that the baker gets the tip reward *) + balance_was_debited ~loc:__LOC__ (B b) baker ~kind:Main baker_bal_main bond + >>=? fun () -> + balance_was_credited + ~loc:__LOC__ + (B b) + baker + ~kind:Deposit + baker_bal_deposit + bond + >>=? fun () -> + Tez.( +? ) baker_reward tip >>?= fun expected_rewards -> + balance_was_credited + ~loc:__LOC__ + (B b) + baker + ~kind:Rewards + baker_bal_rewards + expected_rewards + >>=? fun () -> + (* test that revealing twice produces an error *) + Op.seed_nonce_revelation + (B b) + level_commitment + (WithExceptions.Option.to_exn ~none:Not_found @@ Nonce.get wrong_hash) + |> fun operation -> + Block.bake ~operation ~policy b >>= fun e -> + Assert.proto_error ~loc:__LOC__ e (function + | Nonce_storage.Previously_revealed_nonce -> true + | _ -> false) + >>=? fun () -> + (* bake [preserved_cycles] cycles excluding [id] *) + List.fold_left_es + (fun b _ -> Block.bake_until_cycle_end ~policy b) + b + (1 -- preserved_cycles) + >>=? fun b -> + (* test that [id] receives back the bond and the reward *) + (* note that in order to have that new_bal = bal_main + reward, + id can only bake once; this is why we exclude id from all other bake ops. *) + balance_was_credited ~loc:__LOC__ (B b) id ~kind:Main bal_main reward + >>=? fun () -> + balance_is ~loc:__LOC__ (B b) id ~kind:Deposit Tez.zero >>=? fun () -> + balance_is ~loc:__LOC__ (B b) id ~kind:Rewards Tez.zero + +(** - a committer at cycle 0, which doesn't reveal at cycle 1, + at the end of the cycle 1 looses the fees and the reward + - revealing too late produces an error. + + The parameters allow to consider different scenarios: + - when [with_fees] is [true] an operation is included to generate non null + fees for the baker before it commits to a nonce hash + - when [with_rewards] is [true] an operation is included to generate a non + null reward for the baker before it commits to a nonce hash + - when [double_step] is true, operations are also included after the baker + commits to a nonce hash (depending on parameters [with_fees] and + [with_rewards]) so that the baker's fees and reward exceed the baker's + commitments. *) +let test_revelation_missing_and_late ~with_fees ~with_rewards ~double_step () = + let open Context in + let open Assert in + Context.init 5 >>=? fun (b, accounts) -> + get_constants (B b) >>=? fun csts -> + let blocks_per_commitment = + Int32.to_int csts.parametric.blocks_per_commitment + in + (* bake until commitment *) + Block.bake_n (blocks_per_commitment - 2) b >>=? fun b -> + let fee = Tez.of_int 7 in + let (contract1, contract2) = + match accounts with c1 :: c2 :: _ -> (c1, c2) | _ -> assert false + in + (if with_fees then + (* Include a transaction so that some fees are allocated to the baker. *) + Op.transaction + ~gas_limit:(Alpha_context.Gas.Arith.integral_of_int_exn 3000) + (B b) + ~fee + contract1 + contract2 + Tez.one + >|=? fun op1 -> [op1] + else return []) + >>=? fun operations -> + Context.get_endorser (B b) >>=? fun (endorser, slots) -> + (if with_rewards then + (* Include an endorsement so that some reward is allocated to the baker. *) + Op.endorsement_with_slot ~delegate:(endorser, slots) (B b) () >|=? fun op2 -> + operations @ [Alpha_context.Operation.pack op2] + else return operations) + >>=? fun operations -> + (* the next baker [id] will include a seed_nonce commitment *) + Block.get_next_baker ~policy:(Block.Excluding [endorser]) b + >>=? fun (pkh, _, _) -> + let id = Alpha_context.Contract.implicit_contract pkh in + (* Ensure next baker has no rewards and fees yet. *) + Context.Contract.balance ~kind:Rewards (B b) id >>=? fun bal_rewards -> + Assert.equal_tez ~loc:__LOC__ bal_rewards Tez.zero >>=? fun () -> + Context.Contract.balance ~kind:Fees (B b) id >>=? fun bal_fees -> + Assert.equal_tez ~loc:__LOC__ bal_fees Tez.zero >>=? fun () -> + (* Bake and include seed nonce commitment *) + Block.bake ~policy:(Block.Excluding [endorser]) ~operations b >>=? fun b -> + (* Extract committed rewards and fees and ensure they are not null. *) + Context.Contract.balance ~kind:Fees (B b) id >>=? fun committed_fees -> + (if with_fees then Assert.not_equal_tez ~loc:__LOC__ committed_fees Tez.zero + else Assert.equal_tez ~loc:__LOC__ committed_fees Tez.zero) + >>=? fun () -> + Context.Contract.balance ~kind:Rewards (B b) id >>=? fun committed_rewards -> + (if with_rewards then + Assert.not_equal_tez ~loc:__LOC__ committed_rewards Tez.zero + else Assert.equal_tez ~loc:__LOC__ committed_rewards Tez.zero) + >>=? fun () -> + (* Extract commitment cycle, commitment level and commitment hash. *) + Block.current_cycle b >>=? fun commitment_cycle -> + Context.get_level (B b) >>?= fun level_commitment -> + Context.get_seed_nonce_hash (B b) >>=? fun committed_hash -> + (* Add more operations so that rewards and/or fees are more than what + has already been committed. *) + (if double_step then + (if with_fees then + (* Include a transaction so that some fees are allocated to the baker. *) + Op.transaction + ~gas_limit:(Alpha_context.Gas.Arith.integral_of_int_exn 3000) + (B b) + ~fee + contract1 + contract2 + Tez.one + >|=? fun op1 -> [op1] + else return []) + >>=? fun operations -> + Context.get_endorser (B b) >>=? fun (endorser, slots) -> + (if with_rewards then + (* Include an endorsement so that some reward is allocated to the baker. *) + Op.endorsement_with_slot ~delegate:(endorser, slots) (B b) () + >|=? fun op2 -> operations @ [Alpha_context.Operation.pack op2] + else return operations) + >>=? fun operations -> + Block.bake ~policy:(Block.By_account pkh) ~operations b + else return b) + >>=? fun b -> + (* Extract balances for the cycle post baking. *) + Context.Contract.balance ~kind:Main (B b) id >>=? fun bal_main -> + Context.Contract.balance ~kind:Deposit (B b) id >>=? fun bal_deposit -> + Context.Contract.balance ~kind:Rewards (B b) id >>=? fun bal_rewards -> + Context.Contract.balance ~kind:Fees (B b) id >>=? fun bal_fees -> + (* Check that the [double_step] parameter is effective. *) + Assert.equal_bool + ~loc:__LOC__ + (bal_rewards > committed_rewards) + (with_rewards && double_step) + >>=? fun () -> + Assert.equal_bool + ~loc:__LOC__ + (bal_fees > committed_fees) + (with_fees && double_step) + >>=? fun () -> + (* finish cycle 0 excluding the committing baker [id] *) + let policy = Block.Excluding [pkh] in + Block.bake_until_cycle_end ~policy b >>=? fun b -> + (* finish cycle 1 excluding the committing baker [id] *) + let blocks_per_cycle = Int32.to_int csts.parametric.blocks_per_cycle in + Block.bake_n_with_all_balance_updates ~policy blocks_per_cycle b + >>=? fun (b, cycle_end_bupds) -> + (* check that punishment balance updates are correct. *) + Assert.equal_bool + ~loc:__LOC__ + (List.mem + ~equal:( = ) + Alpha_context.Receipt. + ( Rewards (pkh, commitment_cycle), + Debited committed_rewards, + Block_application ) + cycle_end_bupds) + with_rewards + >>=? fun () -> + Assert.equal_bool + ~loc:__LOC__ + (List.mem + ~equal:( = ) + Alpha_context.Receipt. + ( Fees (pkh, commitment_cycle), + Debited committed_fees, + Block_application ) + cycle_end_bupds) + with_fees + >>=? fun () -> + (* test that baker [id], which didn't reveal at cycle 1 like it was supposed to, + at the end of the cycle 1 looses the reward and fees but not the bond *) + balance_is ~loc:__LOC__ (B b) id ~kind:Main bal_main >>=? fun () -> + balance_is ~loc:__LOC__ (B b) id ~kind:Deposit bal_deposit >>=? fun () -> + balance_was_debited + ~loc:__LOC__ + (B b) + id + ~kind:Rewards + bal_rewards + committed_rewards + >>=? fun () -> + balance_was_debited ~loc:__LOC__ (B b) id ~kind:Fees bal_fees committed_fees + >>=? fun () -> + (* test that revealing too late (after cycle 1) produces an error *) + Op.seed_nonce_revelation + (B b) + level_commitment + (WithExceptions.Option.to_exn ~none:Not_found @@ Nonce.get committed_hash) + |> fun operation -> + Block.bake ~operation b >>= fun e -> + Assert.proto_error ~loc:__LOC__ e (function + | Nonce_storage.Too_late_revelation -> true + | _ -> false) + +let wrap e = e >|= Environment.wrap_tzresult + +(** Test that the amount reported in balance updates is the actual amount burned + when the committed amount is greater than the available amount. *) +let test_unrevealed () = + let accounts = Account.generate_accounts 1 in + let total_rewards = Tez.of_int 250 in + let total_fees = Tez.of_int 550 in + let committed_rewards = Tez.of_int 1000 in + let committed_fees = Tez.of_int 1500 in + let open Alpha_context in + Block.alpha_context accounts >>=? fun ctxt -> + match accounts with + | [({pkh; _}, _)] -> + (* Freeze rewards and fees for cycle 0. *) + wrap (Delegate.freeze_rewards ctxt pkh total_rewards) >>=? fun ctxt -> + wrap (Delegate.freeze_fees ctxt pkh total_fees) >>=? fun ctxt -> + let unrevealed = + Nonce. + { + nonce_hash = Nonce_hash.zero; + delegate = pkh; + rewards = committed_rewards; + fees = committed_fees; + } + in + (* Simulate an end-of-cycle event. *) + wrap (Delegate.cycle_end ctxt (Cycle.add Cycle.root 1) [unrevealed]) + >>=? fun (_ctxt, bupds, _) -> + (* Check that balance updates indicate what has been burned, + i.e. all fees and rewards. *) + let expected_bupds = + Receipt. + [ + (Fees (pkh, Cycle.root), Debited total_fees, Block_application); + (Rewards (pkh, Cycle.root), Debited total_rewards, Block_application); + ] + in + Assert.equal_bool ~loc:__LOC__ (bupds = expected_bupds) true + | _ -> (* Exactly one account has been generated. *) assert false + +let tests = + [ + Tztest.tztest "no commitment" `Quick test_no_commitment; + Tztest.tztest + "revelation_early_wrong_right_twice" + `Quick + test_revelation_early_wrong_right_twice; + Tztest.tztest + "revelation_missing_and_late no fees and no reward (1/2)" + `Quick + (test_revelation_missing_and_late + ~with_fees:false + ~with_rewards:false + ~double_step:false); + Tztest.tztest + "revelation_missing_and_late no fees and no reward (2/2)" + `Quick + (test_revelation_missing_and_late + ~with_fees:false + ~with_rewards:false + ~double_step:true); + Tztest.tztest + "revelation_missing_and_late no fees and some reward (1/2)" + `Quick + (test_revelation_missing_and_late + ~with_fees:false + ~with_rewards:true + ~double_step:false); + Tztest.tztest + "revelation_missing_and_late no fees and some reward (2/2)" + `Quick + (test_revelation_missing_and_late + ~with_fees:false + ~with_rewards:true + ~double_step:true); + Tztest.tztest + "revelation_missing_and_late some fees and no reward (1/2)" + `Quick + (test_revelation_missing_and_late + ~with_fees:true + ~with_rewards:false + ~double_step:false); + Tztest.tztest + "revelation_missing_and_late some fees and no reward (2/2)" + `Quick + (test_revelation_missing_and_late + ~with_fees:true + ~with_rewards:false + ~double_step:true); + Tztest.tztest + "revelation_missing_and_late some fees and some reward (1/2)" + `Quick + (test_revelation_missing_and_late + ~with_fees:true + ~with_rewards:true + ~double_step:false); + Tztest.tztest + "revelation_missing_and_late some fees and some reward (2/2)" + `Quick + (test_revelation_missing_and_late + ~with_fees:true + ~with_rewards:true + ~double_step:true); + Tztest.tztest "test unrevealed" `Quick test_unrevealed; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_storage.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_storage.ml new file mode 100644 index 000000000000..b65ceab189b2 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_storage.ml @@ -0,0 +1,224 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Context Storage + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test storage + Subject: Test the correctnesss of debug message from storage_functor + *) + +open Protocol +open Storage_functors +open Storage_sigs + +module Int32 = struct + type t = int32 + + let encoding = Data_encoding.int32 + + module Index = struct + type t = int + + let path_length = 1 + + let to_path c l = string_of_int c :: l + + let of_path = function + | [] | _ :: _ :: _ -> None + | [c] -> int_of_string_opt c + + type 'a ipath = 'a * t + + let args = + Storage_description.One + { + rpc_arg = Environment.RPC_arg.int; + encoding = Data_encoding.int31; + compare = Compare.Int.compare; + } + end +end + +module Int64 = struct + type t = int64 + + let encoding = Data_encoding.int64 + + module Index = struct + type t = int64 + + let path_length = 1 + + let to_path c l = Int64.to_string c :: l + + let of_path = function + | [] | _ :: _ :: _ -> None + | [c] -> Int64.of_string_opt c + + type 'a ipath = 'a * t + + let args = + Storage_description.One + { + rpc_arg = Environment.RPC_arg.int64; + encoding = Data_encoding.int64; + compare = Compare.Int64.compare; + } + end +end + +let create_context name : (module Raw_context.T with type t = Raw_context.t) = + (module Make_subcontext (Registered) (Raw_context) + (struct + let name = [name] + end)) + +let create_subcontext name + (module Context : Raw_context.T with type t = Raw_context.t) : + (module Raw_context.T with type t = Raw_context.t) = + (module Make_subcontext (Registered) (Context) + (struct + let name = [name] + end)) + +let create_single_data_storage name + (module Context : Raw_context.T with type t = Raw_context.t) : + (module Single_data_storage with type t = Context.t and type value = Int32.t) + = + (module Make_single_data_storage (Registered) (Context) + (struct + let name = [name] + end) + (Int32)) + +let create_indexed_subcontext_int32 + (module Context : Raw_context.T with type t = Raw_context.t) : + (module Data_set_storage with type t = Raw_context.t) = + (module Make_data_set_storage (Context) (Int32.Index)) + +let create_indexed_subcontext_int64 + (module Context : Raw_context.T with type t = Raw_context.t) : + (module Data_set_storage with type t = Raw_context.t) = + (module Make_data_set_storage (Context) (Int64.Index)) + +let must_failwith f_prog error = + try + let _ = f_prog () in + Alcotest.fail "Unexpected successful result" + with exc -> + if exc = error then Lwt.return_unit + else Alcotest.fail "Unexpected error result" + +(** Test: + + This test check that creating value where value already exists + fails*) +let test_register_single_data () = + let f_prog () = + let context = create_context "context1" in + let _single_data = create_single_data_storage "single_data" context in + create_single_data_storage "single_data" context + in + let error = + Invalid_argument + "Could not register a value at [context1 / single_data] because of an \ + existing Value." + in + must_failwith f_prog error + +(** Test: + + This test check that creating a subcontext where a value already exists + fails*) +let test_register_named_subcontext () = + let f_prog () = + let context = create_context "context2" in + let subcontext = create_subcontext "sub_context" context in + let _single_data = create_single_data_storage "error_register" subcontext in + let subcontext = create_subcontext "error_register" subcontext in + create_single_data_storage "single_data2" subcontext + in + let error = + Invalid_argument + "Could not register a named subcontext at [context2 / sub_context / \ + error_register] because of an existing Value." + in + must_failwith f_prog error + +(** Test: + + This test check that creating a indexed subcontext where a value already + exists fails*) +let test_register_indexed_subcontext () = + let f_prog () = + let context = create_context "context3" in + let _ = create_single_data_storage "single_value" context in + create_indexed_subcontext_int32 context + in + let error = + Invalid_argument + "Could not register an indexed subcontext at [context3] because of an \ + existing \n\ + single_value Value." + in + must_failwith f_prog error + +(** Test: + + This test check that creating a indexed subcontext where an indexed + subcontext already exists fails*) +let test_register_indexed_subcontext_2 () = + let f_prog () = + let context = create_context "context4" in + let _ = create_indexed_subcontext_int32 context in + create_indexed_subcontext_int64 context + in + let error = + Invalid_argument + "An indexed subcontext at [context4] already exists but has a different \ + argument: `int64` <> `int`." + in + must_failwith f_prog error + +let tests = + [ + Alcotest_lwt.test_case + "register single data in existing path" + `Quick + (fun _ -> test_register_single_data); + Alcotest_lwt.test_case + "register named subcontext in existing path" + `Quick + (fun _ -> test_register_named_subcontext); + Alcotest_lwt.test_case + "register indexed subcontext in existing path" + `Quick + (fun _ -> test_register_indexed_subcontext); + Alcotest_lwt.test_case + "register indexed subcontext with existing indexed subcontext" + `Quick + (fun _ -> test_register_indexed_subcontext_2); + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_temp_big_maps.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_temp_big_maps.ml new file mode 100644 index 000000000000..88c0b3fe751a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_temp_big_maps.ml @@ -0,0 +1,100 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (temporary big maps) + Invocation: cd src/proto_alpha/lib_protocol/test && dune exec ./main.exe -- test "^temp big maps$" + Subject: On temporary big maps. +*) + +open Protocol + +let to_raw_context (b : Block.t) = + Raw_context.prepare + b.context + ~level:b.header.shell.level + ~predecessor_timestamp:b.header.shell.timestamp + ~timestamp:b.header.shell.timestamp + ~fitness:b.header.shell.fitness + >|= Environment.wrap_tzresult + +let check_no_dangling_temp_big_map b = + to_raw_context b >>=? fun ctxt -> + Storage.Big_map.fold ctxt ~init:() ~f:(fun id () -> + assert (not (Lazy_storage_kind.Big_map.Id.is_temp id)) ; + Lwt.return_unit) + >>= fun () -> return_unit + +let call_the_contract b ~baker ~src contract param_left param_right = + let fee = Alpha_context.Tez.one in + let amount = Alpha_context.Tez.zero in + let param = Printf.sprintf "Pair (%s) %s" param_left param_right in + let parameters = + Alpha_context.Script.lazy_expr + (Contract_helpers.expression_from_string param) + in + Op.transaction ~fee (B b) src contract amount ~parameters + >>=? fun operation -> + Incremental.begin_construction ~policy:Block.(By_account baker) b + >>=? fun incr -> + Incremental.add_operation incr operation >>=? fun incr -> + Incremental.finalize_block incr + +(** Originates the contract at contracts/temp_big_maps.tz and calls it with + the pair [(param_left, param_right)]. + An action (originating, storing, passing, passing twice) is done on a big + map (either fresh, passed, or stored). + All combinations are exercised. +*) +let test_temp_big_maps_contract param_left param_right () = + Contract_helpers.init () >>=? fun (b, baker, src, _src2) -> + Contract_helpers.originate_contract + "contracts/temp_big_maps.tz" + "{}" + src + b + baker + >>=? fun (contract, b) -> + check_no_dangling_temp_big_map b >>=? fun () -> + call_the_contract b ~baker ~src contract param_left param_right >>=? fun b -> + check_no_dangling_temp_big_map b + +let param_left_values = ["Left True"; "Left False"; "Right {}"] + +let param_right_values = ["-1"; "0"; "1"; "2"] + +let tests = + List.flatten + (List.map + (fun param_left -> + List.map + (fun param_right -> + Tztest.tztest + (Printf.sprintf "temp_big_maps(%s, %s)" param_left param_right) + `Quick + (test_temp_big_maps_contract param_left param_right)) + param_right_values) + param_left_values) diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_tez_repr.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_tez_repr.ml new file mode 100644 index 000000000000..37990a26145b --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_tez_repr.ml @@ -0,0 +1,139 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol Library + Invocation: dune build @src/proto_alpha/lib_protocol/runtest_test_tez_repr + Subject: Operations in Tez_repr +*) + +open Test_tez + +let z_mutez_min = Z.zero + +let z_mutez_max = Z.of_int64 Int64.max_int + +let tez_to_z (tez : Tez.t) : Z.t = Z.of_int64 (Tez.to_mutez tez) + +let z_in_mutez_bounds (z : Z.t) : bool = + Z.Compare.(z_mutez_min <= z && z <= z_mutez_max) + +let compare (c' : Z.t) (c : Tez.t tzresult) : bool = + match (z_in_mutez_bounds @@ c', c) with + | (true, Ok c) -> + Lib_test.Qcheck_helpers.qcheck_eq' + ~pp:Z.pp_print + ~expected:c' + ~actual:(tez_to_z c) + () + | (true, Error _) -> + QCheck.Test.fail_reportf + "@[Results are in Z bounds, but tez operation fails.@]" + | (false, Ok _) -> + QCheck.Test.fail_reportf + "@[Results are not in Z bounds, but tez operation did not fail.@]" + | (false, Error _) -> true + +(* [prop_binop f f' (a, b)] compares the function [f] in Tez with a model + function function [f'] in [Z]. + + If [f' a' b'] falls outside Tez bounds, it is true if [f a b] has + failed. If not, it it is true if [f a b = f' a' b'] where [a'] + (resp. [b']) are [a] (resp. [b']) in [Z]. *) +let prop_binop (f : Tez.t -> Tez.t -> Tez.t tzresult) (f' : Z.t -> Z.t -> Z.t) + ((a, b) : Tez.t * Tez.t) : bool = + compare (f' (tez_to_z a) (tez_to_z b)) (f a b) + +(* [prop_binop64 f f' (a, b)] is as [prop_binop] but for binary operations + where the second operand is of type [int64]. *) +let prop_binop64 (f : Tez.t -> int64 -> Tez.t tzresult) (f' : Z.t -> Z.t -> Z.t) + ((a, b) : Tez.t * int64) : bool = + compare (f' (tez_to_z a) (Z.of_int64 b)) (f a b) + +(** Arbitrary int64 by conversion from int32 *) +let arb_int64_of32 : int64 QCheck.arbitrary = + QCheck.(map ~rev:Int64.to_int32 Int64.of_int32 int32) + +(** Arbitrary int64 mixing small positive integers, + int64s from int32 and arbitrary int64 with equal frequency *) +let arb_int64_sizes : int64 QCheck.arbitrary = + let open QCheck in + oneof + [ + QCheck.map ~rev:Int64.to_int Int64.of_int (int_range (-10) 10); + arb_int64_of32; + int64; + ] + +(** Arbitrary positive int64, mixing small positive integers, + int64s from int32 and arbitrary int64 with equal frequency *) +let arb_ui64_sizes : int64 QCheck.arbitrary = + let open QCheck in + map_same_type + (fun i -> + let v = if i = Int64.min_int then Int64.max_int else Int64.abs i in + assert (v >= 0L) ; + v) + arb_int64_sizes + +(** Arbitrary tez based on [arb_tez_sizes] *) +let arb_tez_sizes = + let open QCheck in + map ~rev:Tez.to_mutez Tez.of_mutez_exn arb_ui64_sizes + +let test_coherent_mul = + QCheck.Test.make + ~name:"Tez.(*?) is coherent w.r.t. Z.(*)" + QCheck.(pair arb_tez_sizes arb_ui64_sizes) + (prop_binop64 Tez.( *? ) Z.( * )) + +let test_coherent_sub = + QCheck.Test.make + ~name:"Tez.(-?) is coherent w.r.t. Z.(-)" + QCheck.(pair arb_tez_sizes arb_tez_sizes) + (prop_binop Tez.( -? ) Z.( - )) + +let test_coherent_add = + QCheck.Test.make + ~name:"Tez.(+?) is coherent w.r.t. Z.(+)" + QCheck.(pair arb_tez_sizes arb_tez_sizes) + (prop_binop Tez.( +? ) Z.( + )) + +let test_coherent_div = + QCheck.Test.make + ~name:"Tez.(/?) is coherent w.r.t. Z.(/)" + QCheck.(pair arb_tez_sizes arb_ui64_sizes) + (fun (a, b) -> + QCheck.assume (b > 0L) ; + prop_binop64 Tez.( /? ) Z.( / ) (a, b)) + +let tests = + [test_coherent_mul; test_coherent_sub; test_coherent_add; test_coherent_div] + +let () = + Alcotest.run + "Tez_repr" + [("Tez_repr", Lib_test.Qcheck_helpers.qcheck_wrap tests)] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_time_repr.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_time_repr.ml new file mode 100644 index 000000000000..b2f67327deb9 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_time_repr.ml @@ -0,0 +1,44 @@ +(** Testing + ------- + Component: Protocol (time repr) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^time$" + Subject: Error handling of time operations +*) + +open Protocol + +let test_nominal_add () = + let t = Time_repr.of_seconds (Int64.of_int 2) in + let addition = + Period_repr.of_seconds Int64.one >>? fun p -> Time_repr.( +? ) t p + in + match addition with + | Ok v -> + Assert.equal + ~loc:__LOC__ + Time_repr.equal + "test_nominal_add" + Time_repr.pp_hum + v + (Time_repr.of_seconds (Int64.of_int 3)) + | Error _ -> failwith "Addition has overflowed" + +let test_overflow_add () = + let t = Time_repr.of_seconds Int64.max_int in + match Period_repr.of_seconds Int64.one with + | Error _ -> failwith "period_repr conversion" + | Ok p -> ( + match Time_repr.( +? ) t p with + | Error _ -> return_unit + | Ok tres -> + failwith + "No overflow: %Ld + %Ld = %Ld" + (Time_repr.to_seconds t) + (Period_repr.to_seconds p) + (Time_repr.to_seconds tres)) + +let tests = + [ + Tztest.tztest "non-overflowing addition" `Quick test_nominal_add; + Tztest.tztest "overflowing addition" `Quick test_overflow_add; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_timelock.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_timelock.ml new file mode 100644 index 000000000000..69f9aa54f582 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_timelock.ml @@ -0,0 +1,179 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (Timelock) + Invocation: cd src/proto_alpha/lib_protocol/test + dune exec ./main.exe -- test "^timelock$" + Subject: On timelock +*) + +open Protocol + +let wrap e = Lwt.return (Environment.wrap_tzresult e) + +let simple_test () = + let (public, secret) = Timelock.gen_rsa_keys () in + let locked_value = Timelock.gen_locked_value public in + let time = 1000 in + let unlocked_value = Timelock.unlock_with_secret secret ~time locked_value in + let (same_unlocked, proof) = + Timelock.unlock_and_prove_without_secret public ~time locked_value + in + assert (unlocked_value = same_unlocked) ; + let sym_key = Timelock.unlocked_value_to_symmetric_key unlocked_value in + let message = Bytes.create 12 in + let c = Timelock.encrypt sym_key message in + let expected_result = Environment.Timelock.Correct message in + let chest_key = Timelock.{unlocked_value; proof} in + let chest = Timelock.{locked_value; rsa_public = public; ciphertext = c} in + let result = Environment.Timelock.open_chest chest chest_key ~time in + assert (result = expected_result) ; + return_unit + +let contract_test () = + (* Parse a Michelson contract from string. *) + let toplevel_from_string str = + let (ast, errs) = Michelson_v1_parser.parse_toplevel ~check:true str in + match errs with [] -> ast.expanded | _ -> Stdlib.failwith "parse toplevel" + in + (* Parse a Michelson expression from string, useful for call parameters. *) + let expression_from_string str = + let (ast, errs) = Michelson_v1_parser.parse_expression ~check:true str in + match errs with + | [] -> ast.expanded + | _ -> Stdlib.failwith "parse expression" + in + let originate_contract file storage src b = + let load_file f = + let ic = open_in f in + let res = really_input_string ic (in_channel_length ic) in + close_in ic ; + res + in + let contract_string = load_file file in + let code = toplevel_from_string contract_string in + let storage = expression_from_string storage in + let script = + Alpha_context.Script.{code = lazy_expr code; storage = lazy_expr storage} + in + Op.origination (B b) src ~fee:(Test_tez.Tez.of_int 10) ~script + >>=? fun (operation, dst) -> + Incremental.begin_construction b >>=? fun incr -> + Incremental.add_operation incr operation >>=? fun incr -> + Incremental.finalize_block incr >|=? fun b -> (dst, b) + in + Context.init 3 >>=? fun (b, contracts) -> + let src = match contracts with hd :: _ -> hd | _ -> assert false in + originate_contract "contracts/timelock.tz" "0xaa" src b >>=? fun (dst, b) -> + let (public, secret) = Timelock.gen_rsa_keys () in + let locked_value = Timelock.gen_locked_value public in + let time = 1000 in + let unlocked_value = Timelock.unlock_with_secret secret ~time locked_value in + let (_same_unlocked, proof) = + Timelock.unlock_and_prove_without_secret public ~time locked_value + in + let sym_key = Timelock.unlocked_value_to_symmetric_key unlocked_value in + let message = Bytes.of_string "this is my message" in + let c = Timelock.encrypt sym_key message in + let check_storage chest chest_key expected_storage_hexa = + let chest_key_bytes = + "0x" + ^ Hex.show + (Hex.of_bytes + (Data_encoding.Binary.to_bytes_exn + Timelock.chest_key_encoding + chest_key)) + in + let chest_bytes = + "0x" + ^ Hex.show + (Hex.of_bytes + (Data_encoding.Binary.to_bytes_exn Timelock.chest_encoding chest)) + in + let micheslon_string = + Format.sprintf "(Pair %s %s )" chest_key_bytes chest_bytes + in + let parameters = + Alpha_context.Script.(lazy_expr (expression_from_string micheslon_string)) + in + let fee = Test_tez.Tez.of_int 10 in + Op.transaction ~fee (B b) src dst (Test_tez.Tez.of_int 3) ~parameters + >>=? fun operation -> + Incremental.begin_construction b >>=? fun incr -> + Incremental.add_operation incr operation >>=? fun incr -> + Incremental.finalize_block incr >>=? fun block -> + Incremental.begin_construction block >>=? fun incr -> + let ctxt = Incremental.alpha_ctxt incr in + Alpha_context.Contract.get_storage ctxt dst >>= wrap + >>=? fun (_, expr_option) -> + let expr = expr_option |> WithExceptions.Option.get ~loc:__LOC__ in + let bytes = + match Micheline.root expr with + | Micheline.Bytes (_, b) -> b + | _ -> assert false + in + let to_check = Hex.show (Hex.of_bytes bytes) in + assert (to_check = expected_storage_hexa) ; + return_unit + in + let chest_key_correct = Timelock.{unlocked_value; proof} in + let chest_correct = + Timelock.{locked_value; rsa_public = public; ciphertext = c} + in + check_storage + chest_correct + chest_key_correct + (Hex.show (Hex.of_bytes message)) + >>=? fun () -> + (* We redo an RSA parameters generation to create incorrect cipher and proof *) + let (public_bogus, secret_bogus) = Timelock.gen_rsa_keys () in + let locked_value_bogus = Timelock.gen_locked_value public_bogus in + let time = 1000 in + let unlocked_value_bogus = + Timelock.unlock_with_secret secret_bogus ~time locked_value_bogus + in + let (_same_unlocked, proof_bogus) = + Timelock.unlock_and_prove_without_secret public ~time locked_value_bogus + in + let sym_key_bogus = + Timelock.unlocked_value_to_symmetric_key unlocked_value_bogus + in + let c_bogus = Timelock.encrypt sym_key_bogus message in + + let chest_incorrect = + Timelock.{locked_value; rsa_public = public; ciphertext = c_bogus} + in + check_storage chest_incorrect chest_key_correct "00" >>=? fun () -> + let chest_key_incorrect = Timelock.{unlocked_value; proof = proof_bogus} in + check_storage chest_correct chest_key_incorrect "01" >>=? fun () -> + return_unit + +let tests = + [ + Tztest.tztest "simple test" `Quick simple_test; + Tztest.tztest "contract test" `Quick contract_test; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_transfer.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_transfer.ml new file mode 100644 index 000000000000..73a667a1e23e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_transfer.ml @@ -0,0 +1,642 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (transfer) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^transfer$" + Subject: Quantities transfer between contracts. +*) + +open Protocol +open Alpha_context +open Test_tez + +(*********************************************************************) +(* Utility functions *) +(*********************************************************************) + +(** + [transfer_and_check_balances b fee src dst amount] + this function takes a block, an optional parameter fee if fee does not + given it will be set to zero tez, a source contract, a destination contract + and the amount that one wants to transfer. + + 1- Transfer the amount of tez (w/wo fee) from a source contract to a + destination contract. + + 2- Check the equivalent of the balance of the source/destination + contract before and after transfer is validated. + + This function returns a pair: + - A block that added a valid operation + - a valid operation *) +let transfer_and_check_balances ?(with_burn = false) ~loc b ?(fee = Tez.zero) + ?expect_failure src dst amount = + Tez.( +? ) fee amount >>?= fun amount_fee -> + Context.Contract.balance (I b) src >>=? fun bal_src -> + Context.Contract.balance (I b) dst >>=? fun bal_dst -> + Op.transaction + ~gas_limit:(Alpha_context.Gas.Arith.integral_of_int_exn 3000) + (I b) + ~fee + src + dst + amount + >>=? fun op -> + Incremental.add_operation ?expect_failure b op >>=? fun b -> + Context.get_constants (I b) + >>=? fun {parametric = {origination_size; cost_per_byte; _}; _} -> + Tez.(cost_per_byte *? Int64.of_int origination_size) + >>?= fun origination_burn -> + let amount_fee_maybe_burn = + if with_burn then + match Tez.(amount_fee +? origination_burn) with + | Ok r -> r + | Error _ -> assert false + else amount_fee + in + Assert.balance_was_debited ~loc (I b) src bal_src amount_fee_maybe_burn + >>=? fun () -> + Assert.balance_was_credited ~loc (I b) dst bal_dst amount >|=? fun () -> + (b, op) + +(** + [transfer_to_itself_and_check_balances b fee contract amount] + this function takes a block, an optional parameter fee, + a contract that is a source and a destination contract, + and an amount of tez that one wants to transfer. + + 1- Transfer the amount of tez (w/wo transfer fee) from/to a contract itself. + + 2- Check the equivalent of the balance of the contract before + and after transfer. + + This function returns a pair: + - a block that added the valid transaction + - an valid transaction *) +let transfer_to_itself_and_check_balances ~loc b ?(fee = Tez.zero) contract + amount = + Context.Contract.balance (I b) contract >>=? fun bal -> + Op.transaction (I b) ~fee contract contract amount >>=? fun op -> + Incremental.add_operation b op >>=? fun b -> + Assert.balance_was_debited ~loc (I b) contract bal fee >|=? fun () -> (b, op) + +(** + [n_transactions n b fee source dest amount] + this function takes a number of "n" that one wish to transfer, + a block, an optional parameter fee, a source contract, + a destination contract and an amount one wants to transfer. + + This function will do a transaction from a source contract to + a destination contract with the amount "n" times. *) +let n_transactions n b ?fee source dest amount = + List.fold_left_es + (fun b _ -> + transfer_and_check_balances ~loc:__LOC__ b ?fee source dest amount + >|=? fun (b, _) -> b) + b + (1 -- n) + +let ten_tez = Tez.of_int 10 + +(*********************************************************************) +(* Tests *) +(*********************************************************************) + +let register_two_contracts () = + Context.init 2 >|=? function + | (_, []) | (_, [_]) -> assert false + | (b, contract_1 :: contract_2 :: _) -> (b, contract_1, contract_2) + +(** Compute a fraction of 2/[n] of the balance of [contract] *) +let two_over_n_of_balance incr contract n = + Context.Contract.balance (I incr) contract >>=? fun balance -> + Lwt.return (Tez.( /? ) balance n >>? fun res -> Tez.( *? ) res 2L) + +(********************) +(** Single transfer *) + +(********************) + +let single_transfer ?fee ?expect_failure amount = + register_two_contracts () >>=? fun (b, contract_1, contract_2) -> + Incremental.begin_construction b >>=? fun b -> + transfer_and_check_balances + ~loc:__LOC__ + ?fee + ?expect_failure + b + contract_1 + contract_2 + amount + >>=? fun (b, _) -> + Incremental.finalize_block b >>=? fun _ -> return_unit + +(** Single transfer without fee. *) +let test_block_with_a_single_transfer () = single_transfer Tez.one + +(** Single transfer with fee. *) +let test_block_with_a_single_transfer_with_fee () = + single_transfer ~fee:Tez.one Tez.one + +(** Single transfer without fee. *) +let test_transfer_zero_tez () = + single_transfer + ~expect_failure:(function + | Environment.Ecoproto_error (Contract_storage.Empty_transaction _) :: _ + -> + return_unit + | _ -> failwith "Empty transaction should fail") + Tez.zero + +(** Transfer zero tez from an implicit contract. *) +let test_transfer_zero_implicit () = + Context.init 1 >>=? fun (b, contracts) -> + let dest = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 in + let account = Account.new_account () in + Incremental.begin_construction b >>=? fun i -> + let src = Contract.implicit_contract account.Account.pkh in + Op.transaction (I i) src dest Tez.zero >>=? fun op -> + Incremental.add_operation i op >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Contract_storage.Empty_implicit_contract _ -> true + | _ -> false) + +(** Transfer to originated contract. *) +let test_transfer_to_originate_with_fee () = + Context.init 1 >>=? fun (b, contracts) -> + let contract = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + Incremental.begin_construction b >>=? fun b -> + two_over_n_of_balance b contract 10L >>=? fun fee -> + (* originated contract, paying a fee to originated this contract *) + Op.origination (I b) ~fee:ten_tez contract ~script:Op.dummy_script + >>=? fun (operation, new_contract) -> + Incremental.add_operation b operation >>=? fun b -> + two_over_n_of_balance b contract 3L >>=? fun amount -> + transfer_and_check_balances ~loc:__LOC__ b ~fee contract new_contract amount + >>=? fun (b, _) -> + Incremental.finalize_block b >>=? fun _ -> return_unit + +(** Transfer from balance. *) +let test_transfer_amount_of_contract_balance () = + register_two_contracts () >>=? fun (b, contract_1, contract_2) -> + Context.Contract.pkh contract_1 >>=? fun pkh1 -> + (* given that contract_1 no longer has a sufficient balance to bake, + make sure it cannot be chosen as baker *) + Incremental.begin_construction b ~policy:(Block.Excluding [pkh1]) + >>=? fun b -> + (* get the balance of the source contract *) + Context.Contract.balance (I b) contract_1 >>=? fun balance -> + (* transfer all the tez inside contract 1 *) + transfer_and_check_balances ~loc:__LOC__ b contract_1 contract_2 balance + >>=? fun (b, _) -> + Incremental.finalize_block b >>=? fun _ -> return_unit + +(** Transfer to oneself. *) +let test_transfers_to_self () = + Context.init 1 >>=? fun (b, contracts) -> + let contract = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + Incremental.begin_construction b >>=? fun b -> + two_over_n_of_balance b contract 3L >>=? fun amount -> + transfer_to_itself_and_check_balances ~loc:__LOC__ b contract amount + >>=? fun (b, _) -> + two_over_n_of_balance b contract 5L >>=? fun fee -> + transfer_to_itself_and_check_balances ~loc:__LOC__ b ~fee contract ten_tez + >>=? fun (b, _) -> + Incremental.finalize_block b >>=? fun _ -> return_unit + +(** Forgot to add the valid transaction into the block. *) +let test_missing_transaction () = + register_two_contracts () >>=? fun (b, contract_1, contract_2) -> + (* given that contract_1 no longer has a sufficient balance to bake, + make sure it cannot be chosen as baker *) + Context.Contract.pkh contract_1 >>=? fun pkh1 -> + Incremental.begin_construction b ~policy:(Block.Excluding [pkh1]) + >>=? fun b -> + two_over_n_of_balance b contract_1 6L >>=? fun amount -> + (* Do the transfer 3 times from source contract to destination contract *) + n_transactions 3 b contract_1 contract_2 amount >>=? fun b -> + (* do the fourth transfer from source contract to destination contract *) + Op.transaction (I b) contract_1 contract_2 amount >>=? fun _ -> + Incremental.finalize_block b >>=? fun _ -> return_unit + +(********************) +(* The following tests are for different kind of contracts: + - implicit to implicit + - implicit to originated + - originated to implicit + - originated to originated *) + +(********************) + +(** Implicit to Implicit. *) +let test_transfer_from_implicit_to_implicit_contract () = + Context.init 1 >>=? fun (b, contracts) -> + let bootstrap_contract = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + let account_a = Account.new_account () in + let account_b = Account.new_account () in + Incremental.begin_construction b >>=? fun b -> + let src = Contract.implicit_contract account_a.Account.pkh in + two_over_n_of_balance b bootstrap_contract 3L >>=? fun amount1 -> + two_over_n_of_balance b bootstrap_contract 10L >>=? fun fee1 -> + transfer_and_check_balances + ~with_burn:true + ~loc:__LOC__ + ~fee:fee1 + b + bootstrap_contract + src + amount1 + >>=? fun (b, _) -> + (* Create an implicit contract as a destination contract. *) + let dest = Contract.implicit_contract account_b.pkh in + two_over_n_of_balance b bootstrap_contract 4L >>=? fun amount2 -> + two_over_n_of_balance b bootstrap_contract 10L >>=? fun fee2 -> + (* Transfer from implicit contract to another implicit contract. *) + transfer_and_check_balances + ~with_burn:true + ~loc:__LOC__ + ~fee:fee2 + b + src + dest + amount2 + >>=? fun (b, _) -> + Incremental.finalize_block b >>=? fun _ -> return_unit + +(** Implicit to originated. *) +let test_transfer_from_implicit_to_originated_contract () = + Context.init 1 >>=? fun (b, contracts) -> + let bootstrap_contract = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + let contract = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + let account = Account.new_account () in + let src = Contract.implicit_contract account.Account.pkh in + Incremental.begin_construction b >>=? fun b -> + two_over_n_of_balance b bootstrap_contract 3L >>=? fun amount1 -> + (* transfer the money to implicit contract *) + transfer_and_check_balances + ~with_burn:true + ~loc:__LOC__ + b + bootstrap_contract + src + amount1 + >>=? fun (b, _) -> + (* originated contract *) + Op.origination (I b) contract ~script:Op.dummy_script + >>=? fun (operation, new_contract) -> + Incremental.add_operation b operation >>=? fun b -> + two_over_n_of_balance b bootstrap_contract 4L >>=? fun amount2 -> + (* transfer from implicit contract to originated contract *) + transfer_and_check_balances ~loc:__LOC__ b src new_contract amount2 + >>=? fun (b, _) -> + Incremental.finalize_block b >>=? fun _ -> return_unit + +(********************) +(* Slow tests case *) + +(********************) + +let multiple_transfer n ?fee amount = + register_two_contracts () >>=? fun (b, contract_1, contract_2) -> + Incremental.begin_construction b >>=? fun b -> + n_transactions n b ?fee contract_1 contract_2 amount >>=? fun b -> + Incremental.finalize_block b >>=? fun _ -> return_unit + +(** 1- Create a block with two contracts; + 2- Apply 100 transfers. +*) +let test_block_with_multiple_transfers () = + multiple_transfer 99 (Tez.of_int 1000) + +(** 1- Create a block with two contracts; + 2- Apply 100 transfers with 10tz fee. *) +let test_block_with_multiple_transfers_pay_fee () = + multiple_transfer 10 ~fee:ten_tez (Tez.of_int 1000) + +(* TODO : increase the number of operations and add a `Slow tag to it in `tests` *) + +(** 1- Create a block with 8 contracts; + 2- Apply multiple transfers without fees; + 3- Apply multiple transfers with fees. *) +let test_block_with_multiple_transfers_with_without_fee () = + Context.init 8 >>=? fun (b, contracts) -> + let contracts = Array.of_list contracts in + Incremental.begin_construction b >>=? fun b -> + let hundred = Tez.of_int 100 in + let ten = Tez.of_int 10 in + let twenty = Tez.of_int 20 in + n_transactions 10 b contracts.(0) contracts.(1) Tez.one >>=? fun b -> + n_transactions 30 b contracts.(1) contracts.(2) hundred >>=? fun b -> + n_transactions 30 b contracts.(1) contracts.(3) hundred >>=? fun b -> + n_transactions 30 b contracts.(4) contracts.(3) hundred >>=? fun b -> + n_transactions 20 b contracts.(0) contracts.(1) hundred >>=? fun b -> + n_transactions 10 b contracts.(1) contracts.(3) hundred >>=? fun b -> + n_transactions 10 b contracts.(1) contracts.(3) hundred >>=? fun b -> + n_transactions 20 ~fee:ten b contracts.(3) contracts.(4) ten >>=? fun b -> + n_transactions 10 ~fee:twenty b contracts.(4) contracts.(5) ten >>=? fun b -> + n_transactions 70 ~fee:twenty b contracts.(6) contracts.(0) twenty + >>=? fun b -> + n_transactions 550 ~fee:twenty b contracts.(6) contracts.(4) twenty + >>=? fun b -> + n_transactions 50 ~fee:ten b contracts.(7) contracts.(5) twenty >>=? fun b -> + n_transactions 30 ~fee:ten b contracts.(0) contracts.(7) hundred >>=? fun b -> + n_transactions 20 ~fee:ten b contracts.(1) contracts.(0) twenty >>=? fun b -> + Incremental.finalize_block b >>=? fun _ -> return_unit + +(** Build a chain that has 10 blocks. *) +let test_build_a_chain () = + register_two_contracts () >>=? fun (b, contract_1, contract_2) -> + let ten = Tez.of_int 10 in + List.fold_left_es + (fun b _ -> + Incremental.begin_construction b >>=? fun b -> + transfer_and_check_balances ~loc:__LOC__ b contract_1 contract_2 ten + >>=? fun (b, _) -> Incremental.finalize_block b) + b + (1 -- 10) + >>=? fun _ -> return_unit + +(*********************************************************************) +(* Expected error test cases *) +(*********************************************************************) + +(** Transferring zero tez is forbidden in implicit contract. *) +let test_empty_implicit () = + Context.init 1 >>=? fun (b, contracts) -> + let dest = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 in + let account = Account.new_account () in + Incremental.begin_construction b >>=? fun incr -> + let src = Contract.implicit_contract account.Account.pkh in + two_over_n_of_balance incr dest 3L >>=? fun amount -> + (* Transfer zero tez from an implicit contract. *) + Op.transaction (I incr) src dest amount >>=? fun op -> + Incremental.add_operation incr op >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Contract_storage.Empty_implicit_contract _ -> true + | _ -> false) + +(** Balance is too low to transfer. *) +let test_balance_too_low fee () = + register_two_contracts () >>=? fun (b, contract_1, contract_2) -> + Incremental.begin_construction b >>=? fun i -> + Context.Contract.balance (I i) contract_1 >>=? fun balance1 -> + Context.Contract.balance (I i) contract_2 >>=? fun balance2 -> + (* transfer the amount of tez that is bigger than the balance in the source contract *) + Op.transaction ~fee (I i) contract_1 contract_2 Tez.max_tez >>=? fun op -> + let expect_failure = function + | Environment.Ecoproto_error (Contract_storage.Balance_too_low _) :: _ -> + return_unit + | _ -> failwith "balance too low should fail" + in + (* the fee is higher than the balance then raise an error "Balance_too_low" *) + if fee > balance1 then + Incremental.add_operation ~expect_failure i op >>= fun _res -> return_unit + (* the fee is smaller than the balance, then the transfer is accepted + but it is not processed, and fees are taken *) + else + Incremental.add_operation ~expect_failure i op >>=? fun i -> + (* contract_1 loses the fees *) + Assert.balance_was_debited ~loc:__LOC__ (I i) contract_1 balance1 fee + >>=? fun () -> + (* contract_2 is not credited *) + Assert.balance_was_credited ~loc:__LOC__ (I i) contract_2 balance2 Tez.zero + +(** 1- Create a block, and three contracts; + 2- Add a transfer that at the end the balance of a contract is + zero into this block; + 3- Add another transfer that send tez from a zero balance contract; + 4- Catch the expected error: Balance_too_low. *) +let test_balance_too_low_two_transfers fee () = + Context.init 3 >>=? fun (b, contracts) -> + let contract_1 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + let contract_2 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 1 + in + let contract_3 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 2 + in + Incremental.begin_construction b >>=? fun i -> + Context.Contract.balance (I i) contract_1 >>=? fun balance -> + Tez.( /? ) balance 3L >>?= fun res -> + Tez.( *? ) res 2L >>?= fun two_third_of_balance -> + transfer_and_check_balances + ~loc:__LOC__ + i + contract_1 + contract_2 + two_third_of_balance + >>=? fun (i, _) -> + Context.Contract.balance (I i) contract_1 >>=? fun balance1 -> + Context.Contract.balance (I i) contract_3 >>=? fun balance3 -> + Op.transaction ~fee (I i) contract_1 contract_3 two_third_of_balance + >>=? fun operation -> + let expect_failure = function + | Environment.Ecoproto_error (Contract_storage.Balance_too_low _) :: _ -> + return_unit + | _ -> failwith "balance too low should fail" + in + Incremental.add_operation ~expect_failure i operation >>=? fun i -> + (* contract_1 loses the fees *) + Assert.balance_was_debited ~loc:__LOC__ (I i) contract_1 balance1 fee + >>=? fun () -> + (* contract_3 is not credited *) + Assert.balance_was_credited ~loc:__LOC__ (I i) contract_3 balance3 Tez.zero + +(** The counter is already used for the previous operation. *) +let invalid_counter () = + register_two_contracts () >>=? fun (b, contract_1, contract_2) -> + Incremental.begin_construction b >>=? fun b -> + Op.transaction (I b) contract_1 contract_2 Tez.one >>=? fun op1 -> + Op.transaction (I b) contract_1 contract_2 Tez.one >>=? fun op2 -> + Incremental.add_operation b op1 >>=? fun b -> + Incremental.add_operation b op2 >>= fun b -> + Assert.proto_error ~loc:__LOC__ b (function + | Contract_storage.Counter_in_the_past _ -> true + | _ -> false) + +(** Same as before but through a different way to perform this + error. *) +let test_add_the_same_operation_twice () = + register_two_contracts () >>=? fun (b, contract_1, contract_2) -> + Incremental.begin_construction b >>=? fun b -> + transfer_and_check_balances ~loc:__LOC__ b contract_1 contract_2 ten_tez + >>=? fun (b, op_transfer) -> + Op.transaction (I b) contract_1 contract_2 ten_tez >>=? fun _ -> + Incremental.add_operation b op_transfer >>= fun b -> + Assert.proto_error ~loc:__LOC__ b (function + | Contract_storage.Counter_in_the_past _ -> true + | _ -> false) + +(** Check ownership. *) +let test_ownership_sender () = + register_two_contracts () >>=? fun (b, contract_1, contract_2) -> + Incremental.begin_construction b >>=? fun b -> + (* get the manager of the contract_1 as a sender *) + Context.Contract.manager (I b) contract_1 >>=? fun manager -> + (* create an implicit_contract *) + let imcontract_1 = Alpha_context.Contract.implicit_contract manager.pkh in + transfer_and_check_balances ~loc:__LOC__ b imcontract_1 contract_2 Tez.one + >>=? fun (b, _) -> + Incremental.finalize_block b >>=? fun _ -> return_unit + +(*********************************************************************) +(* Random transfer *) + +(* Return a pair of minimum and maximum random number. *) +let random_range (min, max) = + let interv = max - min + 1 in + let init = + Random.self_init () ; + Random.int interv + min + in + init + +(* Return a random contract. *) +let random_contract contract_array = + let i = Random.int (Array.length contract_array) in + contract_array.(i) + +(** Transfer by randomly choose amount 10 contracts, and randomly + choose the amount in the source contract. *) +let test_random_transfer () = + Context.init 10 >>=? fun (b, contracts) -> + let contracts = Array.of_list contracts in + let source = random_contract contracts in + let dest = random_contract contracts in + Context.Contract.pkh source >>=? fun source_pkh -> + (* given that source may not have a sufficient balance for the transfer + to bake, + make sure it cannot be chosen as baker *) + Incremental.begin_construction b ~policy:(Block.Excluding [source_pkh]) + >>=? fun b -> + Context.Contract.balance (I b) source >>=? fun amount -> + (if source = dest then + transfer_to_itself_and_check_balances ~loc:__LOC__ b source amount + else transfer_and_check_balances ~loc:__LOC__ b source dest amount) + >>=? fun (b, _) -> + Incremental.finalize_block b >>=? fun _ -> return_unit + +(** Transfer random transactions. *) +let test_random_multi_transactions () = + let n = random_range (1, 100) in + multiple_transfer n (Tez.of_int 100) + +(*********************************************************************) + +let tests = + [ + (* single transfer *) + Tztest.tztest "single transfer" `Quick test_block_with_a_single_transfer; + Tztest.tztest + "single transfer with fee" + `Quick + test_block_with_a_single_transfer_with_fee; + (* transfer zero tez *) + Tztest.tztest "single transfer zero tez" `Quick test_transfer_zero_tez; + Tztest.tztest + "transfer zero tez from implicit contract" + `Quick + test_transfer_zero_implicit; + (* transfer to originated contract *) + Tztest.tztest + "transfer to originated contract paying transaction fee" + `Quick + test_transfer_to_originate_with_fee; + (* transfer by the balance of contract *) + Tztest.tztest + "transfer the amount from source contract balance" + `Quick + test_transfer_amount_of_contract_balance; + (* transfer to itself *) + Tztest.tztest "transfers to itself" `Quick test_transfers_to_self; + (* missing operation *) + Tztest.tztest "missing transaction" `Quick test_missing_transaction; + (* transfer from/to implicit/originated contracts*) + Tztest.tztest + "transfer from an implicit to implicit contract " + `Quick + test_transfer_from_implicit_to_implicit_contract; + Tztest.tztest + "transfer from an implicit to an originated contract" + `Quick + test_transfer_from_implicit_to_originated_contract; + (* Slow tests *) + Tztest.tztest + "block with multiple transfers" + `Slow + test_block_with_multiple_transfers; + (* TODO increase the number of transaction times *) + Tztest.tztest + "block with multiple transfer paying fee" + `Slow + test_block_with_multiple_transfers_pay_fee; + Tztest.tztest + "block with multiple transfer without paying fee" + `Slow + test_block_with_multiple_transfers_with_without_fee; + (* build the chain *) + Tztest.tztest "build a chain" `Quick test_build_a_chain; + (* Erroneous *) + Tztest.tztest "empty implicit" `Quick test_empty_implicit; + Tztest.tztest + "balance too low - transfer zero" + `Quick + (test_balance_too_low Tez.zero); + Tztest.tztest "balance too low" `Quick (test_balance_too_low Tez.one); + Tztest.tztest + "balance too low (max fee)" + `Quick + (test_balance_too_low Tez.max_tez); + Tztest.tztest + "balance too low with two transfers - transfer zero" + `Quick + (test_balance_too_low_two_transfers Tez.zero); + Tztest.tztest + "balance too low with two transfers" + `Quick + (test_balance_too_low_two_transfers Tez.one); + Tztest.tztest "invalid_counter" `Quick invalid_counter; + Tztest.tztest + "add the same operation twice" + `Quick + test_add_the_same_operation_twice; + Tztest.tztest "ownership sender" `Quick test_ownership_sender; + (* Random tests *) + Tztest.tztest "random transfer" `Quick test_random_transfer; + Tztest.tztest "random multi transfer" `Quick test_random_multi_transactions; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_typechecking.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_typechecking.ml new file mode 100644 index 000000000000..91905b747a30 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_typechecking.ml @@ -0,0 +1,906 @@ +(** Testing + ------- + Component: Protocol (type-checking) + Invocation: cd src/proto_alpha/lib_protocol/test + dune exec ./main.exe -- test "^typechecking$" + Subject: Type-checking +*) + +open Protocol +open Alpha_context +open Script_interpreter +open Micheline + +exception Expression_from_string + +let expression_from_string str : Script.expr tzresult Lwt.t = + let (ast, errs) = Michelson_v1_parser.parse_expression ~check:false str in + (match errs with + | [] -> () + | lst -> + Format.printf "expr_from_string: %a\n" Error_monad.pp_print_error lst ; + raise Expression_from_string) ; + return ast.expanded + +let ( >>=?? ) x y = + x >>= function + | Ok s -> y s + | Error err -> Lwt.return @@ Error (Environment.wrap_tztrace err) + +let ( >>??= ) x y = + match x with + | Ok s -> y s + | Error err -> Lwt.return @@ Error (Environment.wrap_tztrace err) + +let wrap_error_lwt x = x >>= fun x -> Lwt.return @@ Environment.wrap_tzresult x + +(* Test for Script_ir_translator.unparse_script on a script declaring views. *) +let test_unparse_view () = + let dummy_contract = + "{parameter unit; storage unit; code { CAR; NIL operation; PAIR }; view \ + \"v0\" unit unit { DROP; UNIT }; view \"v1\" nat nat {CAR}}" + in + let contract_expr = Expr.from_string dummy_contract in + let storage_expr = Expr.from_string "Unit" in + let bef = Script.lazy_expr contract_expr |> Data_encoding.force_bytes in + let script = + Script.{code = lazy_expr contract_expr; storage = lazy_expr storage_expr} + in + Test_interpretation.test_context () >>=? fun ctx -> + Script_ir_translator.parse_script + ctx + ~legacy:true + ~allow_forged_in_storage:false + script + >>=?? fun (Ex_script script, ctx) -> + Script_ir_translator.unparse_script ctx Readable script + >>=?? fun (unparse_script, _ctx) -> + let aft = Data_encoding.force_bytes unparse_script.code in + Alcotest.(check bytes) "didn't match" bef aft |> return + +let test_context () = + Context.init 3 >>=? fun (b, _cs) -> + Incremental.begin_construction b >>=? fun v -> + return (Incremental.alpha_ctxt v) + +let test_context_with_nat_nat_big_map () = + Context.init 3 >>=? fun (b, contracts) -> + let source = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd contracts in + Op.origination (B b) source ~script:Op.dummy_script + >>=? fun (operation, originated) -> + Block.bake ~operation b >>=? fun b -> + Incremental.begin_construction b >>=? fun v -> + let ctxt = Incremental.alpha_ctxt v in + wrap_error_lwt @@ Big_map.fresh ~temporary:false ctxt >>=? fun (ctxt, id) -> + let nat_ty = Script_typed_ir.nat_t ~annot:None in + wrap_error_lwt @@ Lwt.return @@ Script_ir_translator.unparse_ty ctxt nat_ty + >>=? fun (nat_ty_node, ctxt) -> + let nat_ty_expr = Micheline.strip_locations nat_ty_node in + let alloc = Big_map.{key_type = nat_ty_expr; value_type = nat_ty_expr} in + let init = Lazy_storage.Alloc alloc in + let diffs = + [ + Lazy_storage.make + Lazy_storage.Kind.Big_map + id + (Update {init; updates = []}); + ] + in + wrap_error_lwt + @@ Contract.update_script_storage ctxt originated nat_ty_expr (Some diffs) + >>=? fun ctxt -> return (ctxt, id) + +let default_source = Contract.implicit_contract Signature.Public_key_hash.zero + +let default_step_constants = + { + source = default_source; + payer = default_source; + self = default_source; + amount = Tez.zero; + chain_id = Chain_id.zero; + } + +(** Helper function that parses and types a script, its initial storage and + parameters from strings. It then executes the typed script with the storage + and parameter and returns the result. *) +let run_script ctx ?(step_constants = default_step_constants) contract + ?(entrypoint = "default") ~storage ~parameter () = + expression_from_string contract >>=? fun contract_expr -> + expression_from_string storage >>=? fun storage_expr -> + expression_from_string parameter >>=? fun parameter_expr -> + let script = + Script.{code = lazy_expr contract_expr; storage = lazy_expr storage_expr} + in + Script_interpreter.execute + ctx + Readable + step_constants + ~script + ~cached_script:None + ~entrypoint + ~parameter:parameter_expr + ~internal:false + >>=?? fun res -> return res + +let read_file filename = + let ch = open_in filename in + let s = really_input_string ch (in_channel_length ch) in + close_in ch ; + s + +(** Check that the custom stack overflow exception is triggered when + it should be. *) +let test_typecheck_stack_overflow () = + test_context () >>=? fun ctxt -> + let storage = "Unit" in + let parameter = "Unit" in + let script = read_file "./contracts/big_interpreter_stack.tz" in + run_script ctxt script ~storage ~parameter () >>= function + | Ok _ -> Alcotest.fail "expected an error" + | Error lst + when List.mem + ~equal:( = ) + (Environment.Ecoproto_error + Script_tc_errors.Typechecking_too_many_recursive_calls) + lst -> + return () + | Error errs -> + Alcotest.failf "Unexpected error: %a" Error_monad.pp_print_error errs + +(* NOTE: this test fails with an out-of-memory exception. *) +let _test_unparse_stack_overflow () = + test_context () >>=? fun ctxt -> + (* Meme *) + let enorme_et_seq n = + let rec aux n acc = aux (n - 1) @@ Micheline.Seq (0, [acc]) in + aux n (Micheline.Int (0, Z.zero)) + in + Script_ir_translator.(unparse_code ctxt Readable (enorme_et_seq 10_001)) + >>= function + | Ok _ -> Alcotest.fail "expected an error" + | Error trace -> + let trace_string = + Format.asprintf "%a" Environment.Error_monad.pp_trace trace + in + let expect_id = "michelson_v1.unparsing_stack_overflow" in + let expect_descrfiption = + "Too many recursive calls were needed for unparsing" + in + if + Astring.String.is_infix ~affix:expect_id trace_string + && Astring.String.is_infix ~affix:expect_descrfiption trace_string + then return_unit + else + Alcotest.failf + "Unexpected error (%s) at %s" + trace_string + __LOC__ + return_unit + +let location = function + | Prim (loc, _, _, _) + | Int (loc, _) + | String (loc, _) + | Bytes (loc, _) + | Seq (loc, _) -> + loc + +let test_parse_ty ctxt node expected = + let legacy = false in + let allow_lazy_storage = true in + let allow_operation = true in + let allow_contract = true in + let allow_ticket = true in + Environment.wrap_tzresult + ( Script_ir_translator.parse_ty + ctxt + ~legacy + ~allow_lazy_storage + ~allow_operation + ~allow_contract + ~allow_ticket + node + >>? fun (Script_ir_translator.Ex_ty actual, ctxt) -> + Script_ir_translator.ty_eq ctxt (location node) actual expected + >|? fun (_, ctxt) -> ctxt ) + +let test_parse_comb_type () = + let open Script in + let open Script_typed_ir in + let nat_prim = Prim (-1, T_nat, [], []) in + let nat_prim_a = Prim (-1, T_nat, [], ["%a"]) in + let nat_prim_b = Prim (-1, T_nat, [], ["%b"]) in + let nat_prim_c = Prim (-1, T_nat, [], ["%c"]) in + let nat_ty = nat_t ~annot:None in + let pair_prim l = Prim (-1, T_pair, l, []) in + let pair_ty ty1 ty2 = + pair_t (-1) (ty1, None, None) (ty2, None, None) ~annot:None + in + let pair_prim2 a b = pair_prim [a; b] in + let pair_nat_nat_prim = pair_prim2 nat_prim nat_prim in + pair_ty nat_ty nat_ty >>??= fun pair_nat_nat_ty -> + test_context () >>=? fun ctxt -> + (* pair nat nat *) + test_parse_ty ctxt pair_nat_nat_prim pair_nat_nat_ty >>?= fun ctxt -> + (* pair (pair nat nat) nat *) + pair_ty pair_nat_nat_ty nat_ty >>??= fun pair_pair_nat_nat_nat_ty -> + test_parse_ty + ctxt + (pair_prim2 pair_nat_nat_prim nat_prim) + pair_pair_nat_nat_nat_ty + >>?= fun ctxt -> + (* pair nat (pair nat nat) *) + pair_ty nat_ty pair_nat_nat_ty >>??= fun pair_nat_pair_nat_nat_ty -> + test_parse_ty + ctxt + (pair_prim2 nat_prim pair_nat_nat_prim) + pair_nat_pair_nat_nat_ty + >>?= fun ctxt -> + (* pair nat nat nat *) + pair_ty nat_ty pair_nat_nat_ty >>??= fun pair_nat_nat_nat_ty -> + test_parse_ty + ctxt + (pair_prim [nat_prim; nat_prim; nat_prim]) + pair_nat_nat_nat_ty + >>?= fun ctxt -> + (* pair (nat %a) nat *) + pair_t + (-1) + (nat_ty, Some (Field_annot "a"), None) + (nat_ty, None, None) + ~annot:None + >>??= fun pair_nat_a_nat_ty -> + test_parse_ty ctxt (pair_prim2 nat_prim_a nat_prim) pair_nat_a_nat_ty + >>?= fun ctxt -> + (* pair nat (nat %b) *) + pair_t + (-1) + (nat_ty, None, None) + (nat_ty, Some (Field_annot "b"), None) + ~annot:None + >>??= fun pair_nat_nat_b_ty -> + test_parse_ty ctxt (pair_prim2 nat_prim nat_prim_b) pair_nat_nat_b_ty + >>?= fun ctxt -> + (* pair (nat %a) (nat %b) *) + pair_t + (-1) + (nat_ty, Some (Field_annot "a"), None) + (nat_ty, Some (Field_annot "b"), None) + ~annot:None + >>??= fun pair_nat_a_nat_b_ty -> + test_parse_ty ctxt (pair_prim2 nat_prim_a nat_prim_b) pair_nat_a_nat_b_ty + >>?= fun ctxt -> + (* pair (nat %a) (nat %b) (nat %c) *) + pair_t + (-1) + (nat_ty, Some (Field_annot "b"), None) + (nat_ty, Some (Field_annot "c"), None) + ~annot:None + >>??= fun pair_nat_b_nat_c_ty -> + pair_t + (-1) + (nat_ty, Some (Field_annot "a"), None) + (pair_nat_b_nat_c_ty, None, None) + ~annot:None + >>??= fun pair_nat_a_nat_b_nat_c_ty -> + test_parse_ty + ctxt + (pair_prim [nat_prim_a; nat_prim_b; nat_prim_c]) + pair_nat_a_nat_b_nat_c_ty + >>?= fun ctxt -> + (* pair (nat %a) (pair %b nat nat) *) + pair_t (-1) (nat_ty, None, None) (nat_ty, None, None) ~annot:None + >>??= fun pair_b_nat_nat_ty -> + pair_t + (-1) + (nat_ty, Some (Field_annot "a"), None) + (pair_b_nat_nat_ty, Some (Field_annot "b"), None) + ~annot:None + >>??= fun pair_nat_a_pair_b_nat_nat_ty -> + test_parse_ty + ctxt + (pair_prim2 nat_prim_a (Prim (-1, T_pair, [nat_prim; nat_prim], ["%b"]))) + pair_nat_a_pair_b_nat_nat_ty + >>?= fun _ -> return_unit + +let test_unparse_ty loc ctxt expected ty = + Environment.wrap_tzresult + ( Script_ir_translator.unparse_ty ctxt ty >>? fun (actual, ctxt) -> + if actual = expected then ok ctxt + else Alcotest.failf "Unexpected error: %s" loc ) + +let test_unparse_comb_type () = + let open Script in + let open Script_typed_ir in + let nat_prim = Prim (-1, T_nat, [], []) in + let nat_prim_a = Prim (-1, T_nat, [], ["%a"]) in + let nat_prim_b = Prim (-1, T_nat, [], ["%b"]) in + let nat_prim_c = Prim (-1, T_nat, [], ["%c"]) in + let nat_ty = nat_t ~annot:None in + let pair_prim l = Prim (-1, T_pair, l, []) in + let pair_ty ty1 ty2 = + pair_t (-1) (ty1, None, None) (ty2, None, None) ~annot:None + in + let pair_prim2 a b = pair_prim [a; b] in + let pair_nat_nat_prim = pair_prim2 nat_prim nat_prim in + pair_ty nat_ty nat_ty >>??= fun pair_nat_nat_ty -> + test_context () >>=? fun ctxt -> + (* pair nat nat *) + test_unparse_ty __LOC__ ctxt pair_nat_nat_prim pair_nat_nat_ty + >>?= fun ctxt -> + (* pair (pair nat nat) nat *) + pair_ty pair_nat_nat_ty nat_ty >>??= fun pair_pair_nat_nat_nat_ty -> + test_unparse_ty + __LOC__ + ctxt + (pair_prim2 pair_nat_nat_prim nat_prim) + pair_pair_nat_nat_nat_ty + >>?= fun ctxt -> + (* pair nat nat nat *) + pair_ty nat_ty pair_nat_nat_ty >>??= fun pair_nat_nat_nat_ty -> + test_unparse_ty + __LOC__ + ctxt + (pair_prim [nat_prim; nat_prim; nat_prim]) + pair_nat_nat_nat_ty + >>?= fun ctxt -> + (* pair (nat %a) nat *) + pair_t + (-1) + (nat_ty, Some (Field_annot "a"), None) + (nat_ty, None, None) + ~annot:None + >>??= fun pair_nat_a_nat_ty -> + test_unparse_ty + __LOC__ + ctxt + (pair_prim2 nat_prim_a nat_prim) + pair_nat_a_nat_ty + >>?= fun ctxt -> + (* pair nat (nat %b) *) + pair_t + (-1) + (nat_ty, None, None) + (nat_ty, Some (Field_annot "b"), None) + ~annot:None + >>??= fun pair_nat_nat_b_ty -> + test_unparse_ty + __LOC__ + ctxt + (pair_prim2 nat_prim nat_prim_b) + pair_nat_nat_b_ty + >>?= fun ctxt -> + (* pair (nat %a) (nat %b) *) + pair_t + (-1) + (nat_ty, Some (Field_annot "a"), None) + (nat_ty, Some (Field_annot "b"), None) + ~annot:None + >>??= fun pair_nat_a_nat_b_ty -> + test_unparse_ty + __LOC__ + ctxt + (pair_prim2 nat_prim_a nat_prim_b) + pair_nat_a_nat_b_ty + >>?= fun ctxt -> + (* pair (nat %a) (nat %b) (nat %c) *) + pair_t + (-1) + (nat_ty, Some (Field_annot "b"), None) + (nat_ty, Some (Field_annot "c"), None) + ~annot:None + >>??= fun pair_nat_b_nat_c_ty -> + pair_t + (-1) + (nat_ty, Some (Field_annot "a"), None) + (pair_nat_b_nat_c_ty, None, None) + ~annot:None + >>??= fun pair_nat_a_nat_b_nat_c_ty -> + test_unparse_ty + __LOC__ + ctxt + (pair_prim [nat_prim_a; nat_prim_b; nat_prim_c]) + pair_nat_a_nat_b_nat_c_ty + >>?= fun ctxt -> + (* pair (nat %a) (pair %b nat nat) *) + pair_t (-1) (nat_ty, None, None) (nat_ty, None, None) ~annot:None + >>??= fun pair_nat_nat_ty -> + pair_t + (-1) + (nat_ty, Some (Field_annot "a"), None) + (pair_nat_nat_ty, Some (Field_annot "b"), None) + ~annot:None + >>??= fun pair_nat_a_pair_b_nat_nat_ty -> + test_unparse_ty + __LOC__ + ctxt + (pair_prim2 nat_prim_a (Prim (-1, T_pair, [nat_prim; nat_prim], ["%b"]))) + pair_nat_a_pair_b_nat_nat_ty + >>?= fun ctxt -> + (* pair nat (pair @b nat nat) *) + pair_t + (-1) + (nat_ty, None, None) + (pair_nat_nat_ty, None, Some (Var_annot "b")) + ~annot:None + >>??= fun pair_nat_pair_b_nat_nat_ty -> + test_unparse_ty + __LOC__ + ctxt + (pair_prim2 nat_prim (Prim (-1, T_pair, [nat_prim; nat_prim], ["@b"]))) + pair_nat_pair_b_nat_nat_ty + >>?= fun ctxt -> + (* pair nat (pair :b nat nat) *) + pair_t + (-1) + (nat_ty, None, None) + (nat_ty, None, None) + ~annot:(Some (Type_annot "b")) + >>??= fun pair_b_nat_nat_ty -> + pair_t (-1) (nat_ty, None, None) (pair_b_nat_nat_ty, None, None) ~annot:None + >>??= fun pair_nat_pair_b_nat_nat_ty -> + test_unparse_ty + __LOC__ + ctxt + (pair_prim2 nat_prim (Prim (-1, T_pair, [nat_prim; nat_prim], [":b"]))) + pair_nat_pair_b_nat_nat_ty + >>?= fun _ -> return_unit + +let test_unparse_comparable_ty loc ctxt expected ty = + (* unparse_comparable_ty is not exported, the simplest way to call it is to + call parse_ty on a set type *) + let open Script_typed_ir in + Environment.wrap_tzresult + ( set_t (-1) ty ~annot:None >>? fun set_ty_ty -> + Script_ir_translator.unparse_ty ctxt set_ty_ty >>? fun (actual, ctxt) -> + if actual = Prim (-1, T_set, [expected], []) then ok ctxt + else Alcotest.failf "Unexpected error: %s" loc ) + +let test_unparse_comb_comparable_type () = + let open Script in + let open Script_typed_ir in + let nat_prim = Prim (-1, T_nat, [], []) in + let nat_prim_a = Prim (-1, T_nat, [], ["%a"]) in + let nat_prim_b = Prim (-1, T_nat, [], ["%b"]) in + let nat_prim_c = Prim (-1, T_nat, [], ["%c"]) in + let nat_ty = nat_key ~annot:None in + let pair_prim l = Prim (-1, T_pair, l, []) in + let pair_ty ty1 ty2 = pair_key (-1) (ty1, None) (ty2, None) ~annot:None in + let pair_prim2 a b = pair_prim [a; b] in + let pair_nat_nat_prim = pair_prim2 nat_prim nat_prim in + pair_ty nat_ty nat_ty >>??= fun pair_nat_nat_ty -> + test_context () >>=? fun ctxt -> + (* pair nat nat *) + test_unparse_comparable_ty __LOC__ ctxt pair_nat_nat_prim pair_nat_nat_ty + >>?= fun ctxt -> + (* pair (pair nat nat) nat *) + pair_ty pair_nat_nat_ty nat_ty >>??= fun pair_pair_nat_nat_nat_ty -> + test_unparse_comparable_ty + __LOC__ + ctxt + (pair_prim2 pair_nat_nat_prim nat_prim) + pair_pair_nat_nat_nat_ty + >>?= fun ctxt -> + (* pair nat nat nat *) + pair_ty nat_ty pair_nat_nat_ty >>??= fun pair_nat_nat_nat_ty -> + test_unparse_comparable_ty + __LOC__ + ctxt + (pair_prim [nat_prim; nat_prim; nat_prim]) + pair_nat_nat_nat_ty + >>?= fun ctxt -> + (* pair (nat %a) nat *) + pair_key (-1) (nat_ty, Some (Field_annot "a")) (nat_ty, None) ~annot:None + >>??= fun pair_nat_a_nat_ty -> + test_unparse_comparable_ty + __LOC__ + ctxt + (pair_prim2 nat_prim_a nat_prim) + pair_nat_a_nat_ty + >>?= fun ctxt -> + (* pair nat (nat %b) *) + pair_key (-1) (nat_ty, None) (nat_ty, Some (Field_annot "b")) ~annot:None + >>??= fun pair_nat_nat_b_ty -> + test_unparse_comparable_ty + __LOC__ + ctxt + (pair_prim2 nat_prim nat_prim_b) + pair_nat_nat_b_ty + >>?= fun ctxt -> + (* pair (nat %a) (nat %b) *) + pair_key + (-1) + (nat_ty, Some (Field_annot "a")) + (nat_ty, Some (Field_annot "b")) + ~annot:None + >>??= fun pair_nat_a_nat_b_ty -> + test_unparse_comparable_ty + __LOC__ + ctxt + (pair_prim2 nat_prim_a nat_prim_b) + pair_nat_a_nat_b_ty + >>?= fun ctxt -> + (* pair (nat %a) (nat %b) (nat %c) *) + pair_key + (-1) + (nat_ty, Some (Field_annot "b")) + (nat_ty, Some (Field_annot "c")) + ~annot:None + >>??= fun pair_nat_b_nat_c_ty -> + pair_key + (-1) + (nat_ty, Some (Field_annot "a")) + (pair_nat_b_nat_c_ty, None) + ~annot:None + >>??= fun pair_nat_a_nat_b_nat_c_ty -> + test_unparse_comparable_ty + __LOC__ + ctxt + (pair_prim [nat_prim_a; nat_prim_b; nat_prim_c]) + pair_nat_a_nat_b_nat_c_ty + >>?= fun ctxt -> + (* pair (nat %a) (pair %b nat nat) *) + pair_key + (-1) + (nat_ty, Some (Field_annot "a")) + (pair_nat_nat_ty, Some (Field_annot "b")) + ~annot:None + >>??= fun pair_nat_a_pair_b_nat_nat_ty -> + test_unparse_comparable_ty + __LOC__ + ctxt + (pair_prim2 nat_prim_a (Prim (-1, T_pair, [nat_prim; nat_prim], ["%b"]))) + pair_nat_a_pair_b_nat_nat_ty + >>?= fun ctxt -> + (* pair nat (pair :b nat nat) *) + pair_key (-1) (nat_ty, None) (nat_ty, None) ~annot:(Some (Type_annot "b")) + >>??= fun pair_b_nat_nat_ty -> + pair_key (-1) (nat_ty, None) (pair_b_nat_nat_ty, None) ~annot:None + >>??= fun pair_nat_pair_b_nat_nat_ty -> + test_unparse_comparable_ty + __LOC__ + ctxt + (pair_prim2 nat_prim (Prim (-1, T_pair, [nat_prim; nat_prim], [":b"]))) + pair_nat_pair_b_nat_nat_ty + >>?= fun _ -> return_unit + +let test_parse_data ?(equal = Stdlib.( = )) loc ctxt ty node expected = + let legacy = false in + let allow_forged = true in + wrap_error_lwt + ( Script_ir_translator.parse_data ctxt ~legacy ~allow_forged ty node + >>=? fun (actual, ctxt) -> + if equal actual expected then return ctxt + else Alcotest.failf "Unexpected error: %s" loc ) + +let test_parse_data_fails loc ctxt ty node = + let legacy = false in + let allow_forged = false in + wrap_error_lwt + (Script_ir_translator.parse_data ctxt ~legacy ~allow_forged ty node + >>= function + | Ok _ -> Alcotest.failf "Unexpected typechecking success: %s" loc + | Error trace -> + let trace_string = + Format.asprintf "%a" Environment.Error_monad.pp_trace trace + in + let expect_id = "michelson_v1.invalid_constant" in + let expect_descrfiption = + "A data expression was invalid for its expected type." + in + if + Astring.String.is_infix ~affix:expect_id trace_string + && Astring.String.is_infix ~affix:expect_descrfiption trace_string + then return_unit + else + Alcotest.failf + "Unexpected error (%s) at %s" + trace_string + __LOC__ + return_unit) + +let test_parse_comb_data () = + let open Script in + let open Script_typed_ir in + let z = Script_int.zero_n in + let z_prim = Micheline.Int (-1, Z.zero) in + let nat_ty = nat_t ~annot:None in + let pair_prim l = Prim (-1, D_Pair, l, []) in + let pair_ty ty1 ty2 = + pair_t (-1) (ty1, None, None) (ty2, None, None) ~annot:None + in + pair_ty nat_ty nat_ty >>??= fun pair_nat_nat_ty -> + let pair_prim2 a b = pair_prim [a; b] in + let pair_z_z_prim = pair_prim2 z_prim z_prim in + list_t (-1) nat_ty ~annot:None >>??= fun list_nat_ty -> + big_map_t (-1) (nat_key ~annot:None) nat_ty ~annot:None + >>??= fun big_map_nat_nat_ty -> + test_context_with_nat_nat_big_map () >>=? fun (ctxt, big_map_id) -> + (* Pair 0 0 *) + test_parse_data __LOC__ ctxt pair_nat_nat_ty pair_z_z_prim (z, z) + >>=? fun ctxt -> + (* {0; 0} *) + test_parse_data + __LOC__ + ctxt + pair_nat_nat_ty + (Micheline.Seq (-1, [z_prim; z_prim])) + (z, z) + >>=? fun ctxt -> + (* Pair (Pair 0 0) 0 *) + pair_ty pair_nat_nat_ty nat_ty >>??= fun pair_pair_nat_nat_nat_ty -> + test_parse_data + __LOC__ + ctxt + pair_pair_nat_nat_nat_ty + (pair_prim2 pair_z_z_prim z_prim) + ((z, z), z) + >>=? fun ctxt -> + (* Pair 0 (Pair 0 0) *) + pair_ty nat_ty pair_nat_nat_ty >>??= fun pair_nat_pair_nat_nat_ty -> + test_parse_data + __LOC__ + ctxt + pair_nat_pair_nat_nat_ty + (pair_prim2 z_prim pair_z_z_prim) + (z, (z, z)) + >>=? fun ctxt -> + (* Pair 0 0 0 *) + test_parse_data + __LOC__ + ctxt + pair_nat_pair_nat_nat_ty + (pair_prim [z_prim; z_prim; z_prim]) + (z, (z, z)) + >>=? fun ctxt -> + (* {0; 0; 0} *) + test_parse_data + __LOC__ + ctxt + pair_nat_pair_nat_nat_ty + (Micheline.Seq (-1, [z_prim; z_prim; z_prim])) + (z, (z, z)) + >>=? fun ctxt -> + (* Should fail: {0} against pair nat (list nat) *) + pair_ty nat_ty list_nat_ty >>??= fun pair_nat_list_nat_ty -> + test_parse_data_fails + __LOC__ + ctxt + pair_nat_list_nat_ty + (Micheline.Seq (-1, [z_prim])) + >>=? fun () -> + (* Should fail: {0; 0; 0} against pair nat (list nat) *) + test_parse_data_fails + __LOC__ + ctxt + pair_nat_list_nat_ty + (Micheline.Seq (-1, [z_prim; z_prim; z_prim])) + >>=? fun () -> + (* check Pair 0 (Pair 0 {}) against pair nat (big_map nat nat) + so that the following test fails for the good reason and not because + the big map doesn't exist + *) + let id_z = Big_map.Id.unparse_to_z big_map_id in + let id_prim = Int (-1, id_z) in + let expected_big_map = + let open Script_typed_ir in + let diff = {map = Big_map_overlay.empty; size = 0} in + let nat_key_ty = nat_key ~annot:None in + {id = Some big_map_id; diff; key_type = nat_key_ty; value_type = nat_ty} + in + let equal (nat1, big_map1) (nat2, big_map2) = + (* Custom equal needed because big maps contain boxed maps containing functional values *) + nat1 = nat2 && big_map1.id = big_map2.id + && big_map1.key_type = big_map2.key_type + && big_map1.value_type = big_map2.value_type + && big_map1.diff.size = big_map2.diff.size + && Big_map_overlay.bindings big_map1.diff.map + = Big_map_overlay.bindings big_map2.diff.map + in + pair_ty nat_ty big_map_nat_nat_ty >>??= fun pair_nat_big_map_nat_nat_ty -> + test_parse_data + ~equal + __LOC__ + ctxt + pair_nat_big_map_nat_nat_ty + (pair_prim2 z_prim (pair_prim2 id_prim (Seq (-1, [])))) + (Script_int.zero_n, expected_big_map) + >>=? fun ctxt -> + (* Should fail: Pair 0 0 {} against pair nat (big_map nat nat) *) + test_parse_data_fails + __LOC__ + ctxt + pair_nat_big_map_nat_nat_ty + (pair_prim [z_prim; id_prim; Seq (-1, [])]) + +let test_parse_address () = + let open Script_typed_ir in + test_context_with_nat_nat_big_map () >>=? fun (ctxt, _big_map_id) -> + (* KT1% (empty entrypoint) *) + wrap_error_lwt + (Lwt.return (Contract.of_b58check "KT1FAKEFAKEFAKEFAKEFAKEFAKEFAKGGSE2x")) + >>=? fun kt1fake -> + test_parse_data + __LOC__ + ctxt + (address_t ~annot:None) + (String (-1, "KT1FAKEFAKEFAKEFAKEFAKEFAKEFAKGGSE2x%")) + (kt1fake, "default") + >>=? fun ctxt -> + (* tz1% (empty entrypoint) *) + wrap_error_lwt + (Lwt.return (Contract.of_b58check "tz1fakefakefakefakefakefakefakcphLA5")) + >>=? fun tz1fake -> + test_parse_data + __LOC__ + ctxt + (address_t ~annot:None) + (String (-1, "tz1fakefakefakefakefakefakefakcphLA5%")) + (tz1fake, "default") + >|=? fun _ctxt -> () + +let test_unparse_data loc ctxt ty x ~expected_readable ~expected_optimized = + wrap_error_lwt + ( Script_ir_translator.unparse_data ctxt Script_ir_translator.Readable ty x + >>=? fun (actual_readable, ctxt) -> + (if actual_readable = expected_readable then return ctxt + else Alcotest.failf "Error in readable unparsing: %s" loc) + >>=? fun ctxt -> + Script_ir_translator.unparse_data ctxt Script_ir_translator.Optimized ty x + >>=? fun (actual_optimized, ctxt) -> + if actual_optimized = expected_optimized then return ctxt + else Alcotest.failf "Error in optimized unparsing: %s" loc ) + +let test_unparse_comb_data () = + let open Script in + let open Script_typed_ir in + let z = Script_int.zero_n in + let z_prim = Micheline.Int (-1, Z.zero) in + let nat_ty = nat_t ~annot:None in + let pair_prim l = Prim (-1, D_Pair, l, []) in + let pair_ty ty1 ty2 = + pair_t (-1) (ty1, None, None) (ty2, None, None) ~annot:None + in + pair_ty nat_ty nat_ty >>??= fun pair_nat_nat_ty -> + let pair_prim2 a b = pair_prim [a; b] in + let pair_z_z_prim = pair_prim2 z_prim z_prim in + test_context () >>=? fun ctxt -> + (* Pair 0 0 *) + test_unparse_data + __LOC__ + ctxt + pair_nat_nat_ty + (z, z) + ~expected_readable:pair_z_z_prim + ~expected_optimized:pair_z_z_prim + >>=? fun ctxt -> + (* Pair (Pair 0 0) 0 *) + pair_ty pair_nat_nat_ty nat_ty >>??= fun pair_pair_nat_nat_nat_ty -> + test_unparse_data + __LOC__ + ctxt + pair_pair_nat_nat_nat_ty + ((z, z), z) + ~expected_readable:(pair_prim2 pair_z_z_prim z_prim) + ~expected_optimized:(pair_prim2 pair_z_z_prim z_prim) + >>=? fun ctxt -> + (* Readable: Pair 0 0 0; Optimized: Pair 0 (Pair 0 0) *) + pair_ty nat_ty pair_nat_nat_ty >>??= fun pair_nat_pair_nat_nat_ty -> + test_unparse_data + __LOC__ + ctxt + pair_nat_pair_nat_nat_ty + (z, (z, z)) + ~expected_readable:(pair_prim [z_prim; z_prim; z_prim]) + ~expected_optimized:(pair_prim2 z_prim pair_z_z_prim) + >>=? fun ctxt -> + (* Readable: Pair 0 0 0 0; Optimized: {0; 0; 0; 0} *) + pair_ty nat_ty pair_nat_pair_nat_nat_ty + >>??= fun pair_nat_pair_nat_pair_nat_nat_ty -> + test_unparse_data + __LOC__ + ctxt + pair_nat_pair_nat_pair_nat_nat_ty + (z, (z, (z, z))) + ~expected_readable:(pair_prim [z_prim; z_prim; z_prim; z_prim]) + ~expected_optimized:(Micheline.Seq (-1, [z_prim; z_prim; z_prim; z_prim])) + >>=? fun _ -> return_unit + +(* Generate all the possible syntaxes for pairs *) +let gen_pairs left right = + [Prim (-1, Script.D_Pair, [left; right], []); Seq (-1, [left; right])] + +(* Generate all the possible syntaxes for combs *) +let rec gen_combs leaf arity = + assert (arity >= 2) ; + if arity = 2 then gen_pairs leaf leaf + else + gen_combs leaf (arity - 1) + |> List.map (fun smaller -> + (match smaller with + | Prim (loc, Script.D_Pair, vs, []) -> + Prim (loc, Script.D_Pair, leaf :: vs, []) + | Seq (loc, vs) -> Seq (loc, leaf :: vs) + | _ -> assert false) + :: gen_pairs leaf smaller) + |> List.flatten + +(* Checks the optimality of the Optimized Micheline representation for combs *) +let test_optimal_comb () = + let open Script_typed_ir in + let leaf_ty = nat_t ~annot:None in + let leaf_mich = Int (-1, Z.zero) in + let leaf_v = Script_int.zero_n in + let size_of_micheline mich = + let canonical = Micheline.strip_locations mich in + ( canonical, + Bytes.length + @@ Data_encoding.Binary.to_bytes_exn Script.expr_encoding canonical ) + in + let check_optimal_comb loc ctxt ty v arity = + wrap_error_lwt + ( Script_ir_translator.unparse_data + ctxt + Script_ir_translator.Optimized + ty + v + >>=? fun (unparsed, ctxt) -> + let (unparsed_canonical, unparsed_size) = size_of_micheline unparsed in + List.iter_es (fun other_repr -> + let (other_repr_canonical, other_repr_size) = + size_of_micheline other_repr + in + if other_repr_size < unparsed_size then + Alcotest.failf + "At %s, for comb of arity %d, representation %a (size %d \ + bytes) is shorter than representation %a (size %d bytes) \ + returned by unparse_data in Optimized mode" + loc + arity + Michelson_v1_printer.print_expr + other_repr_canonical + other_repr_size + Michelson_v1_printer.print_expr + unparsed_canonical + unparsed_size + else return_unit) + @@ gen_combs leaf_mich arity + >>=? fun () -> return ctxt ) + in + let pair_ty ty1 ty2 = + pair_t (-1) (ty1, None, None) (ty2, None, None) ~annot:None + in + test_context () >>=? fun ctxt -> + pair_ty leaf_ty leaf_ty >>??= fun comb2_ty -> + let comb2_v = (leaf_v, leaf_v) in + check_optimal_comb __LOC__ ctxt comb2_ty comb2_v 2 >>=? fun ctxt -> + pair_ty leaf_ty comb2_ty >>??= fun comb3_ty -> + let comb3_v = (leaf_v, comb2_v) in + check_optimal_comb __LOC__ ctxt comb3_ty comb3_v 3 >>=? fun ctxt -> + pair_ty leaf_ty comb3_ty >>??= fun comb4_ty -> + let comb4_v = (leaf_v, comb3_v) in + check_optimal_comb __LOC__ ctxt comb4_ty comb4_v 4 >>=? fun ctxt -> + pair_ty leaf_ty comb4_ty >>??= fun comb5_ty -> + let comb5_v = (leaf_v, comb4_v) in + check_optimal_comb __LOC__ ctxt comb5_ty comb5_v 5 >>=? fun _ctxt -> + return_unit + +let tests = + [ + Tztest.tztest "test unparse view" `Quick test_unparse_view; + Tztest.tztest + "test typecheck stack overflow error" + `Quick + test_typecheck_stack_overflow; + Tztest.tztest "test comb type parsing" `Quick test_parse_comb_type; + Tztest.tztest "test comb type unparsing" `Quick test_unparse_comb_type; + Tztest.tztest + "test comb comparable type unparsing" + `Quick + test_unparse_comb_comparable_type; + Tztest.tztest "test comb data parsing" `Quick test_parse_comb_data; + Tztest.tztest "test comb data unparsing" `Quick test_unparse_comb_data; + Tztest.tztest "test optimal comb data unparsing" `Quick test_optimal_comb; + Tztest.tztest "test parse address" `Quick test_parse_address; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/test_voting.ml b/src/proto_011_PtHangzH/lib_protocol/test/test_voting.ml new file mode 100644 index 000000000000..a4a48dc8155f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/test_voting.ml @@ -0,0 +1,1129 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (voting) + Invocation: dune exec src/proto_alpha/lib_protocol/test/main.exe -- test "^voting$" + Subject: On the voting process. +*) + +open Protocol + +(* missing stuff in Alpha_context.Vote *) +let ballots_zero = Alpha_context.Vote.{yay = 0l; nay = 0l; pass = 0l} + +let ballots_equal b1 b2 = + Alpha_context.Vote.(b1.yay = b2.yay && b1.nay = b2.nay && b1.pass = b2.pass) + +let ballots_pp ppf v = + Alpha_context.Vote.( + Format.fprintf ppf "{ yay = %ld ; nay = %ld ; pass = %ld" v.yay v.nay v.pass) + +(* constants and ratios used in voting: + percent_mul denotes the percent multiplier + initial_participation is 7000 that is, 7/10 * percent_mul + the participation EMA ratio pr_ema_weight / den = 7 / 10 + the participation ratio pr_num / den = 2 / 10 + note: we use the same denominator for both participation EMA and participation rate. + supermajority rate is s_num / s_den = 8 / 10 *) +let percent_mul = 100_00 + +let den = 10 + +let initial_participation_num = 7 + +let initial_participation = initial_participation_num * percent_mul / den + +let pr_ema_weight = 8 + +let pr_num = den - pr_ema_weight + +let s_num = 8 + +let s_den = 10 + +let qr_min_num = 2 + +let qr_max_num = 7 + +let expected_qr_num participation_ema = + let participation_ema = Int32.to_int participation_ema in + let participation_ema = participation_ema * den / percent_mul in + Float.( + of_int qr_min_num + +. of_int participation_ema + *. (of_int qr_max_num -. of_int qr_min_num) + /. of_int den) + +(* Protocol_hash.zero is "PrihK96nBAFSxVL1GLJTVhu9YnzkMFiBeuJRPA8NwuZVZCE1L6i" *) +let protos = + Array.map + (fun s -> Protocol_hash.of_b58check_exn s) + [| + "ProtoALphaALphaALphaALphaALphaALphaALpha61322gcLUGH"; + "ProtoALphaALphaALphaALphaALphaALphaALphabc2a7ebx6WB"; + "ProtoALphaALphaALphaALphaALphaALphaALpha84efbeiF6cm"; + "ProtoALphaALphaALphaALphaALphaALphaALpha91249Z65tWS"; + "ProtoALphaALphaALphaALphaALphaALphaALpha537f5h25LnN"; + "ProtoALphaALphaALphaALphaALphaALphaALpha5c8fefgDYkr"; + "ProtoALphaALphaALphaALphaALphaALphaALpha3f31feSSarC"; + "ProtoALphaALphaALphaALphaALphaALphaALphabe31ahnkxSC"; + "ProtoALphaALphaALphaALphaALphaALphaALphabab3bgRb7zQ"; + "ProtoALphaALphaALphaALphaALphaALphaALphaf8d39cctbpk"; + "ProtoALphaALphaALphaALphaALphaALphaALpha3b981byuYxD"; + "ProtoALphaALphaALphaALphaALphaALphaALphaa116bccYowi"; + "ProtoALphaALphaALphaALphaALphaALphaALphacce68eHqboj"; + "ProtoALphaALphaALphaALphaALphaALphaALpha225c7YrWwR7"; + "ProtoALphaALphaALphaALphaALphaALphaALpha58743cJL6FG"; + "ProtoALphaALphaALphaALphaALphaALphaALphac91bcdvmJFR"; + "ProtoALphaALphaALphaALphaALphaALphaALpha1faaadhV7oW"; + "ProtoALphaALphaALphaALphaALphaALphaALpha98232gD94QJ"; + "ProtoALphaALphaALphaALphaALphaALphaALpha9d1d8cijvAh"; + "ProtoALphaALphaALphaALphaALphaALphaALphaeec52dKF6Gx"; + "ProtoALphaALphaALphaALphaALphaALphaALpha841f2cQqajX"; + |] + +(** helper functions *) + +let assert_period_kind expected_kind kind loc = + if Stdlib.(expected_kind = kind) then return_unit + else + Alcotest.failf + "%s - Unexpected voting period kind - expected %a, got %a" + loc + Alpha_context.Voting_period.pp_kind + expected_kind + Alpha_context.Voting_period.pp_kind + kind + +let assert_period_index expected_index index loc = + if expected_index = index then return_unit + else + Alcotest.failf + "%s - Unexpected voting period index - expected %ld, got %ld" + loc + expected_index + index + +let assert_period_position expected_position position loc = + if position = expected_position then return_unit + else + Alcotest.failf + "%s - Unexpected voting period position blocks - expected %ld, got %ld" + loc + expected_position + position + +let assert_period_remaining expected_remaining remaining loc = + if remaining = expected_remaining then return_unit + else + Alcotest.failf + "%s - Unexpected voting period remaining blocks - expected %ld, got %ld" + loc + expected_remaining + remaining + +let assert_period ?expected_kind ?expected_index ?expected_position + ?expected_remaining b loc = + Context.Vote.get_current_period (B b) + >>=? fun {voting_period; position; remaining} -> + (if Option.is_some expected_kind then + assert_period_kind + (WithExceptions.Option.get ~loc:__LOC__ expected_kind) + voting_period.kind + loc + else return_unit) + >>=? fun () -> + (if Option.is_some expected_index then + assert_period_index + (WithExceptions.Option.get ~loc:__LOC__ expected_index) + voting_period.index + loc + else return_unit) + >>=? fun () -> + (if Option.is_some expected_position then + assert_period_position + (WithExceptions.Option.get ~loc:__LOC__ expected_position) + position + loc + else return_unit) + >>=? fun () -> + if Option.is_some expected_remaining then + assert_period_remaining + (WithExceptions.Option.get ~loc:__LOC__ expected_remaining) + remaining + loc + else return_unit + +let mk_contracts_from_pkh pkh_list = + List.map Alpha_context.Contract.implicit_contract pkh_list + +(* get the list of delegates and the list of their rolls from listings *) +let get_delegates_and_rolls_from_listings b = + Context.Vote.get_listings (B b) >|=? fun l -> + (mk_contracts_from_pkh (List.map fst l), List.map snd l) + +(* compute the rolls of each delegate *) +let get_rolls b delegates loc = + Context.Vote.get_listings (B b) >>=? fun l -> + List.map_es + (fun delegate -> + Context.Contract.pkh delegate >>=? fun pkh -> + match List.find_opt (fun (del, _) -> del = pkh) l with + | None -> failwith "%s - Missing delegate" loc + | Some (_, rolls) -> return rolls) + delegates + +(* Checks that the listings are populated *) +let assert_listings_not_empty b ~loc = + Context.Vote.get_listings (B b) >>=? function + | [] -> failwith "Unexpected empty listings (%s)" loc + | _ -> return_unit + +let bake_until_first_block_of_next_period b = + Context.Vote.get_current_period (B b) >>=? fun {remaining; _} -> + Block.bake_n Int32.(add remaining one |> to_int) b + +(** A normal and successful vote sequence. *) +let test_successful_vote num_delegates () = + let open Alpha_context in + let min_proposal_quorum = Int32.(of_int @@ (100_00 / num_delegates)) in + Context.init ~min_proposal_quorum num_delegates >>=? fun (b, _) -> + (* no ballots in proposal period *) + Context.Vote.get_ballots (B b) >>=? fun v -> + Assert.equal + ~loc:__LOC__ + ballots_equal + "Unexpected ballots" + ballots_pp + v + ballots_zero + >>=? fun () -> + (* no ballots in proposal period *) + (Context.Vote.get_ballot_list (B b) >>=? function + | [] -> return_unit + | _ -> failwith "%s - Unexpected ballot list" __LOC__) + >>=? fun () -> + (* Last baked block is first block of period Proposal *) + assert_period + ~expected_kind:Proposal + ~expected_index:0l + ~expected_position:0l + b + __LOC__ + >>=? fun () -> + assert_listings_not_empty b ~loc:__LOC__ >>=? fun () -> + (* participation EMA starts at initial_participation *) + Context.Vote.get_participation_ema b >>=? fun v -> + Assert.equal_int ~loc:__LOC__ initial_participation (Int32.to_int v) + >>=? fun () -> + (* listings must be populated in proposal period *) + assert_listings_not_empty b ~loc:__LOC__ >>=? fun () -> + (* beginning of proposal, denoted by _p1; + take a snapshot of the active delegates and their rolls from listings *) + get_delegates_and_rolls_from_listings b >>=? fun (delegates_p1, rolls_p1) -> + (* no proposals at the beginning of proposal period *) + Context.Vote.get_proposals (B b) >>=? fun ps -> + (if Environment.Protocol_hash.Map.is_empty ps then return_unit + else failwith "%s - Unexpected proposals" __LOC__) + >>=? fun () -> + (* no current proposal during proposal period *) + (Context.Vote.get_current_proposal (B b) >>=? function + | None -> return_unit + | Some _ -> failwith "%s - Unexpected proposal" __LOC__) + >>=? fun () -> + let del1 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates_p1 0 + in + let del2 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates_p1 1 + in + let props = + List.map (fun i -> protos.(i)) (2 -- Constants.max_proposals_per_delegate) + in + Op.proposals (B b) del1 (Protocol_hash.zero :: props) >>=? fun ops1 -> + Op.proposals (B b) del2 [Protocol_hash.zero] >>=? fun ops2 -> + Block.bake ~operations:[ops1; ops2] b >>=? fun b -> + (* proposals are now populated *) + Context.Vote.get_proposals (B b) >>=? fun ps -> + (* correctly count the double proposal for zero *) + (let weight = + Int32.add + (WithExceptions.Option.get ~loc:__LOC__ @@ List.nth rolls_p1 0) + (WithExceptions.Option.get ~loc:__LOC__ @@ List.nth rolls_p1 1) + in + match Environment.Protocol_hash.(Map.find zero ps) with + | Some v -> + if v = weight then return_unit + else failwith "%s - Wrong count %ld is not %ld" __LOC__ v weight + | None -> failwith "%s - Missing proposal" __LOC__) + >>=? fun () -> + (* proposing more than maximum_proposals fails *) + Op.proposals (B b) del1 (Protocol_hash.zero :: props) >>=? fun ops -> + Block.bake ~operations:[ops] b >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Amendment.Too_many_proposals -> true + | _ -> false) + >>=? fun () -> + (* proposing less than one proposal fails *) + Op.proposals (B b) del1 [] >>=? fun ops -> + Block.bake ~operations:[ops] b >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Amendment.Empty_proposal -> true + | _ -> false) + >>=? fun () -> + (* first block of exploration period *) + bake_until_first_block_of_next_period b >>=? fun b -> + (* next block is first block of exploration *) + assert_period ~expected_kind:Exploration ~expected_index:1l b __LOC__ + >>=? fun () -> + assert_listings_not_empty b ~loc:__LOC__ >>=? fun () -> + (* listings must be populated in proposal period before moving to exploration period *) + assert_listings_not_empty b ~loc:__LOC__ >>=? fun () -> + (* beginning of exploration period, denoted by _p2; + take a snapshot of the active delegates and their rolls from listings *) + get_delegates_and_rolls_from_listings b >>=? fun (delegates_p2, rolls_p2) -> + (* no proposals during exploration period *) + Context.Vote.get_proposals (B b) >>=? fun ps -> + (if Environment.Protocol_hash.Map.is_empty ps then return_unit + else failwith "%s - Unexpected proposals" __LOC__) + >>=? fun () -> + (* current proposal must be set during exploration period *) + (Context.Vote.get_current_proposal (B b) >>=? function + | Some v -> + if Protocol_hash.(equal zero v) then return_unit + else failwith "%s - Wrong proposal" __LOC__ + | None -> failwith "%s - Missing proposal" __LOC__) + >>=? fun () -> + (* unanimous vote: all delegates --active when p2 started-- vote *) + List.map_es + (fun del -> Op.ballot (B b) del Protocol_hash.zero Vote.Yay) + delegates_p2 + >>=? fun operations -> + Block.bake ~operations b >>=? fun b -> + Op.ballot (B b) del1 Protocol_hash.zero Vote.Nay >>=? fun op -> + Block.bake ~operations:[op] b >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (function + | Amendment.Unauthorized_ballot -> true + | _ -> false) + >>=? fun () -> + (* Allocate votes from weight (rolls) of active delegates *) + List.fold_left (fun acc v -> Int32.(add v acc)) 0l rolls_p2 + |> fun rolls_sum -> + (* # of Yay rolls in ballots matches votes of the delegates *) + Context.Vote.get_ballots (B b) >>=? fun v -> + Assert.equal + ~loc:__LOC__ + ballots_equal + "Unexpected ballots" + ballots_pp + v + Vote.{yay = rolls_sum; nay = 0l; pass = 0l} + >>=? fun () -> + (* One Yay ballot per delegate *) + (Context.Vote.get_ballot_list (B b) >>=? function + | [] -> failwith "%s - Unexpected empty ballot list" __LOC__ + | l -> + List.iter_es + (fun delegate -> + Context.Contract.pkh delegate >>=? fun pkh -> + match List.find_opt (fun (del, _) -> del = pkh) l with + | None -> failwith "%s - Missing delegate" __LOC__ + | Some (_, Vote.Yay) -> return_unit + | Some _ -> failwith "%s - Wrong ballot" __LOC__) + delegates_p2) + >>=? fun () -> + (* skip to cooldown period *) + bake_until_first_block_of_next_period b >>=? fun b -> + assert_period ~expected_index:2l ~expected_kind:Cooldown b __LOC__ + >>=? fun () -> + (* no ballots in cooldown period *) + Context.Vote.get_ballots (B b) >>=? fun v -> + Assert.equal + ~loc:__LOC__ + ballots_equal + "Unexpected ballots" + ballots_pp + v + ballots_zero + >>=? fun () -> + (* listings must be populated in cooldown period before moving to promotion_vote period *) + assert_listings_not_empty b ~loc:__LOC__ >>=? fun () -> + (* skip to promotion period *) + bake_until_first_block_of_next_period b >>=? fun b -> + assert_period ~expected_kind:Promotion ~expected_index:3l b __LOC__ + >>=? fun () -> + assert_listings_not_empty b ~loc:__LOC__ >>=? fun () -> + (* period 3 *) + (* listings must be populated in promotion period *) + assert_listings_not_empty b ~loc:__LOC__ >>=? fun () -> + (* beginning of promotion period, denoted by _p4; + take a snapshot of the active delegates and their rolls from listings *) + get_delegates_and_rolls_from_listings b >>=? fun (delegates_p4, rolls_p4) -> + (* no proposals during promotion period *) + Context.Vote.get_proposals (B b) >>=? fun ps -> + (if Environment.Protocol_hash.Map.is_empty ps then return_unit + else failwith "%s - Unexpected proposals" __LOC__) + >>=? fun () -> + (* current proposal must be set during promotion period *) + (Context.Vote.get_current_proposal (B b) >>=? function + | Some v -> + if Protocol_hash.(equal zero v) then return_unit + else failwith "%s - Wrong proposal" __LOC__ + | None -> failwith "%s - Missing proposal" __LOC__) + >>=? fun () -> + (* unanimous vote: all delegates --active when p4 started-- vote *) + List.map_es + (fun del -> Op.ballot (B b) del Protocol_hash.zero Vote.Yay) + delegates_p4 + >>=? fun operations -> + Block.bake ~operations b >>=? fun b -> + List.fold_left (fun acc v -> Int32.(add v acc)) 0l rolls_p4 + |> fun rolls_sum -> + (* # of Yays in ballots matches rolls of the delegate *) + Context.Vote.get_ballots (B b) >>=? fun v -> + Assert.equal + ~loc:__LOC__ + ballots_equal + "Unexpected ballots" + ballots_pp + v + Vote.{yay = rolls_sum; nay = 0l; pass = 0l} + >>=? fun () -> + (* One Yay ballot per delegate *) + (Context.Vote.get_ballot_list (B b) >>=? function + | [] -> failwith "%s - Unexpected empty ballot list" __LOC__ + | l -> + List.iter_es + (fun delegate -> + Context.Contract.pkh delegate >>=? fun pkh -> + match List.find_opt (fun (del, _) -> del = pkh) l with + | None -> failwith "%s - Missing delegate" __LOC__ + | Some (_, Vote.Yay) -> return_unit + | Some _ -> failwith "%s - Wrong ballot" __LOC__) + delegates_p4) + >>=? fun () -> + (* skip to end of promotion period and activation*) + bake_until_first_block_of_next_period b >>=? fun b -> + assert_period ~expected_kind:Adoption ~expected_index:4l b __LOC__ + >>=? fun () -> + (* skip to end of Adoption period and bake 1 more to activate *) + bake_until_first_block_of_next_period b >>=? fun b -> + assert_period ~expected_kind:Proposal ~expected_index:5l b __LOC__ + >>=? fun () -> + assert_listings_not_empty b ~loc:__LOC__ >>=? fun () -> + (* zero is the new protocol (before the vote this value is unset) *) + Context.Vote.get_protocol b >>= fun p -> + Assert.equal + ~loc:__LOC__ + Protocol_hash.equal + "Unexpected proposal" + Protocol_hash.pp + p + Protocol_hash.zero + >>=? fun () -> return_unit + +(* given a list of active delegates, + return the first k active delegates with which one can have quorum, that is: + their roll sum divided by the total roll sum is bigger than pr_ema_weight/den *) +let get_smallest_prefix_voters_for_quorum active_delegates active_rolls + participation_ema = + let expected_quorum = expected_qr_num participation_ema in + List.fold_left (fun acc v -> Int32.(add v acc)) 0l active_rolls + |> fun active_rolls_sum -> + let rec loop delegates rolls sum selected = + match (delegates, rolls) with + | ([], []) -> selected + | (del :: delegates, del_rolls :: rolls) -> + if + den * sum + < Float.to_int (expected_quorum *. Int32.to_float active_rolls_sum) + then + loop delegates rolls (sum + Int32.to_int del_rolls) (del :: selected) + else selected + | (_, _) -> [] + in + loop active_delegates active_rolls 0 [] + +let get_expected_participation_ema rolls voter_rolls old_participation_ema = + (* formula to compute the updated participation_ema *) + let get_updated_participation_ema old_participation_ema participation = + ((pr_ema_weight * Int32.to_int old_participation_ema) + + (pr_num * participation)) + / den + in + List.fold_left (fun acc v -> Int32.(add v acc)) 0l rolls |> fun rolls_sum -> + List.fold_left (fun acc v -> Int32.(add v acc)) 0l voter_rolls + |> fun voter_rolls_sum -> + let participation = + Int32.to_int voter_rolls_sum * percent_mul / Int32.to_int rolls_sum + in + get_updated_participation_ema old_participation_ema participation + +(** If not enough quorum + -- get_updated_participation_ema < pr_ema_weight/den -- + in exploration, go back to proposal period. *) +let test_not_enough_quorum_in_exploration num_delegates () = + let min_proposal_quorum = Int32.(of_int @@ (100_00 / num_delegates)) in + Context.init ~min_proposal_quorum num_delegates >>=? fun (b, delegates) -> + (* proposal period *) + let open Alpha_context in + assert_period ~expected_kind:Proposal b __LOC__ >>=? fun () -> + let proposer = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates 0 + in + Op.proposals (B b) proposer [Protocol_hash.zero] >>=? fun ops -> + Block.bake ~operations:[ops] b >>=? fun b -> + (* skip to exploration period *) + bake_until_first_block_of_next_period b >>=? fun b -> + (* we moved to an exploration period with one proposal *) + assert_period ~expected_kind:Exploration b __LOC__ >>=? fun () -> + Context.Vote.get_participation_ema b >>=? fun initial_participation_ema -> + (* beginning of exploration period, denoted by _p2; + take a snapshot of the active delegates and their rolls from listings *) + get_delegates_and_rolls_from_listings b >>=? fun (delegates_p2, rolls_p2) -> + Context.Vote.get_participation_ema b >>=? fun participation_ema -> + get_smallest_prefix_voters_for_quorum delegates_p2 rolls_p2 participation_ema + |> fun voters -> + (* take the first two voters out so there cannot be quorum *) + let voters_without_quorum = + WithExceptions.Option.get ~loc:__LOC__ @@ List.tl voters + in + get_rolls b voters_without_quorum __LOC__ + >>=? fun voters_rolls_in_exploration -> + (* all voters_without_quorum vote, for yays; + no nays, so supermajority is satisfied *) + List.map_es + (fun del -> Op.ballot (B b) del Protocol_hash.zero Vote.Yay) + voters_without_quorum + >>=? fun operations -> + Block.bake ~operations b >>=? fun b -> + (* bake to next period *) + bake_until_first_block_of_next_period b >>=? fun b -> + (* we move back to the proposal period because not enough quorum *) + assert_period ~expected_kind:Proposal b __LOC__ >>=? fun () -> + (* check participation_ema update *) + get_expected_participation_ema + rolls_p2 + voters_rolls_in_exploration + initial_participation_ema + |> fun expected_participation_ema -> + Context.Vote.get_participation_ema b >>=? fun new_participation_ema -> + (* assert the formula to calculate participation_ema is correct *) + Assert.equal_int + ~loc:__LOC__ + expected_participation_ema + (Int32.to_int new_participation_ema) + >>=? fun () -> return_unit + +(** If not enough quorum + -- get_updated_participation_ema < pr_ema_weight/den -- + In promotion period, go back to proposal period. *) +let test_not_enough_quorum_in_promotion num_delegates () = + let min_proposal_quorum = Int32.(of_int @@ (100_00 / num_delegates)) in + Context.init ~min_proposal_quorum num_delegates >>=? fun (b, delegates) -> + assert_period ~expected_kind:Proposal b __LOC__ >>=? fun () -> + let proposer = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates 0 + in + Op.proposals (B b) proposer [Protocol_hash.zero] >>=? fun ops -> + Block.bake ~operations:[ops] b >>=? fun b -> + (* skip to exploration period *) + bake_until_first_block_of_next_period b >>=? fun b -> + (* we moved to an exploration period with one proposal *) + assert_period ~expected_kind:Exploration b __LOC__ >>=? fun () -> + (* beginning of exploration period, denoted by _p2; + take a snapshot of the active delegates and their rolls from listings *) + get_delegates_and_rolls_from_listings b >>=? fun (delegates_p2, rolls_p2) -> + Context.Vote.get_participation_ema b >>=? fun participation_ema -> + get_smallest_prefix_voters_for_quorum delegates_p2 rolls_p2 participation_ema + |> fun voters -> + let open Alpha_context in + (* all voters vote, for yays; + no nays, so supermajority is satisfied *) + List.map_es + (fun del -> Op.ballot (B b) del Protocol_hash.zero Vote.Yay) + voters + >>=? fun operations -> + Block.bake ~operations b >>=? fun b -> + (* skip to first block cooldown period *) + bake_until_first_block_of_next_period b >>=? fun b -> + (* we move to cooldown because we have supermajority and enough quorum *) + assert_period ~expected_kind:Cooldown b __LOC__ >>=? fun () -> + (* skip to first block of promotion period *) + bake_until_first_block_of_next_period b >>=? fun b -> + assert_period ~expected_kind:Promotion b __LOC__ + (* bake_until_first_block_of_next_period ~offset:1l b + * >>=? fun b -> + * assert_period ~expected_kind:Promotion b __LOC__ *) + >>=? + fun () -> + Context.Vote.get_participation_ema b >>=? fun initial_participation_ema -> + (* beginning of promotion period, denoted by _p4; + take a snapshot of the active delegates and their rolls from listings *) + get_delegates_and_rolls_from_listings b >>=? fun (delegates_p4, rolls_p4) -> + Context.Vote.get_participation_ema b >>=? fun participation_ema -> + get_smallest_prefix_voters_for_quorum delegates_p4 rolls_p4 participation_ema + |> fun voters -> + (* take the first voter out so there cannot be quorum *) + let voters_without_quorum = + WithExceptions.Option.get ~loc:__LOC__ @@ List.tl voters + in + get_rolls b voters_without_quorum __LOC__ >>=? fun voter_rolls -> + (* all voters_without_quorum vote, for yays; + no nays, so supermajority is satisfied *) + List.map_es + (fun del -> Op.ballot (B b) del Protocol_hash.zero Vote.Yay) + voters_without_quorum + >>=? fun operations -> + Block.bake ~operations b >>=? fun b -> + (* skip to end of promotion period *) + bake_until_first_block_of_next_period b >>=? fun b -> + get_expected_participation_ema rolls_p4 voter_rolls initial_participation_ema + |> fun expected_participation_ema -> + Context.Vote.get_participation_ema b >>=? fun new_participation_ema -> + (* assert the formula to calculate participation_ema is correct *) + Assert.equal_int + ~loc:__LOC__ + expected_participation_ema + (Int32.to_int new_participation_ema) + >>=? fun () -> + (* we move back to the proposal period because not enough quorum *) + assert_period ~expected_kind:Proposal b __LOC__ >>=? fun () -> + assert_listings_not_empty b ~loc:__LOC__ >>=? fun () -> return_unit + +(** Identical proposals (identified by their hash) must be counted as + one. *) +let test_multiple_identical_proposals_count_as_one () = + Context.init 1 >>=? fun (b, delegates) -> + assert_period ~expected_kind:Proposal b __LOC__ >>=? fun () -> + let proposer = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd delegates in + Op.proposals (B b) proposer [Protocol_hash.zero; Protocol_hash.zero] + >>=? fun ops -> + Block.bake ~operations:[ops] b >>=? fun b -> + (* compute the weight of proposals *) + Context.Vote.get_proposals (B b) >>=? fun ps -> + (* compute the rolls of proposer *) + Context.Contract.pkh proposer >>=? fun pkh -> + Context.Vote.get_listings (B b) >>=? fun l -> + (match List.find_opt (fun (del, _) -> del = pkh) l with + | None -> failwith "%s - Missing delegate" __LOC__ + | Some (_, proposer_rolls) -> return proposer_rolls) + >>=? fun proposer_rolls -> + (* correctly count the double proposal for zero as one proposal *) + let expected_weight_proposer = proposer_rolls in + match Environment.Protocol_hash.(Map.find zero ps) with + | Some v -> + if v = expected_weight_proposer then return_unit + else + failwith + "%s - Wrong count %ld is not %ld; identical proposals count as one" + __LOC__ + v + expected_weight_proposer + | None -> failwith "%s - Missing proposal" __LOC__ + +(** Assume the initial balance of allocated by Context.init is at + least 4 times the value of the tokens_per_roll constant. *) +let test_supermajority_in_proposal there_is_a_winner () = + let min_proposal_quorum = 0l in + Context.init ~min_proposal_quorum ~initial_balances:[1L; 1L; 1L] 10 + >>=? fun (b, delegates) -> + Context.get_constants (B b) + >>=? fun { + parametric = + {blocks_per_cycle; tokens_per_roll; blocks_per_voting_period; _}; + _; + } -> + let del1 = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates 0 in + let del2 = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates 1 in + let del3 = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates 2 in + List.map_es (fun del -> Context.Contract.pkh del) [del1; del2; del3] + >>=? fun pkhs -> + let policy = Block.Excluding pkhs in + Op.transaction + (B b) + (WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates 3) + del1 + tokens_per_roll + >>=? fun op1 -> + Op.transaction + (B b) + (WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates 4) + del2 + tokens_per_roll + >>=? fun op2 -> + (if there_is_a_winner then Test_tez.Tez.( *? ) tokens_per_roll 3L + else Test_tez.Tez.( *? ) tokens_per_roll 2L) + >>?= fun bal3 -> + Op.transaction + (B b) + (WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates 5) + del3 + bal3 + >>=? fun op3 -> + Block.bake ~policy ~operations:[op1; op2; op3] b >>=? fun b -> + (* we let one voting period pass; we make sure that: + - the three selected delegates remain active by re-registering as delegates + - their number of rolls do not change *) + List.fold_left_es + (fun b _ -> + List.map_es + (fun del -> + Context.Contract.pkh del >>=? fun pkh -> + Op.delegation (B b) del (Some pkh)) + delegates + >>=? fun ops -> + Block.bake ~policy ~operations:ops b >>=? fun b -> + Block.bake_until_cycle_end ~policy b) + b + (1 -- Int32.to_int (Int32.div blocks_per_voting_period blocks_per_cycle)) + >>=? fun b -> + (* make the proposals *) + Op.proposals (B b) del1 [protos.(0)] >>=? fun ops1 -> + Op.proposals (B b) del2 [protos.(0)] >>=? fun ops2 -> + Op.proposals (B b) del3 [protos.(1)] >>=? fun ops3 -> + Block.bake ~policy ~operations:[ops1; ops2; ops3] b >>=? fun b -> + bake_until_first_block_of_next_period b >>=? fun b -> + (* we remain in the proposal period when there is no winner, + otherwise we move to the exploration period *) + (if there_is_a_winner then assert_period ~expected_kind:Exploration b __LOC__ + else assert_period ~expected_kind:Proposal b __LOC__) + >>=? fun () -> return_unit + +(** After one voting period, if [has_quorum] then the period kind must + have been the cooldown vote. Otherwise, it should have remained in + place in the proposal period. *) +let test_quorum_in_proposal has_quorum () = + let total_tokens = 32_000_000_000_000L in + let half_tokens = Int64.div total_tokens 2L in + Context.init ~initial_balances:[1L; half_tokens; half_tokens] 3 + >>=? fun (b, delegates) -> + Context.get_constants (B b) + >>=? fun { + parametric = + { + blocks_per_cycle; + min_proposal_quorum; + blocks_per_voting_period; + _; + }; + _; + } -> + let del1 = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates 0 in + let del2 = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates 1 in + List.map_es (fun del -> Context.Contract.pkh del) [del1; del2] + >>=? fun pkhs -> + let policy = Block.Excluding pkhs in + let quorum = + if has_quorum then Int64.of_int32 min_proposal_quorum + else Int64.(sub (of_int32 min_proposal_quorum) 10L) + in + let bal = + Int64.(div (mul total_tokens quorum) 100_00L) |> Test_tez.Tez.of_mutez_exn + in + Op.transaction (B b) del2 del1 bal >>=? fun op2 -> + Block.bake ~policy ~operations:[op2] b >>=? fun b -> + (* we let one voting period pass; we make sure that: + - the two selected delegates remain active by re-registering as delegates + - their number of rolls do not change *) + List.fold_left_es + (fun b _ -> + List.map_es + (fun del -> + Context.Contract.pkh del >>=? fun pkh -> + Op.delegation (B b) del (Some pkh)) + [del1; del2] + >>=? fun ops -> + Block.bake ~policy ~operations:ops b >>=? fun b -> + Block.bake_until_cycle_end ~policy b) + b + (1 -- Int32.to_int (Int32.div blocks_per_voting_period blocks_per_cycle)) + >>=? fun b -> + (* make the proposal *) + Op.proposals (B b) del1 [protos.(0)] >>=? fun ops -> + Block.bake ~policy ~operations:[ops] b >>=? fun b -> + bake_until_first_block_of_next_period b >>=? fun b -> + (* we remain in the proposal period when there is no quorum, + otherwise we move to the cooldown vote period *) + (if has_quorum then assert_period ~expected_kind:Exploration b __LOC__ + else assert_period ~expected_kind:Proposal b __LOC__) + >>=? fun () -> return_unit + +(** If a supermajority is reached, then the voting period must be + reached. Otherwise, it remains in proposal period. *) +let test_supermajority_in_exploration supermajority () = + let min_proposal_quorum = Int32.(of_int @@ (100_00 / 100)) in + Context.init ~min_proposal_quorum 100 >>=? fun (b, delegates) -> + let del1 = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates 0 in + let proposal = protos.(0) in + Op.proposals (B b) del1 [proposal] >>=? fun ops1 -> + Block.bake ~operations:[ops1] b >>=? fun b -> + bake_until_first_block_of_next_period b >>=? fun b -> + (* move to exploration *) + assert_period ~expected_kind:Exploration b __LOC__ >>=? fun () -> + (* assert our proposal won *) + (Context.Vote.get_current_proposal (B b) >>=? function + | Some v -> + if Protocol_hash.(equal proposal v) then return_unit + else failwith "%s - Wrong proposal" __LOC__ + | None -> failwith "%s - Missing proposal" __LOC__) + >>=? fun () -> + (* beginning of exploration period, denoted by _p2; + take a snapshot of the active delegates and their rolls from listings *) + get_delegates_and_rolls_from_listings b >>=? fun (delegates_p2, _rolls_p2) -> + (* supermajority means [num_yays / (num_yays + num_nays) >= s_num / s_den], + which is equivalent with [num_yays >= num_nays * s_num / (s_den - s_num)] *) + let num_delegates = List.length delegates_p2 in + let num_nays = num_delegates / 5 in + (* any smaller number will do as well *) + let num_yays = num_nays * s_num / (s_den - s_num) in + (* majority/minority vote depending on the [supermajority] parameter *) + let num_yays = if supermajority then num_yays else num_yays - 1 in + let open Alpha_context in + let (nays_delegates, rest) = List.split_n num_nays delegates_p2 in + let (yays_delegates, _) = List.split_n num_yays rest in + List.map_es (fun del -> Op.ballot (B b) del proposal Vote.Yay) yays_delegates + >>=? fun operations_yays -> + List.map_es (fun del -> Op.ballot (B b) del proposal Vote.Nay) nays_delegates + >>=? fun operations_nays -> + let operations = operations_yays @ operations_nays in + Block.bake ~operations b >>=? fun b -> + bake_until_first_block_of_next_period b >>=? fun b -> + (if supermajority then assert_period ~expected_kind:Cooldown b __LOC__ + else assert_period ~expected_kind:Proposal b __LOC__) + >>=? fun () -> return_unit + +(** Test also how the selection scales: all delegates propose max + proposals. *) +let test_no_winning_proposal num_delegates () = + let min_proposal_quorum = Int32.(of_int @@ (100_00 / num_delegates)) in + Context.init ~min_proposal_quorum num_delegates >>=? fun (b, _) -> + (* beginning of proposal, denoted by _p1; + take a snapshot of the active delegates and their rolls from listings *) + get_delegates_and_rolls_from_listings b >>=? fun (delegates_p1, _rolls_p1) -> + let open Alpha_context in + let props = + List.map (fun i -> protos.(i)) (1 -- Constants.max_proposals_per_delegate) + in + (* all delegates active in p1 propose the same proposals *) + List.map_es (fun del -> Op.proposals (B b) del props) delegates_p1 + >>=? fun ops_list -> + Block.bake ~operations:ops_list b >>=? fun b -> + (* skip to exploration period *) + bake_until_first_block_of_next_period b >>=? fun b -> + (* we stay in the same proposal period because no winning proposal *) + assert_period ~expected_kind:Proposal b __LOC__ >>=? fun () -> return_unit + +(** Vote to pass with maximum possible participation_ema (100%), it is + sufficient for the vote quorum to be equal or greater than the + maximum quorum cap. *) +let test_quorum_capped_maximum num_delegates () = + let min_proposal_quorum = Int32.(of_int @@ (100_00 / num_delegates)) in + Context.init ~min_proposal_quorum num_delegates >>=? fun (b, delegates) -> + (* set the participation EMA to 100% *) + Context.Vote.set_participation_ema b 100_00l >>= fun b -> + Context.get_constants (B b) >>=? fun {parametric = {quorum_max; _}; _} -> + (* proposal period *) + let open Alpha_context in + assert_period ~expected_kind:Proposal b __LOC__ >>=? fun () -> + (* propose a new protocol *) + let protocol = Protocol_hash.zero in + let proposer = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates 0 + in + Op.proposals (B b) proposer [protocol] >>=? fun ops -> + Block.bake ~operations:[ops] b >>=? fun b -> + (* skip to exploration period *) + bake_until_first_block_of_next_period b >>=? fun b -> + (* we moved to an exploration period with one proposal *) + assert_period ~expected_kind:Exploration b __LOC__ >>=? fun () -> + (* take percentage of the delegates equal or greater than quorum_max *) + let minimum_to_pass = + Float.of_int (List.length delegates) + *. Int32.(to_float quorum_max) + /. 100_00. + |> Float.ceil |> Float.to_int + in + let voters = List.take_n minimum_to_pass delegates in + (* all voters vote for yays; no nays, so supermajority is satisfied *) + List.map_es (fun del -> Op.ballot (B b) del protocol Vote.Yay) voters + >>=? fun operations -> + Block.bake ~operations b >>=? fun b -> + (* skip to next period *) + bake_until_first_block_of_next_period b >>=? fun b -> + (* expect to move to cooldown because we have supermajority and enough quorum *) + assert_period ~expected_kind:Cooldown b __LOC__ + +(** Vote to pass with minimum possible participation_ema (0%), it is + sufficient for the vote quorum to be equal or greater than the + minimum quorum cap. *) +let test_quorum_capped_minimum num_delegates () = + let min_proposal_quorum = Int32.(of_int @@ (100_00 / num_delegates)) in + Context.init ~min_proposal_quorum num_delegates >>=? fun (b, delegates) -> + (* set the participation EMA to 0% *) + Context.Vote.set_participation_ema b 0l >>= fun b -> + Context.get_constants (B b) >>=? fun {parametric = {quorum_min; _}; _} -> + (* proposal period *) + let open Alpha_context in + assert_period ~expected_kind:Proposal b __LOC__ >>=? fun () -> + (* propose a new protocol *) + let protocol = Protocol_hash.zero in + let proposer = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth delegates 0 + in + Op.proposals (B b) proposer [protocol] >>=? fun ops -> + Block.bake ~operations:[ops] b >>=? fun b -> + (* skip to exploration period *) + bake_until_first_block_of_next_period b >>=? fun b -> + (* we moved to an exploration period with one proposal *) + assert_period ~expected_kind:Exploration b __LOC__ >>=? fun () -> + (* take percentage of the delegates equal or greater than quorum_min *) + let minimum_to_pass = + Float.of_int (List.length delegates) + *. Int32.(to_float quorum_min) + /. 100_00. + |> Float.ceil |> Float.to_int + in + let voters = List.take_n minimum_to_pass delegates in + (* all voters vote for yays; no nays, so supermajority is satisfied *) + List.map_es (fun del -> Op.ballot (B b) del protocol Vote.Yay) voters + >>=? fun operations -> + Block.bake ~operations b >>=? fun b -> + (* skip to next period *) + bake_until_first_block_of_next_period b >>=? fun b -> + (* expect to move to cooldown because we have supermajority and enough quorum *) + assert_period ~expected_kind:Cooldown b __LOC__ + +(* gets the voting power *) +let get_voting_power block pkhash = + let ctxt = Context.B block in + Context.get_voting_power ctxt pkhash + +(** Test that the voting power changes if the balance between bakers changes + and the blockchain moves to the next voting period. It also checks that + the total voting power coincides with the addition of the voting powers + of bakers *) +let test_voting_power_updated_each_voting_period () = + let open Test_tez.Tez in + (* Create three accounts with different amounts *) + Context.init + ~initial_balances:[80_000_000_000L; 48_000_000_000L; 4_000_000_000_000L] + 3 + >>=? fun (block, contracts) -> + let con1 = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 in + let con2 = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 1 in + let con3 = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 2 in + (* Retrieve balance of con1 *) + Context.Contract.balance (B block) con1 >>=? fun balance1 -> + Assert.equal_tez ~loc:__LOC__ balance1 (of_mutez_exn 80_000_000_000L) + >>=? fun _ -> + (* Retrieve balance of con2 *) + Context.Contract.balance (B block) con2 >>=? fun balance2 -> + Assert.equal_tez ~loc:__LOC__ balance2 (of_mutez_exn 48_000_000_000L) + >>=? fun _ -> + (* Retrieve balance of con3 *) + Context.Contract.balance (B block) con3 >>=? fun balance3 -> + (* Retrieve constants blocks_per_voting_period and tokens_per_roll *) + Context.get_constants (B block) + >>=? fun {parametric = {tokens_per_roll; _}; _} -> + (* Get the key hashes of the bakers *) + Context.get_bakers (B block) >>=? fun bakers -> + (* [Context.init] and [Context.get_bakers] store the accounts in reversed orders *) + let baker1 = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth bakers 2 in + let baker2 = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth bakers 1 in + let baker3 = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth bakers 0 in + (* Auxiliary assert_voting_power *) + let assert_voting_power ~loc n block baker = + get_voting_power block baker >>=? fun voting_power -> + Assert.equal_int ~loc n (Int32.to_int voting_power) + in + (* Auxiliary assert_total_voting_power *) + let assert_total_voting_power ~loc n block = + Context.get_total_voting_power (B block) >>=? fun total_voting_power -> + Assert.equal_int ~loc n (Int32.to_int total_voting_power) + in + (* Assert voting power is equal to the balance divided by tokens_per_roll *) + let expected_power_of_baker_1 = + Int64.(to_int (div (to_mutez balance1) (to_mutez tokens_per_roll))) + in + assert_voting_power ~loc:__LOC__ expected_power_of_baker_1 block baker1 + >>=? fun _ -> + (* Assert voting power is equal to the balance divided by tokens_per_roll *) + let expected_power_of_baker_2 = + Int64.(to_int (div (to_mutez balance2) (to_mutez tokens_per_roll))) + in + assert_voting_power ~loc:__LOC__ expected_power_of_baker_2 block baker2 + >>=? fun _ -> + (* Assert total voting power *) + let expected_power_of_baker_3 = + Int64.(to_int (div (to_mutez balance3) (to_mutez tokens_per_roll))) + in + assert_total_voting_power + ~loc:__LOC__ + Int.( + add + (add expected_power_of_baker_1 expected_power_of_baker_2) + expected_power_of_baker_3) + block + >>=? fun _ -> + (* Create policy that excludes baker1 and baker2 from baking *) + let policy = Block.Excluding [baker1; baker2] in + (* Transfer tokens_per_roll * num_rolls from baker1 to baker2 *) + let num_rolls = 5L in + tokens_per_roll *? num_rolls >>?= fun amount -> + Op.transaction (B block) con1 con2 amount >>=? fun op -> + (* Bake the block containing the transaction *) + Block.bake ~policy ~operations:[op] block >>=? fun block -> + (* Retrieve balance of con1 *) + Context.Contract.balance (B block) con1 >>=? fun balance1 -> + (* Assert balance has changed by tokens_per_roll * num_rolls *) + tokens_per_roll *? num_rolls >>?= fun rolls -> + of_mutez_exn 80_000_000_000L -? rolls + >>?= Assert.equal_tez ~loc:__LOC__ balance1 + >>=? fun _ -> + (* Retrieve balance of con2 *) + Context.Contract.balance (B block) con2 >>=? fun balance2 -> + (* Assert balance has changed by tokens_per_roll * num_rolls *) + tokens_per_roll *? num_rolls >>?= fun rolls -> + of_mutez_exn 48_000_000_000L +? rolls + >>?= Assert.equal_tez ~loc:__LOC__ balance2 + >>=? fun () -> + Block.bake block >>=? fun block -> + (* Assert voting power (and total) remains the same before next voting period *) + assert_voting_power ~loc:__LOC__ expected_power_of_baker_1 block baker1 + >>=? fun () -> + assert_voting_power ~loc:__LOC__ expected_power_of_baker_2 block baker2 + >>=? fun () -> + assert_voting_power ~loc:__LOC__ expected_power_of_baker_3 block baker3 + >>=? fun () -> + assert_total_voting_power + ~loc:__LOC__ + Int.( + add + (add expected_power_of_baker_1 expected_power_of_baker_2) + expected_power_of_baker_3) + block + >>=? fun _ -> + bake_until_first_block_of_next_period block >>=? fun block -> + (* Assert voting power of baker1 has decreased by num_rolls *) + let expected_power_of_baker_1 = + Int.sub expected_power_of_baker_1 (Int64.to_int num_rolls) + in + assert_voting_power ~loc:__LOC__ expected_power_of_baker_1 block baker1 + >>=? fun _ -> + (* Assert voting power of baker2 has increased by num_rolls *) + let expected_power_of_baker_2 = + Int.add expected_power_of_baker_2 (Int64.to_int num_rolls) + in + assert_voting_power ~loc:__LOC__ expected_power_of_baker_2 block baker2 + >>=? fun _ -> + (* Retrieve voting power of baker3 *) + get_voting_power block baker3 >>=? fun power -> + let power_of_baker_3 = Int32.to_int power in + (* Assert total voting power *) + assert_total_voting_power + ~loc:__LOC__ + Int.( + add + (add expected_power_of_baker_1 expected_power_of_baker_2) + power_of_baker_3) + block + +let test_voting_period_pp () = + let vp = + Voting_period_repr. + { + index = Int32.of_int 123; + kind = Proposal; + start_position = Int32.of_int 321; + } + in + Assert.equal + ~loc:__LOC__ + ( = ) + "Unexpected pretty printing of voting period" + Format.pp_print_string + (Format.asprintf "%a" Voting_period_repr.pp vp) + "index: 123, kind:proposal, start_position: 321" + +let tests = + [ + Tztest.tztest "voting successful_vote" `Quick (test_successful_vote 137); + Tztest.tztest + "voting cooldown, not enough quorum" + `Quick + (test_not_enough_quorum_in_exploration 245); + Tztest.tztest + "voting promotion, not enough quorum" + `Quick + (test_not_enough_quorum_in_promotion 432); + Tztest.tztest + "voting counting double proposal" + `Quick + test_multiple_identical_proposals_count_as_one; + Tztest.tztest + "voting proposal, with supermajority" + `Quick + (test_supermajority_in_proposal true); + Tztest.tztest + "voting proposal, without supermajority" + `Quick + (test_supermajority_in_proposal false); + Tztest.tztest + "voting proposal, with quorum" + `Quick + (test_quorum_in_proposal true); + Tztest.tztest + "voting proposal, without quorum" + `Quick + (test_quorum_in_proposal false); + Tztest.tztest + "voting cooldown, with supermajority" + `Quick + (test_supermajority_in_exploration true); + Tztest.tztest + "voting cooldown, without supermajority" + `Quick + (test_supermajority_in_exploration false); + Tztest.tztest + "voting proposal, no winning proposal" + `Quick + (test_no_winning_proposal 400); + Tztest.tztest + "voting quorum, quorum capped maximum" + `Quick + (test_quorum_capped_maximum 400); + Tztest.tztest + "voting quorum, quorum capped minimum" + `Quick + (test_quorum_capped_minimum 401); + Tztest.tztest + "voting power updated in each voting period" + `Quick + test_voting_power_updated_each_voting_period; + Tztest.tztest "voting period pretty print" `Quick test_voting_period_pp; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/unit/.ocamlformat b/src/proto_011_PtHangzH/lib_protocol/test/unit/.ocamlformat new file mode 100644 index 000000000000..5e1158919e85 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/unit/.ocamlformat @@ -0,0 +1,17 @@ +version=0.18.0 +wrap-fun-args=false +let-binding-spacing=compact +field-space=loose +break-separators=after +space-around-arrays=false +space-around-lists=false +space-around-records=false +space-around-variants=false +dock-collection-brackets=true +space-around-records=false +sequence-style=separator +doc-comments=before +margin=80 +module-item-spacing=sparse +parens-tuple=always +parens-tuple-patterns=always diff --git a/src/proto_011_PtHangzH/lib_protocol/test/unit/dune b/src/proto_011_PtHangzH/lib_protocol/test/unit/dune new file mode 100644 index 000000000000..18a1861bf5bb --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/unit/dune @@ -0,0 +1,24 @@ +(executable + (name main) + (libraries tezos-base + tezos-micheline + tezos-protocol-environment + alcotest-lwt + tezos-011-PtHangzH-test-helpers + tezos-stdlib-unix + tezos-client-base + tezos-protocol-011-PtHangzH-parameters + tezos-base-test-helpers) + (flags (:standard -open Tezos_base__TzPervasives + -open Tezos_base_test_helpers + -open Tezos_micheline + -open Tezos_client_011_PtHangzH + -open Tezos_protocol_011_PtHangzH + -open Tezos_protocol_environment_011_PtHangzH + -open Tezos_011_PtHangzH_test_helpers))) + +(rule + (alias runtest) + (package tezos-protocol-011-PtHangzH-tests) + (deps main.exe) + (action (run ./main.exe "test" "Unit"))) diff --git a/src/proto_011_PtHangzH/lib_protocol/test/unit/main.ml b/src/proto_011_PtHangzH/lib_protocol/test/unit/main.ml new file mode 100644 index 000000000000..d8a110496537 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/unit/main.ml @@ -0,0 +1,60 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) +module Unit_test : sig + (** + * Example: [spec "Alpha_context.ml" Test_alpha_context.test_cases] + * Unit tests needs tag in log (like "[UNIT] some test description here...") + * This function handles such meta data *) + val spec : + string -> + unit Alcotest_lwt.test_case list -> + string * unit Alcotest_lwt.test_case list + + (** Tests with description string without [Unit] are skipped *) + val skip : + string -> + unit Alcotest_lwt.test_case list -> + string * unit Alcotest_lwt.test_case list +end = struct + let spec unit_name test_cases = ("[Unit] " ^ unit_name, test_cases) + + let skip unit_name test_cases = ("[SKIPPED] " ^ unit_name, test_cases) +end + +let () = + Alcotest_lwt.run + "protocol_011_PtHangzH unit tests" + [ + Unit_test.spec "Alpha_context.ml" Test_alpha_context.tests; + Unit_test.spec "Raw_level_repr.ml" Test_raw_level_repr.tests; + Unit_test.skip "Raw_level_repr.ml" Test_raw_level_repr.skipped_tests; + Unit_test.spec "Tez_repr.ml" Test_tez_repr.tests; + Unit_test.spec "Contract_repr.ml" Test_contract_repr.tests; + Unit_test.spec "Operation_repr.ml" Test_operation_repr.tests; + Unit_test.spec + "Global_constants_storage.ml" + Test_global_constants_storage.tests; + ] + |> Lwt_main.run diff --git a/src/proto_011_PtHangzH/lib_protocol/test/unit/test_alpha_context.ml b/src/proto_011_PtHangzH/lib_protocol/test/unit/test_alpha_context.ml new file mode 100644 index 000000000000..64824a7f6ae4 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/unit/test_alpha_context.ml @@ -0,0 +1,129 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +(** Testing + ------- + Component: Alpha_context + Invocation: dune exec ./src/proto_alpha/lib_protocol/test/unit/main.exe -- test Alpha_context + Dependencies: helpers/block.ml + Subject: To test the modules (including the top-level) + in alpha_context.ml as individual units, particularly + failure cases. Superficial goal: increase coverage percentage. +*) + +(** Creates an Alpha_context without creating a full-fledged block *) +let create () = + let accounts = Account.generate_accounts 1 in + Block.alpha_context accounts + +module Test_Script = struct + (** Force serialise of lazy [Big_map.t] in a given [alpha_context] *) + let test_force_bytes_in_context () = + create () >>=? fun alpha_context -> + let mbytes_pp ppf t = + Format.pp_print_string ppf (Environment.Bytes.to_string t) + in + let open Alpha_context.Script in + Environment.wrap_tzresult + @@ force_bytes_in_context alpha_context + @@ lazy_expr @@ Micheline.strip_locations + @@ Prim (0, D_Unit, [], []) + >>?= fun (bytes, _) -> + Assert.equal + ~loc:__LOC__ + Environment.Bytes.equal + "script serialised incorrectly" + mbytes_pp + bytes + (`Hex "030b" |> Hex.to_bytes) +end + +module Test_Big_map = struct + (** Test failure path: look for a non-existent key in a [Big_map] *) + let test_mem () = + ( create () >>=? fun alpha_context -> + Big_map.fresh ~temporary:true alpha_context >|= Environment.wrap_tzresult + >>=? fun (alpha_context, big_map_id) -> + Big_map.mem + alpha_context + big_map_id + (Script_expr_hash.hash_string ["0"; "0"]) + >|= Environment.wrap_tzresult ) + >>=? fun (_alpha_context, is_member) -> + Assert.equal_bool ~loc:__LOC__ is_member false + + (** Test failure code path of [get_opt] by looking for missing key in a [Big_map.t] *) + let test_get_opt () = + ( create () >>=? fun alpha_context -> + Big_map.fresh ~temporary:true alpha_context >|= Environment.wrap_tzresult + >>=? fun (alpha_context, big_map_id) -> + Big_map.get_opt + alpha_context + big_map_id + (Script_expr_hash.hash_string ["0"; "0"]) + >|= Environment.wrap_tzresult ) + >>=? fun (_alpha_context, value) -> + match value with + | Some _ -> + failwith "get_opt should have failed looking for a non-existent key" + | None -> return_unit + + (** Test existence of a non-existent [Big_map] in an [Alpha_context.t] *) + let test_exists () = + ( create () >>=? fun alpha_context -> + Big_map.fresh ~temporary:true alpha_context >|= Environment.wrap_tzresult + >>=? fun (alpha_context, big_map_id) -> + Big_map.exists alpha_context big_map_id >|= Environment.wrap_tzresult ) + >>=? fun (_alpha_context, value) -> + match value with + | Some _ -> + failwith "exists should have failed looking for a non-existent big_map" + | None -> return_unit +end + +let tests = + [ + Tztest.tztest + "Script.force_bytes_in_context: checks if it serialises a simple \ + michelson expression" + `Quick + Test_Script.test_force_bytes_in_context; + Tztest.tztest + "Big_map.mem: failure case - must return false when starting with an \ + empty map" + `Quick + Test_Big_map.test_mem; + Tztest.tztest + "Big_map.get_opt: failure case - looking up key that doesn't exist" + `Quick + Test_Big_map.test_get_opt; + Tztest.tztest + "Big_map.exists: failure case - looking up big_map that doesn't exist" + `Quick + Test_Big_map.test_exists; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/unit/test_contract_repr.ml b/src/proto_011_PtHangzH/lib_protocol/test/unit/test_contract_repr.ml new file mode 100644 index 000000000000..7ecff1016d63 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/unit/test_contract_repr.ml @@ -0,0 +1,161 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Contract_repr + Invocation: dune exec ./src/proto_alpha/lib_protocol/test/unit/main.exe -- test Contract_repr + Dependencies: contract_hash.ml + Subject: To test the modules (including the top-level) + in contract_repr.ml as individual units, particularly + failure cases. Superficial goal: increase coverage percentage. +*) +open Protocol + +open Tztest + +(* + + TODO: Remove dependence on contract_hash.ml and mock it + + *) + +module Test_contract_repr = struct + (** Assert if [is_implicit] correctly returns the implicit contract *) + open Contract_repr + + let dummy_operation_hash = + Operation_hash.of_bytes_exn + (Bytes.of_string "test-operation-hash-of-length-32") + + let dummy_origination_nonce = initial_origination_nonce dummy_operation_hash + + let dummy_contract_hash = + (* WARNING: Uses Contract_repr itself, which is yet to be tested. This happened because Contract_hash wasn't mocked *) + let data = + Data_encoding.Binary.to_bytes_exn + Contract_repr.origination_nonce_encoding + dummy_origination_nonce + in + Contract_hash.hash_bytes [data] + + let dummy_implicit_contract = implicit_contract Signature.Public_key_hash.zero + + let dummy_originated_contract = originated_contract @@ dummy_origination_nonce + + let test_implicit () = + match is_implicit dummy_implicit_contract with + | Some _ -> return_unit + | None -> + failwith + "must have returned the public key hash of implicit contract. \n\ + \ Instead, returned None" + + (** Check if [is_implicit] catches a non-implicit (originated) contract and returns None *) + let test_not_implicit () = + match is_implicit dummy_originated_contract with + | None -> return_unit + | Some _ -> failwith "must have returned the None. Instead, returned Some _" + + let test_originated () = + match is_originated dummy_originated_contract with + | Some _ -> return_unit + | None -> + failwith + "must have returned the origination nonce correctly. Instead \ + returned None." + + let test_not_originated () = + match is_originated dummy_implicit_contract with + | None -> return_unit + | Some _ -> failwith "must have returned the None. Instead, returned Some _" + + let test_to_b58check_implicit () = + Assert.equal + ~loc:__LOC__ + String.equal + "%s should have been equal to %" + Format.pp_print_string + (to_b58check dummy_implicit_contract) + Signature.Public_key_hash.(to_b58check zero) + + let test_to_b58check_originated () = + Assert.equal + ~loc:__LOC__ + String.equal + "%s should have been equal to %" + Format.pp_print_string + (to_b58check dummy_originated_contract) + Contract_hash.(to_b58check @@ dummy_contract_hash) + + let test_originated_contracts_basic () = + let since = dummy_origination_nonce in + let rec incr_n_times nonce = function + | 0 -> nonce + | n -> incr_n_times (Contract_repr.incr_origination_nonce nonce) (n - 1) + in + let until = incr_n_times since 5 in + let contracts = originated_contracts ~since ~until in + Assert.equal_int ~loc:__LOC__ (List.length contracts) 5 +end + +let tests = + [ + tztest + "Contract_repr.is_implicit: must correctly identify a valid implicit \ + contract" + `Quick + Test_contract_repr.test_implicit; + tztest + "Contract_repr.is_implicit: must correctly return None for a originated \ + contract" + `Quick + Test_contract_repr.test_not_implicit; + tztest + "Contract_repr.is_originated: must correctly return operation hash of \ + the originated contract" + `Quick + Test_contract_repr.test_originated; + tztest + "Contract_repr.is_originated: must correctly return None for an implicit \ + contract contract" + `Quick + Test_contract_repr.test_not_originated; + tztest + "Contract_repr.to_b58check: must correctly stringify, b58check encoded, \ + an implicit contract" + `Quick + Test_contract_repr.test_to_b58check_implicit; + tztest + "Contract_repr.originated_contract: must correctly create an originated \ + contract" + `Quick + Test_contract_repr.test_originated_contracts_basic; + tztest + "Contract_repr.to_b58check: must correctly stringify, b58check encoded, \ + an originated contract" + `Quick + Test_contract_repr.test_to_b58check_originated; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/unit/test_global_constants_storage.ml b/src/proto_011_PtHangzH/lib_protocol/test/unit/test_global_constants_storage.ml new file mode 100644 index 000000000000..774e3c7cd12d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/unit/test_global_constants_storage.ml @@ -0,0 +1,413 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Global table of constants + Invocation: dune exec ./src/proto_alpha/lib_protocol/test/unit/main.exe \ + -- test Global_constants_storage + Dependencies: contract_hash.ml + Subject: Test the global table of constants +*) + +open Protocol +open Alpha_context +open Tztest +open Micheline +open QCheck +open Lib_test.Qcheck_helpers +open Michelson_v1_primitives +open Michelson_v1_printer +open Test_global_constants + +(** [get] on a nonexistent global constant + returns an error. *) +let test_get_on_nonexistent_fails = + tztest_qcheck + ~name:"get on a nonexistent global constants fails" + (pair + Generators.context_arbitrary + Generators.canonical_without_constant_arbitrary) + (fun (context, expr) -> + expr_to_hash expr |> Environment.wrap_tzresult >>?= fun hash -> + Global_constants_storage.get context hash + >|= Environment.wrap_tzresult + >>= assert_proto_error_id __LOC__ "Nonexistent_global") + +(** If registering an expression yields a hash [h] and context [c], + then [get c h] should yield the original expression. *) +let test_get_always_returns_registered_expr = + tztest_qcheck + ~name:"get always returned the registered constant" + (pair + Generators.context_arbitrary + Generators.canonical_without_constant_arbitrary) + (fun (context, expr) -> + Global_constants_storage.register context expr + >|= Environment.wrap_tzresult + >>=? fun (context, hash, _cost) -> + Global_constants_storage.get context hash >|= Environment.wrap_tzresult + >|=? fun (_context, actual_expr) -> + qcheck_eq ~pp:print_expr actual_expr expr) + +(* Attempts to register an expression that contains references + to expressions not already registered should fail. *) +let test_register_fails_with_unregistered_references = + tztest "register: fails with unregistered references" `Quick (fun () -> + let prim_with_constant = + Expr.from_string + {| Pair 1 + (constant "exprubuoE4JFvkSpxsZJXAvhTdozCNZpgfCnyg6WsiAYX79q4z3bXu")|} + in + create_context () >>=? fun context -> + Global_constants_storage.register context prim_with_constant + >|= Environment.wrap_tzresult + >>= assert_proto_error_id __LOC__ "Nonexistent_global") + +(** Same test as [test_register_fails_with_unregistered_references] + but with random values. *) +let test_register_fails_with_unregistered_references_pbt = + tztest_qcheck + ~name:"register: fails with unregistered references pbt" + (pair + Generators.context_arbitrary + Generators.canonical_with_constant_arbitrary) + (fun (context, (_, expr, _)) -> + assume_expr_not_too_large expr ; + Global_constants_storage.register context expr + >|= Environment.wrap_tzresult + >>= assert_proto_error_id __LOC__ "Nonexistent_global") + +let rec grow n node = + match n with n when n <= 0 -> node | n -> grow (n - 1) (Seq (-1, [node])) + +(* Any expression with a depth that exceeds + [Global_constants_storage.max_allowed_global_constant_depth] + should be rejected. *) +let test_register_fails_if_too_deep = + tztest "register: fails if expression too deep" `Quick (fun () -> + let vdeep_expr = + grow + (Constants_repr.max_allowed_global_constant_depth + 1) + (Int (-1, Z.of_int 1)) + |> Micheline.strip_locations + in + create_context () >>=? fun context -> + Global_constants_storage.register context vdeep_expr + >|= Environment.wrap_tzresult + >>= assert_proto_error_id __LOC__ "Expression_too_deep") + +(** [expand] on an expression containing a nonexistent global + constant returns an error. *) +let test_expand_nonexistent_fails = + tztest_qcheck + ~name: + "expand on an expression containing a nonexistent global constant fails" + (pair + Generators.context_arbitrary + Generators.canonical_with_constant_arbitrary) + @@ fun (context, (_, expr, _)) -> + assume_expr_not_too_large expr ; + Global_constants_storage.expand context expr + >|= Environment.wrap_tzresult + >>= assert_proto_error_id __LOC__ "Nonexistent_global" + +(** Expanding an expression without constants should yield the same expression. *) +let test_expand_no_constants = + tztest "expand: no constants case" `Quick (fun () -> + create_context () >>=? fun context -> + let expected = Expr.from_string "Pair 1 (Pair 2 3)" in + Global_constants_storage.expand context expected + >|= Environment.wrap_tzresult + >>=? fun (_, result_expr) -> + assert_expr_equal __LOC__ expected result_expr) + +(** Similar to [test_expand_no_constants], but random. *) +let test_register_and_expand_orthogonal = + tztest_qcheck + ~name:"register and expand are orthogonal" + (triple + Generators.context_arbitrary + Generators.canonical_without_constant_arbitrary + Generators.canonical_without_constant_arbitrary) + (fun (context, expr1, expr2) -> + assume_expr_not_too_large expr1 ; + assume_expr_not_too_large expr2 ; + let open Michelson_v1_printer in + Global_constants_storage.register context expr1 + >|= Environment.wrap_tzresult + >>=? fun (context, _hash, _cost) -> + Global_constants_storage.expand context expr2 + >|= Environment.wrap_tzresult + >|=? fun (_, expr2_result) -> qcheck_eq ~pp:print_expr expr2 expr2_result) + +(** Expanding should expand constants in the given + expression, then expand any new constants, etc. + recursively until no constants remain. *) +let test_expand_deep_constants = + tztest "expand: deep constants" `Quick (fun () -> + (* Should hold for any n, but this test is very slow, + hence we don't do QCheck. *) + let n = 1000 in + let expr1 = Expr.from_string "{}" in + create_context () >>=? fun context -> + let rec n_constants_deep context node n = + Global_constants_storage.register context (strip_locations node) + >|= Environment.wrap_tzresult + >>=? fun (context, hash, _) -> + if n <= 1 then return (context, node, hash) + else + let new_node = + Seq + ( -1, + [ + Prim + ( -1, + H_constant, + [String (-1, Script_expr_hash.to_b58check hash)], + [] ); + ] ) + in + n_constants_deep context new_node (n - 1) + in + n_constants_deep context (root expr1) n >>=? fun (context, _, hash) -> + let deep_expr = + Expr.from_string + @@ Format.sprintf + "{constant \"%s\"; CDR; NIL operation; PAIR}" + (Script_expr_hash.to_b58check hash) + in + Global_constants_storage.expand context deep_expr + >|= Environment.wrap_tzresult + >>=? fun (_, result) -> + let seq_n_deep n = + let rec advance n acc = + match n with 0 -> acc | _ -> advance (n - 1) (Seq (-1, [acc])) + in + advance (n - 1) (Seq (-1, [])) + in + let seq_str = Expr.to_string @@ strip_locations @@ seq_n_deep n in + let expected = + Expr.from_string + @@ Format.sprintf "{ %s; CDR; NIL operation; PAIR; }" + @@ seq_str + in + assert_expr_equal __LOC__ expected result) + +(** The [constant] prim is permitted only to have a + single string argument, representing a valid + Script_repr.expr hash, with no annotations *) +let test_expand_reject_ill_formed = + tztest "expand: ill formed constants are rejected" `Quick (fun () -> + (* first, create a context, register a constant and check + that its expansion works well. *) + create_context () >>=? fun context -> + let some_expr = Expr.from_string "0" in + Global_constants_storage.register context some_expr + >|= Environment.wrap_tzresult + >>=? fun (context, hash, _) -> + let hash = Script_expr_hash.to_b58check hash in + (* check that expansion of the registered constant works *) + Global_constants_storage.expand + context + (Expr.from_string @@ Format.sprintf "constant \"%s\"" hash) + >|= Environment.wrap_tzresult + >>=? fun (context, result) -> + assert_expr_equal __LOC__ some_expr result >>=? fun () -> + let test expr = + let expected = Expr.from_string expr in + Global_constants_storage.expand context expected + >|= Environment.wrap_tzresult + >>= assert_proto_error_id __LOC__ "Badly_formed_constant_expression" + in + (* constant with an argument other than String fails *) + test "constant 9" >>=? fun () -> + (* same as above but nested *) + test "Pair 1 (constant (Pair 2 3))" >>=? fun () -> + (* constant with bad hash fails *) + test "constant \"foobar\"" >>=? fun () -> + (* constant with type annot *) + test @@ Format.sprintf "(constant :a \"%s\")" hash >>=? fun () -> + (* constant with var annot *) + test @@ Format.sprintf "(constant @a \"%s\")" hash >>=? fun () -> + (* constant with field annot *) + test @@ Format.sprintf "(constant %%a \"%s\")" hash) + +(** The [constant] prim is not permitted to have a + [constant] child argument. + + The idea is to have expansion like this: + + constant (constant ) -> constant hash -> value + + But we want to forbid this as a badly formed constant. + Asserting that every constant must be a *static* string + makes it easier to see which constants are used where, because + you can just traverse the AST (no expansion necessary). *) +let test_reject_use_of_inner_constant = + tztest + "expand: use of 'constant (constant ...)' is rejected" + `Quick + (fun () -> + (* First, create a context, register a constant and check + that its expansion works well. *) + create_context () >>=? fun context -> + let some_expr = Expr.from_string "0" in + Global_constants_storage.register context some_expr + >|= Environment.wrap_tzresult + >>=? fun (context, hash, _) -> + let hash = Script_expr_hash.to_b58check hash in + (* Next, register the hash itself as a constant. *) + Global_constants_storage.register + context + (strip_locations (Micheline.String (-1, hash))) + >|= Environment.wrap_tzresult + >>=? fun (context, hash, _) -> + let hash = Script_expr_hash.to_b58check hash in + Global_constants_storage.expand + context + (Expr.from_string + @@ Format.sprintf "{ constant (constant \"%s\") } " hash) + >|= Environment.wrap_tzresult + >>= assert_proto_error_id __LOC__ "Badly_formed_constant_expression") + +(** [test_expand] accepts an expression [stored] to be + registered in the store, an expression [expr] that includes a template slot for + the hash of [stored], and an [expected] expression, and generates a test that + asserts the value of [expr] after expansion matches [expected]. *) +let make_expand_test ~stored ~expr ~expected () = + create_context () >>=? fun context -> + let stored_expr = Expr.from_string stored in + Global_constants_storage.register context stored_expr + >|= Environment.wrap_tzresult + >>=? fun (context, hash, _) -> + let expected = Expr.from_string expected in + let expr_with_constant = + Format.sprintf expr (Script_expr_hash.to_b58check hash) |> Expr.from_string + in + Global_constants_storage.expand context expr_with_constant + >|= Environment.wrap_tzresult + >>=? fun (_, result_expr) -> assert_expr_equal __LOC__ expected result_expr + +let test_expand_data_example = + tztest + "expand: data" + `Quick + (make_expand_test + ~stored:"3" + ~expr:"Pair 1 (Pair 2 (constant \"%s\"))" + ~expected:"Pair 1 (Pair 2 3)") + +let test_expand_types_example = + tztest + "expand: types" + `Quick + (make_expand_test + ~stored:"big_map string string" + ~expr:"PUSH (constant \"%s\") {}" + ~expected:"PUSH (big_map string string) {}") + +let test_expand_instr_example = + tztest + "expand: instr" + `Quick + (make_expand_test + ~stored:"PUSH int 3" + ~expr:"{ DROP; constant \"%s\"; DROP }" + ~expected:"{ DROP; PUSH int 3 ; DROP }") + +(** For any expression [e], when replacing any subexpression + [e'] with a constant hash and registering [e'], calling + [expand] on the new expression yields the + original expression [e]*) +let test_expand_pbt = + let open Michelson_v1_printer in + tztest_qcheck + ~name:"expand: random" + (pair + Generators.context_arbitrary + Generators.canonical_with_constant_arbitrary) + (fun (context, (full_expr, expr_with_constant, sub_expr)) -> + assume_expr_not_too_large full_expr ; + assume_expr_not_too_large expr_with_constant ; + assume_expr_not_too_large sub_expr ; + Global_constants_storage.register context sub_expr + >|= Environment.wrap_tzresult + >>=? fun (context, _, _) -> + Global_constants_storage.expand context expr_with_constant + >|= Environment.wrap_tzresult + >|=? fun (_, result_expr) -> + qcheck_eq ~pp:print_expr full_expr result_expr) + +let test_expand_is_idempotent = + tztest_qcheck + ~name:"expand is idempotent" + (pair + Generators.context_arbitrary + Generators.canonical_with_constant_arbitrary) + (fun (context, (full_expr, expr_with_constant, sub_expr)) -> + assume_expr_not_too_large full_expr ; + Global_constants_storage.register context sub_expr + >|= Environment.wrap_tzresult + >>=? fun (context, _, _) -> + Global_constants_storage.expand context expr_with_constant + >|= Environment.wrap_tzresult + >>=? fun (context, result1) -> + Global_constants_storage.expand context full_expr + >|= Environment.wrap_tzresult + >|=? fun (_, result2) -> qcheck_eq ~pp:print_expr result1 result2) + +(** [bottom_up_fold_cps] does not stack overflow even when + given large values. *) +let test_fold_does_not_stack_overflow = + tztest "bottom_up_fold_cps: does not stack overflow" `Quick (fun () -> + let node = grow 1_000_000 @@ Int (-1, Z.zero) in + return @@ ignore + @@ Global_constants_storage.Internal_for_tests.bottom_up_fold_cps + () + node + (fun _ _ -> ()) + (fun _ node k -> k () node)) + +let tests = + [ + test_get_on_nonexistent_fails; + test_get_always_returns_registered_expr; + test_register_fails_with_unregistered_references; + test_register_fails_with_unregistered_references_pbt; + test_register_fails_if_too_deep; + test_expand_nonexistent_fails; + test_expand_no_constants; + test_register_and_expand_orthogonal; + test_expand_deep_constants; + test_expand_reject_ill_formed; + test_reject_use_of_inner_constant; + test_expand_data_example; + test_expand_types_example; + test_expand_instr_example; + test_expand_pbt; + test_expand_is_idempotent; + test_fold_does_not_stack_overflow; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/unit/test_operation_repr.ml b/src/proto_011_PtHangzH/lib_protocol/test/unit/test_operation_repr.ml new file mode 100644 index 000000000000..ee36932c65cf --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/unit/test_operation_repr.ml @@ -0,0 +1,112 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Operation_repr + Invocation: dune exec ./src/proto_alpha/lib_protocol/test/unit/main.exe -- test Operation_repr + Dependencies: -- + Subject: To test the modules (including the top-level) + in operation_repr.ml as individual units, particularly + failure cases. Superficial goal: increase coverage percentage. +*) +open Protocol + +open Tztest + +module Test_operation_repr = struct + open Operation_repr + + let test_of_list_single_case () = + Environment.wrap_tzresult + @@ of_list + [ + Contents + (Manager_operation + { + fee = Obj.magic 0; + operation = Obj.magic 0; + gas_limit = Obj.magic 0; + storage_limit = Obj.magic 0; + counter = Obj.magic 0; + source = Obj.magic 0; + }); + ] + >>?= fun contents_list -> + match contents_list with + | Contents_list (Single _) -> return_unit + | _ -> failwith "Unexpected value" + + let test_of_list_multiple_case () = + Environment.wrap_tzresult + @@ of_list + [ + Contents + (Manager_operation + { + fee = Obj.magic 0; + operation = Obj.magic 0; + gas_limit = Obj.magic 0; + storage_limit = Obj.magic 0; + counter = Obj.magic 0; + source = Obj.magic 0; + }); + Contents + (Manager_operation + { + fee = Obj.magic 0; + operation = Obj.magic 0; + gas_limit = Obj.magic 0; + storage_limit = Obj.magic 0; + counter = Obj.magic 0; + source = Obj.magic 0; + }); + ] + >>?= fun contents_list -> + match contents_list with + | Contents_list (Cons (_, Single _)) -> return_unit + | _ -> failwith "Unexpected value" + + let test_of_list_empty_case () = + match of_list [] with + | Ok _ -> failwith "of_list of an empty list was expected to fail" + | Error _ -> return_unit +end + +let tests = + [ + tztest + "of_list: single element input list" + `Quick + Test_operation_repr.test_of_list_single_case; + tztest + "of_list: multiple element input list" + `Quick + Test_operation_repr.test_of_list_multiple_case; + tztest + "of_list: empty input list" + `Quick + Test_operation_repr.test_of_list_empty_case; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/unit/test_raw_level_repr.ml b/src/proto_011_PtHangzH/lib_protocol/test/unit/test_raw_level_repr.ml new file mode 100644 index 000000000000..123afe2f6030 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/unit/test_raw_level_repr.ml @@ -0,0 +1,175 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Tztest + +(** Testing + ------- + Component: Raw_level_repr + Invocation: dune exec ./src/proto_alpha/lib_protocol/test/unit/main.exe -- test Raw_level_repr + Dependencies: -- + Subject: To test the modules (including the top-level) + in raw_level_repr.ml as individual units, particularly + failure cases. Superficial goal: increase coverage percentage. +*) + +module Test_raw_level_repr = struct + (* NOTE: Avoid assertions against too many functions from Raw_level_repr. For instance, + Raw_level_repr contains a [compare] function, but while [Assert]'ing, convert them to + int32 (or any convenient OCaml value) and compare instead of using [Raw_level_repr]'s compare *) + + (** Testing [encoding], int32 underneath, by applying it with Data_encoding *) + let test_encoding () = + let encoding = Raw_level_repr.encoding in + let bytes = Bytes.make 4 '0' in + Bytes.set_int32_ne bytes 0 0l ; + (Data_encoding.Binary.of_bytes encoding bytes |> function + | Ok x -> Lwt.return (Ok x) + | Error e -> + failwith + "Data_encoding.Binary.read shouldn't have failed with \ + Raw_level_repr.encoding: %a" + Data_encoding.Binary.pp_read_error + e) + >>=? fun v -> + Assert.equal_int ~loc:__LOC__ (Int32.to_int (Raw_level_repr.to_int32 v)) 0 + >>=? fun () -> + Bytes.set_int32_ne bytes 0 (-1l) ; + Data_encoding.Binary.of_bytes encoding bytes |> function + | Error _ -> return_unit + | Ok x -> + failwith + "Data_encoding.Binary.read shouldn't have succeeded with %a" + Raw_level_repr.pp + x + + (* TODO rpc_arg. RPC_arg needs to be unit tested separately. Preferably, with a functor *) + (* let rpc_arg () = () *) + + (** int32 interop tests *) + let test_int32_interop () = + let int32v = 100l in + Lwt.return (Raw_level_repr.of_int32 int32v) >|= Environment.wrap_tzresult + >>=? fun raw_level -> + Assert.equal_int32 ~loc:__LOC__ (Raw_level_repr.to_int32 raw_level) int32v + >>=? fun () -> + let int32v = -1l in + (Lwt.return (Raw_level_repr.of_int32 int32v) >|= Environment.wrap_tzresult + >>= function + | Ok _ -> failwith "Negative int32s should not be coerced into raw_level" + | Error _ -> return_unit) + >>=? fun () -> + try + let _ = Raw_level_repr.of_int32_exn int32v in + failwith "Negative int32s should not be coerced into raw_level" + with Invalid_argument _ -> return_unit + + (** Asserting [root]'s runtime value. Expected to be [0l] *) + let test_root () = + let root = Raw_level_repr.root in + Assert.equal_int32 ~loc:__LOC__ (root |> Raw_level_repr.to_int32) 0l + + (** Asserting [succ] which is expected to return successor levels *) + let test_succ () = + let next_raw_level = Raw_level_repr.succ Raw_level_repr.root in + Assert.equal_int32 + ~loc:__LOC__ + (next_raw_level |> Raw_level_repr.to_int32) + 1l + >>=? fun () -> + let arbitrary_next_raw_level = + Raw_level_repr.succ (Raw_level_repr.of_int32_exn 99l) + in + Assert.equal_int32 + ~loc:__LOC__ + (arbitrary_next_raw_level |> Raw_level_repr.to_int32) + 100l + + (** Asserting [pred] which is expected to return predecessor levels *) + let test_pred () = + (match Raw_level_repr.pred (Raw_level_repr.of_int32_exn 1l) with + | Some previous_raw_level -> + Assert.equal_int32 + ~loc:__LOC__ + (previous_raw_level |> Raw_level_repr.to_int32) + 0l + | None -> + failwith + "Raw_level_repr.pred should have successfully returned 0l as the \ + predecessor of 1l") + >>=? fun () -> + Raw_level_repr.pred Raw_level_repr.root |> function + | Some _ -> + failwith + "Raw_level_repr.pred should have returned None when asked for \ + predecessor of [root]" + | None -> return_unit + + let test_skip_succ () = + let int32_limit = 0x7FFFFFFFl in + let overflown_next_raw_level = + Raw_level_repr.succ (Raw_level_repr.of_int32_exn int32_limit) + in + if Int32.compare (Raw_level_repr.to_int32 overflown_next_raw_level) 0l >= 0 + then return_unit + else + failwith + "succ of 0x7FFFFFFFl %a was expected to be non-negative" + Assert.Int32.pp + (overflown_next_raw_level |> Raw_level_repr.to_int32) +end + +let tests = + [ + tztest + "Raw_level_repr.encoding: checks if encoding is int32 as expected" + `Quick + Test_raw_level_repr.test_encoding; + tztest + "Raw_level_repr.root: check if value is 0l" + `Quick + Test_raw_level_repr.test_root; + tztest + "Raw_level_repr.succ: basic assertions" + `Quick + Test_raw_level_repr.test_succ; + tztest + "Raw_level_repr.pred: basic assertions" + `Quick + Test_raw_level_repr.test_pred; + tztest + "Raw_level_repr: int32 interop" + `Quick + Test_raw_level_repr.test_int32_interop; + ] + +let skipped_tests = + [ + tztest + "Raw_level_repr.succ: overflow" + `Quick + Test_raw_level_repr.test_skip_succ; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/test/unit/test_tez_repr.ml b/src/proto_011_PtHangzH/lib_protocol/test/unit/test_tez_repr.ml new file mode 100644 index 000000000000..08aa585c46fe --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/test/unit/test_tez_repr.ml @@ -0,0 +1,202 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Tez_repr + Invocation: dune exec ./src/proto_alpha/lib_protocol/test/unit/main.exe -- test Tez_repr + Dependencies: -- + Subject: To test the modules (including the top-level) + in tez_repr.ml as individual units, particularly + failure cases. Superficial goal: increase coverage percentage. +*) +open Protocol + +open Tztest + +module Test_tez_repr = struct + (** Testing predefined units: zero, one_mutez etc *) + let test_predefined_values () = + let zero_int64 = Tez_repr.to_int64 Tez_repr.zero in + Assert.equal_int64 ~loc:__LOC__ zero_int64 0L >>=? fun () -> + let one_mutez_int64 = Tez_repr.to_int64 Tez_repr.one_mutez in + Assert.equal_int64 ~loc:__LOC__ one_mutez_int64 1L >>=? fun () -> + let one_cent_int64 = Tez_repr.to_int64 Tez_repr.one_cent in + Assert.equal_int64 ~loc:__LOC__ one_cent_int64 10000L >>=? fun () -> + let fifty_cents_int64 = Tez_repr.to_int64 Tez_repr.fifty_cents in + Assert.equal_int64 ~loc:__LOC__ fifty_cents_int64 500000L >>=? fun () -> + let one_int64 = Tez_repr.to_int64 Tez_repr.one in + Assert.equal_int64 ~loc:__LOC__ one_int64 1000000L + + let test_subtract () = + (Lwt.return @@ Tez_repr.(one -? zero)) >|= Environment.wrap_tzresult + >>=? fun res -> + Assert.equal_int64 ~loc:__LOC__ (Tez_repr.to_int64 res) 1000000L + + let test_substract_underflow () = + (Lwt.return @@ Tez_repr.(zero -? one)) >|= Environment.wrap_tzresult + >>= function + | Ok _ -> failwith "Expected to underflow" + | Error _ -> return_unit + + let test_addition () = + (Lwt.return @@ Tez_repr.(one +? zero)) >|= Environment.wrap_tzresult + >>=? fun res -> + Assert.equal_int64 ~loc:__LOC__ (Tez_repr.to_int64 res) 1000000L + + let test_addition_overflow () = + (Lwt.return @@ Tez_repr.(of_mutez_exn 0x7fffffffffffffffL +? one)) + >|= Environment.wrap_tzresult + >>= function + | Ok _ -> failwith "Expected to overflow" + | Error _ -> return_unit + + let test_mul () = + (Lwt.return @@ Tez_repr.(zero *? 1L)) >|= Environment.wrap_tzresult + >>=? fun res -> Assert.equal_int64 ~loc:__LOC__ (Tez_repr.to_int64 res) 0L + + let test_mul_overflow () = + (Lwt.return @@ Tez_repr.(of_mutez_exn 0x7fffffffffffffffL *? 2L)) + >|= Environment.wrap_tzresult + >>= function + | Ok _ -> failwith "Expected to overflow" + | Error _ -> return_unit + + let test_div () = + (Lwt.return @@ Tez_repr.(one *? 1L)) >|= Environment.wrap_tzresult + >>=? fun res -> + Assert.equal_int64 ~loc:__LOC__ (Tez_repr.to_int64 res) 1000000L + + let test_div_by_zero () = + (Lwt.return @@ Tez_repr.(one /? 0L)) >|= Environment.wrap_tzresult + >>= function + | Ok _ -> failwith "Expected to overflow" + | Error _ -> return_unit + + let test_to_mutez () = + let int64v = Tez_repr.(to_mutez one) in + Assert.equal_int64 ~loc:__LOC__ int64v 1000000L + + let test_of_mutez_non_negative () = + match Tez_repr.of_mutez 1000000L with + | Some tz -> + Assert.equal_int64 + ~loc:__LOC__ + (Tez_repr.to_int64 tz) + Tez_repr.(to_int64 one) + | None -> failwith "should have successfully converted 1000000L to tez" + + let test_of_mutez_negative () = + match Tez_repr.of_mutez (-1000000L) with + | Some _ -> failwith "should have failed to converted -1000000L to tez" + | None -> return_unit + + let test_of_mutez_exn () = + try + let tz = Tez_repr.of_mutez_exn 1000000L in + Assert.equal_int64 + ~loc:__LOC__ + (Tez_repr.to_int64 tz) + Tez_repr.(to_int64 one) + with e -> + let msg = Printexc.to_string e and stack = Printexc.get_backtrace () in + failwith "Unexpected exception: %s %s" msg stack + + let test_of_mutez_exn_negative () = + try + let _ = Tez_repr.of_mutez_exn (-1000000L) in + failwith "should have failed to converted -1000000L to tez" + with + | Invalid_argument _ -> return_unit + | e -> + let msg = Printexc.to_string e and stack = Printexc.get_backtrace () in + failwith "Unexpected exception: %s %s" msg stack + + (* NOTE: Avoid assertions against too many functions from Tez_repr. Convert them to + int64 and compare instead of using [Tez_repr]'s compare *) + + (** Testing [encoding], int64 underneath, by applying it with Data_encoding *) + let test_data_encoding () = + let encoding = Tez_repr.encoding in + let bytes = + Data_encoding.Binary.to_bytes_exn Data_encoding.n (Z.of_int 1000000) + in + (Data_encoding.Binary.of_bytes encoding bytes |> function + | Ok x -> Lwt.return (Ok x) + | Error e -> + failwith + "Data_encoding.Binary.read shouldn't have failed with \ + Tez_repr.encoding: %a" + Data_encoding.Binary.pp_read_error + e) + >>=? fun v -> Assert.equal_int64 ~loc:__LOC__ (Tez_repr.to_mutez v) 1000000L +end + +let tests = + [ + tztest + "Check if predefined values hold expected values" + `Quick + Test_tez_repr.test_predefined_values; + tztest "Tez.substract: basic behaviour" `Quick Test_tez_repr.test_subtract; + tztest + "Tez.substract: underflow case" + `Quick + Test_tez_repr.test_substract_underflow; + tztest + "Tez.add: basic behaviour (one + zero)" + `Quick + Test_tez_repr.test_addition; + tztest "Tez.add: overflow" `Quick Test_tez_repr.test_addition_overflow; + tztest "Tez.mul: basic case" `Quick Test_tez_repr.test_mul; + tztest "Tez.mul: overflow case" `Quick Test_tez_repr.test_mul_overflow; + tztest "Tez.div: basic case" `Quick Test_tez_repr.test_div; + tztest "Tez.div: division by zero" `Quick Test_tez_repr.test_div_by_zero; + tztest "Tez.to_mutez: basic assertion" `Quick Test_tez_repr.test_to_mutez; + tztest + "Tez.of_mutez: of non-negative ints" + `Quick + Test_tez_repr.test_of_mutez_non_negative; + tztest + "Tez.of_mutez: of non-negative ints" + `Quick + Test_tez_repr.test_of_mutez_non_negative; + tztest + "Tez.of_mutez: of negative ints" + `Quick + Test_tez_repr.test_of_mutez_negative; + tztest + "Tez.of_mutez_exn: of non-negative ints" + `Quick + Test_tez_repr.test_of_mutez_non_negative; + tztest + "Tez.of_mutez_exn: of negative ints" + `Quick + Test_tez_repr.test_of_mutez_negative; + tztest + "Tez.data_encoding: must encode tezzies correctly" + `Quick + Test_tez_repr.test_data_encoding; + ] diff --git a/src/proto_011_PtHangzH/lib_protocol/tez_repr.ml b/src/proto_011_PtHangzH/lib_protocol/tez_repr.ml new file mode 100644 index 000000000000..99345920deec --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/tez_repr.ml @@ -0,0 +1,240 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let id = "tez" + +let name = "mutez" + +include Compare.Int64 (* invariant: positive *) + +type error += + | Addition_overflow of t * t (* `Temporary *) + | Subtraction_underflow of t * t (* `Temporary *) + | Multiplication_overflow of t * int64 (* `Temporary *) + | Negative_multiplicator of t * int64 (* `Temporary *) + | Invalid_divisor of t * int64 + +(* `Temporary *) + +let zero = 0L + +(* all other constant are defined from the value of one micro tez *) +let one_mutez = 1L + +let one_cent = Int64.mul one_mutez 10_000L + +let fifty_cents = Int64.mul one_cent 50L + +(* 1 tez = 100 cents = 1_000_000 mutez *) +let one = Int64.mul one_cent 100L + +let of_string s = + let triplets = function + | hd :: tl -> + let len = String.length hd in + Compare.Int.( + len <= 3 && len > 0 && List.for_all (fun s -> String.length s = 3) tl) + | [] -> false + in + let integers s = triplets (String.split_on_char ',' s) in + let decimals s = + let l = String.split_on_char ',' s in + if Compare.Int.(List.length l > 2) then false else triplets (List.rev l) + in + let parse left right = + let remove_commas s = String.concat "" (String.split_on_char ',' s) in + let pad_to_six s = + let len = String.length s in + String.init 6 (fun i -> if Compare.Int.(i < len) then s.[i] else '0') + in + Int64.of_string_opt (remove_commas left ^ pad_to_six (remove_commas right)) + in + match String.split_on_char '.' s with + | [left; right] -> + if String.contains s ',' then + if integers left && decimals right then parse left right else None + else if + Compare.Int.(String.length right > 0) + && Compare.Int.(String.length right <= 6) + then parse left right + else None + | [left] -> + if (not (String.contains s ',')) || integers left then parse left "" + else None + | _ -> None + +let pp ppf amount = + let mult_int = 1_000_000L in + let[@coq_struct "amount"] rec left ppf amount = + let (d, r) = (Int64.(div amount 1000L), Int64.(rem amount 1000L)) in + if d > 0L then Format.fprintf ppf "%a%03Ld" left d r + else Format.fprintf ppf "%Ld" r + in + let right ppf amount = + let triplet ppf v = + if Compare.Int.(v mod 10 > 0) then Format.fprintf ppf "%03d" v + else if Compare.Int.(v mod 100 > 0) then Format.fprintf ppf "%02d" (v / 10) + else Format.fprintf ppf "%d" (v / 100) + in + let (hi, lo) = (amount / 1000, amount mod 1000) in + if Compare.Int.(lo = 0) then Format.fprintf ppf "%a" triplet hi + else Format.fprintf ppf "%03d%a" hi triplet lo + in + let (ints, decs) = + (Int64.(div amount mult_int), Int64.(to_int (rem amount mult_int))) + in + left ppf ints ; + if Compare.Int.(decs > 0) then Format.fprintf ppf ".%a" right decs + +let to_string t = Format.asprintf "%a" pp t + +let ( -? ) t1 t2 = + if t2 <= t1 then ok (Int64.sub t1 t2) + else error (Subtraction_underflow (t1, t2)) + +let ( +? ) t1 t2 = + let t = Int64.add t1 t2 in + if t < t1 then error (Addition_overflow (t1, t2)) else ok t + +let ( *? ) t m = + if m < 0L then error (Negative_multiplicator (t, m)) + else if m = 0L then ok 0L + else if t > Int64.(div max_int m) then error (Multiplication_overflow (t, m)) + else ok (Int64.mul t m) + +let ( /? ) t d = + if d <= 0L then error (Invalid_divisor (t, d)) else ok (Int64.div t d) + +let mul_exn t m = + match t *? Int64.(of_int m) with + | Ok v -> v + | Error _ -> invalid_arg "mul_exn" + +let of_mutez t = if t < 0L then None else Some t + +let of_mutez_exn x = + match of_mutez x with None -> invalid_arg "Tez.of_mutez" | Some v -> v + +let to_int64 t = t + +let to_mutez t = t + +let encoding = + let open Data_encoding in + Data_encoding.def + name + (check_size 10 (conv Z.of_int64 (Json.wrap_error Z.to_int64) n)) + +let () = + let open Data_encoding in + register_error_kind + `Temporary + ~id:(id ^ ".addition_overflow") + ~title:("Overflowing " ^ id ^ " addition") + ~pp:(fun ppf (opa, opb) -> + Format.fprintf + ppf + "Overflowing addition of %a %s and %a %s" + pp + opa + id + pp + opb + id) + ~description:("An addition of two " ^ id ^ " amounts overflowed") + (obj1 (req "amounts" (tup2 encoding encoding))) + (function Addition_overflow (a, b) -> Some (a, b) | _ -> None) + (fun (a, b) -> Addition_overflow (a, b)) ; + register_error_kind + `Temporary + ~id:(id ^ ".subtraction_underflow") + ~title:("Underflowing " ^ id ^ " subtraction") + ~pp:(fun ppf (opa, opb) -> + Format.fprintf + ppf + "Underflowing subtraction of %a %s and %a %s" + pp + opa + id + pp + opb + id) + ~description:("A subtraction of two " ^ id ^ " amounts underflowed") + (obj1 (req "amounts" (tup2 encoding encoding))) + (function Subtraction_underflow (a, b) -> Some (a, b) | _ -> None) + (fun (a, b) -> Subtraction_underflow (a, b)) ; + register_error_kind + `Temporary + ~id:(id ^ ".multiplication_overflow") + ~title:("Overflowing " ^ id ^ " multiplication") + ~pp:(fun ppf (opa, opb) -> + Format.fprintf + ppf + "Overflowing multiplication of %a %s and %Ld" + pp + opa + id + opb) + ~description: + ("A multiplication of a " ^ id ^ " amount by an integer overflowed") + (obj2 (req "amount" encoding) (req "multiplicator" int64)) + (function Multiplication_overflow (a, b) -> Some (a, b) | _ -> None) + (fun (a, b) -> Multiplication_overflow (a, b)) ; + register_error_kind + `Temporary + ~id:(id ^ ".negative_multiplicator") + ~title:("Negative " ^ id ^ " multiplicator") + ~pp:(fun ppf (opa, opb) -> + Format.fprintf + ppf + "Multiplication of %a %s by negative integer %Ld" + pp + opa + id + opb) + ~description:("Multiplication of a " ^ id ^ " amount by a negative integer") + (obj2 (req "amount" encoding) (req "multiplicator" int64)) + (function Negative_multiplicator (a, b) -> Some (a, b) | _ -> None) + (fun (a, b) -> Negative_multiplicator (a, b)) ; + register_error_kind + `Temporary + ~id:(id ^ ".invalid_divisor") + ~title:("Invalid " ^ id ^ " divisor") + ~pp:(fun ppf (opa, opb) -> + Format.fprintf + ppf + "Division of %a %s by non positive integer %Ld" + pp + opa + id + opb) + ~description: + ("Multiplication of a " ^ id ^ " amount by a non positive integer") + (obj2 (req "amount" encoding) (req "divisor" int64)) + (function Invalid_divisor (a, b) -> Some (a, b) | _ -> None) + (fun (a, b) -> Invalid_divisor (a, b)) + +type tez = t diff --git a/src/proto_011_PtHangzH/lib_protocol/tez_repr.mli b/src/proto_011_PtHangzH/lib_protocol/tez_repr.mli new file mode 100644 index 000000000000..1ceabeb83ee5 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/tez_repr.mli @@ -0,0 +1,96 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Internal representation of the Tez currency. Behaves mostly like a natural + number where number 1 represents 1/1,000,000 Tez (1 micro-Tez or mutez). + It's protected from ever becoming negative and overflowing by special + arithmetic functions, which fail in case something undesired would happen. + When divided, it's always rounded down to 1 mutez. + + Internally encoded as [int64], which may be relevant to guard against + overflow errors. *) +type t + +type tez = t + +val zero : t + +val one_mutez : t + +val one_cent : t + +val fifty_cents : t + +val one : t + +(** Tez subtraction. + + [a -? b] is the difference between [a] and [b] given that [b] is greater or + equal to [a]. Otherwise an error ([Subtraction underflow]) is returned. *) +val ( -? ) : t -> t -> t tzresult + +(** Tez addition. + + [a +? b] is the sum of [a] and [b] or an [Addition overflow] error in case + of overflow. *) +val ( +? ) : t -> t -> t tzresult + +(** Tez multiplication by an integral factor. + + [a *? m] is [a] multiplied by [m] (which must be non-negative) or a + [Multiplication_overflow] error. *) +val ( *? ) : t -> int64 -> t tzresult + +(** Tez division by an integral divisor. + + [a /? d] is [a] divided by [d] (which must be positive). Given that [d] + is positive, this function is safe. The result is rounded down to + 1 mutez. *) +val ( /? ) : t -> int64 -> t tzresult + +val to_mutez : t -> int64 + +(** [of_mutez n] (micro tez) is None if n is negative *) +val of_mutez : int64 -> t option + +(** [of_mutez_exn n] fails if n is negative. + It should only be used at toplevel for constants. *) +val of_mutez_exn : int64 -> t + +(** It should only be used at toplevel for constants. *) +val mul_exn : t -> int -> t + +val encoding : t Data_encoding.t + +val to_int64 : t -> int64 + +include Compare.S with type t := t + +val pp : Format.formatter -> t -> unit + +val of_string : string -> t option + +val to_string : t -> string diff --git a/src/proto_011_PtHangzH/lib_protocol/tezos-embedded-protocol-011-PtHangzH.opam b/src/proto_011_PtHangzH/lib_protocol/tezos-embedded-protocol-011-PtHangzH.opam new file mode 100644 index 000000000000..e901dccacf16 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/tezos-embedded-protocol-011-PtHangzH.opam @@ -0,0 +1,25 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-protocol-011-PtHangzH" + "tezos-protocol-compiler" + "tezos-protocol-updater" +] +build: [ + [ + "%{tezos-protocol-compiler:lib}%/replace" + "%{tezos-protocol-compiler:lib}%/dune_protocol.template.v1" + "dune" + "%{tezos-protocol-compiler:lib}%/final_protocol_versions" + "011_PtHangzH" + ] + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: economic-protocol definition, embedded in `tezos-node`" diff --git a/src/proto_011_PtHangzH/lib_protocol/tezos-protocol-011-PtHangzH-tests.opam b/src/proto_011_PtHangzH/lib_protocol/tezos-protocol-011-PtHangzH-tests.opam new file mode 100644 index 000000000000..f7910b005bcd --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/tezos-protocol-011-PtHangzH-tests.opam @@ -0,0 +1,36 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-protocol-compiler" + "alcotest-lwt" { with-test & >= "1.1.0" } + "astring" { with-test } + "tezos-test-helpers" { with-test } + "qcheck-alcotest" { with-test } + "tezos-011-PtHangzH-test-helpers" { with-test } + "tezos-stdlib-unix" { with-test } + "tezos-protocol-environment" { with-test } + "tezos-client-base" { with-test } + "tezos-protocol-011-PtHangzH-parameters" { with-test } + "tezos-shell-services" { with-test } + "tezos-base-test-helpers" { with-test } + "tezos-benchmark" { with-test } + "tezos-benchmark-011-PtHangzH" { with-test } +] +build: [ + [ + "%{tezos-protocol-compiler:lib}%/replace" + "%{tezos-protocol-compiler:lib}%/dune_protocol.template.v1" + "dune" + "%{tezos-protocol-compiler:lib}%/final_protocol_versions" + "011_PtHangzH" + ] + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: tests for economic-protocol definition" diff --git a/src/proto_011_PtHangzH/lib_protocol/tezos-protocol-011-PtHangzH.opam b/src/proto_011_PtHangzH/lib_protocol/tezos-protocol-011-PtHangzH.opam new file mode 100644 index 000000000000..e354d09643c0 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/tezos-protocol-011-PtHangzH.opam @@ -0,0 +1,23 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-protocol-compiler" +] +build: [ + [ + "%{tezos-protocol-compiler:lib}%/replace" + "%{tezos-protocol-compiler:lib}%/dune_protocol.template.v1" + "dune" + "%{tezos-protocol-compiler:lib}%/final_protocol_versions" + "011_PtHangzH" + ] + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: economic-protocol definition" diff --git a/src/proto_011_PtHangzH/lib_protocol/tezos-protocol-functor-011-PtHangzH.opam b/src/proto_011_PtHangzH/lib_protocol/tezos-protocol-functor-011-PtHangzH.opam new file mode 100644 index 000000000000..a8efeef001ad --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/tezos-protocol-functor-011-PtHangzH.opam @@ -0,0 +1,24 @@ +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: [ "Tezos devteam" ] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "2.0" } + "tezos-protocol-011-PtHangzH" + "tezos-protocol-compiler" +] +build: [ + [ + "%{tezos-protocol-compiler:lib}%/replace" + "%{tezos-protocol-compiler:lib}%/dune_protocol.template.v1" + "dune" + "%{tezos-protocol-compiler:lib}%/final_protocol_versions" + "011_PtHangzH" + ] + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tezos/Protocol: economic-protocol definition parameterized by its environment implementation" diff --git a/src/proto_011_PtHangzH/lib_protocol/time_repr.ml b/src/proto_011_PtHangzH/lib_protocol/time_repr.ml new file mode 100644 index 000000000000..fa281d9be61d --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/time_repr.ml @@ -0,0 +1,66 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) +include Time + +type time = Time.t + +type error += Timestamp_add (* `Permanent *) + +type error += Timestamp_sub (* `Permanent *) + +let () = + register_error_kind + `Permanent + ~id:"timestamp_add" + ~title:"Timestamp add" + ~description:"Overflow when adding timestamps." + ~pp:(fun ppf () -> Format.fprintf ppf "Overflow when adding timestamps.") + Data_encoding.empty + (function Timestamp_add -> Some () | _ -> None) + (fun () -> Timestamp_add) ; + register_error_kind + `Permanent + ~id:"timestamp_sub" + ~title:"Timestamp sub" + ~description:"Subtracting timestamps resulted in negative period." + ~pp:(fun ppf () -> + Format.fprintf ppf "Subtracting timestamps resulted in negative period.") + Data_encoding.empty + (function Timestamp_sub -> Some () | _ -> None) + (fun () -> Timestamp_sub) + +let of_seconds_string s = Option.map Time.of_seconds (Int64.of_string_opt s) + +let to_seconds_string s = Int64.to_string (to_seconds s) + +let pp = pp_hum + +let ( +? ) x y = + let span = Period_repr.to_seconds y in + let t64 = Time.add x span in + if t64 < Time.of_seconds 0L then error Timestamp_add else ok t64 + +let ( -? ) x y = + record_trace Timestamp_sub (Period_repr.of_seconds (Time.diff x y)) diff --git a/src/proto_011_PtHangzH/lib_protocol/time_repr.mli b/src/proto_011_PtHangzH/lib_protocol/time_repr.mli new file mode 100644 index 000000000000..32d8a647a39f --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/time_repr.mli @@ -0,0 +1,48 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +include module type of struct + include Time +end + +(** Internal timestamp representation. *) +type time = t + +(** Pretty-prints the time stamp using RFC3339 format. *) +val pp : Format.formatter -> t -> unit + +(** Parses RFC3339 representation and returns a timestamp. *) +val of_seconds_string : string -> time option + +(** Returns the timestamp encoded in RFC3339 format. *) +val to_seconds_string : time -> string + +(** Adds a time span to a timestamp. + This function fails on integer overflow *) +val ( +? ) : time -> Period_repr.t -> time tzresult + +(** Returns the difference between two timestamps as a time span. + This function fails when the difference is negative *) +val ( -? ) : time -> time -> Period_repr.t tzresult diff --git a/src/proto_011_PtHangzH/lib_protocol/vote_repr.ml b/src/proto_011_PtHangzH/lib_protocol/vote_repr.ml new file mode 100644 index 000000000000..e94cc33ddf52 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/vote_repr.ml @@ -0,0 +1,42 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type proposal = Protocol_hash.t + +type ballot = Yay | Nay | Pass + +let ballot_encoding = + let of_int8 = function + | 0 -> Ok Yay + | 1 -> Ok Nay + | 2 -> Ok Pass + | _ -> Error "ballot_of_int8" + in + let to_int8 = function Yay -> 0 | Nay -> 1 | Pass -> 2 in + let open Data_encoding in + (* union *) + splitted + ~binary:(conv_with_guard to_int8 of_int8 int8) + ~json:(string_enum [("yay", Yay); ("nay", Nay); ("pass", Pass)]) diff --git a/src/proto_011_PtHangzH/lib_protocol/vote_repr.mli b/src/proto_011_PtHangzH/lib_protocol/vote_repr.mli new file mode 100644 index 000000000000..8a7d4a59b685 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/vote_repr.mli @@ -0,0 +1,33 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** a protocol change proposal *) +type proposal = Protocol_hash.t + +(** votes can be for, against or neutral. + Neutral serves to count towards a quorum *) +type ballot = Yay | Nay | Pass + +val ballot_encoding : ballot Data_encoding.t diff --git a/src/proto_011_PtHangzH/lib_protocol/vote_storage.ml b/src/proto_011_PtHangzH/lib_protocol/vote_storage.ml new file mode 100644 index 000000000000..d9987a548754 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/vote_storage.ml @@ -0,0 +1,161 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let recorded_proposal_count_for_delegate ctxt proposer = + Storage.Vote.Proposals_count.find ctxt proposer >|=? Option.value ~default:0 + +let record_proposal ctxt proposal proposer = + recorded_proposal_count_for_delegate ctxt proposer >>=? fun count -> + Storage.Vote.Proposals_count.add ctxt proposer (count + 1) >>= fun ctxt -> + Storage.Vote.Proposals.add ctxt (proposal, proposer) >|= ok + +let get_proposals ctxt = + Storage.Vote.Proposals.fold + ctxt + ~init:(ok Protocol_hash.Map.empty) + ~f:(fun (proposal, delegate) acc -> + (* Assuming the same listings is used at votings *) + Storage.Vote.Listings.get ctxt delegate >>=? fun weight -> + Lwt.return + ( acc >|? fun acc -> + let previous = + match Protocol_hash.Map.find proposal acc with + | None -> 0l + | Some x -> x + in + Protocol_hash.Map.add proposal (Int32.add weight previous) acc )) + +let clear_proposals ctxt = + Storage.Vote.Proposals_count.clear ctxt >>= fun ctxt -> + Storage.Vote.Proposals.clear ctxt + +type ballots = {yay : int32; nay : int32; pass : int32} + +let ballots_encoding = + let open Data_encoding in + conv + (fun {yay; nay; pass} -> (yay, nay, pass)) + (fun (yay, nay, pass) -> {yay; nay; pass}) + @@ obj3 (req "yay" int32) (req "nay" int32) (req "pass" int32) + +let has_recorded_ballot = Storage.Vote.Ballots.mem + +let record_ballot = Storage.Vote.Ballots.init + +let get_ballots ctxt = + Storage.Vote.Ballots.fold + ctxt + ~f:(fun delegate ballot (ballots : ballots tzresult) -> + (* Assuming the same listings is used at votings *) + Storage.Vote.Listings.get ctxt delegate >>=? fun weight -> + let count = Int32.add weight in + Lwt.return + ( ballots >|? fun ballots -> + match ballot with + | Yay -> {ballots with yay = count ballots.yay} + | Nay -> {ballots with nay = count ballots.nay} + | Pass -> {ballots with pass = count ballots.pass} )) + ~init:(ok {yay = 0l; nay = 0l; pass = 0l}) + +let get_ballot_list = Storage.Vote.Ballots.bindings + +let clear_ballots = Storage.Vote.Ballots.clear + +let listings_encoding = + Data_encoding.( + list + (obj2 (req "pkh" Signature.Public_key_hash.encoding) (req "rolls" int32))) + +let update_listings ctxt = + Storage.Vote.Listings.clear ctxt >>= fun ctxt -> + Roll_storage.fold ctxt (ctxt, 0l) ~f:(fun _roll delegate (ctxt, total) -> + (* TODO use snapshots *) + let delegate = Signature.Public_key.hash delegate in + Storage.Vote.Listings.find ctxt delegate >|=? Option.value ~default:0l + >>=? fun count -> + Storage.Vote.Listings.add ctxt delegate (Int32.succ count) >|= fun ctxt -> + ok (ctxt, Int32.succ total)) + >>=? fun (ctxt, total) -> + Storage.Vote.Listings_size.add ctxt total >>= fun ctxt -> return ctxt + +let listing_size = Storage.Vote.Listings_size.get + +let in_listings = Storage.Vote.Listings.mem + +let get_listings = Storage.Vote.Listings.bindings + +let get_voting_power_free ctxt owner = + Storage.Vote.Listings.find ctxt owner >|=? Option.value ~default:0l + +(* This function bypasses the carbonated functors to account for gas consumption. + This is a temporary situation intended to be fixed by adding the right + carbonated functors in a future amendment *) +let get_voting_power ctxt owner = + let open Raw_context in + (* Always consume read access to memory *) + (* Accessing an int32 at /votes/listings// *) + consume_gas ctxt (Storage_costs.read_access ~path_length:4 ~read_bytes:4) + >>?= fun ctxt -> + Storage.Vote.Listings.find ctxt owner >|=? function + | None -> (ctxt, 0l) + | Some power -> (ctxt, power) + +let get_total_voting_power_free = listing_size + +(* This function bypasses the carbonated functors to account for gas consumption. + This is a temporary situation intended to be fixed by adding the right + carbonated functors in a future amendment *) +let get_total_voting_power ctxt = + let open Raw_context in + (* Accessing an int32 at /votes/listings_size *) + consume_gas ctxt (Storage_costs.read_access ~path_length:2 ~read_bytes:4) + >>?= fun ctxt -> + get_total_voting_power_free ctxt >|=? fun total_voting_power -> + (ctxt, total_voting_power) + +let get_current_quorum ctxt = + Storage.Vote.Participation_ema.get ctxt >|=? fun participation_ema -> + let quorum_min = Constants_storage.quorum_min ctxt in + let quorum_max = Constants_storage.quorum_max ctxt in + let quorum_diff = Int32.sub quorum_max quorum_min in + Int32.(add quorum_min (div (mul participation_ema quorum_diff) 100_00l)) + +let get_participation_ema = Storage.Vote.Participation_ema.get + +let set_participation_ema = Storage.Vote.Participation_ema.update + +let get_current_proposal = Storage.Vote.Current_proposal.get + +let find_current_proposal = Storage.Vote.Current_proposal.find + +let init_current_proposal = Storage.Vote.Current_proposal.init + +let clear_current_proposal = Storage.Vote.Current_proposal.remove_existing + +let init ctxt ~start_position = + (* participation EMA is in centile of a percentage *) + let participation_ema = Constants_storage.quorum_max ctxt in + Storage.Vote.Participation_ema.init ctxt participation_ema >>=? fun ctxt -> + Voting_period_storage.init_first_period ctxt ~start_position diff --git a/src/proto_011_PtHangzH/lib_protocol/vote_storage.mli b/src/proto_011_PtHangzH/lib_protocol/vote_storage.mli new file mode 100644 index 000000000000..5bfc0ae34eb5 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/vote_storage.mli @@ -0,0 +1,116 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Manages all the voting related storage in Storage.Vote. *) + +(** Records a protocol proposal with the delegate that proposed it. *) +val record_proposal : + Raw_context.t -> + Protocol_hash.t -> + Signature.Public_key_hash.t -> + Raw_context.t tzresult Lwt.t + +val recorded_proposal_count_for_delegate : + Raw_context.t -> Signature.Public_key_hash.t -> int tzresult Lwt.t + +(** Computes for each proposal how many delegates proposed it. *) +val get_proposals : Raw_context.t -> int32 Protocol_hash.Map.t tzresult Lwt.t + +val clear_proposals : Raw_context.t -> Raw_context.t Lwt.t + +(** Counts of the votes *) +type ballots = {yay : int32; nay : int32; pass : int32} + +val ballots_encoding : ballots Data_encoding.t + +val has_recorded_ballot : + Raw_context.t -> Signature.Public_key_hash.t -> bool Lwt.t + +(** Records a vote for a delegate, returns a {!Storage_error Existing_key} if + the vote was already registered *) +val record_ballot : + Raw_context.t -> + Signature.Public_key_hash.t -> + Vote_repr.ballot -> + Raw_context.t tzresult Lwt.t + +(** Computes the sum of the current ballots weighted by stake. *) +val get_ballots : Raw_context.t -> ballots tzresult Lwt.t + +val get_ballot_list : + Raw_context.t -> (Signature.Public_key_hash.t * Vote_repr.ballot) list Lwt.t + +val clear_ballots : Raw_context.t -> Raw_context.t Lwt.t + +val listings_encoding : + (Signature.Public_key_hash.t * int32) list Data_encoding.t + +(** Populates [!Storage.Vote.Listings] using the currently existing rolls and + sets Listings_size. Delegates without rolls are not included in the listing. *) +val update_listings : Raw_context.t -> Raw_context.t tzresult Lwt.t + +(** Returns the sum of all rolls of all delegates. *) +val listing_size : Raw_context.t -> int32 tzresult Lwt.t + +(** Verifies the presence of a delegate in the listing. *) +val in_listings : Raw_context.t -> Signature.Public_key_hash.t -> bool Lwt.t + +val get_listings : + Raw_context.t -> (Signature.Public_key_hash.t * int32) list Lwt.t + +val get_voting_power_free : + Raw_context.t -> Signature.public_key_hash -> int32 tzresult Lwt.t + +val get_voting_power : + Raw_context.t -> + Signature.public_key_hash -> + (Raw_context.t * int32) tzresult Lwt.t + +val get_total_voting_power_free : Raw_context.t -> int32 tzresult Lwt.t + +val get_total_voting_power : + Raw_context.t -> (Raw_context.t * int32) tzresult Lwt.t + +val get_current_quorum : Raw_context.t -> int32 tzresult Lwt.t + +val get_participation_ema : Raw_context.t -> int32 tzresult Lwt.t + +val set_participation_ema : + Raw_context.t -> int32 -> Raw_context.t tzresult Lwt.t + +val get_current_proposal : Raw_context.t -> Protocol_hash.t tzresult Lwt.t + +val find_current_proposal : + Raw_context.t -> Protocol_hash.t option tzresult Lwt.t + +val init_current_proposal : + Raw_context.t -> Protocol_hash.t -> Raw_context.t tzresult Lwt.t + +val clear_current_proposal : Raw_context.t -> Raw_context.t tzresult Lwt.t + +(** Sets the initial quorum to 80% and period kind to proposal. *) +val init : + Raw_context.t -> start_position:Int32.t -> Raw_context.t tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/voting_period_repr.ml b/src/proto_011_PtHangzH/lib_protocol/voting_period_repr.ml new file mode 100644 index 000000000000..de4cf915bc46 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/voting_period_repr.ml @@ -0,0 +1,175 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type kind = Proposal | Exploration | Cooldown | Promotion | Adoption + +let string_of_kind = function + | Proposal -> "proposal" + | Exploration -> "exploration" + | Cooldown -> "cooldown" + | Promotion -> "promotion" + | Adoption -> "adoption" + +let pp_kind ppf kind = Format.fprintf ppf "%s" @@ string_of_kind kind + +let kind_encoding = + let open Data_encoding in + union + ~tag_size:`Uint8 + [ + case + (Tag 0) + ~title:"Proposal" + (constant "proposal") + (function Proposal -> Some () | _ -> None) + (fun () -> Proposal); + case + (Tag 1) + ~title:"exploration" + (constant "exploration") + (function Exploration -> Some () | _ -> None) + (fun () -> Exploration); + case + (Tag 2) + ~title:"Cooldown" + (constant "cooldown") + (function Cooldown -> Some () | _ -> None) + (fun () -> Cooldown); + case + (Tag 3) + ~title:"Promotion" + (constant "promotion") + (function Promotion -> Some () | _ -> None) + (fun () -> Promotion); + case + (Tag 4) + ~title:"Adoption" + (constant "adoption") + (function Adoption -> Some () | _ -> None) + (fun () -> Adoption); + ] + +let succ_kind = function + | Proposal -> Exploration + | Exploration -> Cooldown + | Cooldown -> Promotion + | Promotion -> Adoption + | Adoption -> Proposal + +type voting_period = {index : int32; kind : kind; start_position : int32} + +type t = voting_period + +type info = {voting_period : t; position : int32; remaining : int32} + +let root ~start_position = {index = 0l; kind = Proposal; start_position} + +let pp ppf {index; kind; start_position} = + Format.fprintf + ppf + "@[index: %ld,@ kind:%a,@ start_position: %ld@]" + index + pp_kind + kind + start_position + +let pp_info ppf {voting_period; position; remaining} = + Format.fprintf + ppf + "@[voting_period: %a,@ position:%ld,@ remaining: %ld@]" + pp + voting_period + position + remaining + +let encoding = + let open Data_encoding in + conv + (fun {index; kind; start_position} -> (index, kind, start_position)) + (fun (index, kind, start_position) -> {index; kind; start_position}) + (obj3 + (req + "index" + ~description: + "The voting period's index. Starts at 0 with the first block of \ + the Alpha family of protocols." + int32) + (req + ~description: + "One of the several kinds of periods in the voting procedure." + "kind" + kind_encoding) + (req + ~description: + "The relative position of the first level of the period with \ + respect to the first level of the Alpha family of protocols." + "start_position" + int32)) + +let info_encoding = + let open Data_encoding in + conv + (fun {voting_period; position; remaining} -> + (voting_period, position, remaining)) + (fun (voting_period, position, remaining) -> + {voting_period; position; remaining}) + (obj3 + (req + ~description:"The voting period to which the block belongs." + "voting_period" + encoding) + (req + ~description:"The position of the block within the voting period." + "position" + int32) + (req + ~description: + "The number of blocks remaining till the end of the voting period." + "remaining" + int32)) + +include Compare.Make (struct + type nonrec t = t + + let compare p p' = Compare.Int32.compare p.index p'.index +end) + +let raw_reset period ~start_position = + let index = Int32.succ period.index in + let kind = Proposal in + {index; kind; start_position} + +let raw_succ period ~start_position = + let index = Int32.succ period.index in + let kind = succ_kind period.kind in + {index; kind; start_position} + +let position_since (level : Level_repr.t) (voting_period : t) = + Int32.(sub level.level_position voting_period.start_position) + +let remaining_blocks (level : Level_repr.t) (voting_period : t) + ~blocks_per_voting_period = + let position = position_since level voting_period in + Int32.(sub blocks_per_voting_period (succ position)) diff --git a/src/proto_011_PtHangzH/lib_protocol/voting_period_repr.mli b/src/proto_011_PtHangzH/lib_protocol/voting_period_repr.mli new file mode 100644 index 000000000000..028281ec567e --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/voting_period_repr.mli @@ -0,0 +1,82 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** The voting period kinds are ordered as follows: + Proposal -> Testing_vote -> Testing -> Promotion -> Adoption. + This order is the one used be the function [succ] below. + *) +type kind = + | Proposal (** protocols can be proposed *) + | Exploration (** a proposal can be voted *) + | Cooldown (** a delay before the second vote of the Promotion period. *) + | Promotion (** activation can be voted *) + | Adoption (** a delay before activation *) + +val kind_encoding : kind Data_encoding.t + +(** A voting period can be of several kinds and is uniquely identified by + the counter 'index'. The 'start_position' represents the relative + position of the first level of the period with respect to the + first level of the Alpha family of protocols. *) +type voting_period = {index : Int32.t; kind : kind; start_position : Int32.t} + +type t = voting_period + +(** Information about a block with respect to the voting period it + belongs to: the voting period, the position within the voting + period and the number of remaining blocks till the end of the + period. The following invariant is satisfied: + `position + remaining + 1 = blocks_per_voting_period` *) +type info = {voting_period : t; position : Int32.t; remaining : Int32.t} + +val root : start_position:Int32.t -> t + +include Compare.S with type t := voting_period + +val encoding : t Data_encoding.t + +val info_encoding : info Data_encoding.t + +val pp : Format.formatter -> t -> unit + +val pp_info : Format.formatter -> info -> unit + +val pp_kind : Format.formatter -> kind -> unit + +(** [raw_reset period ~start_position] increment the index by one and set the + kind to Proposal which is the period kind that start the voting + process. [start_position] is the level at wich this voting_period started. +*) +val raw_reset : t -> start_position:Int32.t -> t + +(** [raw_succ period ~start_position] increment the index by one and set the + kind to its successor. [start_position] is the level at which this + voting_period started. *) +val raw_succ : t -> start_position:Int32.t -> t + +val position_since : Level_repr.t -> t -> Int32.t + +val remaining_blocks : + Level_repr.t -> t -> blocks_per_voting_period:Int32.t -> Int32.t diff --git a/src/proto_011_PtHangzH/lib_protocol/voting_period_storage.ml b/src/proto_011_PtHangzH/lib_protocol/voting_period_storage.ml new file mode 100644 index 000000000000..b6a9156bb7a1 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/voting_period_storage.ml @@ -0,0 +1,191 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* + The shell uses the convention that a context at level n is the resulting + context of the application of block n. + Therefore when using an RPC on the last level of a voting period, the context + that is inspected is the resulting one. + + However [Amendment.may_start_new_voting_period] is run at the end of voting + period and it has to prepare the context for validating operations of the next + period. This causes the counter-intuitive result that the info returned by RPCs + at last level of a voting period mention data of the next voting period. + + For example, when validating the last block of a proposal period at level n + we have: + - Input context: + + voting_period = { kind = Proposal; + index = i; + start_position = n - blocks_per_voting_period} + + - position = n - start_position = blocks_per_voting_period + - remaining = blocks_per_voting_period - (position + 1) = 0 + + - Output context: + + voting_period = { kind = Exploration; + index = i + 1; + start_position = n + 1} + + Now if we calculate position and remaining in the voting period we get + strange results: + - position = n - (n + 1) = -1 + - remaining = blocks_per_voting_period + + To work around this issue, two RPCs were added + `Voting_period_storage.get_rpc_current_info`, which returns the correct + info also for the last context of a period, and + `Voting_period_storage.get_rpc_succ_info`, which can be used at the last + context of a period to craft operations that will be valid for the first + block of the new period. + + This odd behaviour could be fixed if [Amendment.may_start_new_voting_period] + was called when we start validating the first block of a voting period instead + that at the end of the validation of the last block of a voting period. + This should be carefully done because the voting period listing depends on + the rolls and it might break some invariant. + + When this is implemented one should: + - edit the function [reset_current] and [inc_current] to use the + current level and not the next one. + - remove the storage for pred_kind + - make Voting_period_repr.t abstract + + You can also look at the MR description here: + https://gitlab.com/metastatedev/tezos/-/merge_requests/333 + *) + +(* Voting periods start at the first block of a cycle. More formally, + the invariant of start_position with respect to cycle_position is: + cycle_position mod blocks_per_cycle == + position_in_period mod blocks_per_cycle *) + +let set_current = Storage.Vote.Current_period.update + +let get_current = Storage.Vote.Current_period.get + +let init = Storage.Vote.Current_period.init + +let init_first_period ctxt ~start_position = + init ctxt @@ Voting_period_repr.root ~start_position >>=? fun ctxt -> + Storage.Vote.Pred_period_kind.init ctxt Voting_period_repr.Proposal + +let common ctxt = + get_current ctxt >>=? fun current_period -> + Storage.Vote.Pred_period_kind.update ctxt current_period.kind >|=? fun ctxt -> + let start_position = + (* because we are preparing the voting period for the next block we need to + use the next level. *) + Int32.succ (Level_storage.current ctxt).level_position + in + (ctxt, current_period, start_position) + +let reset ctxt = + common ctxt >>=? fun (ctxt, current_period, start_position) -> + Voting_period_repr.raw_reset current_period ~start_position + |> set_current ctxt + +let succ ctxt = + common ctxt >>=? fun (ctxt, current_period, start_position) -> + Voting_period_repr.raw_succ current_period ~start_position |> set_current ctxt + +let get_current_kind ctxt = get_current ctxt >|=? fun {kind; _} -> kind + +let get_current_info ctxt = + get_current ctxt >|=? fun voting_period -> + let blocks_per_voting_period = + Constants_storage.blocks_per_voting_period ctxt + in + let level = Level_storage.current ctxt in + let position = Voting_period_repr.position_since level voting_period in + let remaining = + Voting_period_repr.remaining_blocks + level + voting_period + ~blocks_per_voting_period + in + Voting_period_repr.{voting_period; position; remaining} + +let get_current_remaining ctxt = + get_current ctxt >|=? fun voting_period -> + let blocks_per_voting_period = + Constants_storage.blocks_per_voting_period ctxt + in + Voting_period_repr.remaining_blocks + (Level_storage.current ctxt) + voting_period + ~blocks_per_voting_period + +let is_last_block ctxt = + get_current_remaining ctxt >|=? fun remaining -> + Compare.Int32.(remaining = 0l) + +let get_rpc_current_info ctxt = + get_current_info ctxt + >>=? fun ({voting_period; position; _} as voting_period_info) -> + if Compare.Int32.(position = Int32.minus_one) then + let level = Level_storage.current ctxt in + let blocks_per_voting_period = + Constants_storage.blocks_per_voting_period ctxt + in + Storage.Vote.Pred_period_kind.get ctxt >|=? fun pred_kind -> + let voting_period : Voting_period_repr.t = + { + index = Int32.pred voting_period.index; + kind = pred_kind; + start_position = + Int32.(sub voting_period.start_position blocks_per_voting_period); + } + in + let position = Voting_period_repr.position_since level voting_period in + let remaining = + Voting_period_repr.remaining_blocks + level + voting_period + ~blocks_per_voting_period + in + ({voting_period; remaining; position} : Voting_period_repr.info) + else return voting_period_info + +let get_rpc_succ_info ctxt = + Level_storage.from_raw_with_offset + ctxt + ~offset:1l + (Level_storage.current ctxt).level + >>?= fun level -> + get_current ctxt >|=? fun voting_period -> + let blocks_per_voting_period = + Constants_storage.blocks_per_voting_period ctxt + in + let position = Voting_period_repr.position_since level voting_period in + let remaining = + Voting_period_repr.remaining_blocks + level + voting_period + ~blocks_per_voting_period + in + Voting_period_repr.{voting_period; position; remaining} diff --git a/src/proto_011_PtHangzH/lib_protocol/voting_period_storage.mli b/src/proto_011_PtHangzH/lib_protocol/voting_period_storage.mli new file mode 100644 index 000000000000..f18dc5e9aa10 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/voting_period_storage.mli @@ -0,0 +1,51 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 Metastate AG *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +val init : Raw_context.t -> Voting_period_repr.t -> Raw_context.t tzresult Lwt.t + +(** Sets the initial period to [{voting_period = root; kind = Proposal; + start_position}]. *) +val init_first_period : + Raw_context.t -> start_position:Int32.t -> Raw_context.t tzresult Lwt.t + +(** Increment the index by one and set the kind to Proposal. *) +val reset : Raw_context.t -> Raw_context.t tzresult Lwt.t + +(** Increment the index by one and set the kind to its successor. *) +val succ : Raw_context.t -> Raw_context.t tzresult Lwt.t + +val get_current : Raw_context.t -> Voting_period_repr.t tzresult Lwt.t + +val get_current_kind : Raw_context.t -> Voting_period_repr.kind tzresult Lwt.t + +(** Returns true if the context level is the last of current voting period. *) +val is_last_block : Raw_context.t -> bool tzresult Lwt.t + +(** Returns the voting period information for the current level. *) +val get_rpc_current_info : + Raw_context.t -> Voting_period_repr.info tzresult Lwt.t + +(** Returns the voting period information for the next level. *) +val get_rpc_succ_info : Raw_context.t -> Voting_period_repr.info tzresult Lwt.t diff --git a/src/proto_011_PtHangzH/lib_protocol/voting_services.ml b/src/proto_011_PtHangzH/lib_protocol/voting_services.ml new file mode 100644 index 000000000000..0ff6088eb536 --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/voting_services.ml @@ -0,0 +1,152 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +module S = struct + let path = RPC_path.(open_root / "votes") + + let ballots = + RPC_service.get_service + ~description:"Sum of ballots casted so far during a voting period." + ~query:RPC_query.empty + ~output:Vote.ballots_encoding + RPC_path.(path / "ballots") + + let ballot_list = + RPC_service.get_service + ~description:"Ballots casted so far during a voting period." + ~query:RPC_query.empty + ~output: + Data_encoding.( + list + (obj2 + (req "pkh" Signature.Public_key_hash.encoding) + (req "ballot" Vote.ballot_encoding))) + RPC_path.(path / "ballot_list") + + let current_period = + RPC_service.get_service + ~description: + "Returns the voting period (index, kind, starting position) and \ + related information (position, remaining) of the interrogated block." + ~query:RPC_query.empty + ~output:Voting_period.info_encoding + RPC_path.(path / "current_period") + + let successor_period = + RPC_service.get_service + ~description: + "Returns the voting period (index, kind, starting position) and \ + related information (position, remaining) of the next block.Useful to \ + craft operations that will be valid in the next block." + ~query:RPC_query.empty + ~output:Voting_period.info_encoding + RPC_path.(path / "successor_period") + + let current_quorum = + RPC_service.get_service + ~description:"Current expected quorum." + ~query:RPC_query.empty + ~output:Data_encoding.int32 + RPC_path.(path / "current_quorum") + + let listings = + RPC_service.get_service + ~description: + "List of delegates with their voting weight, in number of rolls." + ~query:RPC_query.empty + ~output:Vote.listings_encoding + RPC_path.(path / "listings") + + let proposals = + RPC_service.get_service + ~description:"List of proposals with number of supporters." + ~query:RPC_query.empty + ~output:(Protocol_hash.Map.encoding Data_encoding.int32) + RPC_path.(path / "proposals") + + let current_proposal = + RPC_service.get_service + ~description:"Current proposal under evaluation." + ~query:RPC_query.empty + ~output:(Data_encoding.option Protocol_hash.encoding) + RPC_path.(path / "current_proposal") + + let total_voting_power = + RPC_service.get_service + ~description: + "Total number of rolls for the delegates in the voting listings." + ~query:RPC_query.empty + ~output:Data_encoding.int32 + RPC_path.(path / "total_voting_power") +end + +let register () = + let open Services_registration in + register0 ~chunked:false S.ballots (fun ctxt () () -> Vote.get_ballots ctxt) ; + register0 ~chunked:true S.ballot_list (fun ctxt () () -> + Vote.get_ballot_list ctxt >|= ok) ; + register0 ~chunked:false S.current_period (fun ctxt () () -> + Voting_period.get_rpc_current_info ctxt) ; + register0 ~chunked:false S.successor_period (fun ctxt () () -> + Voting_period.get_rpc_succ_info ctxt) ; + register0 ~chunked:false S.current_quorum (fun ctxt () () -> + Vote.get_current_quorum ctxt) ; + register0 ~chunked:true S.proposals (fun ctxt () () -> + Vote.get_proposals ctxt) ; + register0 ~chunked:true S.listings (fun ctxt () () -> + Vote.get_listings ctxt >|= ok) ; + register0 ~chunked:false S.current_proposal (fun ctxt () () -> + Vote.find_current_proposal ctxt) ; + register0 ~chunked:false S.total_voting_power (fun ctxt () () -> + Vote.get_total_voting_power_free ctxt) + [@@coq_axiom_with_reason + "disabled because we would need to re-create the error e in order to have \ + different polymorphic variables"] + +let ballots ctxt block = RPC_context.make_call0 S.ballots ctxt block () () + +let ballot_list ctxt block = + RPC_context.make_call0 S.ballot_list ctxt block () () + +let current_period ctxt block = + RPC_context.make_call0 S.current_period ctxt block () () + +let successor_period ctxt block = + RPC_context.make_call0 S.successor_period ctxt block () () + +let current_quorum ctxt block = + RPC_context.make_call0 S.current_quorum ctxt block () () + +let listings ctxt block = RPC_context.make_call0 S.listings ctxt block () () + +let proposals ctxt block = RPC_context.make_call0 S.proposals ctxt block () () + +let current_proposal ctxt block = + RPC_context.make_call0 S.current_proposal ctxt block () () + +let total_voting_power ctxt block = + RPC_context.make_call0 S.total_voting_power ctxt block () () diff --git a/src/proto_011_PtHangzH/lib_protocol/voting_services.mli b/src/proto_011_PtHangzH/lib_protocol/voting_services.mli new file mode 100644 index 000000000000..d56157aa6c1a --- /dev/null +++ b/src/proto_011_PtHangzH/lib_protocol/voting_services.mli @@ -0,0 +1,60 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Alpha_context + +val ballots : 'a #RPC_context.simple -> 'a -> Vote.ballots shell_tzresult Lwt.t + +val ballot_list : + 'a #RPC_context.simple -> + 'a -> + (Signature.Public_key_hash.t * Vote.ballot) list shell_tzresult Lwt.t + +val current_period : + 'a #RPC_context.simple -> 'a -> Voting_period.info shell_tzresult Lwt.t + +val successor_period : + 'a #RPC_context.simple -> 'a -> Voting_period.info shell_tzresult Lwt.t + +val current_quorum : + 'a #RPC_context.simple -> 'a -> Int32.t shell_tzresult Lwt.t + +val listings : + 'a #RPC_context.simple -> + 'a -> + (Signature.Public_key_hash.t * int32) list shell_tzresult Lwt.t + +val proposals : + 'a #RPC_context.simple -> + 'a -> + Int32.t Protocol_hash.Map.t shell_tzresult Lwt.t + +val current_proposal : + 'a #RPC_context.simple -> 'a -> Protocol_hash.t option shell_tzresult Lwt.t + +val register : unit -> unit + +val total_voting_power : + 'a #RPC_context.simple -> 'a -> Int32.t shell_tzresult Lwt.t diff --git a/tests_python/contracts_011/attic/accounts.tz b/tests_python/contracts_011/attic/accounts.tz new file mode 100644 index 000000000000..904a003f4f60 --- /dev/null +++ b/tests_python/contracts_011/attic/accounts.tz @@ -0,0 +1,54 @@ +# This is a very simple accounts system. +# (Left key) initializes or deposits into an account +# (Right key (pair mutez (signed mutez))) withdraws mutez amount to a +# IMPLICIT_ACCOUNT created from the key if the balance is available +# and the key is correctly signed +parameter (or (key_hash %Initialize) + (pair %Withdraw + (key %from) + (pair + (mutez %withdraw_amount) + (signature %sig)))); +# Maps the key to the balance they have stored +storage (map :stored_balance key_hash mutez); +code { DUP; CAR; + # Deposit into account + IF_LEFT { DUP; DIIP{ CDR %stored_balance; DUP }; + DIP{ SWAP }; GET @opt_prev_balance; + # Create the account + IF_SOME # Add to an existing account + { RENAME @previous_balance; + AMOUNT; ADD; SOME; SWAP; UPDATE; NIL operation; PAIR } + { DIP{ AMOUNT; SOME }; UPDATE; NIL operation; PAIR }} + # Withdrawal + { DUP; DUP; DUP; DUP; + # Check signature on data + CAR %from; + DIIP{ CDAR %withdraw_amount; PACK ; BLAKE2B @signed_amount }; + DIP{ CDDR %sig }; CHECK_SIGNATURE; + IF {} { PUSH string "Bad signature"; FAILWITH }; + # Get user account information + DIIP{ CDR %stored_balance; DUP }; + CAR %from; HASH_KEY @from_hash; DUP; DIP{ DIP { SWAP }; SWAP}; GET; + # Account does not exist + IF_NONE { PUSH string "Account does not exist"; PAIR; FAILWITH } + # Account exists + { RENAME @previous_balance; + DIP { DROP }; + DUP; DIIP{ DUP; CDAR %withdraw_amount; DUP }; + # Ensure funds are available + DIP{ CMPLT @not_enough }; SWAP; + IF { PUSH string "Not enough funds"; FAILWITH } + { SUB @new_balance; DIP{ DUP; DIP{ SWAP }}; DUP; + # Delete account if balance is 0 + PUSH @zero mutez 0; CMPEQ @null_balance; + IF { DROP; NONE @new_balance mutez } + # Otherwise update storage with new balance + { SOME @new_balance }; + SWAP; CAR %from; HASH_KEY @from_hash; UPDATE; + SWAP; DUP; CDAR %withdraw_amount; + # Execute the transfer + DIP{ CAR %from; HASH_KEY @from_hash; IMPLICIT_ACCOUNT @from_account}; UNIT; + TRANSFER_TOKENS @withdraw_transfer_op; + NIL operation; SWAP; CONS; + PAIR }}}} diff --git a/tests_python/contracts_011/attic/add1.tz b/tests_python/contracts_011/attic/add1.tz new file mode 100644 index 000000000000..78d4f9d1c020 --- /dev/null +++ b/tests_python/contracts_011/attic/add1.tz @@ -0,0 +1,7 @@ +parameter int; +storage int; +code {CAR; # Get the parameter + PUSH int 1; # We're adding 1, so we need to put 1 on the stack + ADD; # Add the two numbers + NIL operation; # We put an empty list of operations on the stack + PAIR} # Create the end value diff --git a/tests_python/contracts_011/attic/add1_list.tz b/tests_python/contracts_011/attic/add1_list.tz new file mode 100644 index 000000000000..c11616286475 --- /dev/null +++ b/tests_python/contracts_011/attic/add1_list.tz @@ -0,0 +1,6 @@ +parameter (list int); +storage (list int); +code { CAR; # Get the parameter + MAP { PUSH int 1; ADD }; # Map over the list adding one + NIL operation; # No internal op + PAIR } # Match the calling convention diff --git a/tests_python/contracts_011/attic/after_strategy.tz b/tests_python/contracts_011/attic/after_strategy.tz new file mode 100644 index 000000000000..70812e52b200 --- /dev/null +++ b/tests_python/contracts_011/attic/after_strategy.tz @@ -0,0 +1,3 @@ +parameter nat; +storage (pair (pair nat bool) timestamp); +code {DUP; CAR; DIP{CDDR; DUP; NOW; CMPGT}; PAIR; PAIR ; NIL operation ; PAIR}; diff --git a/tests_python/contracts_011/attic/always.tz b/tests_python/contracts_011/attic/always.tz new file mode 100644 index 000000000000..a7802fec96c8 --- /dev/null +++ b/tests_python/contracts_011/attic/always.tz @@ -0,0 +1,4 @@ +parameter nat; +storage (pair nat bool); +code { CAR; PUSH bool True; SWAP; + PAIR; NIL operation; PAIR} diff --git a/tests_python/contracts_011/attic/append.tz b/tests_python/contracts_011/attic/append.tz new file mode 100644 index 000000000000..3b8335455dcd --- /dev/null +++ b/tests_python/contracts_011/attic/append.tz @@ -0,0 +1,8 @@ +parameter (pair (list int) (list int)); +storage (list int); +code { CAR; UNPAIR ; # Unpack lists + NIL int; SWAP; # Setup reverse accumulator + ITER {CONS}; # Reverse list + ITER {CONS}; # Append reversed list + NIL operation; + PAIR} diff --git a/tests_python/contracts_011/attic/at_least.tz b/tests_python/contracts_011/attic/at_least.tz new file mode 100644 index 000000000000..6c6d2968cd12 --- /dev/null +++ b/tests_python/contracts_011/attic/at_least.tz @@ -0,0 +1,6 @@ +parameter unit; +storage mutez; # How much you have to send me +code {CDR; DUP; # Get the amount required (once for comparison, once to save back in storage) + AMOUNT; CMPLT; # Check to make sure no one is wasting my time + IF {FAIL} # Reject the person + {NIL operation;PAIR}} # Finish the transaction diff --git a/tests_python/contracts_011/attic/auction.tz b/tests_python/contracts_011/attic/auction.tz new file mode 100644 index 000000000000..af8aedfb7c22 --- /dev/null +++ b/tests_python/contracts_011/attic/auction.tz @@ -0,0 +1,8 @@ +parameter key_hash; +storage (pair timestamp (pair mutez key_hash)); +code { DUP; CDAR; DUP; NOW; CMPGT; IF {FAIL} {}; SWAP; # Check if auction has ended + DUP; CAR; DIP{CDDR}; AMOUNT; PAIR; SWAP; DIP{SWAP; PAIR}; # Setup replacement storage + DUP; CAR; AMOUNT; CMPLE; IF {FAIL} {}; # Check to make sure that the new amount is greater + DUP; CAR; # Get amount of refund + DIP{CDR; IMPLICIT_ACCOUNT}; UNIT; TRANSFER_TOKENS; # Make refund + NIL operation; SWAP; CONS; PAIR} # Calling convention diff --git a/tests_python/contracts_011/attic/bad_lockup.tz b/tests_python/contracts_011/attic/bad_lockup.tz new file mode 100644 index 000000000000..f334e899e71c --- /dev/null +++ b/tests_python/contracts_011/attic/bad_lockup.tz @@ -0,0 +1,6 @@ +parameter unit; +storage (pair timestamp (pair address address)); +code { CDR; DUP; CAR; NOW; CMPLT; IF {FAIL} {}; + DUP; CDAR; CONTRACT unit ; ASSERT_SOME ; PUSH mutez 100000000; UNIT; TRANSFER_TOKENS; SWAP; + DUP; CDDR; CONTRACT unit ; ASSERT_SOME ; PUSH mutez 100000000; UNIT; TRANSFER_TOKENS; DIP {SWAP} ; + NIL operation ; SWAP ; CONS ; SWAP ; CONS ; PAIR } diff --git a/tests_python/contracts_011/attic/big_map_union.tz b/tests_python/contracts_011/attic/big_map_union.tz new file mode 100644 index 000000000000..0c971ff11ce9 --- /dev/null +++ b/tests_python/contracts_011/attic/big_map_union.tz @@ -0,0 +1,8 @@ +parameter (list (pair string int)) ; +storage (pair (big_map string int) unit) ; +code { UNPAPAIR ; + ITER { UNPAIR ; DUUUP ; DUUP; GET ; + IF_NONE { PUSH int 0 } {} ; + SWAP ; DIP { ADD ; SOME } ; + UPDATE } ; + PAIR ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/attic/cadr_annotation.tz b/tests_python/contracts_011/attic/cadr_annotation.tz new file mode 100644 index 000000000000..3f4978aebf9e --- /dev/null +++ b/tests_python/contracts_011/attic/cadr_annotation.tz @@ -0,0 +1,3 @@ +parameter (pair (pair %p1 unit (string %no_name)) bool); +storage unit; +code { CAR @param; CADR @name %no_name; DROP; UNIT; NIL operation; PAIR } diff --git a/tests_python/contracts_011/attic/concat.tz b/tests_python/contracts_011/attic/concat.tz new file mode 100644 index 000000000000..26814afca55a --- /dev/null +++ b/tests_python/contracts_011/attic/concat.tz @@ -0,0 +1,7 @@ +parameter string; +storage string; +code { DUP; + DIP { CDR ; NIL string ; SWAP ; CONS } ; + CAR ; CONS ; + CONCAT; + NIL operation; PAIR} diff --git a/tests_python/contracts_011/attic/conditionals.tz b/tests_python/contracts_011/attic/conditionals.tz new file mode 100644 index 000000000000..16bf8e91645c --- /dev/null +++ b/tests_python/contracts_011/attic/conditionals.tz @@ -0,0 +1,9 @@ +parameter (or string (option int)); +storage string; +code { CAR; # Access the storage + IF_LEFT {} # The string is on top of the stack, nothing to do + { IF_NONE { FAIL} # Fail if None + { PUSH int 0; CMPGT; # Check for negative number + IF {FAIL} # Fail if negative + {PUSH string ""}}}; # Push the empty string + NIL operation; PAIR} # Calling convention diff --git a/tests_python/contracts_011/attic/cons_twice.tz b/tests_python/contracts_011/attic/cons_twice.tz new file mode 100644 index 000000000000..4761b23f71f1 --- /dev/null +++ b/tests_python/contracts_011/attic/cons_twice.tz @@ -0,0 +1,9 @@ +parameter nat; +storage (list nat); +code { DUP; # Duplicate the storage and parameter + CAR; # Extract the parameter + DIP{CDR}; # Extract the storage + DUP; # Duplicate the parameter + DIP{CONS}; # Add the first instance of the parameter to the list + CONS; # Add the second instance of the parameter to the list + NIL operation; PAIR} # Finish the calling convention diff --git a/tests_python/contracts_011/attic/cps_fact.tz b/tests_python/contracts_011/attic/cps_fact.tz new file mode 100644 index 000000000000..6c8ee7146290 --- /dev/null +++ b/tests_python/contracts_011/attic/cps_fact.tz @@ -0,0 +1,16 @@ +storage nat ; +parameter nat ; +code { UNPAIR ; + DIP { SELF ; ADDRESS ; SENDER; + IFCMPEQ {} { DROP ; PUSH @storage nat 1 } }; + DUP ; + PUSH nat 1 ; + IFCMPGE + { DROP ; NIL operation ; PAIR } + { PUSH nat 1 ; SWAP ; SUB @parameter ; ISNAT ; + IF_NONE + { NIL operation ; PAIR } + { DUP ; DIP { PUSH nat 1 ; ADD ; MUL @storage } ; SWAP; + DIP { DIP { SELF; PUSH mutez 0 } ; + TRANSFER_TOKENS ; NIL operation ; SWAP ; CONS } ; + SWAP ; PAIR } } } \ No newline at end of file diff --git a/tests_python/contracts_011/attic/create_add1_lists.tz b/tests_python/contracts_011/attic/create_add1_lists.tz new file mode 100644 index 000000000000..5a4245966379 --- /dev/null +++ b/tests_python/contracts_011/attic/create_add1_lists.tz @@ -0,0 +1,14 @@ +parameter unit; +storage address; +code { DROP; NIL int; # starting storage for contract + AMOUNT; # Push the starting balance + NONE key_hash; # No delegate + CREATE_CONTRACT # Create the contract + { parameter (list int) ; + storage (list int) ; + code + { CAR; + MAP {PUSH int 1; ADD}; + NIL operation; + PAIR } }; + NIL operation; SWAP; CONS; PAIR} # Ending calling convention stuff diff --git a/tests_python/contracts_011/attic/data_publisher.tz b/tests_python/contracts_011/attic/data_publisher.tz new file mode 100644 index 000000000000..9240d63021bc --- /dev/null +++ b/tests_python/contracts_011/attic/data_publisher.tz @@ -0,0 +1,8 @@ +parameter (pair signature (pair string nat)); +storage (pair (pair key nat) string); +code { DUP; CAR; DIP{CDR; DUP}; + SWAP; DIP{DUP}; CAAR; DIP{DUP; CAR; DIP{CDR; PACK ; BLAKE2B}}; + CHECK_SIGNATURE; + IF { CDR; DUP; DIP{CAR; DIP{CAAR}}; CDR; PUSH nat 1; ADD; + DIP{SWAP}; SWAP; PAIR; PAIR; NIL operation; PAIR} + {FAIL}} diff --git a/tests_python/contracts_011/attic/dispatch.tz b/tests_python/contracts_011/attic/dispatch.tz new file mode 100644 index 000000000000..9c185133ac7f --- /dev/null +++ b/tests_python/contracts_011/attic/dispatch.tz @@ -0,0 +1,9 @@ +parameter (or string (pair string (lambda unit string))); +storage (pair string (map string (lambda unit string))); +code { DUP; DIP{CDDR}; CAR; # Unpack stack + IF_LEFT { DIP{DUP}; GET; # Get lambda if it exists + IF_NONE {FAIL} {}; # Fail if it doesn't + UNIT; EXEC } # Execute the lambda + { DUP; CAR; DIP {CDR; SOME}; UPDATE; PUSH string ""}; # Update the storage + PAIR; + NIL operation; PAIR} # Calling convention diff --git a/tests_python/contracts_011/attic/empty.tz b/tests_python/contracts_011/attic/empty.tz new file mode 100644 index 000000000000..d3aecdb25066 --- /dev/null +++ b/tests_python/contracts_011/attic/empty.tz @@ -0,0 +1,3 @@ +parameter unit; +storage unit; +code {CDR; NIL operation; PAIR} diff --git a/tests_python/contracts_011/attic/fail_amount.tz b/tests_python/contracts_011/attic/fail_amount.tz new file mode 100644 index 000000000000..95b71c4f0ff1 --- /dev/null +++ b/tests_python/contracts_011/attic/fail_amount.tz @@ -0,0 +1,6 @@ +# Fail if the amount transferred is less than 10 +parameter unit; +storage unit; +code { DROP; + AMOUNT; PUSH mutez 10000000; CMPGT; IF {FAIL} {}; + UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/attic/faucet.tz b/tests_python/contracts_011/attic/faucet.tz new file mode 100644 index 000000000000..0c92a0744d94 --- /dev/null +++ b/tests_python/contracts_011/attic/faucet.tz @@ -0,0 +1,7 @@ +parameter key_hash ; +storage timestamp ; +code { UNPAIR ; SWAP ; + PUSH int 300 ; ADD @FIVE_MINUTES_LATER ; + NOW ; ASSERT_CMPGE ; + IMPLICIT_ACCOUNT ; PUSH mutez 1000000 ; UNIT ; TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS ; DIP { NOW } ; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/attic/forward.tz b/tests_python/contracts_011/attic/forward.tz new file mode 100644 index 000000000000..5b66891bb1bf --- /dev/null +++ b/tests_python/contracts_011/attic/forward.tz @@ -0,0 +1,150 @@ +parameter + (or string nat) ; +storage + (pair + (pair nat (pair mutez mutez)) # counter from_buyer from_seller + (pair + (pair nat (pair timestamp timestamp)) # Q T Z + (pair + (pair mutez mutez) # K C + (pair + (pair address address) # B S + address)))) ; # W +code + { DUP ; CDDADDR ; # Z + PUSH int 86400 ; SWAP ; ADD ; # one day in second + NOW ; COMPARE ; LT ; + IF { # Before Z + 24 + DUP ; CAR ; # we must receive (Left "buyer") or (Left "seller") + IF_LEFT + { DUP ; PUSH string "buyer" ; COMPARE ; EQ ; + IF { DROP ; + DUP ; CDADAR ; # amount already versed by the buyer + DIP { AMOUNT } ; ADD ; # transaction + # then we rebuild the globals + DIP { DUP ; CDADDR } ; PAIR ; # seller amount + PUSH nat 0 ; PAIR ; # delivery counter at 0 + DIP { CDDR } ; PAIR ; # parameters + # and return Unit + NIL operation ; PAIR } + { PUSH string "seller" ; COMPARE ; EQ ; + IF { DUP ; CDADDR ; # amount already versed by the seller + DIP { AMOUNT } ; ADD ; # transaction + # then we rebuild the globals + DIP { DUP ; CDADAR } ; SWAP ; PAIR ; # buyer amount + PUSH nat 0 ; PAIR ; # delivery counter at 0 + DIP { CDDR } ; PAIR ; # parameters + # and return Unit + NIL operation ; PAIR } + { FAIL } } } # (Left _) + { FAIL } } # (Right _) + { # After Z + 24 + # if balance is emptied, just fail + BALANCE ; PUSH mutez 0 ; IFCMPEQ { FAIL } {} ; + # test if the required amount is reached + DUP ; CDDAAR ; # Q + DIP { DUP ; CDDDADR } ; MUL ; # C + PUSH nat 2 ; MUL ; + BALANCE ; COMPARE ; LT ; # balance < 2 * (Q * C) + IF { # refund the parties + CDR ; DUP ; CADAR ; # amount versed by the buyer + DIP { DUP ; CDDDAAR } ; # B + DIP { CONTRACT unit ; ASSERT_SOME } ; + UNIT ; TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS ; SWAP ; + DUP ; CADDR ; # amount versed by the seller + DIP { DUP ; CDDDADR } ; # S + DIP { CONTRACT unit ; ASSERT_SOME } ; + UNIT ; TRANSFER_TOKENS ; SWAP ; + DIP { CONS } ; + DUP ; CADAR ; DIP { DUP ; CADDR } ; ADD ; + BALANCE ; SUB ; # bonus to the warehouse + DIP { DUP ; CDDDDR } ; # W + DIP { CONTRACT unit ; ASSERT_SOME } ; + UNIT ; TRANSFER_TOKENS ; + DIP { SWAP } ; CONS ; + # leave the storage as-is, as the balance is now 0 + PAIR } + { # otherwise continue + DUP ; CDDADAR ; # T + NOW ; COMPARE ; LT ; + IF { FAIL } # Between Z + 24 and T + { # after T + DUP ; CDDADAR ; # T + PUSH int 86400 ; ADD ; # one day in second + NOW ; COMPARE ; LT ; + IF { # Between T and T + 24 + # we only accept transactions from the buyer + DUP ; CAR ; # we must receive (Left "buyer") + IF_LEFT + { PUSH string "buyer" ; COMPARE ; EQ ; + IF { DUP ; CDADAR ; # amount already versed by the buyer + DIP { AMOUNT } ; ADD ; # transaction + # The amount must not exceed Q * K + DUP ; + DIIP { DUP ; CDDAAR ; # Q + DIP { DUP ; CDDDAAR } ; MUL ; } ; # K + DIP { COMPARE ; GT ; # new amount > Q * K + IF { FAIL } { } } ; # abort or continue + # then we rebuild the globals + DIP { DUP ; CDADDR } ; PAIR ; # seller amount + PUSH nat 0 ; PAIR ; # delivery counter at 0 + DIP { CDDR } ; PAIR ; # parameters + # and return Unit + NIL operation ; PAIR } + { FAIL } } # (Left _) + { FAIL } } # (Right _) + { # After T + 24 + # test if the required payment is reached + DUP ; CDDAAR ; # Q + DIP { DUP ; CDDDAAR } ; MUL ; # K + DIP { DUP ; CDADAR } ; # amount already versed by the buyer + COMPARE ; NEQ ; + IF { # not reached, pay the seller + BALANCE ; + DIP { DUP ; CDDDDADR } ; # S + DIIP { CDR } ; + DIP { CONTRACT unit ; ASSERT_SOME } ; + UNIT ; TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS ; PAIR } + { # otherwise continue + DUP ; CDDADAR ; # T + PUSH int 86400 ; ADD ; + PUSH int 86400 ; ADD ; # two days in second + NOW ; COMPARE ; LT ; + IF { # Between T + 24 and T + 48 + # We accept only delivery notifications, from W + DUP ; CDDDDDR ; # W + SENDER ; + COMPARE ; NEQ ; + IF { FAIL } {} ; # fail if not the warehouse + DUP ; CAR ; # we must receive (Right amount) + IF_LEFT + { FAIL } # (Left _) + { # We increment the counter + DIP { DUP ; CDAAR } ; ADD ; + # And rebuild the globals in advance + DIP { DUP ; CDADR } ; PAIR ; + DIP { CDDR } ; PAIR ; + UNIT ; PAIR ; + # We test if enough have been delivered + DUP ; CDAAR ; + DIP { DUP ; CDDAAR } ; + COMPARE ; LT ; # counter < Q + IF { CDR ; NIL operation } # wait for more + { # Transfer all the money to the seller + BALANCE ; + DIP { DUP ; CDDDDADR } ; # S + DIIP { CDR } ; + DIP { CONTRACT unit ; ASSERT_SOME } ; + UNIT ; TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS } } ; + PAIR } + { # after T + 48, transfer everything to the buyer + BALANCE ; + DIP { DUP ; CDDDDAAR } ; # B + DIIP { CDR } ; + DIP { CONTRACT unit ; ASSERT_SOME } ; + UNIT ; TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS ; + PAIR} } } } } } } \ No newline at end of file diff --git a/tests_python/contracts_011/attic/id.tz b/tests_python/contracts_011/attic/id.tz new file mode 100644 index 000000000000..4eee565ca2e9 --- /dev/null +++ b/tests_python/contracts_011/attic/id.tz @@ -0,0 +1,3 @@ +parameter string; +storage string; +code {CAR; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/attic/infinite_loop.tz b/tests_python/contracts_011/attic/infinite_loop.tz new file mode 100644 index 000000000000..77cdbc48c0d1 --- /dev/null +++ b/tests_python/contracts_011/attic/infinite_loop.tz @@ -0,0 +1,3 @@ +parameter unit; +storage unit; +code { DROP; PUSH bool True; LOOP {PUSH bool True}; UNIT; NIL operation; PAIR } diff --git a/tests_python/contracts_011/attic/insertion_sort.tz b/tests_python/contracts_011/attic/insertion_sort.tz new file mode 100644 index 000000000000..34eca64d092c --- /dev/null +++ b/tests_python/contracts_011/attic/insertion_sort.tz @@ -0,0 +1,16 @@ +parameter (list int) ; +storage (list int) ; +code { CAR ; + NIL int ; SWAP ; + ITER { SWAP; DIIP{NIL int} ; PUSH bool True ; + LOOP + { IF_CONS + { SWAP ; + DIP{DUP ; DIIP{DUP} ; DIP{CMPLT} ; SWAP} ; + SWAP ; + IF { DIP{SWAP ; DIP{CONS}} ; PUSH bool True} + { SWAP ; CONS ; PUSH bool False}} + { NIL int ; PUSH bool False}} ; + SWAP ; CONS ; SWAP ; + ITER {CONS}} ; + NIL operation ; PAIR } diff --git a/tests_python/contracts_011/attic/int_publisher.tz b/tests_python/contracts_011/attic/int_publisher.tz new file mode 100644 index 000000000000..6ee49b979e2c --- /dev/null +++ b/tests_python/contracts_011/attic/int_publisher.tz @@ -0,0 +1,17 @@ +# (signed hash of the string, string) +parameter (option (pair signature int)); +storage (pair key int); +code {DUP; DUP; CAR; + IF_NONE {PUSH mutez 1000000; # Fee pattern from July 26 + AMOUNT; CMPLE; IF {FAIL} {}; + # Provide the data + CDR; DIP {CDDR}} + {DUP; DIP{SWAP}; SWAP; CDAR; # Move key to the top + DIP {DUP; CAR; DIP {CDR; PACK ; BLAKE2B}}; # Arrange the new piece of data + CHECK_SIGNATURE; # Check to ensure the data is authentic + # Update data + IF {CDR; SWAP; DIP{DUP}; CDAR; PAIR} + # Revert the update. This could be replaced with FAIL + {DROP; DUP; CDR; DIP{CDDR}}}; + # Cleanup + DIP{DROP}; NIL operation; PAIR} diff --git a/tests_python/contracts_011/attic/king_of_tez.tz b/tests_python/contracts_011/attic/king_of_tez.tz new file mode 100644 index 000000000000..033ead7f168c --- /dev/null +++ b/tests_python/contracts_011/attic/king_of_tez.tz @@ -0,0 +1,19 @@ +parameter key_hash; +storage (pair timestamp (pair mutez key_hash)); +code { DUP; CDAR; + # If the time is more than 2 weeks, any amount makes you king + NOW; CMPGT; + # User becomes king of mutez + IF { CAR; AMOUNT; PAIR; NOW; PUSH int 604800; ADD; PAIR; + NIL operation } + # Check balance to see if user has paid enough to become the new king + { DUP; CDDAR; AMOUNT; CMPLT; + IF { FAIL } # user has not paid out + { CAR; DUP; + # New storage + DIP{ AMOUNT; PAIR; NOW; PUSH int 604800; ADD; PAIR }; + # Pay funds to old king + IMPLICIT_ACCOUNT; AMOUNT; UNIT; TRANSFER_TOKENS; + NIL operation; SWAP; CONS}}; + # Cleanup + PAIR }; diff --git a/tests_python/contracts_011/attic/list_of_transactions.tz b/tests_python/contracts_011/attic/list_of_transactions.tz new file mode 100644 index 000000000000..620ceedd5a67 --- /dev/null +++ b/tests_python/contracts_011/attic/list_of_transactions.tz @@ -0,0 +1,8 @@ +parameter unit; +storage (list address); +code { CDR; DUP; + DIP {NIL operation}; PUSH bool True; # Setup loop + LOOP {IF_CONS { CONTRACT unit ; ASSERT_SOME ; PUSH mutez 1000000; UNIT; TRANSFER_TOKENS; # Make transfer + SWAP; DIP {CONS}; PUSH bool True} # Setup for next round of loop + { NIL address ; PUSH bool False}}; # Data to satisfy types and end loop + DROP; PAIR}; # Calling convention diff --git a/tests_python/contracts_011/attic/queue.tz b/tests_python/contracts_011/attic/queue.tz new file mode 100644 index 000000000000..a074906ddf91 --- /dev/null +++ b/tests_python/contracts_011/attic/queue.tz @@ -0,0 +1,24 @@ +parameter (option string); +storage (pair (option string) (pair (pair nat nat) (map nat string))); +code { DUP; CAR; + # Retrieving an element + IF_NONE { CDDR; DUP; CAR; DIP{CDR; DUP}; DUP; + CAR; SWAP; DIP{GET}; # Check if an element is available + SWAP; + # Put NONE on stack and finish + IF_NONE { NONE string; DIP{PAIR}; PAIR} + # Reoption the element and remove the entry from the map + { SOME; + DIP{ DUP; DIP{ CAR; DIP{ NONE string }; UPDATE }; + # Increment the counter and cleanup + DUP; CAR; PUSH nat 1; ADD; DIP{ CDR }; PAIR; PAIR}; + PAIR }} + # Arrange the stack + { DIP{DUP; CDDAR; DIP{CDDDR}; DUP}; SWAP; CAR; + # Add the element to the map + DIP{ SOME; SWAP; CDR; DUP; DIP{UPDATE}; + # Increment the second number + PUSH nat 1; ADD}; + # Cleanup and finish + PAIR; PAIR; NONE string; PAIR }; + NIL operation; PAIR} diff --git a/tests_python/contracts_011/attic/reduce_map.tz b/tests_python/contracts_011/attic/reduce_map.tz new file mode 100644 index 000000000000..aab8ea60d367 --- /dev/null +++ b/tests_python/contracts_011/attic/reduce_map.tz @@ -0,0 +1,16 @@ + +parameter (pair (lambda int int) (list int)); +storage (list int); +code { DIP{NIL int}; + CAR; + DUP; + DIP{CAR; PAIR}; # Unpack data and setup accumulator + CDR; + ITER {PAIR; + DUP; CDAR; + DIP{ DUP; DIP{CDAR}; DUP; + CAR; DIP{CDDR; SWAP}; EXEC; CONS}; + PAIR}; + CDR; DIP{NIL int}; # First reduce + ITER {CONS}; # Reverse + NIL operation; PAIR} # Calling convention diff --git a/tests_python/contracts_011/attic/reentrancy.tz b/tests_python/contracts_011/attic/reentrancy.tz new file mode 100644 index 000000000000..b9e614a4e53e --- /dev/null +++ b/tests_python/contracts_011/attic/reentrancy.tz @@ -0,0 +1,7 @@ +parameter unit; +storage (pair address address); +code { CDR; DUP; CAR; + CONTRACT unit ; ASSERT_SOME ; PUSH mutez 5000000; UNIT; TRANSFER_TOKENS; + DIP {DUP; CDR; + CONTRACT unit ; ASSERT_SOME ; PUSH mutez 5000000; UNIT; TRANSFER_TOKENS}; + DIIP{NIL operation};DIP{CONS};CONS;PAIR}; diff --git a/tests_python/contracts_011/attic/reservoir.tz b/tests_python/contracts_011/attic/reservoir.tz new file mode 100644 index 000000000000..291e09b262b5 --- /dev/null +++ b/tests_python/contracts_011/attic/reservoir.tz @@ -0,0 +1,25 @@ +parameter unit ; +storage + (pair + (pair (timestamp %T) (mutez %N)) + (pair (address %A) (address %B))) ; +code + { CDR ; DUP ; CAAR %T; # T + NOW ; COMPARE ; LE ; + IF { DUP ; CADR %N; # N + BALANCE ; + COMPARE ; LE ; + IF { NIL operation ; PAIR } + { DUP ; CDDR %B; # B + CONTRACT unit ; ASSERT_SOME ; + BALANCE ; UNIT ; + TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS ; + PAIR } } + { DUP ; CDAR %A; # A + CONTRACT unit ; ASSERT_SOME ; + BALANCE ; + UNIT ; + TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS ; + PAIR } } diff --git a/tests_python/contracts_011/attic/scrutable_reservoir.tz b/tests_python/contracts_011/attic/scrutable_reservoir.tz new file mode 100644 index 000000000000..d415cdda0f54 --- /dev/null +++ b/tests_python/contracts_011/attic/scrutable_reservoir.tz @@ -0,0 +1,67 @@ +parameter unit ; +storage + (pair + string # S + (pair + timestamp # T + (pair + (pair mutez mutez) # P N + (pair + address # X + (pair address address))))) ; # A B +code + { DUP ; CDAR ; # S + PUSH string "open" ; + COMPARE ; NEQ ; + IF { FAIL } # on "success", "timeout" or a bad init value + { DUP ; CDDAR ; # T + NOW ; + COMPARE ; LT ; + IF { # Before timeout + # We compute (P + N) mutez + PUSH mutez 0 ; + DIP { DUP ; CDDDAAR } ; ADD ; # P + DIP { DUP ; CDDDADR } ; ADD ; # N + # We compare to the cumulated amount + BALANCE ; + COMPARE; LT ; + IF { # Not enough cash, we just accept the transaction + # and leave the global untouched + CDR ; NIL operation ; PAIR } + { # Enough cash, successful ending + # We update the global + CDDR ; PUSH string "success" ; PAIR ; + # We transfer the fee to the broker + DUP ; CDDAAR ; # P + DIP { DUP ; CDDDAR } ; # X + DIP { CONTRACT unit ; ASSERT_SOME } ; + UNIT ; TRANSFER_TOKENS ; + # We transfer the rest to A + DIP { DUP ; CDDADR ; # N + DIP { DUP ; CDDDDAR } ; # A + DIP { CONTRACT unit ; ASSERT_SOME } ; + UNIT ; TRANSFER_TOKENS } ; + NIL operation ; SWAP ; CONS ; SWAP ; CONS ; + PAIR } } + { # After timeout, we refund + # We update the global + CDDR ; PUSH string "timeout" ; PAIR ; + # We try to transfer the fee to the broker + BALANCE ; # available + DIP { DUP ; CDDAAR } ; # P + COMPARE ; LT ; # available < P + IF { BALANCE ; # available + DIP { DUP ; CDDDAR } ; # X + DIP { CONTRACT unit ; ASSERT_SOME } ; + UNIT ; TRANSFER_TOKENS } + { DUP ; CDDAAR ; # P + DIP { DUP ; CDDDAR } ; # X + DIP { CONTRACT unit ; ASSERT_SOME } ; + UNIT ; TRANSFER_TOKENS } ; + # We transfer the rest to B + DIP { BALANCE ; # available + DIP { DUP ; CDDDDDR } ; # B + DIP { CONTRACT unit ; ASSERT_SOME } ; + UNIT ; TRANSFER_TOKENS } ; + NIL operation ; SWAP ; CONS ; SWAP ; CONS ; + PAIR } } } diff --git a/tests_python/contracts_011/attic/spawn_identities.tz b/tests_python/contracts_011/attic/spawn_identities.tz new file mode 100644 index 000000000000..2208e0d0928d --- /dev/null +++ b/tests_python/contracts_011/attic/spawn_identities.tz @@ -0,0 +1,20 @@ +parameter nat; +storage (list address); +code { DUP; + CAR; # Get the number + DIP{CDR; NIL operation}; # Put the accumulators on the stack + PUSH bool True; # Push true so we have a do while loop + LOOP { DUP; PUSH nat 0; CMPEQ; # Check if the number is 0 + IF { PUSH bool False} # End the loop + { PUSH nat 1; SWAP; SUB; ABS; # Subtract 1. The ABS is to make it back into a nat + PUSH string "init"; # Storage type + PUSH mutez 5000000; # Starting balance + NONE key_hash; + CREATE_CONTRACT + { parameter string ; + storage string ; + code { CAR ; NIL operation ; PAIR } } ; # Make the contract + SWAP ; DIP { SWAP ; DIP { CONS } } ; # emit the operation + SWAP ; DIP { SWAP ; DIP { CONS } } ; # add to the list + PUSH bool True}}; # Continue the loop + DROP; PAIR} # Calling convention diff --git a/tests_python/contracts_011/entrypoints/big_map_entrypoints.tz b/tests_python/contracts_011/entrypoints/big_map_entrypoints.tz new file mode 100644 index 000000000000..d49e6257167a --- /dev/null +++ b/tests_python/contracts_011/entrypoints/big_map_entrypoints.tz @@ -0,0 +1,31 @@ +storage + (pair (big_map string nat) (big_map string nat)) ; +parameter + (or (unit %default) + (or (or %mem (string %mem_left) (string %mem_right)) + (or (or %add (pair %add_left string nat) (pair %add_right string nat)) + (or %rem (string %rem_left) (string %rem_right))))) ; +code { UNPAIR ; + IF_LEFT + { DROP ; + DUP ; CAR ; + PUSH mutez 0 ; + NONE key_hash ; + CREATE_CONTRACT + { parameter string ; + storage (big_map string nat) ; + code { UNPAIR ; DROP ; NIL operation ; PAIR }} ; + DIP { DROP } ; + NIL operation ; SWAP ; CONS ; PAIR } + { IF_LEFT + { IF_LEFT + { DIP { UNPAIR } ; DIP { DUP } ; MEM ; ASSERT } + { DIP { UNPAIR ; SWAP } ; DIP { DUP } ; MEM ; ASSERT ; SWAP } } + { IF_LEFT + { IF_LEFT + { UNPAIR ; DIIP { UNPAIR } ; DIP { SOME } ; UPDATE } + { UNPAIR ; DIIP { UNPAIR ; SWAP } ; DIP { SOME } ; UPDATE ; SWAP } } + { IF_LEFT + { DIP { UNPAIR } ; DIP { NONE nat } ; UPDATE } + { DIP { UNPAIR ; SWAP } ; DIP { NONE nat } ; UPDATE ; SWAP } } } ; + PAIR ; NIL operation ; PAIR } } diff --git a/tests_python/contracts_011/entrypoints/delegatable_target.tz b/tests_python/contracts_011/entrypoints/delegatable_target.tz new file mode 100644 index 000000000000..0db00f4945ed --- /dev/null +++ b/tests_python/contracts_011/entrypoints/delegatable_target.tz @@ -0,0 +1,79 @@ +# Michelson pseudo-code to transform from source script. + # This transformation adds 'set_delegate' entrypoint, e.g.: + # + # parameter ; + # storage ; + # code ; + # + # to: +parameter + (or + (or (key_hash %set_delegate) + (unit %remove_delegate)) + (or %default string nat) + ) ; + +storage + (pair + key_hash # manager + (pair string nat) + ) ; + +code { + DUP ; + CAR ; + IF_LEFT + { # 'set_delegate'/'remove_delegate' entrypoints + # Assert no token was sent: + # to send tokens, the default entry point should be used + PUSH mutez 0 ; + AMOUNT ; + ASSERT_CMPEQ ; + # Assert that the sender is the manager + DUUP ; + CDR ; + CAR ; + IMPLICIT_ACCOUNT ; ADDRESS ; + SENDER ; + IFCMPNEQ + { SENDER ; + PUSH string "Only the owner can operate." ; + PAIR ; + FAILWITH ; + } + { DIP { CDR ; NIL operation } ; + IF_LEFT + { # 'set_delegate' entrypoint + SOME ; + SET_DELEGATE ; + CONS ; + PAIR ; + } + { # 'remove_delegate' entrypoint + DROP ; + NONE key_hash ; + SET_DELEGATE ; + CONS ; + PAIR ; + } + } + } + { # Transform the inputs to the original script types + DIP { CDR ; DUP ; CDR } ; + PAIR ; + + # 'default' entrypoint - original code + { UNPAIR; + IF_LEFT + { DIP { UNPAIR ; DROP } } + { DUG 1; UNPAIR ; DIP { DROP } } ; + PAIR ; NIL operation ; PAIR } + # Transform the outputs to the new script types (manager's storage is unchanged) + SWAP ; + CAR ; + SWAP ; + UNPAIR ; + DIP { SWAP ; PAIR } ; + PAIR ; + } + } diff --git a/tests_python/contracts_011/entrypoints/manager.tz b/tests_python/contracts_011/entrypoints/manager.tz new file mode 100644 index 000000000000..06d9b1067bf4 --- /dev/null +++ b/tests_python/contracts_011/entrypoints/manager.tz @@ -0,0 +1,31 @@ +parameter + (or + (lambda %do unit (list operation)) + (unit %default)); +storage key_hash; +code + { UNPAIR ; + IF_LEFT + { # 'do' entrypoint + # Assert no token was sent: + # to send tokens, the default entry point should be used + PUSH mutez 0 ; + AMOUNT ; + ASSERT_CMPEQ ; + # Assert that the sender is the manager + DUUP ; + IMPLICIT_ACCOUNT ; + ADDRESS ; + SENDER ; + ASSERT_CMPEQ ; + # Execute the lambda argument + UNIT ; + EXEC ; + PAIR ; + } + { # 'default' entrypoint + DROP ; + NIL operation ; + PAIR ; + } + }; diff --git a/tests_python/contracts_011/entrypoints/no_default_target.tz b/tests_python/contracts_011/entrypoints/no_default_target.tz new file mode 100644 index 000000000000..48d5d53df996 --- /dev/null +++ b/tests_python/contracts_011/entrypoints/no_default_target.tz @@ -0,0 +1,11 @@ +storage (pair string nat) ; +parameter + (or unit (or %data string nat)) ; +code { UNPAIR ; + IF_LEFT + { DROP ; NIL operation ; PAIR } + { IF_LEFT + { DIP { UNPAIR ; DROP } } + { DUG 1; UNPAIR ; DIP { DROP } } ; + PAIR ; NIL operation ; PAIR } + } diff --git a/tests_python/contracts_011/entrypoints/no_entrypoint_target.tz b/tests_python/contracts_011/entrypoints/no_entrypoint_target.tz new file mode 100644 index 000000000000..d8041507d58c --- /dev/null +++ b/tests_python/contracts_011/entrypoints/no_entrypoint_target.tz @@ -0,0 +1,11 @@ +storage (pair string nat) ; +parameter + (or unit (or string nat)) ; +code { UNPAIR ; + IF_LEFT + { DROP ; NIL operation ; PAIR } + { IF_LEFT + { DIP { UNPAIR ; DROP } } + { DUG 1; UNPAIR ; DIP { DROP } } ; + PAIR ; NIL operation ; PAIR } + } diff --git a/tests_python/contracts_011/entrypoints/rooted_target.tz b/tests_python/contracts_011/entrypoints/rooted_target.tz new file mode 100644 index 000000000000..2ca2dfb1296d --- /dev/null +++ b/tests_python/contracts_011/entrypoints/rooted_target.tz @@ -0,0 +1,11 @@ +storage (pair string nat) ; +parameter + (or %root unit (or %default string nat)) ; +code { UNPAIR ; + IF_LEFT + { DROP ; NIL operation ; PAIR } + { IF_LEFT + { DIP { UNPAIR ; DROP } } + { DUG 1; UNPAIR ; DIP { DROP } } ; + PAIR ; NIL operation ; PAIR } + } diff --git a/tests_python/contracts_011/entrypoints/simple_entrypoints.tz b/tests_python/contracts_011/entrypoints/simple_entrypoints.tz new file mode 100644 index 000000000000..7b7abb7cb86e --- /dev/null +++ b/tests_python/contracts_011/entrypoints/simple_entrypoints.tz @@ -0,0 +1,4 @@ +# A trivial contract with some entrypoints +parameter (or (unit %A) (or (string %B) (nat %C))) ; +storage unit; +code { CDR ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/ill_typed/badly_indented.tz b/tests_python/contracts_011/ill_typed/badly_indented.tz new file mode 100644 index 000000000000..0fc54663a9f9 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/badly_indented.tz @@ -0,0 +1,3 @@ +parameter string; + storage string; + code {CAR; NIL operation; PAIR} diff --git a/tests_python/contracts_011/ill_typed/big_dip.tz b/tests_python/contracts_011/ill_typed/big_dip.tz new file mode 100644 index 000000000000..697370fdc87e --- /dev/null +++ b/tests_python/contracts_011/ill_typed/big_dip.tz @@ -0,0 +1,4 @@ +parameter unit; +storage unit; +code { DIP 1073741824 { }; # = 0x3fffffff + 1 + DROP; } diff --git a/tests_python/contracts_011/ill_typed/big_drop.tz b/tests_python/contracts_011/ill_typed/big_drop.tz new file mode 100644 index 000000000000..40d81cf8448b --- /dev/null +++ b/tests_python/contracts_011/ill_typed/big_drop.tz @@ -0,0 +1,4 @@ +parameter unit; +storage unit; +code { DROP 1073741824; # = 0x3fffffff + 1 + DROP; } diff --git a/tests_python/contracts_011/ill_typed/big_map_arity.tz b/tests_python/contracts_011/ill_typed/big_map_arity.tz new file mode 100644 index 000000000000..5e5a7d60d5b7 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/big_map_arity.tz @@ -0,0 +1,5 @@ +# This contract tests the error message in case the EMPTY_BIG_MAP instruction has bad arity (1 argument instead of 2). +# The expected type-checking error is "primitive EMPTY_BIG_MAP expects 2 arguments but is given 1." +parameter unit; +storage unit; +code { DROP; EMPTY_BIG_MAP nat; DROP; UNIT; NIL operation; PAIR; } diff --git a/tests_python/contracts_011/ill_typed/chain_id_arity.tz b/tests_python/contracts_011/ill_typed/chain_id_arity.tz new file mode 100644 index 000000000000..4bc9f4f70107 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/chain_id_arity.tz @@ -0,0 +1,3 @@ +parameter (chain_id nat); +storage unit; +code { CDR; NIL operation; PAIR } diff --git a/tests_python/contracts_011/ill_typed/comb0.tz b/tests_python/contracts_011/ill_typed/comb0.tz new file mode 100644 index 000000000000..ab3c79153035 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/comb0.tz @@ -0,0 +1,3 @@ +parameter unit; +storage unit; +code { PAIR 0 } diff --git a/tests_python/contracts_011/ill_typed/comb1.tz b/tests_python/contracts_011/ill_typed/comb1.tz new file mode 100644 index 000000000000..07b709d61cfd --- /dev/null +++ b/tests_python/contracts_011/ill_typed/comb1.tz @@ -0,0 +1,3 @@ +parameter unit; +storage unit; +code { PAIR 1 } diff --git a/tests_python/contracts_011/ill_typed/contract_annotation_default.tz b/tests_python/contracts_011/ill_typed/contract_annotation_default.tz new file mode 100644 index 000000000000..742e140c5e48 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/contract_annotation_default.tz @@ -0,0 +1,11 @@ +parameter (contract (or (or (int %A) (nat %B)) (unit %default))); +storage unit; +code { + CAR; + # CONTRACT %default nat == CONTRACT nat and the former is not allowed. + DUP; ADDRESS; CONTRACT %default nat; ASSERT_SOME; DROP; + DROP; + UNIT; + NIL operation; + PAIR + }; diff --git a/tests_python/contracts_011/ill_typed/dup0.tz b/tests_python/contracts_011/ill_typed/dup0.tz new file mode 100644 index 000000000000..2e46599e490a --- /dev/null +++ b/tests_python/contracts_011/ill_typed/dup0.tz @@ -0,0 +1,3 @@ +parameter unit; +storage unit; +code { DUP 0 } diff --git a/tests_python/contracts_011/ill_typed/failwith_big_map.tz b/tests_python/contracts_011/ill_typed/failwith_big_map.tz new file mode 100644 index 000000000000..33d73c26123c --- /dev/null +++ b/tests_python/contracts_011/ill_typed/failwith_big_map.tz @@ -0,0 +1,22 @@ +# This contract uses FAILWITH to expose a big map diff +# See https://gitlab.com/tezos/tezos/-/issues/1708#note_667884499 + +parameter (big_map int int); + +# Even if the stored big_map is dropped by the initial CAR instruction, +# it can still be accessed by its big-map id and sent as parameter so +# it is important that the type of the storage matches the type of the +# parameter. + +# This test is now ill-typed because FAILWITH accepts only packable types + +storage (big_map int int); + +code { CAR; + PUSH (option int) (Some 1); + PUSH int 1; + UPDATE; + PUSH (option int) None; + PUSH int 2; + UPDATE; + FAILWITH } diff --git a/tests_python/contracts_011/ill_typed/invalid_self_entrypoint.tz b/tests_python/contracts_011/ill_typed/invalid_self_entrypoint.tz new file mode 100644 index 000000000000..4fac9c635044 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/invalid_self_entrypoint.tz @@ -0,0 +1,10 @@ +parameter (or (or (nat %A) (bool %B)) (or %maybe_C (unit %Z) (string %C))); +storage unit; +code { + DROP; + # This entrypoint does not exist + SELF %D; DROP; + UNIT; + NIL operation; + PAIR; + } diff --git a/tests_python/contracts_011/ill_typed/missing_only_code_field.tz b/tests_python/contracts_011/ill_typed/missing_only_code_field.tz new file mode 100644 index 000000000000..4b5b2cd62f56 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/missing_only_code_field.tz @@ -0,0 +1,2 @@ +storage unit; +parameter nat; \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/missing_only_parameter_field.tz b/tests_python/contracts_011/ill_typed/missing_only_parameter_field.tz new file mode 100644 index 000000000000..1f7e8ac75da9 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/missing_only_parameter_field.tz @@ -0,0 +1,4 @@ +storage unit; +code { CAR; + DUP; NEG; ABS; COMPARE; ASSERT_EQ; + UNIT; NIL operation; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/missing_only_storage_field.tz b/tests_python/contracts_011/ill_typed/missing_only_storage_field.tz new file mode 100644 index 000000000000..2aa28922287a --- /dev/null +++ b/tests_python/contracts_011/ill_typed/missing_only_storage_field.tz @@ -0,0 +1,4 @@ +parameter nat; +code { CAR; + DUP; NEG; ABS; COMPARE; ASSERT_EQ; + UNIT; NIL operation; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/missing_parameter_and_storage_fields.tz b/tests_python/contracts_011/ill_typed/missing_parameter_and_storage_fields.tz new file mode 100644 index 000000000000..18e7b35b0a8c --- /dev/null +++ b/tests_python/contracts_011/ill_typed/missing_parameter_and_storage_fields.tz @@ -0,0 +1,3 @@ +code { CAR; + DUP; NEG; ABS; COMPARE; ASSERT_EQ; + UNIT; NIL operation; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/multiple_code_field.tz b/tests_python/contracts_011/ill_typed/multiple_code_field.tz new file mode 100644 index 000000000000..cd47b356d14e --- /dev/null +++ b/tests_python/contracts_011/ill_typed/multiple_code_field.tz @@ -0,0 +1,6 @@ +parameter nat; +storage unit; +code { CAR; + DUP; NEG; ABS; COMPARE; ASSERT_EQ; + UNIT; NIL operation; PAIR }; +code {} \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/multiple_parameter_field.tz b/tests_python/contracts_011/ill_typed/multiple_parameter_field.tz new file mode 100644 index 000000000000..e59fb9fe05be --- /dev/null +++ b/tests_python/contracts_011/ill_typed/multiple_parameter_field.tz @@ -0,0 +1,6 @@ +parameter nat; +parameter nat; +storage unit; +code { CAR; + DUP; NEG; ABS; COMPARE; ASSERT_EQ; + UNIT; NIL operation; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/multiple_storage_and_code_fields.tz b/tests_python/contracts_011/ill_typed/multiple_storage_and_code_fields.tz new file mode 100644 index 000000000000..3b32484dc200 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/multiple_storage_and_code_fields.tz @@ -0,0 +1,7 @@ +parameter nat; +storage unit; +storage unit; +code { CAR; + DUP; NEG; ABS; COMPARE; ASSERT_EQ; + UNIT; NIL operation; PAIR }; +code {} \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/multiple_storage_field.tz b/tests_python/contracts_011/ill_typed/multiple_storage_field.tz new file mode 100644 index 000000000000..06c25f51d3b2 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/multiple_storage_field.tz @@ -0,0 +1,6 @@ +parameter nat; +storage unit; +storage unit; +code { CAR; + DUP; NEG; ABS; COMPARE; ASSERT_EQ; + UNIT; NIL operation; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/never_literal.tz b/tests_python/contracts_011/ill_typed/never_literal.tz new file mode 100644 index 000000000000..ba36b3b5f205 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/never_literal.tz @@ -0,0 +1,6 @@ +parameter unit; +storage unit; +code { + PUSH never {}; + FAILWITH + } diff --git a/tests_python/contracts_011/ill_typed/pack_big_map.tz b/tests_python/contracts_011/ill_typed/pack_big_map.tz new file mode 100644 index 000000000000..29ae0d665051 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/pack_big_map.tz @@ -0,0 +1,7 @@ +parameter unit; +storage (pair (big_map int int) unit); +code { CDAR; + DUP; PACK; DROP; + UNIT; SWAP; PAIR; + NIL operation; + PAIR; } diff --git a/tests_python/contracts_011/ill_typed/pack_operation.tz b/tests_python/contracts_011/ill_typed/pack_operation.tz new file mode 100644 index 000000000000..349ca053af27 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/pack_operation.tz @@ -0,0 +1,20 @@ +parameter unit; +storage unit; +code { DROP; + UNIT; # starting storage for contract + AMOUNT; # Push the starting balance + NONE key_hash; # No delegate + CREATE_CONTRACT # Create the contract + { parameter unit ; + storage unit ; + code + { CDR; + NIL operation; + PAIR; } }; + DIP { DROP }; + # invalid PACK + PACK; + DROP; + UNIT; + NIL operation; + PAIR; } diff --git a/tests_python/contracts_011/ill_typed/pack_sapling_state.tz b/tests_python/contracts_011/ill_typed/pack_sapling_state.tz new file mode 100644 index 000000000000..0524d9b27911 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/pack_sapling_state.tz @@ -0,0 +1,13 @@ +# Verify SAPLING_STATE is not packable. The contract should not typecheck when using `PACK`. +# The lines below PACK are present only in case of PACK allows SAPLING_STATE to +# make the typechecker happy. +parameter unit; +storage (sapling_state 8); +code { UNPAIR; + DROP; + PACK; + DROP; + SAPLING_EMPTY_STATE 8; + NIL operation; + PAIR; + } diff --git a/tests_python/contracts_011/ill_typed/push_big_map_with_id_with_parens.tz b/tests_python/contracts_011/ill_typed/push_big_map_with_id_with_parens.tz new file mode 100644 index 000000000000..2c659e9a639d --- /dev/null +++ b/tests_python/contracts_011/ill_typed/push_big_map_with_id_with_parens.tz @@ -0,0 +1,10 @@ +# This contract verifies it is not possible to use the instruction `PUSH big_map +# tk tv i` where i is the ID of an existing big_map +parameter int; +storage (big_map string nat); +code { UNPAIR; + DROP; + PUSH (big_map string nat) 0; + NIL operation; + PAIR + } \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/push_big_map_with_id_without_parens.tz b/tests_python/contracts_011/ill_typed/push_big_map_with_id_without_parens.tz new file mode 100644 index 000000000000..c5eeef97c7e3 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/push_big_map_with_id_without_parens.tz @@ -0,0 +1,11 @@ +# This contract verifies it is not possible to use the instruction `PUSH big_map +# tk tv i` where i is the ID of an existing big_map +parameter int; +storage (big_map string nat); +code { + UNPAIR; + DROP; + PUSH big_map string nat 0; + NIL operation; + PAIR; + }; \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/sapling_build_empty_state_with_int_parameter.tz b/tests_python/contracts_011/ill_typed/sapling_build_empty_state_with_int_parameter.tz new file mode 100644 index 000000000000..21b48391060b --- /dev/null +++ b/tests_python/contracts_011/ill_typed/sapling_build_empty_state_with_int_parameter.tz @@ -0,0 +1,10 @@ +parameter nat; +storage (sapling_state 8); +code { + UNPAIR; + SWAP; + DROP; + SAPLING_EMPTY_STATE; + NIL operation; + PAIR; + }; diff --git a/tests_python/contracts_011/ill_typed/set_update_non_comparable.tz b/tests_python/contracts_011/ill_typed/set_update_non_comparable.tz new file mode 100644 index 000000000000..4a70691793c7 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/set_update_non_comparable.tz @@ -0,0 +1,9 @@ +# This contract tests the error message in case the UPDATE instruction on set +# is used with a non-comparable type +parameter (set nat); +storage unit; +code { CAR; + PUSH bool True; + NIL operation; + UPDATE; + UNIT; NIL operation; PAIR; } diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_undig2able.tz b/tests_python/contracts_011/ill_typed/stack_bottom_undig2able.tz new file mode 100644 index 000000000000..6f7061e004a0 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_undig2able.tz @@ -0,0 +1,5 @@ +parameter unit; +storage unit; +code { + DIG 2; + } diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_undigable.tz b/tests_python/contracts_011/ill_typed/stack_bottom_undigable.tz new file mode 100644 index 000000000000..2aba7d303eaf --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_undigable.tz @@ -0,0 +1,6 @@ +parameter unit; +storage unit; +code { + DROP; + DIG 0; + } diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_undip2able.tz b/tests_python/contracts_011/ill_typed/stack_bottom_undip2able.tz new file mode 100644 index 000000000000..e048a24f74b8 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_undip2able.tz @@ -0,0 +1,6 @@ +parameter unit; +storage unit; +code { + DUP; + DIP 2 { DUP }; + } diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_undipable.tz b/tests_python/contracts_011/ill_typed/stack_bottom_undipable.tz new file mode 100644 index 000000000000..09f94b133e50 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_undipable.tz @@ -0,0 +1,5 @@ +parameter unit; +storage unit; +code { + DIP { DUP }; + } diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_undropable.tz b/tests_python/contracts_011/ill_typed/stack_bottom_undropable.tz new file mode 100644 index 000000000000..d33142cdb82b --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_undropable.tz @@ -0,0 +1,5 @@ +parameter unit; +storage unit; +code { + DROP 2; + } diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_undug2able.tz b/tests_python/contracts_011/ill_typed/stack_bottom_undug2able.tz new file mode 100644 index 000000000000..5eef1da706f2 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_undug2able.tz @@ -0,0 +1,5 @@ +parameter unit; +storage unit; +code { + DUG 2; + } diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_undugable.tz b/tests_python/contracts_011/ill_typed/stack_bottom_undugable.tz new file mode 100644 index 000000000000..eaf5d7d486e7 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_undugable.tz @@ -0,0 +1,6 @@ +parameter unit; +storage unit; +code { + DROP; + DUG 0; + } diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_undup2able.tz b/tests_python/contracts_011/ill_typed/stack_bottom_undup2able.tz new file mode 100644 index 000000000000..c760764fd5b2 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_undup2able.tz @@ -0,0 +1,5 @@ +parameter unit; +storage unit; +code { + DUP 2; + } diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_unfailwithable.tz b/tests_python/contracts_011/ill_typed/stack_bottom_unfailwithable.tz new file mode 100644 index 000000000000..c8cf263e5dcc --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_unfailwithable.tz @@ -0,0 +1,6 @@ +parameter unit; +storage unit; +code { + DROP; + FAILWITH; + } \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_ungetable.tz b/tests_python/contracts_011/ill_typed/stack_bottom_ungetable.tz new file mode 100644 index 000000000000..6bc5a629e2a4 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_ungetable.tz @@ -0,0 +1,6 @@ +parameter unit; +storage unit; +code { + DROP; + GET; + } \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_unleftable.tz b/tests_python/contracts_011/ill_typed/stack_bottom_unleftable.tz new file mode 100644 index 000000000000..0bc846effa3b --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_unleftable.tz @@ -0,0 +1,6 @@ +parameter unit; +storage unit; +code { + DROP; + LEFT unit; + } \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_unpairable.tz b/tests_python/contracts_011/ill_typed/stack_bottom_unpairable.tz new file mode 100644 index 000000000000..70f7e3a40c10 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_unpairable.tz @@ -0,0 +1,6 @@ +parameter unit; +storage unit; +code { + DROP; + UNPAIR; + } diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_unpopable.tz b/tests_python/contracts_011/ill_typed/stack_bottom_unpopable.tz new file mode 100644 index 000000000000..0f1d8ea456a2 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_unpopable.tz @@ -0,0 +1,10 @@ +parameter unit; +storage unit; +code { + DROP ; + DUP ; + DROP ; + PUSH unit Unit ; + NIL operation ; + PAIR + } diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_unpopable_in_lambda.tz b/tests_python/contracts_011/ill_typed/stack_bottom_unpopable_in_lambda.tz new file mode 100644 index 000000000000..4299b8bef474 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_unpopable_in_lambda.tz @@ -0,0 +1,10 @@ +parameter unit; +storage unit; +code { + DROP ; + LAMBDA int unit { DROP ; DUP }; + DROP ; + PUSH unit Unit ; + NIL operation ; + PAIR + } diff --git a/tests_python/contracts_011/ill_typed/stack_bottom_unrightable.tz b/tests_python/contracts_011/ill_typed/stack_bottom_unrightable.tz new file mode 100644 index 000000000000..a7cf3d06a470 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/stack_bottom_unrightable.tz @@ -0,0 +1,6 @@ +parameter unit; +storage unit; +code { + DROP; + RIGHT unit; + } \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/ticket_apply.tz b/tests_python/contracts_011/ill_typed/ticket_apply.tz new file mode 100644 index 000000000000..a77fb08a6611 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/ticket_apply.tz @@ -0,0 +1,17 @@ +# This script attempts to duplicate a ticket by capturing it using APPLY. +# Is should fail at parsing because tickets are not packable so they are +# not allowed to be captured by APPLY. +parameter (ticket unit); +storage (option (pair (ticket unit) (ticket unit))); +code { + CAR; + LAMBDA (pair (ticket unit) unit) (ticket unit) { CAR }; + SWAP; APPLY; + DUP; + UNIT; EXEC; SWAP; + UNIT; EXEC; + PAIR; + SOME; + NIL operation; + PAIR + } diff --git a/tests_python/contracts_011/ill_typed/ticket_dup.tz b/tests_python/contracts_011/ill_typed/ticket_dup.tz new file mode 100644 index 000000000000..fee0ea3785bc --- /dev/null +++ b/tests_python/contracts_011/ill_typed/ticket_dup.tz @@ -0,0 +1,3 @@ +parameter (ticket %store nat) ; +storage unit; +code { UNPAIR; DUP; DROP 2; NIL operation; PAIR } diff --git a/tests_python/contracts_011/ill_typed/ticket_in_ticket.tz b/tests_python/contracts_011/ill_typed/ticket_in_ticket.tz new file mode 100644 index 000000000000..ee6bdf238723 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/ticket_in_ticket.tz @@ -0,0 +1,16 @@ +# This script attempts to duplicate a ticket by storing it +# in another ticket and calling READ_TICKET twice on it. +# It should fail at parsing because ticket contents must be +# comparable so (ticket (ticket unit)) cannot be built. +parameter (ticket unit); +storage (option (pair (ticket unit) (ticket unit))); +code { + CAR; + PUSH nat 0; + SWAP; + TICKET; + READ_TICKET; CDR; CAR; + SWAP; READ_TICKET; CDR; CAR; + SWAP; DROP; + PAIR; SOME; NIL operation; PAIR + } \ No newline at end of file diff --git a/tests_python/contracts_011/ill_typed/ticket_unpack.tz b/tests_python/contracts_011/ill_typed/ticket_unpack.tz new file mode 100644 index 000000000000..888746f42eb0 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/ticket_unpack.tz @@ -0,0 +1,5 @@ +# UNPACK on ticket should produce a type error +parameter unit; +storage (option (ticket nat)); +code { DROP ; PUSH nat 2 ; PACK ; UNPACK (ticket nat) ; + NIL operation ; PAIR } diff --git a/tests_python/contracts_011/ill_typed/uncomb0.tz b/tests_python/contracts_011/ill_typed/uncomb0.tz new file mode 100644 index 000000000000..9c3370912937 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/uncomb0.tz @@ -0,0 +1,3 @@ +parameter unit; +storage unit; +code { UNPAIR 0 } diff --git a/tests_python/contracts_011/ill_typed/uncomb1.tz b/tests_python/contracts_011/ill_typed/uncomb1.tz new file mode 100644 index 000000000000..6cc515335072 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/uncomb1.tz @@ -0,0 +1,3 @@ +parameter unit; +storage unit; +code { UNPAIR 1 } diff --git a/tests_python/contracts_011/ill_typed/unpack_sapling_state.tz b/tests_python/contracts_011/ill_typed/unpack_sapling_state.tz new file mode 100644 index 000000000000..a80f81eb84b6 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/unpack_sapling_state.tz @@ -0,0 +1,12 @@ +# Verify SAPLING_STATE is not packable. The contract should not typecheck when using `UNPACK`. +# The lines below UNPACK are present only in case of UNPACK allows SAPLING_STATE to +# make the typechecker happy. +parameter bytes; +storage (unit); +code { CAR; + UNPACK (sapling_state 8); + DROP; + PUSH unit Unit; + NIL operation; + PAIR; + } diff --git a/tests_python/contracts_011/ill_typed/unpair_field_annotation_mismatch.tz b/tests_python/contracts_011/ill_typed/unpair_field_annotation_mismatch.tz new file mode 100644 index 000000000000..c2b3fe0a498d --- /dev/null +++ b/tests_python/contracts_011/ill_typed/unpair_field_annotation_mismatch.tz @@ -0,0 +1,10 @@ +parameter (unit :param_unit); +storage (unit :u1); +code { DROP ; + + UNIT @b; UNIT @a; PAIR %@ %@; + # Field annotations must match (or be ommited) + DUP; UNPAIR %c %d; DROP 2; + DROP; + + UNIT; NIL operation; PAIR } diff --git a/tests_python/contracts_011/ill_typed/view_op_bad_name_invalid_char_set.tz b/tests_python/contracts_011/ill_typed/view_op_bad_name_invalid_char_set.tz new file mode 100644 index 000000000000..1bc14a4facef --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_op_bad_name_invalid_char_set.tz @@ -0,0 +1,3 @@ +parameter (pair nat address) ; +storage nat ; +code { CAR ; UNPAIR ; VIEW "^$&*!#~(-=)" nat ; IF_SOME { } { PUSH nat 1 } ; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/ill_typed/view_op_bad_name_invalid_type.tz b/tests_python/contracts_011/ill_typed/view_op_bad_name_invalid_type.tz new file mode 100644 index 000000000000..4bde2b617adc --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_op_bad_name_invalid_type.tz @@ -0,0 +1,3 @@ +parameter (pair nat address) ; +storage nat ; +code { CAR ; UNPAIR ; VIEW 1 nat ; IF_SOME { } { PUSH nat 1 } ; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/ill_typed/view_op_bad_name_non_printable_char.tz b/tests_python/contracts_011/ill_typed/view_op_bad_name_non_printable_char.tz new file mode 100644 index 000000000000..22b3f5665af5 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_op_bad_name_non_printable_char.tz @@ -0,0 +1,3 @@ +parameter (pair nat address) ; +storage nat ; +code { CAR ; UNPAIR ; VIEW "\\x00" nat ; IF_SOME { } { PUSH nat 1 } ; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/ill_typed/view_op_bad_name_too_long.tz b/tests_python/contracts_011/ill_typed/view_op_bad_name_too_long.tz new file mode 100644 index 000000000000..263ecba19684 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_op_bad_name_too_long.tz @@ -0,0 +1,4 @@ +parameter (pair nat address) ; +storage nat ; +code { CAR ; UNPAIR ; VIEW "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" nat ; IF_SOME { } { PUSH nat 1 } ; NIL operation ; PAIR } ; + diff --git a/tests_python/contracts_011/ill_typed/view_op_bad_return_type.tz b/tests_python/contracts_011/ill_typed/view_op_bad_return_type.tz new file mode 100644 index 000000000000..3c9ef69e7ffa --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_op_bad_return_type.tz @@ -0,0 +1,3 @@ +parameter (pair nat address) ; +storage nat ; +code { CAR ; UNPAIR ; VIEW "add" string; IF_SOME { } { PUSH nat 1 } ; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/ill_typed/view_op_dupable_type.tz b/tests_python/contracts_011/ill_typed/view_op_dupable_type.tz new file mode 100644 index 000000000000..45e7ebc43704 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_op_dupable_type.tz @@ -0,0 +1,3 @@ +parameter (pair nat address) ; +storage nat ; +code { CAR ; UNPAIR ; VIEW "add" (ticket nat); DROP ; PUSH nat 1 ; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/ill_typed/view_op_invalid_arity.tz b/tests_python/contracts_011/ill_typed/view_op_invalid_arity.tz new file mode 100644 index 000000000000..a56f40d15c54 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_op_invalid_arity.tz @@ -0,0 +1,3 @@ +parameter (pair nat address) ; +storage nat ; +code { CAR ; UNPAIR ; VIEW "add" ; IF_SOME { } { PUSH nat 1 } ; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/ill_typed/view_op_lazy_storage.tz b/tests_python/contracts_011/ill_typed/view_op_lazy_storage.tz new file mode 100644 index 000000000000..82bfb31f0bce --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_op_lazy_storage.tz @@ -0,0 +1,8 @@ +parameter address; +storage (big_map string nat); +code { + CAR; + UNIT; + VIEW "get_map" (big_map string nat); + IF_SOME { PUSH nat 10 ; SOME ; PUSH string "bar"; UPDATE; NIL operation; PAIR; } { FAIL; } + } diff --git a/tests_python/contracts_011/ill_typed/view_op_lazy_storage_type.tz b/tests_python/contracts_011/ill_typed/view_op_lazy_storage_type.tz new file mode 100644 index 000000000000..82bfb31f0bce --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_op_lazy_storage_type.tz @@ -0,0 +1,8 @@ +parameter address; +storage (big_map string nat); +code { + CAR; + UNIT; + VIEW "get_map" (big_map string nat); + IF_SOME { PUSH nat 10 ; SOME ; PUSH string "bar"; UPDATE; NIL operation; PAIR; } { FAIL; } + } diff --git a/tests_python/contracts_011/ill_typed/view_toplevel_bad_input_type.tz b/tests_python/contracts_011/ill_typed/view_toplevel_bad_input_type.tz new file mode 100644 index 000000000000..9d1551d24285 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_toplevel_bad_input_type.tz @@ -0,0 +1,4 @@ +parameter nat ; +storage nat ; +code { CAR ; NIL operation ; PAIR } ; +view "add" string nat { UNPAIR; ADD } ; diff --git a/tests_python/contracts_011/ill_typed/view_toplevel_bad_name_invalid_char_set.tz b/tests_python/contracts_011/ill_typed/view_toplevel_bad_name_invalid_char_set.tz new file mode 100644 index 000000000000..f9d2a3f1ad5b --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_toplevel_bad_name_invalid_char_set.tz @@ -0,0 +1,5 @@ +parameter nat ; +storage nat ; +code { CAR ; NIL operation ; PAIR } ; +view "^$&*!#~(-=)" nat nat { UNPAIR ; ADD } ; + diff --git a/tests_python/contracts_011/ill_typed/view_toplevel_bad_name_invalid_type.tz b/tests_python/contracts_011/ill_typed/view_toplevel_bad_name_invalid_type.tz new file mode 100644 index 000000000000..fafd89ffd29a --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_toplevel_bad_name_invalid_type.tz @@ -0,0 +1,4 @@ +parameter nat ; +storage nat ; +code { CAR ; NIL operation ; PAIR } ; +view 1 nat nat { UNPAIR ; ADD } ; diff --git a/tests_python/contracts_011/ill_typed/view_toplevel_bad_name_non_printable_char.tz b/tests_python/contracts_011/ill_typed/view_toplevel_bad_name_non_printable_char.tz new file mode 100644 index 000000000000..7a1128527518 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_toplevel_bad_name_non_printable_char.tz @@ -0,0 +1,4 @@ +parameter nat ; +storage nat ; +code { CAR ; NIL operation ; PAIR } ; +view "\\x00" nat nat { UNPAIR ; ADD } ; diff --git a/tests_python/contracts_011/ill_typed/view_toplevel_bad_name_too_long.tz b/tests_python/contracts_011/ill_typed/view_toplevel_bad_name_too_long.tz new file mode 100644 index 000000000000..4f61ae081410 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_toplevel_bad_name_too_long.tz @@ -0,0 +1,4 @@ +parameter nat ; +storage nat ; +code { CAR ; NIL operation ; PAIR } ; +view "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" nat nat { UNPAIR ; ADD } ; diff --git a/tests_python/contracts_011/ill_typed/view_toplevel_bad_return_type.tz b/tests_python/contracts_011/ill_typed/view_toplevel_bad_return_type.tz new file mode 100644 index 000000000000..4572674664ca --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_toplevel_bad_return_type.tz @@ -0,0 +1,4 @@ +parameter nat ; +storage nat ; +code { CAR ; NIL operation ; PAIR } ; +view "add" nat nat { DROP ; PUSH unit Unit } ; diff --git a/tests_python/contracts_011/ill_typed/view_toplevel_bad_type.tz b/tests_python/contracts_011/ill_typed/view_toplevel_bad_type.tz new file mode 100644 index 000000000000..a56d7bc4f88e --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_toplevel_bad_type.tz @@ -0,0 +1,7 @@ +{ parameter nat; + storage nat; + code { CAR; NIL operation ; PAIR }; + view "add_v" nat nat { UNPAIR; ADD }; + view "mul_v" nat nat { UNPAIR; PUSH nat 30; LSR; }; +} + diff --git a/tests_python/contracts_011/ill_typed/view_toplevel_dupable_type_input.tz b/tests_python/contracts_011/ill_typed/view_toplevel_dupable_type_input.tz new file mode 100644 index 000000000000..c252b2eddb28 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_toplevel_dupable_type_input.tz @@ -0,0 +1,5 @@ +parameter nat; +storage nat; +code { CAR ; NIL operation ; PAIR } ; +view "dup" (ticket nat) nat { DROP; PUSH nat 1; PUSH nat 1 ; PAIR} ; + diff --git a/tests_python/contracts_011/ill_typed/view_toplevel_dupable_type_output.tz b/tests_python/contracts_011/ill_typed/view_toplevel_dupable_type_output.tz new file mode 100644 index 000000000000..17919d0004dc --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_toplevel_dupable_type_output.tz @@ -0,0 +1,4 @@ +parameter nat; +storage nat; +code { CAR ; NIL operation ; PAIR } ; +view "dup" address (ticket nat) { DROP; PUSH nat 1; PUSH nat 1 ; TICKET } ; diff --git a/tests_python/contracts_011/ill_typed/view_toplevel_duplicated_name.tz b/tests_python/contracts_011/ill_typed/view_toplevel_duplicated_name.tz new file mode 100644 index 000000000000..680b0ab585d1 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_toplevel_duplicated_name.tz @@ -0,0 +1,5 @@ +parameter nat ; +storage nat ; +code { CAR ; NIL operation ; PAIR } ; +view "add" nat nat { UNPAIR ; ADD } ; +view "add" nat unit { DROP ; PUSH unit Unit } ; diff --git a/tests_python/contracts_011/ill_typed/view_toplevel_invalid_arity.tz b/tests_python/contracts_011/ill_typed/view_toplevel_invalid_arity.tz new file mode 100644 index 000000000000..929e27b6a766 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_toplevel_invalid_arity.tz @@ -0,0 +1,4 @@ +parameter nat ; +storage nat ; +code { CAR ; NIL operation ; PAIR } ; +view "add" nat nat nat { UNPAIR ; ADD } ; diff --git a/tests_python/contracts_011/ill_typed/view_toplevel_lazy_storage_input.tz b/tests_python/contracts_011/ill_typed/view_toplevel_lazy_storage_input.tz new file mode 100644 index 000000000000..3ae7f626a1cf --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_toplevel_lazy_storage_input.tz @@ -0,0 +1,4 @@ +parameter unit; +storage nat; +code { FAIL }; +view "map" (big_map string nat) unit { DROP; UNIT;}; diff --git a/tests_python/contracts_011/ill_typed/view_toplevel_lazy_storage_output.tz b/tests_python/contracts_011/ill_typed/view_toplevel_lazy_storage_output.tz new file mode 100644 index 000000000000..b0ecc0503343 --- /dev/null +++ b/tests_python/contracts_011/ill_typed/view_toplevel_lazy_storage_output.tz @@ -0,0 +1,4 @@ +parameter unit; +storage nat; +code { FAIL; }; +view "get_map" unit (big_map string nat) { CDR; CDR; }; diff --git a/tests_python/contracts_011/legacy/create_account.tz b/tests_python/contracts_011/legacy/create_account.tz new file mode 100644 index 000000000000..7cd38465a10b --- /dev/null +++ b/tests_python/contracts_011/legacy/create_account.tz @@ -0,0 +1,29 @@ +/* +- optional storage: the address of the created account +- param: Left [hash]: + + Create an account with manager [hash]; then perform a recursive call + on Right [addr] where [addr] is the address of the newly created + account. + + The created account has an initial balance of 100tz. It is not + delegatable. + +- param: Right [addr]: + + Check that the sender is self and that [addr] is a contract of type + [unit]. Finally store [addr]. + +*/ +parameter (or key_hash address) ; +storage (option address) ; +code { CAR; + IF_LEFT + { DIP { PUSH mutez 100000000 ; PUSH bool False ; NONE key_hash }; + CREATE_ACCOUNT ; + DIP { RIGHT key_hash ; DIP { SELF ; PUSH mutez 0 } ; TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS } ; + CONS ; NONE address ; SWAP ; PAIR } + { SELF ; ADDRESS ; SENDER ; IFCMPNEQ { FAIL } {} ; + DUP ; CONTRACT unit ; IF_SOME { DROP ; SOME } { FAIL } ; + NIL operation ; PAIR } } ; diff --git a/tests_python/contracts_011/legacy/create_contract.tz b/tests_python/contracts_011/legacy/create_contract.tz new file mode 100644 index 000000000000..a162044ac62b --- /dev/null +++ b/tests_python/contracts_011/legacy/create_contract.tz @@ -0,0 +1,18 @@ +parameter (or key_hash address); +storage unit; +code { CAR; + IF_LEFT + { DIP { PUSH string "dummy"; + PUSH mutez 100000000 ; PUSH bool False ; + PUSH bool False ; NONE key_hash } ; + CREATE_CONTRACT + { parameter string ; + storage string ; + code { CAR ; NIL operation ; PAIR } } ; + DIP { RIGHT key_hash ; DIP { SELF ; PUSH mutez 0 } ; TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS } ; + CONS ; UNIT ; SWAP ; PAIR } + { SELF ; ADDRESS ; SENDER ; IFCMPNEQ { FAIL } {} ; + CONTRACT string ; IF_SOME {} { FAIL } ; + PUSH mutez 0 ; PUSH string "abcdefg" ; TRANSFER_TOKENS ; + NIL operation; SWAP; CONS ; UNIT ; SWAP ; PAIR } }; diff --git a/tests_python/contracts_011/legacy/create_contract_flags.tz b/tests_python/contracts_011/legacy/create_contract_flags.tz new file mode 100644 index 000000000000..888637dd7266 --- /dev/null +++ b/tests_python/contracts_011/legacy/create_contract_flags.tz @@ -0,0 +1,26 @@ +parameter (pair key_hash (pair bool bool)); +storage unit; +code { CAR; + + UNPAPAIR @mgr @spendable @deletagable; + DIP { NONE @delegate key_hash } ; + DIIIIP { UNIT @init; + PUSH @credit mutez 100000000 ; + }; + # type of legacy create_contract + # :: key_hash : option key_hash : bool : bool : mutez : 'g : 'S + # -> operation : address : 'S + CREATE_CONTRACT + { parameter (string %default) ; + storage unit ; + code { DROP; UNIT ; NIL operation ; PAIR } } ; + # simulate create_contract but typecheck for dev + # DROP 6; + # PUSH address "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"; + # NONE key_hash; SET_DELEGATE @origination; + DIP { DROP }; + + NIL operation; + SWAP; CONS; + UNIT; SWAP; PAIR + }; diff --git a/tests_python/contracts_011/legacy/create_contract_rootname.tz b/tests_python/contracts_011/legacy/create_contract_rootname.tz new file mode 100644 index 000000000000..13e24ae5cc24 --- /dev/null +++ b/tests_python/contracts_011/legacy/create_contract_rootname.tz @@ -0,0 +1,18 @@ +parameter (or key_hash address); +storage unit; +code { CAR; + IF_LEFT + { DIP { PUSH string "dummy"; + PUSH mutez 100000000 ; PUSH bool False ; + PUSH bool False ; NONE key_hash } ; + CREATE_CONTRACT + { parameter (string %root) ; + storage string ; + code { CAR ; NIL operation ; PAIR } } ; + DIP { RIGHT key_hash ; DIP { SELF ; PUSH mutez 0 } ; TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS } ; + CONS ; UNIT ; SWAP ; PAIR } + { SELF ; ADDRESS ; SENDER ; IFCMPNEQ { FAIL } {} ; + CONTRACT string ; IF_SOME {} { FAIL } ; + PUSH mutez 0 ; PUSH string "abcdefg" ; TRANSFER_TOKENS ; + NIL operation; SWAP; CONS ; UNIT ; SWAP ; PAIR } }; diff --git a/tests_python/contracts_011/legacy/originator.tz b/tests_python/contracts_011/legacy/originator.tz new file mode 100644 index 000000000000..c454e230dc6d --- /dev/null +++ b/tests_python/contracts_011/legacy/originator.tz @@ -0,0 +1,16 @@ +parameter nat ; +storage (list address) ; +code + { DUP ; CAR ; PUSH nat 0 ; CMPNEQ ; + DIP { DUP ; CAR ; DIP { CDR ; NIL operation } } ; + LOOP + { PUSH mutez 5000000 ; + PUSH bool True ; # delegatable + NONE key_hash ; # delegate + PUSH key_hash "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" ; # manager + CREATE_ACCOUNT ; + SWAP ; DIP { SWAP ; DIP { CONS } } ; + SWAP ; DIP { SWAP ; DIP { CONS } } ; + PUSH nat 1 ; SWAP ; SUB ; ABS ; + DUP ; PUSH nat 0 ; CMPNEQ } ; + DROP ; PAIR } diff --git a/tests_python/contracts_011/legacy/steps_to_quota.tz b/tests_python/contracts_011/legacy/steps_to_quota.tz new file mode 100644 index 000000000000..78e76e308931 --- /dev/null +++ b/tests_python/contracts_011/legacy/steps_to_quota.tz @@ -0,0 +1,12 @@ +parameter int ; +storage nat ; +code { CAR; + DUP; + GT; + LOOP { PUSH int 1; SWAP; SUB; DUP; GT; }; + DROP; + STEPS_TO_QUOTA; + # PUSH nat 1; + NIL operation; + PAIR; + }; diff --git a/tests_python/contracts_011/macros/assert.tz b/tests_python/contracts_011/macros/assert.tz new file mode 100644 index 000000000000..6c5ce503b551 --- /dev/null +++ b/tests_python/contracts_011/macros/assert.tz @@ -0,0 +1,3 @@ +parameter bool; +storage unit; +code {CAR; ASSERT; UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/assert_cmpeq.tz b/tests_python/contracts_011/macros/assert_cmpeq.tz new file mode 100644 index 000000000000..55621bac8fe3 --- /dev/null +++ b/tests_python/contracts_011/macros/assert_cmpeq.tz @@ -0,0 +1,3 @@ +parameter (pair int int); +storage unit; +code {CAR; DUP; CAR; DIP{CDR}; ASSERT_CMPEQ; UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/assert_cmpge.tz b/tests_python/contracts_011/macros/assert_cmpge.tz new file mode 100644 index 000000000000..e98b17044541 --- /dev/null +++ b/tests_python/contracts_011/macros/assert_cmpge.tz @@ -0,0 +1,3 @@ +parameter (pair int int); +storage unit; +code {CAR; DUP; CAR; DIP{CDR}; ASSERT_CMPGE; UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/assert_cmpgt.tz b/tests_python/contracts_011/macros/assert_cmpgt.tz new file mode 100644 index 000000000000..7a44174b7259 --- /dev/null +++ b/tests_python/contracts_011/macros/assert_cmpgt.tz @@ -0,0 +1,3 @@ +parameter (pair int int); +storage unit; +code {CAR; DUP; CAR; DIP{CDR}; ASSERT_CMPGT; UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/assert_cmple.tz b/tests_python/contracts_011/macros/assert_cmple.tz new file mode 100644 index 000000000000..e4b61cfc44c3 --- /dev/null +++ b/tests_python/contracts_011/macros/assert_cmple.tz @@ -0,0 +1,3 @@ +parameter (pair int int); +storage unit; +code {CAR; DUP; CAR; DIP{CDR}; ASSERT_CMPLE; UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/assert_cmplt.tz b/tests_python/contracts_011/macros/assert_cmplt.tz new file mode 100644 index 000000000000..290b495378df --- /dev/null +++ b/tests_python/contracts_011/macros/assert_cmplt.tz @@ -0,0 +1,3 @@ +parameter (pair int int); +storage unit; +code {CAR; DUP; CAR; DIP{CDR}; ASSERT_CMPLT; UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/assert_cmpneq.tz b/tests_python/contracts_011/macros/assert_cmpneq.tz new file mode 100644 index 000000000000..86b601393b8c --- /dev/null +++ b/tests_python/contracts_011/macros/assert_cmpneq.tz @@ -0,0 +1,3 @@ +parameter (pair int int); +storage unit; +code {CAR; DUP; CAR; DIP{CDR}; ASSERT_CMPNEQ; UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/assert_eq.tz b/tests_python/contracts_011/macros/assert_eq.tz new file mode 100644 index 000000000000..338096a6277c --- /dev/null +++ b/tests_python/contracts_011/macros/assert_eq.tz @@ -0,0 +1,3 @@ +parameter (pair int int); +storage unit; +code {CAR; DUP; CAR; DIP{CDR}; COMPARE; ASSERT_EQ; UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/assert_ge.tz b/tests_python/contracts_011/macros/assert_ge.tz new file mode 100644 index 000000000000..06bb3cec944b --- /dev/null +++ b/tests_python/contracts_011/macros/assert_ge.tz @@ -0,0 +1,3 @@ +parameter (pair int int); +storage unit; +code {CAR; DUP; CAR; DIP{CDR}; COMPARE; ASSERT_GE; UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/assert_gt.tz b/tests_python/contracts_011/macros/assert_gt.tz new file mode 100644 index 000000000000..d041093b0ebf --- /dev/null +++ b/tests_python/contracts_011/macros/assert_gt.tz @@ -0,0 +1,3 @@ +parameter (pair int int); +storage unit; +code {CAR; DUP; CAR; DIP{CDR}; COMPARE; ASSERT_GT; UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/assert_le.tz b/tests_python/contracts_011/macros/assert_le.tz new file mode 100644 index 000000000000..8250f3f3bdb1 --- /dev/null +++ b/tests_python/contracts_011/macros/assert_le.tz @@ -0,0 +1,3 @@ +parameter (pair int int); +storage unit; +code {CAR; DUP; CAR; DIP{CDR}; COMPARE; ASSERT_LE; UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/assert_lt.tz b/tests_python/contracts_011/macros/assert_lt.tz new file mode 100644 index 000000000000..e387e9d74070 --- /dev/null +++ b/tests_python/contracts_011/macros/assert_lt.tz @@ -0,0 +1,3 @@ +parameter (pair int int); +storage unit; +code {CAR; DUP; CAR; DIP{CDR}; COMPARE; ASSERT_LT; UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/assert_neq.tz b/tests_python/contracts_011/macros/assert_neq.tz new file mode 100644 index 000000000000..83f19559e1d1 --- /dev/null +++ b/tests_python/contracts_011/macros/assert_neq.tz @@ -0,0 +1,3 @@ +parameter (pair int int); +storage unit; +code {CAR; DUP; CAR; DIP{CDR}; COMPARE; ASSERT_NEQ; UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/big_map_get_add.tz b/tests_python/contracts_011/macros/big_map_get_add.tz new file mode 100644 index 000000000000..2dcf1ce69a08 --- /dev/null +++ b/tests_python/contracts_011/macros/big_map_get_add.tz @@ -0,0 +1,7 @@ +parameter (pair (pair %set_pair int (option int)) (pair %check_pair int (option int))) ; +storage (pair (big_map int int) unit) ; +code { DUP ; DIP { CDAR } ; + DUP ; DIP { CADR; DUP ; CAR ; DIP { CDR } ; UPDATE ; DUP } ; + CADR ; DUP ; CDR ; DIP { CAR ; GET } ; + IF_SOME { SWAP ; IF_SOME { ASSERT_CMPEQ } {FAIL}} { ASSERT_NONE } ; + UNIT ; SWAP ; PAIR ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/macros/big_map_mem.tz b/tests_python/contracts_011/macros/big_map_mem.tz new file mode 100644 index 000000000000..55736ab89da6 --- /dev/null +++ b/tests_python/contracts_011/macros/big_map_mem.tz @@ -0,0 +1,5 @@ +# Fails if the boolean does not match the membership criteria +parameter (pair int bool) ; +storage (pair (big_map int unit) unit) ; +code { DUP ; DUP ; CADR ; DIP { CAAR ; DIP { CDAR ; DUP } ; MEM } ; + ASSERT_CMPEQ ; UNIT ; SWAP ; PAIR ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/macros/build_list.tz b/tests_python/contracts_011/macros/build_list.tz new file mode 100644 index 000000000000..842056d913ce --- /dev/null +++ b/tests_python/contracts_011/macros/build_list.tz @@ -0,0 +1,6 @@ +parameter nat; +storage (list nat); +code { CAR @counter; NIL @acc nat; SWAP; DUP @cmp_num; PUSH nat 0; CMPNEQ; + LOOP { DUP; DIP {SWAP}; CONS @acc; SWAP; PUSH nat 1; SWAP; SUB @counter; + DUP; DIP{ABS}; PUSH int 0; CMPNEQ}; + CONS; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/macros/carn_and_cdrn.tz b/tests_python/contracts_011/macros/carn_and_cdrn.tz new file mode 100644 index 000000000000..cc3cdccee81a --- /dev/null +++ b/tests_python/contracts_011/macros/carn_and_cdrn.tz @@ -0,0 +1,26 @@ +# Same as ../opcodes/comb-get.tz but using the CAR n and CDR n macros instead of GET +parameter (pair nat nat nat unit); +storage unit; +code { + CAR ; + + # Checking the first element + DUP ; CAR ; + PUSH nat 1 ; ASSERT_CMPEQ ; + DUP ; CAR 0 ; + PUSH nat 1 ; ASSERT_CMPEQ ; + + # Checking the second element + DUP ; CAR 1 ; + PUSH nat 4 ; ASSERT_CMPEQ ; + + # Checking the third element + DUP ; CAR 2 ; + PUSH nat 2 ; ASSERT_CMPEQ ; + + # Checking the last (fourth) element + DUP ; CDR 3 ; + UNIT ; ASSERT_CMPEQ ; + + DROP ; UNIT ; NIL operation ; PAIR + } diff --git a/tests_python/contracts_011/macros/compare.tz b/tests_python/contracts_011/macros/compare.tz new file mode 100644 index 000000000000..698ef3e695ed --- /dev/null +++ b/tests_python/contracts_011/macros/compare.tz @@ -0,0 +1,9 @@ +parameter (pair mutez mutez); +storage (list bool); +code {CAR; DUP; DUP; DUP; DUP; DIIIIIP {NIL bool}; + DIIIIP {DUP; CAR; DIP {CDR}; COMPARE; LE; CONS}; + DIIIP {DUP; CAR; DIP {CDR}; COMPARE; GE; CONS}; + DIIP{DUP; CAR; DIP {CDR}; COMPARE; LT; CONS}; + DIP {DUP; CAR; DIP {CDR}; COMPARE; GT; CONS}; + DUP; CAR; DIP {CDR}; COMPARE; EQ; CONS; + NIL operation; PAIR}; diff --git a/tests_python/contracts_011/macros/compare_bytes.tz b/tests_python/contracts_011/macros/compare_bytes.tz new file mode 100644 index 000000000000..3b5e5a9c400c --- /dev/null +++ b/tests_python/contracts_011/macros/compare_bytes.tz @@ -0,0 +1,9 @@ +parameter (pair bytes bytes); +storage (list bool); +code {CAR; DUP; DUP; DUP; DUP; DIIIIIP {NIL bool}; + DIIIIP {DUP; CAR; DIP {CDR}; COMPARE; LE; CONS}; + DIIIP {DUP; CAR; DIP {CDR}; COMPARE; GE; CONS}; + DIIP{DUP; CAR; DIP {CDR}; COMPARE; LT; CONS}; + DIP {DUP; CAR; DIP {CDR}; COMPARE; GT; CONS}; + DUP; CAR; DIP {CDR}; COMPARE; EQ; CONS; + NIL operation; PAIR}; diff --git a/tests_python/contracts_011/macros/fail.tz b/tests_python/contracts_011/macros/fail.tz new file mode 100644 index 000000000000..7f8bde252130 --- /dev/null +++ b/tests_python/contracts_011/macros/fail.tz @@ -0,0 +1,5 @@ +parameter unit; +storage unit; +code + { # This contract will never accept a incoming transaction + FAIL}; diff --git a/tests_python/contracts_011/macros/guestbook.tz b/tests_python/contracts_011/macros/guestbook.tz new file mode 100644 index 000000000000..b362f94b957e --- /dev/null +++ b/tests_python/contracts_011/macros/guestbook.tz @@ -0,0 +1,10 @@ +parameter string; +storage (map address (option string)); + +code { UNPAIR @message @guestbook; SWAP; + DUP; SENDER; GET @previous_message; + ASSERT_SOME; + ASSERT_NONE; + SWAP; SOME; SOME; SENDER; UPDATE; + NIL operation; + PAIR } diff --git a/tests_python/contracts_011/macros/macro_annotations.tz b/tests_python/contracts_011/macros/macro_annotations.tz new file mode 100644 index 000000000000..f48f18e3d942 --- /dev/null +++ b/tests_python/contracts_011/macros/macro_annotations.tz @@ -0,0 +1,6 @@ +parameter unit; +storage (pair (unit %truc) unit); +code { DROP; UNIT ; UNIT ; PAIR %truc ; UNIT ; + DUUP @new_storage ; + DIP { DROP ; DROP } ; + NIL operation ; PAIR } diff --git a/tests_python/contracts_011/macros/map_caddaadr.tz b/tests_python/contracts_011/macros/map_caddaadr.tz new file mode 100644 index 000000000000..45509839cc01 --- /dev/null +++ b/tests_python/contracts_011/macros/map_caddaadr.tz @@ -0,0 +1,4 @@ +parameter unit; +storage (pair (pair nat (pair nat (pair (pair (pair (nat %p) (mutez %value)) nat) nat))) nat); +code { MAP_CDADDAADR @new_storage %value { PUSH mutez 1000000 ; ADD } ; + NIL operation ; SWAP; SET_CAR }; diff --git a/tests_python/contracts_011/macros/max_in_list.tz b/tests_python/contracts_011/macros/max_in_list.tz new file mode 100644 index 000000000000..89c4955e9374 --- /dev/null +++ b/tests_python/contracts_011/macros/max_in_list.tz @@ -0,0 +1,9 @@ +parameter (list int); +storage (option int); +code {CAR; DIP{NONE int}; + ITER {SWAP; + IF_NONE {SOME} + {DIP {DUP}; DUP; DIP{SWAP}; + CMPLE; IF {DROP} {DIP {DROP}}; + SOME}}; + NIL operation; PAIR}; diff --git a/tests_python/contracts_011/macros/min.tz b/tests_python/contracts_011/macros/min.tz new file mode 100644 index 000000000000..cedd835bbac8 --- /dev/null +++ b/tests_python/contracts_011/macros/min.tz @@ -0,0 +1,11 @@ + +parameter (pair int int); +storage int; +code { CAR; # Ignore the storage + DUP; # Duplicate so we can get both the numbers passed as parameters + DUP; # Second dup so we can access the lesser number + CAR; DIP{CDR}; # Unpack the numbers on top of the stack + CMPLT; # Compare the two numbers, placing a boolean on top of the stack + IF {CAR} {CDR}; # Access the first number if the boolean was true + NIL operation; # Return no op + PAIR} # Pair the numbers satisfying the calling convention diff --git a/tests_python/contracts_011/macros/pair_macro.tz b/tests_python/contracts_011/macros/pair_macro.tz new file mode 100644 index 000000000000..55c70a3be3e9 --- /dev/null +++ b/tests_python/contracts_011/macros/pair_macro.tz @@ -0,0 +1,6 @@ +parameter unit; +storage unit; +code { UNIT; UNIT; UNIT; UNIT; UNIT; + PAPAPAPAIR @name %x1 %x2 %x3 %x4 %x5; + CDDDAR %x4 @fourth; + DROP; CDR; NIL operation; PAIR} diff --git a/tests_python/contracts_011/macros/set_caddaadr.tz b/tests_python/contracts_011/macros/set_caddaadr.tz new file mode 100644 index 000000000000..e98671e40989 --- /dev/null +++ b/tests_python/contracts_011/macros/set_caddaadr.tz @@ -0,0 +1,5 @@ +parameter mutez; +storage (pair (pair nat (pair nat (pair (pair (pair (nat %p) (mutez %value)) nat) nat))) nat); +code { DUP ; CAR ; SWAP ; CDR ; + SET_CADDAADR @toplevel_pair_name %value ; + NIL operation ; PAIR }; diff --git a/tests_python/contracts_011/macros/take_my_money.tz b/tests_python/contracts_011/macros/take_my_money.tz new file mode 100644 index 000000000000..bb502d041849 --- /dev/null +++ b/tests_python/contracts_011/macros/take_my_money.tz @@ -0,0 +1,9 @@ +parameter key_hash; +storage unit; +code { CAR; IMPLICIT_ACCOUNT; # Create an account for the recipient of the funds + DIP{UNIT}; # Push a value of the storage type below the contract + PUSH mutez 1000000; # The person can have a ꜩ + UNIT; # Push the contract's argument type + TRANSFER_TOKENS; # Run the transfer + NIL operation; SWAP; CONS; + PAIR }; # Cleanup and put the return values diff --git a/tests_python/contracts_011/macros/unpair_macro.tz b/tests_python/contracts_011/macros/unpair_macro.tz new file mode 100644 index 000000000000..384b6839d88b --- /dev/null +++ b/tests_python/contracts_011/macros/unpair_macro.tz @@ -0,0 +1,9 @@ +parameter (unit :param_unit); +storage (unit :u1); +code { DROP ; + UNIT :u4 @a4; UNIT :u3 @a3; UNIT :u2 @a2; UNIT :u1 @a1; + PAIR; UNPAIR @x1 @x2; + PPAIPAIR @p1 %x1 %x2 %x3 %x4; UNPPAIPAIR %x1 % %x3 %x4 @uno @due @tre @quattro; + PAPAPAIR @p2 %x1 %x2 %x3 %x4; UNPAPAPAIR @un @deux @trois @quatre; + PAPPAIIR @p3 %x1 %x2 %x3 %x4; UNPAPPAIIR @one @two @three @four; + DIP { DROP; DROP; DROP }; NIL operation; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/mini_scenarios/authentication.tz b/tests_python/contracts_011/mini_scenarios/authentication.tz new file mode 100644 index 000000000000..021bbd26361a --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/authentication.tz @@ -0,0 +1,30 @@ +/* + +This contract is an example of using a cryptographic signature to +handle authentication. A public key is stored, and only the owner of +the secret key associated to this public key can interact with the +contract. She is allowed to perform any list of operations by sending +them wrapped in a lambda to the contract with a cryptographic +signature. + +To ensure that each signature is used only once and is not replayed by +an attacker, not only the lambda is signed but also the unique +identifier of the contract (a pair of the contract address and the +chain id) and a counter that is incremented at each successful call. + +More precisely, the signature should check against pack ((chain_id, +self) (param, counter)). + +*/ +parameter (pair (lambda unit (list operation)) signature); +storage (pair (nat %counter) key); +code + { + UNPPAIPAIR; + DUUUP; DUUP ; SELF; CHAIN_ID ; PPAIPAIR; PACK; + DIP { SWAP }; DUUUUUP ; DIP { SWAP }; + DUUUP; DIP {CHECK_SIGNATURE}; SWAP; IF {DROP} {FAILWITH}; + UNIT; EXEC; + DIP { PUSH nat 1; ADD }; + PAPAIR + } diff --git a/tests_python/contracts_011/mini_scenarios/big_map_entrypoints.tz b/tests_python/contracts_011/mini_scenarios/big_map_entrypoints.tz new file mode 100644 index 000000000000..d49e6257167a --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/big_map_entrypoints.tz @@ -0,0 +1,31 @@ +storage + (pair (big_map string nat) (big_map string nat)) ; +parameter + (or (unit %default) + (or (or %mem (string %mem_left) (string %mem_right)) + (or (or %add (pair %add_left string nat) (pair %add_right string nat)) + (or %rem (string %rem_left) (string %rem_right))))) ; +code { UNPAIR ; + IF_LEFT + { DROP ; + DUP ; CAR ; + PUSH mutez 0 ; + NONE key_hash ; + CREATE_CONTRACT + { parameter string ; + storage (big_map string nat) ; + code { UNPAIR ; DROP ; NIL operation ; PAIR }} ; + DIP { DROP } ; + NIL operation ; SWAP ; CONS ; PAIR } + { IF_LEFT + { IF_LEFT + { DIP { UNPAIR } ; DIP { DUP } ; MEM ; ASSERT } + { DIP { UNPAIR ; SWAP } ; DIP { DUP } ; MEM ; ASSERT ; SWAP } } + { IF_LEFT + { IF_LEFT + { UNPAIR ; DIIP { UNPAIR } ; DIP { SOME } ; UPDATE } + { UNPAIR ; DIIP { UNPAIR ; SWAP } ; DIP { SOME } ; UPDATE ; SWAP } } + { IF_LEFT + { DIP { UNPAIR } ; DIP { NONE nat } ; UPDATE } + { DIP { UNPAIR ; SWAP } ; DIP { NONE nat } ; UPDATE ; SWAP } } } ; + PAIR ; NIL operation ; PAIR } } diff --git a/tests_python/contracts_011/mini_scenarios/big_map_magic.tz b/tests_python/contracts_011/mini_scenarios/big_map_magic.tz new file mode 100644 index 000000000000..f4e36f639bff --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/big_map_magic.tz @@ -0,0 +1,41 @@ +# this contracts handles two big_maps +storage + (or (pair (big_map string string) (big_map string string)) unit) ; +parameter + # it has 5 entry points + # swap: swaps the two maps. + (or (unit %swap) + # reset: resets storage, either to a new pair of maps, or to unit + (or (or %reset (pair (big_map string string) (big_map string string)) unit) + # import: drops the existing storage and creates two maps + # from the given lists of string pairs. + (or (pair %import (list (pair string string)) (list (pair string string))) + # add: adds the given list of key - value pairs into the + # first map + (or (list %add (pair string string)) + # rem: removes the given list of key - value pairs + # from the first map + (list %rem string))))) ; +code { UNPAIR ; + IF_LEFT + { DROP ; ASSERT_LEFT ; UNPAIR ; SWAP ; PAIR ; LEFT unit } + { IF_LEFT + { SWAP ; DROP } + { IF_LEFT + { DIP { ASSERT_RIGHT ; DROP } ; + UNPAIR ; + DIP { EMPTY_BIG_MAP string string } ; + ITER { UNPAIR ; DIP { SOME } ; UPDATE } ; + SWAP ; + DIP { EMPTY_BIG_MAP string string } ; + ITER { UNPAIR ; DIP { SOME } ; UPDATE } ; + SWAP ; + PAIR ; LEFT unit } + { IF_LEFT + { DIP { ASSERT_LEFT ; UNPAIR } ; + ITER { UNPAIR ; DIP { SOME } ; UPDATE } ; + PAIR ; LEFT unit } + { DIP { ASSERT_LEFT ; UNPAIR } ; + ITER { DIP { NONE string } ; UPDATE } ; + PAIR ; LEFT unit } }} } ; + NIL operation ; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/mini_scenarios/big_map_read.tz b/tests_python/contracts_011/mini_scenarios/big_map_read.tz new file mode 100644 index 000000000000..60d666e28f29 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/big_map_read.tz @@ -0,0 +1,9 @@ +storage (nat); +parameter (big_map nat nat); +code { CAR; + PUSH nat 1; + GET; + ASSERT_SOME; + NIL operation; + PAIR; + } diff --git a/tests_python/contracts_011/mini_scenarios/big_map_store.tz b/tests_python/contracts_011/mini_scenarios/big_map_store.tz new file mode 100644 index 000000000000..4dc68145a691 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/big_map_store.tz @@ -0,0 +1,8 @@ +storage (big_map nat nat); +parameter (unit); +code { DROP; + EMPTY_BIG_MAP nat nat; + NIL operation; + PAIR; + } + diff --git a/tests_python/contracts_011/mini_scenarios/big_map_write.tz b/tests_python/contracts_011/mini_scenarios/big_map_write.tz new file mode 100644 index 000000000000..bde3b19baa3d --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/big_map_write.tz @@ -0,0 +1,10 @@ +storage (unit); +parameter (big_map nat nat); +code { UNPAIR ; + PUSH (option nat) (Some 1); + PUSH nat 1; + UPDATE; + DROP; + NIL operation; + PAIR; + } diff --git a/tests_python/contracts_011/mini_scenarios/create_contract.tz b/tests_python/contracts_011/mini_scenarios/create_contract.tz new file mode 100644 index 000000000000..0d09a1fdfca6 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/create_contract.tz @@ -0,0 +1,33 @@ +/* +- param: None: + + Create a contract then perform a recursive call on Some [addr] where + [addr] is the address of the newly created contract. + + The created contract simply stores its parameter (a string). It is + initialized with the storage "dummy" and has an initial balance of + 100tz. It has no delegate so these 100tz are totally frozen. + +- param: Some [addr]: + + Check that the sender is self, call the contract at address [addr] + with param "abcdefg" transferring 0tz. + +*/ +parameter (option address) ; +storage unit ; +code { CAR ; + IF_NONE + { PUSH string "dummy" ; + PUSH mutez 100000000 ; NONE key_hash ; + CREATE_CONTRACT + { parameter string ; + storage string ; + code { CAR ; NIL operation ; PAIR } } ; + DIP { SOME ; DIP { SELF ; PUSH mutez 0 } ; TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS } ; + CONS ; UNIT ; SWAP ; PAIR } + { SELF ; ADDRESS ; SENDER ; IFCMPNEQ { FAIL } {} ; + CONTRACT string ; IF_SOME {} { FAIL } ; + PUSH mutez 0 ; PUSH string "abcdefg" ; TRANSFER_TOKENS ; + NIL operation; SWAP; CONS ; UNIT ; SWAP ; PAIR } } ; \ No newline at end of file diff --git a/tests_python/contracts_011/mini_scenarios/create_contract_simple.tz b/tests_python/contracts_011/mini_scenarios/create_contract_simple.tz new file mode 100644 index 000000000000..2a5185d74889 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/create_contract_simple.tz @@ -0,0 +1,14 @@ +parameter unit; +storage unit; +code { CAR; + PUSH string "foo"; + PUSH mutez 0; + NONE key_hash; + CREATE_CONTRACT + { parameter string ; + storage string ; + code { CAR ; NIL operation ; PAIR } } ; + DROP; DROP; + NIL operation; + PAIR; + } diff --git a/tests_python/contracts_011/mini_scenarios/default_account.tz b/tests_python/contracts_011/mini_scenarios/default_account.tz new file mode 100644 index 000000000000..74e7693d7ba5 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/default_account.tz @@ -0,0 +1,9 @@ +/* +Send 100 tz to the implicit account given as parameter. +*/ + +parameter key_hash; +storage unit; +code {DIP{UNIT}; CAR; IMPLICIT_ACCOUNT; + PUSH mutez 100000000; UNIT; TRANSFER_TOKENS; + NIL operation; SWAP; CONS; PAIR} diff --git a/tests_python/contracts_011/mini_scenarios/execution_order_appender.tz b/tests_python/contracts_011/mini_scenarios/execution_order_appender.tz new file mode 100644 index 000000000000..9a519f780924 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/execution_order_appender.tz @@ -0,0 +1,17 @@ +# Given a storage (adr, str), calls the contract at adr with the +# parameter str +parameter unit; +storage (pair address string); +code { + CDR; + DUP; + UNPAIR; + CONTRACT string; + ASSERT_SOME; + PUSH mutez 0; + DIG 2; + TRANSFER_TOKENS; + NIL operation; + SWAP; + CONS; + PAIR }; diff --git a/tests_python/contracts_011/mini_scenarios/execution_order_caller.tz b/tests_python/contracts_011/mini_scenarios/execution_order_caller.tz new file mode 100644 index 000000000000..ead37544f4e8 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/execution_order_caller.tz @@ -0,0 +1,17 @@ +# Given storage [adr1; ...; adrn], emits operations +# [ TRANSFER_TOKENS Unit (Mutez 0) adr1 ; +# ... ; +# TRANSFER_TOKENS Unit (Mutez 0) adrn ] +parameter unit; +storage (list address); +code { + CDR; + DUP; + MAP { + CONTRACT unit; + ASSERT_SOME; + PUSH mutez 0; + UNIT; + TRANSFER_TOKENS; + }; + PAIR }; diff --git a/tests_python/contracts_011/mini_scenarios/execution_order_storer.tz b/tests_python/contracts_011/mini_scenarios/execution_order_storer.tz new file mode 100644 index 000000000000..2bfc7505e9cd --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/execution_order_storer.tz @@ -0,0 +1,4 @@ +# Appends the parameter to the string in storage +parameter (string); +storage (string); +code { UNPAIR; SWAP; CONCAT; NIL operation; PAIR }; diff --git a/tests_python/contracts_011/mini_scenarios/fa12_reference.tz b/tests_python/contracts_011/mini_scenarios/fa12_reference.tz new file mode 100644 index 000000000000..7c2265072db4 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/fa12_reference.tz @@ -0,0 +1,749 @@ +# This contract comes from the gitlab.com/tzip/tzip repository. It is +# distributed under the CC0 1.0 license, which can be found at +# https://gitlab.com/tzip/tzip/-/blob/4b3c67aad5abbf04ec36caea4a1809e7b6e55bb8/LICENSE + +# Its purpose is to serve as a reference contract for TZIP-7, which +# defines Financial Assets 1.2. The original file can be found at +# https://gitlab.com/tzip/tzip/-/blob/4b3c67aad5abbf04ec36caea4a1809e7b6e55bb8/proposals/tzip-7/ManagedLedger.tz + +# This contract was generated from +# https://gitlab.com/morley-framework/morley/tree/ce28076a79b93d48aa7745271e6a1395b8b9e50d/lorentz-contracts/src/Lorentz/Contracts/ManagedLedger.hs +# Storage annotations were added manually. + +parameter (or (or (or (pair %transfer (address :from) + (pair (address :to) + (nat :value))) + (pair %approve (address :spender) + (nat :value))) + (or (pair %getAllowance (pair (address :owner) + (address :spender)) + (contract nat)) + (or (pair %getBalance (address :owner) + (contract nat)) + (pair %getTotalSupply unit + (contract nat))))) + (or (or (bool %setPause) + (address %setAdministrator)) + (or (pair %getAdministrator unit + (contract address)) + (or (pair %mint (address :to) + (nat :value)) + (pair %burn (address :from) + (nat :value)))))); +storage (pair (big_map %ledger (address :user) + (pair (nat :balance) + (map :approvals (address :spender) + (nat :value)))) + (pair (address %admin) + (pair (bool %paused) + (nat %totalSupply)))); +code { CAST (pair (or (or (or (pair address (pair address nat)) (pair address nat)) (or (pair (pair address address) (contract nat)) (or (pair address (contract nat)) (pair unit (contract nat))))) (or (or bool address) (or (pair unit (contract address)) (or (pair address nat) (pair address nat))))) (pair (big_map address (pair nat (map address nat))) (pair address (pair bool nat)))); + DUP; + CAR; + DIP { CDR }; + IF_LEFT { IF_LEFT { IF_LEFT { DIP { DUP; + CDR; + CDR; + CAR; + IF { UNIT; + PUSH string "TokenOperationsArePaused"; + PAIR; + FAILWITH } + { } }; + DUP; + DUP; + CDR; + CAR; + DIP { CAR }; + COMPARE; + EQ; + IF { DROP } + { DUP; + CAR; + SENDER; + COMPARE; + EQ; + IF { } + { DUP; + DIP { DUP; + DIP { DIP { DUP }; + CAR; + SENDER; + PAIR; + DUP; + DIP { CDR; + DIP { CAR }; + GET; + IF_NONE { EMPTY_MAP (address) nat } + { CDR } }; + CAR; + GET; + IF_NONE { PUSH nat 0 } + { } }; + DUP; + CAR; + DIP { SENDER; + DIP { DUP; + CDR; + CDR; + DIP { DIP { DUP }; + SWAP }; + SWAP; + SUB; + ISNAT; + IF_NONE { DIP { DUP }; + SWAP; + DIP { DUP }; + SWAP; + CDR; + CDR; + PAIR; + PUSH string "NotEnoughAllowance"; + PAIR; + FAILWITH } + { } }; + PAIR }; + PAIR; + DIP { DROP; + DROP }; + DIP { DUP }; + SWAP; + DIP { DUP; + CAR }; + SWAP; + DIP { CAR }; + GET; + IF_NONE { PUSH nat 0; + DIP { EMPTY_MAP (address) nat }; + PAIR; + EMPTY_MAP (address) nat } + { DUP; + CDR }; + DIP { DIP { DUP }; + SWAP }; + SWAP; + CDR; + CDR; + DUP; + INT; + EQ; + IF { DROP; + NONE nat } + { SOME }; + DIP { DIP { DIP { DUP }; + SWAP }; + SWAP }; + SWAP; + CDR; + CAR; + UPDATE; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DROP }; + SWAP; + PAIR; + SWAP; + CAR; + DIP { SOME }; + DIP { DIP { DUP; + CAR } }; + UPDATE; + DIP { DUP; + DIP { CDR }; + CAR }; + DIP { DROP }; + PAIR } }; + DIP { DUP }; + SWAP; + DIP { DUP }; + SWAP; + CDR; + CAR; + DIP { CAR }; + GET; + IF_NONE { DUP; + CDR; + CDR; + INT; + EQ; + IF { NONE (pair nat (map address nat)) } + { DUP; + CDR; + CDR; + DIP { EMPTY_MAP (address) nat }; + PAIR; + SOME } } + { DIP { DUP }; + SWAP; + CDR; + CDR; + DIP { DUP; + CAR }; + ADD; + DIP { DUP; + DIP { CDR }; + CAR }; + DIP { DROP }; + PAIR; + SOME }; + SWAP; + DUP; + DIP { CDR; + CAR; + DIP { DIP { DUP; + CAR } }; + UPDATE; + DIP { DUP; + DIP { CDR }; + CAR }; + DIP { DROP }; + PAIR }; + DUP; + DIP { CDR; + CDR; + INT; + DIP { DUP; + CDR; + CDR; + CDR }; + ADD; + ISNAT; + IF_NONE { PUSH string "Internal: Negative total supply"; + FAILWITH } + { }; + DIP { DUP; + CDR }; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DROP }; + SWAP; + PAIR; + SWAP; + PAIR; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DROP }; + SWAP; + PAIR }; + DIP { DUP }; + SWAP; + DIP { DUP }; + SWAP; + CAR; + DIP { CAR }; + GET; + IF_NONE { CDR; + CDR; + PUSH nat 0; + SWAP; + PAIR; + PUSH string "NotEnoughBalance"; + PAIR; + FAILWITH } + { }; + DUP; + CAR; + DIP { DIP { DUP }; + SWAP }; + SWAP; + CDR; + CDR; + SWAP; + SUB; + ISNAT; + IF_NONE { CAR; + DIP { DUP }; + SWAP; + CDR; + CDR; + PAIR; + PUSH string "NotEnoughBalance"; + PAIR; + FAILWITH } + { }; + DIP { DUP; + DIP { CDR }; + CAR }; + DIP { DROP }; + PAIR; + DIP { DUP }; + SWAP; + DIP { DUP; + CAR; + INT; + EQ; + IF { DUP; + CDR; + SIZE; + INT; + EQ; + IF { DROP; + NONE (pair nat (map address nat)) } + { SOME } } + { SOME }; + SWAP; + CAR; + DIP { DIP { DUP; + CAR } }; + UPDATE; + DIP { DUP; + DIP { CDR }; + CAR }; + DIP { DROP }; + PAIR }; + DUP; + DIP { CDR; + CDR; + NEG; + DIP { DUP; + CDR; + CDR; + CDR }; + ADD; + ISNAT; + IF_NONE { PUSH string "Internal: Negative total supply"; + FAILWITH } + { }; + DIP { DUP; + CDR }; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DROP }; + SWAP; + PAIR; + SWAP; + PAIR; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DROP }; + SWAP; + PAIR }; + DROP }; + NIL operation; + PAIR } + { SENDER; + PAIR; + DIP { DUP; + CDR; + CDR; + CAR; + IF { UNIT; + PUSH string "TokenOperationsArePaused"; + PAIR; + FAILWITH } + { } }; + DIP { DUP }; + SWAP; + DIP { DUP }; + SWAP; + DUP; + DIP { CAR; + DIP { CAR }; + GET; + IF_NONE { EMPTY_MAP (address) nat } + { CDR } }; + CDR; + CAR; + GET; + IF_NONE { PUSH nat 0 } + { }; + DUP; + INT; + EQ; + IF { DROP } + { DIP { DUP }; + SWAP; + CDR; + CDR; + INT; + EQ; + IF { DROP } + { PUSH string "UnsafeAllowanceChange"; + PAIR; + FAILWITH } }; + DIP { DUP }; + SWAP; + DIP { DUP; + CAR }; + SWAP; + DIP { CAR }; + GET; + IF_NONE { PUSH nat 0; + DIP { EMPTY_MAP (address) nat }; + PAIR; + EMPTY_MAP (address) nat } + { DUP; + CDR }; + DIP { DIP { DUP }; + SWAP }; + SWAP; + CDR; + CDR; + DUP; + INT; + EQ; + IF { DROP; + NONE nat } + { SOME }; + DIP { DIP { DIP { DUP }; + SWAP }; + SWAP }; + SWAP; + CDR; + CAR; + UPDATE; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DROP }; + SWAP; + PAIR; + SWAP; + CAR; + DIP { SOME }; + DIP { DIP { DUP; + CAR } }; + UPDATE; + DIP { DUP; + DIP { CDR }; + CAR }; + DIP { DROP }; + PAIR; + NIL operation; + PAIR } } + { IF_LEFT { DUP; + CAR; + DIP { CDR }; + DIP { DIP { DUP }; + SWAP }; + PAIR; + DUP; + CAR; + DIP { CDR }; + DUP; + DIP { CAR; + DIP { CAR }; + GET; + IF_NONE { EMPTY_MAP (address) nat } + { CDR } }; + CDR; + GET; + IF_NONE { PUSH nat 0 } + { }; + DIP { AMOUNT }; + TRANSFER_TOKENS; + NIL operation; + SWAP; + CONS; + PAIR } + { IF_LEFT { DUP; + CAR; + DIP { CDR }; + DIP { DIP { DUP }; + SWAP }; + PAIR; + DUP; + CAR; + DIP { CDR }; + DIP { CAR }; + GET; + IF_NONE { PUSH nat 0 } + { CAR }; + DIP { AMOUNT }; + TRANSFER_TOKENS; + NIL operation; + SWAP; + CONS; + PAIR } + { DUP; + CAR; + DIP { CDR }; + DIP { DIP { DUP }; + SWAP }; + PAIR; + CDR; + CDR; + CDR; + CDR; + DIP { AMOUNT }; + TRANSFER_TOKENS; + NIL operation; + SWAP; + CONS; + PAIR } } } } + { IF_LEFT { IF_LEFT { DIP { DUP; + CDR; + CAR; + SENDER; + COMPARE; + EQ; + IF { } + { UNIT; + PUSH string "SenderIsNotAdmin"; + PAIR; + FAILWITH } }; + DIP { DUP; + CDR }; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DUP; + DIP { CDR }; + CAR }; + DIP { DROP }; + PAIR; + SWAP; + PAIR; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DROP }; + SWAP; + PAIR; + NIL operation; + PAIR } + { DIP { DUP; + CDR; + CAR; + SENDER; + COMPARE; + EQ; + IF { } + { UNIT; + PUSH string "SenderIsNotAdmin"; + PAIR; + FAILWITH } }; + DIP { DUP; + CDR }; + DIP { DUP; + DIP { CDR }; + CAR }; + DIP { DROP }; + PAIR; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DROP }; + SWAP; + PAIR; + NIL operation; + PAIR } } + { IF_LEFT { DUP; + CAR; + DIP { CDR }; + DIP { DIP { DUP }; + SWAP }; + PAIR; + CDR; + CDR; + CAR; + DIP { AMOUNT }; + TRANSFER_TOKENS; + NIL operation; + SWAP; + CONS; + PAIR } + { IF_LEFT { DIP { DUP; + CDR; + CAR; + SENDER; + COMPARE; + EQ; + IF { } + { UNIT; + PUSH string "SenderIsNotAdmin"; + PAIR; + FAILWITH } }; + DIP { DUP }; + SWAP; + DIP { DUP }; + SWAP; + CAR; + DIP { CAR }; + GET; + IF_NONE { DUP; + CDR; + INT; + EQ; + IF { NONE (pair nat (map address nat)) } + { DUP; + CDR; + DIP { EMPTY_MAP (address) nat }; + PAIR; + SOME } } + { DIP { DUP }; + SWAP; + CDR; + DIP { DUP; + CAR }; + ADD; + DIP { DUP; + DIP { CDR }; + CAR }; + DIP { DROP }; + PAIR; + SOME }; + SWAP; + DUP; + DIP { CAR; + DIP { DIP { DUP; + CAR } }; + UPDATE; + DIP { DUP; + DIP { CDR }; + CAR }; + DIP { DROP }; + PAIR }; + DUP; + DIP { CDR; + INT; + DIP { DUP; + CDR; + CDR; + CDR }; + ADD; + ISNAT; + IF_NONE { PUSH string "Internal: Negative total supply"; + FAILWITH } + { }; + DIP { DUP; + CDR }; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DROP }; + SWAP; + PAIR; + SWAP; + PAIR; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DROP }; + SWAP; + PAIR }; + DROP; + NIL operation; + PAIR } + { DIP { DUP; + CDR; + CAR; + SENDER; + COMPARE; + EQ; + IF { } + { UNIT; + PUSH string "SenderIsNotAdmin"; + PAIR; + FAILWITH } }; + DIP { DUP }; + SWAP; + DIP { DUP }; + SWAP; + CAR; + DIP { CAR }; + GET; + IF_NONE { CDR; + PUSH nat 0; + SWAP; + PAIR; + PUSH string "NotEnoughBalance"; + PAIR; + FAILWITH } + { }; + DUP; + CAR; + DIP { DIP { DUP }; + SWAP }; + SWAP; + CDR; + SWAP; + SUB; + ISNAT; + IF_NONE { CAR; + DIP { DUP }; + SWAP; + CDR; + PAIR; + PUSH string "NotEnoughBalance"; + PAIR; + FAILWITH } + { }; + DIP { DUP; + DIP { CDR }; + CAR }; + DIP { DROP }; + PAIR; + DIP { DUP }; + SWAP; + DIP { DUP; + CAR; + INT; + EQ; + IF { DUP; + CDR; + SIZE; + INT; + EQ; + IF { DROP; + NONE (pair nat (map address nat)) } + { SOME } } + { SOME }; + SWAP; + CAR; + DIP { DIP { DUP; + CAR } }; + UPDATE; + DIP { DUP; + DIP { CDR }; + CAR }; + DIP { DROP }; + PAIR }; + DUP; + DIP { CDR; + NEG; + DIP { DUP; + CDR; + CDR; + CDR }; + ADD; + ISNAT; + IF_NONE { PUSH string "Internal: Negative total supply"; + FAILWITH } + { }; + DIP { DUP; + CDR }; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DROP }; + SWAP; + PAIR; + SWAP; + PAIR; + DIP { DUP; + DIP { CAR }; + CDR }; + DIP { DROP }; + SWAP; + PAIR }; + DROP; + NIL operation; + PAIR } } } } }; diff --git a/tests_python/contracts_011/mini_scenarios/generic_multisig.tz b/tests_python/contracts_011/mini_scenarios/generic_multisig.tz new file mode 100644 index 000000000000..2e78f1cea983 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/generic_multisig.tz @@ -0,0 +1,92 @@ +# Source: https://github.com/murbard/smart-contracts/blob/master/multisig/michelson/generic.tz +parameter (or (unit %default) + (pair %main + (pair :payload + (nat %counter) # counter, used to prevent replay attacks + (or :action # payload to sign, represents the requested action + (lambda %operation unit (list operation)) + (pair %change_keys # change the keys controlling the multisig + (nat %threshold) # new threshold + (list %keys key)))) # new list of keys + (list %sigs (option signature)))); # signatures + +storage (pair (nat %stored_counter) (pair (nat %threshold) (list %keys key))) ; + +code + { + UNPAIR ; + IF_LEFT + { # Default entry point: do nothing + # This entry point can be used to send tokens to this contract + DROP ; NIL operation ; PAIR } + { # Main entry point + # Assert no token was sent: + # to send tokens, the default entry point should be used + PUSH mutez 0 ; AMOUNT ; ASSERT_CMPEQ ; + SWAP ; DUP ; DIP { SWAP } ; + DIP + { + UNPAIR ; + # pair the payload with the current contract address, to ensure signatures + # can't be replayed accross different contracts if a key is reused. + DUP ; SELF ; ADDRESS ; CHAIN_ID ; PAIR ; PAIR ; + PACK ; # form the binary payload that we expect to be signed + DIP { UNPAIR @counter ; DIP { SWAP } } ; SWAP + } ; + + # Check that the counters match + UNPAIR @stored_counter; DIP { SWAP }; + ASSERT_CMPEQ ; + + # Compute the number of valid signatures + DIP { SWAP } ; UNPAIR @threshold @keys; + DIP + { + # Running count of valid signatures + PUSH @valid nat 0; SWAP ; + ITER + { + DIP { SWAP } ; SWAP ; + IF_CONS + { + IF_SOME + { SWAP ; + DIP + { + SWAP ; DIIP { DUUP } ; + # Checks signatures, fails if invalid + { DUUUP; DIP {CHECK_SIGNATURE}; SWAP; IF {DROP} {FAILWITH} }; + PUSH nat 1 ; ADD @valid } } + { SWAP ; DROP } + } + { + # There were fewer signatures in the list + # than keys. Not all signatures must be present, but + # they should be marked as absent using the option type. + FAIL + } ; + SWAP + } + } ; + # Assert that the threshold is less than or equal to the + # number of valid signatures. + ASSERT_CMPLE ; + # Assert no unchecked signature remains + IF_CONS {FAIL} {} ; + DROP ; + + # Increment counter and place in storage + DIP { UNPAIR ; PUSH nat 1 ; ADD @new_counter ; PAIR} ; + + # We have now handled the signature verification part, + # produce the operation requested by the signers. + IF_LEFT + { # Get operation + UNIT ; EXEC + } + { + # Change set of signatures + DIP { CAR } ; SWAP ; PAIR ; NIL operation + }; + PAIR } + } diff --git a/tests_python/contracts_011/mini_scenarios/groth16.tz b/tests_python/contracts_011/mini_scenarios/groth16.tz new file mode 100644 index 000000000000..66ff23a5e73b --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/groth16.tz @@ -0,0 +1,74 @@ +# The contract returns if the proof verifies, and fails otherwise. +# The verifying key, proof, and inputs are generated from +# ZoKrates, modified to use BLS12-381. +# The circuit proves knowledge of a square root of 113569. +storage unit; + +# The parameter is a pair consisting of: +# * A pair of Fr element inputs, x and y +# * A proof, consisting of +# * G1 points `a` and `c` +# * G2 point `b` +parameter (pair (pair (bls12_381_fr %input_x) (bls12_381_fr %input_y)) + (pair (pair (bls12_381_g1 %proof_a) (bls12_381_g2 %proof_b)) + (bls12_381_g1 %proof_c))); + +code + { + # Discard storage and unpair. Result stack should be + # input{x:y} : proof{a:b:c}. + CAR; UNPPAIPPAIIR; + + # Push the verifying key. Result stack should be + # input{x:y} + # : proof{a:b:c} + # : vk_{a:b:gamma:delta:gamma_{a:b:c}} + DIP 5 + { + PUSH @vk_gamma_c bls12_381_g1 0x063bd6e11e2fcaac1dd8cf68c6b1925a73c3c583e298ed37c41c3715115cf96358a42dbe85a0228cbfd8a6c8a8c54cd015b5ae2860d1cc47f84698d951f14d9448d03f04df2ca0ffe609a2067d6f1a892163a5e05e541279134cae52b1f23c6b; + + PUSH @vk_gamma_b bls12_381_g1 0x11f5b5db1da7f1f26217edcce2219d016003af6e5b4d1ca3ad0ff477e354717e658bf16beddc4f4fb76ce39d3327811e0601709dc7ed98c70463cfa1ba33f99851b52b51d1a042d7425bec6277287441c399973632445ce61e7fdd63a70f0f60; + + PUSH @vk_gamma_a bls12_381_g1 0x03535a322edd23c55b0ca025e54d450d95df49cc9ee873dcd500e8219f4771264bf159b3b105954d85c7bea8ffe1ea0400c767fe58989366c2837fba76f1b4f46644f19be8ad01e22d894b649e427e0d7e04677ee3919d982f0f96bb0a2f0c34; + + PUSH @vk_delta bls12_381_g2 0x10c6d5cdca84fc3c7f33061add256f48e0ab03a697832b338901898b650419eb6f334b28153fb73ad2ecd1cd2ac67053161e9f46cfbdaf7b1132a4654a55162850249650f9b873ac3113fa8c02ef1cd1df481480a4457f351d28f4da89d19fa405c3d77f686dc9a24d2681c9184bf2b091f62e6b24df651a3da8bd7067e14e7908fb02f8955b84af5081614cb5bc49b416d9edf914fc608c441b3f2eb8b6043736ddb9d4e4d62334a23b5625c14ef3e1a7e99258386310221b22d83a5eac035c; + + PUSH @vk_gamma bls12_381_g2 0x16dcbd28bff336c2649c7dd1d8391ac7ce6f7ef0124a9db7a4a485a124199eded7ce963c1c18aee1eca9994fe06f192c00e0fb653e1fc737d8d0e2f2f91424ca01f6e6e7c5c04f1c43db03a2900cf6b942aaed6ae77daea6200e094b78c38d770028d531a9d1a118ec23d5a39be7aa6dc28f778da1988856d2235c4a35e81fa48380f050d4baf7ebd7b5e058bf294da916afc34562f097c02a8fcbcf62a00de44f8ae6cfa7acb8ad254e3aeea8b2af12f65b7ee0f54855cb9bd432f3436f238f; + + PUSH @vk_b bls12_381_g2 0x0e9383f98df2c6e8b5b45f3876c3384596a0cdbc41349f83c4380bf463a050cdbd1d5057aa483a642e66486d1ed7362a1869e423c3877095e215c17282b11108601166f928043254bbce603bf86f4cec9f2e97e9660e98e4f5bce9b2b3bbacb40946b702ccfcc9a31e0bfc1543a2128edcc95807740a2310ae25eb47b935648e392c58dfae5b5e899d3b970d64e4e9e209741ea8bfedcfcc16b3fd890ff02c788ec0943feaaf01bbb354317acb85fcfd611133e4e563d53ca4e0f50e21cf2e7e; + + PUSH @vk_a bls12_381_g1 0x1040577c7d349e332735fc947c868c24a665f812f5dc1e7f60e65e2df80be2267a4b7341ed2287285fccd517acd96d910abba947235c364553aa6445f2f2b3a1a728225a330286ba5197ab87f0edc560d89fc7b623812f7d0d633341726e597a + }; + + # Compute vk_x as + # (vk_gamma_b * input_x) + (vk_gamma_c * input_y) + vk_gamma_a + # Result stack should be + # vk_x + # : input{x:y} + # : proof{a:b:c} + # : vk_{a:b:gamma:delta:gamma_{a:b:c}} + DUP; DUP 12; MUL; + DUP 3; DUP 14; MUL; + ADD; DUP 11; ADD @vk_x; + + # Push the list for the pairing check. The list should be + # [ (proof_a, proof_b); + # (-vk_x, vk_gamma); + # (-proof_c, vk_delta); + # (-vk_a, vk_b) ] + NIL (pair bls12_381_g1 bls12_381_g2); + DUP 9; DUP 9; NEG; PAIR; CONS; + DUP 11; DUP 8; NEG; PAIR; CONS; + DUP 10; DUP 3; NEG; PAIR; CONS; + DUP 6; DUP 6; PAIR; CONS; + + # Compute the pairing check and fail if it doesn't succeed + PAIRING_CHECK; ASSERT; + + # Drop the stack + DROP 13; + + # return no operations + UNIT; NIL operation; PAIR + + } diff --git a/tests_python/contracts_011/mini_scenarios/hardlimit.tz b/tests_python/contracts_011/mini_scenarios/hardlimit.tz new file mode 100644 index 000000000000..464062a52166 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/hardlimit.tz @@ -0,0 +1,5 @@ +parameter unit ; +storage int ; +code { # This contract stops accepting transactions after N incoming transactions + CDR ; DUP ; PUSH int 0 ; CMPLT; IF {PUSH int -1 ; ADD} {FAIL}; + NIL operation ; PAIR} ; diff --git a/tests_python/contracts_011/mini_scenarios/legacy_multisig.tz b/tests_python/contracts_011/mini_scenarios/legacy_multisig.tz new file mode 100644 index 000000000000..98ea6c603898 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/legacy_multisig.tz @@ -0,0 +1,78 @@ +parameter (pair + (pair :payload + (nat %counter) # counter, used to prevent replay attacks + (or :action # payload to sign, represents the requested action + (pair :transfer # transfer tokens + (mutez %amount) # amount to transfer + (contract %dest unit)) # destination to transfer to + (or + (option %delegate key_hash) # change the delegate to this address + (pair %change_keys # change the keys controlling the multisig + (nat %threshold) # new threshold + (list %keys key))))) # new list of keys + (list %sigs (option signature))); # signatures +storage (pair (nat %stored_counter) (pair (nat %threshold) (list %keys key))) ; +code + { + UNPAIR ; SWAP ; DUP ; DIP { SWAP } ; + DIP + { + UNPAIR ; + # pair the payload with the current contract address, to ensure signatures + # can't be replayed across different contracts if a key is reused. + DUP ; SELF ; ADDRESS ; CHAIN_ID ; PAIR ; PAIR ; + PACK ; # form the binary payload that we expect to be signed + DIP { UNPAIR @counter ; DIP { SWAP } } ; SWAP + } ; + # Check that the counters match + UNPAIR @stored_counter; DIP { SWAP }; + ASSERT_CMPEQ ; + # Compute the number of valid signatures + DIP { SWAP } ; UNPAIR @threshold @keys; + DIP + { + # Running count of valid signatures + PUSH @valid nat 0; SWAP ; + ITER + { + DIP { SWAP } ; SWAP ; + IF_CONS + { + IF_SOME + { SWAP ; + DIP + { + SWAP ; DIIP { DUUP } ; + # Checks signatures, fails if invalid + { DUUUP; DIP {CHECK_SIGNATURE}; SWAP; IF {DROP} {FAILWITH} }; + PUSH nat 1 ; ADD @valid } } + { SWAP ; DROP } + } + { + # There were fewer signatures in the list + # than keys. Not all signatures must be present, but + # they should be marked as absent using the option type. + FAIL + } ; + SWAP + } + } ; + # Assert that the threshold is less than or equal to the + # number of valid signatures. + ASSERT_CMPLE ; + DROP ; DROP ; + # Increment counter and place in storage + DIP { UNPAIR ; PUSH nat 1 ; ADD @new_counter ; PAIR} ; + # We have now handled the signature verification part, + # produce the operation requested by the signers. + NIL operation ; SWAP ; + IF_LEFT + { # Transfer tokens + UNPAIR ; UNIT ; TRANSFER_TOKENS ; CONS } + { IF_LEFT { + # Change delegate + SET_DELEGATE ; CONS } + { + # Change set of signatures + DIP { SWAP ; CAR } ; SWAP ; PAIR ; SWAP }} ; + PAIR } diff --git a/tests_python/contracts_011/mini_scenarios/lockup.tz b/tests_python/contracts_011/mini_scenarios/lockup.tz new file mode 100644 index 000000000000..a8ff43aa0f85 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/lockup.tz @@ -0,0 +1,19 @@ +parameter unit; +storage (pair timestamp (pair mutez address)); +code { CDR; # Ignore the parameter + DUP; # Duplicate the storage + CAR; # Get the timestamp + NOW; # Push the current timestamp + CMPLT; # Compare to the current time + IF {FAIL} {}; # Fail if it is too soon + DUP; # Duplicate the storage value + # this must be on the bottom of the stack for us to call transfer tokens + CDR; # Ignore the timestamp, focussing in on the transfer data + DUP; # Duplicate the transfer information + CAR; # Get the amount of the transfer on top of the stack + DIP{CDR}; # Put the contract underneath it + DIP { CONTRACT unit ; ASSERT_SOME } ; + UNIT; # Put the contract's argument type on top of the stack + TRANSFER_TOKENS; # Emit the transfer + NIL operation; SWAP; CONS;# Make a singleton list of internal operations + PAIR} # Pair up to meet the calling convention diff --git a/tests_python/contracts_011/mini_scenarios/lqt_fa12.mligo.tz b/tests_python/contracts_011/mini_scenarios/lqt_fa12.mligo.tz new file mode 100644 index 000000000000..7f606cea3243 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/lqt_fa12.mligo.tz @@ -0,0 +1,328 @@ +# FA1.2 implementation used for Liquidity Baking + +{ parameter + (or (or (or (pair %approve (address %spender) (nat %value)) + (pair %getAllowance + (pair %request (address %owner) (address %spender)) + (contract %callback nat))) + (or (pair %getBalance (address %owner) (contract %callback nat)) + (pair %getTotalSupply (unit %request) (contract %callback nat)))) + (or (pair %mintOrBurn (int %quantity) (address %target)) + (pair %transfer (address %from) (pair (address %to) (nat %value))))) ; + storage + (pair (big_map %tokens address nat) + (pair (big_map %allowances (pair (address %owner) (address %spender)) nat) + (pair (address %admin) (nat %total_supply)))) ; + code { DUP ; + CDR ; + PUSH mutez 0 ; + AMOUNT ; + COMPARE ; + NEQ ; + IF { PUSH string "DontSendTez" ; FAILWITH } {} ; + SWAP ; + CAR ; + IF_LEFT + { IF_LEFT + { IF_LEFT + { SWAP ; + DUP ; + DUG 2 ; + CDR ; + CAR ; + SWAP ; + DUP ; + DUG 2 ; + CAR ; + SENDER ; + PAIR ; + PUSH nat 0 ; + DIG 3 ; + DUP ; + DUG 4 ; + CDR ; + COMPARE ; + GT ; + PUSH nat 0 ; + DIG 3 ; + DUP ; + DUG 4 ; + DIG 3 ; + DUP ; + DUG 4 ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + COMPARE ; + GT ; + AND ; + IF { PUSH string "UnsafeAllowanceChange" ; FAILWITH } {} ; + DIG 3 ; + DUP ; + DUG 4 ; + CDR ; + CDR ; + DIG 2 ; + DIG 3 ; + CDR ; + PUSH nat 0 ; + SWAP ; + DUP ; + DUG 2 ; + COMPARE ; + EQ ; + IF { DROP ; NONE nat } { SOME } ; + DIG 3 ; + UPDATE ; + PAIR ; + SWAP ; + CAR ; + PAIR ; + NIL operation ; + PAIR } + { SWAP ; + DUP ; + DIG 2 ; + NIL operation ; + SWAP ; + DUP ; + DUG 2 ; + CDR ; + PUSH mutez 0 ; + DIG 4 ; + CDR ; + CAR ; + DIG 4 ; + CAR ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + TRANSFER_TOKENS ; + CONS ; + PAIR } } + { IF_LEFT + { SWAP ; + DUP ; + DIG 2 ; + NIL operation ; + SWAP ; + DUP ; + DUG 2 ; + CDR ; + PUSH mutez 0 ; + DIG 4 ; + CAR ; + DIG 4 ; + CAR ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + TRANSFER_TOKENS ; + CONS ; + PAIR } + { SWAP ; + DUP ; + DIG 2 ; + NIL operation ; + SWAP ; + CDR ; + PUSH mutez 0 ; + DIG 3 ; + CDR ; + CDR ; + CDR ; + TRANSFER_TOKENS ; + CONS ; + PAIR } } } + { IF_LEFT + { SWAP ; + DUP ; + DUG 2 ; + CDR ; + CDR ; + CAR ; + SENDER ; + COMPARE ; + NEQ ; + IF { PUSH string "OnlyAdmin" ; FAILWITH } {} ; + DUP ; + CAR ; + DIG 2 ; + DUP ; + DUG 3 ; + CAR ; + DIG 2 ; + DUP ; + DUG 3 ; + CDR ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + ADD ; + ISNAT ; + IF_NONE + { PUSH string "Cannot burn more than the target's balance." ; FAILWITH } + {} ; + SWAP ; + DUP ; + DUG 2 ; + CAR ; + DIG 3 ; + DUP ; + DUG 4 ; + CDR ; + CDR ; + CDR ; + ADD ; + ABS ; + DIG 3 ; + DUP ; + DUG 4 ; + CDR ; + DIG 4 ; + CAR ; + PUSH nat 0 ; + DIG 4 ; + DUP ; + DUG 5 ; + COMPARE ; + EQ ; + IF { DIG 3 ; DROP ; NONE nat } { DIG 3 ; SOME } ; + DIG 4 ; + CDR ; + UPDATE ; + PAIR ; + DUP ; + DUG 2 ; + CDR ; + CDR ; + CAR ; + PAIR ; + SWAP ; + DUP ; + DUG 2 ; + CDR ; + CAR ; + PAIR ; + SWAP ; + CAR ; + PAIR ; + NIL operation ; + PAIR } + { SWAP ; + DUP ; + DUG 2 ; + CDR ; + CAR ; + DIG 2 ; + DUP ; + DUG 3 ; + CAR ; + DIG 2 ; + DUP ; + DUG 3 ; + CAR ; + SENDER ; + COMPARE ; + EQ ; + IF { SWAP } + { SENDER ; + DIG 3 ; + DUP ; + DUG 4 ; + CAR ; + PAIR ; + DIG 3 ; + DUP ; + DUG 4 ; + CDR ; + CDR ; + DIG 3 ; + DUP ; + DUG 4 ; + DIG 2 ; + DUP ; + DUG 3 ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + SUB ; + ISNAT ; + IF_NONE { PUSH string "NotEnoughAllowance" ; FAILWITH } {} ; + DIG 3 ; + PUSH nat 0 ; + DIG 2 ; + DUP ; + DUG 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE nat } { SWAP ; SOME } ; + DIG 2 ; + UPDATE } ; + DIG 2 ; + DUP ; + DUG 3 ; + CDR ; + CDR ; + DIG 2 ; + DUP ; + DUG 3 ; + DIG 4 ; + DUP ; + DUG 5 ; + CAR ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + SUB ; + ISNAT ; + IF_NONE { PUSH string "NotEnoughBalance" ; FAILWITH } {} ; + DIG 2 ; + PUSH nat 0 ; + DIG 2 ; + DUP ; + DUG 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE nat } { SWAP ; SOME } ; + DIG 3 ; + DUP ; + DUG 4 ; + CAR ; + UPDATE ; + DIG 2 ; + DUP ; + DUG 3 ; + CDR ; + CDR ; + SWAP ; + DUP ; + DUG 2 ; + DIG 4 ; + DUP ; + DUG 5 ; + CDR ; + CAR ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + ADD ; + SWAP ; + PUSH nat 0 ; + DIG 2 ; + DUP ; + DUG 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE nat } { SWAP ; SOME } ; + DIG 3 ; + CDR ; + CAR ; + UPDATE ; + DIG 2 ; + CDR ; + SWAP ; + PAIR ; + DUP ; + CDR ; + CDR ; + DIG 2 ; + PAIR ; + SWAP ; + CAR ; + PAIR ; + NIL operation ; + PAIR } } } } diff --git a/tests_python/contracts_011/mini_scenarios/multiple_en2.tz b/tests_python/contracts_011/mini_scenarios/multiple_en2.tz new file mode 100644 index 000000000000..a1acafd48706 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/multiple_en2.tz @@ -0,0 +1,77 @@ +{ parameter unit ; + storage (option address) ; + code { SENDER ; + SELF ; + ADDRESS ; + { COMPARE ; + EQ ; + IF { CDR ; + { IF_NONE { { UNIT ; FAILWITH } } {} } ; + DIP { NIL operation } ; + DUP ; + CONTRACT %add unit ; + { IF_NONE {} { { UNIT ; FAILWITH } } } ; + DUP ; + CONTRACT %fact nat ; + { IF_NONE {} { { UNIT ; FAILWITH } } } ; + DUP ; + CONTRACT %add nat ; + { IF_NONE { { UNIT ; FAILWITH } } {} } ; + PUSH mutez 0 ; + PUSH nat 12 ; + TRANSFER_TOKENS ; + SWAP ; + DIP { CONS } ; + DUP ; + CONTRACT unit ; + { IF_NONE { { UNIT ; FAILWITH } } {} } ; + PUSH mutez 0 ; + PUSH unit Unit ; + TRANSFER_TOKENS ; + SWAP ; + DIP { CONS } ; + DUP ; + CONTRACT %sub nat ; + { IF_NONE { { UNIT ; FAILWITH } } {} } ; + PUSH mutez 0 ; + PUSH nat 3 ; + TRANSFER_TOKENS ; + SWAP ; + DIP { CONS } ; + DUP ; + CONTRACT %add nat ; + { IF_NONE { { UNIT ; FAILWITH } } {} } ; + PUSH mutez 0 ; + PUSH nat 5 ; + TRANSFER_TOKENS ; + SWAP ; + DIP { CONS } ; + DROP ; + DIP { NONE address } ; + PAIR } + { CAR ; + DUP ; + DIP { DIP { PUSH int 0 ; PUSH mutez 0 ; NONE key_hash } ; + DROP ; + CREATE_CONTRACT + { parameter (or (or (nat %add) (nat %sub)) (unit %default)) ; + storage int ; + code { AMOUNT ; + PUSH mutez 0 ; + { { COMPARE ; EQ } ; IF {} { { UNIT ; FAILWITH } } } ; + { { DUP ; CAR ; DIP { CDR } } } ; + IF_LEFT + { IF_LEFT { ADD } { SWAP ; SUB } } + { DROP ; DROP ; PUSH int 0 } ; + NIL operation ; + PAIR } } } ; + DIP { SELF ; PUSH mutez 0 } ; + TRANSFER_TOKENS ; + NIL operation ; + SWAP ; + CONS ; + SWAP ; + CONS ; + DIP { SOME } ; + PAIR } } + } } diff --git a/tests_python/contracts_011/mini_scenarios/multiple_entrypoints_counter.tz b/tests_python/contracts_011/mini_scenarios/multiple_entrypoints_counter.tz new file mode 100644 index 000000000000..740190697171 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/multiple_entrypoints_counter.tz @@ -0,0 +1,29 @@ +{ parameter unit ; + storage (option address) ; + code { SENDER ; SELF ; ADDRESS ; + IFCMPEQ + { CDR ; ASSERT_SOME ; + DIP { NIL operation } ; + DUP ; CONTRACT %add unit ; ASSERT_NONE ; + DUP ; CONTRACT %fact nat ; ASSERT_NONE ; + DUP ; CONTRACT %add nat ; ASSERT_SOME ; PUSH mutez 0 ; PUSH nat 12 ; TRANSFER_TOKENS ; SWAP ; DIP { CONS } ; + DUP ; CONTRACT unit ; ASSERT_SOME ; PUSH mutez 0 ; PUSH unit Unit ; TRANSFER_TOKENS ; SWAP ; DIP { CONS } ; + DUP ; CONTRACT %sub nat ; ASSERT_SOME ; PUSH mutez 0 ; PUSH nat 3 ; TRANSFER_TOKENS ; SWAP ; DIP { CONS } ; + DUP ; CONTRACT %add nat ; ASSERT_SOME ; PUSH mutez 0 ; PUSH nat 5 ; TRANSFER_TOKENS ; SWAP ; DIP { CONS } ; + DROP ; DIP { NONE address } ; PAIR } + { CAR ; DUP ; + DIP + { DIP { PUSH int 0 ; PUSH mutez 0 ; NONE key_hash } ; + DROP ; + CREATE_CONTRACT + { parameter (or (or (nat %add) (nat %sub)) (unit %default)) ; + storage int ; + code { AMOUNT ; PUSH mutez 0 ; ASSERT_CMPEQ ; + UNPAIR ; + IF_LEFT + { IF_LEFT { ADD } { SWAP ; SUB } } + { DROP ; DROP ; PUSH int 0 } ; + NIL operation ; PAIR } } } ; + DIP { SELF ; PUSH mutez 0 } ; TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS ; SWAP ; CONS ; + DIP { SOME } ; PAIR } } } \ No newline at end of file diff --git a/tests_python/contracts_011/mini_scenarios/parameterized_multisig.tz b/tests_python/contracts_011/mini_scenarios/parameterized_multisig.tz new file mode 100644 index 000000000000..16f785ae0a25 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/parameterized_multisig.tz @@ -0,0 +1,24 @@ +storage (pair bool (pair (map nat (pair bool bool)) (pair key key))); +parameter (or nat (pair signature nat)); +code { DUP; CAR; DIP{CDDR}; # Stack tangling + IF_LEFT { DIP{DUP; CAR}; GET; # Get the value stored for that index + IF_NONE { PUSH bool False} # If not referenced, reject + { DUP; CAR; DIP{CDR}; AND}; + PAIR} + { DUP; CAR; DIP{CDR; DUP; PACK ; BLAKE2B}; PAIR; SWAP; # Create the signature pair + DIP{ DIP{DUP; CDR; DIP{CAR}; DUP}; + SWAP; CAR; DIP{DUP; UNPAIR}; CHECK_SIGNATURE }; # Check the first signature + SWAP; + # If the signature typechecked, get and update the first element of the pair + IF { DIP{DROP; SWAP; DUP}; DUP; + DIP{ GET; IF_NONE{PUSH (pair bool bool) (Pair False False)} {}; + CDR; PUSH bool True; PAIR; SOME }} + # Check the second signature + { DIP{DIP{DUP; CDR}; SWAP; DIP {UNPAIR}; CHECK_SIGNATURE}; SWAP; + IF { DUP; DIP{DIP{SWAP; DUP}; GET}; SWAP; + IF_NONE {PUSH (pair bool bool) (Pair False False)} {}; + CAR; PUSH bool True; SWAP; PAIR; SOME; SWAP} + {FAIL}}; + # Update the stored value and finish off + UPDATE; PAIR; PUSH bool False; PAIR}; + NIL operation; PAIR } diff --git a/tests_python/contracts_011/mini_scenarios/replay.tz b/tests_python/contracts_011/mini_scenarios/replay.tz new file mode 100644 index 000000000000..e03ac4ab2113 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/replay.tz @@ -0,0 +1,8 @@ +# This contract always fail because it tries to execute twice the same operation +parameter unit ; +storage unit ; +code { CDR ; NIL operation ; + SOURCE ; CONTRACT unit ; ASSERT_SOME ; + PUSH mutez 1 ; UNIT ; TRANSFER_TOKENS ; + DUP ; DIP { CONS } ; CONS ; + PAIR } diff --git a/tests_python/contracts_011/mini_scenarios/reveal_signed_preimage.tz b/tests_python/contracts_011/mini_scenarios/reveal_signed_preimage.tz new file mode 100644 index 000000000000..1a7e97eb8a68 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/reveal_signed_preimage.tz @@ -0,0 +1,13 @@ +parameter (pair bytes signature) ; +storage (pair bytes key) ; +code { + #check that sha256(param.bytes) == storage.bytes + DUP ; UNPAIR ; CAR; SHA256; DIP { CAR } ; ASSERT_CMPEQ ; + + # check that the sig is a valid signature of the preimage + DUP ; UNPAIR ; SWAP ; DIP { UNPAIR ; SWAP } ; CDR ; CHECK_SIGNATURE ; ASSERT ; + + # send all our tokens to the implicit account corresponding to the stored public key + CDR ; DUP ; CDR ; HASH_KEY ; IMPLICIT_ACCOUNT ; + BALANCE ; UNIT ; TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS ; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/mini_scenarios/self_address_receiver.tz b/tests_python/contracts_011/mini_scenarios/self_address_receiver.tz new file mode 100644 index 000000000000..6ebda8daad9e --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/self_address_receiver.tz @@ -0,0 +1,12 @@ +# See self_address_sender.tz +parameter (lambda unit address); +storage unit; +code { + UNPAIR; + UNIT; + EXEC; + SELF_ADDRESS; + ASSERT_CMPEQ; + NIL operation; + PAIR + } diff --git a/tests_python/contracts_011/mini_scenarios/self_address_sender.tz b/tests_python/contracts_011/mini_scenarios/self_address_sender.tz new file mode 100644 index 000000000000..b0f74073c2ff --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/self_address_sender.tz @@ -0,0 +1,17 @@ +# This tests that the SELF_ADDRESS inside a lambda returns the address +# of the contract executing the lambda (not the contract defining it). +# To do so, two contracts called the sender and the receiver are used. +# The sender (this contract) sends the lambda { DROP; SELF_ADDRESS } +# to the receiver (see self_address_receiver.tz) who checks that the +# returned value is the same as its SELF_ADDRESS. +parameter (contract (lambda unit address)); +storage unit; +code { + CAR; + BALANCE; + LAMBDA unit address { DROP; SELF_ADDRESS }; + TRANSFER_TOKENS; + DIP { UNIT; NIL operation }; + CONS; + PAIR + } diff --git a/tests_python/contracts_011/mini_scenarios/ticket_builder_fungible.tz b/tests_python/contracts_011/mini_scenarios/ticket_builder_fungible.tz new file mode 100644 index 000000000000..674ae800771d --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/ticket_builder_fungible.tz @@ -0,0 +1,40 @@ +## A simple fungible token contract implemented using tickets of type +## [ticket unit]. + +## To store and transfer the tokens see ticket_wallet_fungible.tz + +## For non-fungible tokens, see ticket_builder_non_fungible.tz + +parameter (or (ticket %burn unit) (pair %mint (contract %destination (ticket unit)) (nat %amount))); +storage address; +code + { + AMOUNT; PUSH mutez 0; ASSERT_CMPEQ; + + UNPAIR; + IF_LEFT + { + # Burn entrypoint + + # Check that the ticket is ticketed by ourselves + READ_TICKET; CAR; SELF_ADDRESS; ASSERT_CMPEQ; + + # Drop the ticket + DROP; + + # Finish + NIL operation + } + { + # Mint entrypoint + + # Authenticate SENDER + DUP @manager 2; SENDER; ASSERT_CMPEQ; + + UNPAIR; + SWAP; UNIT; TICKET; + PUSH mutez 0; SWAP; TRANSFER_TOKENS; + NIL operation; SWAP; CONS + }; + PAIR + } diff --git a/tests_python/contracts_011/mini_scenarios/ticket_builder_non_fungible.tz b/tests_python/contracts_011/mini_scenarios/ticket_builder_non_fungible.tz new file mode 100644 index 000000000000..ae669d17ad60 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/ticket_builder_non_fungible.tz @@ -0,0 +1,47 @@ +## A simple non-fungible token contract implemented using tickets of +## type [ticket nat] with amounts of 1. + +## To store and transfer the tokens see ticket_wallet_non_fungible.tz + +## For fungible tokens, see ticket_builder_fungible.tz + +parameter (or (ticket %burn nat) (contract %mint_destination (ticket nat))); +storage (pair (address %manager) (nat %counter)); +code + { + AMOUNT; PUSH mutez 0; ASSERT_CMPEQ; + + UNPAIR 3; + IF_LEFT + { + # Burn entrypoint + + # Check that the ticket is ticketed by ourselves + READ_TICKET; CAR; SELF_ADDRESS; ASSERT_CMPEQ; + + # Drop the ticket + DROP; + + # Finish + NIL operation + } + { + # Mint entrypoint + + # Authenticate SENDER + DUP @manager 2; SENDER; ASSERT_CMPEQ; + + # Mint the token + PUSH @amount nat 1; + DUP @counter 4; + TICKET; + + # Send it + PUSH mutez 0; SWAP; TRANSFER_TOKENS; + NIL operation; SWAP; CONS; + + # Increment counter + DIP 2 {PUSH nat 1; ADD}; + }; + PAIR 3 + } diff --git a/tests_python/contracts_011/mini_scenarios/ticket_wallet_fungible.tz b/tests_python/contracts_011/mini_scenarios/ticket_wallet_fungible.tz new file mode 100644 index 000000000000..d04180ddb899 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/ticket_wallet_fungible.tz @@ -0,0 +1,88 @@ +## A simple wallet for fungible tokens implemented using tickets of +## type [ticket unit]. + +## For actually minting or burning the tokens, see ticket_builder_fungible.tz + +## For non-fungible tokens, see ticket_wallet_non_fungible.tz + +parameter (or (ticket %receive unit) (pair %send (contract %destination (ticket unit)) (nat %amount) (address %ticketer))); +storage (pair (address %manager) (big_map %tickets address (ticket unit))); +code + { + AMOUNT; PUSH mutez 0; ASSERT_CMPEQ; + + UNPAIR 3; + IF_LEFT + { + # Receive entrypoint + + # Get the ticketer + READ_TICKET; CAR @ticketer; DUP; + + # Extract the associated ticket, if any, from the stored big map + DIG 4; + NONE (ticket unit); + DIG 2; + GET_AND_UPDATE; + + # Join it with the parameter + IF_SOME + { + DIG 3; + PAIR; + JOIN_TICKETS; + ASSERT_SOME + } + { DIG 2 }; + SOME; + DIG 2; + GET_AND_UPDATE; + ASSERT_NONE; + SWAP; + PAIR; + NIL operation + } + { + # Send entrypoints + + # Authenticate SENDER + DUP @manager 2; SENDER; ASSERT_CMPEQ; + + UNPAIR 3; + + # Get the ticket associated to the requested ticketer + DIG 4; + NONE (ticket unit); + DUP @ticketer 5; + GET_AND_UPDATE; + ASSERT_SOME; + + # Substract the requested amount + READ_TICKET; + GET @total_amount 4; + DUP @amount 5; + SWAP; SUB; ISNAT; ASSERT_SOME @remaining_amount; + + # Split the ticket + DIG 4; PAIR; SWAP; SPLIT_TICKET; + ASSERT_SOME; UNPAIR @to_send @to_keep; + + # Store the ticket to keep + DUG 5; + SOME; + DIG 3; + GET_AND_UPDATE; + ASSERT_NONE; + DIG 2; PAIR; + + # Send the ticket + SWAP; + PUSH mutez 0; + DIG 3; + TRANSFER_TOKENS; + NIL operation; + SWAP; + CONS; + }; + PAIR + } diff --git a/tests_python/contracts_011/mini_scenarios/ticket_wallet_non_fungible.tz b/tests_python/contracts_011/mini_scenarios/ticket_wallet_non_fungible.tz new file mode 100644 index 000000000000..ba0170ae830e --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/ticket_wallet_non_fungible.tz @@ -0,0 +1,61 @@ +## A simple wallet for non-fungible tokens implemented using tickets +## of type [ticket nat]. + +## For each nat [n], the ticketer is assumed to produce at most one +## ticket containing [n] and to always use amounts of exactly one. + +## For fungible tokens, see ticket_wallet_fungible.tz + +parameter (or (ticket %receive nat) (pair %send (contract %destination (ticket nat)) (address %ticketer) (nat %id))); +storage (pair (address %manager) (big_map %tickets (pair address nat) (ticket nat))); +code + { + AMOUNT; PUSH mutez 0; ASSERT_CMPEQ; + + UNPAIR 3; + IF_LEFT + { + # Receive entrypoint + + # Get the ticketer and id + READ_TICKET; CAST (pair (address %ticketer) (nat %id) (nat %amount)); + UNPAIR 3; + DIG 2; PUSH nat 1; ASSERT_CMPEQ; # This checks that the amount is 1 + PAIR; + + # Extract the associated ticket, if any, from the stored big map + DIP {SOME; DIP {SWAP}}; + GET_AND_UPDATE; + ASSERT_NONE; + + SWAP; + PAIR; + NIL operation + } + { + # Send entrypoints + + # Authenticate SENDER + DUP @manager 2; SENDER; ASSERT_CMPEQ; + + UNPAIR; + + # Get the ticket associated to the requested ticketer and id + DIG 3; + NONE (ticket nat); + DIG 3; + GET_AND_UPDATE; + ASSERT_SOME; + + SWAP; DIG 3; PAIR; DUG 2; + + # Send the ticket + PUSH mutez 0; + SWAP; + TRANSFER_TOKENS; + NIL operation; + SWAP; + CONS; + }; + PAIR + } diff --git a/tests_python/contracts_011/mini_scenarios/tzip4_view.tz b/tests_python/contracts_011/mini_scenarios/tzip4_view.tz new file mode 100644 index 000000000000..aee5f1fa15f3 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/tzip4_view.tz @@ -0,0 +1,7 @@ +parameter (or (pair %view_const unit (contract nat)) (pair %view_add (pair int int) (contract int))); +storage unit; +code { + CAR; + IF_LEFT {CDR; AMOUNT; PUSH nat 5; TRANSFER_TOKENS; NIL operation; SWAP; CONS; UNIT; SWAP; PAIR} + {UNPAIR; UNPAIR; ADD; AMOUNT; SWAP; TRANSFER_TOKENS; NIL operation; SWAP; CONS; UNIT; SWAP; PAIR}; + } diff --git a/tests_python/contracts_011/mini_scenarios/vote_for_delegate.tz b/tests_python/contracts_011/mini_scenarios/vote_for_delegate.tz new file mode 100644 index 000000000000..1155c073f588 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/vote_for_delegate.tz @@ -0,0 +1,30 @@ +parameter (option key_hash) ; +storage (pair + (pair %mgr1 (address %addr) (option %key key_hash)) + (pair %mgr2 (address %addr) (option %key key_hash))) ; +code { # Update the storage + DUP ; CDAAR %addr @%; SENDER ; PAIR %@ %@; UNPAIR; + IFCMPEQ + { UNPAIR ; SWAP ; SET_CADR %key @changed_mgr1_key } + { DUP ; CDDAR ; SENDER ; + IFCMPEQ + { UNPAIR ; SWAP ; SET_CDDR %key } + { FAIL } } ; + # Now compare the proposals + DUP ; CADR ; + DIP { DUP ; CDDR } ; + IF_NONE + { IF_NONE + { NONE key_hash ; + SET_DELEGATE ; NIL operation ; SWAP ; CONS } + { DROP ; NIL operation } } + { SWAP ; + IF_SOME + { DIP { DUP } ; + IFCMPEQ + { SOME ; + SET_DELEGATE ; NIL operation ; SWAP ; CONS } + { DROP ; + NIL operation }} + { DROP ; NIL operation }} ; + PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/mini_scenarios/weather_insurance.tz b/tests_python/contracts_011/mini_scenarios/weather_insurance.tz new file mode 100644 index 000000000000..e7e99e018335 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/weather_insurance.tz @@ -0,0 +1,19 @@ +parameter (pair (signature %signed_weather_data) (nat :rain %actual_level)); +# (pair (under_key over_key) (pair weather_service_key (pair rain_level days_in_future))) +storage (pair (pair (address %under_key) + (address %over_key)) + (pair (nat :rain %rain_level) (key %weather_service_key))); +code { DUP; DUP; + CAR; MAP_CDR{PACK ; BLAKE2B}; + SWAP; CDDDR %weather_service_key; + DIP {UNPAIR} ; CHECK_SIGNATURE @sigok; # Check if the data has been correctly signed + ASSERT; # If signature is not correct, end the execution + DUP; DUP; DUP; DIIIP{CDR %storage}; # Place storage type on bottom of stack + DIIP{CDAR}; # Place contracts below numbers + DIP{CADR %actual_level}; # Get actual rain + CDDAR %rain_level; # Get rain threshold + CMPLT; IF {CAR %under_key} {CDR %over_key}; # Select contract to receive tokens + CONTRACT unit ; ASSERT_SOME ; + BALANCE; UNIT ; TRANSFER_TOKENS @trans.op; # Setup and execute transfer + NIL operation ; SWAP ; CONS ; + PAIR }; diff --git a/tests_python/contracts_011/mini_scenarios/xcat.tz b/tests_python/contracts_011/mini_scenarios/xcat.tz new file mode 100644 index 000000000000..83e6c7ac1d50 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/xcat.tz @@ -0,0 +1,48 @@ +parameter (bytes); +storage (unit); +code { + # Extract parameter from initial stack. + CAR @preimage; + DIP { + # Push contract constants to the stack. + # + # There's a temptation to use @storage to parametrize + # a contract but, in general, there's no reason to encumber + # @storage with immutable values. + PUSH @from key_hash "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"; #changeme + IMPLICIT_ACCOUNT ; + PUSH @to key_hash "tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN"; #changeme + IMPLICIT_ACCOUNT ; + PUSH @target_hash bytes 0x123456; #changeme + PUSH @deadline timestamp "2018-08-08 00:00:00Z"; #changeme + }; + # Test if the deadline has passed. + SWAP; NOW; + IFCMPLT + # In case the deadline did pass: + { + # Ignore parameter, just transfer xtz balance back to @from + DROP; DROP; DROP; BALANCE; UNIT; TRANSFER_TOKENS; + } + # In case the deadline hasn't passed yet: + { + # Test length of parameter. + DUP; SIZE; + PUSH @max_length nat 32; + IFCMPLT + { PUSH string "preimage too long"; FAILWITH; } + { + # Test if it's a preimage of @target_hash. + SHA256 @candidate_hash; + IFCMPNEQ + { PUSH string "invalid preimage"; FAILWITH; } + { + # Transfer xtz balance to @to. + BALANCE; UNIT; TRANSFER_TOKENS; DIP { DROP }; + }; + }; + }; + # Transform single operation into a list. + NIL operation; SWAP; CONS; + UNIT; SWAP; PAIR + } diff --git a/tests_python/contracts_011/mini_scenarios/xcat_dapp.tz b/tests_python/contracts_011/mini_scenarios/xcat_dapp.tz new file mode 100644 index 000000000000..86ca62c5ac50 --- /dev/null +++ b/tests_python/contracts_011/mini_scenarios/xcat_dapp.tz @@ -0,0 +1,79 @@ +parameter (or + # First possible action is funding, to create an xcat + (pair %fund + (address %dest) + (pair %settings (bytes %target_hash) (timestamp %deadline))) + + # Other possible action is to claim the tokens (or ask a refund) + (or %claim_refund + (bytes %preimage_claim) + (bytes %refund_hash))); + +storage (pair + (big_map + bytes # The target hash is used as a key + (pair + # We store in %from the person who funded the xcat + (pair %recipients (address %from) (address %dest)) + (pair %settings (mutez %amount) (timestamp %deadline))) + ) + unit); + +code { + NIL @operations operation; SWAP; + UNPAPAIR @% @% @%; DIP {DUP}; + IF_LEFT # Let's fund a new xcat! + { + # Unpack the parameters + UNPAIR @% @%; + # Assert that the destination address is of type unit. + # This costs a bit more gas but limits foot-shooting. + DUP; CONTRACT @dest unit; ASSERT_SOME; DROP; + SWAP; UNPAIR @% @%; + DIP + { + AMOUNT @amount; + SENDER; + DUP; CONTRACT @from unit; ASSERT_SOME; DROP; + DIP { PAIR; SWAP; }; PAIR; PAIR; SOME @xcat; + SWAP; + }; + DUP; DIP { MEM; NOT; ASSERT }; # Assert that this target hash isn't already in the map + UPDATE; PAIR @new_storage; SWAP; PAIR; + } + { + # Let's process a claim or a refund + IF_LEFT + { # It's a claim! + DUP; SIZE; PUSH nat 32; ASSERT_CMPGE; + SHA256 @hash; DUP; DIP {SWAP}; + DIIP { + GET; ASSERT_SOME; + # Check deadline and prepare transaction. + DUP; CADR @%; CONTRACT @dest unit; ASSERT_SOME; + SWAP; CDR @%; + UNPAIR @% @%; SWAP; + # The deadline must not have passed + NOW; ASSERT_CMPLT; + # prepare transaction + UNIT; TRANSFER_TOKENS; + }; + } + { # It's a refund! + DUP; + DIP + { + GET; ASSERT_SOME; + DUP; CAAR @%; CONTRACT @from unit; ASSERT_SOME; SWAP; CDR; + UNPAIR @% @%; SWAP; + # The deadline must not HAVE passed + NOW; ASSERT_CMPGE; + UNIT; TRANSFER_TOKENS; SWAP; + }; + }; + # Clear the big map + NONE @none (pair (pair address address) (pair mutez timestamp)); + SWAP; UPDATE @cleared_map; SWAP; DIP { PAIR; SWAP }; + CONS; PAIR; + } + } \ No newline at end of file diff --git a/tests_python/contracts_011/non_regression/bug_262.tz b/tests_python/contracts_011/non_regression/bug_262.tz new file mode 100644 index 000000000000..63475c5ac185 --- /dev/null +++ b/tests_python/contracts_011/non_regression/bug_262.tz @@ -0,0 +1,5 @@ +{ parameter unit ; + storage unit ; + code { DROP ; + LAMBDA unit unit {} ; UNIT ; EXEC ; + NIL operation ; PAIR } } \ No newline at end of file diff --git a/tests_python/contracts_011/non_regression/pairk_annot.tz b/tests_python/contracts_011/non_regression/pairk_annot.tz new file mode 100644 index 000000000000..8b0cf242bd9c --- /dev/null +++ b/tests_python/contracts_011/non_regression/pairk_annot.tz @@ -0,0 +1,7 @@ +# Test for old PAIR k annotation handling bug +parameter unit; +storage unit; +code { SENDER; SOURCE; PAIR 2; + SOURCE; SENDER; PAIR 2; + COMPARE; DROP; + CDR; NIL operation; PAIR } diff --git a/tests_python/contracts_011/opcodes/abs.tz b/tests_python/contracts_011/opcodes/abs.tz new file mode 100644 index 000000000000..d03d0883fe73 --- /dev/null +++ b/tests_python/contracts_011/opcodes/abs.tz @@ -0,0 +1,5 @@ +parameter nat; +storage unit; +code { CAR; + DUP; NEG; ABS; COMPARE; ASSERT_EQ; + UNIT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/add.tz b/tests_python/contracts_011/opcodes/add.tz new file mode 100644 index 000000000000..cbefea08a7a4 --- /dev/null +++ b/tests_python/contracts_011/opcodes/add.tz @@ -0,0 +1,25 @@ +parameter unit; +storage unit; +code + { + CAR; + + PUSH int 2; PUSH int 2; ADD; PUSH int 4; ASSERT_CMPEQ; + PUSH int 2; PUSH int 2; ADD; PUSH int 4; ASSERT_CMPEQ; + PUSH int 2; PUSH nat 2; ADD; PUSH int 4; ASSERT_CMPEQ; + PUSH nat 2; PUSH int 2; ADD; PUSH int 4; ASSERT_CMPEQ; + PUSH nat 2; PUSH nat 2; ADD; PUSH nat 4; ASSERT_CMPEQ; + + # Offset a timestamp by 60 seconds + PUSH int 60; PUSH timestamp "2019-09-09T12:08:37Z"; ADD; + PUSH timestamp "2019-09-09T12:09:37Z"; ASSERT_CMPEQ; + + PUSH timestamp "2019-09-09T12:08:37Z"; PUSH int 60; ADD; + PUSH timestamp "2019-09-09T12:09:37Z"; ASSERT_CMPEQ; + + PUSH mutez 1000; PUSH mutez 1000; ADD; + PUSH mutez 2000; ASSERT_CMPEQ; + + NIL operation; + PAIR; + } diff --git a/tests_python/contracts_011/opcodes/add_bls12_381_fr.tz b/tests_python/contracts_011/opcodes/add_bls12_381_fr.tz new file mode 100644 index 000000000000..e7b60dedc932 --- /dev/null +++ b/tests_python/contracts_011/opcodes/add_bls12_381_fr.tz @@ -0,0 +1,3 @@ +parameter (pair bls12_381_fr bls12_381_fr); +storage (option (bls12_381_fr)); +code {CAR; UNPAIR; ADD; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/add_bls12_381_g1.tz b/tests_python/contracts_011/opcodes/add_bls12_381_g1.tz new file mode 100644 index 000000000000..9f817c88d8a5 --- /dev/null +++ b/tests_python/contracts_011/opcodes/add_bls12_381_g1.tz @@ -0,0 +1,3 @@ +parameter (pair bls12_381_g1 bls12_381_g1); +storage (option (bls12_381_g1)); +code {CAR; UNPAIR; ADD; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/add_bls12_381_g2.tz b/tests_python/contracts_011/opcodes/add_bls12_381_g2.tz new file mode 100644 index 000000000000..1d1c0688c1d2 --- /dev/null +++ b/tests_python/contracts_011/opcodes/add_bls12_381_g2.tz @@ -0,0 +1,3 @@ +parameter (pair bls12_381_g2 bls12_381_g2); +storage (option (bls12_381_g2)); +code {CAR; UNPAIR; ADD; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/add_delta_timestamp.tz b/tests_python/contracts_011/opcodes/add_delta_timestamp.tz new file mode 100644 index 000000000000..b9ed86901726 --- /dev/null +++ b/tests_python/contracts_011/opcodes/add_delta_timestamp.tz @@ -0,0 +1,3 @@ +parameter (pair int timestamp); +storage (option timestamp); +code { CAR; DUP; CAR; DIP{CDR}; ADD; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/add_timestamp_delta.tz b/tests_python/contracts_011/opcodes/add_timestamp_delta.tz new file mode 100644 index 000000000000..766bf9f91f51 --- /dev/null +++ b/tests_python/contracts_011/opcodes/add_timestamp_delta.tz @@ -0,0 +1,3 @@ +parameter (pair timestamp int); +storage (option timestamp); +code { CAR; DUP; CAR; DIP{CDR}; ADD; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/address.tz b/tests_python/contracts_011/opcodes/address.tz new file mode 100644 index 000000000000..7e6bcdec337b --- /dev/null +++ b/tests_python/contracts_011/opcodes/address.tz @@ -0,0 +1,3 @@ +parameter (contract unit); +storage (option address); +code {CAR; ADDRESS; SOME; NIL operation; PAIR } diff --git a/tests_python/contracts_011/opcodes/and.tz b/tests_python/contracts_011/opcodes/and.tz new file mode 100644 index 000000000000..48e346ca04f3 --- /dev/null +++ b/tests_python/contracts_011/opcodes/and.tz @@ -0,0 +1,3 @@ +parameter (pair :param (bool %first) (bool %second)); +storage (option bool); +code { CAR ; UNPAIR; AND @and; SOME @res; NIL @noop operation; PAIR; UNPAIR @x @y; PAIR %a %b }; diff --git a/tests_python/contracts_011/opcodes/and_binary.tz b/tests_python/contracts_011/opcodes/and_binary.tz new file mode 100644 index 000000000000..96f60082c713 --- /dev/null +++ b/tests_python/contracts_011/opcodes/and_binary.tz @@ -0,0 +1,27 @@ +parameter unit; +storage unit; +code { DROP; + + # 0101 & 0110 = 0100 + PUSH nat 5; PUSH nat 6; AND; PUSH nat 4; ASSERT_CMPEQ; + + # 0110 & 0101 = 0100 + PUSH nat 6; PUSH int 5; AND; PUSH nat 4; ASSERT_CMPEQ; + + # Negative numbers are represented as with a initial virtual + # infinite series of 1's. + # Hence, AND with -1 (1111...) is identity: + + # 12 = ...1100 + # & -1 = ...1111 + # ---- + # = 12 = ...1100 + PUSH nat 12; PUSH int -1; AND; PUSH nat 12; ASSERT_CMPEQ; + + # 12 = ...0001100 + # & -5 = ...1111011 + # ----------------- + # 8 = ...0001000 + PUSH nat 12; PUSH int -5; AND; PUSH nat 8; ASSERT_CMPEQ; + + UNIT; NIL @noop operation; PAIR; }; diff --git a/tests_python/contracts_011/opcodes/and_logical_1.tz b/tests_python/contracts_011/opcodes/and_logical_1.tz new file mode 100644 index 000000000000..20743c0bfdf9 --- /dev/null +++ b/tests_python/contracts_011/opcodes/and_logical_1.tz @@ -0,0 +1,3 @@ +parameter (pair bool bool); +storage bool; +code { CAR ; UNPAIR; AND @and; NIL @noop operation; PAIR; }; diff --git a/tests_python/contracts_011/opcodes/balance.tz b/tests_python/contracts_011/opcodes/balance.tz new file mode 100644 index 000000000000..0a9bfc61494c --- /dev/null +++ b/tests_python/contracts_011/opcodes/balance.tz @@ -0,0 +1,3 @@ +parameter unit; +storage mutez; +code {DROP; BALANCE; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/big_map_mem_nat.tz b/tests_python/contracts_011/opcodes/big_map_mem_nat.tz new file mode 100644 index 000000000000..71ecaf2c4a75 --- /dev/null +++ b/tests_python/contracts_011/opcodes/big_map_mem_nat.tz @@ -0,0 +1,7 @@ +parameter nat; +storage (pair (big_map nat nat) (option bool)) ; +# stores (map, Some flag) where flag = parameter is a member of +# the map in first component of storage +code { UNPAIR; + DIP { CAR; DUP }; + MEM; SOME; SWAP; PAIR; NIL operation; PAIR;} diff --git a/tests_python/contracts_011/opcodes/big_map_mem_string.tz b/tests_python/contracts_011/opcodes/big_map_mem_string.tz new file mode 100644 index 000000000000..8c557f7dc1f8 --- /dev/null +++ b/tests_python/contracts_011/opcodes/big_map_mem_string.tz @@ -0,0 +1,7 @@ +parameter string; +storage (pair (big_map string nat) (option bool)) ; +# stores (map, Some flag) where flag = parameter is a member of +# the map in first component of storage +code { UNPAIR; + DIP { CAR; DUP }; + MEM; SOME; SWAP; PAIR; NIL operation; PAIR;} diff --git a/tests_python/contracts_011/opcodes/big_map_to_self.tz b/tests_python/contracts_011/opcodes/big_map_to_self.tz new file mode 100644 index 000000000000..6a9442b9f3e5 --- /dev/null +++ b/tests_python/contracts_011/opcodes/big_map_to_self.tz @@ -0,0 +1,22 @@ +parameter (or (pair %have_fun (big_map string nat) unit) (unit %default)); +storage (big_map string nat); +code { + UNPAIR; + DIP {NIL operation}; + IF_LEFT { + DROP + } + { + DROP; + SELF %have_fun; + PUSH mutez 0; + DUP 4; + PUSH (option nat) (Some 8); + PUSH string "hahaha"; + UPDATE; + UNIT; SWAP; PAIR; + TRANSFER_TOKENS; + CONS + }; + PAIR + } diff --git a/tests_python/contracts_011/opcodes/bls12_381_fr_push_bytes_not_padded.tz b/tests_python/contracts_011/opcodes/bls12_381_fr_push_bytes_not_padded.tz new file mode 100644 index 000000000000..fd4142914d2c --- /dev/null +++ b/tests_python/contracts_011/opcodes/bls12_381_fr_push_bytes_not_padded.tz @@ -0,0 +1,9 @@ +parameter unit; +storage (option bls12_381_fr); +code { + DROP; + PUSH bls12_381_fr 0x00; + SOME; + NIL operation; + PAIR; + }; \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/bls12_381_fr_push_nat.tz b/tests_python/contracts_011/opcodes/bls12_381_fr_push_nat.tz new file mode 100644 index 000000000000..314b97f2a6b9 --- /dev/null +++ b/tests_python/contracts_011/opcodes/bls12_381_fr_push_nat.tz @@ -0,0 +1,9 @@ +parameter unit; +storage (option bls12_381_fr); +code { + DROP; + PUSH bls12_381_fr 16; + SOME; + NIL operation; + PAIR; + }; \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/bls12_381_fr_to_int.tz b/tests_python/contracts_011/opcodes/bls12_381_fr_to_int.tz new file mode 100644 index 000000000000..67e2c9b080b1 --- /dev/null +++ b/tests_python/contracts_011/opcodes/bls12_381_fr_to_int.tz @@ -0,0 +1,8 @@ +parameter bls12_381_fr; +storage int; +code { + CAR; + INT; + NIL operation; + PAIR; + }; \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/bls12_381_fr_to_mutez.tz b/tests_python/contracts_011/opcodes/bls12_381_fr_to_mutez.tz new file mode 100644 index 000000000000..39630958e515 --- /dev/null +++ b/tests_python/contracts_011/opcodes/bls12_381_fr_to_mutez.tz @@ -0,0 +1,12 @@ +parameter bls12_381_fr; +storage mutez; +code { + CAR; + INT; + ISNAT; + ASSERT_SOME; + PUSH mutez 1; + MUL; + NIL operation; + PAIR; + }; \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/bls12_381_fr_z_int.tz b/tests_python/contracts_011/opcodes/bls12_381_fr_z_int.tz new file mode 100644 index 000000000000..67018c55faba --- /dev/null +++ b/tests_python/contracts_011/opcodes/bls12_381_fr_z_int.tz @@ -0,0 +1,8 @@ +parameter int; +storage (bls12_381_fr); +code { + UNPAIR; + MUL; + NIL operation; + PAIR; + }; \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/bls12_381_fr_z_nat.tz b/tests_python/contracts_011/opcodes/bls12_381_fr_z_nat.tz new file mode 100644 index 000000000000..1376e0c39561 --- /dev/null +++ b/tests_python/contracts_011/opcodes/bls12_381_fr_z_nat.tz @@ -0,0 +1,8 @@ +parameter nat; +storage (bls12_381_fr); +code { + UNPAIR; + MUL; + NIL operation; + PAIR; + }; \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/bls12_381_z_fr_int.tz b/tests_python/contracts_011/opcodes/bls12_381_z_fr_int.tz new file mode 100644 index 000000000000..783fb3c0d660 --- /dev/null +++ b/tests_python/contracts_011/opcodes/bls12_381_z_fr_int.tz @@ -0,0 +1,9 @@ +parameter int; +storage (bls12_381_fr); +code { + UNPAIR; + SWAP; + MUL; + NIL operation; + PAIR; + }; \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/bls12_381_z_fr_nat.tz b/tests_python/contracts_011/opcodes/bls12_381_z_fr_nat.tz new file mode 100644 index 000000000000..1210e36db0e1 --- /dev/null +++ b/tests_python/contracts_011/opcodes/bls12_381_z_fr_nat.tz @@ -0,0 +1,9 @@ +parameter nat; +storage (bls12_381_fr); +code { + UNPAIR; + SWAP; + MUL; + NIL operation; + PAIR; + }; \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/bytes.tz b/tests_python/contracts_011/opcodes/bytes.tz new file mode 100644 index 000000000000..e4dd8445eecc --- /dev/null +++ b/tests_python/contracts_011/opcodes/bytes.tz @@ -0,0 +1,11 @@ +# A contract that accepts bytes in a default entry point and does nothing. +# Useful for testing transfers of arbitrary sizes. +parameter bytes; +storage unit; +code + { + CDR; # @storage + # == default == # @storage + NIL operation; # list operation : @storage + PAIR; # pair (list operation) @storage + }; \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/car.tz b/tests_python/contracts_011/opcodes/car.tz new file mode 100644 index 000000000000..8fd03ba51052 --- /dev/null +++ b/tests_python/contracts_011/opcodes/car.tz @@ -0,0 +1,3 @@ +parameter (pair (nat :l) (nat :r)); +storage nat; +code { CAR; CAR ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/opcodes/cdr.tz b/tests_python/contracts_011/opcodes/cdr.tz new file mode 100644 index 000000000000..dae260c5be74 --- /dev/null +++ b/tests_python/contracts_011/opcodes/cdr.tz @@ -0,0 +1,3 @@ +parameter (pair (nat :l) (nat :r)); +storage nat; +code { CAR; CDR ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/opcodes/chain_id.tz b/tests_python/contracts_011/opcodes/chain_id.tz new file mode 100644 index 000000000000..783d13fa0afc --- /dev/null +++ b/tests_python/contracts_011/opcodes/chain_id.tz @@ -0,0 +1,3 @@ +parameter unit; +storage unit; +code { CHAIN_ID; DROP; CAR; NIL operation; PAIR } diff --git a/tests_python/contracts_011/opcodes/chain_id_store.tz b/tests_python/contracts_011/opcodes/chain_id_store.tz new file mode 100644 index 000000000000..11e57fd210c7 --- /dev/null +++ b/tests_python/contracts_011/opcodes/chain_id_store.tz @@ -0,0 +1,3 @@ +parameter unit; +storage (option chain_id); +code { DROP; CHAIN_ID; SOME; NIL operation; PAIR } diff --git a/tests_python/contracts_011/opcodes/check_signature.tz b/tests_python/contracts_011/opcodes/check_signature.tz new file mode 100644 index 000000000000..b5d5b2842648 --- /dev/null +++ b/tests_python/contracts_011/opcodes/check_signature.tz @@ -0,0 +1,10 @@ +parameter key; +storage (pair signature string); +code { + DUP; DUP; + DIP{ CDR; DUP; CAR; + DIP{CDR; PACK}}; + CAR; CHECK_SIGNATURE; + IF {} {FAIL} ; + CDR; NIL operation ; PAIR}; + diff --git a/tests_python/contracts_011/opcodes/comb-get.tz b/tests_python/contracts_011/opcodes/comb-get.tz new file mode 100644 index 000000000000..5493d68f2696 --- /dev/null +++ b/tests_python/contracts_011/opcodes/comb-get.tz @@ -0,0 +1,27 @@ +# See also ../macros/carn_and_cdrn.tz for the same test using the +# CAR n and CDR n macros. +parameter (pair nat nat nat unit); +storage unit; +code { + CAR ; + + # Checking the first element + DUP ; CAR ; + PUSH nat 1 ; ASSERT_CMPEQ ; + DUP ; GET 1 ; + PUSH nat 1 ; ASSERT_CMPEQ ; + + # Checking the second element + DUP ; GET 3 ; + PUSH nat 4 ; ASSERT_CMPEQ ; + + # Checking the third element + DUP ; GET 5 ; + PUSH nat 2 ; ASSERT_CMPEQ ; + + # Checking the last (fourth) element + DUP ; GET 6 ; + UNIT ; ASSERT_CMPEQ ; + + DROP ; UNIT ; NIL operation ; PAIR + } diff --git a/tests_python/contracts_011/opcodes/comb-literals.tz b/tests_python/contracts_011/opcodes/comb-literals.tz new file mode 100644 index 000000000000..2a2b217d7857 --- /dev/null +++ b/tests_python/contracts_011/opcodes/comb-literals.tz @@ -0,0 +1,9 @@ +# This pushes a list of combs to test the effect of the normalize script command +parameter unit; +storage unit; +code { + PUSH + (list (pair nat nat nat nat)) + {Pair 0 3 6 9; Pair 1 (Pair 4 (Pair 7 10)); {2; 5; 8; 11}}; + DROP 2; UNIT; NIL operation; PAIR + } diff --git a/tests_python/contracts_011/opcodes/comb-set-2.tz b/tests_python/contracts_011/opcodes/comb-set-2.tz new file mode 100644 index 000000000000..757acfd380e6 --- /dev/null +++ b/tests_python/contracts_011/opcodes/comb-set-2.tz @@ -0,0 +1,10 @@ +# This tests UPDATE on combs. Contrary to comb-set.tz, both the values +# and their types are updated. +parameter (pair nat nat nat unit); +storage (option (pair int nat string bytes)); +code { + CAR ; + PUSH int 2 ; UPDATE 1 ; + PUSH string "toto" ; UPDATE 5 ; + PUSH bytes 0x01 ; UPDATE 6 ; + SOME ; NIL operation ; PAIR ; } diff --git a/tests_python/contracts_011/opcodes/comb-set.tz b/tests_python/contracts_011/opcodes/comb-set.tz new file mode 100644 index 000000000000..fe407571923e --- /dev/null +++ b/tests_python/contracts_011/opcodes/comb-set.tz @@ -0,0 +1,10 @@ +# This tests UPDATE on combs. See also comb-set-2.tz for tests of +# UPDATE that also change the type of fields. +parameter unit; +storage (pair nat nat nat unit); +code { CDR ; + PUSH nat 2 ; UPDATE 1 ; + PUSH nat 12 ; UPDATE 3 ; + PUSH nat 8 ; UPDATE 5 ; + UNIT ; UPDATE 6 ; + NIL operation ; PAIR ; } diff --git a/tests_python/contracts_011/opcodes/comb.tz b/tests_python/contracts_011/opcodes/comb.tz new file mode 100644 index 000000000000..6709bde8b883 --- /dev/null +++ b/tests_python/contracts_011/opcodes/comb.tz @@ -0,0 +1,9 @@ +parameter unit; +storage (pair nat nat nat); +code { DROP ; + PUSH nat 3 ; + PUSH nat 2 ; + PUSH nat 1 ; + NIL operation ; + PAIR 4 + } diff --git a/tests_python/contracts_011/opcodes/compare.tz b/tests_python/contracts_011/opcodes/compare.tz new file mode 100644 index 000000000000..963215fb46cd --- /dev/null +++ b/tests_python/contracts_011/opcodes/compare.tz @@ -0,0 +1,52 @@ +parameter unit; +storage unit; +code { + DROP; + + # bool + PUSH bool True; DUP; COMPARE; ASSERT_EQ; + PUSH bool False; DUP; COMPARE; ASSERT_EQ; + PUSH bool False; PUSH bool True; COMPARE; ASSERT_GT; + PUSH bool True; PUSH bool False; COMPARE; ASSERT_LT; + + # bytes + PUSH bytes 0xAABBCC; DUP; COMPARE; ASSERT_EQ; + PUSH bytes 0x; PUSH bytes 0x; COMPARE; ASSERT_EQ; + PUSH bytes 0x; PUSH bytes 0x01; COMPARE; ASSERT_GT; + PUSH bytes 0x01; PUSH bytes 0x02; COMPARE; ASSERT_GT; + PUSH bytes 0x02; PUSH bytes 0x01; COMPARE; ASSERT_LT; + + # int + PUSH int 1; DUP; COMPARE; ASSERT_EQ; + PUSH int 10; PUSH int 5; COMPARE; ASSERT_LT; + PUSH int -4; PUSH int 1923; COMPARE; ASSERT_GT; + + # nat + PUSH nat 1; DUP; COMPARE; ASSERT_EQ; + PUSH nat 10; PUSH nat 5; COMPARE; ASSERT_LT; + PUSH nat 4; PUSH nat 1923; COMPARE; ASSERT_GT; + + # key_hash + PUSH key_hash "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"; DUP; COMPARE; ASSERT_EQ; + PUSH key_hash "tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv"; PUSH key_hash "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"; COMPARE; ASSERT_LT; + PUSH key_hash "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"; PUSH key_hash "tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv"; COMPARE; ASSERT_GT; + + # mutez + PUSH mutez 1; DUP; COMPARE; ASSERT_EQ; + PUSH mutez 10; PUSH mutez 5; COMPARE; ASSERT_LT; + PUSH mutez 4; PUSH mutez 1923; COMPARE; ASSERT_GT; + + # string + PUSH string "AABBCC"; DUP; COMPARE; ASSERT_EQ; + PUSH string ""; PUSH string ""; COMPARE; ASSERT_EQ; + PUSH string ""; PUSH string "a"; COMPARE; ASSERT_GT; + PUSH string "a"; PUSH string "b"; COMPARE; ASSERT_GT; + PUSH string "b"; PUSH string "a"; COMPARE; ASSERT_LT; + + # timestamp + PUSH timestamp "2019-09-16T08:38:05Z"; DUP; COMPARE; ASSERT_EQ; + PUSH timestamp "2017-09-16T08:38:04Z"; PUSH timestamp "2019-09-16T08:38:05Z"; COMPARE; ASSERT_GT; + PUSH timestamp "2019-09-16T08:38:05Z"; PUSH timestamp "2019-09-16T08:38:04Z"; COMPARE; ASSERT_LT; + + UNIT; NIL operation; PAIR; + } diff --git a/tests_python/contracts_011/opcodes/compare_big_type.tz b/tests_python/contracts_011/opcodes/compare_big_type.tz new file mode 100644 index 000000000000..666ad3137777 --- /dev/null +++ b/tests_python/contracts_011/opcodes/compare_big_type.tz @@ -0,0 +1,20 @@ +# This contract should cost a lot of gas to typecheck +# because big types are compared in COMPARE +parameter unit; +storage unit; +code { DROP; PUSH nat 0 ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; DUP ; COMPARE ; DROP ; + DUP ; DUP ; COMPARE ; DROP ; + DUP ; DUP ; COMPARE ; DROP ; + DUP ; DUP ; COMPARE ; DROP ; + DUP ; DUP ; COMPARE ; DROP ; + DUP ; DUP ; COMPARE ; DROP ; + DROP ; UNIT ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/opcodes/compare_big_type2.tz b/tests_python/contracts_011/opcodes/compare_big_type2.tz new file mode 100644 index 000000000000..126217d79fdf --- /dev/null +++ b/tests_python/contracts_011/opcodes/compare_big_type2.tz @@ -0,0 +1,22 @@ +# Like compare_big_type.tz but with an extra line +# DUP ; DUP ; COMPARE ; DROP ; +# so that we can measure how much it costs +parameter unit; +storage unit; +code { DROP; PUSH nat 0 ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; DUP ; COMPARE ; DROP ; + DUP ; DUP ; COMPARE ; DROP ; + DUP ; DUP ; COMPARE ; DROP ; + DUP ; DUP ; COMPARE ; DROP ; + DUP ; DUP ; COMPARE ; DROP ; + DUP ; DUP ; COMPARE ; DROP ; + DUP ; DUP ; COMPARE ; DROP ; + DROP ; UNIT ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/opcodes/comparisons.tz b/tests_python/contracts_011/opcodes/comparisons.tz new file mode 100644 index 000000000000..c603f07339ce --- /dev/null +++ b/tests_python/contracts_011/opcodes/comparisons.tz @@ -0,0 +1,15 @@ +parameter (list int); +storage (list (list bool)); +code { + CAR; + + NIL (list bool); + DIP {DUP; MAP { EQ; };}; SWAP; CONS; + DIP {DUP; MAP { NEQ; };}; SWAP; CONS; + DIP {DUP; MAP { LE; };}; SWAP; CONS; + DIP {DUP; MAP { LT; };}; SWAP; CONS; + DIP {DUP; MAP { GE; };}; SWAP; CONS; + DIP {MAP { GT; };}; SWAP; CONS; + + NIL operation; PAIR; + } diff --git a/tests_python/contracts_011/opcodes/concat_hello.tz b/tests_python/contracts_011/opcodes/concat_hello.tz new file mode 100644 index 000000000000..e290b90fb2ad --- /dev/null +++ b/tests_python/contracts_011/opcodes/concat_hello.tz @@ -0,0 +1,4 @@ +parameter (list string); +storage (list string); +code{ CAR; + MAP { PUSH @hello string "Hello "; CONCAT }; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/concat_hello_bytes.tz b/tests_python/contracts_011/opcodes/concat_hello_bytes.tz new file mode 100644 index 000000000000..55f8ab7a216b --- /dev/null +++ b/tests_python/contracts_011/opcodes/concat_hello_bytes.tz @@ -0,0 +1,4 @@ +parameter (list bytes); +storage (list bytes); +code{ CAR; + MAP { PUSH bytes 0xFF; CONCAT }; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/concat_list.tz b/tests_python/contracts_011/opcodes/concat_list.tz new file mode 100644 index 000000000000..b570027ff68e --- /dev/null +++ b/tests_python/contracts_011/opcodes/concat_list.tz @@ -0,0 +1,5 @@ +parameter (list string); +storage string; +code {CAR; PUSH string ""; SWAP; + ITER {SWAP; DIP{NIL string; SWAP; CONS}; CONS; CONCAT}; + NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/cons.tz b/tests_python/contracts_011/opcodes/cons.tz new file mode 100644 index 000000000000..5189b47c36b4 --- /dev/null +++ b/tests_python/contracts_011/opcodes/cons.tz @@ -0,0 +1,3 @@ +parameter int; +storage (list int); +code { UNPAIR; CONS; NIL operation; PAIR; }; diff --git a/tests_python/contracts_011/opcodes/contains_all.tz b/tests_python/contracts_011/opcodes/contains_all.tz new file mode 100644 index 000000000000..fe4160f87227 --- /dev/null +++ b/tests_python/contracts_011/opcodes/contains_all.tz @@ -0,0 +1,7 @@ +parameter (pair (list string) (list string)); +storage (option bool); +code {CAR; DUP; CAR; DIP{CDR}; EMPTY_SET string; SWAP; + ITER {PAIR; DUP; CAR; DIP{CDR}; PUSH bool True; SWAP; UPDATE}; + PUSH bool True; SWAP; PAIR; SWAP; + ITER {PAIR; DUP; DUP; CAR; DIP{CDAR; DIP{CDDR}; DUP}; MEM; DIP{SWAP}; AND; SWAP; PAIR}; + CDR; SOME; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/contract.tz b/tests_python/contracts_011/opcodes/contract.tz new file mode 100644 index 000000000000..939337918d1c --- /dev/null +++ b/tests_python/contracts_011/opcodes/contract.tz @@ -0,0 +1,11 @@ +parameter address; +storage unit; +code { + CAR; + CONTRACT unit; + ASSERT_SOME; + DROP; + UNIT; + NIL operation; + PAIR + }; diff --git a/tests_python/contracts_011/opcodes/create_contract.tz b/tests_python/contracts_011/opcodes/create_contract.tz new file mode 100644 index 000000000000..d3fb8dc617a8 --- /dev/null +++ b/tests_python/contracts_011/opcodes/create_contract.tz @@ -0,0 +1,14 @@ +parameter unit; +storage (option address); +code { DROP; + UNIT; # starting storage for contract + AMOUNT; # Push the starting balance + NONE key_hash; # No delegate + CREATE_CONTRACT # Create the contract + { parameter unit ; + storage unit ; + code + { CDR; + NIL operation; + PAIR; } }; + DIP {SOME;NIL operation};CONS ; PAIR} # Ending calling convention stuff diff --git a/tests_python/contracts_011/opcodes/create_contract_rootname.tz b/tests_python/contracts_011/opcodes/create_contract_rootname.tz new file mode 100644 index 000000000000..b85b4cf8bb41 --- /dev/null +++ b/tests_python/contracts_011/opcodes/create_contract_rootname.tz @@ -0,0 +1,15 @@ +# this contract creates a contract +parameter unit; +storage (option address); +code { DROP; + UNIT; # starting storage for contract + AMOUNT; # Push the starting balance + NONE key_hash; # No delegate + CREATE_CONTRACT # Create the contract + { parameter %root unit ; + storage unit ; + code + { CDR; + NIL operation; + PAIR; } }; + DIP {SOME;NIL operation}; CONS ; PAIR} # Ending calling convention stuff diff --git a/tests_python/contracts_011/opcodes/create_contract_rootname_alt.tz b/tests_python/contracts_011/opcodes/create_contract_rootname_alt.tz new file mode 100644 index 000000000000..226a9abba298 --- /dev/null +++ b/tests_python/contracts_011/opcodes/create_contract_rootname_alt.tz @@ -0,0 +1,14 @@ +parameter unit; +storage (option address); +code { DROP; + UNIT; # starting storage for contract + AMOUNT; # Push the starting balance + NONE key_hash; # No delegate + CREATE_CONTRACT # Create the contract + { parameter (unit %root) ; + storage unit ; + code + { CDR; + NIL operation; + PAIR; } }; + DIP {SOME;NIL operation}; CONS ; PAIR} # Ending calling convention stuff diff --git a/tests_python/contracts_011/opcodes/create_contract_with_view.tz b/tests_python/contracts_011/opcodes/create_contract_with_view.tz new file mode 100644 index 000000000000..c8b591e9d3bc --- /dev/null +++ b/tests_python/contracts_011/opcodes/create_contract_with_view.tz @@ -0,0 +1,17 @@ +parameter unit; +storage (option address); +code { DROP; + UNIT; # starting storage for contract + AMOUNT; # Push the starting balance + NONE key_hash; # No delegate + CREATE_CONTRACT # Create the contract + { parameter unit ; + storage unit ; + code + { CDR; + NIL operation; + PAIR; } ; + view "const" nat nat { CAR; } ; + }; + DIP {SOME;NIL operation};CONS ; PAIR} # Ending calling convention stuff + diff --git a/tests_python/contracts_011/opcodes/diff_timestamps.tz b/tests_python/contracts_011/opcodes/diff_timestamps.tz new file mode 100644 index 000000000000..f1991a37a5d2 --- /dev/null +++ b/tests_python/contracts_011/opcodes/diff_timestamps.tz @@ -0,0 +1,3 @@ +parameter (pair timestamp timestamp); +storage int; +code { CAR; DUP; CAR; DIP{CDR}; SUB; NIL operation; PAIR } diff --git a/tests_python/contracts_011/opcodes/dig_eq.tz b/tests_python/contracts_011/opcodes/dig_eq.tz new file mode 100644 index 000000000000..aaafc4271fae --- /dev/null +++ b/tests_python/contracts_011/opcodes/dig_eq.tz @@ -0,0 +1,14 @@ +parameter (pair nat nat nat nat nat nat nat nat nat nat nat nat nat nat nat nat nat); +storage unit; +# this contract receives a 17-tuple, unpairs it, reverses the order, reverses it again, and pairs it and verifies that the result is the same as the original tuple. +code { CAR; + DUP; + + UNPAPAPAPAPAPAPAPAPAPAPAPAPAPAPAPAIR; + DIG 0; DIG 1; DIG 2; DIG 3; DIG 4; DIG 5; DIG 6; DIG 7; DIG 8; DIG 9; DIG 10; DIG 11; DIG 12; DIG 13; DIG 14; DIG 15; DIG 16; + # PUSH nat 1; ADD; + DIG 0; DIG 1; DIG 2; DIG 3; DIG 4; DIG 5; DIG 6; DIG 7; DIG 8; DIG 9; DIG 10; DIG 11; DIG 12; DIG 13; DIG 14; DIG 15; DIG 16; + PAPAPAPAPAPAPAPAPAPAPAPAPAPAPAPAIR; + ASSERT_CMPEQ; + + UNIT; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/dign.tz b/tests_python/contracts_011/opcodes/dign.tz new file mode 100644 index 000000000000..ec8a339dd48c --- /dev/null +++ b/tests_python/contracts_011/opcodes/dign.tz @@ -0,0 +1,3 @@ +parameter (pair (pair (pair (pair nat nat) nat) nat) nat); +storage nat; +code {CAR; UNPAIR ; UNPAIR ; UNPAIR ; UNPAIR ; DIG 4 ; DIP { DROP ; DROP ; DROP ; DROP } ; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/dip.tz b/tests_python/contracts_011/opcodes/dip.tz new file mode 100644 index 000000000000..f0c32a838747 --- /dev/null +++ b/tests_python/contracts_011/opcodes/dip.tz @@ -0,0 +1,8 @@ +parameter (pair nat nat); +storage (pair nat nat); +code{ + CAR; UNPAIR; + DUP; DIP { ADD }; + PAIR; + NIL operation; + PAIR}; diff --git a/tests_python/contracts_011/opcodes/dipn.tz b/tests_python/contracts_011/opcodes/dipn.tz new file mode 100644 index 000000000000..55d088e5518f --- /dev/null +++ b/tests_python/contracts_011/opcodes/dipn.tz @@ -0,0 +1,3 @@ +parameter (pair (pair (pair (pair nat nat) nat) nat) nat); +storage nat; +code {CAR; UNPAIR ; UNPAIR ; UNPAIR ; UNPAIR ; DIP 5 {PUSH nat 6} ; DROP ; DROP ; DROP ; DROP ; DROP ; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/dropn.tz b/tests_python/contracts_011/opcodes/dropn.tz new file mode 100644 index 000000000000..4b5379b3a3b3 --- /dev/null +++ b/tests_python/contracts_011/opcodes/dropn.tz @@ -0,0 +1,3 @@ +parameter (pair (pair (pair (pair nat nat) nat) nat) nat); +storage nat; +code {CAR; UNPAIR ; UNPAIR ; UNPAIR ; UNPAIR ; DROP 4 ; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/dugn.tz b/tests_python/contracts_011/opcodes/dugn.tz new file mode 100644 index 000000000000..521c052f1fcd --- /dev/null +++ b/tests_python/contracts_011/opcodes/dugn.tz @@ -0,0 +1,3 @@ +parameter (pair (pair (pair (pair nat nat) nat) nat) nat); +storage nat; +code {CAR; UNPAIR ; UNPAIR ; UNPAIR ; UNPAIR ; DUG 4 ; DROP ; DROP ; DROP ; DROP ; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/dup-n.tz b/tests_python/contracts_011/opcodes/dup-n.tz new file mode 100644 index 000000000000..7e530c0971d0 --- /dev/null +++ b/tests_python/contracts_011/opcodes/dup-n.tz @@ -0,0 +1,18 @@ +parameter unit; +storage unit; +code + { + DROP ; + PUSH nat 5 ; + PUSH nat 4 ; + PUSH nat 3 ; + PUSH nat 2 ; + PUSH nat 1 ; + DUP 1 ; PUSH nat 1 ; ASSERT_CMPEQ ; + DUP 2 ; PUSH nat 2 ; ASSERT_CMPEQ ; + DUP 3 ; PUSH nat 3 ; ASSERT_CMPEQ ; + DUP 4 ; PUSH nat 4 ; ASSERT_CMPEQ ; + DUP 5 ; PUSH nat 5 ; ASSERT_CMPEQ ; + DROP 5 ; + UNIT ; NIL operation ; PAIR ; + }; diff --git a/tests_python/contracts_011/opcodes/ediv.tz b/tests_python/contracts_011/opcodes/ediv.tz new file mode 100644 index 000000000000..a1fc89992a02 --- /dev/null +++ b/tests_python/contracts_011/opcodes/ediv.tz @@ -0,0 +1,13 @@ +parameter (pair int int); +storage (pair (option (pair int nat)) (option (pair int nat)) (option (pair int nat)) (option (pair nat nat))); +code { CAR; + # :: nat : nat : 'S -> option (pair nat nat) : 'S + DUP; UNPAIR; ABS; DIP { ABS; }; EDIV; SWAP; + # :: nat : int : 'S -> option (pair int nat) : 'S + DUP; UNPAIR; ABS; EDIV; SWAP; + # :: int : nat : 'S -> option (pair int nat) : 'S + DUP; UNPAIR; DIP { ABS; }; EDIV; SWAP; + # :: int : int : 'S -> option (pair int nat) : 'S + UNPAIR; EDIV; + PAPAPAIR; + NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/ediv_mutez.tz b/tests_python/contracts_011/opcodes/ediv_mutez.tz new file mode 100644 index 000000000000..2df73dd4a0e3 --- /dev/null +++ b/tests_python/contracts_011/opcodes/ediv_mutez.tz @@ -0,0 +1,12 @@ +parameter (pair mutez (or mutez nat)); +storage (or (option (pair nat mutez)) (option (pair mutez mutez))); +code { CAR; + UNPAIR; + SWAP; + IF_LEFT { + SWAP; EDIV; LEFT (option (pair mutez mutez)); + } + { + SWAP; EDIV; RIGHT (option (pair nat mutez)); + }; + NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/empty_map.tz b/tests_python/contracts_011/opcodes/empty_map.tz new file mode 100644 index 000000000000..9023fe847b3f --- /dev/null +++ b/tests_python/contracts_011/opcodes/empty_map.tz @@ -0,0 +1,6 @@ +storage (map string string); +parameter unit; +code {DROP; + EMPTY_MAP string string; + PUSH string "world"; SOME; PUSH string "hello"; UPDATE; + NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/exec_concat.tz b/tests_python/contracts_011/opcodes/exec_concat.tz new file mode 100644 index 000000000000..0265f1557f0e --- /dev/null +++ b/tests_python/contracts_011/opcodes/exec_concat.tz @@ -0,0 +1,7 @@ +parameter string; +storage string; +code {CAR; + LAMBDA string string + {PUSH string "_abc"; NIL string ; + SWAP ; CONS ; SWAP ; CONS ; CONCAT}; + SWAP; EXEC; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/first.tz b/tests_python/contracts_011/opcodes/first.tz new file mode 100644 index 000000000000..6e47b4c008e8 --- /dev/null +++ b/tests_python/contracts_011/opcodes/first.tz @@ -0,0 +1,3 @@ +parameter (list nat); +storage nat; +code{CAR; IF_CONS {DIP{DROP}} {FAIL}; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/get_and_update_big_map.tz b/tests_python/contracts_011/opcodes/get_and_update_big_map.tz new file mode 100644 index 000000000000..3b39c9a6f733 --- /dev/null +++ b/tests_python/contracts_011/opcodes/get_and_update_big_map.tz @@ -0,0 +1,9 @@ +parameter string; +storage (pair (option nat) (big_map string nat)); +code { + UNPAPAIR; + GET_AND_UPDATE; + PAIR; + NIL operation; + PAIR + } diff --git a/tests_python/contracts_011/opcodes/get_and_update_map.tz b/tests_python/contracts_011/opcodes/get_and_update_map.tz new file mode 100644 index 000000000000..b67f08ce7746 --- /dev/null +++ b/tests_python/contracts_011/opcodes/get_and_update_map.tz @@ -0,0 +1,9 @@ +parameter string; +storage (pair (option nat) (map string nat)); +code { + UNPAPAIR; + GET_AND_UPDATE; + PAIR; + NIL operation; + PAIR + } diff --git a/tests_python/contracts_011/opcodes/get_big_map_value.tz b/tests_python/contracts_011/opcodes/get_big_map_value.tz new file mode 100644 index 000000000000..4ca52343d45a --- /dev/null +++ b/tests_python/contracts_011/opcodes/get_big_map_value.tz @@ -0,0 +1,6 @@ +parameter string; +storage (pair (big_map string string) (option string)); +# retrieves the values stored in the big_map on the left side of the +# pair at the key denoted by the parameter and puts it in the right +# hand side of the storage +code {DUP; CAR; DIP{CDAR; DUP}; GET; SWAP; PAIR; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/get_map_value.tz b/tests_python/contracts_011/opcodes/get_map_value.tz new file mode 100644 index 000000000000..f46639649a34 --- /dev/null +++ b/tests_python/contracts_011/opcodes/get_map_value.tz @@ -0,0 +1,3 @@ +parameter string; +storage (pair (option string) (map string string)); +code {DUP; CAR; DIP{CDDR; DUP}; GET; PAIR; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/hash_consistency_checker.tz b/tests_python/contracts_011/opcodes/hash_consistency_checker.tz new file mode 100644 index 000000000000..fb98a39da496 --- /dev/null +++ b/tests_python/contracts_011/opcodes/hash_consistency_checker.tz @@ -0,0 +1,3 @@ +parameter (pair mutez (pair timestamp int)) ; +storage bytes ; +code { CAR ; PACK ; BLAKE2B ; NIL operation ; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/hash_key.tz b/tests_python/contracts_011/opcodes/hash_key.tz new file mode 100644 index 000000000000..6c7f78b4aaf6 --- /dev/null +++ b/tests_python/contracts_011/opcodes/hash_key.tz @@ -0,0 +1,3 @@ +parameter key; +storage (option key_hash); +code {CAR; HASH_KEY; SOME ;NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/hash_string.tz b/tests_python/contracts_011/opcodes/hash_string.tz new file mode 100644 index 000000000000..b0b8ddea6403 --- /dev/null +++ b/tests_python/contracts_011/opcodes/hash_string.tz @@ -0,0 +1,3 @@ +parameter string; +storage bytes; +code {CAR; PACK ; BLAKE2B; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/if.tz b/tests_python/contracts_011/opcodes/if.tz new file mode 100644 index 000000000000..4bc0e353daeb --- /dev/null +++ b/tests_python/contracts_011/opcodes/if.tz @@ -0,0 +1,3 @@ +parameter bool; +storage (option bool); +code {CAR; IF {PUSH bool True} {PUSH bool False}; SOME; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/if_some.tz b/tests_python/contracts_011/opcodes/if_some.tz new file mode 100644 index 000000000000..5c3138b2272b --- /dev/null +++ b/tests_python/contracts_011/opcodes/if_some.tz @@ -0,0 +1,3 @@ +parameter (option string); +storage string; +code { CAR; IF_SOME {} {PUSH string ""}; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/int.tz b/tests_python/contracts_011/opcodes/int.tz new file mode 100644 index 000000000000..3f199881392a --- /dev/null +++ b/tests_python/contracts_011/opcodes/int.tz @@ -0,0 +1,5 @@ +parameter nat; +storage (option int); +# this contract takes a natural number as parameter, converts it to an +# integer and stores it. +code { CAR; INT; SOME; NIL operation; PAIR }; diff --git a/tests_python/contracts_011/opcodes/keccak.tz b/tests_python/contracts_011/opcodes/keccak.tz new file mode 100644 index 000000000000..e96256100999 --- /dev/null +++ b/tests_python/contracts_011/opcodes/keccak.tz @@ -0,0 +1,8 @@ +storage (option bytes); +parameter bytes; +code + { + CAR; + KECCAK; SOME; + NIL operation; PAIR + } diff --git a/tests_python/contracts_011/opcodes/left_right.tz b/tests_python/contracts_011/opcodes/left_right.tz new file mode 100644 index 000000000000..d5650c03422e --- /dev/null +++ b/tests_python/contracts_011/opcodes/left_right.tz @@ -0,0 +1,3 @@ +parameter (or bool string); +storage (or string bool); +code {CAR; IF_LEFT {RIGHT string} {LEFT bool}; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/level.tz b/tests_python/contracts_011/opcodes/level.tz new file mode 100644 index 000000000000..7e3adb9d05f4 --- /dev/null +++ b/tests_python/contracts_011/opcodes/level.tz @@ -0,0 +1,3 @@ +parameter unit; +storage nat; +code {DROP; LEVEL; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/list_concat.tz b/tests_python/contracts_011/opcodes/list_concat.tz new file mode 100644 index 000000000000..d7bfb7d134ea --- /dev/null +++ b/tests_python/contracts_011/opcodes/list_concat.tz @@ -0,0 +1,3 @@ +parameter (list string); +storage string; +code { UNPAIR ; SWAP ; CONS ; CONCAT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/list_concat_bytes.tz b/tests_python/contracts_011/opcodes/list_concat_bytes.tz new file mode 100644 index 000000000000..0fc8e1620669 --- /dev/null +++ b/tests_python/contracts_011/opcodes/list_concat_bytes.tz @@ -0,0 +1,3 @@ +parameter (list bytes); +storage bytes; +code { UNPAIR ; SWAP ; CONS ; CONCAT; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/list_id.tz b/tests_python/contracts_011/opcodes/list_id.tz new file mode 100644 index 000000000000..6cd3693a1e14 --- /dev/null +++ b/tests_python/contracts_011/opcodes/list_id.tz @@ -0,0 +1,3 @@ +parameter (list string); +storage (list string); +code {CAR; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/list_id_map.tz b/tests_python/contracts_011/opcodes/list_id_map.tz new file mode 100644 index 000000000000..38b4493e8e0f --- /dev/null +++ b/tests_python/contracts_011/opcodes/list_id_map.tz @@ -0,0 +1,3 @@ +parameter (list string); +storage (list string); +code {CAR; MAP {}; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/list_iter.tz b/tests_python/contracts_011/opcodes/list_iter.tz new file mode 100644 index 000000000000..df904d882234 --- /dev/null +++ b/tests_python/contracts_011/opcodes/list_iter.tz @@ -0,0 +1,5 @@ +parameter (list int); +storage int; +code { CAR; PUSH int 1; SWAP; + ITER { MUL }; + NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/list_map_block.tz b/tests_python/contracts_011/opcodes/list_map_block.tz new file mode 100644 index 000000000000..b5202dd9b6fb --- /dev/null +++ b/tests_python/contracts_011/opcodes/list_map_block.tz @@ -0,0 +1,5 @@ +parameter (list int); +storage (list int); +code { CAR; PUSH int 0; SWAP; + MAP { DIP{DUP}; ADD; DIP{PUSH int 1; ADD}}; + NIL operation; PAIR; DIP{DROP}} diff --git a/tests_python/contracts_011/opcodes/list_size.tz b/tests_python/contracts_011/opcodes/list_size.tz new file mode 100644 index 000000000000..6ced12799187 --- /dev/null +++ b/tests_python/contracts_011/opcodes/list_size.tz @@ -0,0 +1,3 @@ +parameter (list int); +storage nat; +code {CAR; SIZE; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/loop_left.tz b/tests_python/contracts_011/opcodes/loop_left.tz new file mode 100644 index 000000000000..64bcc76c89cc --- /dev/null +++ b/tests_python/contracts_011/opcodes/loop_left.tz @@ -0,0 +1,7 @@ +parameter (list string); +storage (list string); +code { CAR; NIL string; SWAP; PAIR; LEFT (list string); + LOOP_LEFT { DUP; CAR; DIP{CDR}; + IF_CONS { SWAP; DIP{CONS}; PAIR; LEFT (list string) } + { RIGHT (pair (list string) (list string)) }; }; + NIL operation; PAIR } diff --git a/tests_python/contracts_011/opcodes/map_car.tz b/tests_python/contracts_011/opcodes/map_car.tz new file mode 100644 index 000000000000..b763590ece2c --- /dev/null +++ b/tests_python/contracts_011/opcodes/map_car.tz @@ -0,0 +1,5 @@ +parameter bool; +storage (pair (bool %b) (nat %n)); +code { DUP; CAR; DIP{CDR}; SWAP; + MAP_CAR @new_storage %b { AND }; + NIL operation; PAIR }; diff --git a/tests_python/contracts_011/opcodes/map_id.tz b/tests_python/contracts_011/opcodes/map_id.tz new file mode 100644 index 000000000000..ff0a3bbbf213 --- /dev/null +++ b/tests_python/contracts_011/opcodes/map_id.tz @@ -0,0 +1,3 @@ +parameter (map nat nat); +storage (map nat nat); +code { CAR ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/opcodes/map_iter.tz b/tests_python/contracts_011/opcodes/map_iter.tz new file mode 100644 index 000000000000..3ab5c35c73b8 --- /dev/null +++ b/tests_python/contracts_011/opcodes/map_iter.tz @@ -0,0 +1,7 @@ +parameter (map (int :k) (int :e)); +storage (pair (int :k) (int :e)); +code { CAR; PUSH @acc_e (int :e) 0; PUSH @acc_k (int :k) 0; PAIR % %r; SWAP; + ITER + { DIP {DUP; CAR; DIP{CDR}}; DUP; # Last instr + DIP{CAR; ADD}; SWAP; DIP{CDR; ADD}; PAIR % %r }; + NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/map_map.tz b/tests_python/contracts_011/opcodes/map_map.tz new file mode 100644 index 000000000000..4acbd63c32c4 --- /dev/null +++ b/tests_python/contracts_011/opcodes/map_map.tz @@ -0,0 +1,8 @@ +parameter nat; +storage (map string nat); +# this contract adds the value passed by parameter to each entry in +# the stored map. +code { UNPAIR; SWAP; + MAP { CDR; DIP {DUP}; ADD; }; + DIP { DROP; }; + NIL operation; PAIR; } diff --git a/tests_python/contracts_011/opcodes/map_map_sideeffect.tz b/tests_python/contracts_011/opcodes/map_map_sideeffect.tz new file mode 100644 index 000000000000..960b02a553ce --- /dev/null +++ b/tests_python/contracts_011/opcodes/map_map_sideeffect.tz @@ -0,0 +1,12 @@ +parameter nat; +storage (pair (map string nat) nat); +# this contract adds the value passed by parameter to each entry in +# the stored map, and it sets the second component of the pair to the +# sum of the map's elements +code { UNPAIR; SWAP; CAR; + DIP 2 { PUSH @sum nat 0; }; + MAP { CDR; DIP {DUP}; ADD; + DUP; DUG 2; DIP 2 { ADD @sum }; + }; + DIP { DROP; }; PAIR; + NIL operation; PAIR; } diff --git a/tests_python/contracts_011/opcodes/map_mem_nat.tz b/tests_python/contracts_011/opcodes/map_mem_nat.tz new file mode 100644 index 000000000000..0c245d7e0a65 --- /dev/null +++ b/tests_python/contracts_011/opcodes/map_mem_nat.tz @@ -0,0 +1,7 @@ +parameter nat; +storage (pair (map nat nat) (option bool)) ; +# stores (map, Some flag) where flag = parameter is a member of +# the map in first component of storage +code { UNPAIR; + DIP { CAR; DUP }; + MEM; SOME; SWAP; PAIR; NIL operation; PAIR;} diff --git a/tests_python/contracts_011/opcodes/map_mem_string.tz b/tests_python/contracts_011/opcodes/map_mem_string.tz new file mode 100644 index 000000000000..3fa5cd5b579f --- /dev/null +++ b/tests_python/contracts_011/opcodes/map_mem_string.tz @@ -0,0 +1,7 @@ +parameter string; +storage (pair (map string nat) (option bool)) ; +# stores (map, Some flag) where flag = parameter is a member of +# the map in first component of storage +code { UNPAIR; + DIP { CAR; DUP }; + MEM; SOME; SWAP; PAIR; NIL operation; PAIR;} diff --git a/tests_python/contracts_011/opcodes/map_size.tz b/tests_python/contracts_011/opcodes/map_size.tz new file mode 100644 index 000000000000..4bd6417e6d79 --- /dev/null +++ b/tests_python/contracts_011/opcodes/map_size.tz @@ -0,0 +1,3 @@ +parameter (map string nat); +storage nat; +code {CAR; SIZE; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/merge_comparable_pairs.tz b/tests_python/contracts_011/opcodes/merge_comparable_pairs.tz new file mode 100644 index 000000000000..14fcc73411c7 --- /dev/null +++ b/tests_python/contracts_011/opcodes/merge_comparable_pairs.tz @@ -0,0 +1,14 @@ +# tests that merging comparable pair types works +parameter (set (pair (nat %n) (pair %p (string %s) (int %i)))); +storage nat; +code {UNPAIR; + SWAP; + PUSH nat 3; + COMPARE; + GT; + IF {} + {DROP; + EMPTY_SET (pair nat (pair string int));}; + SIZE; + NIL operation; + PAIR;} diff --git a/tests_python/contracts_011/opcodes/mul.tz b/tests_python/contracts_011/opcodes/mul.tz new file mode 100644 index 000000000000..8432394b526d --- /dev/null +++ b/tests_python/contracts_011/opcodes/mul.tz @@ -0,0 +1,48 @@ +parameter unit ; +storage unit ; +code { CAR ; + DROP ; + # tez-nat, no overflow + PUSH nat 7987 ; + PUSH mutez 10 ; + MUL ; + PUSH mutez 79870 ; + COMPARE ; + ASSERT_EQ ; + # nat-tez, no overflow + PUSH mutez 10 ; + PUSH nat 7987 ; + MUL ; + PUSH mutez 79870 ; + COMPARE ; + ASSERT_EQ ; + # int-int, no overflow + PUSH int 10 ; + PUSH int -7987 ; + MUL ; + PUSH int -79870 ; + COMPARE ; + ASSERT_EQ ; + # int-nat, no overflow + PUSH nat 10 ; + PUSH int -7987 ; + MUL ; + PUSH int -79870 ; + COMPARE ; + ASSERT_EQ ; + # nat-int, no overflow + PUSH int -10 ; + PUSH nat 7987 ; + MUL ; + PUSH int -79870 ; + COMPARE ; + ASSERT_EQ ; + # nat-nat, no overflow + PUSH nat 10 ; + PUSH nat 7987 ; + MUL ; + PUSH nat 79870 ; + COMPARE ; + ASSERT_EQ ; + + UNIT ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/opcodes/mul_bls12_381_fr.tz b/tests_python/contracts_011/opcodes/mul_bls12_381_fr.tz new file mode 100644 index 000000000000..dd201863b034 --- /dev/null +++ b/tests_python/contracts_011/opcodes/mul_bls12_381_fr.tz @@ -0,0 +1,3 @@ +parameter (pair bls12_381_fr bls12_381_fr); +storage (option (bls12_381_fr)); +code {CAR; UNPAIR; MUL; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/mul_bls12_381_g1.tz b/tests_python/contracts_011/opcodes/mul_bls12_381_g1.tz new file mode 100644 index 000000000000..af3f376501da --- /dev/null +++ b/tests_python/contracts_011/opcodes/mul_bls12_381_g1.tz @@ -0,0 +1,3 @@ +parameter (pair bls12_381_g1 bls12_381_fr); +storage (option (bls12_381_g1)); +code {CAR; UNPAIR; MUL; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/mul_bls12_381_g2.tz b/tests_python/contracts_011/opcodes/mul_bls12_381_g2.tz new file mode 100644 index 000000000000..1875e8e3dac8 --- /dev/null +++ b/tests_python/contracts_011/opcodes/mul_bls12_381_g2.tz @@ -0,0 +1,3 @@ +parameter (pair bls12_381_g2 bls12_381_fr); +storage (option (bls12_381_g2)); +code {CAR; UNPAIR; MUL; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/mul_overflow.tz b/tests_python/contracts_011/opcodes/mul_overflow.tz new file mode 100644 index 000000000000..5d2b3a3dcff2 --- /dev/null +++ b/tests_python/contracts_011/opcodes/mul_overflow.tz @@ -0,0 +1,18 @@ +parameter (or unit unit) ; +storage unit ; +code { CAR ; + IF_LEFT + { + PUSH nat 922337203685477580700 ; + PUSH mutez 10 ; + MUL ; # FAILURE + DROP + } + { + PUSH mutez 10 ; + PUSH nat 922337203685477580700 ; + MUL ; # FAILURE + DROP + } ; + + NIL operation ; PAIR } diff --git a/tests_python/contracts_011/opcodes/munch.tz b/tests_python/contracts_011/opcodes/munch.tz new file mode 100644 index 000000000000..7efe43ca092d --- /dev/null +++ b/tests_python/contracts_011/opcodes/munch.tz @@ -0,0 +1,14 @@ +# A contract that accepts bytes in a default entry point and does nothing. +# Useful for testing transfers of arbitrary sizes. +parameter (or (bytes %bytes) + (or (lambda %lambda unit unit) + (or (nat %nat) + (list %list_nat nat)))); +storage unit; +code + { + CDR; # @storage + # == default == # @storage + NIL operation; # list operation : @storage + PAIR; # pair (list operation) @storage + }; diff --git a/tests_python/contracts_011/opcodes/mutez_to_bls12_381_fr.tz b/tests_python/contracts_011/opcodes/mutez_to_bls12_381_fr.tz new file mode 100644 index 000000000000..fefc038474da --- /dev/null +++ b/tests_python/contracts_011/opcodes/mutez_to_bls12_381_fr.tz @@ -0,0 +1,14 @@ +parameter mutez; +storage bls12_381_fr; +code { + CAR; + PUSH mutez 1; + SWAP; + EDIV; + ASSERT_SOME; + CAR; + PUSH bls12_381_fr 1; + MUL; + NIL operation; + PAIR; + }; \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/neg.tz b/tests_python/contracts_011/opcodes/neg.tz new file mode 100644 index 000000000000..9cedf765f1b2 --- /dev/null +++ b/tests_python/contracts_011/opcodes/neg.tz @@ -0,0 +1,8 @@ +parameter (or int nat); +storage int; +code { + CAR; + IF_LEFT {NEG} {NEG}; + NIL operation; + PAIR + } diff --git a/tests_python/contracts_011/opcodes/neg_bls12_381_fr.tz b/tests_python/contracts_011/opcodes/neg_bls12_381_fr.tz new file mode 100644 index 000000000000..cd9b0a945cc5 --- /dev/null +++ b/tests_python/contracts_011/opcodes/neg_bls12_381_fr.tz @@ -0,0 +1,3 @@ +parameter bls12_381_fr; +storage (option (bls12_381_fr)); +code {CAR; NEG; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/neg_bls12_381_g1.tz b/tests_python/contracts_011/opcodes/neg_bls12_381_g1.tz new file mode 100644 index 000000000000..60806deada20 --- /dev/null +++ b/tests_python/contracts_011/opcodes/neg_bls12_381_g1.tz @@ -0,0 +1,3 @@ +parameter bls12_381_g1; +storage (option (bls12_381_g1)); +code {CAR; NEG; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/neg_bls12_381_g2.tz b/tests_python/contracts_011/opcodes/neg_bls12_381_g2.tz new file mode 100644 index 000000000000..593052546258 --- /dev/null +++ b/tests_python/contracts_011/opcodes/neg_bls12_381_g2.tz @@ -0,0 +1,3 @@ +parameter bls12_381_g2; +storage (option (bls12_381_g2)); +code {CAR; NEG; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/none.tz b/tests_python/contracts_011/opcodes/none.tz new file mode 100644 index 000000000000..473a288b4926 --- /dev/null +++ b/tests_python/contracts_011/opcodes/none.tz @@ -0,0 +1,3 @@ +parameter unit; +storage (option nat); +code { DROP; NONE nat; NIL operation; PAIR; }; diff --git a/tests_python/contracts_011/opcodes/noop.tz b/tests_python/contracts_011/opcodes/noop.tz new file mode 100644 index 000000000000..bd19da15cf49 --- /dev/null +++ b/tests_python/contracts_011/opcodes/noop.tz @@ -0,0 +1,3 @@ +parameter unit; +storage unit; +code {CDR; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/not.tz b/tests_python/contracts_011/opcodes/not.tz new file mode 100644 index 000000000000..f89394072d2a --- /dev/null +++ b/tests_python/contracts_011/opcodes/not.tz @@ -0,0 +1,3 @@ +parameter bool; +storage (option bool); +code {CAR; NOT; SOME; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/not_binary.tz b/tests_python/contracts_011/opcodes/not_binary.tz new file mode 100644 index 000000000000..c1e0f97979d7 --- /dev/null +++ b/tests_python/contracts_011/opcodes/not_binary.tz @@ -0,0 +1,12 @@ +parameter (or int nat); +storage (option int); +code { CAR; + IF_LEFT + { + NOT; + } + { + NOT; + } ; + SOME; NIL operation ; PAIR + } diff --git a/tests_python/contracts_011/opcodes/or.tz b/tests_python/contracts_011/opcodes/or.tz new file mode 100644 index 000000000000..89d533c4483e --- /dev/null +++ b/tests_python/contracts_011/opcodes/or.tz @@ -0,0 +1,3 @@ +parameter (pair bool bool); +storage (option bool); +code {CAR; DUP; CAR; SWAP; CDR; OR; SOME; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/or_binary.tz b/tests_python/contracts_011/opcodes/or_binary.tz new file mode 100644 index 000000000000..a31f109827ef --- /dev/null +++ b/tests_python/contracts_011/opcodes/or_binary.tz @@ -0,0 +1,9 @@ +parameter (pair nat nat); +storage (option nat); +# This contract takes a pair of natural numbers as argument and +# stores the result of their binary OR. +code { CAR; + UNPAIR; + OR; + SOME; NIL operation; PAIR + } diff --git a/tests_python/contracts_011/opcodes/originate_big_map.tz b/tests_python/contracts_011/opcodes/originate_big_map.tz new file mode 100644 index 000000000000..97d7db669fe8 --- /dev/null +++ b/tests_python/contracts_011/opcodes/originate_big_map.tz @@ -0,0 +1,3 @@ +parameter (big_map int int); +storage (big_map int int); +code { CAR; NIL operation; PAIR } diff --git a/tests_python/contracts_011/opcodes/packunpack.tz b/tests_python/contracts_011/opcodes/packunpack.tz new file mode 100644 index 000000000000..ad313fa8aee6 --- /dev/null +++ b/tests_python/contracts_011/opcodes/packunpack.tz @@ -0,0 +1,6 @@ +parameter (pair (pair (pair string (list int)) (set nat)) bytes) ; +storage unit ; +code { CAR ; UNPAIR ; DIP { DUP } ; + PACK ; ASSERT_CMPEQ ; + UNPACK (pair (pair string (list int)) (set nat)) ; ASSERT_SOME ; DROP ; + UNIT ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/opcodes/packunpack_rev.tz b/tests_python/contracts_011/opcodes/packunpack_rev.tz new file mode 100644 index 000000000000..9c94cd68dcc1 --- /dev/null +++ b/tests_python/contracts_011/opcodes/packunpack_rev.tz @@ -0,0 +1,43 @@ +parameter (pair + int + nat + string + bytes + mutez + bool + key_hash + timestamp address); +storage unit ; +code { CAR; + # Check the int + DUP; CAR; DIP { UNPAIR; }; PACK; UNPACK int; ASSERT_SOME; ASSERT_CMPEQ; + # Check the nat + DUP; CAR; DIP { UNPAIR; }; PACK; UNPACK nat; ASSERT_SOME; ASSERT_CMPEQ; + # Check the string + DUP; CAR; DIP { UNPAIR; }; PACK; UNPACK string; ASSERT_SOME; ASSERT_CMPEQ; + # Check the bytes + DUP; CAR; DIP { UNPAIR; }; PACK; UNPACK bytes; ASSERT_SOME; ASSERT_CMPEQ; + # Check the mutez + DUP; CAR; DIP { UNPAIR; }; PACK; UNPACK mutez; ASSERT_SOME; ASSERT_CMPEQ; + # Check the bool + DUP; CAR; DIP { UNPAIR; }; PACK; UNPACK bool; ASSERT_SOME; ASSERT_CMPEQ; + # Check the key_hash + DUP; CAR; DIP { UNPAIR; }; PACK; UNPACK key_hash; ASSERT_SOME; ASSERT_CMPEQ; + # Check the timestamp + DUP; CAR; DIP { UNPAIR; }; PACK; UNPACK timestamp; ASSERT_SOME; ASSERT_CMPEQ; + # Check the address + DUP; PACK; UNPACK address; ASSERT_SOME; ASSERT_CMPEQ; + + # Assert failure modes of unpack + PUSH int 0; PACK; UNPACK nat; ASSERT_SOME; DROP; + PUSH int -1; PACK; UNPACK nat; ASSERT_NONE; + + # Try deserializing invalid byte sequence (no magic number) + PUSH bytes 0x; UNPACK nat; ASSERT_NONE; + PUSH bytes 0x04; UNPACK nat; ASSERT_NONE; + + # Assert failure for byte sequences that do not correspond to + # any micheline value + PUSH bytes 0x05; UNPACK nat; ASSERT_NONE; + + UNIT ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/opcodes/packunpack_rev_cty.tz b/tests_python/contracts_011/opcodes/packunpack_rev_cty.tz new file mode 100644 index 000000000000..7ca7ca64a3c3 --- /dev/null +++ b/tests_python/contracts_011/opcodes/packunpack_rev_cty.tz @@ -0,0 +1,31 @@ +parameter (pair key unit signature (option signature) (list unit) (set bool) (pair int int) (or key_hash timestamp) (map int string) (lambda string bytes)); +storage unit ; +# for each uncomparable type t (we take an arbitrary parameter for +# parametric data-types e.g. pair, list), +# that is packable (which excludes big_map, operation, and contract) +# this contract receives a parameter v_t. +# it verifies that pack v_t == pack (unpack (pack v_t)) +code { CAR; + # packable uncomparable types + # checking: key + DUP; CAR; DIP { UNPAIR; }; PACK; DIP { PACK; UNPACK key; ASSERT_SOME; PACK; }; ASSERT_CMPEQ; + # checking: unit + DUP; CAR; DIP { UNPAIR; }; PACK; DIP { PACK; UNPACK unit; ASSERT_SOME; PACK; }; ASSERT_CMPEQ; + # checking: signature + DUP; CAR; DIP { UNPAIR; }; PACK; DIP { PACK; UNPACK (signature); ASSERT_SOME; PACK; }; ASSERT_CMPEQ; + # checking: option signature + DUP; CAR; DIP { UNPAIR; }; PACK; DIP { PACK; UNPACK (option signature); ASSERT_SOME; PACK; }; ASSERT_CMPEQ; + # checking: list unit + DUP; CAR; DIP { UNPAIR; }; PACK; DIP { PACK; UNPACK (list unit); ASSERT_SOME; PACK; }; ASSERT_CMPEQ; + # checking: set bool + DUP; CAR; DIP { UNPAIR; }; PACK; DIP { PACK; UNPACK (set bool); ASSERT_SOME; PACK; }; ASSERT_CMPEQ; + # checking: pair int int + DUP; CAR; DIP { UNPAIR; }; PACK; DIP { PACK; UNPACK (pair int int); ASSERT_SOME; PACK; }; ASSERT_CMPEQ; + # checking: or key_hash timestamp + DUP; CAR; DIP { UNPAIR; }; PACK; DIP { PACK; UNPACK (or key_hash timestamp); ASSERT_SOME; PACK; }; ASSERT_CMPEQ; + # checking: map int string + DUP; CAR; DIP { UNPAIR; }; PACK; DIP { PACK; UNPACK (map int string); ASSERT_SOME; PACK; }; ASSERT_CMPEQ; + # checking: lambda string bytes + DUP; PACK; DIP { PACK; UNPACK (lambda string bytes); ASSERT_SOME; PACK; }; ASSERT_CMPEQ; + + UNIT ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/opcodes/pair_id.tz b/tests_python/contracts_011/opcodes/pair_id.tz new file mode 100644 index 000000000000..3bfedf2d8cdf --- /dev/null +++ b/tests_python/contracts_011/opcodes/pair_id.tz @@ -0,0 +1,3 @@ +parameter (pair bool bool); +storage (option (pair bool bool)); +code {CAR; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/pairing_check.tz b/tests_python/contracts_011/opcodes/pairing_check.tz new file mode 100644 index 000000000000..3b829f315c05 --- /dev/null +++ b/tests_python/contracts_011/opcodes/pairing_check.tz @@ -0,0 +1,3 @@ +parameter (list (pair bls12_381_g1 bls12_381_g2)); +storage (option bool); +code {CAR; PAIRING_CHECK; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/pexec.tz b/tests_python/contracts_011/opcodes/pexec.tz new file mode 100644 index 000000000000..eab0c71b4f59 --- /dev/null +++ b/tests_python/contracts_011/opcodes/pexec.tz @@ -0,0 +1,6 @@ +parameter nat; +storage nat; +code { + LAMBDA (pair nat nat) nat + {UNPAIR ; ADD}; + SWAP; UNPAIR ; DIP { APPLY } ; EXEC ; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/pexec_2.tz b/tests_python/contracts_011/opcodes/pexec_2.tz new file mode 100644 index 000000000000..d64f7442f50e --- /dev/null +++ b/tests_python/contracts_011/opcodes/pexec_2.tz @@ -0,0 +1,11 @@ +parameter int; +storage (list int); +code { + UNPAIR @p @s ; # p :: s + LAMBDA (pair int (pair int int)) int + { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL }; # l :: p :: s + SWAP ; APPLY ; # l :: s + PUSH int 3 ; APPLY ; # l :: s + SWAP ; MAP { DIP { DUP } ; EXEC } ; # s :: l + DIP { DROP } ; # s + NIL operation; PAIR }; diff --git a/tests_python/contracts_011/opcodes/proxy.tz b/tests_python/contracts_011/opcodes/proxy.tz new file mode 100644 index 000000000000..185bbcd321cc --- /dev/null +++ b/tests_python/contracts_011/opcodes/proxy.tz @@ -0,0 +1,13 @@ +/* This proxy contract transfers the received amount to the contract given as parameter. + It is used to test the SOURCE and SENDER opcodes; see source.tz and sender.tz. */ +parameter (contract unit) ; +storage unit ; +code{ + UNPAIR; + AMOUNT ; + UNIT ; + TRANSFER_TOKENS; + DIP {NIL operation} ; + CONS; + PAIR + } \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/ret_int.tz b/tests_python/contracts_011/opcodes/ret_int.tz new file mode 100644 index 000000000000..720a99568e96 --- /dev/null +++ b/tests_python/contracts_011/opcodes/ret_int.tz @@ -0,0 +1,3 @@ +parameter unit; +storage (option nat); +code {DROP; PUSH nat 300; SOME; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/reverse.tz b/tests_python/contracts_011/opcodes/reverse.tz new file mode 100644 index 000000000000..5a851f3e29d0 --- /dev/null +++ b/tests_python/contracts_011/opcodes/reverse.tz @@ -0,0 +1,5 @@ +parameter (list string); +storage (list string); +code { CAR; NIL string; SWAP; + ITER {CONS}; + NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/reverse_loop.tz b/tests_python/contracts_011/opcodes/reverse_loop.tz new file mode 100644 index 000000000000..d8117135c984 --- /dev/null +++ b/tests_python/contracts_011/opcodes/reverse_loop.tz @@ -0,0 +1,5 @@ +parameter (list string); +storage (list string); +code { CAR; NIL string; SWAP; PUSH bool True; + LOOP { IF_CONS {SWAP; DIP{CONS}; PUSH bool True} {NIL string; PUSH bool False}}; + DROP; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/sapling_empty_state.tz b/tests_python/contracts_011/opcodes/sapling_empty_state.tz new file mode 100644 index 000000000000..6a568da92dd3 --- /dev/null +++ b/tests_python/contracts_011/opcodes/sapling_empty_state.tz @@ -0,0 +1,3 @@ +parameter unit; +storage (sapling_state 8); +code { DROP; SAPLING_EMPTY_STATE 8; NIL operation; PAIR; }; diff --git a/tests_python/contracts_011/opcodes/self.tz b/tests_python/contracts_011/opcodes/self.tz new file mode 100644 index 000000000000..d96457fd1331 --- /dev/null +++ b/tests_python/contracts_011/opcodes/self.tz @@ -0,0 +1,3 @@ +parameter unit ; +storage address ; +code { DROP ; SELF ; ADDRESS ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/opcodes/self_address.tz b/tests_python/contracts_011/opcodes/self_address.tz new file mode 100644 index 000000000000..73f4779bab24 --- /dev/null +++ b/tests_python/contracts_011/opcodes/self_address.tz @@ -0,0 +1,11 @@ +parameter unit; +storage unit; +code { + DROP; + LAMBDA unit address { DROP; SELF_ADDRESS }; + UNIT; + EXEC; + SELF; ADDRESS; + ASSERT_CMPEQ; + UNIT; NIL operation; PAIR + } diff --git a/tests_python/contracts_011/opcodes/self_with_default_entrypoint.tz b/tests_python/contracts_011/opcodes/self_with_default_entrypoint.tz new file mode 100644 index 000000000000..47f848c0d5a1 --- /dev/null +++ b/tests_python/contracts_011/opcodes/self_with_default_entrypoint.tz @@ -0,0 +1,19 @@ +parameter (or (or (nat %A) (bool %B)) (or %maybe_C (unit %default) (string %C))); +storage unit; +code { + DROP; + SELF; DROP; + # Refers to entrypoint A of the current contract. + SELF %A; DROP; + # Refers to the default entry of the current contract + SELF %default; PACK; + # "SELF" w/o annotation also refers to the default + # entry of the current contract. Internally, they are equal. + SELF; PACK; ASSERT_CMPEQ; + # The following instruction would not typecheck: + # SELF %D, + # since there is no entrypoint D. + UNIT; + NIL operation; + PAIR; + } diff --git a/tests_python/contracts_011/opcodes/self_with_entrypoint.tz b/tests_python/contracts_011/opcodes/self_with_entrypoint.tz new file mode 100644 index 000000000000..ea6f8e1898e2 --- /dev/null +++ b/tests_python/contracts_011/opcodes/self_with_entrypoint.tz @@ -0,0 +1,26 @@ +parameter (or (or (nat %A) (bool %B)) (or %maybe_C (unit %Z) (string %C))); +storage unit; +code { + DROP; + # Refers to entrypoint A of the current contract. + SELF %A; PACK @Apacked; + # Refers to the default entry of the current contract + SELF %default; PACK @defpacked; DUP; DIP { SWAP }; ASSERT_CMPNEQ; + # "SELF" w/o annotation also refers to the default + # entry of the current contract + SELF; PACK @selfpacked; ASSERT_CMPEQ; + + # Verify the types of the different entrypoints. CAST is noop + # if its argument is convertible with the type of the top of + # the stack. + SELF %A; CAST (contract nat); DROP; + SELF %B; CAST (contract bool); DROP; + SELF %maybe_C; CAST (contract (or (unit) (string))); DROP; + SELF %Z; CAST (contract unit); DROP; + SELF; CAST (contract (or (or (nat %A) (bool %B)) (or %maybe_C (unit %Z) (string %C)))); DROP; + SELF %default; CAST (contract (or (or (nat %A) (bool %B)) (or %maybe_C (unit %Z) (string %C)))); DROP; + + UNIT; + NIL operation; + PAIR; + } diff --git a/tests_python/contracts_011/opcodes/sender.tz b/tests_python/contracts_011/opcodes/sender.tz new file mode 100644 index 000000000000..fb174179aca5 --- /dev/null +++ b/tests_python/contracts_011/opcodes/sender.tz @@ -0,0 +1,8 @@ +parameter unit ; +storage address ; +code{ + DROP ; + SENDER; + NIL operation ; + PAIR + } diff --git a/tests_python/contracts_011/opcodes/set_car.tz b/tests_python/contracts_011/opcodes/set_car.tz new file mode 100644 index 000000000000..460b33856743 --- /dev/null +++ b/tests_python/contracts_011/opcodes/set_car.tz @@ -0,0 +1,3 @@ +parameter string; +storage (pair (string %s) (nat %n)); +code { DUP; CDR; DIP{CAR}; SET_CAR %s; NIL operation; PAIR }; diff --git a/tests_python/contracts_011/opcodes/set_cdr.tz b/tests_python/contracts_011/opcodes/set_cdr.tz new file mode 100644 index 000000000000..d725756bbcaa --- /dev/null +++ b/tests_python/contracts_011/opcodes/set_cdr.tz @@ -0,0 +1,3 @@ +parameter nat; +storage (pair (string %s) (nat %n)); +code { DUP; CDR; DIP{CAR}; SET_CDR %n; NIL operation; PAIR }; diff --git a/tests_python/contracts_011/opcodes/set_delegate.tz b/tests_python/contracts_011/opcodes/set_delegate.tz new file mode 100644 index 000000000000..a7e051e50494 --- /dev/null +++ b/tests_python/contracts_011/opcodes/set_delegate.tz @@ -0,0 +1,9 @@ +parameter (option key_hash); +storage unit; +code { + UNPAIR; + SET_DELEGATE; + DIP {NIL operation}; + CONS; + PAIR + } diff --git a/tests_python/contracts_011/opcodes/set_id.tz b/tests_python/contracts_011/opcodes/set_id.tz new file mode 100644 index 000000000000..ede301b0e979 --- /dev/null +++ b/tests_python/contracts_011/opcodes/set_id.tz @@ -0,0 +1,3 @@ +parameter (set string); +storage (set string); +code { CAR ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/opcodes/set_iter.tz b/tests_python/contracts_011/opcodes/set_iter.tz new file mode 100644 index 000000000000..55d8ae34aba7 --- /dev/null +++ b/tests_python/contracts_011/opcodes/set_iter.tz @@ -0,0 +1,3 @@ +parameter (set int); +storage int; +code { CAR; PUSH int 0; SWAP; ITER { ADD }; NIL operation; PAIR } diff --git a/tests_python/contracts_011/opcodes/set_member.tz b/tests_python/contracts_011/opcodes/set_member.tz new file mode 100644 index 000000000000..ae97cce14345 --- /dev/null +++ b/tests_python/contracts_011/opcodes/set_member.tz @@ -0,0 +1,3 @@ +parameter string; +storage (pair (set string) (option bool)); +code {DUP; DUP; CAR; DIP{CDAR}; MEM; SOME; DIP {CDAR}; SWAP; PAIR ; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/set_size.tz b/tests_python/contracts_011/opcodes/set_size.tz new file mode 100644 index 000000000000..aa055cb02192 --- /dev/null +++ b/tests_python/contracts_011/opcodes/set_size.tz @@ -0,0 +1,3 @@ +parameter (set int); +storage nat; +code {CAR; SIZE; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/sha3.tz b/tests_python/contracts_011/opcodes/sha3.tz new file mode 100644 index 000000000000..3ce8cde000e3 --- /dev/null +++ b/tests_python/contracts_011/opcodes/sha3.tz @@ -0,0 +1,8 @@ +storage (option bytes); +parameter bytes; +code + { + CAR; + SHA3; SOME; + NIL operation; PAIR + } diff --git a/tests_python/contracts_011/opcodes/shifts.tz b/tests_python/contracts_011/opcodes/shifts.tz new file mode 100644 index 000000000000..71964750c0b8 --- /dev/null +++ b/tests_python/contracts_011/opcodes/shifts.tz @@ -0,0 +1,18 @@ +parameter (or (pair nat nat) (pair nat nat)); +storage (option nat); +# this contract takes either (Left a b) and stores (a << b) +# or (Right a b) and stores (a >> b). +# i.e., in the first case, the first component shifted to the left by +# the second, and the second case, component shifted to the right by +# the second. +code { CAR; + IF_LEFT { + UNPAIR; LSL; + } + { + UNPAIR; LSR; + }; + SOME; + NIL operation; + PAIR; + }; diff --git a/tests_python/contracts_011/opcodes/slice.tz b/tests_python/contracts_011/opcodes/slice.tz new file mode 100644 index 000000000000..3461bb5533d1 --- /dev/null +++ b/tests_python/contracts_011/opcodes/slice.tz @@ -0,0 +1,5 @@ +parameter (pair nat nat); +storage (option string); +code { UNPAIR; SWAP; + IF_SOME {SWAP; UNPAIR; SLICE;} {DROP; NONE string;}; + NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/slice_bytes.tz b/tests_python/contracts_011/opcodes/slice_bytes.tz new file mode 100644 index 000000000000..c0f60f358765 --- /dev/null +++ b/tests_python/contracts_011/opcodes/slice_bytes.tz @@ -0,0 +1,5 @@ +parameter (pair nat nat); +storage (option bytes); +code { UNPAIR; SWAP; + IF_SOME {SWAP; UNPAIR; SLICE;} {DROP; NONE bytes;}; + NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/slices.tz b/tests_python/contracts_011/opcodes/slices.tz new file mode 100644 index 000000000000..fa76827261c0 --- /dev/null +++ b/tests_python/contracts_011/opcodes/slices.tz @@ -0,0 +1,11 @@ +parameter (pair bytes signature) ; +storage key ; +code { DUP ; + CAAR ; DUP ; SIZE ; PUSH nat 128 ; SWAP ; SUB ; ISNAT ; IF_SOME {} { FAIL } ; + PUSH nat 128 ; SLICE @payload ; ASSERT_SOME ; + DUP ; DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 0 ; SLICE ; ASSERT_SOME } ; SHA256 ; ASSERT_CMPEQ } ; + DUP ; DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 32 ; SLICE ; ASSERT_SOME } ; BLAKE2B ; ASSERT_CMPEQ } ; + DUP ; DIP { DIP { DUP ; CAAR ; PUSH nat 64 ; PUSH nat 64 ; SLICE ; ASSERT_SOME } ; SHA512 ; ASSERT_CMPEQ } ; + DIP { DUP ; CDR ; DIP { DUP ; CADR }} ; SWAP ; DIP { SWAP } ; CHECK_SIGNATURE ; ASSERT ; + CDR ; DUP ; HASH_KEY ; IMPLICIT_ACCOUNT ; BALANCE ; UNIT ; TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS ; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/source.tz b/tests_python/contracts_011/opcodes/source.tz new file mode 100644 index 000000000000..fc3c642027d3 --- /dev/null +++ b/tests_python/contracts_011/opcodes/source.tz @@ -0,0 +1,10 @@ +parameter unit ; + +storage address ; + +code{ + DROP ; + SOURCE; + NIL operation ; + PAIR + } \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/split_bytes.tz b/tests_python/contracts_011/opcodes/split_bytes.tz new file mode 100644 index 000000000000..f3b623b3c4b3 --- /dev/null +++ b/tests_python/contracts_011/opcodes/split_bytes.tz @@ -0,0 +1,16 @@ +parameter bytes ; +storage (list bytes) ; +code { UNPAIR ; + DIP { NIL bytes ; SWAP ; ITER { CONS } } ; + DUP ; SIZE ; PUSH nat 0 ; CMPNEQ ; + DIP { PUSH @index nat 0 } ; + LOOP + { PAIR ; DUP ; + DIP { UNPAIR ; DIP { PUSH nat 1 } ; SLICE ; ASSERT_SOME ; CONS @storage } ; + UNPAIR ; + PUSH nat 1 ; ADD @index ; + DUP ; DIP { DIP { DUP } ; SWAP ; SIZE ; CMPNEQ } ; SWAP ; + } ; + DROP ; DROP ; + NIL bytes ; SWAP ; ITER { CONS } ; + NIL operation ; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/split_string.tz b/tests_python/contracts_011/opcodes/split_string.tz new file mode 100644 index 000000000000..909ba604742d --- /dev/null +++ b/tests_python/contracts_011/opcodes/split_string.tz @@ -0,0 +1,16 @@ +parameter string ; +storage (list string) ; +code { UNPAIR ; + DIP { NIL string ; SWAP ; ITER { CONS } } ; + DUP ; SIZE ; PUSH nat 0 ; CMPNEQ ; + DIP { PUSH @index nat 0 } ; + LOOP + { PAIR ; DUP ; + DIP { UNPAIR ; DIP { PUSH nat 1 } ; SLICE ; ASSERT_SOME ; CONS @storage } ; + UNPAIR ; + PUSH nat 1 ; ADD @index ; + DUP ; DIP { DIP { DUP } ; SWAP ; SIZE ; CMPNEQ } ; SWAP ; + } ; + DROP ; DROP ; + NIL string ; SWAP ; ITER { CONS } ; + NIL operation ; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/store_bls12_381_fr.tz b/tests_python/contracts_011/opcodes/store_bls12_381_fr.tz new file mode 100644 index 000000000000..b40aa9b4ad1c --- /dev/null +++ b/tests_python/contracts_011/opcodes/store_bls12_381_fr.tz @@ -0,0 +1,3 @@ +parameter bls12_381_fr; +storage (option (bls12_381_fr)); +code {CAR; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/store_bls12_381_g1.tz b/tests_python/contracts_011/opcodes/store_bls12_381_g1.tz new file mode 100644 index 000000000000..1bc148f54282 --- /dev/null +++ b/tests_python/contracts_011/opcodes/store_bls12_381_g1.tz @@ -0,0 +1,3 @@ +parameter bls12_381_g1; +storage (option (bls12_381_g1)); +code {CAR; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/store_bls12_381_g2.tz b/tests_python/contracts_011/opcodes/store_bls12_381_g2.tz new file mode 100644 index 000000000000..b64087706265 --- /dev/null +++ b/tests_python/contracts_011/opcodes/store_bls12_381_g2.tz @@ -0,0 +1,3 @@ +parameter bls12_381_g2; +storage (option (bls12_381_g2)); +code {CAR; SOME; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/store_input.tz b/tests_python/contracts_011/opcodes/store_input.tz new file mode 100644 index 000000000000..4eee565ca2e9 --- /dev/null +++ b/tests_python/contracts_011/opcodes/store_input.tz @@ -0,0 +1,3 @@ +parameter string; +storage string; +code {CAR; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/store_now.tz b/tests_python/contracts_011/opcodes/store_now.tz new file mode 100644 index 000000000000..1a868ac06f14 --- /dev/null +++ b/tests_python/contracts_011/opcodes/store_now.tz @@ -0,0 +1,3 @@ +parameter unit; +storage timestamp; +code {DROP; NOW; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/str_id.tz b/tests_python/contracts_011/opcodes/str_id.tz new file mode 100644 index 000000000000..f9e0710c328f --- /dev/null +++ b/tests_python/contracts_011/opcodes/str_id.tz @@ -0,0 +1,3 @@ +parameter string; +storage (option string); +code { CAR ; SOME ; NIL operation ; PAIR }; diff --git a/tests_python/contracts_011/opcodes/sub_timestamp_delta.tz b/tests_python/contracts_011/opcodes/sub_timestamp_delta.tz new file mode 100644 index 000000000000..f154e952414f --- /dev/null +++ b/tests_python/contracts_011/opcodes/sub_timestamp_delta.tz @@ -0,0 +1,3 @@ +parameter (pair timestamp int); +storage timestamp; +code { CAR; DUP; CAR; DIP{CDR}; SUB; NIL operation; PAIR} diff --git a/tests_python/contracts_011/opcodes/subset.tz b/tests_python/contracts_011/opcodes/subset.tz new file mode 100644 index 000000000000..a16ef1695cb2 --- /dev/null +++ b/tests_python/contracts_011/opcodes/subset.tz @@ -0,0 +1,12 @@ +parameter (pair (set string) (set string)); +storage bool; +code { CAR; DUP; CDR; DIP{CAR}; # Unpack lists + PUSH bool True; + PAIR; SWAP; # Setup accumulator + ITER { DIP{ DUP; DUP; CDR; + DIP{CAR; DIP{CDR}}}; + MEM; # Check membership + AND; # Combine accumulator and input + PAIR}; + CAR; # Get the accumulator value + NIL operation; PAIR} # Calling convention diff --git a/tests_python/contracts_011/opcodes/tez_add_sub.tz b/tests_python/contracts_011/opcodes/tez_add_sub.tz new file mode 100644 index 000000000000..39eba1d16275 --- /dev/null +++ b/tests_python/contracts_011/opcodes/tez_add_sub.tz @@ -0,0 +1,5 @@ +parameter (pair mutez mutez); +storage (option (pair mutez mutez)); +code {CAR; DUP; DUP; CAR; DIP{CDR}; ADD; + DIP{DUP; CAR; DIP{CDR}; SUB}; + PAIR; SOME; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/ticket_bad.tz b/tests_python/contracts_011/opcodes/ticket_bad.tz new file mode 100644 index 000000000000..e183ac5278b5 --- /dev/null +++ b/tests_python/contracts_011/opcodes/ticket_bad.tz @@ -0,0 +1,5 @@ +# Although this contract is correctly typed, originating it with a forged +# ticket should be refused +parameter unit; +storage (ticket nat); +code { CDR ; NIL operation ; PAIR } diff --git a/tests_python/contracts_011/opcodes/ticket_big_store.tz b/tests_python/contracts_011/opcodes/ticket_big_store.tz new file mode 100644 index 000000000000..6d1de845235e --- /dev/null +++ b/tests_python/contracts_011/opcodes/ticket_big_store.tz @@ -0,0 +1,3 @@ +parameter nat ; +storage (big_map unit (ticket nat)); +code { UNPAIR ; PUSH nat 1 ; SWAP ; TICKET ; SOME ; UNIT ; UPDATE ; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/opcodes/ticket_join.tz b/tests_python/contracts_011/opcodes/ticket_join.tz new file mode 100644 index 000000000000..3aef469a48c5 --- /dev/null +++ b/tests_python/contracts_011/opcodes/ticket_join.tz @@ -0,0 +1,7 @@ +parameter (ticket nat); +storage (option (ticket nat)); +code { UNPAIR ; SWAP ; + IF_NONE {} { PAIR ; JOIN_TICKETS ; ASSERT_SOME } ; + SOME ; + NIL operation ; + PAIR } diff --git a/tests_python/contracts_011/opcodes/ticket_read.tz b/tests_python/contracts_011/opcodes/ticket_read.tz new file mode 100644 index 000000000000..c41176a5fee0 --- /dev/null +++ b/tests_python/contracts_011/opcodes/ticket_read.tz @@ -0,0 +1,8 @@ +parameter (ticket nat); +storage address; +code { CAR ; + READ_TICKET ; DIP { DROP } ; UNPAIR ; DIP { UNPAIR } ; + DIIP { PUSH nat 1 ; ASSERT_CMPEQ } ; + DIP { PUSH nat 42 ; ASSERT_CMPEQ } ; + NIL operation ; + PAIR } diff --git a/tests_python/contracts_011/opcodes/ticket_split.tz b/tests_python/contracts_011/opcodes/ticket_split.tz new file mode 100644 index 000000000000..a2587beb717e --- /dev/null +++ b/tests_python/contracts_011/opcodes/ticket_split.tz @@ -0,0 +1,11 @@ +parameter (ticket nat) ; +storage unit; +code + { CAR ; + PUSH (pair nat nat) (Pair 1 2) ; SWAP; + SPLIT_TICKET; ASSERT_SOME; UNPAIR; + READ_TICKET; CDDR; PUSH nat 1; ASSERT_CMPEQ; + DROP; + READ_TICKET; CDDR; PUSH nat 2; ASSERT_CMPEQ; + DROP; + UNIT ; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/opcodes/ticket_store-2.tz b/tests_python/contracts_011/opcodes/ticket_store-2.tz new file mode 100644 index 000000000000..cab3dd79d012 --- /dev/null +++ b/tests_python/contracts_011/opcodes/ticket_store-2.tz @@ -0,0 +1,3 @@ +parameter (option (ticket nat)) ; +storage (option (ticket nat)); +code { CAR ; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/opcodes/ticket_store.tz b/tests_python/contracts_011/opcodes/ticket_store.tz new file mode 100644 index 000000000000..926a04aa1e88 --- /dev/null +++ b/tests_python/contracts_011/opcodes/ticket_store.tz @@ -0,0 +1,3 @@ +parameter (ticket nat) ; +storage (option (ticket nat)); +code { CAR ; SOME ; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/opcodes/ticketer-2.tz b/tests_python/contracts_011/opcodes/ticketer-2.tz new file mode 100644 index 000000000000..bce940ccabe2 --- /dev/null +++ b/tests_python/contracts_011/opcodes/ticketer-2.tz @@ -0,0 +1,9 @@ +parameter (pair (pair address nat) nat) ; +storage unit; +code { CAR ; UNPAIR ; UNPAIR ; + CONTRACT (ticket nat) ; ASSERT_SOME ; + DIP { TICKET } ; + SWAP ; DIP { PUSH mutez 0 } ; + TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS ; + UNIT ; SWAP ; PAIR } diff --git a/tests_python/contracts_011/opcodes/ticketer.tz b/tests_python/contracts_011/opcodes/ticketer.tz new file mode 100644 index 000000000000..c8ec4565398a --- /dev/null +++ b/tests_python/contracts_011/opcodes/ticketer.tz @@ -0,0 +1,10 @@ +parameter address; +storage nat; +code { UNPAIR ; DIP { DUP } ; + SWAP ; + PUSH nat 1 ; SWAP ; + TICKET ; + DIP { CONTRACT (ticket nat) ; ASSERT_SOME ; PUSH mutez 0 } ; + TRANSFER_TOKENS ; + NIL operation ; SWAP ; CONS ; + PAIR } diff --git a/tests_python/contracts_011/opcodes/transfer_amount.tz b/tests_python/contracts_011/opcodes/transfer_amount.tz new file mode 100644 index 000000000000..973c64f04dcc --- /dev/null +++ b/tests_python/contracts_011/opcodes/transfer_amount.tz @@ -0,0 +1,3 @@ +parameter unit; +storage mutez; +code { DROP; AMOUNT; NIL operation; PAIR }; diff --git a/tests_python/contracts_011/opcodes/transfer_tokens.tz b/tests_python/contracts_011/opcodes/transfer_tokens.tz new file mode 100644 index 000000000000..599b4dae180f --- /dev/null +++ b/tests_python/contracts_011/opcodes/transfer_tokens.tz @@ -0,0 +1,5 @@ +parameter (contract unit); +storage unit; +code { CAR; DIP{UNIT}; PUSH mutez 100000000; UNIT; + TRANSFER_TOKENS; + NIL operation; SWAP; CONS; PAIR}; diff --git a/tests_python/contracts_011/opcodes/uncomb.tz b/tests_python/contracts_011/opcodes/uncomb.tz new file mode 100644 index 000000000000..84c3ced7ca9c --- /dev/null +++ b/tests_python/contracts_011/opcodes/uncomb.tz @@ -0,0 +1,8 @@ +parameter (pair nat nat nat); +storage nat; +code { CAR ; + UNPAIR 3 ; + PUSH nat 100 ; MUL ; + SWAP ; PUSH nat 10 ; MUL ; + ADD ; ADD ; + NIL operation ; PAIR ; } diff --git a/tests_python/contracts_011/opcodes/unpair.tz b/tests_python/contracts_011/opcodes/unpair.tz new file mode 100644 index 000000000000..b45f30a03d38 --- /dev/null +++ b/tests_python/contracts_011/opcodes/unpair.tz @@ -0,0 +1,71 @@ +parameter (unit :param_unit); +storage (unit :u1); +code { DROP ; + + # No annotation + UNIT; UNIT; PAIR; UNPAIR; DROP 2; + + # Variable annotations are overriden by UNPAIR + UNIT @b; UNIT @a; PAIR; UNPAIR @c @d; DROP 2; + + UNIT @b; UNIT @a; PAIR %@ %@; + DUP; UNPAIR %a %b; DROP 2; + DUP; UNPAIR % %b; DROP 2; + DUP; UNPAIR %a %; DROP 2; + DUP; UNPAIR % %; DROP 2; + DUP; UNPAIR %a; DROP 2; + DUP; UNPAIR %; DROP 2; + DUP; UNPAIR; DROP 2; + DUP; UNPAIR %a %b @a @b; DROP 2; + DUP; UNPAIR @a @b %a %b; DROP 2; + DUP; UNPAIR @a @% %a %b; DROP 2; + DUP; UNPAIR @% @% %a %b; DROP 2; + DUP; UNPAIR @% @b %a %b; DROP 2; + DROP; + + # Same test with non-matching field and variable annotations + UNIT @d; UNIT @c; PAIR %a %b; + DUP; UNPAIR %a %b; DROP 2; + DUP; UNPAIR % %b; DROP 2; + DUP; UNPAIR %a %; DROP 2; + DUP; UNPAIR % %; DROP 2; + DUP; UNPAIR %a; DROP 2; + DUP; UNPAIR %; DROP 2; + DUP; UNPAIR; DROP 2; + DUP; UNPAIR %a %b @a @b; DROP 2; + DUP; UNPAIR @a @b %a %b; DROP 2; + DUP; UNPAIR @a @% %a %b; DROP 2; + DUP; UNPAIR @% @% %a %b; DROP 2; + DUP; UNPAIR @% @b %a %b; DROP 2; + DROP; + + # Same tests without the variable annotations in input + UNIT; UNIT; PAIR %a %b; + DUP; UNPAIR %a %b; DROP 2; + DUP; UNPAIR % %b; DROP 2; + DUP; UNPAIR %a %; DROP 2; + DUP; UNPAIR % %; DROP 2; + DUP; UNPAIR %a; DROP 2; + DUP; UNPAIR %; DROP 2; + DUP; UNPAIR; DROP 2; + DUP; UNPAIR %a %b @a @b; DROP 2; + DUP; UNPAIR @a @b %a %b; DROP 2; + DUP; UNPAIR @a @% %a %b; DROP 2; + DUP; UNPAIR @% @% %a %b; DROP 2; + DUP; UNPAIR @% @b %a %b; DROP 2; + DROP; + + # Tests for @%% + UNIT; UNIT; PAIR %a %b @p; + DUP; UNPAIR @%% @b; DROP 2; + DUP; UNPAIR @a @%%; DROP 2; + DUP; UNPAIR @%% @%%; DROP 2; + DUP; UNPAIR @% @%%; DROP 2; + DUP; UNPAIR @%% @%; DROP 2; + DROP; + + # Swapping variable annotations + UNIT @b; UNIT @a; PAIR @c; UNPAIR @b @a; DROP 2; + + # End of test + UNIT; NIL operation; PAIR } \ No newline at end of file diff --git a/tests_python/contracts_011/opcodes/update_big_map.tz b/tests_python/contracts_011/opcodes/update_big_map.tz new file mode 100644 index 000000000000..c403975a38fb --- /dev/null +++ b/tests_python/contracts_011/opcodes/update_big_map.tz @@ -0,0 +1,6 @@ +storage (pair (big_map string string) unit); +parameter (map string (option string)); +# this contract the stored big_map according to the map taken in parameter +code { UNPAPAIR; + ITER { UNPAIR; UPDATE; } ; + PAIR; NIL operation; PAIR}; diff --git a/tests_python/contracts_011/opcodes/utxo_read.tz b/tests_python/contracts_011/opcodes/utxo_read.tz new file mode 100644 index 000000000000..aec29b79730b --- /dev/null +++ b/tests_python/contracts_011/opcodes/utxo_read.tz @@ -0,0 +1,9 @@ +parameter (pair (ticket nat) nat); +storage address; +code { CAR ; + UNPAIR ; + READ_TICKET ; DIP { DROP } ; UNPAIR ; DIP { UNPAIR } ; + DIIP { ASSERT_CMPEQ } ; + DIP { PUSH nat 42 ; ASSERT_CMPEQ } ; + NIL operation ; + PAIR } diff --git a/tests_python/contracts_011/opcodes/utxor.tz b/tests_python/contracts_011/opcodes/utxor.tz new file mode 100644 index 000000000000..81d9632d35d2 --- /dev/null +++ b/tests_python/contracts_011/opcodes/utxor.tz @@ -0,0 +1,24 @@ +parameter (pair address address); +storage nat; +code { UNPAIR ; DIP { DUP } ; + SWAP ; + PUSH nat 5 ; SWAP ; + TICKET ; + PUSH nat 2 ; PUSH nat 3 ; PAIR ; + SWAP ; + SPLIT_TICKET ; + ASSERT_SOME ; + UNPAIR ; + DIP { DIP { DUP ; CAR ; + CONTRACT (pair (ticket nat) nat) ; ASSERT_SOME ; + PUSH mutez 0 } ; + PUSH nat 2 ; SWAP ; PAIR ; } ; + DIP { TRANSFER_TOKENS } ; + SWAP ; + DIP { DIP { CDR ; + CONTRACT (pair (ticket nat) nat) ; ASSERT_SOME ; + PUSH mutez 0 } ; + PUSH nat 3 ; SWAP ; PAIR ; } ; + DIP { TRANSFER_TOKENS } ; + NIL operation ; SWAP ; CONS ; SWAP ; CONS ; + PAIR } diff --git a/tests_python/contracts_011/opcodes/view_fib.tz b/tests_python/contracts_011/opcodes/view_fib.tz new file mode 100644 index 000000000000..1b44288dd4a1 --- /dev/null +++ b/tests_python/contracts_011/opcodes/view_fib.tz @@ -0,0 +1,9 @@ +parameter (pair nat address) ; +storage nat; +code { + CAR; + UNPAIR; + VIEW "fib" nat; + IF_SOME {NIL operation ; PAIR;} { FAIL } + } + diff --git a/tests_python/contracts_011/opcodes/view_mutual_recursion.tz b/tests_python/contracts_011/opcodes/view_mutual_recursion.tz new file mode 100644 index 000000000000..9446a195b6e7 --- /dev/null +++ b/tests_python/contracts_011/opcodes/view_mutual_recursion.tz @@ -0,0 +1,11 @@ +parameter (pair nat address) ; +storage nat; +code { + CAR; + DUP; + CDR; + SWAP; + VIEW "is_twenty" nat; + IF_SOME {NIL operation ; PAIR;} { FAIL } + } + diff --git a/tests_python/contracts_011/opcodes/view_op_add.tz b/tests_python/contracts_011/opcodes/view_op_add.tz new file mode 100644 index 000000000000..e0c611cd3e8c --- /dev/null +++ b/tests_python/contracts_011/opcodes/view_op_add.tz @@ -0,0 +1,3 @@ +parameter (pair nat address) ; +storage nat ; +code { CAR ; UNPAIR ; VIEW "add" nat ; IF_SOME { } { FAIL }; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/opcodes/view_op_constant.tz b/tests_python/contracts_011/opcodes/view_op_constant.tz new file mode 100644 index 000000000000..5fc8b427884a --- /dev/null +++ b/tests_python/contracts_011/opcodes/view_op_constant.tz @@ -0,0 +1,3 @@ +parameter (pair nat address) ; +storage nat; +code { CAR ; UNPAIR ; VIEW "const" nat ; IF_SOME { } { FAIL }; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/opcodes/view_op_id.tz b/tests_python/contracts_011/opcodes/view_op_id.tz new file mode 100644 index 000000000000..7eb267bda064 --- /dev/null +++ b/tests_python/contracts_011/opcodes/view_op_id.tz @@ -0,0 +1,4 @@ +parameter (pair nat address) ; +storage (pair nat nat) ; +code { CAR ; UNPAIR ; VIEW "id" (pair nat nat) ; IF_SOME { } { FAIL }; NIL operation ; PAIR } ; + diff --git a/tests_python/contracts_011/opcodes/view_op_nonexistent_addr.tz b/tests_python/contracts_011/opcodes/view_op_nonexistent_addr.tz new file mode 100644 index 000000000000..f6947732e00e --- /dev/null +++ b/tests_python/contracts_011/opcodes/view_op_nonexistent_addr.tz @@ -0,0 +1,5 @@ +parameter (pair nat address) ; +storage bool ; +code { DROP; PUSH address "tz1SuakBpFdG9b4twyfrSMqZzruxhpMeSrE5"; PUSH nat 0; + VIEW "test" bool; IF_SOME { DROP ; PUSH bool True } { PUSH bool False } ; + NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/opcodes/view_op_nonexistent_func.tz b/tests_python/contracts_011/opcodes/view_op_nonexistent_func.tz new file mode 100644 index 000000000000..ca8ae6be4d34 --- /dev/null +++ b/tests_python/contracts_011/opcodes/view_op_nonexistent_func.tz @@ -0,0 +1,3 @@ +parameter (pair nat address) ; +storage bool ; +code { CAR ; UNPAIR ; VIEW "not_exist" bool ; IF_SOME { DROP; PUSH bool True } { PUSH bool False }; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/opcodes/view_op_test_step_contants.tz b/tests_python/contracts_011/opcodes/view_op_test_step_contants.tz new file mode 100644 index 000000000000..42106d2a6087 --- /dev/null +++ b/tests_python/contracts_011/opcodes/view_op_test_step_contants.tz @@ -0,0 +1,8 @@ +parameter address ; +storage (option (pair (pair mutez mutez) (pair (pair address address) address ))); +code { CAR ; + UNIT; + VIEW "step_constants" (pair (pair mutez mutez) (pair (pair address address) address )) ; + NIL operation ; + PAIR } ; + diff --git a/tests_python/contracts_011/opcodes/view_op_toplevel_inconsistent_input_type.tz b/tests_python/contracts_011/opcodes/view_op_toplevel_inconsistent_input_type.tz new file mode 100644 index 000000000000..d99353ace3d9 --- /dev/null +++ b/tests_python/contracts_011/opcodes/view_op_toplevel_inconsistent_input_type.tz @@ -0,0 +1,3 @@ +parameter (pair int address) ; +storage nat; +code { CAR ; UNPAIR ; VIEW "add" nat ; IF_SOME { DROP ; PUSH nat 1 } { PUSH nat 0 }; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/opcodes/view_op_toplevel_inconsistent_output_type.tz b/tests_python/contracts_011/opcodes/view_op_toplevel_inconsistent_output_type.tz new file mode 100644 index 000000000000..258cf616793c --- /dev/null +++ b/tests_python/contracts_011/opcodes/view_op_toplevel_inconsistent_output_type.tz @@ -0,0 +1,3 @@ +parameter (pair nat address) ; +storage bool; +code { CAR ; UNPAIR ; VIEW "add" bool; IF_SOME { DROP ; PUSH bool True} { PUSH bool False }; NIL operation ; PAIR } ; diff --git a/tests_python/contracts_011/opcodes/view_rec.tz b/tests_python/contracts_011/opcodes/view_rec.tz new file mode 100644 index 000000000000..490c72d29498 --- /dev/null +++ b/tests_python/contracts_011/opcodes/view_rec.tz @@ -0,0 +1,12 @@ +parameter unit ; +storage unit ; +view "loop" address never { CAR; DUP; VIEW "loop" never; ASSERT_SOME } ; +code { CDR ; + SELF ; + ADDRESS ; + DUP ; + VIEW "loop" never ; + ASSERT_SOME ; + DROP ; + NIL operation ; + PAIR } ; diff --git a/tests_python/contracts_011/opcodes/view_toplevel_lib.tz b/tests_python/contracts_011/opcodes/view_toplevel_lib.tz new file mode 100644 index 000000000000..1810a8a8ec4c --- /dev/null +++ b/tests_python/contracts_011/opcodes/view_toplevel_lib.tz @@ -0,0 +1,67 @@ +parameter nat ; +storage nat ; +code { CAR ; NIL operation ; PAIR } ; +view "add" nat nat { UNPAIR ; ADD } ; +view "id" nat (pair nat nat) { } ; +view "test_failwith" nat (pair nat nat) { FAILWITH } ; +view "step_constants" unit (pair (pair mutez mutez) (pair (pair address address) address )) + { DROP ; + SOURCE; + SENDER; + SELF_ADDRESS; + PAIR; + PAIR; + BALANCE; + AMOUNT; + PAIR; + PAIR; + } ; + +view "succ" (pair nat address) nat + { CAR; + UNPAIR; + PUSH nat 1; ADD; + PAIR; + DUP; CDR; SWAP; + VIEW "is_twenty" nat; ASSERT_SOME; + } ; +view "is_twenty" (pair nat address) nat + { + CAR; + DUP; + CAR; + PUSH nat 20 ; + COMPARE; + EQ ; + IF { CAR; } + { DUP; CDR; SWAP; VIEW "succ" nat; ASSERT_SOME } + } ; +view "fib" nat nat + { + CAR; + DUP; + PUSH nat 0 ; + COMPARE ; + EQ ; + IF { } + { DUP; + PUSH nat 1; + COMPARE; + EQ; + IF { } + { DUP; + PUSH nat 1; SWAP; SUB; ABS; + SELF_ADDRESS; + SWAP; + VIEW "fib" nat; + IF_SOME { SWAP; + PUSH nat 2; SWAP; SUB; ABS; + SELF_ADDRESS; + SWAP; + VIEW "fib" nat; + IF_SOME { ADD; } { FAIL } + } + { FAIL }; + } + } + } diff --git a/tests_python/contracts_011/opcodes/voting_power.tz b/tests_python/contracts_011/opcodes/voting_power.tz new file mode 100644 index 000000000000..741bb196788d --- /dev/null +++ b/tests_python/contracts_011/opcodes/voting_power.tz @@ -0,0 +1,7 @@ +parameter key; # A public key +storage (pair nat nat); +code { CAR; + HASH_KEY; VOTING_POWER; # Get the number of rolls for the key + DIP { TOTAL_VOTING_POWER }; # Get the total number of rolls + PAIR; + NIL operation; PAIR; }; diff --git a/tests_python/contracts_011/opcodes/xor.tz b/tests_python/contracts_011/opcodes/xor.tz new file mode 100644 index 000000000000..557eaa642b9a --- /dev/null +++ b/tests_python/contracts_011/opcodes/xor.tz @@ -0,0 +1,13 @@ +parameter (or (pair bool bool) (pair nat nat)); +storage (option (or bool nat)); +code { + CAR; + IF_LEFT + { + UNPAIR; XOR; LEFT nat + } + { + UNPAIR; XOR; RIGHT bool + } ; + SOME; NIL operation ; PAIR + } diff --git a/tests_python/tests_011/__init__.py b/tests_python/tests_011/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize.out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize.out new file mode 100644 index 000000000000..69e3b79ce2c9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize.out @@ -0,0 +1,8 @@ +tests_011/test_contract.py::TestNormalize::test_normalize + +{ Pair 0 3 6 9 ; Pair 1 4 7 10 ; Pair 2 5 8 11 } +{ Pair 0 3 6 9 ; Pair 1 4 7 10 ; Pair 2 5 8 11 } +{ { 0 ; 3 ; 6 ; 9 } ; { 1 ; 4 ; 7 ; 10 } ; { 2 ; 5 ; 8 ; 11 } } +{ Pair 0 (Pair 3 (Pair 6 9)) ; + Pair 1 (Pair 4 (Pair 7 10)) ; + Pair 2 (Pair 5 (Pair 8 11)) } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_legacy_flag.out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_legacy_flag.out new file mode 100644 index 000000000000..f6c3e7846324 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_legacy_flag.out @@ -0,0 +1,8 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_legacy_flag + +{ Elt 0 1 } +At (unshown) location 0, value { Elt %a 0 1 } +is invalid for type map nat nat. +At (unshown) location 1, unexpected annotation. +Fatal error: + ill-typed data expression diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[None].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[None].out new file mode 100644 index 000000000000..a4137482d1dd --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[None].out @@ -0,0 +1,10 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_script[None] + +{ parameter unit ; + storage unit ; + code { PUSH (list (pair nat nat nat nat)) + { Pair 0 3 6 9 ; Pair 1 4 7 10 ; Pair 2 5 8 11 } ; + DROP 2 ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[Optimized].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[Optimized].out new file mode 100644 index 000000000000..4f38d806cbf5 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[Optimized].out @@ -0,0 +1,10 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_script[Optimized] + +{ parameter unit ; + storage unit ; + code { PUSH (list (pair nat nat nat nat)) + { { 0 ; 3 ; 6 ; 9 } ; { 1 ; 4 ; 7 ; 10 } ; { 2 ; 5 ; 8 ; 11 } } ; + DROP 2 ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[Optimized_legacy].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[Optimized_legacy].out new file mode 100644 index 000000000000..ccad656d8024 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[Optimized_legacy].out @@ -0,0 +1,12 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_script[Optimized_legacy] + +{ parameter unit ; + storage unit ; + code { PUSH (list (pair nat nat nat nat)) + { Pair 0 (Pair 3 (Pair 6 9)) ; + Pair 1 (Pair 4 (Pair 7 10)) ; + Pair 2 (Pair 5 (Pair 8 11)) } ; + DROP 2 ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[Readable].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[Readable].out new file mode 100644 index 000000000000..fe0a564129ce --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_script[Readable].out @@ -0,0 +1,10 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_script[Readable] + +{ parameter unit ; + storage unit ; + code { PUSH (list (pair nat nat nat nat)) + { Pair 0 3 6 9 ; Pair 1 4 7 10 ; Pair 2 5 8 11 } ; + DROP 2 ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list (pair nat int bool bytes)].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list (pair nat int bool bytes)].out new file mode 100644 index 000000000000..a15e4bc87cb3 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list (pair nat int bool bytes)].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_type[list (pair nat int bool bytes)] + +list (pair nat (pair int (pair bool bytes))) diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list (pair nat int bool)].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list (pair nat int bool)].out new file mode 100644 index 000000000000..9b89b6d62e85 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list (pair nat int bool)].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_type[list (pair nat int bool)] + +list (pair nat (pair int bool)) diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list (pair nat int)].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list (pair nat int)].out new file mode 100644 index 000000000000..132310921929 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list (pair nat int)].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_type[list (pair nat int)] + +list (pair nat int) diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list nat].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list nat].out new file mode 100644 index 000000000000..9d8561608733 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[list nat].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_type[list nat] + +list nat diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[nat].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[nat].out new file mode 100644 index 000000000000..56232b639ba9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[nat].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_type[nat] + +nat diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[pair nat int bool bytes].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[pair nat int bool bytes].out new file mode 100644 index 000000000000..c8d413e4d504 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[pair nat int bool bytes].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_type[pair nat int bool bytes] + +pair nat (pair int (pair bool bytes)) diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[pair nat int bool].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[pair nat int bool].out new file mode 100644 index 000000000000..2d56a075bd84 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[pair nat int bool].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_type[pair nat int bool] + +pair nat (pair int bool) diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[pair nat int].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[pair nat int].out new file mode 100644 index 000000000000..2aaf7c3c0d31 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_type[pair nat int].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_type[pair nat int] + +pair nat int diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[None].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[None].out new file mode 100644 index 000000000000..14f341ee99ed --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[None].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_unparsing_mode[None] + +{ Pair 0 3 6 9 ; Pair 1 4 7 10 ; Pair 2 5 8 11 } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[Optimized].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[Optimized].out new file mode 100644 index 000000000000..10caef8c3ebe --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[Optimized].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_unparsing_mode[Optimized] + +{ { 0 ; 3 ; 6 ; 9 } ; { 1 ; 4 ; 7 ; 10 } ; { 2 ; 5 ; 8 ; 11 } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[Optimized_legacy].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[Optimized_legacy].out new file mode 100644 index 000000000000..345ecede075f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[Optimized_legacy].out @@ -0,0 +1,5 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_unparsing_mode[Optimized_legacy] + +{ Pair 0 (Pair 3 (Pair 6 9)) ; + Pair 1 (Pair 4 (Pair 7 10)) ; + Pair 2 (Pair 5 (Pair 8 11)) } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[Readable].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[Readable].out new file mode 100644 index 000000000000..e1e599e5a194 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestNormalize::test_normalize_unparsing_mode[Readable].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestNormalize::test_normalize_unparsing_mode[Readable] + +{ Pair 0 3 6 9 ; Pair 1 4 7 10 ; Pair 2 5 8 11 } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[client_regtest_custom_scrubber0].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[client_regtest_custom_scrubber0].out new file mode 100644 index 000000000000..f6e673d07947 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[client_regtest_custom_scrubber0].out @@ -0,0 +1,282 @@ +tests_011/test_contract.py::TestScriptHashRegression::test_contract_hash[client_regtest_custom_scrubber0] + +exprvMpUfcC7hMdJYPY7D7a1R835h9LxR1JDXAYMa1DiHURr2PoMcs [CONTRACT_PATH]/attic/accounts.tz +expruucsMyaSmmP5gmkFWjJfv4a52FQV5EGaf3XpHoeXHQgyJgMJfF [CONTRACT_PATH]/attic/add1.tz +exprvEM4Lvihz6jFYszxazuQQPsHjxA4J54tfLeowwDkY1jjTi8Qft [CONTRACT_PATH]/attic/add1_list.tz +exprta1x6QtexpFktejHoB1KwuMQRXePhgre9rDiJ3GDSZCqb3vtqL [CONTRACT_PATH]/attic/after_strategy.tz +expruEosJCXYteRXxfbAVJ5XythgpVQPMdiu3kbbZj3VAVSVjk8ud7 [CONTRACT_PATH]/attic/always.tz +exprvR9m6PaVeLfPHZjA3A929bbfjonzMJs1Kzcmj8baoEvLct9Ry9 [CONTRACT_PATH]/attic/append.tz +exprvQh7vw7vYfp2qdiyYPCFgd6jVkxqYZimmqoYCGZbqaoMgfLifS [CONTRACT_PATH]/attic/at_least.tz +exprtyZC9vL831BnATCkdrP585F4cEzQQQp1ZqnZSqvCDLqp7S33V1 [CONTRACT_PATH]/attic/auction.tz +expruZ4wjBCm3DQNhEf69L27tqaqAJa1TF34728yyPJ9BUg3sEwcxB [CONTRACT_PATH]/attic/bad_lockup.tz +expruazd13u4uPHS7oFWFeZ5nodWR5QC6nQwgy5LGoUTAR3KXsYPXg [CONTRACT_PATH]/attic/big_map_union.tz +exprv7aEg823PTvrEG5bXr4QGk3XCsEkodhUxWCaMBBSq44ZuAxnNf [CONTRACT_PATH]/attic/cadr_annotation.tz +expruwmej4r1RSMDEmmU4SjWUbrzpURnAwybrSwBaMkHpxVobLkWAe [CONTRACT_PATH]/attic/concat.tz +exprte328K2NmgWrmHLbFrGVjvoZKZNFB7577Vt7cWQa8KdvWbfxYk [CONTRACT_PATH]/attic/conditionals.tz +exprvRVXhJFcFjGMkatDwgaLRcJq4TctY979bjniTqwACgXtC3mWko [CONTRACT_PATH]/attic/cons_twice.tz +exprtcnAL38pt7fyZdCiqd97qcYeESWQStPR6sbN2SxMCfbPJhVjau [CONTRACT_PATH]/attic/cps_fact.tz +exprv9BquR6NXVwKMwD4MS5vdWqqvMzjvWumrBf6NsGQXSfgm2Rtqk [CONTRACT_PATH]/attic/create_add1_lists.tz +exprv4cq5g9hsxWU65zCp8dfUi3RtBzu9rGXZ7otetL23tj1zSkNQ2 [CONTRACT_PATH]/attic/data_publisher.tz +expruavAC89RfrZxSrYwdoA6Wr5ghwdUSns8SNaHcng1JRcqR1dwpR [CONTRACT_PATH]/attic/dispatch.tz +expruat2BS4KCwn9kbopeX1ZwxtrtJbyFhpnpnG6A5KdCBCwHNsdod [CONTRACT_PATH]/attic/empty.tz +exprubD7VQHa8qeqRsFByes3ANZ24mvUnqW3qKAsKVUCncjxYEXtGp [CONTRACT_PATH]/attic/fail_amount.tz +expruYCfXuFoyakdWc3C6Np5ojQrGLDMMN6btVbVEAc97MJzpQYVrm [CONTRACT_PATH]/attic/faucet.tz +exprtrmofsqXxiLHqJi9gcXNsywWoYHtp8WAGsqzHbWo3MjkZnfmc3 [CONTRACT_PATH]/attic/forward.tz +exprv8K6ceBpFH5SFjQm4BRYSLJCHQBFeQU6BFTdvQSRPaPkzdLyAL [CONTRACT_PATH]/attic/id.tz +exprujqMuqia1zKuReMgjumpsn8XAJ5N6RWaoz3kZpLNRUyyQXwrtY [CONTRACT_PATH]/attic/infinite_loop.tz +exprtoE9fvqNeHngkFPopZv412GoqoZ57HgaCi2XFR7YxkwPpvHXBZ [CONTRACT_PATH]/attic/insertion_sort.tz +exprux8tMeArJNXUekbuHqLb6epu2eWXJy85f8Yts5oHASHyWp6bva [CONTRACT_PATH]/attic/int_publisher.tz +expruosSkGQbRDc3NUt5oEqSkt3dqxymQDKDeNxcjRgFNLxARG414v [CONTRACT_PATH]/attic/king_of_tez.tz +exprtZcF9NutGBwyuXTqEi4SyL3bZdAWqzkDc782wxNhYT7LtdY4Lb [CONTRACT_PATH]/attic/list_of_transactions.tz +expruDiMLqyYi67RbkDfNyEjBDgJqQLiCGVx2xLUiWujSkwr7rVyRD [CONTRACT_PATH]/attic/queue.tz +exprtZYeWyxANtdrSANECgXdeakcP9fJm7ecJhpeuGR55a8gDTSXWe [CONTRACT_PATH]/attic/reduce_map.tz +exprvMneQMtBQzcPKboFsEV7R4BAuoF8QLUDMWB62iYLmKz9tztNdJ [CONTRACT_PATH]/attic/reentrancy.tz +exprueaa65wkL9ennP6vZoUP6yCkzz6Wc4cF3w11q8bGXguokXAEvK [CONTRACT_PATH]/attic/reservoir.tz +exprtwrNpVRUJaVTBs5vXFLbt4v6Fb8LRySwc1Ap8ZWZh4JbLfgJ6P [CONTRACT_PATH]/attic/scrutable_reservoir.tz +expruwtkYFMkNLVjKD8hypuDc53SHLQQ65g6VPGiHFXbY5hHwmb552 [CONTRACT_PATH]/attic/spawn_identities.tz +expruiDvGyQG5GzKzcBP7d5Z5doUcdxTmUcM6vL1jCTyTmxLrekmP7 [CONTRACT_PATH]/macros/assert.tz +expruMKaaLoPjYfDaKymizi9fnFY7hSDyPj2NfJFxSuAoEVknDxSM6 [CONTRACT_PATH]/macros/assert_cmpeq.tz +exprtqiRJEnWeqF5KKBRPjamJGoi2oQvekfnRwsdZNRy8w8wkbroKJ [CONTRACT_PATH]/macros/assert_cmpge.tz +exprtZWviL38eegiNAN55KfEtAHhAqUWoadkbxyFCGs3vDnDRzueft [CONTRACT_PATH]/macros/assert_cmpgt.tz +exprvBWTmSLBAGgcuBFSToCQPqH5J1F5R2vf8iJMiPVdZjG3B7hWq7 [CONTRACT_PATH]/macros/assert_cmple.tz +expruuDzygKxAaQ348e6BcRSk8A2Chq4WinaTUCTvg5YEVnGpptBg3 [CONTRACT_PATH]/macros/assert_cmplt.tz +expruxeuWRoEFHhzv7tG1rwderXePZzxtpL9BRQ9N7ZhoFXS6RPy9a [CONTRACT_PATH]/macros/assert_cmpneq.tz +expruaqEBPqAjaUawnFTSbGZXXr1HemnecV8GuLGD15nQvtxaXiH3z [CONTRACT_PATH]/macros/assert_eq.tz +expru9etUCKvNXZyDCx1x55QfZzyGxmgsteFNBoWAZeh6F5FHEHy3m [CONTRACT_PATH]/macros/assert_ge.tz +exprvP9aPgepXY1C4hVPWPMoDGhvSjNvH5sJvB25qcMMPFHurVyH9c [CONTRACT_PATH]/macros/assert_gt.tz +exprtbLVpjXVnhdMUyDM53MXHH2HBNSMxdnXsVTNtFFMHHVn18yUuZ [CONTRACT_PATH]/macros/assert_le.tz +exprtx7nibNobG8Y7asBYktu2NdPv3k3No29rM4nP1WSbricymunvc [CONTRACT_PATH]/macros/assert_lt.tz +exprvQM6Ukz3TKVSo4dqNDYmMvNG5rs3U7WGXpvjSVsM2oQj6SbdLM [CONTRACT_PATH]/macros/assert_neq.tz +exprueGaPWpG6szfmTAccNH5MaoqxovN7JCbx4CDsmpvnhBAUrAizc [CONTRACT_PATH]/macros/big_map_get_add.tz +exprvFc9HFkvwNGZVrJkU2KpXuXieVKCJ9VXbTo51LRWBMAB6oEbWq [CONTRACT_PATH]/macros/big_map_mem.tz +exprv7Gwz5KP32zP9FYPSng9mPqLYbxwttDZin5QPnqzsUM3MZBvLK [CONTRACT_PATH]/macros/build_list.tz +exprvNqdnnqWgrrZYgnkuFeXrboqQYnYiRLSb7wV4E27bdZcbrU5GK [CONTRACT_PATH]/macros/carn_and_cdrn.tz +exprtknptGzyx8quFM8gHyGcpyX5xYeUxUpoVPhZeBkRqz5hUHfuq7 [CONTRACT_PATH]/macros/compare.tz +exprussGZ9wiqKqGkCsFJrfvr5DXxqZiLuHATJuvr3D8ar3KCeNaCz [CONTRACT_PATH]/macros/compare_bytes.tz +expru4Mmhu46yLQj4Q767jgVgvbaNe7B6EwvYvWA9KCrfzCxwBnzCQ [CONTRACT_PATH]/macros/fail.tz +exprtyJ1YYdejX7jRUh8FDjbbwrbAFwZYKPjdEZMNUUWdncqEwvuyr [CONTRACT_PATH]/macros/guestbook.tz +exprvMCL9Ti9C12EZUiFR1YtSp7nYjPN4DoyJPQiyVDYCZsSsheTeV [CONTRACT_PATH]/macros/macro_annotations.tz +expruq2AH96hXvqFqphuMKhJUY8mGMmdHuiHWHjkZqooZoEusTNNRf [CONTRACT_PATH]/macros/map_caddaadr.tz +exprueEkWTdWS8F25vnUP8gWd75MCfxk3vMhETn5dUYtrifV6FU8x5 [CONTRACT_PATH]/macros/max_in_list.tz +expruGfNErSHzpWnoNpgvZ3MRc52jiCHu8YTDUvh2T643QABr7NDZN [CONTRACT_PATH]/macros/min.tz +exprtw4kigYCiREgky6KBKryS7JkaGih6ju8jkjaXtpdcWYrYukRKX [CONTRACT_PATH]/macros/pair_macro.tz +exprtxutG1Nu8d198ebiCraNuQ8a6iYYqJYfGXq19aykNPB1uECc8w [CONTRACT_PATH]/macros/set_caddaadr.tz +exprvCE6JDXrzEfZuxTQzSgxWXtxX5GoNxvidL84CN2TAm6Hk3kuK6 [CONTRACT_PATH]/macros/take_my_money.tz +exprunGqZLZZwm9mY31NFGbBemCgXGevYqLRKdeRKQArPf824Npnni [CONTRACT_PATH]/macros/unpair_macro.tz +exprufRUAYF6r5QHQvK8CzWkKQcdvYkPx5fjEYzWPXc35Dry77KDT1 [CONTRACT_PATH]/mini_scenarios/authentication.tz +exprtjdvZr5J7WfN4SyNgKueLnxX4fALUYJ4cmi675EHJdUu5yyg2n [CONTRACT_PATH]/mini_scenarios/big_map_entrypoints.tz +exprtfWRfK4RoY8CF9VXvcHeBxizfjMMPAkLojfUTuoZkMSyiPKoyK [CONTRACT_PATH]/mini_scenarios/big_map_magic.tz +expruRE8G1Qc1dU8ZeQCTA48D69uPv8hpZYtDiKKHbfiy1mQLno8nx [CONTRACT_PATH]/mini_scenarios/big_map_read.tz +exprtotUpA2o34SHPX7ZQHD69WvJyEykTvPJ8T3RFErKAq4TQHFAgP [CONTRACT_PATH]/mini_scenarios/big_map_store.tz +exprtbeKR4fc2tqCWahuCeXAb42Hpye5dwmq8sj2guSztorTFJnh1J [CONTRACT_PATH]/mini_scenarios/big_map_write.tz +exprvTRcwMZnUPdSeRG8DdiC2xH3DrfMbp8qCwg76Av4pqbX5k4tHw [CONTRACT_PATH]/mini_scenarios/create_contract.tz +exprubRYeqf14u8CU4cEri2RWBrx26gkxyGe5wGeVAf4PDjKdsNhLK [CONTRACT_PATH]/mini_scenarios/create_contract_simple.tz +exprvLDpqaNLp1Cb8hbCqRU6tyU53n9PQkixgcBwFdSLJWsUdwhCQU [CONTRACT_PATH]/mini_scenarios/default_account.tz +expruaNoYRNTQxG5yujhHLetzS68ppQ38MFyi2ZhzNs5WNFv3wBAHG [CONTRACT_PATH]/mini_scenarios/execution_order_appender.tz +exprv6GXw7FheWdWKfY5oxtkB1AcqWkpKQDq4w7rxYFvwypZQijymK [CONTRACT_PATH]/mini_scenarios/execution_order_caller.tz +exprvSqfUw3oLZmQDwys8V5Qn9K1RAgMDGxdUUxzx1wpnyif3uSZG8 [CONTRACT_PATH]/mini_scenarios/execution_order_storer.tz +expruhMQvp6kKepaVGL8EEMPPk6zY1uyyW22Ugrr4ty21dtjDcVdbq [CONTRACT_PATH]/mini_scenarios/fa12_reference.tz +exprub9UzpxmhedNQnsv1J1DazWGJnj1dLhtG1fxkUoWSdFLBGLqJ4 [CONTRACT_PATH]/mini_scenarios/generic_multisig.tz +exprvTVuhJ2wNH8LHYEUiNC6ugx264rdfka1HkGfdVxV5632GjqgNv [CONTRACT_PATH]/mini_scenarios/groth16.tz +expru1u3Ta2uCGgcz6Z86K2mA5ierGB9RMaSwSppzVFxeuiXpBFZrf [CONTRACT_PATH]/mini_scenarios/hardlimit.tz +exprutz4BVGJ3Qms6qjmqvUF8sEk27H1cfqhRT17qpTdhEs5hEjbWm [CONTRACT_PATH]/mini_scenarios/legacy_multisig.tz +exprvRy1WUs7SQaNJm478UQHzz8uJAQoWT3bR5TXSnmbxWAcpZdGKu [CONTRACT_PATH]/mini_scenarios/lockup.tz +exprufAK15C2FCbxGLCEVXFe26p3eQdYuwZRk1morJUwy9NBUmEZVB [CONTRACT_PATH]/mini_scenarios/lqt_fa12.mligo.tz +expruBi6wgss7SRmpBCseBzcu3L283Jfx2CpUjgfuT2MgsozUsvBwt [CONTRACT_PATH]/mini_scenarios/multiple_en2.tz +exprtgxcdQP1EVvEYN2BHjbqTvwzywuYAdCmnfVgeP9zcgkxUrmScN [CONTRACT_PATH]/mini_scenarios/multiple_entrypoints_counter.tz +exprucgYdABPRbbq2yy2rpyt4Z8fv7PN4yhkch3QYZ5QQ5ehbtNA4K [CONTRACT_PATH]/mini_scenarios/parameterized_multisig.tz +exprvJ8zXaBkyXMhJ2eKtPwdwbg5NLrggvW8MEpVK3hk3nAe215PQ6 [CONTRACT_PATH]/mini_scenarios/replay.tz +exprtuiYUMjM6d8XxPda1yfKeN61ko6riom35PzybC31NKXkVhgBQy [CONTRACT_PATH]/mini_scenarios/reveal_signed_preimage.tz +expruB4maBvk1y4JaeSLpDXWC3zKiXK5QFYv4B3R5KfdGEt4B5VvTT [CONTRACT_PATH]/mini_scenarios/self_address_receiver.tz +exprvTG7hjtWXeogStj3pzM1MCVcNg1q6KnivqNVzQjviUrJvsjfQn [CONTRACT_PATH]/mini_scenarios/self_address_sender.tz +expru9ASRmfbXX8Ajf5uDeiZDbNwonrCiS1e6UaDXUstKU3yuwQwdZ [CONTRACT_PATH]/mini_scenarios/ticket_builder_fungible.tz +exprtXrMgaXhLsw6ioNNPThqPF1yDyLjqGdJeB6yMRKLUQZfkTD6jy [CONTRACT_PATH]/mini_scenarios/ticket_builder_non_fungible.tz +expruryVEK55xjeHpeGgHjuLr9jtRS2D1gzAgYXpzGfripoX8qFhNK [CONTRACT_PATH]/mini_scenarios/ticket_wallet_fungible.tz +expruoGtEJH3sXXm2ruNG6DGTFE3GM6fjAS6fzDZKtdaMnRzHvi3Xd [CONTRACT_PATH]/mini_scenarios/ticket_wallet_non_fungible.tz +exprtnBz8poqNTrK4rzTXZFKQx7HWpx4WidHB5wxcM2oTS8NcrkAUt [CONTRACT_PATH]/mini_scenarios/tzip4_view.tz +exprugya6ngixBfjyxV28ffnC8jmJPi4vbJdqD1aVUx82YLhzbH8Tn [CONTRACT_PATH]/mini_scenarios/vote_for_delegate.tz +expruaKedvXmhg6wbV361DHykomz5dPqLi473KxBwJwyicEnKMhpb9 [CONTRACT_PATH]/mini_scenarios/weather_insurance.tz +exprv9PvyjnsPjPCg5f13WtBiuD3o6idDAVWU6QfPtdWMjCLGRpwTh [CONTRACT_PATH]/mini_scenarios/xcat.tz +exprvKm5t6a6LL2d3HjvRiJumGrGei24aRXscJk3zB1hs516Ju4oMZ [CONTRACT_PATH]/mini_scenarios/xcat_dapp.tz +exprucvy7NUDPu2yTWEA6WVsusEZgGRmU1WpVzrFnNZV7m2H8BVysF [CONTRACT_PATH]/non_regression/bug_262.tz +exprv3FvpUYzomvhmzxsQyuR1katpswNnicQZB4jA5uec3MERXk1cB [CONTRACT_PATH]/non_regression/pairk_annot.tz +exprujPzkrPVucSvhHc1d9xm6kcs7oggkQyJXN8L2Rj3fteEABAkTe [CONTRACT_PATH]/opcodes/abs.tz +expruNtqq51Lm75X61pxUx7P2FyR2uyUKLsZNHMXWx6X5rsyJ5M6WX [CONTRACT_PATH]/opcodes/add.tz +exprupWD554EpqFBjo4KUpTqrfQcJAHqr3ijKmv5cmLRJ93Q1SgwGX [CONTRACT_PATH]/opcodes/add_bls12_381_fr.tz +exprugu3H5MPrpWJRZMPMGDM3Dbvykaa1fHejEvYr7ePKaLtahjQV5 [CONTRACT_PATH]/opcodes/add_bls12_381_g1.tz +expru41eYPF7gPvBRAtantBxbFU75RqBEwHPZ7UeX2EgHmExRoA4dh [CONTRACT_PATH]/opcodes/add_bls12_381_g2.tz +exprtcPYR7TZHxzcpmZWjjLgMWp6CeRWAxQ5Bt2bgpUK5uKjmNAdzL [CONTRACT_PATH]/opcodes/add_delta_timestamp.tz +expruLFQ1mcR5sg9sqyFHThknANoBeL4C5HFGgH55MqwPBEb1TUxLt [CONTRACT_PATH]/opcodes/add_timestamp_delta.tz +exprtz1uUW5sVUVaKNLhPaKGjA7jK9JmzWBCQu5Xn1MC3aS1FjTUmK [CONTRACT_PATH]/opcodes/address.tz +exprvJ4NRS33cboLuTx58f3sbYpXf1m7Cq2ou9gpCh1k8foaCZAoas [CONTRACT_PATH]/opcodes/and.tz +expru5BXwmdpWQ3WDKA24g6gYGwLxPc868wKkdeAaGh899nD77Uxwn [CONTRACT_PATH]/opcodes/and_binary.tz +expruL6aKRTXN2hWb9EXLuJASu7nuBGJxL7VyT1oEjX9b2s3u6Y5Ff [CONTRACT_PATH]/opcodes/and_logical_1.tz +exprtpYYuLewZWKCK1aPb9gfYSiPWSaeXRM4P2e4rpa6UktVueB1uf [CONTRACT_PATH]/opcodes/balance.tz +exprtZRAy4QHqpF8c3CusD6e1kxWA3KAUrmgeXndfQYSEGArDmkWUm [CONTRACT_PATH]/opcodes/big_map_mem_nat.tz +exprugsT35M51mCw6Fim3ysNKpCh8JyW9m7CYW65QQ7XUEDmspqz2i [CONTRACT_PATH]/opcodes/big_map_mem_string.tz +exprvN3tk4o5YPYJB6aYAxEx8KU93yNSaw4K6mbEZZh9RQayua6odv [CONTRACT_PATH]/opcodes/big_map_to_self.tz +exprv712JoEC7RRhoP7gbTUiVgLbtAgHmenwa5TqhVykDZ3e538MGU [CONTRACT_PATH]/opcodes/bls12_381_fr_push_bytes_not_padded.tz +exprufF1yaR5QHdy8iECBLjhBtDZVLiEjZRuJntSkXjsrJRYozXLmW [CONTRACT_PATH]/opcodes/bls12_381_fr_push_nat.tz +expruSVRATSSsbfHowLHGs5XHms95RuqBWSdDJoUKdns3fWbwasU1p [CONTRACT_PATH]/opcodes/bls12_381_fr_to_int.tz +exprvTBYxSJ7d1z1aZvvAgPrdZUXHzoFxkwBC7McES5BS56xvqkGXg [CONTRACT_PATH]/opcodes/bls12_381_fr_to_mutez.tz +expruTppbXBm1YHSCB4uYv9MQs6zxqRWqbkwGWoiKfF5Sjj5n2TpJx [CONTRACT_PATH]/opcodes/bls12_381_fr_z_int.tz +exprv5Si29PfXErNuJdEvJWQhWRJ3qPETygaWzRE3ctmCU4s6y2V9v [CONTRACT_PATH]/opcodes/bls12_381_fr_z_nat.tz +expruRsYz6JopAFGU95WfFU61SE3RbMGn3XPR9PFiTfLbgQr2kzu7u [CONTRACT_PATH]/opcodes/bls12_381_z_fr_int.tz +expruyE3E3o8EAptRBZtQAB5Kv3sxUZGv7DK6CpJ2YdotQj9gqW5wN [CONTRACT_PATH]/opcodes/bls12_381_z_fr_nat.tz +exprui72n1Jur5Px5ESXgxiF9Uw86DsoXPt1edGDpSv4CvnuPCtBPR [CONTRACT_PATH]/opcodes/bytes.tz +exprtvRRYmpToi9y67ZzNmgjtdrgNkwVduSnBi7GZVrsmgDna8TSjB [CONTRACT_PATH]/opcodes/car.tz +expru5dDnxp1rhgXGmKigbLJ9ASaVHbkpkL6gLggtk9krgYC3jusc8 [CONTRACT_PATH]/opcodes/cdr.tz +expruxH6gEuBmNzg5nWEM4tv3jMBbknbEtTHKTPMeC4EBdFdujbRph [CONTRACT_PATH]/opcodes/chain_id.tz +expruGhHABGLz2wxAyyx3RpfyKHa8HE9voC19vLiAKYWYMMsUUTFdd [CONTRACT_PATH]/opcodes/chain_id_store.tz +exprtjDuLEzh8dcjpCcJiiuKXDdG3XusjuuURVCh3JWKBgjJGsVsMs [CONTRACT_PATH]/opcodes/check_signature.tz +expruHKTiWeY6mty7RokwdyZdwdzHQbu7udbbZbpu3C8h9n6jXnp4v [CONTRACT_PATH]/opcodes/comb-get.tz +exprtsyJo5ceZQM76zpAUeTren1YnBxw2MNDKmx8k11Ejai8T296Sg [CONTRACT_PATH]/opcodes/comb-literals.tz +exprv733yfMh1C9uyuAJJP66WPQDXAjjfcTcSfHhbboJnz6DUCEh41 [CONTRACT_PATH]/opcodes/comb-set-2.tz +exprvHamsTHMJKF6ohaSAwdgp2Sv33LGgYnjase3LUcwXKnJfh53wn [CONTRACT_PATH]/opcodes/comb-set.tz +expruufsxtik2vxyQfL3QKNWWH9TnJZgGx1ELi3AR5L3LM71uqxiP4 [CONTRACT_PATH]/opcodes/comb.tz +expruKknV6VYzPHkSxc3EFb488JPBfUX1UHsJUzceaGFafdnbgsKw2 [CONTRACT_PATH]/opcodes/compare.tz +exprvGXTYwatNh32w78r83SuLAW1YQefufYN1Bcu9AZ1BLDUU77dKR [CONTRACT_PATH]/opcodes/compare_big_type.tz +expruR3ZCLJTuojpTuS2sR3SGxqait52kXQNKfy8bipv69b2XJZG8A [CONTRACT_PATH]/opcodes/compare_big_type2.tz +expruUDL3EP43hFhcdCZD7K1xvfPtiNWfkU2Nyq8jmr9XgZuXqWXc5 [CONTRACT_PATH]/opcodes/comparisons.tz +exprtjqEmEBnmG7yiDXn224ER9bt4qh18LF4LzFSfoeuo1cbJpNBPy [CONTRACT_PATH]/opcodes/concat_hello.tz +exprtqd5qPLeh5Fi52YdkgWuvRXctgUoxU1Q4JDB2VseRk6DAEpMvd [CONTRACT_PATH]/opcodes/concat_hello_bytes.tz +expruv8MHvRmp3ipXYRyyP4aEE4iFHWsNZjNQSaCWUt7fwbgLeFBXY [CONTRACT_PATH]/opcodes/concat_list.tz +expruYk7GXYQ7bKbUcqcHDKs97USVBrxAkzSo2Bkj5AXVjSawDkNAS [CONTRACT_PATH]/opcodes/cons.tz +expruMW9W9kkb2JaQWzKVThky4ULQ6ckgLzE2xD49XUp5E1iwWfUbe [CONTRACT_PATH]/opcodes/contains_all.tz +exprvDvotLP1G2qjPJiqz2RvVUm8wJ2cEuFvKtm7YUNW3w6krDponF [CONTRACT_PATH]/opcodes/contract.tz +exprvNrgGoLvfEaXw6QmjQrkXESpWo72JHR4G4mhTJy7Y266YXa3fe [CONTRACT_PATH]/opcodes/create_contract.tz +exprv8no3WSXCsf89WYazUNurLm8hwZRwTWYBQrzihscQcR6M1uKEu [CONTRACT_PATH]/opcodes/create_contract_rootname.tz +exprttdxhC3YwJ9SGJNTDMQRpyWX1KwqAUuPbkQHX3uMPHNt3GKkZK [CONTRACT_PATH]/opcodes/create_contract_rootname_alt.tz +expruxUAUoijmC6A4rZK9XHcQL4WmgreJwT17hrgpuYkg1VeELBdbF [CONTRACT_PATH]/opcodes/create_contract_with_view.tz +exprteqmco8PDGH1PnTGgF5jPjBPCYyZfyvER2ULtv2y3MRgGdcP8T [CONTRACT_PATH]/opcodes/diff_timestamps.tz +exprtt6joHWnYr4AAW3uem8nzbxYgLcSpEJtaUT66qWchoKPS8sFXx [CONTRACT_PATH]/opcodes/dig_eq.tz +exprvKBfwAg4hVHrTtq3UV8AunaqUKxAkvx35TScbZDARNSgH737Ck [CONTRACT_PATH]/opcodes/dign.tz +exprv8t3ZfoBs6B7LMeFNN6U4PRpE1M6MhdtKPT5keNZT4je3RBadj [CONTRACT_PATH]/opcodes/dip.tz +expruncwh1qqNqSwq6kHYXfwhQyjpuJjbernTsyHAMnaLjU5h3qjxr [CONTRACT_PATH]/opcodes/dipn.tz +exprv62zo2ACMdseAu1HKzDDLSjBrYr2nZzi36PCTVJqcBwSdvt4yU [CONTRACT_PATH]/opcodes/dropn.tz +exprujbvaRkoroj5eVgboUyeP3578oJgScTQ78eBYMgfdLVaGWPPTW [CONTRACT_PATH]/opcodes/dugn.tz +exprur99uFkrwM63FXSTqSTypHcfEmzb5KQ9EypTRqZWDY5NP6tCHL [CONTRACT_PATH]/opcodes/dup-n.tz +exprtarW6tiguR7YAo6SxhCUDs1pLDhx9xJEG78h6GnXLAWpt3H1pT [CONTRACT_PATH]/opcodes/ediv.tz +exprvQhRaLYxiWN3QsJgT6VKf6DmGVuXR8DxeU63P9A8iNWA4TVQfs [CONTRACT_PATH]/opcodes/ediv_mutez.tz +exprv8Sy3DsiKMm3ZQPmi46kZGn9ctTigpLB2t6xYFdYkkeVHMXy6z [CONTRACT_PATH]/opcodes/empty_map.tz +exprufqf2G8PoZN768K2YGex6M7zmz7bYHE5LF5QHJBVvFtAFLi6qr [CONTRACT_PATH]/opcodes/exec_concat.tz +exprut53jocMPdPP8FXrKRDYSoRaxk1FXqCt7o46ak2wQaocjsSwwx [CONTRACT_PATH]/opcodes/first.tz +expru5fjTGWP1BXZz3BbbEFyDFkyZGJKHcZ2Y6jDT3CdHHp81n6G1r [CONTRACT_PATH]/opcodes/get_and_update_big_map.tz +exprua5oh3PDJEPQbEsnbHYCz6L7bY6kNvpyhEt7Cg9sPsrx82UmHQ [CONTRACT_PATH]/opcodes/get_and_update_map.tz +exprtgnkjSH6Tdw5C1BMKr8kCJjEnxCfMiaAxHTVLnEcyCQ6WmJ1jr [CONTRACT_PATH]/opcodes/get_big_map_value.tz +expruv8JdHeURNpuLHao37SGJauDPwB9yxFXUaL6hNCdXGzbHSqCZN [CONTRACT_PATH]/opcodes/get_map_value.tz +exprvHC1MDkeqCNL8yrN74nmqk5qrZCvR42qoVUxYCB4ALpgDfmhbL [CONTRACT_PATH]/opcodes/hash_consistency_checker.tz +expruzeve85eDLTpQ1EbgrQQcEUft7AGauZBwtK1ibuvJpwmZt9AE8 [CONTRACT_PATH]/opcodes/hash_key.tz +expruycqvZn4ufKjVQmYXcCfAfm7C81zN3BAqxuYVVfnpFibSKsahG [CONTRACT_PATH]/opcodes/hash_string.tz +expru34ooMhYSarFg7vZCe1Y23jwfxfHiDqwaE1wGXC48yjB21PLi1 [CONTRACT_PATH]/opcodes/if.tz +exprtmbKAmbV2XioTbmpJQpg9QDAxXkTBXmKRWdC8zbk8CWAtVXwAc [CONTRACT_PATH]/opcodes/if_some.tz +expruTGRZeiojz3Rrr45KUcwtpJuJYu6U8pxi4DBZpL2kGavVxxM4H [CONTRACT_PATH]/opcodes/int.tz +exprudLYgw6yWSrTHpXYsg9NcZxGGpCxdNFbNv7ksr6Ss8rNmh2fgT [CONTRACT_PATH]/opcodes/keccak.tz +exprusrBf5Sakr6dRngzuPmwsP28X6W56nVqCXqG1Jcfrd1SYwPRuU [CONTRACT_PATH]/opcodes/left_right.tz +exprvHZpmtBKjjsUZmchx2RTLmFAZnYKCnHSKXaKUdP5EUpiPYwsp2 [CONTRACT_PATH]/opcodes/level.tz +exprtkasRZbYRQg7WKnoXwJnRwXkvmjZEY4yPYXKGAQQFUupt5VAmt [CONTRACT_PATH]/opcodes/list_concat.tz +expru32VE4LnqAqhbpUFCdgEdRSHjLQipkXTjn624fL41yk3a4H5Q3 [CONTRACT_PATH]/opcodes/list_concat_bytes.tz +exprvCkexzSQFgEWkFvrkrQ8wATasfkbKCyeXYSM4qZft3g3UuoTBi [CONTRACT_PATH]/opcodes/list_id.tz +exprtbHaLLF4cUTh4VCjtnH32EAA2AFwvPBsCzUTgrrdofbotKMyr7 [CONTRACT_PATH]/opcodes/list_id_map.tz +expruAxpePKSFaGkjukWx4HEZAvXaWvyfyGyxCfhvK9tZjkPNSpZ1m [CONTRACT_PATH]/opcodes/list_iter.tz +exprvSCwmQGBkxgu2Tg5rYUXbyv33SpUskCJS7sPF4LN7e5pQ1fn7z [CONTRACT_PATH]/opcodes/list_map_block.tz +expruu6vcnLhDhSkSo8NNNJWQL99VCFr6iArtKrmavJWSNkQwDJsKC [CONTRACT_PATH]/opcodes/list_size.tz +exprv15pFChKhH3QKoJn5BCT1bP4R7DjnXWtTDsSfwf2eVonZNxzZs [CONTRACT_PATH]/opcodes/loop_left.tz +exprubosuA8peKBt4EEo1RsYjxSxK7HXytSkBFAjns5Zg7ncicPWrC [CONTRACT_PATH]/opcodes/map_car.tz +expruqCpEBS2R8FqpBfDNUNrPhXZr39CBL6zKpyMogJR94sve62iv9 [CONTRACT_PATH]/opcodes/map_id.tz +exprtb1QBmNfCYjce9FnvKdikbtgqcN5o2VdVwZZP2Fmy8C3TJjA7q [CONTRACT_PATH]/opcodes/map_iter.tz +exprtuspLRSrYnp2FyqNcLfsBrBBFD8nnFog2Em3p7tfG4DcGujS3f [CONTRACT_PATH]/opcodes/map_map.tz +exprtipeMFcMFwYRAmzZBMoUjrtPYDk5ZyhMSyuhSgfiJV5UNAcLGp [CONTRACT_PATH]/opcodes/map_map_sideeffect.tz +exprtc9HPyzpfc71TE4a8UbRPxfdm4WGRPNQhfB5fHiWwkh1aA8uzm [CONTRACT_PATH]/opcodes/map_mem_nat.tz +exprtrkfCSUckShrEP5TmC5Y4CdeU35FFL7R8kyJHQUFZ4DNdJZasD [CONTRACT_PATH]/opcodes/map_mem_string.tz +expruqncptpX6oXeX88mAkVHh9DnzWb6vPwT6LvuND9yobgcH5Gd2x [CONTRACT_PATH]/opcodes/map_size.tz +expruZ7Tb7uhcAu3MhiDJFWrJiYseWyagZYEnzjEdpjSei8i73hsfG [CONTRACT_PATH]/opcodes/merge_comparable_pairs.tz +exprvNxEfUTwaryUzets4qyTbHAfNPb5ARQsMsxbm8CnGNHDedqxgy [CONTRACT_PATH]/opcodes/mul.tz +exprtYi1xHmB1AY6j4e3XTPvXpmuWnM4b4o78yVihYt1i2yNjrQqhY [CONTRACT_PATH]/opcodes/mul_bls12_381_fr.tz +expruFTKqYqMmWSakzE1gjs2p8kWtcRWTaddkYL5p2Z8wpcCfe5ei1 [CONTRACT_PATH]/opcodes/mul_bls12_381_g1.tz +exprvBDM3kep2f7bRkhRa2XWt9sdPGJ79sq6TdWNNnM4yydTQ88TaH [CONTRACT_PATH]/opcodes/mul_bls12_381_g2.tz +exprujbPsZAUa1tzgWNgeHEQ22JXDfNhkgx6sCCxbWjYoNWPbTvwhy [CONTRACT_PATH]/opcodes/mul_overflow.tz +exprth31LKm5FDFGxcXg1Rv9z9YeAQ8eu2oYTh2zZ7kJas3f5CWkZm [CONTRACT_PATH]/opcodes/munch.tz +expruP5gECQdRLkmuYg8xqvEAdE4oRGFjDVG3ZkWxtCyxve1jviw6k [CONTRACT_PATH]/opcodes/mutez_to_bls12_381_fr.tz +exprtw9PgkJCxyqdLjuA4dEdRjQXY7Ge4a7jjd2UoU6Q6KrvhFgciM [CONTRACT_PATH]/opcodes/neg.tz +expru5fYi1tAG8a9j2dYT561dXaox8wYjsZDZP18xPa5JN3bUNfHWS [CONTRACT_PATH]/opcodes/neg_bls12_381_fr.tz +expruY94PxNhmT8BeyGrFurRF6gC7XfgsBY9Vjh6hJyiDPaR8nFmri [CONTRACT_PATH]/opcodes/neg_bls12_381_g1.tz +exprv9bM4xnqjA33RkvUzz8ZppJXT32KdNXoYqY2NSh7whBcFPn2QS [CONTRACT_PATH]/opcodes/neg_bls12_381_g2.tz +expruZzA96Rh5o6HBboygY3iD97dgQcepXd45WBBD4DYZ2qcn8cxyY [CONTRACT_PATH]/opcodes/none.tz +expruat2BS4KCwn9kbopeX1ZwxtrtJbyFhpnpnG6A5KdCBCwHNsdod [CONTRACT_PATH]/opcodes/noop.tz +expruMUpBKBPGde4GfNLM8NgMq9nL6KsQXGA3LPt4C6wtMTxcUnE9A [CONTRACT_PATH]/opcodes/not.tz +exprtnpHGyp2TurQb2YzbXBKTipXnrUQ4RrZwPxWfa1yMXS7oi49jV [CONTRACT_PATH]/opcodes/not_binary.tz +exprusKUuYeoKXUAYtUhtknryT9MpbPZVZtbfUNCdRpXUbdzEzbwmN [CONTRACT_PATH]/opcodes/or.tz +exprvG84juZWwLHTrhtvWFWBs8D2wZw6rfpoAbXp2pkekuCMAaPbAn [CONTRACT_PATH]/opcodes/or_binary.tz +exprv39cZxxm6fTcFSbLcwpBbAPW56FPqjdf6aGm21KqGA6DQtwn6u [CONTRACT_PATH]/opcodes/originate_big_map.tz +exprunveMvzjDskHYCvYJzDfRR9aGwwvXkVUMqTwSxJJbEjeq63c2D [CONTRACT_PATH]/opcodes/packunpack.tz +expruKkmmajE1UFXRHXtntLZU8VvnLfFKwYPd4azsAdcrDMaq5zu9H [CONTRACT_PATH]/opcodes/packunpack_rev.tz +exprtk9p4ur3KZK2w8ziFoZVHPABxQWZXeSNowcJuTauL3zTxr1zcH [CONTRACT_PATH]/opcodes/packunpack_rev_cty.tz +expruSamDrL2Dh4zp92cVgfV7ETT7VcnqACDVcvnafi3qgBZq9v3PL [CONTRACT_PATH]/opcodes/pair_id.tz +expru3WFEX5bVjBUkZzuWspLG18hy5jTzbr2WtKEYpfPHGpDFvcqhd [CONTRACT_PATH]/opcodes/pairing_check.tz +expru2U5Bi7ehgkQvP7Qmij4c8gkSFUBNtiCyXMX3WwGjEdRRZc5x1 [CONTRACT_PATH]/opcodes/pexec.tz +expruPr8QtATywJFqPjDhF7gyqdF15L6J7pxgpypzorEvtubdJN8U2 [CONTRACT_PATH]/opcodes/pexec_2.tz +exprvBUenyTMJKwERZ1ULzMVrJ1owqymBF32f627arqtFUzMpaMvbC [CONTRACT_PATH]/opcodes/proxy.tz +exprvPaPcYHvKmnyBMaYXtp6ZuaSEHWr5y92bcroKKppAZvF4RvcWE [CONTRACT_PATH]/opcodes/ret_int.tz +expru8MKLXqiNRYnPccUN4if3VnWfthDy24K4zuJrFh2JaMmmh6Rii [CONTRACT_PATH]/opcodes/reverse.tz +expruta4Bjo3FggDcvZDzEVwzeTcdZptzkJZyFEkdB8suFGbMVtT2Z [CONTRACT_PATH]/opcodes/reverse_loop.tz +exprueR2MPCHUFtPjMZXE57X3EsysuWJXGRz8ZgcPJj21UySLqULV1 [CONTRACT_PATH]/opcodes/sapling_empty_state.tz +exprvSNMswzVUk47vqs4wTGipDb3qDKVUwNBDwXtGzjCprEYx4nWPo [CONTRACT_PATH]/opcodes/self.tz +exprtzokY2FHvPvB9YHSi8MM5YUbPdUPLi7tEKkp8BKongPb2zrZch [CONTRACT_PATH]/opcodes/self_address.tz +exprvDVUQXNsfs9FiHkMSofonWCWcBfYbfxeQy9DRaa5Tnbw1XM18Y [CONTRACT_PATH]/opcodes/self_with_default_entrypoint.tz +expruXGf2YpXKkr74mcv83fQ6bztVD1RBoFXaEnAd9bidnRXcfD3Nj [CONTRACT_PATH]/opcodes/self_with_entrypoint.tz +exprudmJ37Q8ZASPbZSSBfy5UezxLhniszTVkLAB8QKvxkav4gVVYr [CONTRACT_PATH]/opcodes/sender.tz +exprurSxmHBRCHUxtXcqNkPA8UE6gaFeJa19bBhq1CarZ3CZuAzShs [CONTRACT_PATH]/opcodes/set_car.tz +expruogQk6tG5W7CtZrcMzsRtJ1f9moG9y5Qg5j29NATiaSywvQCcS [CONTRACT_PATH]/opcodes/set_cdr.tz +exprvCt5LtbC3mLLWHdvyxGcX3ND21Ym5GayCvePEHHGXAtgWu32sJ [CONTRACT_PATH]/opcodes/set_delegate.tz +expru133Wm63xA1qs5ymovjbP3N3iwPoTMcdUsbUqqbTf896jU78WR [CONTRACT_PATH]/opcodes/set_id.tz +expru151wgMY5reA7WVbnvkHrh9MVnfYFbCDaiE2aTGmkKACu2ZbJA [CONTRACT_PATH]/opcodes/set_iter.tz +expru13v2dm35MgMgTbwDJ4nEwNjRTau8mqztAyxGxXVbHNmskAA2q [CONTRACT_PATH]/opcodes/set_member.tz +expruE8c9EzG6kYQdp5RQXrAt2CekSFXVtKUzNDUnpVTDygEBP7VvF [CONTRACT_PATH]/opcodes/set_size.tz +exprteVcB53uqnwQsZMTsBojwez6tkgRqj1qWCQTLgaQWxQGiNWXEE [CONTRACT_PATH]/opcodes/sha3.tz +exprvPbB5NtiV87RARduqoXtMoRjjy6jX8WYrfiu3RDjQrTKxPQnoe [CONTRACT_PATH]/opcodes/shifts.tz +exprtnS2EjwJ3MdSWS7R6UbZMqFoUHj1JpUhhtJacXdfmmzRNHL33W [CONTRACT_PATH]/opcodes/slice.tz +exprugZMQtZN7safMU7hV5QpM7nh7Vi5ur9sGjeWsmGRkW1ETox8uR [CONTRACT_PATH]/opcodes/slice_bytes.tz +exprvCqvDAp66YnPaZDdaAkCNafoGtw1fEuWaLxMFeMnX6oqrb93nP [CONTRACT_PATH]/opcodes/slices.tz +exprtzW4jh4MgY6iXgiCXft5q3Mig5XXANHn9CmcL8ApTrdnQgWzAm [CONTRACT_PATH]/opcodes/source.tz +exprvD9HJMfLEUdamfH9U8ozBaxA7hYVRMbK7At6sUqFMmhZ6UorWv [CONTRACT_PATH]/opcodes/split_bytes.tz +exprvJcmHwozD2DTtagjJJfyPgoCvBx5bMzXAkrsteYVvxeMr9SWm3 [CONTRACT_PATH]/opcodes/split_string.tz +expruDY992zB37mWpZwFQCrfDbkwmrCmjSHD4fzQcW1z1AeWeW8M3r [CONTRACT_PATH]/opcodes/store_bls12_381_fr.tz +expruZAkBxtwSXuMp6ZDNp41mJ6uZ4bw7RF9HNzJS9EnzTLxVhQ4SB [CONTRACT_PATH]/opcodes/store_bls12_381_g1.tz +expruZfFC7WkBQhK4Ksg5k5WxBamF4PvH2NGCxcd4DHUkKfeqQEBUe [CONTRACT_PATH]/opcodes/store_bls12_381_g2.tz +exprv8K6ceBpFH5SFjQm4BRYSLJCHQBFeQU6BFTdvQSRPaPkzdLyAL [CONTRACT_PATH]/opcodes/store_input.tz +exprvStWRo24QuETruMmMqkmLme6UAMHuTRNNq9Lq65oFgUvQmJGPV [CONTRACT_PATH]/opcodes/store_now.tz +exprtZPsTsBtNf9hjv7Yfda2EV4Sz3iaHpk4NkYHcKteXbsyQ9d6pH [CONTRACT_PATH]/opcodes/str_id.tz +exprv4UZUuBDCZZjtW5kaezZjaKqpi1GN6vxHsvQNNkFktnaEbDb1M [CONTRACT_PATH]/opcodes/sub_timestamp_delta.tz +expruVuXhQmoBMzZjPeY7VQSuJxefBBTuPyNR7PGnYhwouo9zKg3T1 [CONTRACT_PATH]/opcodes/subset.tz +exprtkETLPUQ2EqTdgteuJN7XC25xCTSuEhQjz1NJiXWwAPJvDL9pG [CONTRACT_PATH]/opcodes/tez_add_sub.tz +exprugbVFDGWcSSozyN3EK3AcdwtPeES3ao45HNogWc5V8fsJ8NsSP [CONTRACT_PATH]/opcodes/ticket_bad.tz +exprtvedUmBuu66gdQXWpEJNQBU96bnUVQmrWWLAbcdsCLV4Rwa34K [CONTRACT_PATH]/opcodes/ticket_big_store.tz +expruqx789AMcKUYwDeeeRvSnwdCw8gMVvWA6vuzPzBQwBM2qcDXJB [CONTRACT_PATH]/opcodes/ticket_join.tz +exprvMp1LX8aeyEq9NiMXGyD34J4offZDANGRwFTxoEWXumEsDdAP8 [CONTRACT_PATH]/opcodes/ticket_read.tz +exprtvtEFi6v3awAwbHivJkjki6mDNivewiCBeJDJT78PqWtq7VyUD [CONTRACT_PATH]/opcodes/ticket_split.tz +exprtifPFaLqHvR9uGWbeLj5r3YVBnKaawt12q3BMhM9wsUdM9dFNy [CONTRACT_PATH]/opcodes/ticket_store-2.tz +exprvJGjz1EDdnAPWZQ7ZngDNDDDXnxA2VY6SHdHKu8LxqcVHd3E6z [CONTRACT_PATH]/opcodes/ticket_store.tz +expruhNaUWmTNpmFWSXUgf1ZjgcUXmjtXGaMumzteyFYzT9CMmU4wc [CONTRACT_PATH]/opcodes/ticketer-2.tz +exprvPfYzs3x1V67saypcaPGwj5rnuKsb3tFi2VtqX7gtP4W3sjfye [CONTRACT_PATH]/opcodes/ticketer.tz +expruhV9RSEPAtKAUhBbdTw5gPFdjcKk8zr7cVLSsGtmJuH3o7VXXo [CONTRACT_PATH]/opcodes/transfer_amount.tz +expru3MSjYZRmQi3yiN6gYa4X6rs88XLWH4H8ivzrCvxs8z8cJfu4Z [CONTRACT_PATH]/opcodes/transfer_tokens.tz +exprtbACDcFtDfEwsBA5LAG13uMRAjnQsFjzNELMS7jQ87bcqgdE6r [CONTRACT_PATH]/opcodes/uncomb.tz +exprufJpS3BWpgv4QBaBEMucbn1jsVpdqEGLLMfXjDuKGPRGCpZUkj [CONTRACT_PATH]/opcodes/unpair.tz +exprv4ACaZe4aECCfG93NGVVHbQBNQ5Atxtju5vWASZSEp5sLECcjg [CONTRACT_PATH]/opcodes/update_big_map.tz +expruWzM36ATA3fAee4WHDS4vvMeewkwhya1fZaa6HFPbjwt9vvGpg [CONTRACT_PATH]/opcodes/utxo_read.tz +expru3YgRPQBAnTWgKytSMs3tRj7dMgtWUxo75b1pUFrTLscKy2byF [CONTRACT_PATH]/opcodes/utxor.tz +expruJxgC2Q8Ubt8tPyQbZ41j6w4b8yw5f6bxjrMMM81TmMC9x5Lrc [CONTRACT_PATH]/opcodes/view_fib.tz +expru9EavkgPCUAwHccJf9j1t4aTTssPKoBkCqC4YNr12kxXSwqFqD [CONTRACT_PATH]/opcodes/view_mutual_recursion.tz +exprv4QXQuZtQE7CpKyecjrXJ8U2ovU1qjUKtw37J6kAEmu3fAKyN5 [CONTRACT_PATH]/opcodes/view_op_add.tz +exprugGjNh2tTsofJyhkNMrQVJnkyLydJywNVMAXL9rW3nhnCmRd3F [CONTRACT_PATH]/opcodes/view_op_constant.tz +exprtn56ZZ3mXHoz9GMS9HGMfmgayukvVXub8zXeDKbE4U7L5L8dXX [CONTRACT_PATH]/opcodes/view_op_id.tz +exprtaNDFRcdw8SB4Bz1a6CKARxZaoxpc6G2hnJYedp1iZgJqEwMNV [CONTRACT_PATH]/opcodes/view_op_nonexistent_addr.tz +exprtmA9Auh8GAHpvKP2qkVhiaRCtokWcw7qg31CaxbouJW1g8yYK7 [CONTRACT_PATH]/opcodes/view_op_nonexistent_func.tz +exprubMFU6xrnHREoXUZinEeV3PuZBjSw35M6gti7tyQ83S6LTKja1 [CONTRACT_PATH]/opcodes/view_op_test_step_contants.tz +exprtj9pixxS7UHchhthZa8zdU2GAjvW7oA7QEMA3PHgf88vmAEjFb [CONTRACT_PATH]/opcodes/view_op_toplevel_inconsistent_input_type.tz +exprurrbjDgnipRBhqb7pPLQFAgtPm5jrpwJjJL5ZvQyFJZzGvqteY [CONTRACT_PATH]/opcodes/view_op_toplevel_inconsistent_output_type.tz +exprvSPcq1w7iTMA3LjQcHegnRUQ621sqQLRJm1Zh4tjHCkmeZV268 [CONTRACT_PATH]/opcodes/view_rec.tz +exprv1LkSMvSyZSBrg9Tf2PdcoiWDYPz2npmYb7rH6bWx2sYMAHMgg [CONTRACT_PATH]/opcodes/view_toplevel_lib.tz +expruF13NKWWyF51seiYv4tsb55dZHYViNWDKTmhLq9b1LXXenwaB2 [CONTRACT_PATH]/opcodes/voting_power.tz +exprvSZMaiMSbKgRYm1W4rcoBGN21bPu8NMQuYBH9ujhXGeHhdtVGk [CONTRACT_PATH]/opcodes/xor.tz diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_fac.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_fac.tz].out new file mode 100644 index 000000000000..8f321d919e31 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_fac.tz].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestScriptHashRegression::test_contract_hash[opcodes/view_fac.tz] + +exprv5Zq1iL1bPVUnL4TZZcmuezBhf3BBoCa3HyktPw1AivsHv1FnP diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_fib.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_fib.tz].out new file mode 100644 index 000000000000..e2582d9c5d38 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_fib.tz].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestScriptHashRegression::test_contract_hash[opcodes/view_fib.tz] + +expruJxgC2Q8Ubt8tPyQbZ41j6w4b8yw5f6bxjrMMM81TmMC9x5Lrc diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_mutual_recursion.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_mutual_recursion.tz].out new file mode 100644 index 000000000000..cdfd2eff58a8 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_mutual_recursion.tz].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestScriptHashRegression::test_contract_hash[opcodes/view_mutual_recursion.tz] + +expru9EavkgPCUAwHccJf9j1t4aTTssPKoBkCqC4YNr12kxXSwqFqD diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_add.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_add.tz].out new file mode 100644 index 000000000000..ef762e4e6051 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_add.tz].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestScriptHashRegression::test_contract_hash[opcodes/view_op_add.tz] + +exprv4QXQuZtQE7CpKyecjrXJ8U2ovU1qjUKtw37J6kAEmu3fAKyN5 diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_id.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_id.tz].out new file mode 100644 index 000000000000..bd187a3dcbee --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_id.tz].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestScriptHashRegression::test_contract_hash[opcodes/view_op_id.tz] + +exprtn56ZZ3mXHoz9GMS9HGMfmgayukvVXub8zXeDKbE4U7L5L8dXX diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_nonexistent_addr.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_nonexistent_addr.tz].out new file mode 100644 index 000000000000..12e81a4f5de3 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_nonexistent_addr.tz].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestScriptHashRegression::test_contract_hash[opcodes/view_op_nonexistent_addr.tz] + +exprtaNDFRcdw8SB4Bz1a6CKARxZaoxpc6G2hnJYedp1iZgJqEwMNV diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_nonexistent_func.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_nonexistent_func.tz].out new file mode 100644 index 000000000000..6daeb2f5040e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_nonexistent_func.tz].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestScriptHashRegression::test_contract_hash[opcodes/view_op_nonexistent_func.tz] + +exprtmA9Auh8GAHpvKP2qkVhiaRCtokWcw7qg31CaxbouJW1g8yYK7 diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_test_step_contants.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_test_step_contants.tz].out new file mode 100644 index 000000000000..07551f137aff --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_test_step_contants.tz].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestScriptHashRegression::test_contract_hash[opcodes/view_op_test_step_contants.tz] + +exprubMFU6xrnHREoXUZinEeV3PuZBjSw35M6gti7tyQ83S6LTKja1 diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_toplevel_inconsistent_input_type.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_toplevel_inconsistent_input_type.tz].out new file mode 100644 index 000000000000..5f2dfb7851f0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_toplevel_inconsistent_input_type.tz].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestScriptHashRegression::test_contract_hash[opcodes/view_op_toplevel_inconsistent_input_type.tz] + +exprtj9pixxS7UHchhthZa8zdU2GAjvW7oA7QEMA3PHgf88vmAEjFb diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_toplevel_inconsistent_output_type.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_toplevel_inconsistent_output_type.tz].out new file mode 100644 index 000000000000..850858ab0c61 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_op_toplevel_inconsistent_output_type.tz].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestScriptHashRegression::test_contract_hash[opcodes/view_op_toplevel_inconsistent_output_type.tz] + +exprurrbjDgnipRBhqb7pPLQFAgtPm5jrpwJjJL5ZvQyFJZzGvqteY diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_rec.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_rec.tz].out new file mode 100644 index 000000000000..6fddc46ee0e0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_rec.tz].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestScriptHashRegression::test_contract_hash[opcodes/view_rec.tz] + +exprvSPcq1w7iTMA3LjQcHegnRUQ621sqQLRJm1Zh4tjHCkmeZV268 diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_toplevel_lib.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_toplevel_lib.tz].out new file mode 100644 index 000000000000..1a7dcf7a25c2 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestScriptHashRegression::test_contract_hash[opcodes--view_toplevel_lib.tz].out @@ -0,0 +1,3 @@ +tests_011/test_contract.py::TestScriptHashRegression::test_contract_hash[opcodes/view_toplevel_lib.tz] + +exprv1LkSMvSyZSBrg9Tf2PdcoiWDYPz2npmYb7rH6bWx2sYMAHMgg diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestSelfAddressTransfer::test_self_address_originate_receiver.out b/tests_python/tests_011/_regtest_outputs/test_contract.TestSelfAddressTransfer::test_self_address_originate_receiver.out new file mode 100644 index 000000000000..e58f05a00fa4 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestSelfAddressTransfer::test_self_address_originate_receiver.out @@ -0,0 +1,50 @@ +tests_011/test_contract.py::TestSelfAddressTransfer::test_self_address_originate_receiver + +Node is bootstrapped. +Estimated gas: 1411.143 units (will add 100 for safety) +Estimated storage: 340 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000462 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1512 + Storage limit: 360 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000462 + fees(the baker who will include this operation,0) ... +ꜩ0.000462 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ0 + Script: + { parameter (lambda unit address) ; + storage unit ; + code { UNPAIR ; + UNIT ; + EXEC ; + SELF_ADDRESS ; + ASSERT_CMPEQ ; + NIL operation ; + PAIR } } + Initial storage: Unit + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 83 bytes + Paid storage size diff: 83 bytes + Consumed gas: 1411.143 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.02075 + [CONTRACT_HASH] ... -ꜩ0.06425 + +New contract [CONTRACT_HASH] originated. +Contract memorized as self_address_receiver. +Injected block [BLOCK_HASH] +[ [], [], [], [ "[BLOCK_HASH]" ] ] diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestSelfAddressTransfer::test_self_address_originate_sender.out b/tests_python/tests_011/_regtest_outputs/test_contract.TestSelfAddressTransfer::test_self_address_originate_sender.out new file mode 100644 index 000000000000..e9d94adb8e70 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestSelfAddressTransfer::test_self_address_originate_sender.out @@ -0,0 +1,50 @@ +tests_011/test_contract.py::TestSelfAddressTransfer::test_self_address_originate_sender + +Node is bootstrapped. +Estimated gas: 1410.574 units (will add 100 for safety) +Estimated storage: 339 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000461 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1511 + Storage limit: 359 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000461 + fees(the baker who will include this operation,0) ... +ꜩ0.000461 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ0 + Script: + { parameter (contract (lambda unit address)) ; + storage unit ; + code { CAR ; + BALANCE ; + LAMBDA unit address { DROP ; SELF_ADDRESS } ; + TRANSFER_TOKENS ; + DIP { UNIT ; NIL operation } ; + CONS ; + PAIR } } + Initial storage: Unit + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 82 bytes + Paid storage size diff: 82 bytes + Consumed gas: 1410.574 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0205 + [CONTRACT_HASH] ... -ꜩ0.06425 + +New contract [CONTRACT_HASH] originated. +Contract memorized as self_address_sender. +Injected block [BLOCK_HASH] +[ [], [], [], [ "[BLOCK_HASH]" ] ] diff --git a/tests_python/tests_011/_regtest_outputs/test_contract.TestSelfAddressTransfer::test_send_self_address.out b/tests_python/tests_011/_regtest_outputs/test_contract.TestSelfAddressTransfer::test_send_self_address.out new file mode 100644 index 000000000000..b58264fca65f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract.TestSelfAddressTransfer::test_send_self_address.out @@ -0,0 +1,42 @@ +tests_011/test_contract.py::TestSelfAddressTransfer::test_send_self_address + +Node is bootstrapped. +Estimated gas: 4812.766 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000786 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 4913 + Storage limit: 0 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000786 + fees(the baker who will include this operation,0) ... +ꜩ0.000786 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: "[CONTRACT_HASH]" + This transaction was successfully applied + Updated storage: Unit + Storage size: 82 bytes + Consumed gas: 2754.768 + Internal operations: + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: { DROP ; SELF_ADDRESS } + This transaction was successfully applied + Updated storage: Unit + Storage size: 83 bytes + Consumed gas: 2057.998 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_one[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_one[Fr].out new file mode 100644 index 000000000000..9143512060a2 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_one[Fr].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_one_one[Fr] + +storage + (Some 0x0200000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_one[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_one[G1].out new file mode 100644 index 000000000000..47caca9abdac --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_one[G1].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_one_one[G1] + +storage + (Some 0x0572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e166a9d8cabc673a322fda673779d8e3822ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_one[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_one[G2].out new file mode 100644 index 000000000000..56cd70a9b275 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_one[G2].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_one_one[G2] + +storage + (Some 0x0a4edef9c1ed7f729f520e47730a124fd70662a904ba1074728114d1031e1572c6c886f6b57ec72a6178288c47c335771638533957d540a9d2370f17cc7ed5863bc0b995b8825e0ee1ea1e1e4d00dbae81f14b0bf3611b78c952aacab827a0530f6d4552fa65dd2638b361543f887136a43253d9c66c411697003f7a13c308f5422e1aa0a59c8967acdefd8b6e36ccf30468fb440d82b0630aeb8dca2b5256789a66da69bf91009cbfe6bd221e47aa8ae88dece9764bf3bd999d95d71e4c9899) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_random[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_random[Fr].out new file mode 100644 index 000000000000..24cb9b4d5976 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_random[Fr].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_one_random[Fr] + +storage + (Some 0x660dec4a316a24f34cad26e886cb480da89c55113f5c1a2b6bfdaab82d737708) +emitted operations + +big_map diff + + +storage + (Some 0xa711c66e47a4f376a769f9accfd675dcc6a2b9ce09c0482923c19f8218f16849) +emitted operations + +big_map diff + + +storage + (Some 0x111a13c7d5feb5e8fe5b2c5550d3335c04737fcbeece373eabf07b1b1604bb3b) +emitted operations + +big_map diff + + +storage + (Some 0x366bf41ff7bd7828a3d206500267d5c888aa120292be0cd6399fe4b9db75625b) +emitted operations + +big_map diff + + +storage + (Some 0x86b8dc4aa73cccb08dd143980ec0a4f73c2067807b3b4f2ff96368cb5efd8d4e) +emitted operations + +big_map diff + + +storage + (Some 0x7b83a6a4c37d5536bebe96766b25195e32b69257f3dc2d1e6fcdd7144db0f80c) +emitted operations + +big_map diff + + +storage + (Some 0xac54d72aff4eb7b9acce60a61f8f2ca1a1a387557cd6df2e9fe690ce209eca63) +emitted operations + +big_map diff + + +storage + (Some 0x183b7f72e291320045c63ad9453dacada669ef605e72c708a8735ae2fa7f795d) +emitted operations + +big_map diff + + +storage + (Some 0xb82eba460eb5d8e64d597cca0278098e87f2e1bba06d0fe19f6da2075084c66f) +emitted operations + +big_map diff + + +storage + (Some 0xb87216f6813286cfabec830fa176f2aa127cc1b99b824d312bd8d239c2555d6e) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_random[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_random[G1].out new file mode 100644 index 000000000000..3614cf3263dd --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_random[G1].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_one_random[G1] + +storage + (Some 0x058026aa05e53a8be99d756ad00d2f3577786eeb07abe3d0bb51a9c6c4786fa31579791ecca13a22e423a3ca2e1d8ae6049f0d41d63294fa63d9679c2dfda2ccc5263bdff7d8f404fb566e3a420fdf9bcc003cd33b7d4a46f1d9a1dd059c879f) +emitted operations + +big_map diff + + +storage + (Some 0x11613e266146d8bf256974bfd8bc7bcfc1aa33d1abb8407d5199c18c1d71bdc27c37bcc64a30f3e39ef8f04e521a099a029636513b15f1e71a7aa6042fff9d1d552c542caa5f302071504d524d511173027aa21ad9d1928dba8a201c9f24d9a3) +emitted operations + +big_map diff + + +storage + (Some 0x026fcea34d1a4c5125142dfa3b616086309cab49e60e548d95de658af4d9329c269dc132bd5d884617e8767600daeee90c6f5d25f3d63540f3b799d291e5df4a90244346ed780d5c9d3afa8f3c9a196e089fa4edc4a9806592e8561d626579e3) +emitted operations + +big_map diff + + +storage + (Some 0x0f048c8e56ad4ddbb3fe800e2667ecaa5683d33a2828c7f9341ed2708f83e1cc58484085399822f6af8f05e9761cb49f0ee1db03e81501d8982d1362518386e77fbcf240d9d4768187ab4727c6b4ede0057dbe0358f37dac17eb2eb395088a44) +emitted operations + +big_map diff + + +storage + (Some 0x114c27c6a72b3eb7bb0176261d670ce20a9cf90a52da5b68faf2013bac314f7987e735ac04ebb1c164a48f60c16ec4be0c1eb74c865b1df94202b4eceb42e22d86099ad360339303463d68c0d931774304fa4c780208abcf1c79640b0c4190ce) +emitted operations + +big_map diff + + +storage + (Some 0x054b5561e8d9de0052a167f4886efd49890dfda073843dee3077c37ccb3d7ad2326970eb9615f318a0851b30aaa7f1150b4a687ddf9672bdbcf159358ea75025adc8584532a046b48d30868ee38dba0ca8a209af29cd791594cfb7e9ae991119) +emitted operations + +big_map diff + + +storage + (Some 0x174e2a1898303aba4520148510fbdc740d8154886d04d1ef7f65c904cbd2171af98345f2463bf26c35576da1be372d680bd755d4c860640a9991cfe703590382c2c20ab7121bc94926dac025e25526ffbb234785bfb6eb5ebd9b8be521e5cda3) +emitted operations + +big_map diff + + +storage + (Some 0x04cf46cee905ad068310d3e0764cba786372efd7eea4a8a2354da24eea26af1578320cc25a5c0dd9fa016c16ef956b071529c2fe97c6c69690675a5484220900d6c48d03976289801f818899416e014e9d50ca19c165b9c43e4de8ee0b16a792) +emitted operations + +big_map diff + + +storage + (Some 0x0ec968f32f75a84a3bac57f2025ebcef650a8ccf5da9b27ca53331eda42ca2848948e8e9cc7588acdc9430ba4051a0c70ada591853bf90ebcd4df22ce469c453ce5d4bfb7d968ba8b85ec48188f7912a549dc7a81f246264da9b355aeb1b0178) +emitted operations + +big_map diff + + +storage + (Some 0x018637aff527610ee1a083eca3f3ad2a989dbcce2a393e24703e52e418b8d373433155bda3bb4664aef12d8cb058932d14d26d519045ce36b21cb50c77373077cced9fc000b8696cc5e035ad7d2dbdf41971c8403bee31ae0a6a36263066b847) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_random[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_random[G2].out new file mode 100644 index 000000000000..5e4f499c5771 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_random[G2].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_one_random[G2] + +storage + (Some 0x139bd98ba7fa37cb7e1ba9177ca818063bd14a8aba77a7f4dbff7a6c848683ac17415104d5c63e46df848499f209dfbc105f18d1e114210fbce28d22f30818e75bc412526a55f7937ac290bf37adadeee6f40b9614b74b1962376d5c3078085a02a53c9021eba8b107a43bdebaef9fddc6a8c8d8c19138d06a332f986f256c32b8f19d5e39f203eba23ea36b4bcff9300dad02b62de4defe358fe6b835b3d93571ef66989530e61090c3db145c389f66ab2ee01e4f05a9ca18fb1ecf48faed94) +emitted operations + +big_map diff + + +storage + (Some 0x192438792f58ae648d5cc73d07d263f0866430fa798d61cddcf35ac48533cd60ceb7e1adaf2ac7475b0819d583b5fe210454a94b83d8a110f699db4c1963dd9bbc1f5b8d1de6ae59f0c5c1d0c0fccdc04d5cfaf901b9c1b713b48938589bd53419a11025e8f61abf088d72b3fe3e3f8d6682e235804855d5a02897ad8ce252fb2584670c27dd81e48ba14d01b09add9e0857cd0cfd23bce8702ad2cf73709debce427df15ba1bd920c941eabc712fa2652e906a1f49d604222410929de6498a1) +emitted operations + +big_map diff + + +storage + (Some 0x14e9b22683a66543ec447b7aa76e4404424709728507581d0b3f60a8062c3f7c7d3365197c59f7c961fa9731084f5be60d0a936e93d556bdef2032cdcae2fa9902dcbe105e01d7ab7126d83486d882c4efd2fc1ac55044157333be19acf0cb7a10bc41c8081c9babd8d5b41b645badd4a679b3d4e1b3ea2c0e1f53b39c00b3889a40306c9b9ee2da5831e90148334d91016474d07e0f4e36d2d51b5ca11b633b9a940b9c126aebf4a2537c18fdc6967fb677824bfa902157e53cb499a021e57b) +emitted operations + +big_map diff + + +storage + (Some 0x139bf65acd684812defe34a647e77d562d16ec07aadc8df7460835bb42e52783265fc7062d24399533488aa26f177f300a05c44ba3deb272a9334bfbd15e3df49169622e8cc739c8d8ad1658769e94f28c36b3ddc608a71ea590f5d956820116019860de9ec8f5257791279a546c6d7efc62ce91114bcb11053f999f5adf35c0f0da321602ce11347567aefe05c58bfc17693d82a530ed5c07e7e1d87d3ac3c639005480f5fc9b9fb378aa693781d0ba8ee097bff01964faa41c9361ae9da3ed) +emitted operations + +big_map diff + + +storage + (Some 0x17df1d683296888e1ef6becb004061a658609faa7aecfc56e09be2cb07f621e6bf383f3ed9eaa5ad6eb4c5ff3e4ac51615cf8e6d23843b1665d6efefdc8024b15651ee05b939f1fc529a5d4233d58ee83cd4fcd07508eb0fa1229bf649db9fb407167c5d410f1f4c403bd4cc234e3f757d74587ead39d549b88e6d6e0e187498386152a981e26a0ecfbc89349db5e5f502e61c367aea8d829cbc8d2441362f075c9245a82c8daf849dde2316fb06127db9eeb2d99a5bfee90e39ac18ac062db2) +emitted operations + +big_map diff + + +storage + (Some 0x072666f55bcd0330329524efb1a8bf981fcb0ee73c739be4b83339fa2953888bf058a115c834ed7460f6ef6e7aa36d0d1002adc9e373cfcfc62f47a6a6670700c749e6df92e360fa0a379c5621b39f35b02c578aea5e79d54f692d2fab9ad7c01527640d6462324d6a137bf7c36abd863f3efe2953d3b1729e8d3f07321af14f38893ca2e61eba4c987a5f7988569c4f0626e86728ce9292df1bd38c5e21b32d329b86f8f41eaa11eac36cc0ddf0b3fba543d94f4d3a4b992eb7e60fe9680072) +emitted operations + +big_map diff + + +storage + (Some 0x152f2b940efd3d2c53640e2ccf881935f114404ac116a54c859c59511058db4d7e2f4369e3e846ccdda94e72e22e06ce0fb52ada3931bb686d52e45ef020b58b9da28f370cd27a595b07eae78ec26e044f58c15cd256fb426e0b862a37bb751212256f5e61ef53dcf799657d5071e6dfa1040b2ac0ec31e18069d2e6e7e6424d09ece1b68a8be6d56dca3de4d467e8a80c395cd9ebe4645d3e465f0263bc100bb9d49dbaadf0572836c8bf03d8c2155068a1f56017864a51e8f4915d24885afa) +emitted operations + +big_map diff + + +storage + (Some 0x0c5ae8a5d7042b893b4600512b81b205b0f3aec3b00d0b2ece549e31c0466f49cd8900270ac48f253e66dc8a05a83e3c0ed8790344651fb0d17ef0c0f86340687e890424c06b5426e6732c3ff837ad4c76a2dfb9f5d80e80eadd024cc4c386f10bc203d5bba633fa3f50fb84140e9ef8c0f7c83ad41b2d1230b8af982e541c07f137b59b71142a4e2be49d9a0fd1212f11fe2ebabe025ab38dfc64f38e724edea44610b88239679e60d9ee151174a3bd1425eb865b8533c0b833577e430ae37a) +emitted operations + +big_map diff + + +storage + (Some 0x127093c56626b5e31114ddc6565ac257c3f5642d4eeabb469c2e6cfa23c713bd87fbccc738eae6c6356eb1bc3e62babc1985437cd7bcf96041d3547efa5c1c5ab0dc66aecae18f5a70055a4f4c518b6f7f31f18709d0a7f37f5eb3cd413557f7164ead5569fd618dee7145ce3b5786a4d5551c63b6936e682e618f9db2aa1c97117369cde387255d063890b4a7c788b80ebabf2427faab4c8cc0a71d467ca7c78cc625fd9dbb48fd485124cdf1c5748f6488a06f1e71b429fc904f249fd5885f) +emitted operations + +big_map diff + + +storage + (Some 0x0e18a45de8e16ce54070d9df1ee055e933e7c65e2d33bbfd9eba62dbcd84c00eca86bffec4f0e02ea6172242243ca205067af2bd83fee2481e6ed3fee5b327e9d7aa95513d1fa3b60093b86b29ae14df53b03ac63f5b0c2ea3df9575fddd2bc7045df4179eb4de582fd6c3955d1947036131eea418e57fa977181e9b7c6af89686f47593bc3e1d9ea0be7c46004f23ce0d3abe0bd9fbae591d5b3fba5ed26ee6756ab595e79f27825afe20fa68d7d6b954356b589c80dc909d5d91c6afed0440) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_zero[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_zero[Fr].out new file mode 100644 index 000000000000..1421916e3ce9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_zero[Fr].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_one_zero[Fr] + +storage + (Some 0x0100000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_zero[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_zero[G1].out new file mode 100644 index 000000000000..f4769b68c1c8 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_zero[G1].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_one_zero[G1] + +storage + (Some 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_zero[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_zero[G2].out new file mode 100644 index 000000000000..e81fc06983e1 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_one_zero[G2].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_one_zero[G2] + +storage + (Some 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_one[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_one[Fr].out new file mode 100644 index 000000000000..6ef1e41e240d --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_one[Fr].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_random_one[Fr] + +storage + (Some 0xf09d35856fcfe3dd435bed02f67e1a34b246f9eb48f9034e3bce2a83ba806c23) +emitted operations + +big_map diff + + +storage + (Some 0x2a5cababf8f15f832f44e2a935f029722c2e4c87fdcd3ad1bf4ec872042d9f11) +emitted operations + +big_map diff + + +storage + (Some 0x90bdbed3c04f5a16f7dd885aa2bf82e0688da08f687d29a38c6ebf46631d7a38) +emitted operations + +big_map diff + + +storage + (Some 0xb0df3414f8f1b9b0265f7d243790b57dbf3f028bd0e99707a4ec7c6753ff9c5a) +emitted operations + +big_map diff + + +storage + (Some 0xd908b12f4af05efc5a4fc60806a64be2cc267846d93f2d6e857334c2aa66dd62) +emitted operations + +big_map diff + + +storage + (Some 0xb2a92200b1c95da0fbc293e7fb078961820240c26c87ff727a63fbcd3bf7591a) +emitted operations + +big_map diff + + +storage + (Some 0xa4fcd4658ae7312cd766f6d32afb2a57acbc386000d7a817fb45b4ddb7064c5f) +emitted operations + +big_map diff + + +storage + (Some 0x93e781ac13e039a74b9329fe4c62581e78cbe5f98c3a40ef4aef0afffb52e915) +emitted operations + +big_map diff + + +storage + (Some 0x4c7dc9dffae7cafafb2d713f334576a96a530ed57c5fe4c083130f67cce8c33b) +emitted operations + +big_map diff + + +storage + (Some 0x2a72fa0e849cecab222419ae6b7ef22b21221f06f7755caab4aa0c035d10d90e) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_one[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_one[G1].out new file mode 100644 index 000000000000..c33a505e8b2d --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_one[G1].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_random_one[G1] + +storage + (Some 0x03511648ff12b05121af6aee879ec39ded8e895f3bf83c64425c374ed1f1eb022d69b23657d36c7caf3a4680c0ac4617193583c1f57a61b18d61b2584a9b373bb45564b67ebdb884f7fc771ee639d596d343b302872a39a649b25eb4420963af) +emitted operations + +big_map diff + + +storage + (Some 0x01382fcd60894365df78f25e41a72e66a8b82633a94c8aad9a782bf880951b2e77794775bc0f2beb2200896c3042f24219fbc49d8c9f4a446ef1e5d3c8bf0d5da5e5c7480389030f971eef2fe382ecf7017351d7a838456e9f32fc7c32400277) +emitted operations + +big_map diff + + +storage + (Some 0x046dfb65aeebf558d612af9e6efe5aca9332026c0bf584afe7f11166a511a209cb750b2a037f28c476d49c0f8d5b42401479f06b06eddadef2139b142d1f44d4d63ec870a12fd574a89fefb05000a48a0c1d4cad1ec1fb53ffecbb05d2fd1a26) +emitted operations + +big_map diff + + +storage + (Some 0x12f06982de9983d040b51bf0cbbca5c8eebd6636f81c49a4b56d06ef8092126c50a0451931917a5ae0a551b16d0e3fa60bab06dbd78fc6a64f6c9647ae4ea534baf2fa5f08d438399937e4458563f47c1e8c4f0495d5c0f6609492d548310cb5) +emitted operations + +big_map diff + + +storage + (Some 0x0d8b71b72b170030fcb76bc7324fa823f8b59f2cb6b014687620a3d01c8cae25a41c423ff9258524571ab273fdd1783704b9fd0d5a4e1801cfb819aff9297579012d3cf77291ad1a2748fb1727c46fe3d0f9d2feadcc57c2cd495b6cb9314a5a) +emitted operations + +big_map diff + + +storage + (Some 0x016a3c5fff7923ad1c3566886a6dd256e32e69d992fd92a34496ae3667b33df6b699b7805fe732c68c98703e93a2ab9716dcf3d2a244889d3ff2804b9aa2043e7b07398789e39b8ac022606a90f303f176dca030856cc0777c2df1f7fe1a58f3) +emitted operations + +big_map diff + + +storage + (Some 0x11851bdd68f0062a6f4729647cc25af2431689ef7bddd79f82a4682d6d1292fcd7922a697a4fb8982d26680ad4af336004af74b34bdb318d0fdae9d0413065d47a5202903a59cb033460b3d88b942e5f611d542fd2e8b9c9d300b3b153f43efb) +emitted operations + +big_map diff + + +storage + (Some 0x07809251bc1b99439e63008e8d783acbe2fde93625f4175c33db220d96c310931753794535e47d84317de54b035582e9060a1f49de845f3f870a46e7e8939bf2d387f2e6d87f2244cb26b9e153723629d92adaa94f46e1be7458fc45c556fb0c) +emitted operations + +big_map diff + + +storage + (Some 0x0ce4e3355f0a5df9eab02eecb2510de9a9837611481d4fe8e5f803e7c60db5da63a1afb13a019a0f1f199d0ffe87297c01d5cbae9a4df48cef28ab34c8e2a684b1601fe30729e2512e937eea6e4071fb715926508fe1efaa9edf0633a1057718) +emitted operations + +big_map diff + + +storage + (Some 0x1358174de7b56cf42eb7d6ffe1ed41fefed8bacb3b18c88925e69ec8c51992ff84942d2d468d49e256d77c5d38d9d71b016480cb05ae9ed0c549b8446e9366493ceffc9471c206a359d8c9f58351ee2f6292208442baa3cfd09813af73d0b7c7) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_one[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_one[G2].out new file mode 100644 index 000000000000..965e9b45b101 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_one[G2].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_random_one[G2] + +storage + (Some 0x08fefb71e4511ed0d6a3bd0409725b908a0c192d13307a72b1c83e586f534897e3d2a7276eddf2c0027b44058e5da8e11911a8bae300eba2295ae0121dd9f78d2dbb3fa6f38f397b8b67dfb43d1c7303e699925597f04c463c55e625b66d0c02107220b0a6af8b1c2f445c396e3920a573e573b90d51d0d7e3baeb7921f35a261a1324fa74cb05cfc5dc3b09c14ea2fb14e0c74a54dd945b8256a69e2f72c084e54e29ba8b0dcaae61f8dded3054c47d0e96eee36c0bb002d2803f7b51cfb96f) +emitted operations + +big_map diff + + +storage + (Some 0x0508c45054a19a896a24fc4cd6f35ff97a3db9375bcd489f2737f4182c6f7dfbbb7412497f3609d417e44934c4ac10b717c67161445629d6d7532e40929c795b8b3d672a053cb59408352c24d5148e97e807dfbca83a3fa49a629b4a00a5a79c0f2f871ff459bfe82b647c864560019a5894f7b0725917bded14f81631f4df52cb88e0d72fb0503d90a562f7b28f49cb00ecf93cf750fb701e2e3fb50a7f1ddb205562a0c84097c241a0491785a8080fcb0340842eb81908a282343ca94c6d38) +emitted operations + +big_map diff + + +storage + (Some 0x128b9b6b5677981632671b3a4200b33265fe75ac2569fd7613357b59dd740e2abb342cd40c3f7021972c2b85a4cc9f680f7e28d1c48fe5bd039569424c63eb9606e7199bcbaf81d3b45ecaee9f469a2278ce9b933961384a21cc547facaa61cc03b6424ecc1f5d20cbec956c93024ed9153c2c3862fdcbcaac5cd2e13806f6ae2ca4d3253b7f712b54c879e26dbf3e5807f58735263798c2c6bc07be9012e4eb586d64021ce5a0ad7ec6dac72224f7a121f2630f07a49e4ad438e359b72c16c8) +emitted operations + +big_map diff + + +storage + (Some 0x040323c862873989f4eb7aedcd6cf03d9c4e6d89fe86ab05767f3b10b988fd452383160f11559ec04b6ad10fab6765fa07416b61c915c55945811dec59808a3640b58243bcdf79cc7d8c5c7b4769118e86fbb5cd9296b6ea8b1009b309f33f6619c20ac87938bd643e0d8fe7f41a2f7fb89987340cc557beb9c499b7ae0beb651d13a16b55fed41e98e8118495d570e3165305df86cd00ab6b884471b0c89c2099731f613bdf07fa5b453fe47edf688b7e340f24aadef705903b4c0abe322a90) +emitted operations + +big_map diff + + +storage + (Some 0x05c66c2a9cd7bff629a8be6b6915f8cbd5b9b50430ad9f1f95ef83df93a289b14b0c069a45e9a3083c8091222e3f44e30b3ed9b7fbec7939db06aad0d5140c7c4933840deb9a514e568e2efa86a4ba835752a6ca91359f8dc20ac43f3fb30a3c04f8c1d1e302d37a0ddf2f4cbef9cc2b317ff16dd818725cb0d0195974992b14ee683afa06101db2acc697ac3f4202ef126995a62e8ae1dff6298dc9f768ab5a183d3a00cc56c81bcf3ab05c17087e66e743d559a4707b23c4b33f484aed3848) +emitted operations + +big_map diff + + +storage + (Some 0x03c9200acd88aa776039333734833f04c3673ef47f8e39ef44a98489a3683f6eb75032a6a5e134adab3b0c06931f444c10c4302c59f70893d23492c5ab767a6f60bc5521aa4ae879706b992726ce64cda1187e26ae2fd0cb3d05fcfa3e8f379902765404f27b2d4b0e22b20cc86a9ab7f0cd3f3f13fb6863ff9d4f26860c3905341d1a267a738e4385270f746afc93260fb6b00fe51f9a34c77e18e99d2c6e21c653eb82450e5bfb2d0d9a40d5e45696a1e1b4e32ea747f1e87500177b67e37c) +emitted operations + +big_map diff + + +storage + (Some 0x0cf8aec4898b6cf6698e74551deb9aac87a11dab50c7a3cbc69b2c4b4b230e9cab2290f2135fc365a6ed4dfaae5504821866a9bc35f182f2bc41a5bc2e4b998385e157bb9b7aab5b3722aa145b45681c85318f45a754c6c324b8ed3be1519ac013f476059991edef5732f11ccef162d314a7eae6aa22d8ab1d63a9d7207bbf3eb73021dc2f3562a7c69326de49e44470106e5429bda1ad096008838511176e879d4902b41cad20ac87bbc36c0d79d424e2a396893566cedfff341354fe901619) +emitted operations + +big_map diff + + +storage + (Some 0x0b9da9500e096383beb19b243b5d02ce37649b33f4e1671d649d8804552882fc1eee23f9fd522b022cabb4c962f73f0208e73a90df86cfcada188576f7f9d0a68b274aa0686402cd6b9af6fa0077d090c7d876faa1ff8222d00a8cd137ba02d31751a64a107ff326767085a8e486c60b604fa734c79935604869499ca2c5a79a8d37fc453c48cd18406e1486b7169445020494338e65c0db9bc80313cd0c4f8bb0c3d797e2a043652d5ee3a13e9ec97b6caa76b139d9e0ca05dcce3318a0ac4f) +emitted operations + +big_map diff + + +storage + (Some 0x091a244f18b87030e2b863c4229cb5e1afe53134e8a49ef8381da6f9a6816bd811cc485d0d9f4af8e702d2473367facc10c88b308cd546cb4f17a41ecf063b1326771b8b06099c402d787fde9f0cc13e837ca584134f725fc4d257ae04aa791d1100b618548b45488a0a0c52831f0f6252d805cc24118a8077d3985011d9afd8524d0dc630fd9c9279187251aa699bb308c895051974015232739452ad614031630ec533cae1f874210d39fda10a3cc34816075703b6e1c7f2902c6afad0518e) +emitted operations + +big_map diff + + +storage + (Some 0x1401fb979d3d7ba9f9b7464c12cc4b299242008ae161e00bccc6d791f8c6c69475eced6fd21f854e1f10e479af46730d08f0ce149b481d41e0862e195794d641337be00ad3ddc17eed2a107d6b20c8abfd109e0f75416f8d03059aa54e1b5c31170a0511c66e5557226619e6d0ddeb786b77fbc2a0e4125d37ed956db6f8eff7238e326d4dfe859f452b9082c21be1c60aec585dc2296b6ba5c10d91ab8235cfa1aa64f11bd5bab8bd9d929e6d0d86e8ce126617376551bc613366fd6e4ded1a) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_random[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_random[Fr].out new file mode 100644 index 000000000000..afc49fae6d35 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_random[Fr].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_random_random[Fr] + +storage + (Some 0x32c59df1aa60931c6fa6ff2b2d3358ebb570cc673b3519afec797a9a4dfd7427) +emitted operations + +big_map diff + + +storage + (Some 0xf2bff685b56f9e6f601d6a12abdf82db11d0ddf088620f605f873edacd48213f) +emitted operations + +big_map diff + + +storage + (Some 0x49c26f616a9483bbcfa389d8cf7fbe992621180d464407e757114a0804103f1b) +emitted operations + +big_map diff + + +storage + (Some 0x522f644c7566b3ad9445a0ac25b904b76c72434093ac409435d135f6e88e1431) +emitted operations + +big_map diff + + +storage + (Some 0x9efb69b24f277cbd42e5631c2e0ca566bfdaa9d27aa9608741b691fa01ce913e) +emitted operations + +big_map diff + + +storage + (Some 0xf0a71c2682cf211a1c325c530d0505eadc8a18974dffa4619e9b191050540c68) +emitted operations + +big_map diff + + +storage + (Some 0x4b18e93c841b6e6145923e527fd4fc35d6dbd6efba45745dd040a212a93d2d6f) +emitted operations + +big_map diff + + +storage + (Some 0x0918faba389d8ffb1b18345d62186f0980efd1724b792a9fa84e037513b4b165) +emitted operations + +big_map diff + + +storage + (Some 0x9806b79c2d171acc44814af407331430dc012ee27c5e52ae4660e8a3ea967242) +emitted operations + +big_map diff + + +storage + (Some 0xbeb8fa12abe52ffa9fa48d73d3c176a0bc3f8be04586f86dd456e3049dee0428) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_random[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_random[G1].out new file mode 100644 index 000000000000..c357b3737756 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_random[G1].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_random_random[G1] + +storage + (Some 0x0572db5547103186bdf2f89953627c1c6ee79da42909470ccdb2b3a63d1a56872fa3f3998a53af08e34f6cbbb5d2ae31134939f276ca6eed853a730194aec002dcda3bb02231e12852a23d52665bbb4fd4c9ca2060976768f294e3a651bdfa24) +emitted operations + +big_map diff + + +storage + (Some 0x19bf076ad1697fb06e3006ba85b7299a58da677178781306ed64bfec71f97195e0fe8e5bbf9bf9f130c27fac85cf0ae102f80edcfe8374130006f99a0415e7debe4e2452084af7a92ec6b32a3c23acb1e936098bde4e99ae33d5bd4f098189a5) +emitted operations + +big_map diff + + +storage + (Some 0x0f8a8b4f0e2bf9e5612e906f9dee13de3a4a86a78779579ae0931938c9e33fabc200051dca4c290d3cda64c46c22d65102bbde334d33cc4d9b77b220848ca969b86a4d3fc828ebff8c154f8606a99fdb6c12f8e3a936b7f717307ac66617c155) +emitted operations + +big_map diff + + +storage + (Some 0x168ff86947fb37c511c29b34cd5683045eae063d394d4ca6fb478be51fd0d51f02362afa2e5b829e161744b0cb44537009da2ef5522ecaca11925bbca35be447402f2385fdb000647b0f97fd957706ad54a89dccc9d91a967fd7d3245699ce9a) +emitted operations + +big_map diff + + +storage + (Some 0x132714e690347a4818aa28078c04a9fa00af5a874f6e384b3c10385edff00b078fdd9b2d24756216cd221fcea02836061565f5e4903c19654928de543888be273f11954cfa069ee8b7b28f1501d723b5cd53a070c99976789683a9ba84ec3f88) +emitted operations + +big_map diff + + +storage + (Some 0x1160d2c1a9468460987e83389d2b14e83da2203bccda6af5698088fba85a70b0f81338e7266f1d2aa35c0c9fd90849cb19271f959b22d25e9d39be01e81ca28cbfd941681141e8494cc53eebf0fed66cf1d9c25cff0acb79a9c8de89978d665c) +emitted operations + +big_map diff + + +storage + (Some 0x19e4f619ba2bed08319d9c6d8233ac67992f979a09c1c2b578f6db33160da265453b6534404273f58b62b465081f177a04b2b5742855d0273a9a4b285040d806ac3c9b4222967dda1ca5b15b701e1cd8ea6d903ba3de1d4b772edd312f5f0e4e) +emitted operations + +big_map diff + + +storage + (Some 0x11cdd047200409941c0c76b6d3bcbd8e213190b4a0129a7bca64383d7574b41465771ecf903dec7f572dd4363595be400ca671f579f590ce3014426b45cf4ad91eaab36cc69b4d594dd60c3521ef037eeb4ecacc4449aa71f26f434e35a87746) +emitted operations + +big_map diff + + +storage + (Some 0x00b2274f474533ac0db515a0e9dfaa821f5da4d22602adc3b63757e0258b237710273f0385067c920250f3ac93e58c5106501678f78b7248129687c46e47737e9737cb4b57bd37495b2966b61239e5fe91946d65c19f948d89a2905f23ba4b33) +emitted operations + +big_map diff + + +storage + (Some 0x02469c3272ed5ff2685c19feeb227f6ac7fd45eef79266e78dc17bc53930ba5b754f94ee6f07c28a0be5f7cd63ba616c0cde39bbdb8e3add322a8d0ced1627e2601442dad06a7b1c0fd9ba9e08bca8866913f0336de0075564dad5ecc63c6cc7) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_random[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_random[G2].out new file mode 100644 index 000000000000..f6510a267d03 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_random[G2].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_random_random[G2] + +storage + (Some 0x14e6a70d1e489c9feeefc7314994b0207da500737728cc2cd17919ed6d5eae570622815ee576563c25075fad12129e900b9764ef6332c435e56a57c1a46b1c427889456fbc01b6e571ea995e925337e6cdff2d062520c61c52d2377e773ba34e08bc7961bb8618eb9951954ca98d01eb69e56e04d16b7a2c21d8cb74ed0bcef735fdc43e6939c4d4194958ac1d5f70d41407d01b8bf34478d970a86af954f0ec67bad1a95c43ea118b8ae2e9ad7053cfd92b0058755e4dc1128e4e17476a8653) +emitted operations + +big_map diff + + +storage + (Some 0x071616c0847497f2acd699cdfa848cd50527971ba6d99ab2debfaad23f658f233c262e78e4f841e4e24b16a981b46f5b13b2de1c75de619374ce4715cda6598b7603c474f4bfae3201e26ec1a0ea4dcac5bb859067aa907fd113cbb8e12eaba0099bc61dfcb137a7978464d2c4c2db5eea9dc673857ad8dbacaf8a30156c2495bb0f09dc5e6b66c9b9a5245a5dd99afe0e9f735ed6682f0d92af05b3f965697c1e8f4ee5aea15caaa6e6905db608aa78c788554f1d63bf1781322ca089a73226) +emitted operations + +big_map diff + + +storage + (Some 0x0bcb3473d903308ecbf86e3d7339f636944b30ae69b693ee870ce4313dc5c678a8e3efc782df3c143200fc9f9c74da9805e4d15ec9fd45471f05f6a89c234b4bb353f5f0b59ff1c32aa0a53e3cb5d00d2f1a4bbeb26df8feafc8c6eadd4271ee0a479169a73291553225df03876a1cf264fe9fec6c1d7abb9498b6e9fe6f68373dfb11c897c8f4587bb68a73348624dc114b4430ca48f9e93c2ffdba64d0200b6213aa1c30dc5b8ee1ada58f7d8f17209c80a0638dac2d84706bb964d5adc810) +emitted operations + +big_map diff + + +storage + (Some 0x02bfcc6cedc5432b3094b3c3a07f4f5605e396779c996fc4451a148626994422aaa2813f25e971377cf4a79199e6b64c08dfd812339542c370ab0968994699fe11be923f5ffdfafc489e92f00aa3e7b346c15a216f4756318f2e275c1add44b1184926b94b03ff641a4dd7c48a62a8bc95db0e10051542e64838e919936b1dedb53eff5aff762504b52e7d7f29038b9807052c826bb33a2a63a23d97f1ae4631b78597169d5a8c5c7b44e76a9612b4caf931cb991bc50c400ca2dae41fd284bb) +emitted operations + +big_map diff + + +storage + (Some 0x199dae008159f71a8766dc2dd36b38eea3cc4570f53c5a75e1c634104c2de1fae8d08d82d746a32620f9fe735e1167c20dc0f1f29d8cb8c7003a0134003fd6bedbf06e3ca40163ade57d7c58134ccd178132839a421a0c54e4e3d7f1f7f6f3c302b2e86c3571aa93f060ac296490439624e0a65c3793ca193d12a87dd59d9db0ded93cb48dd1bdf2c253d512fa8740d40c60c89c6f6f3d0a1e031e9cb792c42988c5fd2df05221d44f0b98db56fcd3fce8dc52f7aac73e65da92a97edd38b871) +emitted operations + +big_map diff + + +storage + (Some 0x057b2871d7a164fd1ff36b65aa26203e9ead4073db80fd3e65cb11f526c3a36d04fd5d42d77f2eaf8ecbd87d31860ac60702affc28f09199509f4bcafcafc555e2924dc7023af9663d5e2add1febb92f274f7712bd50773cb3c21e058e06842911a67737914abdeb318d01a4dce9de50cff14a385c919d69f2b6dc9a4fbab82e4bc73ff153379aa09f44c9237c28a97b194536cf4ef1d033722ee02f2da4fdd2c22c6aa5876eb5e4632f57b86c9a5b1a750a6ce6eb38a21c9ebbad3477cc5081) +emitted operations + +big_map diff + + +storage + (Some 0x0f560f66aa318954f1a715277e07586e66ad90e4cae0e3cdd99a927c59cf9dd4fba60a1ab352ce417440e078116f8d4e06102984b8bcad27f90712873b678249ee83a01a30b0a8feacfa2bb4b068fa0f0342ad55bd269bdbebe7c5cfd5769098084ea794e5252f7cf5b0fd10db3a17f5fef9c3df9418109b9a269790dc35ab83821d39cd373dd26a60fcac49f57f1372111b5f5e8bfc1c2c921545561a541a1fd6f3e7b5dab870c16ffa8c41a8d1cc91d148f99700e3968e0cbff2f74b4613e9) +emitted operations + +big_map diff + + +storage + (Some 0x12d73c3ffbbb0e5135c89aed8a0bb246ac94ba2ffb79fdf103a7c9e71bf09b67fc928fef16c4013b45b963bad15e0e020c0635fb75638ffe385e578e06098e1ea4e5697a3850fc31f888c7ffc8544c4322ab5fda30c34b6959636ce6db02998b03c35b506840723cc3bc4788c47e64ad00ccf727581c76898bf1b331860ead87f9984965c6ec515f0b2ea1bc1a1aad1a0e9c8bc1799a1777a8acda5dc68ae83f7200ad998be79c35f252aa1e427c0b51c9fb463665acb7e7678797a0e0677659) +emitted operations + +big_map diff + + +storage + (Some 0x12f203deaa2a60bb330227161f38c0104c92c1598751bae6af52102dbbd6c9c4d2ec72155b9b4363d90ec83dc7f9a23a0fca208610b342d53abf1d5729ae6e39806844a6eef99c0df4bfe6eaa8b1216c0dc9e4d9f6c4d1f7f8a323459aabcc78184bf83ce121264be8e3931e50275dccfeb4318b1d6a834fd3e5df9b0f33748ce3e88da3bee4f3111f3c0787ac93891c073e576342224498c6c3fd5055bb3c33a8165c56dc6829261511b573401e707e055f9e43b1f29307ffb9959fb114162d) +emitted operations + +big_map diff + + +storage + (Some 0x1636bb0aa543964f7b8b5eb9c79a168f4840befc80a40b98716f5be1c85587c87d541df53c5344fc43fd59e7bef0192e149733e479d7e718938a4da503972a834f9e2b725430a3349f1d8359add70c286d912d26afdf0bf9ef72290cce771c9e11bd93d75a681fac52f10efe82c86b2a6e08a154ccdf56ab2af2c199dc9519ed94bc7aea2b2afec5cba663652bc8906c02c0a16e0c8d7ccc739dd4e0939dd5438ee244b52cc7cc22b3711c5738ee6a110442a7a75e8c5324b2e0a2c9ec61c475) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_zero[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_zero[Fr].out new file mode 100644 index 000000000000..67e6471dd2e0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_zero[Fr].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_random_zero[Fr] + +storage + (Some 0xa739fa15d114468388738a042a2d5c1697ae01687088c0f12b1a9aa08e8d333b) +emitted operations + +big_map diff + + +storage + (Some 0x90d72fcd8feff9474e2e54b4b9dd25693f4165bbd63e9fb1df790005841cd138) +emitted operations + +big_map diff + + +storage + (Some 0x1d88e731f9ace2515da1c8a180a91edc5a582ed1c55d4cfd32eec3124afe754c) +emitted operations + +big_map diff + + +storage + (Some 0x239754a5133c74f2cd2e055471a52aad9bf61d0cb8d87c1a145e52fa4b623471) +emitted operations + +big_map diff + + +storage + (Some 0xd96f5c434bc636ac77a076276cf41025130b480175d4ac3b89b492fe8ce02a59) +emitted operations + +big_map diff + + +storage + (Some 0x55da36ff0ab31698692128f58826a17fe737a5de292b3833f84f6b2dc088be48) +emitted operations + +big_map diff + + +storage + (Some 0x8aaac27a92aca48439a67deb4f7d04a291eaf8df409a966a5cc5938a433c8e46) +emitted operations + +big_map diff + + +storage + (Some 0x75c6cc6c226ce12140160f0740499913a5c2c4788868273b15dca2bd7a6b6837) +emitted operations + +big_map diff + + +storage + (Some 0x800a55193f60eb4de95f6c29ab095ac4f3f1d21a1e90096eba89c4c00f2d8a31) +emitted operations + +big_map diff + + +storage + (Some 0x995fdb626195b85107a30d8d6106e7d8c46af3c8f3f6be0bebe198652d2e6c00) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_zero[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_zero[G1].out new file mode 100644 index 000000000000..37324f2d82d4 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_zero[G1].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_random_zero[G1] + +storage + (Some 0x0e134832be250ddb5839670997abb5d7a89811c1335e7db37a321efe001c35422abe6a14ac850eea1acee01cad17c0330c5437362450b8d760a2d1f0e07fb3dc465a4ef1ceb1b026e6314e5a53a7aa4e7c8e5fc77472c691498680d465c593c9) +emitted operations + +big_map diff + + +storage + (Some 0x05ee99471b023ea35057440bf490170def6356133c85549b45895c0a14f45e450fe1fb44305d57a417461cef5a7132ea137b46dde47bee6177d3300341999d6d3dc996d19767d8c30b8b8425b34230813eda03d6db53f8f2b5e2ac99d0d9aa4a) +emitted operations + +big_map diff + + +storage + (Some 0x0e8cc3b0289c1ec90eb49b97da831d4d9bddf1d3ed02e26ca7328ad618945ca288e736aa7c7c06e59ddd34522765eb5f02ca674a5dffe0aab83d25086876d5a87ebcf4d5903125a8f5c637f9ae0618a1f682d5d18c0bfaeeec866c2dbabbe41b) +emitted operations + +big_map diff + + +storage + (Some 0x16fddca3f0f59d49ba43f6861d71d8f4353f6d43899b14311f4914987ad0fb359cd4048b9dc8db6378e302107296037311ec2289dac6db85e45d3dc93673eb3104711664872dc931d4cfe6fcc6a4afded609a738759078d371b5538436180f24) +emitted operations + +big_map diff + + +storage + (Some 0x114f5bff07e03161a9c9fdd20fbb672a71a9aebe2c187e821d4005129278d5d5c195926c7718afda76194b35943339a00efc8c4c040e9b1dbad9ed20768c9c62e4dcdb680bc0add60b218bb42328a116d3e43d579024dfdb4df0f1f0c016d8ec) +emitted operations + +big_map diff + + +storage + (Some 0x0cdd83bdfa776066c37697324ce0a444d064ebb079d99fdb2c03e63563030f824fa95bc7e1c10ad14cd6362857e9a0010073d89e5fae09c29ee2d1a6e8770f7c5a19be2e2e465a50539833b1a463e24d3ea02c606c5990cb8c892200b6e3ec55) +emitted operations + +big_map diff + + +storage + (Some 0x05a3fc74d5c1f3a883631ef0fb7bc08705e85b62786f2d61560ca231e6f7178d10d6c9a97ff5ef4218046e66f9142d1314d8e28bbba2db0f505669a31b4ccb4cb08aab73e175871139b2fff8cf687a0affe2463f0cdcc88f51a4123434533e79) +emitted operations + +big_map diff + + +storage + (Some 0x039b2ab4cabbf7bc5d0851aa4034d4e478e6350a6508d54fe37232e92e5b673ba1bc14db53ebdb317493c9fb3089a25f0ffb75f9a4da47eb6e54be326a07dd56cf8b57a52d49892669f79922569eebedd0848b172deb497b959855b85d66a8c6) +emitted operations + +big_map diff + + +storage + (Some 0x08fe5a710347c0b1a5f1f61c9268778af2611a42f883479e289f1ae28ae1c15408aef3943b951c8377b6a79faefbfbf2150c7fa5f938156c3d8f27b7f5e5143220f5e0752d762ab54a53d9178f4112eddebd4daca6a585cc469be1ab4f5d5ca2) +emitted operations + +big_map diff + + +storage + (Some 0x00d471074aee131574be07c9b749d7bbd09234578fb2acb4a248e6583564b341cb55f2a2b61a227a093a0dbd4bdea67f190a01cd3614435914153e782cf7332911ad79c48a1dbcb8072063f834347441530091809be2c15692b8c0b98ae646bb) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_zero[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_zero[G2].out new file mode 100644 index 000000000000..854c9bdc83af --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_random_zero[G2].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_random_zero[G2] + +storage + (Some 0x131c7f76cfde58ed74ce8c26a4e9c6a6e135fcee1a61a41e5c0f2f33a718d6bfcfb7de2f43d98608b68dcca040c217a6007c5a33c5bb8d523634469302348d23df90d150b28e4f41f1539afa50adf951126233146e4dc98d21a0de35312571b310696279b7105aa5830ef3cfa6df1ff1379f17b24ab561c899e3fc830942e23a4b73019b1ef5110baa4068ba2e8b4c2c09e3b16b0894333f41eccf24b96be85a0d17ef071657b1abfd6fd0e7878aa55d3a5446a9c0ee5b5c293ff8d3cb4722f0) +emitted operations + +big_map diff + + +storage + (Some 0x09de05cde8a5a7a1328aac8335bce420aa41f1077e3be4aa51f93b3a8e822423ef67d263d8042a65bcd89e0091a6b3dc03727a50fd6fc80ed0b1078e81560e759b8013d48261a2cd0e65bc83b9a37cd8e952bcb6a63e5c9ac016d7d588915e0d0fa9247132b7488528ee8f136bc9026f8531c5baacd1647a768bc801e726200b34fcdea976e82d1633e1da82a36cec580f8f3e197860bb36ff010e747a361c54f11003d33b6d3c8c29eaa13be92034b2d9e04a1b6e81fea1911fa8c8b1010b8e) +emitted operations + +big_map diff + + +storage + (Some 0x11d76ee03154c0ee80237e9d757e5fc6fb6f0dff68032489db4edfa4a79d4a2ad8af5854d1b80e5eab6046d236bbc97b16a1dbe3dfeac51233c05fb1ce011cffa48dd38b052ff81783cca048ce5d7c44743a57feceee2512aeeb75344fc0123a18459f774f0e6474bf80a154a754e3abfd281dad0a967cdbfe25e98e8d0a22a41c41f0822fffcd3d92a519b40d48f9b109f79370c21568150d9dfbbdbb3187605e4e675280fdc6de9689de0c82083da87a4a776efad2beeb2b2a8e238faf0543) +emitted operations + +big_map diff + + +storage + (Some 0x056ddeca0596e44d080a38cb233517d706f5529482d8e7cf5618e2c1b17222bb3cf9627173a05ed34c19e925244c775d0bae3e10aead5ef97474d420845b1752c054222387e5767797f2ecbebee3f002e930c7ecc666719760a2a7625590d2261360cf5c50023104c36e79765707275f0517283f1834b3b378946f48675459342b701b5d421af115764b639736ec666712e9e21a5028fa9958afb36e610e74bbfe0db03a3147409e11b2d12e45513f0ed91cae918ab723773aa1d16956754b7a) +emitted operations + +big_map diff + + +storage + (Some 0x016319cfc0cc2f9682f2171aee2448828d2dae206cd4eee18485d4d528dbe42d91331c54b99071c54f60852279bee33408843ad79e654427d875c5ac932a82596e88bfd0ed1e7bedeac67cd6d260730a1bfdeb7ee072c10bac1536b77b89ecb614f3b216d3ef4cbf7d12fb26d61e5e3b50ef7fde0ec13311606c55ec631935f5abe99ffced1ff1879df289694091866f088752642b4791b742acef63b6c7068f2789c7a5c37c5b923c9f855deeb15af919537ebc700f0754a5b3cf76a4aeb585) +emitted operations + +big_map diff + + +storage + (Some 0x0487d5eefd82485134b6dc3eb070ad29f24b283e66b21b7ab89dc9837833d577282d6886900daca411e1251851c6898a14540427013fd1777ff4bc6caa17c499b45714fd944c23123c21996f08ddf9c841be93bbc3b427f3e97bcc96f0d2dc80076e1cf2b08d1e061e5dc05d04a9700f0f498c55740cdb07513113481cb2be4ec8b2445c06207bd49199f8784321e3e6188f33ed153ccd194cce9574678af873a515e2fc683d1e949131ec946e212e80c4b48876ac5b4329ebd66e30c3e64716) +emitted operations + +big_map diff + + +storage + (Some 0x1825a997ebad0d60dff12bad0b182818c5939c85bb90df49815f161f160c34b007b765d5f45bf8be5714f5687e8ed52d0067d80904c49cf9f9d7a6f6b6748ef1722a4fe7e5c3ad6e4535188dab7b4fd756e024bff36798349a6b3796d4e0eba00e4a44260a6527af74bc062df2fd3d922b04052e654483234d944edfa3e81b9432d16b804deca1690a2a6ffd276fda7e0f427e3315cf2555c0d3d146715393a24939b0bf36d6284c672a212f7e7902ee2e873281d396290bf26af6b3a330f058) +emitted operations + +big_map diff + + +storage + (Some 0x14fd9f5cb51b90075b3250c91c45be2eeabc425584b7b451539f238c191ad58c6c364020ec6a8ae1810fcd6a894999da065bb45ad11327c28d9bcb1fe85d45b10a2e42fbb1f3eef622a8c261e52ae5207840c8805fd2b8448c7f97aaff8bcb710cba0f99825e190b5de72f359c21058d3a17a30799f1d1552dd1128aeed5ef96ba586e62fd71a004cda332362df3d70b15816951c6070599f40ac6a1bff7d8c21744f00da365ac6c2b81e7abc752a01736e089226911da70e7b908a130af37b3) +emitted operations + +big_map diff + + +storage + (Some 0x07c239bc8ae325e0ea294eb2d7a8134c9986099cdae78224b2326f9d419769b065570154776fa16b98c1b5bf2f69eef41403ed7557754558c686ad6c00cc61b386f3a2a8185d1738e9c6ff6cdf9353ae1a30265ed02828a2979de0e8f10b15d3087901b1d719a2fdf367564719fb05a9196c282f244ef434090e39ff091feb12c45c117c2d68e36e8bf37aa7b7847213110f3424cea97cca09e3939d418883ef7f394715e5448f833fa0ff61ebc8c9d9fc5ecbe8d2480f4955cda3097cd72289) +emitted operations + +big_map diff + + +storage + (Some 0x070a718668a1f4e692191f9a7653827f6051848cfa72df0c3e99fcffcdd9e09267f8e6711948b43565699d4bf02feb0f0faacfa8e44cb5c50d2d07a54c811a0fb86a1e0f565efe32ec11bc147ec6f8073067c6330afe0c5be6ec5962921f58bf0b97bb667d15b6b0596cfe29f41fd994c1ff7332dea6699dd72f828593485a97d72f8322ba503653a6a82a42dfe68eb9166bfb6fe8478bea584d01d252c7e256bbae17b371a8bb87916ddfdbcb28ebb7f4670ce1dd3be5067e38b0e9c9f17140) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_one[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_one[Fr].out new file mode 100644 index 000000000000..93156080031b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_one[Fr].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_zero_one[Fr] + +storage + (Some 0x0100000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_one[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_one[G1].out new file mode 100644 index 000000000000..79d35b99bf92 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_one[G1].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_zero_one[G1] + +storage + (Some 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_one[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_one[G2].out new file mode 100644 index 000000000000..caa3cf1901ea --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_one[G2].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_zero_one[G2] + +storage + (Some 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_random[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_random[Fr].out new file mode 100644 index 000000000000..f716b60fb982 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_random[Fr].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_zero_random[Fr] + +storage + (Some 0x6b1f61b3ffa8e49f9a840c0f4114fbc6061bf98a51e51fe4a396f041c50f5e02) +emitted operations + +big_map diff + + +storage + (Some 0x0e4c13a518d43c1a04ca2b7b16ca21d8f2443a861e7b6184a85cee5892916903) +emitted operations + +big_map diff + + +storage + (Some 0xa18e92f24830c77e59167062c6e8b22c08b86800c498b932bffaccb68fa1b934) +emitted operations + +big_map diff + + +storage + (Some 0xa91c486e8bdcba53453336ed752ef9b214926a2b3ab452552a31eda0ef3cfd3b) +emitted operations + +big_map diff + + +storage + (Some 0x0b9fb344957ac93904848f30fb9c068ca7c9cbdd6006445489226be02676026c) +emitted operations + +big_map diff + + +storage + (Some 0xdad4e76170b71edf3c7ae65a00659f332dfa08e9d2cec5a632f8100cf938ac62) +emitted operations + +big_map diff + + +storage + (Some 0xdcb9d72844fc8c9d4e25acafc2c1945f1f8b0556817c333f0e6c0e5c932f4c5f) +emitted operations + +big_map diff + + +storage + (Some 0x53745aa1b2b2734a0b038307fec0d0f20e6ce9d512a4ccca1ce49dc8b294b93e) +emitted operations + +big_map diff + + +storage + (Some 0xb1cc9dcc3ba2a71687b388d23758da47c067e1fa6f0b185fd5d39b9050416a12) +emitted operations + +big_map diff + + +storage + (Some 0xdad6443c3e503dc862ecd96031f0f5c40fc4560b73313dc153bac7118338aa14) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_random[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_random[G1].out new file mode 100644 index 000000000000..89d5e7c03895 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_random[G1].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_zero_random[G1] + +storage + (Some 0x043d39d06dae5a1faa8e462a13a7254b8ca438e47c7846fbeeef71e44379e7df2e29613e18d658ab0da4547b4f3852590831612b23e928a01f20857216d823ca7c5e07fbda46923ea626380c4c95cc2046b9b228ffc599eee8ae2788484a1e4c) +emitted operations + +big_map diff + + +storage + (Some 0x05b38be001d64a2d9e17a27d90e29b9f8f8bb28c7c8720371e7f72612f0306a97162cad563ee5af54df372c89035a2830404865f74dde79ccf6640806f47cfa66373656335a4ad64cb383ee44f339707678730d141cefb643ae5a7ca36fd2b0f) +emitted operations + +big_map diff + + +storage + (Some 0x0f644fff548f117895a24c9e4345c4dfb995caaeb5a01c1bd8092677f0dda287a03d7c86b0cb50a61739e21a5950de540abf3818624bd6f162d808aa8ff6b9993ce584fecf10d3aad86ef521545f2b5dc76839620e52d27f42fbc7d9e548b250) +emitted operations + +big_map diff + + +storage + (Some 0x0dd72a72f8dc7d26d4f54ce50d6bac81bad784cf2b886d5d2ff66a06f5358e945c5c70b81693ace7d21e6fdf8db436820d5f1d73d015e5799f7fe9a1e4068fee0e6874f3e8c56f85f673e0b1cba80511b1f4bbc02d8461b2919bf8cdbdf9a051) +emitted operations + +big_map diff + + +storage + (Some 0x0da1488962b00f17e629884dee4f153e0a717af426bde7c75da0f5067ea5e63297ba068bc230e5179081af8a23c5d5b618f5b3bdae5915cd2724687e228a4c1843578a0c2aa2297031745fc1f3b77024851cad2bdb815197fbc1d76e7dc17e7d) +emitted operations + +big_map diff + + +storage + (Some 0x153d1e9eaba3bb00055584ad97fe9b49fa83bad011d1b97598bfac9db9c54a8ee0152887ddb42d1d46ac4d4ff97da3210e5d38c8b1f74d70b56e94f953a289ca8604fe6731498987c3bd186fb24f569a0c403c0173dfa6765f1cbcc75248547b) +emitted operations + +big_map diff + + +storage + (Some 0x0165ba92201bc7848e74e23c842141407b407f09ae7922e01a290c4268579c84f2a3bdc20a8a1005e9669064ad2e634405e460b2eb3026d92cd2833ae7d1f5a009756ac91c58f2ca88a358c9312de31f9caec97acad38cdbf9f1f8c844ec23ee) +emitted operations + +big_map diff + + +storage + (Some 0x02bbf3966383231f6c0b5a0fd62240867a8944331afa0c6d06b5f1bf83d3c2eb5a37edde3f51860afe887526e343fafe007cd4b0abe3d4868391ccc730e997525108e17740b0edbed0d1cc15bbe411f33e35232ae16e79c77b6acf22ae67210e) +emitted operations + +big_map diff + + +storage + (Some 0x0ec1ff5c67f23f47f82e834bce1d48e56e76b78f42d7ee530e660718c3cac29f207d58aa4c231376f8a8ea4951f37d680991eb20bfd4c9033acda6621b2861bcd983a1066f6add9510215cfe0e66485e6433331232d37d944d1cb56230727b1b) +emitted operations + +big_map diff + + +storage + (Some 0x0b020051cc583ef24590ef0626e7bb42d30556013f5b490c78bd1c689c759e04e3865f04b6807f9b7a52e4f4fd23a4a70684f9d93f58388210075b8de217efbcdbaa41c4c7126dc925c1263d36953db065b15d7fbdd248857651db0f6229ee89) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_random[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_random[G2].out new file mode 100644 index 000000000000..f440adb2a3e9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_random[G2].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_zero_random[G2] + +storage + (Some 0x0a8801dd5d45269185fef3af4c71e27aa302f843c4f75ce58267d5cba2588d63e240629f85cb551fca316f32709a3c6e02487c3309ffda4098b64d73d16074121a6a8bd6ffe89151c45ddd7381e05b7243db96e4f6edfa06c57d0bb0265b20bf03d1c067162e0dda121fa11b9c7dfbd14a027f8b5af1630ab703a146b9a5ec97e820133a732fdf0f438814a693e77a820edf72b5820459bcb682af727b7590463ff39b863dffd2a9839fca3f6530b13942c53a5ba928be5b039b125b88716729) +emitted operations + +big_map diff + + +storage + (Some 0x0afc630b73b1d1b407c89c797f07acf80710dfa9ce57b46722e7dcb8a43a847341372d2eedfd6c2a3c42305306ed468512fd95cfceec1194d749b13948f699beea5b33aeacb902d2e12a2b65e9589c57d26251b350edd142cec634b23a7318bf1553647560e99b285b82153ba4f70fb7c3f494fe5cb65c0b7f1446adedc646d14628f45b4b8d7a22510b8551490b04cf0a0103d13a5deb5d68d32a85189cccf1134dd908da9ea8ee034d067f729d892bad11a45113f0e5f5ab25c021759417f2) +emitted operations + +big_map diff + + +storage + (Some 0x0b8026c50e2cf76e4fc00cf25ada386641261fbe457250746098edbe44d28eb0961b4f4aa7d3d3f65e0f3d0d92a131ef17cf0aa479c55d0c529b2ca05b8488adf9dd829d91f0bec387c5e91ff7082678c6e76a74649279bb327f3a4f3cc73d80104e0f1880c6647428a0b7a5883214cb46255a49c13cf4d8106818b782078ef1007f7e34790535e97ebf8b1cbf3b723317b7223c824964da23c4b6bd421a76603c0dfc8f2779acdea5cdb721f71dd9fd44f9488ad519057def31360c1673e5e3) +emitted operations + +big_map diff + + +storage + (Some 0x0fd3a77a6a919626d31505fbf7ea71d3f60b78dffb1b7232c1b3569dbb67381aa9df4ab99aa25934912112b2b9f1612004b3c9f71504341d8abb591f6d7ba5b9309217467d332b6ae66d634937a112cba73009befc554a2f9c6701d65a29e8cb1525e405ef803bf935000e2b0ed5b7ba1106dce0369069391fda557b7282e7ca77513fea88f364dbfb17ca9b9c308a860760a41f8268069fe3f9f84002add2e2e14b6a4497b3ef826fc885a633050c1d9852e942006aeb234d2944e17a5afc58) +emitted operations + +big_map diff + + +storage + (Some 0x00ea54ce4ab2f8cea7e6f172c249638844225c5e72980030f45e5645680d9f2860ff22d0310d7e2a39b70b2fd2e91fbb099428b8e20bc8895f9e9308b66c8afaaa06f1bea33ff8dd55524d1206e22278e1e4b23aa1eda324bd1446467a995f400fc4d7ab9df219f5af91a3bab904077f36e25450bbbe708f5f4d5a1f0fc3383af24a86ccd3f424bb1acaa65015c0fd9e0e5020e8ac03981166b9ced9b74e0712424e60950c9a774daa4d2677290794c5a34dad95b9e6123d83adb9dfb84acd22) +emitted operations + +big_map diff + + +storage + (Some 0x1667ce729e66b328dfddd67b3308183f2adba83792b637a9d6a54ee5c520f4a84b6d4446e906650ef19be90956246a12109589b3b1c2694b39d3d5ab8a3d2570e70b15a3ce81fdf28b488f90fe54809069b3143faeadf4392fa41b0178382e8e05579ff476cc9290b1847ed3895beebdc1c2fa106cc097ad369d2652b57feffee233a9f8e879164a649e59b7cb22fbef1252d6ab8cf8376f56df57627a064a206843d58ea6fefb53a07088c93786d13f47a91a07839b58d0d230598709bf12eb) +emitted operations + +big_map diff + + +storage + (Some 0x042c1082a0a914a892b975934ca4b161aa2b2c3d45600fc565d71047c95b1e6f0348534309ca6f506f74f1089187507f099ce83b41b120cd8b8d7a6bfec0cfbbeb90a5936ca9dd386e2335eb8c12f9a84ad4ad2a1ecf69bf05427bbe96482384112b2326686e63c03d9f3ded29536fe476366b1ec177c016370ad1b21c93970dfe04779be2dbdcbd1a306f5c6ca9f5bb0629414f83ae3549ab79ee283fb0be885a9706355efc1aa0d0ae6243118e7ac6cc8303e68d0afeaaf6add5d41caa7b57) +emitted operations + +big_map diff + + +storage + (Some 0x191f9cec71fc06393c562a77e79041f3851837dc39efa4b458bb55b6f89e15c8fef9dbadb3f75b4b9873c094503742210deb4371bb8293c102c122bef0c8972b6dcb4f9add18109234c3b94400e3e5ceb52f59beb33ca036c89bb60ad7b629e80ffff89bfcbc65f23e1ce932cf2992530fcb0056901ea31cc425585fcd63b444e2ee671eb7109b0978d23a19ab468387087dda6c1354fc4b645d3f0a6975eef41ba75a14b4450db71f4d899e71d4fa7a52b275b06e1ffdf36f539244c69654de) +emitted operations + +big_map diff + + +storage + (Some 0x091703cb9cd4ba012c631f8be02f949e9c488987c6144dd8a1660a4eb65a41474cac5edeb65824214875ee21298fee01083224b8cb2bcb353c47a796567b823aa8075d28e9e8ed55895dbdbfa8efe589c8c58218308bdf4d7737b27b0c6daeae17b36d402a7f7ea148c3fba6ec80633d64cfce6b31d055bff659b875ce0b513f4bbfd5e79580f1a5d896e551f082ef3912efabf6b0dadbc53fa3e03aab4817ad547fc2877f4850ed5861e37ccc29115c203f6c92154a84f898ac1fce677f702d) +emitted operations + +big_map diff + + +storage + (Some 0x0ed6b993962b955b8fbd1b7e7207ee2faad1460282274305837f89ed9081a405ad1a088f9d46487015b082db7ce3c80f09408e6d2f2e02868d1be1dcf067c8143a887921dc7098ef4c116800562a2786611a65b437ade3db1629d5eaf3b8eb56199fd734d8017287f5b24d4b4f0afae0cc86db7e751d2e1cb25d06f6bb3c7ba69c3b5d94a6913e9e1c8d870fb1a4470a1864d95b7519f8d7230465df4fc23e7f08fb912a467496a58b024b0e82ea5b8cac35aeceb1509db29b2f5bcde0c2d5b8) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_zero[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_zero[Fr].out new file mode 100644 index 000000000000..2f144e87823e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_zero[Fr].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_zero_zero[Fr] + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_zero[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_zero[G1].out new file mode 100644 index 000000000000..231c8e159d8e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_zero[G1].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_zero_zero[G1] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_zero[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_zero[G2].out new file mode 100644 index 000000000000..9307a32ab776 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_add_zero_zero[G2].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_add_zero_zero[G2] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_fr_bytes_parameters_more_than_32_bytes.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_fr_bytes_parameters_more_than_32_bytes.out new file mode 100644 index 000000000000..9c88044d99ea --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_fr_bytes_parameters_more_than_32_bytes.out @@ -0,0 +1,8 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_fr_bytes_parameters_more_than_32_bytes + +Invalid argument passed to contract KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi. +At (unshown) location 0, value + 0xf7ef66f95c90b2f953eb0555af65f22095d4f54b40ea8c6dcc2014740e8662c16bb8786723 +is invalid for type bls12_381_fr. +Fatal error: + error running script diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_groth16.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_groth16.out new file mode 100644 index 000000000000..1544f166ad20 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_groth16.out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_groth16 + +storage + Unit +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_one[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_one[Fr].out new file mode 100644 index 000000000000..a740f1f82ce9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_one[Fr].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_one_one[Fr] + +storage + (Some 0x0100000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_one[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_one[G1].out new file mode 100644 index 000000000000..cc3530daa653 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_one[G1].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_one_one[G1] + +storage + (Some 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_one[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_one[G2].out new file mode 100644 index 000000000000..b3b19c860cb3 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_one[G2].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_one_one[G2] + +storage + (Some 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_random[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_random[Fr].out new file mode 100644 index 000000000000..9e1ae6961de2 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_random[Fr].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_one_random[Fr] + +storage + (Some 0x3a14168aa51fae4ac33e62e94267e61ced8f00785e295c9c7125b881afbe111a) +emitted operations + +big_map diff + + +storage + (Some 0xe842c1ffe3c767806c91f42120e27cda0e3578a1c52c53e1b33a65cff1e22b1b) +emitted operations + +big_map diff + + +storage + (Some 0xeafb8e3cf1e223497893cdc3130c6c13aa7d3d3e6a3502034d19d3ef4a39ee18) +emitted operations + +big_map diff + + +storage + (Some 0x614e3f935e4b1511d8b63143d2a7e3bb2235c5f1b1a8597f44347c4ff1e7764d) +emitted operations + +big_map diff + + +storage + (Some 0xb34999b9256eb7205c0303553559e8b14668241277fc207b21ec9aadc4451a1d) +emitted operations + +big_map diff + + +storage + (Some 0x307b86cff0794406b7e07ff937fa843c09a4e0dade758b297e39569dd41c5b04) +emitted operations + +big_map diff + + +storage + (Some 0x6322ae545e19b2b35e4649e021b2025caa9df47de27b69e023c71e349fb8643c) +emitted operations + +big_map diff + + +storage + (Some 0x36d7ee80fb7f1e6bc31f1384ed67d8c5b195f4daf6ca413e64703cbc4e9d0d53) +emitted operations + +big_map diff + + +storage + (Some 0xfc6cd59996ca5aa047bd59b6001a43e3777d9b19ae65de6ce8c2ef7f52cf1c4a) +emitted operations + +big_map diff + + +storage + (Some 0x6e9f624533c9bed9c971db028e9bd5ad034d25d38f1387b090a2cea2685fcf16) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_random[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_random[G1].out new file mode 100644 index 000000000000..923e8c5b8a9c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_random[G1].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_one_random[G1] + +storage + (Some 0x0e3c67b12372907bb20da67474058dd766c165200d525b1e0ccb5ff5e3f2c8ab66ce557601ee6f39a81d7f89715e350303ca13302a0866206377c197d62d8e5149dfe3b944179af3646b886a0bb16b89e9864a7bbf89f18d1177c1c010213e4b) +emitted operations + +big_map diff + + +storage + (Some 0x1627a49ada91f905e37da3cb998e77177177866dfa21b714e8e60a969d993dea22dfea1468ec27bb502abffecd297af208a8954ec9b70cce4b5f045e9ad030e1e3a9e822ba31fc9ecda63f7483ed87dd251c117657f331ed316161c22ebd9a8b) +emitted operations + +big_map diff + + +storage + (Some 0x0044c4f40be86203e6d9879fe49fb510b1e40b1a58e26db3265f5c62b49ee1311f12f1e8fd034be3f4027c1a5dcdf0610a721358155dde11af7e315a1246f483973321095593a72d236149904a4761ec3134b482ef46851052e78e24fad5fa2d) +emitted operations + +big_map diff + + +storage + (Some 0x140bc58ab952ed42a4fd28fef1f76f5207f8202f15bb12375d8a4102a6c9323cdf80dca17ee79d1a80cb438b56f75a901822447a54c0b4858e2dbede0ed4634ee0d0f190c2b0f347247da09edc81cbbfcf2f5be25b842cf1777e151582ab797b) +emitted operations + +big_map diff + + +storage + (Some 0x0413f511b1c65f6a27766c69d4518eff63f9bb913feede2c82b7943f620feb27772f48b1a8b0196b88935a8b67eef112038f995b978f71a5d2d0470d026ae5c786be0ebe748045399a688f550e4950f2b5e0bea6131466d72a8eb4c6fbf2f750) +emitted operations + +big_map diff + + +storage + (Some 0x00e088d901aec4f3701eba2206c722276395202270c2a66471a5442861ef6ba997f2b12686e7b5413b24db4aec0babb207e5f81cccca63d939853e1b389695d58e907550fe6e4b347d870ab526b2b7667b888b92182366b5300314dc2fe305d0) +emitted operations + +big_map diff + + +storage + (Some 0x11641aa9417f8eb1659c74cd4a8f180242283634c5b059c497fedd502fad9c6fa00ecc991e978260a7452e79735d5e101559382cd1f3f92d964dc8a3f54b8d7dc37855650bbe11fa9b5e90881002b290951781aee93495d0e5703b35db31bf38) +emitted operations + +big_map diff + + +storage + (Some 0x0804d36e490be2f867fcc99338af37df61df443c73e47bd18f4f6eb8748a31ce403bb3a8aba27f281898a5f8e72f6c4f1321db8c96fffa9893be378e259ea6534fa1aa8be504b3f896e2af2a4cc53c6d017dcb587700689d81382f1cb1013f55) +emitted operations + +big_map diff + + +storage + (Some 0x1843835c32147cd7191e2f2aeecfef744f96757e1e5d2427c7cbe351d2142bb5723dc61b6211adfd79d335d632d72cb10d2e0686443369c8f26dd290b98af5e8d892a4085cfd7eac21742b783c57fbc5ee5a5a89a5b2a03ed732a0271bd2b548) +emitted operations + +big_map diff + + +storage + (Some 0x0d8dc00f3ecfb62c9e9e4af0dc3392fc24f2861de4e609b77d8866f561d90904e9e5531b5203cf646d5a22c4a26885520de353e43fb6cf32bbe12b2f243c858ecf9c388cb02be5b935ff8411f76991c00411a40a990d63af69902d0f3dbb18ee) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_random[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_random[G2].out new file mode 100644 index 000000000000..f548762375c0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_random[G2].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_one_random[G2] + +storage + (Some 0x0d95415b2c0375d132c0700938c4590a75498165c923d00317fc3baf5048081b92995c9f651438490ea51f47ae1f871d06450ed22ec65658e7583c95236d3224479355196db6f0e0f8edc6c26c6d1e7c6edd8fc0217d86942a0078705c2188d90b4ccbc374d0076cbd6d0f9f01f4992fc87e8b2b4e17d3d4c91c14e3a0eb33000b34a923350c7a7c6f72f04d64db00320cd31bba7dea1243ddfca66e8e14fbd2b233c2201b43bd099e0f68cb9ce347cabe68ab4f42e972bbcb834d9d73da0eec) +emitted operations + +big_map diff + + +storage + (Some 0x1953081fd90afdd618ed308d2e556cc466cd7c0bdc79bcfcf25b96ece923fe8517e72c98034097d9eee722f737e39a41113223084fa6fd9daab9efb9e0481087c30f3cfef3e046fc2f1bab2a8b142a94335ac957f8521646fe4925cd443430f00c90e874ef50eca42050742f7f605d0f8cfe00c5571a2a99240b88541e3a7c08c91af2bc89ad29b4d397d10d42c93e9b0ac8dff1d86ad777e8b5c6f8880411a139155e8ffa1708e085972bbe6d4d5c4f39415e5ee902c3427d54ea84334b7ff3) +emitted operations + +big_map diff + + +storage + (Some 0x06a72dbd7d92de83d95290f1d7e8923e0d8e29eb84024b18fcea2097225481c29fbbbe7d030ff1b4018f12418b9c28a60728f0e17309868072e1dc188bc9548e4f3a0d4fc35ea2203f42539b462b7070feea8293fe47818fe89809ad977179620d727fc335198a6ddbb9e4ba25def0445c22c227bbd811cb005828b2d42024d1ccba6c20d5987bfe9ce114ca112c04b50d142f815aa648bdfb092e5509b72013b6417e6f5b5ada3cc590a6d4ba0ba908afc6ab5dc5a34ae976afc74d8e75da1d) +emitted operations + +big_map diff + + +storage + (Some 0x13ff1086d5713b7931883f01c36424ef26d28dd314473c073ca3ade1da5e8fcd7e22a86f0514beeb5b16f53176bb8ac70d8fe482a5ff16db0f19ac5738b52efc3f9228a997da35fa8e3a2cc9aea049fb23fbf5926f199ed7f29c73022610e4e70ca6547613b84940c90bfe7438339770ee180237cf717b67d2eac23fee8c42c17e0a5a903e0eeaf854856a241781298e0b13af3d210efad5757c6112565bffdcdbf649ba5b645d6d1a46fdea5014d2f3edf257af5ec593fbf69f14f0d8e3ef24) +emitted operations + +big_map diff + + +storage + (Some 0x0f3012df11a5a21ea69e484e3b1aae6426f47131b6c8de2d2ddcf5f08b7e2264beab80d08bdc3464e5ba93ae5c70dfa81792d5af6898237318173dee0241ad29f3a243837764dc8a5f66deb5868fd69ab434912233d3ccdedde5b8ee484a4b6f07ce143b9d525568a35c28ce4ad2ab57463cdc2fd6cd967864e130645e0f2807bf13228b000a2dc124dd4fa45bcee53202b486642d735da0ad84458ff8989cdfe9ff1478b2d80b4e45dad71d7098bffc890d65b720372793fc0ce9c6fc169b0c) +emitted operations + +big_map diff + + +storage + (Some 0x1429e92a93f2ba48ebe5d66ecfaa3b148e8414beae4aa83b5c054caf6937f30821e23621e278e197966ab69806010819156379b3a6f4674207d680dbd0e45a1399efe202631f30507fa96d88c4363bbe852e95edabd9902bc72485e6dce044a0072da73fb04a55e27613ddadd5915d0637f5756e4a489eb29347e76fb329c0e289a156f8e758ccbec03376ccd67a528a0abaa11be4c810443b52082cb54174e2019ea8d9d7373c99e103908da27c1aab943e745d5026304527528def70f391ad) +emitted operations + +big_map diff + + +storage + (Some 0x07d9eda0c029333aa344535a1520d5e1ff32767edc4a9d2f963fae4bf7a76762a1402a70fe2497059912016e20a082a20faff41e659f197f5c99532070782107a586dbd7e6609b31b89b4e91d5eb85ea01aac0e19aaeba32f86090c9f489b1ab0f8c51be59ebfd70a90246e364f817054a149dbc7fb6ad6e5ed3991c3e55f6dd08bcffc0f9e1e7d1c4fef6ed7141aced0da4ff47847aa5f5d7347bdf698525b75c840569e1dc731c1971eafebb305e77d44b2b06737a9f60d3b0cefe5a3412eb) +emitted operations + +big_map diff + + +storage + (Some 0x1047eb6211bae046da85a8085a23c5df6f73ed25abb394b16fa673842d19107b2e40ab9289b36f2699dfe34f5fecd2ad0596e9d73d3b697bb342d5b4a74922fac2c0ba20ed89db874e23dc07ef1c02df48ed3b5f2b9e63e1749b65d64ff3572c1034d01a148145d63b85d0f01b7c84c47ead9963b84233ce9f5cc48b1cee86b094087fba5d718ab4aa8a09153b078aa6036351a3042bfeff633a6e023945a0b6d88bd82cebf4c4b9010d16f98a30299ba276f8451ce728c26010a05bd09ba365) +emitted operations + +big_map diff + + +storage + (Some 0x0acd7057df12eccc09376a20c70c6c054bdd064503446d525413fc494251c0f19181eeb1280c83b6d34916a3904900bf177981828b72d00113c22542eda6e9130fe13f4b9d2f3dc2a78962fac295596cfa28f95bff49e35358f8a85cc764f2030dbadceba39d7e87f274f1b22e0d1f92e79a4452c6a97efad1aa6a71ba2987d6506341c1b8f9352548cdd40f445e545b051e6665e110109b6e80894d973b10ab4469a21d5d167563c2ac7645523fae0a2ae2745318b660f2cd19d725c3a17fda) +emitted operations + +big_map diff + + +storage + (Some 0x04f081fba03150088bdfae16217e3785de649dd8866c728a2ce05abb271cdb664a45d8c539f1a6c7b42335e5beb4a97e07c41c2e946a74f95d390b574fde8df58bda9d43fa695b02ea8cd290949097ba7cec710d802cfbce1a804c74e8b6826a017b201bf0b344cf7d469ebb203b4eb2b7ca41b6f7cd3797423276d55742542d9435b6261956076718a1eaf5fcdf0f1a127b43756c11c7baf603bfb4f929933ad5c263c9774bd6eee6131705416739a15d49c87bbe0a182ab62f70f55db77144) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_zero[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_zero[Fr].out new file mode 100644 index 000000000000..158d3d5ba03a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_zero[Fr].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_one_zero[Fr] + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_zero[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_zero[G1].out new file mode 100644 index 000000000000..fc68513e9be4 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_zero[G1].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_one_zero[G1] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_zero[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_zero[G2].out new file mode 100644 index 000000000000..8622beba7c2b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_one_zero[G2].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_one_zero[G2] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_one[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_one[Fr].out new file mode 100644 index 000000000000..743fe11f69ec --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_one[Fr].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_random_one[Fr] + +storage + (Some 0x286f0ec6252484c8bb981a3b8382b975c4ea92e11d1889a4bac541d0657db547) +emitted operations + +big_map diff + + +storage + (Some 0xd3b3ab5cfdfbd937887b10406248e8afef754b2692568adeca80be1c7abe3057) +emitted operations + +big_map diff + + +storage + (Some 0x469fba7341e28e67f35affe2fe4b97662a8b6481cf297346ee94e3d7d932c92d) +emitted operations + +big_map diff + + +storage + (Some 0x8a7177b61d33e4cb78eead124de5a06175df7e3b59f3bc4dca273de59b8a4151) +emitted operations + +big_map diff + + +storage + (Some 0x252050ca68bc0bc7940a33b68e12982233df654e652e96f2d28ab32be9ba046c) +emitted operations + +big_map diff + + +storage + (Some 0xae809d9a60de4be2126f115a819b9399358c9063790951f0373420a664335748) +emitted operations + +big_map diff + + +storage + (Some 0x128327880e041a2d6890d969f494c5581025dc3cdc3e3b6ce2d790f8ee68821e) +emitted operations + +big_map diff + + +storage + (Some 0x709b3e567cd3889a553a34818720157dd38724cf85ff458cfa91cb624db84b72) +emitted operations + +big_map diff + + +storage + (Some 0x932b426e549c4acc360611dfca579d436d7ce59111cb3f2bce5e9fa1562d4c1c) +emitted operations + +big_map diff + + +storage + (Some 0xef9144b2686c7a1de7488aeb9669bc3dafce03e580b27796d5489bbc2d5cef30) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_one[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_one[G1].out new file mode 100644 index 000000000000..e2028514c00b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_one[G1].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_random_one[G1] + +storage + (Some 0x121ad63b7b9c90355f2862d56fe793c29fd884e311a65917f860071464068682612e78f29d936ceea7056ccd2506f12d03ffb304ff19fd039c7404c0af9119775534e2d93c5f9fe172893767c1dc12a25edfff52434bd309aed1d54bd0a89fc4) +emitted operations + +big_map diff + + +storage + (Some 0x0538edb42138a4fec97b74645550b722d7e87ccdea13249fe9fbad25e314d8587287821622e9c7cbd8b5ffc5b244a5c70600605fd5a514fbf6d13764bdb35639fc7edb3b95006fad00083bdb65420ac4a2b7a5a67100ec7b0fed8cc3f5bcf251) +emitted operations + +big_map diff + + +storage + (Some 0x0e4b6dbffad2f4b3ff5be58477f3dca892a060954b35a0ba682a9e388071023d32e4d4f241d6b926348d1b76b78369af05485f02b87fe3666c70f04ed7439d175fcd2d76fb9790cd4fea48c38f2fa1194799208195286274a0c94aa4e7225c1b) +emitted operations + +big_map diff + + +storage + (Some 0x0ef689c3ad66bbc9bdb16bae245346c3e1d314091c15b37622720ef5e70defd6c59d2f4e4335c791644c28f967aa5a510607bc31d79aa0a40fe637c47fd825bc06c7ae7839eaeca4a0e4dd8f1589ca8db8b4fee09b91f5a43e04f17ef9ba3c04) +emitted operations + +big_map diff + + +storage + (Some 0x143c03201ff3222e412deca15c6345f6f3a82ea30a8d0b289952dfd4e6edca156617cffdfac43466e7745e5ad5222c7f09b8ed107474064dc0c94140949264aa6b3aec28772a8b1b3dd0571ecf433ccc9a7e51d2ac119b7bbeadec90d1f3c837) +emitted operations + +big_map diff + + +storage + (Some 0x122c5f9870721941131cbed468f1c754dc52f494fcd486dc761b4281e17eb41d29a40a983de68cec836a36f6d3c396e1054b6904fd965d74805b1c088ac71e7b5eeb41a1611b399c63777170365859ce68ed99bfde5158a207ade9807f5cc458) +emitted operations + +big_map diff + + +storage + (Some 0x0fbe56abacb7f089a1e46ca6d2837b8f98e51dd1054445c2dc599deec36800688b6add762d6eaea36823fe5e867955730f1c175b454fb0bae81377a0b30a0017d2c11b4a768b78679e8634e8d2567874ef10b5f523f2e7bf8e4698311de58051) +emitted operations + +big_map diff + + +storage + (Some 0x05014fcf35b18ed937a24b4ec2f635e371e331766f6971204a6d458c6876381476ed691a0d020a6b487b14cf4512fcc20678c937e35d63f63e52af3fd081162d4c34a1333ebcc40841a7bccec941e8596956cb56bae1d2768ce7dcebb31ed170) +emitted operations + +big_map diff + + +storage + (Some 0x016f4c61393eacd1b8365656d475d00271c146649018368fe2b0acb056daa92e133a45acc5ebc121d100673f49a55b1f0a91f97170f0ac67e8f8fa516a173fae35645c26748696f5d6b2094d0a4e5a8402f59cde699ff5627d3f16034d745174) +emitted operations + +big_map diff + + +storage + (Some 0x0a8fdae48244aa6f45cb349ccf56b7dce450c08036f96ca38a13ac8ba3c136bd9bd83a91559c7f5269f4e7f34f001e6d0152b902148420a763d285716810dd24cc17b9b486e8578ad7dbedeee3a4eab0d1ad73cbd3a1ea783b875b171d897030) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_one[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_one[G2].out new file mode 100644 index 000000000000..4c0c827c8d48 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_one[G2].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_random_one[G2] + +storage + (Some 0x09437976147a4d0d174d809df2b91247f2e2a482fa928fed9817b1740ddd941be108809ec427bba3abebab29e0fc91360dd9f11f94ec1c4cc3da10c13df7fe0a3e089b48c7f129c02c3fc47211f895c2243242f1a238cfca841e8d9d1e7927e400b626a5e4a4bf8f147aa6cd82073d5ec66504722a4ac8cf5939d5676a8b2b37731c94dce4e64ba9862eb657d17d789c19b1fb83a099335db3c569279fad3516257eef911af59c39e72a10da16e2c87394bee5a58b107c55ae00470377dea973) +emitted operations + +big_map diff + + +storage + (Some 0x05ef75bfe22c1366532a0be4e76af4f44c83653e53e7441e31eafd50d23f406093a42d56830ea0b2d6bd72c946c82bd6020366ebc02291ce6864c9923414fa0db8065979cd8031a84ab0bfe58ffa7d97c4f5829fc22126f8818d2b30cec132250207685a42ebd4b3566d3ae6437b12d1397ff6101d5cafb3283c0a26113b39436141bf2a09ec817d49145171a7cb0b4005483eff64cc380f7fab70479ff783e05b0c6a15245c93b732d9483adc38a3beb0179f766e685fae2ac8b91b888a4f3f) +emitted operations + +big_map diff + + +storage + (Some 0x16f479fc7f990fe798762da4e839ae6ab1c3ea82caa08d6d5892f28585b14ae178dcec9cbfe6f1a8128dcd46b87df07609798415e658f9387aa6138fbe3c335fb2327ffd2504c3f5aebd3285a2d08fc9966e8dd12f1c70dfdb369cc98f67b712179379ea1fd9bf46362cd7878a3667aa89f8c08627ad8d60868f219d49ed36336e393e0b7ebccd9027edbe634ab2d44507d065115a3ab3f4bd2ec1bb6361f580aa0040ccb0501426bd186e1e1971f7575e1e12ce77c8c2d8269799dd380de810) +emitted operations + +big_map diff + + +storage + (Some 0x04ff37dc37877f596cf0fee3190b74567c6925c5822c8776a1fdb926d250ecbd59c16109b3e18bf6389fd29a51f9815904b4d3277553a1afed4dc7c441cd16078016edf441df1bd21bf3590b701727a7a4ee5cfb77b4af06f154fcfe47cb44f91400cebb1f66c59f2ef796b5d8309c6d20a948156624e4d46ac09bc6b2566c115d2bc989e53137ee0bfa6e2e17d7b6fd10448f47c61b0fead5e32eb9f24f1f7635730a822166aa400d5537614fbf808d6e40f92746d6932993e74c3b57ef1520) +emitted operations + +big_map diff + + +storage + (Some 0x0b7028a94c140119e30ec04b76f245e78dc6d9828bcb5f503f44f2048faa675fac874f88b058c9b6e9ea2fb878a931fe0606479ff1fbaa8f8a1caa797ee960de8ee345eaef846578e7c6eef78aaa1a16c9cb9985821639cea2ec5866219d77de1593c6981c3da9e8c0a64bd8aa12a12d83e03494bf94ce9b098feb97a8921fc3a4a2656ba5a5eb130210b66766a0dc8512eb97e67cd5fe60859f1810ec7a1237fd80d4cb73e8641e1990a0e9e5c61f738ad8125b9108d78f96d704f3d43c71cd) +emitted operations + +big_map diff + + +storage + (Some 0x0f3e9c3968ce220c8d22fa306fd12e8afd05be41538ce630650650c8461563267ee4eb22e87818cd9e9022a1c23641d50b904a7acea602f907c97fb8701fe29fd6b2a276052b1d5cc152510016c466fe3ffb38ebdc0036058383c7643efaf10f07e7a1e694e4618c2057f4070912400e0c1457b32223be85ceb98afc5a9891ef467bbd4f96aeaf59dd92f39fd7698d4a1464d7b940f605a0afb023c06b2316ae5ce3e522e10e9e67ec2bc5dfef45e85e1272e5d4c26a7eb6b5255eea7117bea5) +emitted operations + +big_map diff + + +storage + (Some 0x17b906ef7baf4816f9ff3930b61253bbee2dc0cb2580449c234979733739d60b1e4c250cf38460240ddd8de171da0e790404c64d73d02d42540bb35b99bb9ef2d51af633c8546ed8eefd7a47cca204d3e6a2a82a6a661940e40995de3068033e12ad259c9a05af8b88196215be9a4310fa41e88454d8037572147571482cb0ffd39d50d1b09c2a68ae8a5694842bc8f9104104b65969eee42a43680a763fb577b0811d4b03d04c5060521b569d253014832d66cbb2163b1a15d5dc395969d47a) +emitted operations + +big_map diff + + +storage + (Some 0x0192202a64ffc9df0023d8b9b7125fb5b889386ea4e421bd8a113b1ebe45f491ecf552369e0e9e297d75264e73f5ac29119347d4871f1452d0375b4a19eaec758c58f6066bdc7c804ac9bab38b61f475913d0b1e80d8eb00790a11cd5ba3b81001069862fe6de4183f916099da7b8cfffdea73965df644dbb21fe2c9036296b01506fbd8299a8dce20c185f12a864e6c0f3c2e18a2e79a922a5f8bc59f48a4cd8ef322c678f080a10c4585c27af5c3bcb38a19f10c83ac484d81b55eb1393dd7) +emitted operations + +big_map diff + + +storage + (Some 0x1251e8448175157c4d2856be19064bf584481dfda30cae0d0b6f1e33b2a335be1a02dba175aec178718db6dc67409e8d09ae2872ec0d74b84c4a6eba82024630c290c6da27f387b39abe0f4fef1e1879bd17d32b1712cd9c2fa59c42796a6beb0f820092b9a5722b03aaf53470ead23b1d1c0a2263f2f010a5872d0251a81e21c21f4900aad8cad4f5615a9f9966e1090b13b49d84b63a6480c608dde86c383c6c943ca211d57b11aa4d518ef81121fa2604c2e650998138942d892fd49c258b) +emitted operations + +big_map diff + + +storage + (Some 0x05d336c2765803c6cb4b385ab9d4f4fa1ce2da0e5efd59a1fff5367678e6620664406da388d05b3b448be22281b2b3460f0c2b3b46ef2845bb1bf11ca2909f321cc35a295c656d7f0a432c31d6ff82b62cebfe000324d5bd35dfcff4016e526d0c424b33f830246ebca7fc52d1843d93275265da2bb6edb6edf6b9a0ff928cbb621aaa0c274614b185e39f3b8a91e50a13c54002d7842ba912b15f0671bc8e10bee8c8cd6f219f7115d9ed6d259cd029e75fc00ddb4cb508841b3c4ffe383d31) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_random[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_random[Fr].out new file mode 100644 index 000000000000..c2a43139e55f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_random[Fr].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_random_random[Fr] + +storage + (Some 0xb33a7eba53cdefc6ad9cb5c1328402d360c44984ea5dc51c2f542faadc6be816) +emitted operations + +big_map diff + + +storage + (Some 0xd3c6ed5a38abf39effe32bb89f2750a7792d10533191c9e7c24c4a110e918462) +emitted operations + +big_map diff + + +storage + (Some 0x712b1fcd10c384804b22abbcd62dbf10434baf60e33078f349b47a245a99394f) +emitted operations + +big_map diff + + +storage + (Some 0xc2a04fd112a74a4c60193a518a7a2dd968e63c4f122c5ccda2842e30040a1d0a) +emitted operations + +big_map diff + + +storage + (Some 0x145e33354dccac366850661cd8dc6b08f69edcd424055700833440bd798c1f1e) +emitted operations + +big_map diff + + +storage + (Some 0x9add5ab74ffe4b42e3618c846e60ea2b8a785d5b9392762ede89f50c85ff7803) +emitted operations + +big_map diff + + +storage + (Some 0x90827b0e55cd078db382a78e437a2320adeaf00847ad95a6c920ef2a13954727) +emitted operations + +big_map diff + + +storage + (Some 0x5bb1c6b970d42235a163ce608b783311e47114fd2d755624d9ec2c416d09250a) +emitted operations + +big_map diff + + +storage + (Some 0x3c32dff99dd4798310d347d73dcd51055acb344aca9135fd75a5b5be45ac8221) +emitted operations + +big_map diff + + +storage + (Some 0x8951db6a4a847740ee7a89d7e4057e2ba8e0fa5fbd8a6989c99f204492765e3b) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_random[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_random[G1].out new file mode 100644 index 000000000000..e1f01c4e594b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_random[G1].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_random_random[G1] + +storage + (Some 0x04e31b8535d081c6216917afc0b998284a19efb004598e40af32cf07a7c01baacb96621f42800d560e7bbc1cd76ef211046404a2303e2df0f827efee06a0146a3cf18a213b890080e33478eb652c142191363cec93bfe88f0f29ee65cd8a45a3) +emitted operations + +big_map diff + + +storage + (Some 0x158932735210b3c07f9c15eedec8acccefe84d080d3d5e06795e6ea3383e34a57c8ed1c091b6990d636dc3dc6e2b0a03077fb11f6c64d76840c168238b5838d2f06a27d48b1bd95cfd43b68f0a5871d22df1117b398118e71379602ee7a98e08) +emitted operations + +big_map diff + + +storage + (Some 0x0a32114ba43665abeb4ddb111a262bcd7ef8aab2f628627a4e237dea512835b4c8f7d3ed3bb2c4f8c99d68cff26b138519da6ab3ef7d260c2dbf7e84cb65890d65df014911b2d3f6d6e4248a23f36add20fc3c27c93560959c366a408ea38847) +emitted operations + +big_map diff + + +storage + (Some 0x14512db2530c824ca00345cc815036ad2a6e9d048c7571c74aff33f9f6b3a54239a893ac73142f3e0c74a5d179c0c5b2010a163762468c6feb4d27f1abccc4cf3fca36ce15868737320bff7aa4294bde62d103155e63b74de46d06d6b06ee1fd) +emitted operations + +big_map diff + + +storage + (Some 0x0e4459b6675e6b703556b06bc3db6adf195e4a0e3262bb12fa82fdbbb41d6aa0620743ed337ee87654fa8a22d907847b0d0c3e578ef5c00e360dba8567b12e4f3ecad77a2bdb303888af1c2fd730f5bdcbccfb4ad50e8571a0da0db8d7f63227) +emitted operations + +big_map diff + + +storage + (Some 0x0f32aa210d52283f4495ca85ce595df832cfa90d212922afe466a3d58203d419fa6cac2bc33fe2ef42c684c97ea061f90f49309180a9238b366642cc78ff5bd4ee8ee82aee112368248ec1a13d36210649b5696528e64a16e04f7c52ee14fd8c) +emitted operations + +big_map diff + + +storage + (Some 0x1658a9b3195f1103234c8115a54afd9455751a59223922cfb3b2c680be32511087f3ae762616d843fbfa19096fd58d990d6b9ddff4af5bcdfd44e7f49ed23393bf466a82b3e8e2281d883c6ccf8708755add7581a6a90f19be9263d8d624266b) +emitted operations + +big_map diff + + +storage + (Some 0x0182e82dbcb3151a65e424f9d5962e652eecf163a5a06ef5dcf1835009cd2cc0106b125bc6187a3eabaa25a8c4ef5c5b1009427ce8cf6efc38cdbd6efeb6c5463cd5d508fcf28bd7bd2c7eaf90b29bdc49cdde479a6c64bfb086d023972bb0f5) +emitted operations + +big_map diff + + +storage + (Some 0x130144b4bf38c092a5239371271624d48cbe36a0461feece232015f64917f2bec1bcba8e57597932d2a2776e2288b0e3068a74d96f52781b2b11a40ae730c56d909b6aa82afe81f291ba17667f8def0c8c62cf75b800d42460e5f1956eee18e9) +emitted operations + +big_map diff + + +storage + (Some 0x00f309e7224d4e6d1c59e27e2f651300d9bbb17f58ccf23943d88c7a4ada9902779c3d92a701e419cbf2e719927d94ac106420f6c2c79cc43631033d59ea62663c1c4eb127c43806a2b9d0e34bebca1ade68fefc795913823724a74a15df6a76) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_random[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_random[G2].out new file mode 100644 index 000000000000..ccea61eb3227 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_random[G2].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_random_random[G2] + +storage + (Some 0x0b2d5f882010f2406dd4fdda47ed2dce0a7419de3ce13360c709d420955d8fd254c0369250de38a69484f3d42266e56a0df6a9f48674db24a8adc43947f4d4155059769fda12b7de6de9c7d70166c3aa3b5780b3ef4e6285860935c5025a48a70ddb77c5df41cc6653f5ef1edf35776fd7f926e303115c1eca0465ab524626e16095d2d1bd516bf2bfc2ab4bb39c968c03bbda48f947a526fe887442e9cfd9dba4ac84be8f8d03308b9f32d566289a6cbfe19a87b13f87c3220bde5223f13568) +emitted operations + +big_map diff + + +storage + (Some 0x1170918e77a35dfc20db737834c50807efd778b7f0371e0a5cc5621df21f45311fc7d2cf36fa244a15605ac94f9bb12d0002517d54651966d9159aebc372ff2a7deec9a0d7dc80bce22025ace6cc1a32b8165e89790a8d6205121eb00238782709157dd20f2755c12822abc330be0b4a72df19d04d71f8cbd0357de1af8336987fd5db4f91f8813e66ded7570255c2fb11a13ba75e65187d7f342d7b4ef3ab41778bbd01f42680c86488bd7864cb78d9326e2e69f7195fd2fd09e06cffcce84d) +emitted operations + +big_map diff + + +storage + (Some 0x13d581984d95ad0ccedc521ee63077dfbfd3570ddf8dc0372f7411b903ce87caf5fc8a1cb1f66762e267a48f46a488ff1610ef168e28b79c9ab047ac9707de363b1ef06fb5ad86d919acadb9a6bca419d05dd129bc7436d4a8f024d4bdf7af8c0b1342fe8a6e949a51bb0901116d89437e7e18b8a40fb4be11f447879fb2651f7d449d70f84a1f959cc42869a85fe608062802296c3fe013f46b28c458ba28651c70fb61056b9a6af6b947e80becb252040dc8fc2fa9c79478973118d0984fda) +emitted operations + +big_map diff + + +storage + (Some 0x065e2a7e8b6ce16f9d46bfefa994cd13fa6813f6bad47e1d792dfd2e9bb4c3449cd7ebb05a8fb6b82b49116ca0dfb8a4041d960f46a4b0ac4bfe755470dff54f7b4d5bcb4f4d52ccf520b3f7e5defd6e6eac7b09f09f0e429c27477d5ec3a12706ad589e303bbed584d1ce39479c7a709bd73d4cc204ba78b7f4d70927a17d61dcd8e10e3359f396f98509f3b63cb16a06b68abc4b9597262f73f181bf042ef5c79b97c40304c259034534b3716d8168bf975565beea7f1ea21bfee63140d7db) +emitted operations + +big_map diff + + +storage + (Some 0x0c886b3d45067177888373985b7ad9e01f50fa934a67021f917ffe8a4f5730885c490f312bcb74590609a0550b26985711c932d4b30f82101a6b058f27b41edc2374273063470c3015840a9074c433cff7008f7c237bca62eac80cf82408ac85147a01f835601cb405e7a5daafb481462de4f5e765821c5e9c24d79945ffeb9926bcb5c516b1be62474f152fdcd79a7318f5733f19908cb27a4339c7cec46d2e904026ec421f41935ac05ee52dcd32ddf957d36da0478a231483cee910e158e9) +emitted operations + +big_map diff + + +storage + (Some 0x016720c0b2c7541ade5089d83b25c42eb26f76120904edf5d48c12a654df5bc690f3b8274f9a13b471e9d3397b253d5b0070d7e75316b1fe6581e120becefae1963f2c02e3dbe78fccaa0e82f3dc6b26b0f8fc878ccee3aca8681570864732791521735b6585f5543059a43e88d2293b372e76838962fcef28d9063259fcd7dc6216c833ad99fa0cd83c7aba57176da20a8a10c28d40cb495a3b4a7bfdddaa5b721a85b9dcb606bda5763eab6faea0ebceb638af2b2d8c61fa35c7e22d0393f3) +emitted operations + +big_map diff + + +storage + (Some 0x00971061214085d6e490b4e543696d4e2a5da1d7e3593bbb04444ffbc824a8f9bd9273b0a75f9672e5ef75407dc4daa503ebd0198f1af03f5d49688de7c9864836a521b93804a442d582b103d2ce3acf805ab611ed00d94eafe205fee48b1cc808c738a923f793e75b4a3070be1cc70d25eea3939703cddd1490f0f518d0cdcdcd7942b294020cd26338a25d3d8a2ddd02988eec1b3a4bbe0e13b6508b5a3bf790ff8ae7c78fc5ecd3760c7be57e94decf97f0271e7ef0c7396133b2b8927441) +emitted operations + +big_map diff + + +storage + (Some 0x17a0f51a199054d24bf00e707680a5318740b1e0f60935ae262a04a2e6a965d78ca4b066c8810c1c4ece3ba054b4f706132145795844cc04aba7fe5b92af3010c7d2ea264d82257de9caa012d267d5d2f040204d3a9b162ff35d58a94171a1dd0a6bf8ecae4b6109dca88a2bb07a4f2aff9148cb1d5af227278cafdc4a482070df87bd7cb968efafc621bd9fc0019e1114dd78975957c315f8f0988093457cbd710ba31b0f9eeda8b8d78e9d5833037ccb4a729726c3bb14941344aac882b9f1) +emitted operations + +big_map diff + + +storage + (Some 0x19d4f927fb96db848401d650a01ad72d05be245d7d75dc7e670e054e450e59b4c57119c8ba3df43e36ed405553a3439e13d903d0d8644031b13e46030ca2cd9f1450ac1428b54b399db96ed24f3d017a97bf5509470689b7585fdd848c587bc30f2c4d9df0e3b88e7d70a1288dddbc86e9c1f17cc110ea1a84f6900287a6a6ee016f59e02129792808721cee006337cb16657108891cb67ffdb6a5fd6fe4b5160cac312ca16aafd01ad9352a69b9e5ed2fdcbd58624fa800dcf0af4f6afc6cac) +emitted operations + +big_map diff + + +storage + (Some 0x0d4c4a2a8095869ea61b83d864cf7ad2611aeae6d8f2c980e8646e3cf101ebcc53ec086effeff6e79b97c09cd9e49b5719b698cb3540859837103da3bba5f89814a66a4bde5b6b8e12a585cefef8a2b884bb38e4dba52c3dccbe775291f971d41177f7ed1a9360fbc3ab6227d0f71a11dfd2a44f8e7d6fc4e8f42ad1e10bb1bdb3868595beddefd15f75c45fa857bbdb05955023d97e7360438d8588415ee12a626d8c0e147e9de1ccf2ded3e2826e5ebd9f48ca19fdd8b12c98dc6c8da4c951) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_zero[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_zero[Fr].out new file mode 100644 index 000000000000..90a26d379ec9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_zero[Fr].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_random_zero[Fr] + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_zero[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_zero[G1].out new file mode 100644 index 000000000000..d19a0b40c2df --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_zero[G1].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_random_zero[G1] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_zero[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_zero[G2].out new file mode 100644 index 000000000000..0313f705bc9e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_random_zero[G2].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_random_zero[G2] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_one[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_one[Fr].out new file mode 100644 index 000000000000..ec69bf8bb53c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_one[Fr].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_zero_one[Fr] + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_one[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_one[G1].out new file mode 100644 index 000000000000..d55b0641c1d2 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_one[G1].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_zero_one[G1] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_one[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_one[G2].out new file mode 100644 index 000000000000..64a1519f86df --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_one[G2].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_zero_one[G2] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_random[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_random[Fr].out new file mode 100644 index 000000000000..8f028d1bb672 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_random[Fr].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_zero_random[Fr] + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_random[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_random[G1].out new file mode 100644 index 000000000000..13d69e6b0c49 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_random[G1].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_zero_random[G1] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_random[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_random[G2].out new file mode 100644 index 000000000000..44edb22fac30 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_random[G2].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_zero_random[G2] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_zero[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_zero[Fr].out new file mode 100644 index 000000000000..41ce23a7eace --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_zero[Fr].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_zero_zero[Fr] + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_zero[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_zero[G1].out new file mode 100644 index 000000000000..e2b4d73b0000 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_zero[G1].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_zero_zero[G1] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_zero[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_zero[G2].out new file mode 100644 index 000000000000..291456c5b5ff --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_mul_zero_zero[G2].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_mul_zero_zero[G2] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_one[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_one[Fr].out new file mode 100644 index 000000000000..380cea02c722 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_one[Fr].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_neg_one[Fr] + +storage + (Some 0x00000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_one[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_one[G1].out new file mode 100644 index 000000000000..65766aeba6a7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_one[G1].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_neg_one[G1] + +storage + (Some 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb114d1d6855d545a8aa7d76c8cf2e21f267816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_one[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_one[G2].out new file mode 100644 index 000000000000..ab504ae3f3ff --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_one[G2].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_neg_one[G2] + +storage + (Some 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb813fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed0d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_random[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_random[Fr].out new file mode 100644 index 000000000000..6ebc4ef555d7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_random[Fr].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_neg_random[Fr] + +storage + (Some 0x9ac69bc1db5f20d9044178b065f5a09c8442bae11c45371f325e816bf721d739) +emitted operations + +big_map diff + + +storage + (Some 0x24a3fec4e7f8ad2ed4b6b0284e5d03ad143f3ac4d0ef3aed1f302c3459823c59) +emitted operations + +big_map diff + + +storage + (Some 0x0dd533bc546e5dcc64ac9d74ef41109f23d374ad2885194873e582d7700d0d16) +emitted operations + +big_map diff + + +storage + (Some 0xc0f43e2aff39fa4bcf5319a48396587b076d0193d9a1c31b676614d9b6a2dc0d) +emitted operations + +big_map diff + + +storage + (Some 0xbf12217bfe47d2f1d96db15e3f4a8eb9ba1229c610e2c0ca85205e217fe44422) +emitted operations + +big_map diff + + +storage + (Some 0x5b33082c052de9699109edb03ca4961ccdce7dc0b21f35ffa208f0c380d47353) +emitted operations + +big_map diff + + +storage + (Some 0x56bd703658653401c10d85274f305dec559e9630f202e307dfa3bb3980829360) +emitted operations + +big_map diff + + +storage + (Some 0x8b7fa597cd2d60533467ba57c1a15029a40239dd4cbf50341e7eb8aaa53abf4f) +emitted operations + +big_map diff + + +storage + (Some 0xcf62b00037ebd1ad24ffc51831e12878fdd817915f3bfc1f23150099fb2fb81e) +emitted operations + +big_map diff + + +storage + (Some 0x41df1100e72effd309b1f30f51729681df099140be3fbeeebf55468b9cb35d22) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_random[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_random[G1].out new file mode 100644 index 000000000000..792ef6ed5595 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_random[G1].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_neg_random[G1] + +storage + (Some 0x197eab592fb38019ed2b362a048af848d1cc13b4a6c1d035f0dec4f5c461df58ddc92c9b6cab42fe3683000d91ceafe418d5a984c5833a305e02b18372d56e0b3943e34fc5aa2e79dcc359d8a299928b43bec4667443ab008dc91432a9e81ae1) +emitted operations + +big_map diff + + +storage + (Some 0x15d02840b69f06135d0fb3b82ae94649b2a10da9f7b4a5df7365c95b9d04c755a863ff2010332a8cf2609e08578ff02a05d1699ce8d778f3d2d7aa3841ec11e23682ab0e7933b43d8bd7e8e2c3b0dc5bb3878d7c0f01fcdc2b4e97f84c46472c) +emitted operations + +big_map diff + + +storage + (Some 0x14f7f5b6207b770382e65ebe91981942bc7c88908d1b2e73c6ee1322300f703877064d65d16493a3a9c3e6c45b049dfc0166df18d9caa4a3ba208d1ec549ea8cd27dccb7e22497594b4981ad758393a96de9be4247b185d8117774616032a403) +emitted operations + +big_map diff + + +storage + (Some 0x19b7acfd822ce85763c2d9e81425e571397c506ee31a5ae31c44fad5288bf3ca43c1abf6e78d380f0f75dcb83e1ec9cd17edeaaadb33ca8c4640da22fbb6733c5c11cd77bffc1a8e900399f6ea807bdda382b5173ee95ccb8807f52923a4297f) +emitted operations + +big_map diff + + +storage + (Some 0x16a404c56efceca50db3014d9c764842f6cd2221ff6b89605bc617b48a12e791e01c089489a5cfcf8f02956dcf8d2d8b015b9061f8f854b00f95fd177a0e9d8254b9dcb23e486a2ed13a79cf4f2fb430cf3d1c1eb727909712cc71e780226728) +emitted operations + +big_map diff + + +storage + (Some 0x03fd56e83ffaec3a3441bdcd46ad961f62819e72e9aeadb78b830a271c4d480014215b337fc7fcca3a7a6c9e57b62ed909c0dc635400cf2268eb1b1c841ca68e5cdb7edbba2a388714319740348180b33795377af9228b13035cdb4bbfa5bb60) +emitted operations + +big_map diff + + +storage + (Some 0x0a31c603358cc5f0536c3b4cc7bb8ed1a6e0da1113eb42a13a07201f071f69f84fdab55bfcf3791495317a9826e0a9ca07ea3e8155f0c3a0df59c86120a0decf70bfd0886be8433932dfb62e7eaabb68da56859be8c78fe0efe6d774fbf2ca1b) +emitted operations + +big_map diff + + +storage + (Some 0x0b2b25da57dfdbcd47c80f821d732052e890661fec1b1a89e2bf83b1bfcc0f0c59fa59be2eea602692472819aa581cc319742355a5c737fb173d6fd2b53772de1fb90859d39fc6d9d64528be91b41230dccef41eb8af2e228d73bf80ce152dea) +emitted operations + +big_map diff + + +storage + (Some 0x072cfea08d58f5fc8db45c45c7ac6fcc01a0279b33652a685e1e961c2385b307ef336ff7a7529008158388ec3342a3980b0ffd641f1319835631e7e4c72450900c2d4cfc9ca2a9427189047b4d84ce7cb21148b414f1a160efa4b069c0a884ca) +emitted operations + +big_map diff + + +storage + (Some 0x12d6f85f33ad5cf0c0fc2c77c79bb7ac152b065cbdafbb7ae9b190ef16f3f3ba07a1a7be5af71e80038b843fc6d9772612da90cb178d7a6b48bc95b33cc431168d84bb441364c1df012faa8b53fa7b602d2a961fb65a8e13d37cc4e1d417b8d8) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_random[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_random[G2].out new file mode 100644 index 000000000000..3edf78f8d14d --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_random[G2].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_neg_random[G2] + +storage + (Some 0x04c4113c5de4461ee1effcfc208bb5a9804748c180af325b70966de7c379381de993a4659457b37367c9284ebf914033072014d5e51b7a11f6ceecdf68e310399700d00cd49696797fd39a95e701043291aa570cc853a3fc98389428112e62e90827091bae55288eddb843baa59bbbae59aeefc2e92d212a062dca9e1e96d621c4fae7cd94b1abab9b6efcbc720723b60ddfba8ba68bc874a1aab91b5fa6c6cb36a5cec01fb27b513a87c84ee21f18badc394467093a111040da3175c968157c) +emitted operations + +big_map diff + + +storage + (Some 0x19bf6c44cbd63175794a5730a440de20c66d93c2955412f40501117770de06ca62ac213b332dabafc32fb535c27c734d11d897534063baba835363bc6c8bb52d436d0cd6d3b7d80aae8f412960c6e31938b4c8b361ed3452dcf3fcc5021475dd02b7a90965f4ff09880874e59b382e0c1b37619a6f1320a124cf55b36b3aa716e42a588ae6f01af4364d08e3c0d814ef0d02bbeb23ef4c23f4b145aef8a73bb1ffc4895bafccfc86e621c05afbd218cdd3c2fc69268dc8a16129194a72c606c7) +emitted operations + +big_map diff + + +storage + (Some 0x11f4ea2b3cd84230f43e085ae38a0c60d712486564ce5eabf2de3df5f0da8d891657ce1f0c9fcf016b9aff1f48bc583d12ced40a391db04687b45de84f4a59eeef3c3db75ad8862c4241d03dd0bf36ff855156a58f185234bef6ec7301826f8c00b0f31e6a7c2c87eb9866c0259cf5b30997a7ea4513a70edc430c2e201822a3cea3bf3e0d2ad17680036d3423f2db7f132866d134609c331dc4aa1caf0caef348c51633e789f152b6cc255a8fc426c27331b519eb0cefd05b08bd23c2db1aba) +emitted operations + +big_map diff + + +storage + (Some 0x08968210984e1431183676214a406cb925239d7eb1334a07bae001019419d0f41ade7163bcf5578b7b7cea9c9efa12ca0dced010adea7a72bce2be7f2dee13be641ee209b87fb4ae77b00b43f30f770f6c745e9d4617d22020d5686ae40a495219db215c85c3166e233a2027314f1c3807aca9e90315a9dd0da624a87c61c709e2fad9b800290ebddbb413f5655ebb6b01008c500234652c966f668524577ddd3268ba1934d0eb44171fb2d2c8f24c21ff1edc3a68473604e2660646de8fe01a) +emitted operations + +big_map diff + + +storage + (Some 0x04d151207587d306af535541cd193cfc0f0039e84155c78bf9b0e5ef4b61f6cc49f39f9e84ed48c7c9b04c6e78dfc4b317fadc38e9900aefc0ff618ff983eb713861d8ff8cd0af5a9445f0cad43bef39ed4e0855072b8dae4ccec6f6ae7e1a62134d156f2cd1587df87ae54cbb3a6de862dbda2c898cc94e93833a573380d3af53d17061668c6693264cb124c87ab2050c9ecf6526f6401055724eb2fcb5173453c77870eedb8f774a711b8b75d0e7308c8e1aa3acda6466c48f148dbe04d1ad) +emitted operations + +big_map diff + + +storage + (Some 0x0c430e8fe9556cc97d2b00a6d84ae91f4eabd287e8a9ab9fb158b80eae7b000109f5ef7dd5d1efc9b7de64077041337110cdaa2bb05c7dbd6751bcdb6ade70100794d1a0ef3d462ae7e6a969a83e9f81245d389810da2e3ba8993ef7daff017005b222f1c29db487aac92aab1068afda51cd1e5489fc8931d2d9bdc142db5cccc17c65f729a57cf0ef7e4af9449f77000f39713ef371664621e2ad89f7c0261f4415dee34a6fe7c8dd041257bd2b793745d70103be171d0326cdc0321487d37d) +emitted operations + +big_map diff + + +storage + (Some 0x093485ee7701aefb89433f119a5b8d5a4230dabdafe8e55f26b23190b8550a1c51aa83ea1939d33de5477a4599f5101d0b36aa79caab813b87e102a83105b6bdb892e2381578aad742e53293c9bd24463156ca976342cbd03059b174e811884207b155b1dfc641bb0180493fcf47ed39010fd2d8420098b6ce5c1378cd402f725e7a91ee74cf068e4111a76ebdd2e6030b0220df748b9882f8f17cfbd1e624341262073563e037281c86eb70212e399c5efe102e9b0ba01f0b89ef266cb37cf9) +emitted operations + +big_map diff + + +storage + (Some 0x19428930e5a0f05f3319c7f034baf62b00cabd1568cff58065f30046b90021873cf56360730fefba5f2930d9d661dcb5034274f468bd901fed787268a0abaf18641ff90df4651d82e5c6d8c76af87032a8ff6e6e8b1a7bf2965e6f23cf0da586112cd75db7d04b7ed070d16a4372f0520b1c06a995af83d4389b418b8c026f2f3ddbe2ff6d0d8430a61b9b7cce9ff9d7196e415e4390bab69c57f39392dc448df55ea15f576492d15d046904d49e634a03809ccb1873ec89f23e95753c335495) +emitted operations + +big_map diff + + +storage + (Some 0x17692241047f40181fc0ea3d78c9c576477c5c2bef94dc7e795a1f06a32278f59ee4a862338c8d91093336652ea979e20595946083e9500ad695371dd38a84d3782f9bd1362c22210abff64e461b6f0dd6480f5af62ad72f6501a3b1cd5cd36215eec26a3f41f51d8066b88cf6882651b9a90fab9858e91e8cbb4231cc523aa5d031ba95123bc6a5f8e4b2f52fff5b650a81e87155d9e039f6aa9807a4ff68e91c61fc0b80d10e28ffda4e1f088079926575b35ef7f776cb0f36648066765c01) +emitted operations + +big_map diff + + +storage + (Some 0x1541b770bc7b492490eba70ec85bdc68ca78eb22e4f67bfabdf84ee7769e615efde8e6bd754d03ec62c41583b0bef01d06ff063375db383cf814f3807a5127afd82f55bf157bba04e36399cbaf189f63da12d29b0c584833d55b6e788e27d4a5176635964576c34bc77e17c29ffd8cad66a2b14880bfb03f5fbef5a66152617a093935ceca865ff6115b04a3720316db0b0b49aecb7883f2700551b8b1f632d7d6dbb1b2a4777c8745300a152eb4b46c742d08df7e8f99715df3a561c233ef00) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_zero[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_zero[Fr].out new file mode 100644 index 000000000000..da036d979a7f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_zero[Fr].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_neg_zero[Fr] + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_zero[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_zero[G1].out new file mode 100644 index 000000000000..1ae1ddfa66b9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_zero[G1].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_neg_zero[G1] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_zero[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_zero[G2].out new file mode 100644 index 000000000000..8f5366f1b549 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_neg_zero[G2].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_neg_zero[G2] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_neg_g1.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_neg_g1.out new file mode 100644 index 000000000000..f28d90270ff9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_neg_g1.out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_pairing_neg_g1 + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_neg_g2.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_neg_g2.out new file mode 100644 index 000000000000..9e43e0265f3e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_neg_g2.out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_pairing_neg_g2 + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_nil.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_nil.out new file mode 100644 index 000000000000..115540cb9ef6 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_nil.out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_pairing_nil + +storage + (Some True) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_one_one.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_one_one.out new file mode 100644 index 000000000000..9abf1946e359 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_one_one.out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_pairing_one_one + +storage + (Some False) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_one_random.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_one_random.out new file mode 100644 index 000000000000..67f4cb19d955 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_one_random.out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_pairing_one_random + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_one_zero.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_one_zero.out new file mode 100644 index 000000000000..4cf1d7716bb7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_one_zero.out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_pairing_one_zero + +storage + (Some True) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_random_one.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_random_one.out new file mode 100644 index 000000000000..071fe1651f1c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_random_one.out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_pairing_random_one + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_random_random.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_random_random.out new file mode 100644 index 000000000000..0468dd7a9fad --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_random_random.out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_pairing_random_random + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + +storage + (Some False) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_random_zero.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_random_zero.out new file mode 100644 index 000000000000..8f9cdec77e74 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_random_zero.out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_pairing_random_zero + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_zero_one.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_zero_one.out new file mode 100644 index 000000000000..3bcc0568e9eb --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_zero_one.out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_pairing_zero_one + +storage + (Some True) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_zero_random.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_zero_random.out new file mode 100644 index 000000000000..0c6a8f7bea9a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_zero_random.out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_pairing_zero_random + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_zero_zero.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_zero_zero.out new file mode 100644 index 000000000000..92dcf471ec7f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_pairing_zero_zero.out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_pairing_zero_zero + +storage + (Some True) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_signature_aggregation.out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_signature_aggregation.out new file mode 100644 index 000000000000..17656d832434 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_signature_aggregation.out @@ -0,0 +1,142 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_signature_aggregation + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + +storage + (Some True) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_one[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_one[Fr].out new file mode 100644 index 000000000000..a711b2bbe7b6 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_one[Fr].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_store_one[Fr] + +storage + (Some 0x0100000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_one[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_one[G1].out new file mode 100644 index 000000000000..80427270f259 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_one[G1].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_store_one[G1] + +storage + (Some 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_one[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_one[G2].out new file mode 100644 index 000000000000..1164570d6c85 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_one[G2].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_store_one[G2] + +storage + (Some 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_random[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_random[Fr].out new file mode 100644 index 000000000000..78661dc2e6b3 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_random[Fr].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_store_random[Fr] + +storage + (Some 0x4fa3eebe8eb999919b25e9496a740ba7e3db1e6af6d7dfc4226af5b7ff1bb31a) +emitted operations + +big_map diff + + +storage + (Some 0xeb3b4692c6d5d3be4529f58dc95561395d4fb06a4b56d5ecee427cb769df650c) +emitted operations + +big_map diff + + +storage + (Some 0x0fd278b6ab93ce8d6b66643b0173fd4e80d0d1776d0de34b13b6ff24227bae29) +emitted operations + +big_map diff + + +storage + (Some 0x9a6bc10fb59d3d43dd642524ddeb3f901c185488da989078efbd0166b878a66b) +emitted operations + +big_map diff + + +storage + (Some 0xd2e244946f6aa1a9f2e36a9f83faf915dd94d7fb31b1a4642eb7bb73861d0a58) +emitted operations + +big_map diff + + +storage + (Some 0xce66a6b5c6d97c52c44f3430271d6c466b1c9f656d43a3f6db6fb76a77b56d02) +emitted operations + +big_map diff + + +storage + (Some 0xfb437df580e072dbc887e9e0546c0843ccdc7b31264730e8e2f3c341a2d13908) +emitted operations + +big_map diff + + +storage + (Some 0xa1d61bc7847d649c7ed6bfdb0511393e83e6a8fe6a8999748ea767f44e2bca11) +emitted operations + +big_map diff + + +storage + (Some 0x5839a13cbc9d2ab02bba8d95197a7145d30d49b05c809ecf226e3e10a5181e02) +emitted operations + +big_map diff + + +storage + (Some 0x90348d02274bba201f5cb5a914c73410d7b34f5bbe090b3cfbe92ae307709055) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_random[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_random[G1].out new file mode 100644 index 000000000000..51a801b63940 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_random[G1].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_store_random[G1] + +storage + (Some 0x18782e3fbbe1f7abb5e2021b79bce810b5e8ae950c1e60d41731f0ae2ee4ebacbe59a9837bc34d5c61896561b04002be1760374bfa91e105077c507da80c080fe3a6c0ed820ce2515535f339b3f1510016ad6da0ff1a277065798e11aec2f74d) +emitted operations + +big_map diff + + +storage + (Some 0x1054b960d67ee71da9b596e7c543faf72544ba1ea2bc24d635f3da62feeeab2d0b00a8fed7ecf450767e1fdf1f2a913c127c6632387c6b5364a82dd2ff346b93cd29555913377b887c32e5a58fa37a7e69d1d82065e8b84865fee75aca361e6a) +emitted operations + +big_map diff + + +storage + (Some 0x0dbd1f474d065640ee4bde569142e26f7101a5c339c2f6630db6201c47483ed1303637aacb90002e1d7e7a84804b126205a8189fa87963e0fc81ea9c63e0a288768689f0ebe0868d98e9bb7e975026876f1df8502c6340adb3fde872f308704c) +emitted operations + +big_map diff + + +storage + (Some 0x141bebcd3a9c4145dcf836d368618d106cb3ab96669cce51cda04944eb3e0f07f0151a6fb4ba31d395692d4a305d623818a95f330d82b398d85782eb3a2793e098078058a289d5c5903cb78541807339db47e47d7dbbf2b5b4f0b6f9af323626) +emitted operations + +big_map diff + + +storage + (Some 0x088dcd93944d3cd43068b322488e178dd56f0ac3572d535d2c2d1da410e27572e425a4fcbbb8e10836f88d4010dba4a105a5ba71e19fc20bc6054df060a52887551b7b81196d63a3572c080705e9598e20cf3319343940de851d3d7ead06e8e9) +emitted operations + +big_map diff + + +storage + (Some 0x14c66800599dae815074aecfc36e2d43e2cdcf0c6663d9a0ab082488230ed0f6af46976598062df148d8b96144f55c5210e252370e812f951b90cc9765edbd2db2ba8157590338b3f5717a1bed450453f2674e3502bc95b2a8808e6d7442eada) +emitted operations + +big_map diff + + +storage + (Some 0x172318134285db82ebf7eab40d471dd4f733c0a624b360d8df00305ed381f3d59c7a54ce3996be88a63ce593a01c66e813ddee3711dca2ff243ea1e7141de5aec0a7611e67fa1f9c0e89ce7145ce58d0eef987d8949ad02d671166597d3a03ed) +emitted operations + +big_map diff + + +storage + (Some 0x0eb24546ddd153b1f2511c6155417c1d3fcc9750cb6b3af4367d01d485c2b6dba27cb1a7f19286e646e2f7a7aaf0363415735526cbb0f20f3d4141e6776f3c8b3255ee11ef05418ebfa62cf7e03220a5013a27e020544752260e295156f49c0a) +emitted operations + +big_map diff + + +storage + (Some 0x0e76d4b163d641ed1edbfdebdfa71c9fb6ad2e556e56ea0dadc3ea6bfc59b77e1e070063d9eb428b7730f35362310ac917e2386fd701b9389afb48d090552b8cb7a808aaec6669a06db758a7b30cf50933a275bac9a6e56ee4011fce86c496dd) +emitted operations + +big_map diff + + +storage + (Some 0x0a58dd111159092a784e404e0fbe2b03681a0c60ce1ebe52fea33f9780ac82118b6b8583b68fed0907adffdeef055d74120b04a2ebfd3a2a60a638cc4cd997090bb9b04d19cddcd61f9078903bd9f3e65fcdf9e5aec6de5a574ff7daef7cb079) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_random[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_random[G2].out new file mode 100644 index 000000000000..1788a0dc309a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_random[G2].out @@ -0,0 +1,72 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_store_random[G2] + +storage + (Some 0x0fdb404adcca2b3e91f5b6824e6f3c88d0086605135f34e733a47749f72e941ea0a546307b76881a2735b6aa24d630a20b9c453f8be68c3a875c4623df2156e61419a83dec2945fab6a50256f03cc9beabfb209d91858be53ead266aff598280191da483f4545715b6bfed1f3bc1aed02f97ed2e92f5bd9818432d1a17c6cef0b738beacef691b40c48b310a3befb95c10e67239e6fdf04c5c6720107466f19bb4d21b06ec221b72cf1a0b6ec4c1657872af587ffdda647cb36f9d73089b83d5) +emitted operations + +big_map diff + + +storage + (Some 0x00ec703f53406268b162add4b534cafad633e6d9453d289aad5f00a7ac68e2a9b1d97e9fb3b622bd95597b62b1fa0e7211fc2a54d8fded35cd021de7396db9dc1bdadce1d940da9c0dfbc6883c1212c639f2982b0f8943fe08ec1a12f1ea03081326c959ac2d47e6f75eacdf604efaa784796cafa511ad560c73552b9db0f8c9e0b1c281163f05b5d86b6b939c8fa5f512f6352c990f48e11a057e748a9695ae1d277918be1aa8fab5c96df723c47825136ef09c36d562214c25a087a5667b39) +emitted operations + +big_map diff + + +storage + (Some 0x17100f69943b685b53113c589254c0b26b23808b376a6addffa896ef873147871a0194d077acce64254e667890048f18056a3208afc3295e0829902800cfa9fcf50edc78841749d02198a3946010e6d800bd36171d41dfb6d79988f61524136003db45da43b3825c6dcf8b9ef46c8a40c842fcc3fee4ccf6d119b7b643ead789612ba75fca0d0a16dd31be31658c7b1d122b6a32d75113bb900ccf4a4da9cefc69b23814c486c9ade79d82eaa0593167b14a06ea2158f9d7710318d82553f1c5) +emitted operations + +big_map diff + + +storage + (Some 0x039c8fa2998d6fd874ea7b5cdfa5089bbe4cddd9958b445b6f33f65c27fd47b56a911e8134fe620275e7feece2ba1f560f731c917b8f756ec340c9d213a14c0f04bc79488ad38ca088d96c9a1c899aabc6cbf5070abf3231394b917c428fb0c5148e4d6c75c3b64e614582fefd2ccc979767d4b4da262d9c95ab27cf2fdf500268f0de8ecce5dad0f8ff5a06ef0e270f0dafac5b9ee6c9ff6665954a58e7dc792a257c1d80f27c1f91f9dedf4efc8da6e1d69d445364c7b7c076aef189f594e7) +emitted operations + +big_map diff + + +storage + (Some 0x118f6abab59d71635a4206e8fd16212e6d2f5f7c756e4308505f9e6473002a198292be2c834ca70cb40a1abeb3989c820a94d180da0025992a5c5ce516a2fa84c2e66d772acaf71c990aecefe420f885823f55bfdfa13db98035ae41c06ee6dc1305555d6da8ba4a92fd9eda92934ac5aed6db9fcc925fa51193a0ddf04594f2707d680d710171f041222e14644debfd14f43b880a07bdca546ffd02d792ed38be37171971ff662b094d54a37816aff6efbb2e57875dd9af97dee97e8c5f6109) +emitted operations + +big_map diff + + +storage + (Some 0x11308b1d8c4cb3cb1a57c98f1163ea78c44c1035cbc741988dc56a3c10c3d3b94b29445eae3199073857dbe6b146d6aa087a91a83306c1cbbc1f2eef3d058639ceda4e98ab1124dbaccc52dd25d7116675de0ba740fe95f2700ec1504461365a08ff04b06bba77a77b5b7ffa45a3ec56c8626fb7219f0d2d891251c1b4881f141bbbaf09217044e9bb69c8c1652476500153567f2ca8dd517cbd1c3467c10771d02fbf45fdad811118b325ce97e43ef72beff8857f44b0968de7b01a770fddd0) +emitted operations + +big_map diff + + +storage + (Some 0x0172fab176d798aed92f6ac9abeb28c510d77fd42601522db72c8fd7abe52fa0ce5adfb2ef67739bc4fb64fbbe3cd52b12a54aa1af0a44cdcc5c9110c13eac553ff037f1a8f304d052a0fc96ea40c946d5d31a8427feb1249fec862c28356afc0794bfcdc71fb3dfcf664e9a8db201c5b774ec45c2f0028531ff6abd2292dc1856fa9420fc8f5b632e84a592d73b25ba0fbb3e8cc6371e5f0d6c04b356f0e9d786545619a397f1dc1041854b5bde626b1b1d01258d6b16a80588453996a6eb00) +emitted operations + +big_map diff + + +storage + (Some 0x0156d0250e60af2f0678224eed0afee0594bb6f85293f7c4ab93b17ea0231bc1590d28250968931b8ee23a6f0f364d8c029e81178b6e60e9de5f858d44b102b823a028c4b8c230cf78e5f8a77964fda2bc4cb1a8cafd08641dcb20689b0903c104e58754b4c52b2b225473b407544d32823b8a7b47b2b919b96da883e20bd8a526ffe21928186d36d8355c16aa56523004f6dc232f441b80a9efaedec4dfd3abafffa97af0623f434e324120ecf61516affd143cc275ebda8c7552c89c718764) +emitted operations + +big_map diff + + +storage + (Some 0x058b2dbf9ed4d328d9afa79262a86ef47a044bba9226441df410d255040ae88931ca92ad6f127656c2309a3f9724af830cdb406c0cf88f930976f2b162d300d58930a9ef86869073be0043e9383e5875d9f5ce8a2cfee895f2591b6a265811ca13baaa13b0d54995b9ac5c2bd893730b07abf2f8b4c99b121870227c594365dac3e330dbeff1c2fb93f8b1dc6ec4d8311525ee7f96ac8b71f94b149bde3749c2d03fb8494592daafb6963c6a9427b887d67b0ad72c29804aff97897e6272379b) +emitted operations + +big_map diff + + +storage + (Some 0x0cfe1a34585ccf7095a05262a23fa1acde77911d1b9d0f894d63457ae6da644c417569c14a4e39b0ee2e51926a1ce7f108d6d899a1e78d27e6586f31d50fdf882d001bdb7fe934061214b756c5a9e64b66b5b13cd4c44ba1dd97101e394f82ec0661b38d968d819b85eab59f321c42b2d05e8037f4d1ba00bcaa80f2fe8f4130c4e292c073a856e095cc823965ffe97918ef4fa0f24b9bfa56b0ce783b3a6362de2781080d6ff52651e6ff71176b873318138cade3d284921c3eacf1734f5854) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_zero[Fr].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_zero[Fr].out new file mode 100644 index 000000000000..5eb3203ebc11 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_zero[Fr].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_store_zero[Fr] + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_zero[G1].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_zero[G1].out new file mode 100644 index 000000000000..005c089f6969 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_zero[G1].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_store_zero[G1] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_zero[G2].out b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_zero[G2].out new file mode 100644 index 000000000000..06d60e3dbe55 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_bls12_381.TestBls12_381::test_store_zero[G2].out @@ -0,0 +1,9 @@ +tests_011/test_contract_bls12_381.py::TestBls12_381::test_store_zero[G2] + +storage + (Some 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert.tz].out new file mode 100644 index 000000000000..0311f17aaab8 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert.tz].out @@ -0,0 +1,9 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/assert.tz] + +{ parameter bool ; + storage unit ; + code { CAR ; + { IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpeq.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpeq.tz].out new file mode 100644 index 000000000000..aa13fc75fa75 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpeq.tz].out @@ -0,0 +1,12 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/assert_cmpeq.tz] + +{ parameter (pair int int) ; + storage unit ; + code { CAR ; + DUP ; + CAR ; + DIP { CDR } ; + { { COMPARE ; EQ } ; IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpge.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpge.tz].out new file mode 100644 index 000000000000..8235fde05d59 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpge.tz].out @@ -0,0 +1,12 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/assert_cmpge.tz] + +{ parameter (pair int int) ; + storage unit ; + code { CAR ; + DUP ; + CAR ; + DIP { CDR } ; + { { COMPARE ; GE } ; IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpgt.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpgt.tz].out new file mode 100644 index 000000000000..fcdfada7b2f7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpgt.tz].out @@ -0,0 +1,12 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/assert_cmpgt.tz] + +{ parameter (pair int int) ; + storage unit ; + code { CAR ; + DUP ; + CAR ; + DIP { CDR } ; + { { COMPARE ; GT } ; IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmple.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmple.tz].out new file mode 100644 index 000000000000..f79a9b3402a9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmple.tz].out @@ -0,0 +1,12 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/assert_cmple.tz] + +{ parameter (pair int int) ; + storage unit ; + code { CAR ; + DUP ; + CAR ; + DIP { CDR } ; + { { COMPARE ; LE } ; IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmplt.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmplt.tz].out new file mode 100644 index 000000000000..0cbb9c49cb02 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmplt.tz].out @@ -0,0 +1,12 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/assert_cmplt.tz] + +{ parameter (pair int int) ; + storage unit ; + code { CAR ; + DUP ; + CAR ; + DIP { CDR } ; + { { COMPARE ; LT } ; IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpneq.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpneq.tz].out new file mode 100644 index 000000000000..974918c748b1 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_cmpneq.tz].out @@ -0,0 +1,12 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/assert_cmpneq.tz] + +{ parameter (pair int int) ; + storage unit ; + code { CAR ; + DUP ; + CAR ; + DIP { CDR } ; + { { COMPARE ; NEQ } ; IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_eq.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_eq.tz].out new file mode 100644 index 000000000000..e47bb8d334e1 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_eq.tz].out @@ -0,0 +1,13 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/assert_eq.tz] + +{ parameter (pair int int) ; + storage unit ; + code { CAR ; + DUP ; + CAR ; + DIP { CDR } ; + COMPARE ; + { EQ ; IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_ge.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_ge.tz].out new file mode 100644 index 000000000000..ab7dbae93a54 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_ge.tz].out @@ -0,0 +1,13 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/assert_ge.tz] + +{ parameter (pair int int) ; + storage unit ; + code { CAR ; + DUP ; + CAR ; + DIP { CDR } ; + COMPARE ; + { GE ; IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_gt.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_gt.tz].out new file mode 100644 index 000000000000..1b3d9c65a7be --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_gt.tz].out @@ -0,0 +1,13 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/assert_gt.tz] + +{ parameter (pair int int) ; + storage unit ; + code { CAR ; + DUP ; + CAR ; + DIP { CDR } ; + COMPARE ; + { GT ; IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_le.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_le.tz].out new file mode 100644 index 000000000000..2fc9088b00ee --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_le.tz].out @@ -0,0 +1,13 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/assert_le.tz] + +{ parameter (pair int int) ; + storage unit ; + code { CAR ; + DUP ; + CAR ; + DIP { CDR } ; + COMPARE ; + { LE ; IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_lt.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_lt.tz].out new file mode 100644 index 000000000000..94006881f059 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_lt.tz].out @@ -0,0 +1,13 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/assert_lt.tz] + +{ parameter (pair int int) ; + storage unit ; + code { CAR ; + DUP ; + CAR ; + DIP { CDR } ; + COMPARE ; + { LT ; IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_neq.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_neq.tz].out new file mode 100644 index 000000000000..f75e6ab8d934 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--assert_neq.tz].out @@ -0,0 +1,13 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/assert_neq.tz] + +{ parameter (pair int int) ; + storage unit ; + code { CAR ; + DUP ; + CAR ; + DIP { CDR } ; + COMPARE ; + { NEQ ; IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--big_map_get_add.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--big_map_get_add.tz].out new file mode 100644 index 000000000000..ba24182856fe --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--big_map_get_add.tz].out @@ -0,0 +1,23 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/big_map_get_add.tz] + +{ parameter (pair (pair %set_pair int (option int)) (pair %check_pair int (option int))) ; + storage (pair (big_map int int) unit) ; + code { DUP ; + DIP { { CDR ; CAR } } ; + DUP ; + DIP { { CAR ; CDR } ; DUP ; CAR ; DIP { CDR } ; UPDATE ; DUP } ; + { CAR ; CDR } ; + DUP ; + CDR ; + DIP { CAR ; GET } ; + { IF_NONE + { { IF_NONE {} { { UNIT ; FAILWITH } } } } + { SWAP ; + { IF_NONE + { { UNIT ; FAILWITH } } + { { { COMPARE ; EQ } ; IF {} { { UNIT ; FAILWITH } } } } } } } ; + UNIT ; + SWAP ; + PAIR ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--big_map_mem.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--big_map_mem.tz].out new file mode 100644 index 000000000000..59ab55977b85 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--big_map_mem.tz].out @@ -0,0 +1,14 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/big_map_mem.tz] + +{ parameter (pair int bool) ; + storage (pair (big_map int unit) unit) ; + code { DUP ; + DUP ; + { CAR ; CDR } ; + DIP { { CAR ; CAR } ; DIP { { CDR ; CAR } ; DUP } ; MEM } ; + { { COMPARE ; EQ } ; IF {} { { UNIT ; FAILWITH } } } ; + UNIT ; + SWAP ; + PAIR ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--build_list.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--build_list.tz].out new file mode 100644 index 000000000000..3248282e9954 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--build_list.tz].out @@ -0,0 +1,24 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/build_list.tz] + +{ parameter nat ; + storage (list nat) ; + code { CAR @counter ; + NIL @acc nat ; + SWAP ; + DUP @cmp_num ; + PUSH nat 0 ; + { COMPARE ; NEQ } ; + LOOP { DUP ; + DIP { SWAP } ; + CONS @acc ; + SWAP ; + PUSH nat 1 ; + SWAP ; + SUB @counter ; + DUP ; + DIP { ABS } ; + PUSH int 0 ; + { COMPARE ; NEQ } } ; + CONS ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--carn_and_cdrn.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--carn_and_cdrn.tz].out new file mode 100644 index 000000000000..6c28d68fcf69 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--carn_and_cdrn.tz].out @@ -0,0 +1,29 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/carn_and_cdrn.tz] + +{ parameter (pair nat nat nat unit) ; + storage unit ; + code { CAR ; + DUP ; + CAR ; + PUSH nat 1 ; + { { COMPARE ; EQ } ; IF {} { { UNIT ; FAILWITH } } } ; + DUP ; + { GET 1 } ; + PUSH nat 1 ; + { { COMPARE ; EQ } ; IF {} { { UNIT ; FAILWITH } } } ; + DUP ; + { GET 3 } ; + PUSH nat 4 ; + { { COMPARE ; EQ } ; IF {} { { UNIT ; FAILWITH } } } ; + DUP ; + { GET 5 } ; + PUSH nat 2 ; + { { COMPARE ; EQ } ; IF {} { { UNIT ; FAILWITH } } } ; + DUP ; + { GET 6 } ; + UNIT ; + { { COMPARE ; EQ } ; IF {} { { UNIT ; FAILWITH } } } ; + DROP ; + UNIT ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--compare.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--compare.tz].out new file mode 100644 index 000000000000..81742b257526 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--compare.tz].out @@ -0,0 +1,22 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/compare.tz] + +{ parameter (pair mutez mutez) ; + storage (list bool) ; + code { CAR ; + DUP ; + DUP ; + DUP ; + DUP ; + DIP 5 { NIL bool } ; + DIP 4 { DUP ; CAR ; DIP { CDR } ; COMPARE ; LE ; CONS } ; + DIP 3 { DUP ; CAR ; DIP { CDR } ; COMPARE ; GE ; CONS } ; + DIP 2 { DUP ; CAR ; DIP { CDR } ; COMPARE ; LT ; CONS } ; + DIP { DUP ; CAR ; DIP { CDR } ; COMPARE ; GT ; CONS } ; + DUP ; + CAR ; + DIP { CDR } ; + COMPARE ; + EQ ; + CONS ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--compare_bytes.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--compare_bytes.tz].out new file mode 100644 index 000000000000..1e0a898ef292 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--compare_bytes.tz].out @@ -0,0 +1,22 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/compare_bytes.tz] + +{ parameter (pair bytes bytes) ; + storage (list bool) ; + code { CAR ; + DUP ; + DUP ; + DUP ; + DUP ; + DIP 5 { NIL bool } ; + DIP 4 { DUP ; CAR ; DIP { CDR } ; COMPARE ; LE ; CONS } ; + DIP 3 { DUP ; CAR ; DIP { CDR } ; COMPARE ; GE ; CONS } ; + DIP 2 { DUP ; CAR ; DIP { CDR } ; COMPARE ; LT ; CONS } ; + DIP { DUP ; CAR ; DIP { CDR } ; COMPARE ; GT ; CONS } ; + DUP ; + CAR ; + DIP { CDR } ; + COMPARE ; + EQ ; + CONS ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--fail.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--fail.tz].out new file mode 100644 index 000000000000..17531448bc03 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--fail.tz].out @@ -0,0 +1,3 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/fail.tz] + +{ parameter unit ; storage unit ; code { { UNIT ; FAILWITH } } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--guestbook.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--guestbook.tz].out new file mode 100644 index 000000000000..1eb1ae49f4d5 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--guestbook.tz].out @@ -0,0 +1,18 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/guestbook.tz] + +{ parameter string ; + storage (map address (option string)) ; + code { UNPAIR @message @guestbook ; + SWAP ; + DUP ; + SENDER ; + GET @previous_message ; + { IF_NONE { { UNIT ; FAILWITH } } {} } ; + { IF_NONE {} { { UNIT ; FAILWITH } } } ; + SWAP ; + SOME ; + SOME ; + SENDER ; + UPDATE ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--macro_annotations.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--macro_annotations.tz].out new file mode 100644 index 000000000000..c03936ab7b10 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--macro_annotations.tz].out @@ -0,0 +1,13 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/macro_annotations.tz] + +{ parameter unit ; + storage (pair (unit %truc) unit) ; + code { DROP ; + UNIT ; + UNIT ; + PAIR %truc ; + UNIT ; + DUP @new_storage 2 ; + DIP { DROP ; DROP } ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--map_caddaadr.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--map_caddaadr.tz].out new file mode 100644 index 000000000000..e3f9a95fc540 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--map_caddaadr.tz].out @@ -0,0 +1,40 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/map_caddaadr.tz] + +{ parameter unit ; + storage (pair (pair nat (pair nat (pair (pair (pair (nat %p) (mutez %value)) nat) nat))) nat) ; + code { { DUP ; + DIP { CDR @%% ; + { DUP ; + DIP { CAR @%% ; + { DUP ; + DIP { CDR @%% ; + { DUP ; + DIP { CDR @%% ; + { DUP ; + DIP { CAR @%% ; + { DUP ; + DIP { CAR @%% ; + { DUP ; + CDR @value ; + { PUSH mutez 1000000 ; ADD } ; + SWAP ; + CAR @%% ; + PAIR %@ %value } } ; + CDR @%% ; + SWAP ; + PAIR %@ %@ } } ; + CDR @%% ; + SWAP ; + PAIR %@ %@ } } ; + CAR @%% ; + PAIR %@ %@ } } ; + CAR @%% ; + PAIR %@ %@ } } ; + CDR @%% ; + SWAP ; + PAIR %@ %@ } } ; + CAR @%% ; + PAIR %@ %@ @new_storage } ; + NIL operation ; + SWAP ; + { CDR @%% ; SWAP ; PAIR % %@ } } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--max_in_list.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--max_in_list.tz].out new file mode 100644 index 000000000000..40496e002eda --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--max_in_list.tz].out @@ -0,0 +1,17 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/max_in_list.tz] + +{ parameter (list int) ; + storage (option int) ; + code { CAR ; + DIP { NONE int } ; + ITER { SWAP ; + IF_NONE + { SOME } + { DIP { DUP } ; + DUP ; + DIP { SWAP } ; + { COMPARE ; LE } ; + IF { DROP } { DIP { DROP } } ; + SOME } } ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--min.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--min.tz].out new file mode 100644 index 000000000000..5538c636ef00 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--min.tz].out @@ -0,0 +1,13 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/min.tz] + +{ parameter (pair int int) ; + storage int ; + code { CAR ; + DUP ; + DUP ; + CAR ; + DIP { CDR } ; + { COMPARE ; LT } ; + IF { CAR } { CDR } ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--pair_macro.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--pair_macro.tz].out new file mode 100644 index 000000000000..b3d5f1e0fb3e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--pair_macro.tz].out @@ -0,0 +1,18 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/pair_macro.tz] + +{ parameter unit ; + storage unit ; + code { UNIT ; + UNIT ; + UNIT ; + UNIT ; + UNIT ; + { DIP 3 { PAIR %x4 %x5 } ; + DIP 2 { PAIR %x3 } ; + DIP { PAIR %x2 } ; + PAIR %x1 @name } ; + { CDR ; CDR ; CDR ; CAR %x4 @fourth } ; + DROP ; + CDR ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--set_caddaadr.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--set_caddaadr.tz].out new file mode 100644 index 000000000000..c375f660962b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--set_caddaadr.tz].out @@ -0,0 +1,33 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/set_caddaadr.tz] + +{ parameter mutez ; + storage (pair (pair nat (pair nat (pair (pair (pair (nat %p) (mutez %value)) nat) nat))) nat) ; + code { DUP ; + CAR ; + SWAP ; + CDR ; + { DUP ; + DIP { CAR @%% ; + { DUP ; + DIP { CDR @%% ; + { DUP ; + DIP { CDR @%% ; + { DUP ; + DIP { CAR @%% ; + { DUP ; + DIP { CAR @%% ; { DUP ; CDR %value ; DROP ; CAR @%% ; PAIR %@ %value } } ; + CDR @%% ; + SWAP ; + PAIR %@ %@ } } ; + CDR @%% ; + SWAP ; + PAIR %@ %@ } } ; + CAR @%% ; + PAIR %@ %@ } } ; + CAR @%% ; + PAIR %@ %@ } } ; + CDR @%% ; + SWAP ; + PAIR %@ %@ @toplevel_pair_name } ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--take_my_money.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--take_my_money.tz].out new file mode 100644 index 000000000000..0e35d9ecd1e8 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--take_my_money.tz].out @@ -0,0 +1,14 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/take_my_money.tz] + +{ parameter key_hash ; + storage unit ; + code { CAR ; + IMPLICIT_ACCOUNT ; + DIP { UNIT } ; + PUSH mutez 1000000 ; + UNIT ; + TRANSFER_TOKENS ; + NIL operation ; + SWAP ; + CONS ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--unpair_macro.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--unpair_macro.tz].out new file mode 100644 index 000000000000..27852bae5fb1 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_macros.TestMacroExpansion::test_macro_expansion[macros--unpair_macro.tz].out @@ -0,0 +1,20 @@ +tests_011/test_contract_macros.py::TestMacroExpansion::test_macro_expansion[macros/unpair_macro.tz] + +{ parameter (unit :param_unit) ; + storage (unit :u1) ; + code { DROP ; + UNIT :u4 @a4 ; + UNIT :u3 @a3 ; + UNIT :u2 @a2 ; + UNIT :u1 @a1 ; + PAIR ; + UNPAIR @x1 @x2 ; + { DIP 2 { PAIR %x3 %x4 } ; PAIR %x1 %x2 ; PAIR @p1 } ; + { UNPAIR ; UNPAIR ; DIP 2 { UNPAIR } } ; + { DIP 2 { PAIR %x3 %x4 } ; DIP { PAIR %x2 } ; PAIR %x1 @p2 } ; + { UNPAIR ; DIP { UNPAIR } ; DIP 2 { UNPAIR } } ; + { DIP { PAIR %x2 %x3 } ; DIP { PAIR % %x4 } ; PAIR %x1 @p3 } ; + { UNPAIR ; DIP { UNPAIR } ; DIP { UNPAIR } } ; + DIP { DROP ; DROP ; DROP } ; + NIL operation ; + PAIR } } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_origination_diff.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_origination_diff.out new file mode 100644 index 000000000000..f5c8223de24b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_origination_diff.out @@ -0,0 +1,29 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractBigMapOrigination::test_big_map_origination_diff + +Node is bootstrapped. +This simulation failed: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1040000 + Storage limit: 60000 bytes + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ1000 + Script: + { parameter (big_map int int) ; + storage (big_map int int) ; + code { CAR ; NIL operation ; PAIR } } + Initial storage: (Pair 0 { Elt 1 (Some 4) }) + No delegate for this contract + This operation FAILED. + +Ill typed data: 1: (Pair 0 { Elt 1 (Some 4) }) +is not an expression of type big_map int int +At line 1 characters 0 to 26, value (Pair 0 { Elt 1 (Some 4) }) +is invalid for type big_map int int. +At line 1 characters 6 to 7, +Unexpected forged value. +Fatal error: + origination simulation failed diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_origination_id.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_origination_id.out new file mode 100644 index 000000000000..799b6f40cdff --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_origination_id.out @@ -0,0 +1,27 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractBigMapOrigination::test_big_map_origination_id + +Node is bootstrapped. +This simulation failed: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1040000 + Storage limit: 60000 bytes + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ1000 + Script: + { parameter (big_map int int) ; + storage (big_map int int) ; + code { CAR ; NIL operation ; PAIR } } + Initial storage: 0 + No delegate for this contract + This operation FAILED. + +Ill typed data: 1: 0 is not an expression of type big_map int int +At line 1 characters 0 to 1, value 0 is invalid for type big_map int int. +At line 1 characters 0 to 1, +Unexpected forged value. +Fatal error: + origination simulation failed diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_origination_literal.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_origination_literal.out new file mode 100644 index 000000000000..c172a1ca8518 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_origination_literal.out @@ -0,0 +1,48 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractBigMapOrigination::test_big_map_origination_literal + +Node is bootstrapped. +Estimated gas: 1636.504 units (will add 100 for safety) +Estimated storage: 403 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.00046 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1737 + Storage limit: 423 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.00046 + fees(the baker who will include this operation,0) ... +ꜩ0.00046 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ1000 + Script: + { parameter (big_map int int) ; + storage (big_map int int) ; + code { CAR ; NIL operation ; PAIR } } + Initial storage: { Elt 0 0 } + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 146 bytes + Updated big_maps: + New map(4) of type (big_map int int) + Set map(4)[0] to 0 + Paid storage size diff: 146 bytes + Consumed gas: 1636.504 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0365 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ1000 + [CONTRACT_HASH] ... +ꜩ1000 + +New contract [CONTRACT_HASH] originated. +Contract memorized as originate_big_map_literal. +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_transfer_diff.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_transfer_diff.out new file mode 100644 index 000000000000..deb379bfd708 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_transfer_diff.out @@ -0,0 +1,23 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractBigMapOrigination::test_big_map_transfer_diff + +Node is bootstrapped. +This simulation failed: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1040000 + Storage limit: 60000 bytes + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: (Pair 0 { Elt 1 (Some 4) }) + This operation FAILED. + +Invalid argument passed to contract [CONTRACT_HASH]. +At (unshown) location 0, value (Pair 0 { Elt 1 (Some 4) }) +is invalid for type big_map int int. +At (unshown) location 1, Unexpected forged value. +Fatal error: + transfer simulation failed diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_transfer_id.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_transfer_id.out new file mode 100644 index 000000000000..4fc79be4fcd7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractBigMapOrigination::test_big_map_transfer_id.out @@ -0,0 +1,22 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractBigMapOrigination::test_big_map_transfer_id + +Node is bootstrapped. +This simulation failed: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1040000 + Storage limit: 60000 bytes + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: 0 + This operation FAILED. + +Invalid argument passed to contract [CONTRACT_HASH]. +At (unshown) location 0, value 0 is invalid for type big_map int int. +At (unshown) location 0, Unexpected forged value. +Fatal error: + transfer simulation failed diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainLevel::test_level.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainLevel::test_level.out new file mode 100644 index 000000000000..ef8dd11f1c5a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainLevel::test_level.out @@ -0,0 +1,121 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainLevel::test_level + +Node is bootstrapped. +Estimated gas: 1404.624 units (will add 100 for safety) +Estimated storage: 300 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000424 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1505 + Storage limit: 320 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000424 + fees(the baker who will include this operation,0) ... +ꜩ0.000424 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ100 + Script: + { parameter unit ; + storage nat ; + code { DROP ; LEVEL ; NIL operation ; PAIR } } + Initial storage: 9999999 + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 43 bytes + Paid storage size diff: 43 bytes + Consumed gas: 1404.624 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01075 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ100 + [CONTRACT_HASH] ... +ꜩ100 + +New contract [CONTRACT_HASH] originated. +Contract memorized as level. +Injected block [BLOCK_HASH] +Injected block [BLOCK_HASH] +Node is bootstrapped. +Estimated gas: 2048.813 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000467 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 2149 + Storage limit: 0 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000467 + fees(the baker who will include this operation,0) ... +ꜩ0.000467 + Transaction: + Amount: ꜩ500 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Updated storage: 4 + Storage size: 40 bytes + Consumed gas: 2048.813 + Balance updates: + [CONTRACT_HASH] ... -ꜩ500 + [CONTRACT_HASH] ... +ꜩ500 + +Injected block [BLOCK_HASH] +{ "level": [LEVEL], "proto": 1, + "predecessor": "[BLOCK_HASH]", + "timestamp": "[TIMESTAMP]", "validation_pass": 4, + "operations_hash": "[OPERATION_HASH]", + "fitness": "[FITNESS]", + "context": "[CONTEXT]" } +4 +Injected block [BLOCK_HASH] +Injected block [BLOCK_HASH] +4 +Node is bootstrapped. +Estimated gas: 1202.320 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000383 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1303 + Storage limit: 0 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000383 + fees(the baker who will include this operation,0) ... +ꜩ0.000383 + Transaction: + Amount: ꜩ500 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Updated storage: 7 + Storage size: 40 bytes + Consumed gas: 1202.320 + Balance updates: + [CONTRACT_HASH] ... -ꜩ500 + [CONTRACT_HASH] ... +ꜩ500 + +Injected block [BLOCK_HASH] +7 diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_contract_fails.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_contract_fails.out new file mode 100644 index 000000000000..d3d1bccfd77a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_contract_fails.out @@ -0,0 +1,2 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_contract_fails + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_gen_keys.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_gen_keys.out new file mode 100644 index 000000000000..89a1f921beaa --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_gen_keys.out @@ -0,0 +1,2 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_gen_keys + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_init_proxy.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_init_proxy.out new file mode 100644 index 000000000000..1884b40e933b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_init_proxy.out @@ -0,0 +1,51 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_init_proxy + +Node is bootstrapped. +Estimated gas: 1407.574 units (will add 100 for safety) +Estimated storage: 312 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000437 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1508 + Storage limit: 332 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000437 + fees(the baker who will include this operation,2) ... +ꜩ0.000437 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ1000 + Script: + { parameter (contract unit) ; + storage unit ; + code { UNPAIR ; + AMOUNT ; + UNIT ; + TRANSFER_TOKENS ; + DIP { NIL operation } ; + CONS ; + PAIR } } + Initial storage: Unit + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 55 bytes + Paid storage size diff: 55 bytes + Consumed gas: 1407.574 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01375 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ1000 + [CONTRACT_HASH] ... +ꜩ1000 + +New contract [CONTRACT_HASH] originated. +Contract memorized as proxy. +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_now.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_now.out new file mode 100644 index 000000000000..deb1788aa2e8 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_now.out @@ -0,0 +1,2 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_now + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_self.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_self.out new file mode 100644 index 000000000000..5c824685ffe2 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_self.out @@ -0,0 +1,2 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_self + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_sender.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_sender.out new file mode 100644 index 000000000000..259ff433b88c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_sender.out @@ -0,0 +1,2 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_sender + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_set_delegate.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_set_delegate.out new file mode 100644 index 000000000000..51c3b807a1ff --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_set_delegate.out @@ -0,0 +1,121 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_set_delegate + +Node is bootstrapped. +Estimated gas: 1406.268 units (will add 100 for safety) +Estimated storage: 308 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000433 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1507 + Storage limit: 328 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000433 + fees(the baker who will include this operation,4) ... +ꜩ0.000433 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ1000 + Script: + { parameter (option key_hash) ; + storage unit ; + code { UNPAIR ; SET_DELEGATE ; DIP { NIL operation } ; CONS ; PAIR } } + Initial storage: Unit + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 51 bytes + Paid storage size diff: 51 bytes + Consumed gas: 1406.268 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01275 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ1000 + [CONTRACT_HASH] ... +ꜩ1000 + +New contract [CONTRACT_HASH] originated. +Contract memorized as set_delegate. +Injected block [BLOCK_HASH] +Injected block [BLOCK_HASH] +none +Node is bootstrapped. +Estimated gas: 3054.215 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000612 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 3155 + Storage limit: 0 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000612 + fees(the baker who will include this operation,4) ... +ꜩ0.000612 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: (Some "[CONTRACT_HASH]") + This transaction was successfully applied + Updated storage: Unit + Storage size: 51 bytes + Consumed gas: 2054.215 + Internal operations: + Delegation: + Contract: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This delegation was successfully applied + Consumed gas: 1000 + +Injected block [BLOCK_HASH] +[CONTRACT_HASH] (known as bootstrap5) +Node is bootstrapped. +Estimated gas: 2202.442 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000486 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 2303 + Storage limit: 0 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000486 + fees(the baker who will include this operation,4) ... +ꜩ0.000486 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: None + This transaction was successfully applied + Updated storage: Unit + Storage size: 51 bytes + Consumed gas: 1202.442 + Internal operations: + Delegation: + Contract: [CONTRACT_HASH] + To: nobody + This delegation was successfully applied + Consumed gas: 1000 + +Injected block [BLOCK_HASH] +none diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice.out new file mode 100644 index 000000000000..3f3528b22652 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice.out @@ -0,0 +1,85 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_slice + +Node is bootstrapped. +Estimated gas: 1517.475 units (will add 100 for safety) +Estimated storage: 835 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000992 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1618 + Storage limit: 855 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000992 + fees(the baker who will include this operation,3) ... +ꜩ0.000992 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ1000 + Script: + { parameter (pair bytes signature) ; + storage key ; + code { DUP ; + CAAR ; + DUP ; + SIZE ; + PUSH nat 128 ; + SWAP ; + SUB ; + ISNAT ; + ASSERT_SOME ; + PUSH nat 128 ; + SLICE @payload ; + ASSERT_SOME ; + DUP ; + DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 0 ; SLICE ; ASSERT_SOME } ; + SHA256 ; + ASSERT_CMPEQ } ; + DUP ; + DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 32 ; SLICE ; ASSERT_SOME } ; + BLAKE2B ; + ASSERT_CMPEQ } ; + DUP ; + DIP { DIP { DUP ; CAAR ; PUSH nat 64 ; PUSH nat 64 ; SLICE ; ASSERT_SOME } ; + SHA512 ; + ASSERT_CMPEQ } ; + DIP { DUP ; CDR ; DIP { DUP ; CADR } } ; + SWAP ; + DIP { SWAP } ; + CHECK_SIGNATURE ; + ASSERT ; + CDR ; + DUP ; + HASH_KEY ; + IMPLICIT_ACCOUNT ; + BALANCE ; + UNIT ; + TRANSFER_TOKENS ; + NIL operation ; + SWAP ; + CONS ; + PAIR } } + Initial storage: + "[OPERATION_HASH]na" + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 578 bytes + Paid storage size diff: 578 bytes + Consumed gas: 1517.475 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.1445 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ1000 + [CONTRACT_HASH] ... +ꜩ1000 + +New contract [CONTRACT_HASH] originated. +Contract memorized as slices. +Injected block [BLOCK_HASH] diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0 \"spsig1PPUFZucuAQybs5wsqs.818025e860.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0 \"spsig1PPUFZucuAQybs5wsqs.818025e860.out" new file mode 100644 index 000000000000..9d8d2ae9bf48 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0 \"spsig1PPUFZucuAQybs5wsqs.818025e860.out" @@ -0,0 +1,66 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0 "spsig1PPUFZucuAQybs5wsqsNQ68QNgFaBnVKMFaoZZfi1BtNnuCAWnmL9wVy5HfHkR6AeodjVGxpBVVSYcJKyMURn6K1yknYLm")] + +Node is bootstrapped. +This simulation failed: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1040000 + Storage limit: 60000 bytes + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: (Pair 0xe009ab79e8b84ef0 + "sp[SIGNATURE]m") + This operation FAILED. + +Runtime error in contract [CONTRACT_HASH]: + 01: { parameter (pair bytes signature) ; + 02: storage key ; + 03: code { DUP ; + 04: CAAR ; + 05: DUP ; + 06: SIZE ; + 07: PUSH nat 128 ; + 08: SWAP ; + 09: SUB ; + 10: ISNAT ; + 11: ASSERT_SOME ; + 12: PUSH nat 128 ; + 13: SLICE @payload ; + 14: ASSERT_SOME ; + 15: DUP ; + 16: DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 0 ; SLICE ; ASSERT_SOME } ; + 17: SHA256 ; + 18: ASSERT_CMPEQ } ; + 19: DUP ; + 20: DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 32 ; SLICE ; ASSERT_SOME } ; + 21: BLAKE2B ; + 22: ASSERT_CMPEQ } ; + 23: DUP ; + 24: DIP { DIP { DUP ; CAAR ; PUSH nat 64 ; PUSH nat 64 ; SLICE ; ASSERT_SOME } ; + 25: SHA512 ; + 26: ASSERT_CMPEQ } ; + 27: DIP { DUP ; CDR ; DIP { DUP ; CADR } } ; + 28: SWAP ; + 29: DIP { SWAP } ; + 30: CHECK_SIGNATURE ; + 31: ASSERT ; + 32: CDR ; + 33: DUP ; + 34: HASH_KEY ; + 35: IMPLICIT_ACCOUNT ; + 36: BALANCE ; + 37: UNIT ; + 38: TRANSFER_TOKENS ; + 39: NIL operation ; + 40: SWAP ; + 41: CONS ; + 42: PAIR } } +At line 11 characters 9 to 20, +script reached FAILWITH instruction +with Unit +Fatal error: + transfer simulation failed diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75.2d6806d54e.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75.2d6806d54e.out new file mode 100644 index 000000000000..743b283ca0ed --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75.2d6806d54e.out @@ -0,0 +1,66 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75ba63500a5694fb2ffe174acc2deaad01ccb7259342437f05e1987949f0ad82e9f32e9a0b79cb252d7f7b8236ad728893f4e7150742eefdbeda254970f9fcd92c6228c178e1a923e5600758eb83f2a05edd0be7625657901f2ba81eaf145d003dbef78e33f43a32a3788bdf0501000000085341554349535345 "spsig1PPUFZucuAQybs5wsqsNQ68QNgFaBnVKMFaoZZfi1BtNnuCAWnmL9wVy5HfHkR6AeodjVGxpBVVSYcJKyMURn6K1yknYLm")] + +Node is bootstrapped. +This simulation failed: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1040000 + Storage limit: 60000 bytes + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: (Pair [OPERATION_HASH][OPERATION_HASH][OPERATION_HASH][OPERATION_HASH][OPERATION_HASH]000085341554349535345 + "sp[SIGNATURE]m") + This operation FAILED. + +Runtime error in contract [CONTRACT_HASH]: + 01: { parameter (pair bytes signature) ; + 02: storage key ; + 03: code { DUP ; + 04: CAAR ; + 05: DUP ; + 06: SIZE ; + 07: PUSH nat 128 ; + 08: SWAP ; + 09: SUB ; + 10: ISNAT ; + 11: ASSERT_SOME ; + 12: PUSH nat 128 ; + 13: SLICE @payload ; + 14: ASSERT_SOME ; + 15: DUP ; + 16: DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 0 ; SLICE ; ASSERT_SOME } ; + 17: SHA256 ; + 18: ASSERT_CMPEQ } ; + 19: DUP ; + 20: DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 32 ; SLICE ; ASSERT_SOME } ; + 21: BLAKE2B ; + 22: ASSERT_CMPEQ } ; + 23: DUP ; + 24: DIP { DIP { DUP ; CAAR ; PUSH nat 64 ; PUSH nat 64 ; SLICE ; ASSERT_SOME } ; + 25: SHA512 ; + 26: ASSERT_CMPEQ } ; + 27: DIP { DUP ; CDR ; DIP { DUP ; CADR } } ; + 28: SWAP ; + 29: DIP { SWAP } ; + 30: CHECK_SIGNATURE ; + 31: ASSERT ; + 32: CDR ; + 33: DUP ; + 34: HASH_KEY ; + 35: IMPLICIT_ACCOUNT ; + 36: BALANCE ; + 37: UNIT ; + 38: TRANSFER_TOKENS ; + 39: NIL operation ; + 40: SWAP ; + 41: CONS ; + 42: PAIR } } +At line 22 characters 15 to 27, +script reached FAILWITH instruction +with Unit +Fatal error: + transfer simulation failed diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75.378d03ae2d.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75.378d03ae2d.out new file mode 100644 index 000000000000..d8cb0f36a1f5 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75.378d03ae2d.out @@ -0,0 +1,66 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75ba63500a5694fb2ffe174acc2de22d01ccb7259342437f05e1987949f0ad82e9f32e9a0b79cb252d7f7b8236ad728893f4e7150733eefdbeda254970f9fcd92c6228c178e1a923e5600758eb83f2a05edd0be7625657901f2ba81eaf145d003dbef78e33f43a32a3788bdf0501000000085341554349535345 "spsig1PPUFZucuAQybs5wsqsNQ68QNgFaBnVKMFaoZZfi1BtNnuCAWnmL9wVy5HfHkR6AeodjVGxpBVVSYcJKyMURn6K1yknYLm")] + +Node is bootstrapped. +This simulation failed: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1040000 + Storage limit: 60000 bytes + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: (Pair [OPERATION_HASH][OPERATION_HASH][OPERATION_HASH][OPERATION_HASH][OPERATION_HASH]000085341554349535345 + "sp[SIGNATURE]m") + This operation FAILED. + +Runtime error in contract [CONTRACT_HASH]: + 01: { parameter (pair bytes signature) ; + 02: storage key ; + 03: code { DUP ; + 04: CAAR ; + 05: DUP ; + 06: SIZE ; + 07: PUSH nat 128 ; + 08: SWAP ; + 09: SUB ; + 10: ISNAT ; + 11: ASSERT_SOME ; + 12: PUSH nat 128 ; + 13: SLICE @payload ; + 14: ASSERT_SOME ; + 15: DUP ; + 16: DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 0 ; SLICE ; ASSERT_SOME } ; + 17: SHA256 ; + 18: ASSERT_CMPEQ } ; + 19: DUP ; + 20: DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 32 ; SLICE ; ASSERT_SOME } ; + 21: BLAKE2B ; + 22: ASSERT_CMPEQ } ; + 23: DUP ; + 24: DIP { DIP { DUP ; CAAR ; PUSH nat 64 ; PUSH nat 64 ; SLICE ; ASSERT_SOME } ; + 25: SHA512 ; + 26: ASSERT_CMPEQ } ; + 27: DIP { DUP ; CDR ; DIP { DUP ; CADR } } ; + 28: SWAP ; + 29: DIP { SWAP } ; + 30: CHECK_SIGNATURE ; + 31: ASSERT ; + 32: CDR ; + 33: DUP ; + 34: HASH_KEY ; + 35: IMPLICIT_ACCOUNT ; + 36: BALANCE ; + 37: UNIT ; + 38: TRANSFER_TOKENS ; + 39: NIL operation ; + 40: SWAP ; + 41: CONS ; + 42: PAIR } } +At line 26 characters 15 to 27, +script reached FAILWITH instruction +with Unit +Fatal error: + transfer simulation failed diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75.57fdc7ad1c.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75.57fdc7ad1c.out new file mode 100644 index 000000000000..296b34bf8a32 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75.57fdc7ad1c.out @@ -0,0 +1,66 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_slice_fails[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75ba63500a5694fb2ffe174acc2de22d01ccb7259342437f05e1987949f0ad82e9f32e9a0b79cb252d7f7b8236ad728893f4e7150742eefdbeda254970f9fcd92c6228c178e1a923e5600758eb83f2a05edd0be7625657901f2ba81eaf145d003dbef78e33f43a32a3788bdf0501000000085341554349535345 "p2sigsceCzcDw2AeYDzUonj4JT341WC9Px4wdhHBxbZcG1FhfqFVuG7f2fGCzrEHSAZgrsrQWpxduDPk9qZRgrpzwJnSHC3gZJ")] + +Node is bootstrapped. +This simulation failed: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1040000 + Storage limit: 60000 bytes + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: (Pair [OPERATION_HASH][OPERATION_HASH][OPERATION_HASH][OPERATION_HASH][OPERATION_HASH]000085341554349535345 + "p2[SIGNATURE]") + This operation FAILED. + +Runtime error in contract [CONTRACT_HASH]: + 01: { parameter (pair bytes signature) ; + 02: storage key ; + 03: code { DUP ; + 04: CAAR ; + 05: DUP ; + 06: SIZE ; + 07: PUSH nat 128 ; + 08: SWAP ; + 09: SUB ; + 10: ISNAT ; + 11: ASSERT_SOME ; + 12: PUSH nat 128 ; + 13: SLICE @payload ; + 14: ASSERT_SOME ; + 15: DUP ; + 16: DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 0 ; SLICE ; ASSERT_SOME } ; + 17: SHA256 ; + 18: ASSERT_CMPEQ } ; + 19: DUP ; + 20: DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 32 ; SLICE ; ASSERT_SOME } ; + 21: BLAKE2B ; + 22: ASSERT_CMPEQ } ; + 23: DUP ; + 24: DIP { DIP { DUP ; CAAR ; PUSH nat 64 ; PUSH nat 64 ; SLICE ; ASSERT_SOME } ; + 25: SHA512 ; + 26: ASSERT_CMPEQ } ; + 27: DIP { DUP ; CDR ; DIP { DUP ; CADR } } ; + 28: SWAP ; + 29: DIP { SWAP } ; + 30: CHECK_SIGNATURE ; + 31: ASSERT ; + 32: CDR ; + 33: DUP ; + 34: HASH_KEY ; + 35: IMPLICIT_ACCOUNT ; + 36: BALANCE ; + 37: UNIT ; + 38: TRANSFER_TOKENS ; + 39: NIL operation ; + 40: SWAP ; + 41: CONS ; + 42: PAIR } } +At line 31 characters 9 to 15, +script reached FAILWITH instruction +with Unit +Fatal error: + transfer simulation failed diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xeaa9ab79e8b84ef0e55c43a9a857214d8761e67b75.c583c796bf.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xeaa9ab79e8b84ef0e55c43a9a857214d8761e67b75.c583c796bf.out new file mode 100644 index 000000000000..81af73861792 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_fails[(Pair 0xeaa9ab79e8b84ef0e55c43a9a857214d8761e67b75.c583c796bf.out @@ -0,0 +1,66 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_slice_fails[(Pair 0xeaa9ab79e8b84ef0e55c43a9a857214d8761e67b75ba63500a5694fb2ffe174acc2de22d01ccb7259342437f05e1987949f0ad82e9f32e9a0b79cb252d7f7b8236ad728893f4e7150742eefdbeda254970f9fcd92c6228c178e1a923e5600758eb83f2a05edd0be7625657901f2ba81eaf145d003dbef78e33f43a32a3788bdf0501000000085341554349535345 "spsig1PPUFZucuAQybs5wsqsNQ68QNgFaBnVKMFaoZZfi1BtNnuCAWnmL9wVy5HfHkR6AeodjVGxpBVVSYcJKyMURn6K1yknYLm")] + +Node is bootstrapped. +This simulation failed: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1040000 + Storage limit: 60000 bytes + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: (Pair [OPERATION_HASH][OPERATION_HASH][OPERATION_HASH][OPERATION_HASH][OPERATION_HASH]000085341554349535345 + "sp[SIGNATURE]m") + This operation FAILED. + +Runtime error in contract [CONTRACT_HASH]: + 01: { parameter (pair bytes signature) ; + 02: storage key ; + 03: code { DUP ; + 04: CAAR ; + 05: DUP ; + 06: SIZE ; + 07: PUSH nat 128 ; + 08: SWAP ; + 09: SUB ; + 10: ISNAT ; + 11: ASSERT_SOME ; + 12: PUSH nat 128 ; + 13: SLICE @payload ; + 14: ASSERT_SOME ; + 15: DUP ; + 16: DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 0 ; SLICE ; ASSERT_SOME } ; + 17: SHA256 ; + 18: ASSERT_CMPEQ } ; + 19: DUP ; + 20: DIP { DIP { DUP ; CAAR ; PUSH nat 32 ; PUSH nat 32 ; SLICE ; ASSERT_SOME } ; + 21: BLAKE2B ; + 22: ASSERT_CMPEQ } ; + 23: DUP ; + 24: DIP { DIP { DUP ; CAAR ; PUSH nat 64 ; PUSH nat 64 ; SLICE ; ASSERT_SOME } ; + 25: SHA512 ; + 26: ASSERT_CMPEQ } ; + 27: DIP { DUP ; CDR ; DIP { DUP ; CADR } } ; + 28: SWAP ; + 29: DIP { SWAP } ; + 30: CHECK_SIGNATURE ; + 31: ASSERT ; + 32: CDR ; + 33: DUP ; + 34: HASH_KEY ; + 35: IMPLICIT_ACCOUNT ; + 36: BALANCE ; + 37: UNIT ; + 38: TRANSFER_TOKENS ; + 39: NIL operation ; + 40: SWAP ; + 41: CONS ; + 42: PAIR } } +At line 18 characters 15 to 27, +script reached FAILWITH instruction +with Unit +Fatal error: + transfer simulation failed diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_success[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b.7da5c9014e.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_success[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b.7da5c9014e.out new file mode 100644 index 000000000000..f2b286c1aff7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_slice_success[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b.7da5c9014e.out @@ -0,0 +1,45 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_slice_success[(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75ba63500a5694fb2ffe174acc2de22d01ccb7259342437f05e1987949f0ad82e9f32e9a0b79cb252d7f7b8236ad728893f4e7150742eefdbeda254970f9fcd92c6228c178e1a923e5600758eb83f2a05edd0be7625657901f2ba81eaf145d003dbef78e33f43a32a3788bdf0501000000085341554349535345 "spsig1PPUFZucuAQybs5wsqsNQ68QNgFaBnVKMFaoZZfi1BtNnuCAWnmL9wVy5HfHkR6AeodjVGxpBVVSYcJKyMURn6K1yknYLm")] + +Node is bootstrapped. +Estimated gas: 3878.785 units (will add 100 for safety) +Estimated storage: 257 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000905 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 3979 + Storage limit: 277 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000905 + fees(the baker who will include this operation,3) ... +ꜩ0.000905 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: (Pair [OPERATION_HASH][OPERATION_HASH][OPERATION_HASH][OPERATION_HASH][OPERATION_HASH]000085341554349535345 + "sp[SIGNATURE]m") + This transaction was successfully applied + Updated storage: + [OPERATION_HASH]48f709699019725ba + Storage size: 578 bytes + Consumed gas: 2458.785 + Internal operations: + Transaction: + Amount: ꜩ1000 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Consumed gas: 1420 + Balance updates: + [CONTRACT_HASH] ... -ꜩ1000 + [CONTRACT_HASH] ... +ꜩ1000 + [CONTRACT_HASH] ... -ꜩ0.06425 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_source.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_source.out new file mode 100644 index 000000000000..7a20a43691bb --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_source.out @@ -0,0 +1,117 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_source + +Node is bootstrapped. +Estimated gas: 1468.257 units (will add 100 for safety) +Estimated storage: 322 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000467 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1569 + Storage limit: 342 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000467 + fees(the baker who will include this operation,2) ... +ꜩ0.000467 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ1000 + Script: + { parameter unit ; + storage address ; + code { DROP ; SOURCE ; NIL operation ; PAIR } } + Initial storage: "[CONTRACT_HASH]" + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 65 bytes + Paid storage size diff: 65 bytes + Consumed gas: 1468.257 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01625 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ1000 + [CONTRACT_HASH] ... +ꜩ1000 + +New contract [CONTRACT_HASH] originated. +Contract memorized as source. +Injected block [BLOCK_HASH] +Node is bootstrapped. +Estimated gas: 2113.422 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.00047 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 2214 + Storage limit: 0 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.00047 + fees(the baker who will include this operation,2) ... +ꜩ0.00047 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Updated storage: 0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c + Storage size: 65 bytes + Consumed gas: 2113.422 + +Injected block [BLOCK_HASH] +"[CONTRACT_HASH]" +[CONTRACT_HASH] + +Node is bootstrapped. +Estimated gas: 3740.283 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000679 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 3841 + Storage limit: 0 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000679 + fees(the baker who will include this operation,2) ... +ꜩ0.000679 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: "[CONTRACT_HASH]" + This transaction was successfully applied + Updated storage: Unit + Storage size: 55 bytes + Consumed gas: 2528.278 + Internal operations: + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Updated storage: 0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c + Storage size: 65 bytes + Consumed gas: 1212.005 + +Injected block [BLOCK_HASH] +"[CONTRACT_HASH]" diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_split_bytes.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_split_bytes.out new file mode 100644 index 000000000000..4cb3a4e2113e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_split_bytes.out @@ -0,0 +1,135 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_split_bytes + +Node is bootstrapped. +Estimated gas: 1438.304 units (will add 100 for safety) +Estimated storage: 511 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000639 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1539 + Storage limit: 531 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000639 + fees(the baker who will include this operation,3) ... +ꜩ0.000639 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ1000 + Script: + { parameter bytes ; + storage (list bytes) ; + code { UNPAIR ; + DIP { NIL bytes ; SWAP ; ITER { CONS } } ; + DUP ; + SIZE ; + PUSH nat 0 ; + CMPNEQ ; + DIP { PUSH @index nat 0 } ; + LOOP { PAIR ; + DUP ; + DIP { UNPAIR ; DIP { PUSH nat 1 } ; SLICE ; ASSERT_SOME ; CONS @storage } ; + UNPAIR ; + PUSH nat 1 ; + ADD @index ; + DUP ; + DIP { DIP { DUP } ; SWAP ; SIZE ; CMPNEQ } ; + SWAP } ; + DROP ; + DROP ; + NIL bytes ; + SWAP ; + ITER { CONS } ; + NIL operation ; + PAIR } } + Initial storage: {} + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 254 bytes + Paid storage size diff: 254 bytes + Consumed gas: 1438.304 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0635 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ1000 + [CONTRACT_HASH] ... +ꜩ1000 + +New contract [CONTRACT_HASH] originated. +Contract memorized as split_bytes. +Injected block [BLOCK_HASH] +Node is bootstrapped. +Estimated gas: 2093.755 units (will add 100 for safety) +Estimated storage: 18 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000481 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 2194 + Storage limit: 38 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000481 + fees(the baker who will include this operation,4) ... +ꜩ0.000481 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: 0xaabbcc + This transaction was successfully applied + Updated storage: { 0xaa ; 0xbb ; 0xcc } + Storage size: 272 bytes + Paid storage size diff: 18 bytes + Consumed gas: 2093.755 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0045 + +Injected block [BLOCK_HASH] +{ 0xaa ; 0xbb ; 0xcc } +Node is bootstrapped. +Estimated gas: 1206.614 units (will add 100 for safety) +Estimated storage: 18 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000392 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1307 + Storage limit: 38 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000392 + fees(the baker who will include this operation,4) ... +ꜩ0.000392 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: 0xddeeff + This transaction was successfully applied + Updated storage: { 0xaa ; 0xbb ; 0xcc ; 0xdd ; 0xee ; 0xff } + Storage size: 290 bytes + Paid storage size diff: 18 bytes + Consumed gas: 1206.614 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0045 + +Injected block [BLOCK_HASH] +{ 0xaa ; 0xbb ; 0xcc ; 0xdd ; 0xee ; 0xff } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_split_string.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_split_string.out new file mode 100644 index 000000000000..697a4f21dc70 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_split_string.out @@ -0,0 +1,135 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_split_string + +Node is bootstrapped. +Estimated gas: 1438.304 units (will add 100 for safety) +Estimated storage: 511 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000639 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1539 + Storage limit: 531 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000639 + fees(the baker who will include this operation,3) ... +ꜩ0.000639 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ1000 + Script: + { parameter string ; + storage (list string) ; + code { UNPAIR ; + DIP { NIL string ; SWAP ; ITER { CONS } } ; + DUP ; + SIZE ; + PUSH nat 0 ; + CMPNEQ ; + DIP { PUSH @index nat 0 } ; + LOOP { PAIR ; + DUP ; + DIP { UNPAIR ; DIP { PUSH nat 1 } ; SLICE ; ASSERT_SOME ; CONS @storage } ; + UNPAIR ; + PUSH nat 1 ; + ADD @index ; + DUP ; + DIP { DIP { DUP } ; SWAP ; SIZE ; CMPNEQ } ; + SWAP } ; + DROP ; + DROP ; + NIL string ; + SWAP ; + ITER { CONS } ; + NIL operation ; + PAIR } } + Initial storage: {} + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 254 bytes + Paid storage size diff: 254 bytes + Consumed gas: 1438.304 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0635 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ1000 + [CONTRACT_HASH] ... +ꜩ1000 + +New contract [CONTRACT_HASH] originated. +Contract memorized as split_string. +Injected block [BLOCK_HASH] +Node is bootstrapped. +Estimated gas: 2093.742 units (will add 100 for safety) +Estimated storage: 18 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000481 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 2194 + Storage limit: 38 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000481 + fees(the baker who will include this operation,3) ... +ꜩ0.000481 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: "abc" + This transaction was successfully applied + Updated storage: { "a" ; "b" ; "c" } + Storage size: 272 bytes + Paid storage size diff: 18 bytes + Consumed gas: 2093.742 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0045 + +Injected block [BLOCK_HASH] +{ "a" ; "b" ; "c" } +Node is bootstrapped. +Estimated gas: 1206.601 units (will add 100 for safety) +Estimated storage: 18 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000392 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1307 + Storage limit: 38 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000392 + fees(the baker who will include this operation,3) ... +ꜩ0.000392 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: "def" + This transaction was successfully applied + Updated storage: { "a" ; "b" ; "c" ; "d" ; "e" ; "f" } + Storage size: 290 bytes + Paid storage size diff: 18 bytes + Consumed gas: 1206.601 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0045 + +Injected block [BLOCK_HASH] +{ "a" ; "b" ; "c" ; "d" ; "e" ; "f" } diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_store_input.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_store_input.out new file mode 100644 index 000000000000..cc04a46a314a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_store_input.out @@ -0,0 +1,180 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_store_input + +Node is bootstrapped. +Estimated gas: 1420 units (will add 100 for safety) +Estimated storage: 257 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000405 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1520 + Storage limit: 277 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000405 + fees(the baker who will include this operation,0) ... +ꜩ0.000405 + Transaction: + Amount: ꜩ1000 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Consumed gas: 1420 + Balance updates: + [CONTRACT_HASH] ... -ꜩ1000 + [CONTRACT_HASH] ... +ꜩ1000 + [CONTRACT_HASH] ... -ꜩ0.06425 + +Injected block [BLOCK_HASH] +Node is bootstrapped. +Estimated gas: 1420 units (will add 100 for safety) +Estimated storage: 257 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000405 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1520 + Storage limit: 277 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000405 + fees(the baker who will include this operation,0) ... +ꜩ0.000405 + Transaction: + Amount: ꜩ2000 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Consumed gas: 1420 + Balance updates: + [CONTRACT_HASH] ... -ꜩ2000 + [CONTRACT_HASH] ... +ꜩ2000 + [CONTRACT_HASH] ... -ꜩ0.06425 + +Injected block [BLOCK_HASH] +1000 ꜩ +2000 ꜩ +Node is bootstrapped. +Estimated gas: 1403.956 units (will add 100 for safety) +Estimated storage: 298 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000422 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1504 + Storage limit: 318 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000422 + fees(the baker who will include this operation,0) ... +ꜩ0.000422 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ100 + Script: + { parameter string ; + storage string ; + code { CAR ; NIL operation ; PAIR } } + Initial storage: "" + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 41 bytes + Paid storage size diff: 41 bytes + Consumed gas: 1403.956 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01025 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ100 + [CONTRACT_HASH] ... +ꜩ100 + +New contract [CONTRACT_HASH] originated. +Contract memorized as store_input. +Injected block [BLOCK_HASH] +Node is bootstrapped. +Estimated gas: 2048.288 units (will add 100 for safety) +Estimated storage: 7 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000483 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 2149 + Storage limit: 27 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000483 + fees(the baker who will include this operation,0) ... +ꜩ0.000483 + Transaction: + Amount: ꜩ100 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: "abcdefg" + This transaction was successfully applied + Updated storage: "abcdefg" + Storage size: 48 bytes + Paid storage size diff: 7 bytes + Consumed gas: 2048.288 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.00175 + [CONTRACT_HASH] ... -ꜩ100 + [CONTRACT_HASH] ... +ꜩ100 + +Injected block [BLOCK_HASH] +200 ꜩ +"abcdefg" +Node is bootstrapped. +Estimated gas: 1202.368 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000395 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1303 + Storage limit: 0 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000395 + fees(the baker who will include this operation,0) ... +ꜩ0.000395 + Transaction: + Amount: ꜩ100 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: "xyz" + This transaction was successfully applied + Updated storage: "xyz" + Storage size: 44 bytes + Consumed gas: 1202.368 + Balance updates: + [CONTRACT_HASH] ... -ꜩ100 + [CONTRACT_HASH] ... +ꜩ100 + +Injected block [BLOCK_HASH] +"xyz" diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_trace_origination[compare_big_type.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_trace_origination[compare_big_type.tz].out new file mode 100644 index 000000000000..a693cef9f9ed --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_trace_origination[compare_big_type.tz].out @@ -0,0 +1,91 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_trace_origination[compare_big_type.tz] + +Node is bootstrapped. +Estimated gas: 2860.815 units (will add 100 for safety) +Estimated storage: 385 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000656 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 2961 + Storage limit: 405 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000656 + fees(the baker who will include this operation,4) ... +ꜩ0.000656 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ1000 + Script: + { parameter unit ; + storage unit ; + code { DROP ; + PUSH nat 0 ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + DUP ; + COMPARE ; + DROP ; + DUP ; + DUP ; + COMPARE ; + DROP ; + DUP ; + DUP ; + COMPARE ; + DROP ; + DUP ; + DUP ; + COMPARE ; + DROP ; + DUP ; + DUP ; + COMPARE ; + DROP ; + DUP ; + DUP ; + COMPARE ; + DROP ; + DROP ; + UNIT ; + NIL operation ; + PAIR } } + Initial storage: Unit + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 128 bytes + Paid storage size diff: 128 bytes + Consumed gas: 2860.815 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.032 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ1000 + [CONTRACT_HASH] ... +ꜩ1000 + +New contract [CONTRACT_HASH] originated. +Contract memorized as compare_big_type. +Injected block [BLOCK_HASH] +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_trace_origination[compare_big_type2.tz].out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_trace_origination[compare_big_type2.tz].out new file mode 100644 index 000000000000..38cd40199bfd --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_trace_origination[compare_big_type2.tz].out @@ -0,0 +1,95 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_trace_origination[compare_big_type2.tz] + +Node is bootstrapped. +Estimated gas: 3093.226 units (will add 100 for safety) +Estimated storage: 393 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000687 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 3194 + Storage limit: 413 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000687 + fees(the baker who will include this operation,5) ... +ꜩ0.000687 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ1000 + Script: + { parameter unit ; + storage unit ; + code { DROP ; + PUSH nat 0 ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + PAIR ; + DUP ; + DUP ; + COMPARE ; + DROP ; + DUP ; + DUP ; + COMPARE ; + DROP ; + DUP ; + DUP ; + COMPARE ; + DROP ; + DUP ; + DUP ; + COMPARE ; + DROP ; + DUP ; + DUP ; + COMPARE ; + DROP ; + DUP ; + DUP ; + COMPARE ; + DROP ; + DUP ; + DUP ; + COMPARE ; + DROP ; + DROP ; + UNIT ; + NIL operation ; + PAIR } } + Initial storage: Unit + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 136 bytes + Paid storage size diff: 136 bytes + Consumed gas: 3093.226 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.034 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ1000 + [CONTRACT_HASH] ... +ꜩ1000 + +New contract [CONTRACT_HASH] originated. +Contract memorized as compare_big_type2. +Injected block [BLOCK_HASH] +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_transfer_amount.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_transfer_amount.out new file mode 100644 index 000000000000..08bbf1eff22a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_transfer_amount.out @@ -0,0 +1,80 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_transfer_amount + +Node is bootstrapped. +Estimated gas: 1404.537 units (will add 100 for safety) +Estimated storage: 297 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000421 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1505 + Storage limit: 317 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000421 + fees(the baker who will include this operation,0) ... +ꜩ0.000421 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ100 + Script: + { parameter unit ; + storage mutez ; + code { DROP ; AMOUNT ; NIL operation ; PAIR } } + Initial storage: 0 + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 40 bytes + Paid storage size diff: 40 bytes + Consumed gas: 1404.537 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ100 + [CONTRACT_HASH] ... +ꜩ100 + +New contract [CONTRACT_HASH] originated. +Contract memorized as transfer_amount. +Injected block [BLOCK_HASH] +Node is bootstrapped. +Estimated gas: 2048.768 units (will add 100 for safety) +Estimated storage: 4 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000467 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 2149 + Storage limit: 24 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000467 + fees(the baker who will include this operation,0) ... +ꜩ0.000467 + Transaction: + Amount: ꜩ500 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Updated storage: 500000000 + Storage size: 44 bytes + Paid storage size diff: 4 bytes + Consumed gas: 2048.768 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.001 + [CONTRACT_HASH] ... -ꜩ500 + [CONTRACT_HASH] ... +ꜩ500 + +Injected block [BLOCK_HASH] +500000000 diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_transfer_tokens.out b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_transfer_tokens.out new file mode 100644 index 000000000000..90c251b32b6a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_onchain_opcodes.TestContractOnchainOpcodes::test_transfer_tokens.out @@ -0,0 +1,232 @@ +tests_011/test_contract_onchain_opcodes.py::TestContractOnchainOpcodes::test_transfer_tokens + +Node is bootstrapped. +Estimated gas: 1403.930 units (will add 100 for safety) +Estimated storage: 295 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000419 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1504 + Storage limit: 315 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000419 + fees(the baker who will include this operation,1) ... +ꜩ0.000419 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ100 + Script: + { parameter unit ; storage unit ; code { CDR ; NIL operation ; PAIR } } + Initial storage: Unit + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 38 bytes + Paid storage size diff: 38 bytes + Consumed gas: 1403.930 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0095 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ100 + [CONTRACT_HASH] ... +ꜩ100 + +New contract [CONTRACT_HASH] originated. +Contract memorized as test_transfer_account1. +Injected block [BLOCK_HASH] +Node is bootstrapped. +Estimated gas: 1403.930 units (will add 100 for safety) +Estimated storage: 295 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000419 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1504 + Storage limit: 315 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000419 + fees(the baker who will include this operation,1) ... +ꜩ0.000419 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ20 + Script: + { parameter unit ; storage unit ; code { CDR ; NIL operation ; PAIR } } + Initial storage: Unit + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 38 bytes + Paid storage size diff: 38 bytes + Consumed gas: 1403.930 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0095 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ20 + [CONTRACT_HASH] ... +ꜩ20 + +New contract [CONTRACT_HASH] originated. +Contract memorized as test_transfer_account2. +Injected block [BLOCK_HASH] +Node is bootstrapped. +Estimated gas: 1409.219 units (will add 100 for safety) +Estimated storage: 323 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000448 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1510 + Storage limit: 343 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000448 + fees(the baker who will include this operation,1) ... +ꜩ0.000448 + Origination: + From: [CONTRACT_HASH] + Credit: ꜩ1000 + Script: + { parameter (contract unit) ; + storage unit ; + code { CAR ; + DIP { UNIT } ; + PUSH mutez 100000000 ; + UNIT ; + TRANSFER_TOKENS ; + NIL operation ; + SWAP ; + CONS ; + PAIR } } + Initial storage: Unit + No delegate for this contract + This origination was successfully applied + Originated contracts: + [CONTRACT_HASH] + Storage size: 66 bytes + Paid storage size diff: 66 bytes + Consumed gas: 1409.219 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0165 + [CONTRACT_HASH] ... -ꜩ0.06425 + [CONTRACT_HASH] ... -ꜩ1000 + [CONTRACT_HASH] ... +ꜩ1000 + +New contract [CONTRACT_HASH] originated. +Contract memorized as transfer_tokens. +Injected block [BLOCK_HASH] +100 ꜩ +[CONTRACT_HASH] + +Node is bootstrapped. +Estimated gas: 4578.226 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000765 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 4679 + Storage limit: 0 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000765 + fees(the baker who will include this operation,1) ... +ꜩ0.000765 + Transaction: + Amount: ꜩ100 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: "[CONTRACT_HASH]" + This transaction was successfully applied + Updated storage: Unit + Storage size: 66 bytes + Consumed gas: 2530.272 + Balance updates: + [CONTRACT_HASH] ... -ꜩ100 + [CONTRACT_HASH] ... +ꜩ100 + Internal operations: + Transaction: + Amount: ꜩ100 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Updated storage: Unit + Storage size: 38 bytes + Consumed gas: 2047.954 + Balance updates: + [CONTRACT_HASH] ... -ꜩ100 + [CONTRACT_HASH] ... +ꜩ100 + +Injected block [BLOCK_HASH] +200 ꜩ +[CONTRACT_HASH] + +Node is bootstrapped. +Estimated gas: 3726.189 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.00068 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 3827 + Storage limit: 0 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.00068 + fees(the baker who will include this operation,1) ... +ꜩ0.00068 + Transaction: + Amount: ꜩ100 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Parameter: "[CONTRACT_HASH]" + This transaction was successfully applied + Updated storage: Unit + Storage size: 66 bytes + Consumed gas: 1678.235 + Balance updates: + [CONTRACT_HASH] ... -ꜩ100 + [CONTRACT_HASH] ... +ꜩ100 + Internal operations: + Transaction: + Amount: ꜩ100 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Updated storage: Unit + Storage size: 38 bytes + Consumed gas: 2047.954 + Balance updates: + [CONTRACT_HASH] ... -ꜩ100 + [CONTRACT_HASH] ... +ꜩ100 + +Injected block [BLOCK_HASH] +120 ꜩ diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 4) {})-\"hello\"-(Pa.f6092ac5d6.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 4) {})-\"hello\"-(Pa.f6092ac5d6.out" new file mode 100644 index 000000000000..d0109fdb4736 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 4) {})-\"hello\"-(Pa.f6092ac5d6.out" @@ -0,0 +1,35 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 4) {})-"hello"-(Pair None 4)-big_map_diff10] + +storage + (Pair None 4) +emitted operations + +big_map diff + New map(4) of type (big_map string nat) + Set map(4)["hello"] to 4 +trace + - location: 13 (remaining gas: 1039991.226 units remaining) + [ (Pair "hello" (Some 4) {}) ] + - location: 13 (remaining gas: 1039991.216 units remaining) + [ "hello" @parameter + (Pair (Some 4) {}) @storage ] + - location: 14 (remaining gas: 1039991.201 units remaining) + [ (Pair (Some 4) {}) @storage ] + - location: 16 (remaining gas: 1039991.191 units remaining) + [ (Some 4) + {} ] + - location: 14 (remaining gas: 1039991.161 units remaining) + [ "hello" @parameter + (Some 4) + {} ] + - location: 17 (remaining gas: 1039989.586 units remaining) + [ None + { Elt "hello" 4 } ] + - location: 18 (remaining gas: 1039989.571 units remaining) + [ (Pair None { Elt "hello" 4 }) ] + - location: 19 (remaining gas: 1039989.556 units remaining) + [ {} + (Pair None { Elt "hello" 4 }) ] + - location: 21 (remaining gas: 1039989.541 units remaining) + [ (Pair {} None { Elt "hello" 4 }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 5) { Elt \"hello\" 4.0427752f13.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 5) { Elt \"hello\" 4.0427752f13.out" new file mode 100644 index 000000000000..a21d90a66bc3 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 5) { Elt \"hello\" 4.0427752f13.out" @@ -0,0 +1,35 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 5) { Elt "hello" 4 })-"hello"-(Pair (Some 4) 4)-big_map_diff12] + +storage + (Pair (Some 4) 4) +emitted operations + +big_map diff + New map(4) of type (big_map string nat) + Set map(4)["hello"] to 5 +trace + - location: 13 (remaining gas: 1039989.453 units remaining) + [ (Pair "hello" (Some 5) { Elt "hello" 4 }) ] + - location: 13 (remaining gas: 1039989.443 units remaining) + [ "hello" @parameter + (Pair (Some 5) { Elt "hello" 4 }) @storage ] + - location: 14 (remaining gas: 1039989.428 units remaining) + [ (Pair (Some 5) { Elt "hello" 4 }) @storage ] + - location: 16 (remaining gas: 1039989.418 units remaining) + [ (Some 5) + { Elt "hello" 4 } ] + - location: 14 (remaining gas: 1039989.388 units remaining) + [ "hello" @parameter + (Some 5) + { Elt "hello" 4 } ] + - location: 17 (remaining gas: 1039987.808 units remaining) + [ (Some 4) + { Elt "hello" 5 } ] + - location: 18 (remaining gas: 1039987.793 units remaining) + [ (Pair (Some 4) { Elt "hello" 5 }) ] + - location: 19 (remaining gas: 1039987.778 units remaining) + [ {} + (Pair (Some 4) { Elt "hello" 5 }) ] + - location: 21 (remaining gas: 1039987.763 units remaining) + [ (Pair {} (Some 4) { Elt "hello" 5 }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 5) { Elt \"hello\" 4.0793dc66d5.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 5) { Elt \"hello\" 4.0793dc66d5.out" new file mode 100644 index 000000000000..6e4f85bd90be --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 5) { Elt \"hello\" 4.0793dc66d5.out" @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair (Some 5) { Elt "hello" 4 })-"hi"-(Pair None 4)-big_map_diff13] + +storage + (Pair None 4) +emitted operations + +big_map diff + New map(4) of type (big_map string nat) + Set map(4)["hello"] to 4 + Set map(4)["hi"] to 5 +trace + - location: 13 (remaining gas: 1039989.483 units remaining) + [ (Pair "hi" (Some 5) { Elt "hello" 4 }) ] + - location: 13 (remaining gas: 1039989.473 units remaining) + [ "hi" @parameter + (Pair (Some 5) { Elt "hello" 4 }) @storage ] + - location: 14 (remaining gas: 1039989.458 units remaining) + [ (Pair (Some 5) { Elt "hello" 4 }) @storage ] + - location: 16 (remaining gas: 1039989.448 units remaining) + [ (Some 5) + { Elt "hello" 4 } ] + - location: 14 (remaining gas: 1039989.418 units remaining) + [ "hi" @parameter + (Some 5) + { Elt "hello" 4 } ] + - location: 17 (remaining gas: 1039988.039 units remaining) + [ None + { Elt "hello" 4 ; Elt "hi" 5 } ] + - location: 18 (remaining gas: 1039988.024 units remaining) + [ (Pair None { Elt "hello" 4 ; Elt "hi" 5 }) ] + - location: 19 (remaining gas: 1039988.009 units remaining) + [ {} + (Pair None { Elt "hello" 4 ; Elt "hi" 5 }) ] + - location: 21 (remaining gas: 1039987.994 units remaining) + [ (Pair {} None { Elt "hello" 4 ; Elt "hi" 5 }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt \"1\" 1 ; .df114499b8.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt \"1\" 1 ; .df114499b8.out" new file mode 100644 index 000000000000..e0ced311873c --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt \"1\" 1 ; .df114499b8.out" @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt "1" 1 ; Elt "2" 2 })-"1"-(Pair (Some 1) 4)-big_map_diff14] + +storage + (Pair (Some 1) 4) +emitted operations + +big_map diff + New map(4) of type (big_map string nat) + Set map(4)["2"] to 2 + Unset map(4)["1"] +trace + - location: 13 (remaining gas: 1039988.400 units remaining) + [ (Pair "1" None { Elt "1" 1 ; Elt "2" 2 }) ] + - location: 13 (remaining gas: 1039988.390 units remaining) + [ "1" @parameter + (Pair None { Elt "1" 1 ; Elt "2" 2 }) @storage ] + - location: 14 (remaining gas: 1039988.375 units remaining) + [ (Pair None { Elt "1" 1 ; Elt "2" 2 }) @storage ] + - location: 16 (remaining gas: 1039988.365 units remaining) + [ None + { Elt "1" 1 ; Elt "2" 2 } ] + - location: 14 (remaining gas: 1039988.335 units remaining) + [ "1" @parameter + None + { Elt "1" 1 ; Elt "2" 2 } ] + - location: 17 (remaining gas: 1039987.020 units remaining) + [ (Some 1) + { Elt "2" 2 } ] + - location: 18 (remaining gas: 1039987.005 units remaining) + [ (Pair (Some 1) { Elt "2" 2 }) ] + - location: 19 (remaining gas: 1039986.990 units remaining) + [ {} + (Pair (Some 1) { Elt "2" 2 }) ] + - location: 21 (remaining gas: 1039986.975 units remaining) + [ (Pair {} (Some 1) { Elt "2" 2 }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt \"1\" 1 ; .f9bea98de9.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt \"1\" 1 ; .f9bea98de9.out" new file mode 100644 index 000000000000..7edaf74c5277 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt \"1\" 1 ; .f9bea98de9.out" @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt "1" 1 ; Elt "2" 2 })-"1"-(Pair (Some 1) 4)-big_map_diff15] + +storage + (Pair (Some 1) 4) +emitted operations + +big_map diff + New map(4) of type (big_map string nat) + Set map(4)["2"] to 2 + Unset map(4)["1"] +trace + - location: 13 (remaining gas: 1039988.400 units remaining) + [ (Pair "1" None { Elt "1" 1 ; Elt "2" 2 }) ] + - location: 13 (remaining gas: 1039988.390 units remaining) + [ "1" @parameter + (Pair None { Elt "1" 1 ; Elt "2" 2 }) @storage ] + - location: 14 (remaining gas: 1039988.375 units remaining) + [ (Pair None { Elt "1" 1 ; Elt "2" 2 }) @storage ] + - location: 16 (remaining gas: 1039988.365 units remaining) + [ None + { Elt "1" 1 ; Elt "2" 2 } ] + - location: 14 (remaining gas: 1039988.335 units remaining) + [ "1" @parameter + None + { Elt "1" 1 ; Elt "2" 2 } ] + - location: 17 (remaining gas: 1039987.020 units remaining) + [ (Some 1) + { Elt "2" 2 } ] + - location: 18 (remaining gas: 1039987.005 units remaining) + [ (Pair (Some 1) { Elt "2" 2 }) ] + - location: 19 (remaining gas: 1039986.990 units remaining) + [ {} + (Pair (Some 1) { Elt "2" 2 }) ] + - location: 21 (remaining gas: 1039986.975 units remaining) + [ (Pair {} (Some 1) { Elt "2" 2 }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt \"hello\" 4 })-.1db12cd837.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt \"hello\" 4 })-.1db12cd837.out" new file mode 100644 index 000000000000..fc4f3a9f654f --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt \"hello\" 4 })-.1db12cd837.out" @@ -0,0 +1,35 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None { Elt "hello" 4 })-"hello"-(Pair (Some 4) 4)-big_map_diff11] + +storage + (Pair (Some 4) 4) +emitted operations + +big_map diff + New map(4) of type (big_map string nat) + Unset map(4)["hello"] +trace + - location: 13 (remaining gas: 1039989.553 units remaining) + [ (Pair "hello" None { Elt "hello" 4 }) ] + - location: 13 (remaining gas: 1039989.543 units remaining) + [ "hello" @parameter + (Pair None { Elt "hello" 4 }) @storage ] + - location: 14 (remaining gas: 1039989.528 units remaining) + [ (Pair None { Elt "hello" 4 }) @storage ] + - location: 16 (remaining gas: 1039989.518 units remaining) + [ None + { Elt "hello" 4 } ] + - location: 14 (remaining gas: 1039989.488 units remaining) + [ "hello" @parameter + None + { Elt "hello" 4 } ] + - location: 17 (remaining gas: 1039987.908 units remaining) + [ (Some 4) + {} ] + - location: 18 (remaining gas: 1039987.893 units remaining) + [ (Pair (Some 4) {}) ] + - location: 19 (remaining gas: 1039987.878 units remaining) + [ {} + (Pair (Some 4) {}) ] + - location: 21 (remaining gas: 1039987.863 units remaining) + [ (Pair {} (Some 4) {}) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None {})-\"hello\"-(Pair N.6fc7d0acf2.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None {})-\"hello\"-(Pair N.6fc7d0acf2.out" new file mode 100644 index 000000000000..f8208d5f8858 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None {})-\"hello\"-(Pair N.6fc7d0acf2.out" @@ -0,0 +1,35 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[get_and_update_big_map.tz-(Pair None {})-"hello"-(Pair None 4)-big_map_diff9] + +storage + (Pair None 4) +emitted operations + +big_map diff + New map(4) of type (big_map string nat) + Unset map(4)["hello"] +trace + - location: 13 (remaining gas: 1039991.326 units remaining) + [ (Pair "hello" None {}) ] + - location: 13 (remaining gas: 1039991.316 units remaining) + [ "hello" @parameter + (Pair None {}) @storage ] + - location: 14 (remaining gas: 1039991.301 units remaining) + [ (Pair None {}) @storage ] + - location: 16 (remaining gas: 1039991.291 units remaining) + [ None + {} ] + - location: 14 (remaining gas: 1039991.261 units remaining) + [ "hello" @parameter + None + {} ] + - location: 17 (remaining gas: 1039989.686 units remaining) + [ None + {} ] + - location: 18 (remaining gas: 1039989.671 units remaining) + [ (Pair None {}) ] + - location: 19 (remaining gas: 1039989.656 units remaining) + [ {} + (Pair None {}) ] + - location: 21 (remaining gas: 1039989.641 units remaining) + [ (Pair {} None {}) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"tw.524c5459f8.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"tw.524c5459f8.out" new file mode 100644 index 000000000000..648a7fb2e5c4 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"tw.524c5459f8.out" @@ -0,0 +1,46 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt "1" "one" ; Elt "2" "two" } None)-"1"-(Pair 4 (Some "one"))-big_map_diff2] + +storage + (Pair 4 (Some "one")) +emitted operations + +big_map diff + New map(4) of type (big_map string string) + Set map(4)["2"] to "two" + Set map(4)["1"] to "one" +trace + - location: 12 (remaining gas: 1039985.131 units remaining) + [ (Pair "1" { Elt "1" "one" ; Elt "2" "two" } None) ] + - location: 12 (remaining gas: 1039985.121 units remaining) + [ (Pair "1" { Elt "1" "one" ; Elt "2" "two" } None) + (Pair "1" { Elt "1" "one" ; Elt "2" "two" } None) ] + - location: 13 (remaining gas: 1039985.111 units remaining) + [ "1" @parameter + (Pair "1" { Elt "1" "one" ; Elt "2" "two" } None) ] + - location: 14 (remaining gas: 1039985.096 units remaining) + [ (Pair "1" { Elt "1" "one" ; Elt "2" "two" } None) ] + - location: 17 (remaining gas: 1039985.086 units remaining) + [ (Pair { Elt "1" "one" ; Elt "2" "two" } None) @storage ] + - location: 18 (remaining gas: 1039985.076 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } ] + - location: 19 (remaining gas: 1039985.066 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } + { Elt "1" "one" ; Elt "2" "two" } ] + - location: 14 (remaining gas: 1039985.036 units remaining) + [ "1" @parameter + { Elt "1" "one" ; Elt "2" "two" } + { Elt "1" "one" ; Elt "2" "two" } ] + - location: 20 (remaining gas: 1039983.815 units remaining) + [ (Some "one") + { Elt "1" "one" ; Elt "2" "two" } ] + - location: 21 (remaining gas: 1039983.805 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } + (Some "one") ] + - location: 22 (remaining gas: 1039983.790 units remaining) + [ (Pair { Elt "1" "one" ; Elt "2" "two" } (Some "one")) ] + - location: 23 (remaining gas: 1039983.775 units remaining) + [ {} + (Pair { Elt "1" "one" ; Elt "2" "two" } (Some "one")) ] + - location: 25 (remaining gas: 1039983.760 units remaining) + [ (Pair {} { Elt "1" "one" ; Elt "2" "two" } (Some "one")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt \"hello\" \"hi\" } None)-\"\".33eba403e7.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt \"hello\" \"hi\" } None)-\"\".33eba403e7.out" new file mode 100644 index 000000000000..dd67a2a6a130 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt \"hello\" \"hi\" } None)-\"\".33eba403e7.out" @@ -0,0 +1,45 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt "hello" "hi" } None)-""-(Pair 4 None)-big_map_diff1] + +storage + (Pair 4 None) +emitted operations + +big_map diff + New map(4) of type (big_map string string) + Set map(4)["hello"] to "hi" +trace + - location: 12 (remaining gas: 1039986.388 units remaining) + [ (Pair "" { Elt "hello" "hi" } None) ] + - location: 12 (remaining gas: 1039986.378 units remaining) + [ (Pair "" { Elt "hello" "hi" } None) + (Pair "" { Elt "hello" "hi" } None) ] + - location: 13 (remaining gas: 1039986.368 units remaining) + [ "" @parameter + (Pair "" { Elt "hello" "hi" } None) ] + - location: 14 (remaining gas: 1039986.353 units remaining) + [ (Pair "" { Elt "hello" "hi" } None) ] + - location: 17 (remaining gas: 1039986.343 units remaining) + [ (Pair { Elt "hello" "hi" } None) @storage ] + - location: 18 (remaining gas: 1039986.333 units remaining) + [ { Elt "hello" "hi" } ] + - location: 19 (remaining gas: 1039986.323 units remaining) + [ { Elt "hello" "hi" } + { Elt "hello" "hi" } ] + - location: 14 (remaining gas: 1039986.293 units remaining) + [ "" @parameter + { Elt "hello" "hi" } + { Elt "hello" "hi" } ] + - location: 20 (remaining gas: 1039985.140 units remaining) + [ None + { Elt "hello" "hi" } ] + - location: 21 (remaining gas: 1039985.130 units remaining) + [ { Elt "hello" "hi" } + None ] + - location: 22 (remaining gas: 1039985.115 units remaining) + [ (Pair { Elt "hello" "hi" } None) ] + - location: 23 (remaining gas: 1039985.100 units remaining) + [ {} + (Pair { Elt "hello" "hi" } None) ] + - location: 25 (remaining gas: 1039985.085 units remaining) + [ (Pair {} { Elt "hello" "hi" } None) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt \"hello\" \"hi\" } None)-\"h.a5cd1005c9.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt \"hello\" \"hi\" } None)-\"h.a5cd1005c9.out" new file mode 100644 index 000000000000..49927f140c2f --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt \"hello\" \"hi\" } None)-\"h.a5cd1005c9.out" @@ -0,0 +1,45 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[get_big_map_value.tz-(Pair { Elt "hello" "hi" } None)-"hello"-(Pair 4 (Some "hi"))-big_map_diff0] + +storage + (Pair 4 (Some "hi")) +emitted operations + +big_map diff + New map(4) of type (big_map string string) + Set map(4)["hello"] to "hi" +trace + - location: 12 (remaining gas: 1039986.338 units remaining) + [ (Pair "hello" { Elt "hello" "hi" } None) ] + - location: 12 (remaining gas: 1039986.328 units remaining) + [ (Pair "hello" { Elt "hello" "hi" } None) + (Pair "hello" { Elt "hello" "hi" } None) ] + - location: 13 (remaining gas: 1039986.318 units remaining) + [ "hello" @parameter + (Pair "hello" { Elt "hello" "hi" } None) ] + - location: 14 (remaining gas: 1039986.303 units remaining) + [ (Pair "hello" { Elt "hello" "hi" } None) ] + - location: 17 (remaining gas: 1039986.293 units remaining) + [ (Pair { Elt "hello" "hi" } None) @storage ] + - location: 18 (remaining gas: 1039986.283 units remaining) + [ { Elt "hello" "hi" } ] + - location: 19 (remaining gas: 1039986.273 units remaining) + [ { Elt "hello" "hi" } + { Elt "hello" "hi" } ] + - location: 14 (remaining gas: 1039986.243 units remaining) + [ "hello" @parameter + { Elt "hello" "hi" } + { Elt "hello" "hi" } ] + - location: 20 (remaining gas: 1039984.754 units remaining) + [ (Some "hi") + { Elt "hello" "hi" } ] + - location: 21 (remaining gas: 1039984.744 units remaining) + [ { Elt "hello" "hi" } + (Some "hi") ] + - location: 22 (remaining gas: 1039984.729 units remaining) + [ (Pair { Elt "hello" "hi" } (Some "hi")) ] + - location: 23 (remaining gas: 1039984.714 units remaining) + [ {} + (Pair { Elt "hello" "hi" } (Some "hi")) ] + - location: 25 (remaining gas: 1039984.699 units remaining) + [ (Pair {} { Elt "hello" "hi" } (Some "hi")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .6f3d35b151.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .6f3d35b151.out" new file mode 100644 index 000000000000..b39476d30325 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .6f3d35b151.out" @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt "1" "one" ; Elt "2" "two" } Unit)-{}-(Pair 4 Unit)-big_map_diff3] + +storage + (Pair 4 Unit) +emitted operations + +big_map diff + New map(4) of type (big_map string string) + Set map(4)["2"] to "two" + Set map(4)["1"] to "one" +trace + - location: 15 (remaining gas: 1039986.537 units remaining) + [ (Pair {} { Elt "1" "one" ; Elt "2" "two" } Unit) ] + - location: 15 (remaining gas: 1039986.527 units remaining) + [ {} @parameter + (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) @storage ] + - location: 16 (remaining gas: 1039986.512 units remaining) + [ (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) @storage ] + - location: 18 (remaining gas: 1039986.502 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 16 (remaining gas: 1039986.472 units remaining) + [ {} @parameter + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 19 (remaining gas: 1039986.472 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 23 (remaining gas: 1039986.457 units remaining) + [ (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) ] + - location: 24 (remaining gas: 1039986.442 units remaining) + [ {} + (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) ] + - location: 26 (remaining gas: 1039986.427 units remaining) + [ (Pair {} { Elt "1" "one" ; Elt "2" "two" } Unit) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .76aeaa0706.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .76aeaa0706.out" new file mode 100644 index 000000000000..ef9dad08a397 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .76aeaa0706.out" @@ -0,0 +1,48 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt "1" "one" ; Elt "2" "two" } Unit)-{ Elt "1" (Some "two") }-(Pair 4 Unit)-big_map_diff4] + +storage + (Pair 4 Unit) +emitted operations + +big_map diff + New map(4) of type (big_map string string) + Set map(4)["2"] to "two" + Set map(4)["1"] to "two" +trace + - location: 15 (remaining gas: 1039986.019 units remaining) + [ (Pair { Elt "1" (Some "two") } { Elt "1" "one" ; Elt "2" "two" } Unit) ] + - location: 15 (remaining gas: 1039986.009 units remaining) + [ { Elt "1" (Some "two") } @parameter + (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) @storage ] + - location: 16 (remaining gas: 1039985.994 units remaining) + [ (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) @storage ] + - location: 18 (remaining gas: 1039985.984 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 16 (remaining gas: 1039985.954 units remaining) + [ { Elt "1" (Some "two") } @parameter + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 19 (remaining gas: 1039985.954 units remaining) + [ (Pair "1" (Some "two")) + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 21 (remaining gas: 1039985.944 units remaining) + [ "1" @key + (Some "two") @elt + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 22 (remaining gas: 1039984.698 units remaining) + [ { Elt "1" "two" ; Elt "2" "two" } + Unit ] + - location: 19 (remaining gas: 1039984.683 units remaining) + [ { Elt "1" "two" ; Elt "2" "two" } + Unit ] + - location: 23 (remaining gas: 1039984.668 units remaining) + [ (Pair { Elt "1" "two" ; Elt "2" "two" } Unit) ] + - location: 24 (remaining gas: 1039984.653 units remaining) + [ {} + (Pair { Elt "1" "two" ; Elt "2" "two" } Unit) ] + - location: 26 (remaining gas: 1039984.638 units remaining) + [ (Pair {} { Elt "1" "two" ; Elt "2" "two" } Unit) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .7e7197f248.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .7e7197f248.out" new file mode 100644 index 000000000000..83f49401d77c --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .7e7197f248.out" @@ -0,0 +1,48 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt "1" "one" ; Elt "2" "two" } Unit)-{ Elt "1" (Some "two") }-(Pair 4 Unit)-big_map_diff8] + +storage + (Pair 4 Unit) +emitted operations + +big_map diff + New map(4) of type (big_map string string) + Set map(4)["2"] to "two" + Set map(4)["1"] to "two" +trace + - location: 15 (remaining gas: 1039986.019 units remaining) + [ (Pair { Elt "1" (Some "two") } { Elt "1" "one" ; Elt "2" "two" } Unit) ] + - location: 15 (remaining gas: 1039986.009 units remaining) + [ { Elt "1" (Some "two") } @parameter + (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) @storage ] + - location: 16 (remaining gas: 1039985.994 units remaining) + [ (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) @storage ] + - location: 18 (remaining gas: 1039985.984 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 16 (remaining gas: 1039985.954 units remaining) + [ { Elt "1" (Some "two") } @parameter + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 19 (remaining gas: 1039985.954 units remaining) + [ (Pair "1" (Some "two")) + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 21 (remaining gas: 1039985.944 units remaining) + [ "1" @key + (Some "two") @elt + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 22 (remaining gas: 1039984.698 units remaining) + [ { Elt "1" "two" ; Elt "2" "two" } + Unit ] + - location: 19 (remaining gas: 1039984.683 units remaining) + [ { Elt "1" "two" ; Elt "2" "two" } + Unit ] + - location: 23 (remaining gas: 1039984.668 units remaining) + [ (Pair { Elt "1" "two" ; Elt "2" "two" } Unit) ] + - location: 24 (remaining gas: 1039984.653 units remaining) + [ {} + (Pair { Elt "1" "two" ; Elt "2" "two" } Unit) ] + - location: 26 (remaining gas: 1039984.638 units remaining) + [ (Pair {} { Elt "1" "two" ; Elt "2" "two" } Unit) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .7ef2c415a7.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .7ef2c415a7.out" new file mode 100644 index 000000000000..f4754045180b --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .7ef2c415a7.out" @@ -0,0 +1,49 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt "1" "one" ; Elt "2" "two" } Unit)-{ Elt "3" (Some "three") }-(Pair 4 Unit)-big_map_diff5] + +storage + (Pair 4 Unit) +emitted operations + +big_map diff + New map(4) of type (big_map string string) + Set map(4)["2"] to "two" + Set map(4)["3"] to "three" + Set map(4)["1"] to "one" +trace + - location: 15 (remaining gas: 1039985.999 units remaining) + [ (Pair { Elt "3" (Some "three") } { Elt "1" "one" ; Elt "2" "two" } Unit) ] + - location: 15 (remaining gas: 1039985.989 units remaining) + [ { Elt "3" (Some "three") } @parameter + (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) @storage ] + - location: 16 (remaining gas: 1039985.974 units remaining) + [ (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) @storage ] + - location: 18 (remaining gas: 1039985.964 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 16 (remaining gas: 1039985.934 units remaining) + [ { Elt "3" (Some "three") } @parameter + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 19 (remaining gas: 1039985.934 units remaining) + [ (Pair "3" (Some "three")) + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 21 (remaining gas: 1039985.924 units remaining) + [ "3" @key + (Some "three") @elt + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 22 (remaining gas: 1039984.678 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" ; Elt "3" "three" } + Unit ] + - location: 19 (remaining gas: 1039984.663 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" ; Elt "3" "three" } + Unit ] + - location: 23 (remaining gas: 1039984.648 units remaining) + [ (Pair { Elt "1" "one" ; Elt "2" "two" ; Elt "3" "three" } Unit) ] + - location: 24 (remaining gas: 1039984.633 units remaining) + [ {} + (Pair { Elt "1" "one" ; Elt "2" "two" ; Elt "3" "three" } Unit) ] + - location: 26 (remaining gas: 1039984.618 units remaining) + [ (Pair {} { Elt "1" "one" ; Elt "2" "two" ; Elt "3" "three" } Unit) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .b688cc94a7.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .b688cc94a7.out" new file mode 100644 index 000000000000..2acdc82f2047 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .b688cc94a7.out" @@ -0,0 +1,49 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt "1" "one" ; Elt "2" "two" } Unit)-{ Elt "3" None }-(Pair 4 Unit)-big_map_diff6] + +storage + (Pair 4 Unit) +emitted operations + +big_map diff + New map(4) of type (big_map string string) + Set map(4)["2"] to "two" + Unset map(4)["3"] + Set map(4)["1"] to "one" +trace + - location: 15 (remaining gas: 1039986.163 units remaining) + [ (Pair { Elt "3" None } { Elt "1" "one" ; Elt "2" "two" } Unit) ] + - location: 15 (remaining gas: 1039986.153 units remaining) + [ { Elt "3" None } @parameter + (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) @storage ] + - location: 16 (remaining gas: 1039986.138 units remaining) + [ (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) @storage ] + - location: 18 (remaining gas: 1039986.128 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 16 (remaining gas: 1039986.098 units remaining) + [ { Elt "3" None } @parameter + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 19 (remaining gas: 1039986.098 units remaining) + [ (Pair "3" None) + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 21 (remaining gas: 1039986.088 units remaining) + [ "3" @key + None @elt + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 22 (remaining gas: 1039984.842 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 19 (remaining gas: 1039984.827 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 23 (remaining gas: 1039984.812 units remaining) + [ (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) ] + - location: 24 (remaining gas: 1039984.797 units remaining) + [ {} + (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) ] + - location: 26 (remaining gas: 1039984.782 units remaining) + [ (Pair {} { Elt "1" "one" ; Elt "2" "two" } Unit) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .c68db221ed.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .c68db221ed.out" new file mode 100644 index 000000000000..d3e47ab2af75 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt \"1\" \"one\" ; Elt \"2\" \"two\" .c68db221ed.out" @@ -0,0 +1,48 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test__big_map_contract_io[update_big_map.tz-(Pair { Elt "1" "one" ; Elt "2" "two" } Unit)-{ Elt "2" None }-(Pair 4 Unit)-big_map_diff7] + +storage + (Pair 4 Unit) +emitted operations + +big_map diff + New map(4) of type (big_map string string) + Unset map(4)["2"] + Set map(4)["1"] to "one" +trace + - location: 15 (remaining gas: 1039986.163 units remaining) + [ (Pair { Elt "2" None } { Elt "1" "one" ; Elt "2" "two" } Unit) ] + - location: 15 (remaining gas: 1039986.153 units remaining) + [ { Elt "2" None } @parameter + (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) @storage ] + - location: 16 (remaining gas: 1039986.138 units remaining) + [ (Pair { Elt "1" "one" ; Elt "2" "two" } Unit) @storage ] + - location: 18 (remaining gas: 1039986.128 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 16 (remaining gas: 1039986.098 units remaining) + [ { Elt "2" None } @parameter + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 19 (remaining gas: 1039986.098 units remaining) + [ (Pair "2" None) + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 21 (remaining gas: 1039986.088 units remaining) + [ "2" @key + None @elt + { Elt "1" "one" ; Elt "2" "two" } + Unit ] + - location: 22 (remaining gas: 1039984.842 units remaining) + [ { Elt "1" "one" } + Unit ] + - location: 19 (remaining gas: 1039984.827 units remaining) + [ { Elt "1" "one" } + Unit ] + - location: 23 (remaining gas: 1039984.812 units remaining) + [ (Pair { Elt "1" "one" } Unit) ] + - location: 24 (remaining gas: 1039984.797 units remaining) + [ {} + (Pair { Elt "1" "one" } Unit) ] + - location: 26 (remaining gas: 1039984.782 units remaining) + [ (Pair {} { Elt "1" "one" } Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[mul_overflow.tz-Unit-Left Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[mul_overflow.tz-Unit-Left Unit].out new file mode 100644 index 000000000000..23088416c656 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[mul_overflow.tz-Unit-Left Unit].out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_arithmetic_overflow[mul_overflow.tz-Unit-Left Unit] + +Runtime error in contract [CONTRACT_HASH]: + 01: parameter (or unit unit) ; + 02: storage unit ; + 03: code { CAR ; + 04: IF_LEFT + 05: { + 06: PUSH nat 922337203685477580700 ; + 07: PUSH mutez 10 ; + 08: MUL ; # FAILURE + 09: DROP + 10: } + 11: { + 12: PUSH mutez 10 ; + 13: PUSH nat 922337203685477580700 ; + 14: MUL ; # FAILURE + 15: DROP + 16: } ; + 17: + 18: NIL operation ; PAIR } + 19: +At line 8 characters 11 to 14, +unexpected arithmetic overflow +Fatal error: + error running script diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[mul_overflow.tz-Unit-Right Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[mul_overflow.tz-Unit-Right Unit].out new file mode 100644 index 000000000000..6cf330ea10db --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[mul_overflow.tz-Unit-Right Unit].out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_arithmetic_overflow[mul_overflow.tz-Unit-Right Unit] + +Runtime error in contract [CONTRACT_HASH]: + 01: parameter (or unit unit) ; + 02: storage unit ; + 03: code { CAR ; + 04: IF_LEFT + 05: { + 06: PUSH nat 922337203685477580700 ; + 07: PUSH mutez 10 ; + 08: MUL ; # FAILURE + 09: DROP + 10: } + 11: { + 12: PUSH mutez 10 ; + 13: PUSH nat 922337203685477580700 ; + 14: MUL ; # FAILURE + 15: DROP + 16: } ; + 17: + 18: NIL operation ; PAIR } + 19: +At line 14 characters 11 to 14, +unexpected arithmetic overflow +Fatal error: + error running script diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Left (Pair 1 257))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Left (Pair 1 257))].out new file mode 100644 index 000000000000..d9ff2299d230 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Left (Pair 1 257))].out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Left (Pair 1 257))] + +Runtime error in contract [CONTRACT_HASH]: + 01: parameter (or (pair nat nat) (pair nat nat)); + 02: storage (option nat); + 03: # this contract takes either (Left a b) and stores (a << b) + 04: # or (Right a b) and stores (a >> b). + 05: # i.e., in the first case, the first component shifted to the left by + 06: # the second, and the second case, component shifted to the right by + 07: # the second. + 08: code { CAR; + 09: IF_LEFT { + 10: UNPAIR; LSL; + 11: } + 12: { + 13: UNPAIR; LSR; + 14: }; + 15: SOME; + 16: NIL operation; + 17: PAIR; + 18: }; + 19: +At line 10 characters 25 to 28, +unexpected arithmetic overflow +Fatal error: + error running script diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Left (Pair 123 257))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Left (Pair 123 257))].out new file mode 100644 index 000000000000..00cc43235082 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Left (Pair 123 257))].out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Left (Pair 123 257))] + +Runtime error in contract [CONTRACT_HASH]: + 01: parameter (or (pair nat nat) (pair nat nat)); + 02: storage (option nat); + 03: # this contract takes either (Left a b) and stores (a << b) + 04: # or (Right a b) and stores (a >> b). + 05: # i.e., in the first case, the first component shifted to the left by + 06: # the second, and the second case, component shifted to the right by + 07: # the second. + 08: code { CAR; + 09: IF_LEFT { + 10: UNPAIR; LSL; + 11: } + 12: { + 13: UNPAIR; LSR; + 14: }; + 15: SOME; + 16: NIL operation; + 17: PAIR; + 18: }; + 19: +At line 10 characters 25 to 28, +unexpected arithmetic overflow +Fatal error: + error running script diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Right (Pair 1 257))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Right (Pair 1 257))].out new file mode 100644 index 000000000000..13ba613d901d --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Right (Pair 1 257))].out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Right (Pair 1 257))] + +Runtime error in contract [CONTRACT_HASH]: + 01: parameter (or (pair nat nat) (pair nat nat)); + 02: storage (option nat); + 03: # this contract takes either (Left a b) and stores (a << b) + 04: # or (Right a b) and stores (a >> b). + 05: # i.e., in the first case, the first component shifted to the left by + 06: # the second, and the second case, component shifted to the right by + 07: # the second. + 08: code { CAR; + 09: IF_LEFT { + 10: UNPAIR; LSL; + 11: } + 12: { + 13: UNPAIR; LSR; + 14: }; + 15: SOME; + 16: NIL operation; + 17: PAIR; + 18: }; + 19: +At line 13 characters 25 to 28, +unexpected arithmetic overflow +Fatal error: + error running script diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Right (Pair 123 257))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Right (Pair 123 257))].out new file mode 100644 index 000000000000..398b736712ea --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Right (Pair 123 257))].out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_arithmetic_overflow[shifts.tz-None-(Right (Pair 123 257))] + +Runtime error in contract [CONTRACT_HASH]: + 01: parameter (or (pair nat nat) (pair nat nat)); + 02: storage (option nat); + 03: # this contract takes either (Left a b) and stores (a << b) + 04: # or (Right a b) and stores (a >> b). + 05: # i.e., in the first case, the first component shifted to the left by + 06: # the second, and the second case, component shifted to the right by + 07: # the second. + 08: code { CAR; + 09: IF_LEFT { + 10: UNPAIR; LSL; + 11: } + 12: { + 13: UNPAIR; LSR; + 14: }; + 15: SOME; + 16: NIL operation; + 17: PAIR; + 18: }; + 19: +At line 13 characters 25 to 28, +unexpected arithmetic overflow +Fatal error: + error running script diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[0.5].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[0.5].out new file mode 100644 index 000000000000..38f89b49b2ac --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[0.5].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_balance[0.5] + +storage + 500000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.668 units remaining) + [ (Pair Unit 0) ] + - location: 7 (remaining gas: 1039995.658 units remaining) + [ ] + - location: 8 (remaining gas: 1039775.642 units remaining) + [ 500000 @balance ] + - location: 9 (remaining gas: 1039775.627 units remaining) + [ {} + 500000 @balance ] + - location: 11 (remaining gas: 1039775.612 units remaining) + [ (Pair {} 500000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[0].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[0].out new file mode 100644 index 000000000000..738204607c9a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[0].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_balance[0] + +storage + 0 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.668 units remaining) + [ (Pair Unit 0) ] + - location: 7 (remaining gas: 1039995.658 units remaining) + [ ] + - location: 8 (remaining gas: 1039775.642 units remaining) + [ 0 @balance ] + - location: 9 (remaining gas: 1039775.627 units remaining) + [ {} + 0 @balance ] + - location: 11 (remaining gas: 1039775.612 units remaining) + [ (Pair {} 0) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[1000].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[1000].out new file mode 100644 index 000000000000..eabb682cdff3 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[1000].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_balance[1000] + +storage + 1000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.668 units remaining) + [ (Pair Unit 0) ] + - location: 7 (remaining gas: 1039995.658 units remaining) + [ ] + - location: 8 (remaining gas: 1039775.642 units remaining) + [ 1000000000 @balance ] + - location: 9 (remaining gas: 1039775.627 units remaining) + [ {} + 1000000000 @balance ] + - location: 11 (remaining gas: 1039775.612 units remaining) + [ (Pair {} 1000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[1].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[1].out new file mode 100644 index 000000000000..5e5d2d9ff7cf --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[1].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_balance[1] + +storage + 1000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.668 units remaining) + [ (Pair Unit 0) ] + - location: 7 (remaining gas: 1039995.658 units remaining) + [ ] + - location: 8 (remaining gas: 1039775.642 units remaining) + [ 1000000 @balance ] + - location: 9 (remaining gas: 1039775.627 units remaining) + [ {} + 1000000 @balance ] + - location: 11 (remaining gas: 1039775.612 units remaining) + [ (Pair {} 1000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[1e-06].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[1e-06].out new file mode 100644 index 000000000000..216e980fd207 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[1e-06].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_balance[1e-06] + +storage + 1 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.668 units remaining) + [ (Pair Unit 0) ] + - location: 7 (remaining gas: 1039995.658 units remaining) + [ ] + - location: 8 (remaining gas: 1039775.642 units remaining) + [ 1 @balance ] + - location: 9 (remaining gas: 1039775.627 units remaining) + [ {} + 1 @balance ] + - location: 11 (remaining gas: 1039775.612 units remaining) + [ (Pair {} 1) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[5].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[5].out new file mode 100644 index 000000000000..dcf484b08754 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[5].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_balance[5] + +storage + 5000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.668 units remaining) + [ (Pair Unit 0) ] + - location: 7 (remaining gas: 1039995.658 units remaining) + [ ] + - location: 8 (remaining gas: 1039775.642 units remaining) + [ 5000000 @balance ] + - location: 9 (remaining gas: 1039775.627 units remaining) + [ {} + 5000000 @balance ] + - location: 11 (remaining gas: 1039775.612 units remaining) + [ (Pair {} 5000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[8000000000000.0].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[8000000000000.0].out new file mode 100644 index 000000000000..62b46119678b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_balance[8000000000000.0].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_balance[8000000000000.0] + +storage + 8000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.668 units remaining) + [ (Pair Unit 0) ] + - location: 7 (remaining gas: 1039995.658 units remaining) + [ ] + - location: 8 (remaining gas: 1039775.642 units remaining) + [ 8000000000000000000 @balance ] + - location: 9 (remaining gas: 1039775.627 units remaining) + [ {} + 8000000000000000000 @balance ] + - location: 11 (remaining gas: 1039775.612 units remaining) + [ (Pair {} 8000000000000000000) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }) )-(Right (Righ.7492e8cdea.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }) )-(Right (Righ.7492e8cdea.out" new file mode 100644 index 000000000000..18741e335fb4 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }) )-(Right (Righ.7492e8cdea.out" @@ -0,0 +1,90 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt "1" "one" } { Elt "2" "two" }) )-(Right (Right (Right (Left { Pair "3" "three" }))))-(Left (Pair 4 5))-big_map_diff4] + +storage + (Left (Pair 4 5)) +emitted operations + +big_map diff + New map(5) of type (big_map string string) + Set map(5)["2"] to "two" + New map(4) of type (big_map string string) + Set map(4)["3"] to "three" + Set map(4)["1"] to "one" +trace + - location: 43 (remaining gas: 1039930.551 units remaining) + [ (Pair (Right (Right (Right (Left { Pair "3" "three" })))) + (Left (Pair { Elt "1" "one" } { Elt "2" "two" }))) ] + - location: 43 (remaining gas: 1039930.541 units remaining) + [ (Right (Right (Right (Left { Pair "3" "three" })))) @parameter + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 44 (remaining gas: 1039930.531 units remaining) + [ (Right (Right (Left { Pair "3" "three" }))) @parameter.right + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 60 (remaining gas: 1039930.521 units remaining) + [ (Right (Left { Pair "3" "three" })) @parameter.right.right + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 65 (remaining gas: 1039930.511 units remaining) + [ (Left { Pair "3" "three" }) @parameter.right.right.right + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 108 (remaining gas: 1039930.501 units remaining) + [ { Pair "3" "three" } @parameter.right.right.right.add + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 110 (remaining gas: 1039930.486 units remaining) + [ (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 113 (remaining gas: 1039930.476 units remaining) + [ (Pair { Elt "1" "one" } { Elt "2" "two" }) @storage.left ] + - location: 113 (remaining gas: 1039930.461 units remaining) + [ (Pair { Elt "1" "one" } { Elt "2" "two" }) @storage.left ] + - location: 119 (remaining gas: 1039930.451 units remaining) + [ { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 110 (remaining gas: 1039930.421 units remaining) + [ { Pair "3" "three" } @parameter.right.right.right.add + { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 120 (remaining gas: 1039930.421 units remaining) + [ (Pair "3" "three") @parameter.right.right.right.add.elt + { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 122 (remaining gas: 1039930.411 units remaining) + [ "3" + "three" + { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 123 (remaining gas: 1039930.396 units remaining) + [ "three" + { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 125 (remaining gas: 1039930.381 units remaining) + [ (Some "three") + { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 123 (remaining gas: 1039930.351 units remaining) + [ "3" + (Some "three") + { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 126 (remaining gas: 1039929.108 units remaining) + [ { Elt "1" "one" ; Elt "3" "three" } + { Elt "2" "two" } ] + - location: 120 (remaining gas: 1039929.093 units remaining) + [ { Elt "1" "one" ; Elt "3" "three" } + { Elt "2" "two" } ] + - location: 127 (remaining gas: 1039929.078 units remaining) + [ (Pair { Elt "1" "one" ; Elt "3" "three" } { Elt "2" "two" }) ] + - location: 128 (remaining gas: 1039929.063 units remaining) + [ (Left (Pair { Elt "1" "one" ; Elt "3" "three" } { Elt "2" "two" })) ] + - location: 108 (remaining gas: 1039929.048 units remaining) + [ (Left (Pair { Elt "1" "one" ; Elt "3" "three" } { Elt "2" "two" })) ] + - location: 65 (remaining gas: 1039929.033 units remaining) + [ (Left (Pair { Elt "1" "one" ; Elt "3" "three" } { Elt "2" "two" })) ] + - location: 60 (remaining gas: 1039929.018 units remaining) + [ (Left (Pair { Elt "1" "one" ; Elt "3" "three" } { Elt "2" "two" })) ] + - location: 44 (remaining gas: 1039929.003 units remaining) + [ (Left (Pair { Elt "1" "one" ; Elt "3" "three" } { Elt "2" "two" })) ] + - location: 151 (remaining gas: 1039928.988 units remaining) + [ {} + (Left (Pair { Elt "1" "one" ; Elt "3" "three" } { Elt "2" "two" })) ] + - location: 153 (remaining gas: 1039928.973 units remaining) + [ (Pair {} (Left (Pair { Elt "1" "one" ; Elt "3" "three" } { Elt "2" "two" }))) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Left Unit)-(.21b30dd90f.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Left Unit)-(.21b30dd90f.out" new file mode 100644 index 000000000000..bf419b1bf686 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Left Unit)-(.21b30dd90f.out" @@ -0,0 +1,44 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt "1" "one" } { Elt "2" "two" }))-(Left Unit)-(Left (Pair 4 5))-big_map_diff0] + +storage + (Left (Pair 4 5)) +emitted operations + +big_map diff + New map(5) of type (big_map string string) + Set map(5)["1"] to "one" + New map(4) of type (big_map string string) + Set map(4)["2"] to "two" +trace + - location: 43 (remaining gas: 1039931.459 units remaining) + [ (Pair (Left Unit) (Left (Pair { Elt "1" "one" } { Elt "2" "two" }))) ] + - location: 43 (remaining gas: 1039931.449 units remaining) + [ (Left Unit) @parameter + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 44 (remaining gas: 1039931.439 units remaining) + [ Unit @parameter.swap + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 46 (remaining gas: 1039931.429 units remaining) + [ (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 48 (remaining gas: 1039931.419 units remaining) + [ (Pair { Elt "1" "one" } { Elt "2" "two" }) @storage.left ] + - location: 48 (remaining gas: 1039931.404 units remaining) + [ (Pair { Elt "1" "one" } { Elt "2" "two" }) @storage.left ] + - location: 54 (remaining gas: 1039931.394 units remaining) + [ { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 55 (remaining gas: 1039931.384 units remaining) + [ { Elt "2" "two" } + { Elt "1" "one" } ] + - location: 56 (remaining gas: 1039931.369 units remaining) + [ (Pair { Elt "2" "two" } { Elt "1" "one" }) ] + - location: 57 (remaining gas: 1039931.354 units remaining) + [ (Left (Pair { Elt "2" "two" } { Elt "1" "one" })) ] + - location: 44 (remaining gas: 1039931.339 units remaining) + [ (Left (Pair { Elt "2" "two" } { Elt "1" "one" })) ] + - location: 151 (remaining gas: 1039931.324 units remaining) + [ {} + (Left (Pair { Elt "2" "two" } { Elt "1" "one" })) ] + - location: 153 (remaining gas: 1039931.309 units remaining) + [ (Pair {} (Left (Pair { Elt "2" "two" } { Elt "1" "one" }))) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Right (Left .2873ef610c.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Right (Left .2873ef610c.out" new file mode 100644 index 000000000000..c8c9c27f1261 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Right (Left .2873ef610c.out" @@ -0,0 +1,39 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt "1" "one" } { Elt "2" "two" }))-(Right (Left (Left (Pair { Elt "3" "three" } { Elt "4" "four" }))))-(Left (Pair 4 5))-big_map_diff1] + +storage + (Left (Pair 4 5)) +emitted operations + +big_map diff + New map(5) of type (big_map string string) + Set map(5)["4"] to "four" + New map(4) of type (big_map string string) + Set map(4)["3"] to "three" +trace + - location: 43 (remaining gas: 1039927.133 units remaining) + [ (Pair (Right (Left (Left (Pair { Elt "3" "three" } { Elt "4" "four" })))) + (Left (Pair { Elt "1" "one" } { Elt "2" "two" }))) ] + - location: 43 (remaining gas: 1039927.123 units remaining) + [ (Right (Left (Left (Pair { Elt "3" "three" } { Elt "4" "four" })))) @parameter + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 44 (remaining gas: 1039927.113 units remaining) + [ (Left (Left (Pair { Elt "3" "three" } { Elt "4" "four" }))) @parameter.right + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 60 (remaining gas: 1039927.103 units remaining) + [ (Left (Pair { Elt "3" "three" } { Elt "4" "four" })) @parameter.right.reset + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 62 (remaining gas: 1039927.093 units remaining) + [ (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage + (Left (Pair { Elt "3" "three" } { Elt "4" "four" })) @parameter.right.reset ] + - location: 63 (remaining gas: 1039927.083 units remaining) + [ (Left (Pair { Elt "3" "three" } { Elt "4" "four" })) ] + - location: 60 (remaining gas: 1039927.068 units remaining) + [ (Left (Pair { Elt "3" "three" } { Elt "4" "four" })) ] + - location: 44 (remaining gas: 1039927.053 units remaining) + [ (Left (Pair { Elt "3" "three" } { Elt "4" "four" })) ] + - location: 151 (remaining gas: 1039927.038 units remaining) + [ {} + (Left (Pair { Elt "3" "three" } { Elt "4" "four" })) ] + - location: 153 (remaining gas: 1039927.023 units remaining) + [ (Pair {} (Left (Pair { Elt "3" "three" } { Elt "4" "four" }))) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Right (Left .8a6f480005.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Right (Left .8a6f480005.out" new file mode 100644 index 000000000000..4dcbfad20a2f --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Right (Left .8a6f480005.out" @@ -0,0 +1,35 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt "1" "one" } { Elt "2" "two" }))-(Right (Left (Right Unit)))-(Right Unit)-big_map_diff2] + +storage + (Right Unit) +emitted operations + +big_map diff + +trace + - location: 43 (remaining gas: 1039930.819 units remaining) + [ (Pair (Right (Left (Right Unit))) (Left (Pair { Elt "1" "one" } { Elt "2" "two" }))) ] + - location: 43 (remaining gas: 1039930.809 units remaining) + [ (Right (Left (Right Unit))) @parameter + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 44 (remaining gas: 1039930.799 units remaining) + [ (Left (Right Unit)) @parameter.right + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 60 (remaining gas: 1039930.789 units remaining) + [ (Right Unit) @parameter.right.reset + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 62 (remaining gas: 1039930.779 units remaining) + [ (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage + (Right Unit) @parameter.right.reset ] + - location: 63 (remaining gas: 1039930.769 units remaining) + [ (Right Unit) ] + - location: 60 (remaining gas: 1039930.754 units remaining) + [ (Right Unit) ] + - location: 44 (remaining gas: 1039930.739 units remaining) + [ (Right Unit) ] + - location: 151 (remaining gas: 1039930.724 units remaining) + [ {} + (Right Unit) ] + - location: 153 (remaining gas: 1039930.709 units remaining) + [ (Pair {} (Right Unit)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Right (Right.d336ca1903.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Right (Right.d336ca1903.out" new file mode 100644 index 000000000000..63c38a082cbb --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt \"1\" \"one\" } { Elt \"2\" \"two\" }))-(Right (Right.d336ca1903.out" @@ -0,0 +1,83 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_big_map_magic[(Left (Pair { Elt "1" "one" } { Elt "2" "two" }))-(Right (Right (Right (Right { "1" }))))-(Left (Pair 4 5))-big_map_diff5] + +storage + (Left (Pair 4 5)) +emitted operations + +big_map diff + New map(5) of type (big_map string string) + Set map(5)["2"] to "two" + New map(4) of type (big_map string string) + Unset map(4)["1"] +trace + - location: 43 (remaining gas: 1039930.815 units remaining) + [ (Pair (Right (Right (Right (Right { "1" })))) + (Left (Pair { Elt "1" "one" } { Elt "2" "two" }))) ] + - location: 43 (remaining gas: 1039930.805 units remaining) + [ (Right (Right (Right (Right { "1" })))) @parameter + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 44 (remaining gas: 1039930.795 units remaining) + [ (Right (Right (Right { "1" }))) @parameter.right + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 60 (remaining gas: 1039930.785 units remaining) + [ (Right (Right { "1" })) @parameter.right.right + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 65 (remaining gas: 1039930.775 units remaining) + [ (Right { "1" }) @parameter.right.right.right + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 108 (remaining gas: 1039930.765 units remaining) + [ { "1" } @parameter.right.right.right.rem + (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 131 (remaining gas: 1039930.750 units remaining) + [ (Left (Pair { Elt "1" "one" } { Elt "2" "two" })) @storage ] + - location: 134 (remaining gas: 1039930.740 units remaining) + [ (Pair { Elt "1" "one" } { Elt "2" "two" }) @storage.left ] + - location: 134 (remaining gas: 1039930.725 units remaining) + [ (Pair { Elt "1" "one" } { Elt "2" "two" }) @storage.left ] + - location: 140 (remaining gas: 1039930.715 units remaining) + [ { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 131 (remaining gas: 1039930.685 units remaining) + [ { "1" } @parameter.right.right.right.rem + { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 141 (remaining gas: 1039930.685 units remaining) + [ "1" @parameter.right.right.right.rem.elt + { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 143 (remaining gas: 1039930.670 units remaining) + [ { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 145 (remaining gas: 1039930.655 units remaining) + [ None + { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 143 (remaining gas: 1039930.625 units remaining) + [ "1" @parameter.right.right.right.rem.elt + None + { Elt "1" "one" } + { Elt "2" "two" } ] + - location: 147 (remaining gas: 1039929.382 units remaining) + [ {} + { Elt "2" "two" } ] + - location: 141 (remaining gas: 1039929.367 units remaining) + [ {} + { Elt "2" "two" } ] + - location: 148 (remaining gas: 1039929.352 units remaining) + [ (Pair {} { Elt "2" "two" }) ] + - location: 149 (remaining gas: 1039929.337 units remaining) + [ (Left (Pair {} { Elt "2" "two" })) ] + - location: 108 (remaining gas: 1039929.322 units remaining) + [ (Left (Pair {} { Elt "2" "two" })) ] + - location: 65 (remaining gas: 1039929.307 units remaining) + [ (Left (Pair {} { Elt "2" "two" })) ] + - location: 60 (remaining gas: 1039929.292 units remaining) + [ (Left (Pair {} { Elt "2" "two" })) ] + - location: 44 (remaining gas: 1039929.277 units remaining) + [ (Left (Pair {} { Elt "2" "two" })) ] + - location: 151 (remaining gas: 1039929.262 units remaining) + [ {} + (Left (Pair {} { Elt "2" "two" })) ] + - location: 153 (remaining gas: 1039929.247 units remaining) + [ (Pair {} (Left (Pair {} { Elt "2" "two" }))) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Right Unit)-(Right (Right (Left (Pair { Pair \"foo\" \"bar\" } { P.7f2ee47600.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Right Unit)-(Right (Right (Left (Pair { Pair \"foo\" \"bar\" } { P.7f2ee47600.out" new file mode 100644 index 000000000000..594e250f455f --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_big_map_magic[(Right Unit)-(Right (Right (Left (Pair { Pair \"foo\" \"bar\" } { P.7f2ee47600.out" @@ -0,0 +1,135 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_big_map_magic[(Right Unit)-(Right (Right (Left (Pair { Pair "foo" "bar" } { Pair "gaz" "baz" }) )))-(Left (Pair 4 5))-big_map_diff3] + +storage + (Left (Pair 4 5)) +emitted operations + +big_map diff + New map(5) of type (big_map string string) + Set map(5)["gaz"] to "baz" + New map(4) of type (big_map string string) + Set map(4)["foo"] to "bar" +trace + - location: 43 (remaining gas: 1039933.719 units remaining) + [ (Pair (Right (Right (Left (Pair { Pair "foo" "bar" } { Pair "gaz" "baz" })))) (Right Unit)) ] + - location: 43 (remaining gas: 1039933.709 units remaining) + [ (Right (Right (Left (Pair { Pair "foo" "bar" } { Pair "gaz" "baz" })))) @parameter + (Right Unit) @storage ] + - location: 44 (remaining gas: 1039933.699 units remaining) + [ (Right (Left (Pair { Pair "foo" "bar" } { Pair "gaz" "baz" }))) @parameter.right + (Right Unit) @storage ] + - location: 60 (remaining gas: 1039933.689 units remaining) + [ (Left (Pair { Pair "foo" "bar" } { Pair "gaz" "baz" })) @parameter.right.right + (Right Unit) @storage ] + - location: 65 (remaining gas: 1039933.679 units remaining) + [ (Pair { Pair "foo" "bar" } { Pair "gaz" "baz" }) @parameter.right.right.import + (Right Unit) @storage ] + - location: 67 (remaining gas: 1039933.664 units remaining) + [ (Right Unit) @storage ] + - location: 70 (remaining gas: 1039933.654 units remaining) + [ Unit @storage.right ] + - location: 70 (remaining gas: 1039933.639 units remaining) + [ Unit @storage.right ] + - location: 76 (remaining gas: 1039933.629 units remaining) + [ ] + - location: 67 (remaining gas: 1039933.599 units remaining) + [ (Pair { Pair "foo" "bar" } { Pair "gaz" "baz" }) @parameter.right.right.import ] + - location: 77 (remaining gas: 1039933.589 units remaining) + [ { Pair "foo" "bar" } + { Pair "gaz" "baz" } ] + - location: 78 (remaining gas: 1039933.574 units remaining) + [ { Pair "gaz" "baz" } ] + - location: 80 (remaining gas: 1039933.559 units remaining) + [ {} + { Pair "gaz" "baz" } ] + - location: 78 (remaining gas: 1039933.529 units remaining) + [ { Pair "foo" "bar" } + {} + { Pair "gaz" "baz" } ] + - location: 83 (remaining gas: 1039933.529 units remaining) + [ (Pair "foo" "bar") @elt + {} + { Pair "gaz" "baz" } ] + - location: 85 (remaining gas: 1039933.519 units remaining) + [ "foo" + "bar" + {} + { Pair "gaz" "baz" } ] + - location: 86 (remaining gas: 1039933.504 units remaining) + [ "bar" + {} + { Pair "gaz" "baz" } ] + - location: 88 (remaining gas: 1039933.489 units remaining) + [ (Some "bar") + {} + { Pair "gaz" "baz" } ] + - location: 86 (remaining gas: 1039933.459 units remaining) + [ "foo" + (Some "bar") + {} + { Pair "gaz" "baz" } ] + - location: 89 (remaining gas: 1039932.084 units remaining) + [ { Elt "foo" "bar" } + { Pair "gaz" "baz" } ] + - location: 83 (remaining gas: 1039932.069 units remaining) + [ { Elt "foo" "bar" } + { Pair "gaz" "baz" } ] + - location: 90 (remaining gas: 1039932.059 units remaining) + [ { Pair "gaz" "baz" } + { Elt "foo" "bar" } ] + - location: 91 (remaining gas: 1039932.044 units remaining) + [ { Elt "foo" "bar" } ] + - location: 93 (remaining gas: 1039932.029 units remaining) + [ {} + { Elt "foo" "bar" } ] + - location: 91 (remaining gas: 1039931.999 units remaining) + [ { Pair "gaz" "baz" } + {} + { Elt "foo" "bar" } ] + - location: 96 (remaining gas: 1039931.999 units remaining) + [ (Pair "gaz" "baz") @elt + {} + { Elt "foo" "bar" } ] + - location: 98 (remaining gas: 1039931.989 units remaining) + [ "gaz" + "baz" + {} + { Elt "foo" "bar" } ] + - location: 99 (remaining gas: 1039931.974 units remaining) + [ "baz" + {} + { Elt "foo" "bar" } ] + - location: 101 (remaining gas: 1039931.959 units remaining) + [ (Some "baz") + {} + { Elt "foo" "bar" } ] + - location: 99 (remaining gas: 1039931.929 units remaining) + [ "gaz" + (Some "baz") + {} + { Elt "foo" "bar" } ] + - location: 102 (remaining gas: 1039930.554 units remaining) + [ { Elt "gaz" "baz" } + { Elt "foo" "bar" } ] + - location: 96 (remaining gas: 1039930.539 units remaining) + [ { Elt "gaz" "baz" } + { Elt "foo" "bar" } ] + - location: 103 (remaining gas: 1039930.529 units remaining) + [ { Elt "foo" "bar" } + { Elt "gaz" "baz" } ] + - location: 104 (remaining gas: 1039930.514 units remaining) + [ (Pair { Elt "foo" "bar" } { Elt "gaz" "baz" }) ] + - location: 105 (remaining gas: 1039930.499 units remaining) + [ (Left (Pair { Elt "foo" "bar" } { Elt "gaz" "baz" })) ] + - location: 65 (remaining gas: 1039930.484 units remaining) + [ (Left (Pair { Elt "foo" "bar" } { Elt "gaz" "baz" })) ] + - location: 60 (remaining gas: 1039930.469 units remaining) + [ (Left (Pair { Elt "foo" "bar" } { Elt "gaz" "baz" })) ] + - location: 44 (remaining gas: 1039930.454 units remaining) + [ (Left (Pair { Elt "foo" "bar" } { Elt "gaz" "baz" })) ] + - location: 151 (remaining gas: 1039930.439 units remaining) + [ {} + (Left (Pair { Elt "foo" "bar" } { Elt "gaz" "baz" })) ] + - location: 153 (remaining gas: 1039930.424 units remaining) + [ (Pair {} (Left (Pair { Elt "foo" "bar" } { Elt "gaz" "baz" }))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_check_signature.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_check_signature.out new file mode 100644 index 000000000000..13246119b2e4 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_check_signature.out @@ -0,0 +1,241 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_check_signature + +storage + (Pair "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039951.005 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 9 (remaining gas: 1039950.995 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 10 (remaining gas: 1039950.985 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 11 (remaining gas: 1039950.970 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 13 (remaining gas: 1039950.960 units remaining) + [ (Pair "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") @storage + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 14 (remaining gas: 1039950.950 units remaining) + [ (Pair "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") @storage + (Pair "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") @storage + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 15 (remaining gas: 1039950.940 units remaining) + [ "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + (Pair "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") @storage + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 16 (remaining gas: 1039950.925 units remaining) + [ (Pair "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") @storage + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 18 (remaining gas: 1039950.915 units remaining) + [ "hello" + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 19 (remaining gas: 1039950.126 units remaining) + [ 0x05010000000568656c6c6f @packed + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 16 (remaining gas: 1039950.096 units remaining) + [ "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + 0x05010000000568656c6c6f @packed + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 11 (remaining gas: 1039950.066 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + 0x05010000000568656c6c6f @packed + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 20 (remaining gas: 1039950.056 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" @parameter + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + 0x05010000000568656c6c6f @packed + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 21 (remaining gas: 1039707.094 units remaining) + [ True + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 22 (remaining gas: 1039707.084 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 22 (remaining gas: 1039707.069 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + - location: 28 (remaining gas: 1039707.059 units remaining) + [ (Pair "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") @storage ] + - location: 29 (remaining gas: 1039707.044 units remaining) + [ {} + (Pair "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") @storage ] + - location: 31 (remaining gas: 1039707.029 units remaining) + [ (Pair {} + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "hello") ] + +Runtime error in contract [CONTRACT_HASH]: + 01: parameter key; + 02: storage (pair signature string); + 03: code { + 04: DUP; DUP; + 05: DIP{ CDR; DUP; CAR; + 06: DIP{CDR; PACK}}; + 07: CAR; CHECK_SIGNATURE; + 08: IF {} {FAIL} ; + 09: CDR; NIL operation ; PAIR}; + 10: + 11: +At line 8 characters 14 to 18, +script reached FAILWITH instruction +with Unit +trace + - location: 9 (remaining gas: 1039951.015 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 9 (remaining gas: 1039951.005 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 10 (remaining gas: 1039950.995 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 11 (remaining gas: 1039950.980 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 13 (remaining gas: 1039950.970 units remaining) + [ (Pair "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") @storage + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 14 (remaining gas: 1039950.960 units remaining) + [ (Pair "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") @storage + (Pair "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") @storage + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 15 (remaining gas: 1039950.950 units remaining) + [ "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + (Pair "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") @storage + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 16 (remaining gas: 1039950.935 units remaining) + [ (Pair "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") @storage + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 18 (remaining gas: 1039950.925 units remaining) + [ "abcd" + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 19 (remaining gas: 1039950.202 units remaining) + [ 0x05010000000461626364 @packed + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 16 (remaining gas: 1039950.172 units remaining) + [ "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + 0x05010000000461626364 @packed + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 11 (remaining gas: 1039950.142 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + 0x05010000000461626364 @packed + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 20 (remaining gas: 1039950.132 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" @parameter + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + 0x05010000000461626364 @packed + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 21 (remaining gas: 1039707.171 units remaining) + [ False + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 22 (remaining gas: 1039707.161 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] + - location: 26 (remaining gas: 1039707.151 units remaining) + [ Unit + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF" + "abcd") ] +Fatal error: + error running script diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[abs.tz-Unit-0-Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[abs.tz-Unit-0-Unit].out new file mode 100644 index 000000000000..05b730c05018 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[abs.tz-Unit-0-Unit].out @@ -0,0 +1,38 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[abs.tz-Unit-0-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039989.219 units remaining) + [ (Pair 0 Unit) ] + - location: 7 (remaining gas: 1039989.209 units remaining) + [ 0 @parameter ] + - location: 8 (remaining gas: 1039989.199 units remaining) + [ 0 @parameter + 0 @parameter ] + - location: 9 (remaining gas: 1039989.174 units remaining) + [ 0 + 0 @parameter ] + - location: 10 (remaining gas: 1039989.149 units remaining) + [ 0 + 0 @parameter ] + - location: 11 (remaining gas: 1039989.114 units remaining) + [ 0 ] + - location: 13 (remaining gas: 1039989.099 units remaining) + [ True ] + - location: 14 (remaining gas: 1039989.089 units remaining) + [ ] + - location: 14 (remaining gas: 1039989.074 units remaining) + [ ] + - location: 20 (remaining gas: 1039989.064 units remaining) + [ Unit ] + - location: 21 (remaining gas: 1039989.049 units remaining) + [ {} + Unit ] + - location: 23 (remaining gas: 1039989.034 units remaining) + [ (Pair {} Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[abs.tz-Unit-12039123919239192312931-Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[abs.tz-Unit-12039123919239192312931-Unit].out new file mode 100644 index 000000000000..95ddc3e3fc22 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[abs.tz-Unit-12039123919239192312931-Unit].out @@ -0,0 +1,38 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[abs.tz-Unit-12039123919239192312931-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039989.219 units remaining) + [ (Pair 12039123919239192312931 Unit) ] + - location: 7 (remaining gas: 1039989.209 units remaining) + [ 12039123919239192312931 @parameter ] + - location: 8 (remaining gas: 1039989.199 units remaining) + [ 12039123919239192312931 @parameter + 12039123919239192312931 @parameter ] + - location: 9 (remaining gas: 1039989.174 units remaining) + [ -12039123919239192312931 + 12039123919239192312931 @parameter ] + - location: 10 (remaining gas: 1039989.149 units remaining) + [ 12039123919239192312931 + 12039123919239192312931 @parameter ] + - location: 11 (remaining gas: 1039989.114 units remaining) + [ 0 ] + - location: 13 (remaining gas: 1039989.099 units remaining) + [ True ] + - location: 14 (remaining gas: 1039989.089 units remaining) + [ ] + - location: 14 (remaining gas: 1039989.074 units remaining) + [ ] + - location: 20 (remaining gas: 1039989.064 units remaining) + [ Unit ] + - location: 21 (remaining gas: 1039989.049 units remaining) + [ {} + Unit ] + - location: 23 (remaining gas: 1039989.034 units remaining) + [ (Pair {} Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[abs.tz-Unit-948-Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[abs.tz-Unit-948-Unit].out new file mode 100644 index 000000000000..4adebf2927e0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[abs.tz-Unit-948-Unit].out @@ -0,0 +1,38 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[abs.tz-Unit-948-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039989.219 units remaining) + [ (Pair 948 Unit) ] + - location: 7 (remaining gas: 1039989.209 units remaining) + [ 948 @parameter ] + - location: 8 (remaining gas: 1039989.199 units remaining) + [ 948 @parameter + 948 @parameter ] + - location: 9 (remaining gas: 1039989.174 units remaining) + [ -948 + 948 @parameter ] + - location: 10 (remaining gas: 1039989.149 units remaining) + [ 948 + 948 @parameter ] + - location: 11 (remaining gas: 1039989.114 units remaining) + [ 0 ] + - location: 13 (remaining gas: 1039989.099 units remaining) + [ True ] + - location: 14 (remaining gas: 1039989.089 units remaining) + [ ] + - location: 14 (remaining gas: 1039989.074 units remaining) + [ ] + - location: 20 (remaining gas: 1039989.064 units remaining) + [ Unit ] + - location: 21 (remaining gas: 1039989.049 units remaining) + [ {} + Unit ] + - location: 23 (remaining gas: 1039989.034 units remaining) + [ (Pair {} Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add.tz-Unit-Unit-Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add.tz-Unit-Unit-Unit].out new file mode 100644 index 000000000000..1f71061a475f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add.tz-Unit-Unit-Unit].out @@ -0,0 +1,211 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[add.tz-Unit-Unit-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039927.083 units remaining) + [ (Pair Unit Unit) ] + - location: 7 (remaining gas: 1039927.073 units remaining) + [ Unit @parameter ] + - location: 8 (remaining gas: 1039927.063 units remaining) + [ 2 + Unit @parameter ] + - location: 11 (remaining gas: 1039927.053 units remaining) + [ 2 + 2 + Unit @parameter ] + - location: 14 (remaining gas: 1039927.018 units remaining) + [ 4 + Unit @parameter ] + - location: 15 (remaining gas: 1039927.008 units remaining) + [ 4 + 4 + Unit @parameter ] + - location: 20 (remaining gas: 1039926.973 units remaining) + [ 0 + Unit @parameter ] + - location: 21 (remaining gas: 1039926.958 units remaining) + [ True + Unit @parameter ] + - location: 22 (remaining gas: 1039926.948 units remaining) + [ Unit @parameter ] + - location: 22 (remaining gas: 1039926.933 units remaining) + [ Unit @parameter ] + - location: 28 (remaining gas: 1039926.923 units remaining) + [ 2 + Unit @parameter ] + - location: 31 (remaining gas: 1039926.913 units remaining) + [ 2 + 2 + Unit @parameter ] + - location: 34 (remaining gas: 1039926.878 units remaining) + [ 4 + Unit @parameter ] + - location: 35 (remaining gas: 1039926.868 units remaining) + [ 4 + 4 + Unit @parameter ] + - location: 40 (remaining gas: 1039926.833 units remaining) + [ 0 + Unit @parameter ] + - location: 41 (remaining gas: 1039926.818 units remaining) + [ True + Unit @parameter ] + - location: 42 (remaining gas: 1039926.808 units remaining) + [ Unit @parameter ] + - location: 42 (remaining gas: 1039926.793 units remaining) + [ Unit @parameter ] + - location: 48 (remaining gas: 1039926.783 units remaining) + [ 2 + Unit @parameter ] + - location: 51 (remaining gas: 1039926.773 units remaining) + [ 2 + 2 + Unit @parameter ] + - location: 54 (remaining gas: 1039926.738 units remaining) + [ 4 + Unit @parameter ] + - location: 55 (remaining gas: 1039926.728 units remaining) + [ 4 + 4 + Unit @parameter ] + - location: 60 (remaining gas: 1039926.693 units remaining) + [ 0 + Unit @parameter ] + - location: 61 (remaining gas: 1039926.678 units remaining) + [ True + Unit @parameter ] + - location: 62 (remaining gas: 1039926.668 units remaining) + [ Unit @parameter ] + - location: 62 (remaining gas: 1039926.653 units remaining) + [ Unit @parameter ] + - location: 68 (remaining gas: 1039926.643 units remaining) + [ 2 + Unit @parameter ] + - location: 71 (remaining gas: 1039926.633 units remaining) + [ 2 + 2 + Unit @parameter ] + - location: 74 (remaining gas: 1039926.598 units remaining) + [ 4 + Unit @parameter ] + - location: 75 (remaining gas: 1039926.588 units remaining) + [ 4 + 4 + Unit @parameter ] + - location: 80 (remaining gas: 1039926.553 units remaining) + [ 0 + Unit @parameter ] + - location: 81 (remaining gas: 1039926.538 units remaining) + [ True + Unit @parameter ] + - location: 82 (remaining gas: 1039926.528 units remaining) + [ Unit @parameter ] + - location: 82 (remaining gas: 1039926.513 units remaining) + [ Unit @parameter ] + - location: 88 (remaining gas: 1039926.503 units remaining) + [ 2 + Unit @parameter ] + - location: 91 (remaining gas: 1039926.493 units remaining) + [ 2 + 2 + Unit @parameter ] + - location: 94 (remaining gas: 1039926.458 units remaining) + [ 4 + Unit @parameter ] + - location: 95 (remaining gas: 1039926.448 units remaining) + [ 4 + 4 + Unit @parameter ] + - location: 100 (remaining gas: 1039926.413 units remaining) + [ 0 + Unit @parameter ] + - location: 101 (remaining gas: 1039926.398 units remaining) + [ True + Unit @parameter ] + - location: 102 (remaining gas: 1039926.388 units remaining) + [ Unit @parameter ] + - location: 102 (remaining gas: 1039926.373 units remaining) + [ Unit @parameter ] + - location: 108 (remaining gas: 1039926.363 units remaining) + [ 60 + Unit @parameter ] + - location: 111 (remaining gas: 1039926.353 units remaining) + [ "2019-09-09T12:08:37Z" + 60 + Unit @parameter ] + - location: 114 (remaining gas: 1039926.318 units remaining) + [ "2019-09-09T12:09:37Z" + Unit @parameter ] + - location: 115 (remaining gas: 1039926.308 units remaining) + [ "2019-09-09T12:09:37Z" + "2019-09-09T12:09:37Z" + Unit @parameter ] + - location: 120 (remaining gas: 1039926.273 units remaining) + [ 0 + Unit @parameter ] + - location: 121 (remaining gas: 1039926.258 units remaining) + [ True + Unit @parameter ] + - location: 122 (remaining gas: 1039926.248 units remaining) + [ Unit @parameter ] + - location: 122 (remaining gas: 1039926.233 units remaining) + [ Unit @parameter ] + - location: 128 (remaining gas: 1039926.223 units remaining) + [ "2019-09-09T12:08:37Z" + Unit @parameter ] + - location: 131 (remaining gas: 1039926.213 units remaining) + [ 60 + "2019-09-09T12:08:37Z" + Unit @parameter ] + - location: 134 (remaining gas: 1039926.178 units remaining) + [ "2019-09-09T12:09:37Z" + Unit @parameter ] + - location: 135 (remaining gas: 1039926.168 units remaining) + [ "2019-09-09T12:09:37Z" + "2019-09-09T12:09:37Z" + Unit @parameter ] + - location: 140 (remaining gas: 1039926.133 units remaining) + [ 0 + Unit @parameter ] + - location: 141 (remaining gas: 1039926.118 units remaining) + [ True + Unit @parameter ] + - location: 142 (remaining gas: 1039926.108 units remaining) + [ Unit @parameter ] + - location: 142 (remaining gas: 1039926.093 units remaining) + [ Unit @parameter ] + - location: 148 (remaining gas: 1039926.083 units remaining) + [ 1000 + Unit @parameter ] + - location: 151 (remaining gas: 1039926.073 units remaining) + [ 1000 + 1000 + Unit @parameter ] + - location: 154 (remaining gas: 1039926.048 units remaining) + [ 2000 + Unit @parameter ] + - location: 155 (remaining gas: 1039926.038 units remaining) + [ 2000 + 2000 + Unit @parameter ] + - location: 160 (remaining gas: 1039926.003 units remaining) + [ 0 + Unit @parameter ] + - location: 161 (remaining gas: 1039925.988 units remaining) + [ True + Unit @parameter ] + - location: 162 (remaining gas: 1039925.978 units remaining) + [ Unit @parameter ] + - location: 162 (remaining gas: 1039925.963 units remaining) + [ Unit @parameter ] + - location: 168 (remaining gas: 1039925.948 units remaining) + [ {} + Unit @parameter ] + - location: 170 (remaining gas: 1039925.933 units remaining) + [ (Pair {} Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x00 0x00-(Some 0x0000000.3c2de60480.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x00 0x00-(Some 0x0000000.3c2de60480.out new file mode 100644 index 000000000000..7f6181c5ef93 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x00 0x00-(Some 0x0000000.3c2de60480.out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x00 0x00-(Some 0x0000000000000000000000000000000000000000000000000000000000000000)] + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039993.624 units remaining) + [ (Pair (Pair 0x0000000000000000000000000000000000000000000000000000000000000000 + 0x0000000000000000000000000000000000000000000000000000000000000000) + None) ] + - location: 10 (remaining gas: 1039993.614 units remaining) + [ (Pair 0x0000000000000000000000000000000000000000000000000000000000000000 + 0x0000000000000000000000000000000000000000000000000000000000000000) @parameter ] + - location: 11 (remaining gas: 1039993.604 units remaining) + [ 0x0000000000000000000000000000000000000000000000000000000000000000 + 0x0000000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039993.459 units remaining) + [ 0x0000000000000000000000000000000000000000000000000000000000000000 ] + - location: 13 (remaining gas: 1039993.444 units remaining) + [ (Some 0x0000000000000000000000000000000000000000000000000000000000000000) ] + - location: 14 (remaining gas: 1039993.429 units remaining) + [ {} + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) ] + - location: 16 (remaining gas: 1039993.414 units remaining) + [ (Pair {} + (Some 0x0000000000000000000000000000000000000000000000000000000000000000)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x01 0x00-(Some 0x0100000.12b2c1172b.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x01 0x00-(Some 0x0100000.12b2c1172b.out new file mode 100644 index 000000000000..5ba5677eba31 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x01 0x00-(Some 0x0100000.12b2c1172b.out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x01 0x00-(Some 0x0100000000000000000000000000000000000000000000000000000000000000)] + +storage + (Some 0x0100000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039993.624 units remaining) + [ (Pair (Pair 0x0100000000000000000000000000000000000000000000000000000000000000 + 0x0000000000000000000000000000000000000000000000000000000000000000) + None) ] + - location: 10 (remaining gas: 1039993.614 units remaining) + [ (Pair 0x0100000000000000000000000000000000000000000000000000000000000000 + 0x0000000000000000000000000000000000000000000000000000000000000000) @parameter ] + - location: 11 (remaining gas: 1039993.604 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 + 0x0000000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039993.459 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 13 (remaining gas: 1039993.444 units remaining) + [ (Some 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 14 (remaining gas: 1039993.429 units remaining) + [ {} + (Some 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 16 (remaining gas: 1039993.414 units remaining) + [ (Pair {} + (Some 0x0100000000000000000000000000000000000000000000000000000000000000)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x010000 0x00-(Some 0x010.0e44fc6f40.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x010000 0x00-(Some 0x010.0e44fc6f40.out new file mode 100644 index 000000000000..a811d7448661 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x010000 0x00-(Some 0x010.0e44fc6f40.out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x010000 0x00-(Some 0x0100000000000000000000000000000000000000000000000000000000000000)] + +storage + (Some 0x0100000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039993.624 units remaining) + [ (Pair (Pair 0x0100000000000000000000000000000000000000000000000000000000000000 + 0x0000000000000000000000000000000000000000000000000000000000000000) + None) ] + - location: 10 (remaining gas: 1039993.614 units remaining) + [ (Pair 0x0100000000000000000000000000000000000000000000000000000000000000 + 0x0000000000000000000000000000000000000000000000000000000000000000) @parameter ] + - location: 11 (remaining gas: 1039993.604 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 + 0x0000000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039993.459 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 13 (remaining gas: 1039993.444 units remaining) + [ (Some 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 14 (remaining gas: 1039993.429 units remaining) + [ {} + (Some 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 16 (remaining gas: 1039993.414 units remaining) + [ (Pair {} + (Some 0x0100000000000000000000000000000000000000000000000000000000000000)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x010000 0x010000-(Some 0.7e0ed229a3.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x010000 0x010000-(Some 0.7e0ed229a3.out new file mode 100644 index 000000000000..0c5e620c8a36 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x010000 0x010000-(Some 0.7e0ed229a3.out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[add_bls12_381_fr.tz-None-Pair 0x010000 0x010000-(Some 0x0200000000000000000000000000000000000000000000000000000000000000)] + +storage + (Some 0x0200000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039993.624 units remaining) + [ (Pair (Pair 0x0100000000000000000000000000000000000000000000000000000000000000 + 0x0100000000000000000000000000000000000000000000000000000000000000) + None) ] + - location: 10 (remaining gas: 1039993.614 units remaining) + [ (Pair 0x0100000000000000000000000000000000000000000000000000000000000000 + 0x0100000000000000000000000000000000000000000000000000000000000000) @parameter ] + - location: 11 (remaining gas: 1039993.604 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 + 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039993.459 units remaining) + [ 0x0200000000000000000000000000000000000000000000000000000000000000 ] + - location: 13 (remaining gas: 1039993.444 units remaining) + [ (Some 0x0200000000000000000000000000000000000000000000000000000000000000) ] + - location: 14 (remaining gas: 1039993.429 units remaining) + [ {} + (Some 0x0200000000000000000000000000000000000000000000000000000000000000) ] + - location: 16 (remaining gas: 1039993.414 units remaining) + [ (Pair {} + (Some 0x0200000000000000000000000000000000000000000000000000000000000000)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair -100 100)-(Some \"1970.7c1b1e4e5b.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair -100 100)-(Some \"1970.7c1b1e4e5b.out" new file mode 100644 index 000000000000..6290442d5431 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair -100 100)-(Some \"1970.7c1b1e4e5b.out" @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair -100 100)-(Some "1970-01-01T00:00:00Z")] + +storage + (Some "1970-01-01T00:00:00Z") +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039991.453 units remaining) + [ (Pair (Pair -100 "1970-01-01T00:01:40Z") None) ] + - location: 10 (remaining gas: 1039991.443 units remaining) + [ (Pair -100 "1970-01-01T00:01:40Z") @parameter ] + - location: 11 (remaining gas: 1039991.433 units remaining) + [ (Pair -100 "1970-01-01T00:01:40Z") @parameter + (Pair -100 "1970-01-01T00:01:40Z") @parameter ] + - location: 12 (remaining gas: 1039991.423 units remaining) + [ -100 + (Pair -100 "1970-01-01T00:01:40Z") @parameter ] + - location: 13 (remaining gas: 1039991.408 units remaining) + [ (Pair -100 "1970-01-01T00:01:40Z") @parameter ] + - location: 15 (remaining gas: 1039991.398 units remaining) + [ "1970-01-01T00:01:40Z" ] + - location: 13 (remaining gas: 1039991.368 units remaining) + [ -100 + "1970-01-01T00:01:40Z" ] + - location: 16 (remaining gas: 1039991.333 units remaining) + [ "1970-01-01T00:00:00Z" ] + - location: 17 (remaining gas: 1039991.318 units remaining) + [ (Some "1970-01-01T00:00:00Z") ] + - location: 18 (remaining gas: 1039991.303 units remaining) + [ {} + (Some "1970-01-01T00:00:00Z") ] + - location: 20 (remaining gas: 1039991.288 units remaining) + [ (Pair {} (Some "1970-01-01T00:00:00Z")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair 0 \"1970-01-01T00:00:0.528ed42c01.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair 0 \"1970-01-01T00:00:0.528ed42c01.out" new file mode 100644 index 000000000000..496874a352e1 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair 0 \"1970-01-01T00:00:0.528ed42c01.out" @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair 0 "1970-01-01T00:00:00Z")-(Some "1970-01-01T00:00:00Z")] + +storage + (Some "1970-01-01T00:00:00Z") +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039991.333 units remaining) + [ (Pair (Pair 0 "1970-01-01T00:00:00Z") None) ] + - location: 10 (remaining gas: 1039991.323 units remaining) + [ (Pair 0 "1970-01-01T00:00:00Z") @parameter ] + - location: 11 (remaining gas: 1039991.313 units remaining) + [ (Pair 0 "1970-01-01T00:00:00Z") @parameter + (Pair 0 "1970-01-01T00:00:00Z") @parameter ] + - location: 12 (remaining gas: 1039991.303 units remaining) + [ 0 + (Pair 0 "1970-01-01T00:00:00Z") @parameter ] + - location: 13 (remaining gas: 1039991.288 units remaining) + [ (Pair 0 "1970-01-01T00:00:00Z") @parameter ] + - location: 15 (remaining gas: 1039991.278 units remaining) + [ "1970-01-01T00:00:00Z" ] + - location: 13 (remaining gas: 1039991.248 units remaining) + [ 0 + "1970-01-01T00:00:00Z" ] + - location: 16 (remaining gas: 1039991.213 units remaining) + [ "1970-01-01T00:00:00Z" ] + - location: 17 (remaining gas: 1039991.198 units remaining) + [ (Some "1970-01-01T00:00:00Z") ] + - location: 18 (remaining gas: 1039991.183 units remaining) + [ {} + (Some "1970-01-01T00:00:00Z") ] + - location: 20 (remaining gas: 1039991.168 units remaining) + [ (Pair {} (Some "1970-01-01T00:00:00Z")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair 100 100)-(Some \"1970-.6566111ad2.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair 100 100)-(Some \"1970-.6566111ad2.out" new file mode 100644 index 000000000000..5b80b2eb432a --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair 100 100)-(Some \"1970-.6566111ad2.out" @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[add_delta_timestamp.tz-None-(Pair 100 100)-(Some "1970-01-01T00:03:20Z")] + +storage + (Some "1970-01-01T00:03:20Z") +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039991.453 units remaining) + [ (Pair (Pair 100 "1970-01-01T00:01:40Z") None) ] + - location: 10 (remaining gas: 1039991.443 units remaining) + [ (Pair 100 "1970-01-01T00:01:40Z") @parameter ] + - location: 11 (remaining gas: 1039991.433 units remaining) + [ (Pair 100 "1970-01-01T00:01:40Z") @parameter + (Pair 100 "1970-01-01T00:01:40Z") @parameter ] + - location: 12 (remaining gas: 1039991.423 units remaining) + [ 100 + (Pair 100 "1970-01-01T00:01:40Z") @parameter ] + - location: 13 (remaining gas: 1039991.408 units remaining) + [ (Pair 100 "1970-01-01T00:01:40Z") @parameter ] + - location: 15 (remaining gas: 1039991.398 units remaining) + [ "1970-01-01T00:01:40Z" ] + - location: 13 (remaining gas: 1039991.368 units remaining) + [ 100 + "1970-01-01T00:01:40Z" ] + - location: 16 (remaining gas: 1039991.333 units remaining) + [ "1970-01-01T00:03:20Z" ] + - location: 17 (remaining gas: 1039991.318 units remaining) + [ (Some "1970-01-01T00:03:20Z") ] + - location: 18 (remaining gas: 1039991.303 units remaining) + [ {} + (Some "1970-01-01T00:03:20Z") ] + - location: 20 (remaining gas: 1039991.288 units remaining) + [ (Pair {} (Some "1970-01-01T00:03:20Z")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair \"1970-01-01T00:00:00Z.72c424f3da.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair \"1970-01-01T00:00:00Z.72c424f3da.out" new file mode 100644 index 000000000000..c49a1db00e76 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair \"1970-01-01T00:00:00Z.72c424f3da.out" @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair "1970-01-01T00:00:00Z" 0)-(Some "1970-01-01T00:00:00Z")] + +storage + (Some "1970-01-01T00:00:00Z") +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039991.333 units remaining) + [ (Pair (Pair "1970-01-01T00:00:00Z" 0) None) ] + - location: 10 (remaining gas: 1039991.323 units remaining) + [ (Pair "1970-01-01T00:00:00Z" 0) @parameter ] + - location: 11 (remaining gas: 1039991.313 units remaining) + [ (Pair "1970-01-01T00:00:00Z" 0) @parameter + (Pair "1970-01-01T00:00:00Z" 0) @parameter ] + - location: 12 (remaining gas: 1039991.303 units remaining) + [ "1970-01-01T00:00:00Z" + (Pair "1970-01-01T00:00:00Z" 0) @parameter ] + - location: 13 (remaining gas: 1039991.288 units remaining) + [ (Pair "1970-01-01T00:00:00Z" 0) @parameter ] + - location: 15 (remaining gas: 1039991.278 units remaining) + [ 0 ] + - location: 13 (remaining gas: 1039991.248 units remaining) + [ "1970-01-01T00:00:00Z" + 0 ] + - location: 16 (remaining gas: 1039991.213 units remaining) + [ "1970-01-01T00:00:00Z" ] + - location: 17 (remaining gas: 1039991.198 units remaining) + [ (Some "1970-01-01T00:00:00Z") ] + - location: 18 (remaining gas: 1039991.183 units remaining) + [ {} + (Some "1970-01-01T00:00:00Z") ] + - location: 20 (remaining gas: 1039991.168 units remaining) + [ (Pair {} (Some "1970-01-01T00:00:00Z")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair 100 -100)-(Some \"1970.7c4b12e9aa.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair 100 -100)-(Some \"1970.7c4b12e9aa.out" new file mode 100644 index 000000000000..bc2bb37df27f --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair 100 -100)-(Some \"1970.7c4b12e9aa.out" @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair 100 -100)-(Some "1970-01-01T00:00:00Z")] + +storage + (Some "1970-01-01T00:00:00Z") +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039991.453 units remaining) + [ (Pair (Pair "1970-01-01T00:01:40Z" -100) None) ] + - location: 10 (remaining gas: 1039991.443 units remaining) + [ (Pair "1970-01-01T00:01:40Z" -100) @parameter ] + - location: 11 (remaining gas: 1039991.433 units remaining) + [ (Pair "1970-01-01T00:01:40Z" -100) @parameter + (Pair "1970-01-01T00:01:40Z" -100) @parameter ] + - location: 12 (remaining gas: 1039991.423 units remaining) + [ "1970-01-01T00:01:40Z" + (Pair "1970-01-01T00:01:40Z" -100) @parameter ] + - location: 13 (remaining gas: 1039991.408 units remaining) + [ (Pair "1970-01-01T00:01:40Z" -100) @parameter ] + - location: 15 (remaining gas: 1039991.398 units remaining) + [ -100 ] + - location: 13 (remaining gas: 1039991.368 units remaining) + [ "1970-01-01T00:01:40Z" + -100 ] + - location: 16 (remaining gas: 1039991.333 units remaining) + [ "1970-01-01T00:00:00Z" ] + - location: 17 (remaining gas: 1039991.318 units remaining) + [ (Some "1970-01-01T00:00:00Z") ] + - location: 18 (remaining gas: 1039991.303 units remaining) + [ {} + (Some "1970-01-01T00:00:00Z") ] + - location: 20 (remaining gas: 1039991.288 units remaining) + [ (Pair {} (Some "1970-01-01T00:00:00Z")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair 100 100)-(Some \"1970-.af32743640.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair 100 100)-(Some \"1970-.af32743640.out" new file mode 100644 index 000000000000..1dbd987cbe0d --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair 100 100)-(Some \"1970-.af32743640.out" @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[add_timestamp_delta.tz-None-(Pair 100 100)-(Some "1970-01-01T00:03:20Z")] + +storage + (Some "1970-01-01T00:03:20Z") +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039991.453 units remaining) + [ (Pair (Pair "1970-01-01T00:01:40Z" 100) None) ] + - location: 10 (remaining gas: 1039991.443 units remaining) + [ (Pair "1970-01-01T00:01:40Z" 100) @parameter ] + - location: 11 (remaining gas: 1039991.433 units remaining) + [ (Pair "1970-01-01T00:01:40Z" 100) @parameter + (Pair "1970-01-01T00:01:40Z" 100) @parameter ] + - location: 12 (remaining gas: 1039991.423 units remaining) + [ "1970-01-01T00:01:40Z" + (Pair "1970-01-01T00:01:40Z" 100) @parameter ] + - location: 13 (remaining gas: 1039991.408 units remaining) + [ (Pair "1970-01-01T00:01:40Z" 100) @parameter ] + - location: 15 (remaining gas: 1039991.398 units remaining) + [ 100 ] + - location: 13 (remaining gas: 1039991.368 units remaining) + [ "1970-01-01T00:01:40Z" + 100 ] + - location: 16 (remaining gas: 1039991.333 units remaining) + [ "1970-01-01T00:03:20Z" ] + - location: 17 (remaining gas: 1039991.318 units remaining) + [ (Some "1970-01-01T00:03:20Z") ] + - location: 18 (remaining gas: 1039991.303 units remaining) + [ {} + (Some "1970-01-01T00:03:20Z") ] + - location: 20 (remaining gas: 1039991.288 units remaining) + [ (Pair {} (Some "1970-01-01T00:03:20Z")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[address.tz-None-\"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5\"-.f9045c3a04.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[address.tz-None-\"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5\"-.f9045c3a04.out" new file mode 100644 index 000000000000..36a98fe1dbb2 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[address.tz-None-\"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5\"-.f9045c3a04.out" @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[address.tz-None-"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5"-(Some "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5")] + +storage + (Some "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039940.689 units remaining) + [ (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" None) ] + - location: 9 (remaining gas: 1039940.679 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" @parameter ] + - location: 10 (remaining gas: 1039940.669 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" @parameter.address ] + - location: 11 (remaining gas: 1039940.654 units remaining) + [ (Some "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 12 (remaining gas: 1039940.639 units remaining) + [ {} + (Some "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 14 (remaining gas: 1039940.624 units remaining) + [ (Pair {} (Some "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5")) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair False False)-(Some False)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair False False)-(Some False)].out new file mode 100644 index 000000000000..b33e33f65671 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair False False)-(Some False)].out @@ -0,0 +1,31 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair False False)-(Some False)] + +storage + (Some False) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039992.203 units remaining) + [ (Pair (Pair False False) None) ] + - location: 10 (remaining gas: 1039992.193 units remaining) + [ (Pair False False) @param ] + - location: 11 (remaining gas: 1039992.183 units remaining) + [ False + False ] + - location: 12 (remaining gas: 1039992.163 units remaining) + [ False @and ] + - location: 13 (remaining gas: 1039992.148 units remaining) + [ (Some False) @res ] + - location: 14 (remaining gas: 1039992.133 units remaining) + [ {} @noop + (Some False) @res ] + - location: 16 (remaining gas: 1039992.118 units remaining) + [ (Pair {} (Some False)) ] + - location: 17 (remaining gas: 1039992.108 units remaining) + [ {} @x + (Some False) @y ] + - location: 18 (remaining gas: 1039992.093 units remaining) + [ (Pair {} (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair False True)-(Some False)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair False True)-(Some False)].out new file mode 100644 index 000000000000..3c6bacce070a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair False True)-(Some False)].out @@ -0,0 +1,31 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair False True)-(Some False)] + +storage + (Some False) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039992.203 units remaining) + [ (Pair (Pair False True) None) ] + - location: 10 (remaining gas: 1039992.193 units remaining) + [ (Pair False True) @param ] + - location: 11 (remaining gas: 1039992.183 units remaining) + [ False + True ] + - location: 12 (remaining gas: 1039992.163 units remaining) + [ False @and ] + - location: 13 (remaining gas: 1039992.148 units remaining) + [ (Some False) @res ] + - location: 14 (remaining gas: 1039992.133 units remaining) + [ {} @noop + (Some False) @res ] + - location: 16 (remaining gas: 1039992.118 units remaining) + [ (Pair {} (Some False)) ] + - location: 17 (remaining gas: 1039992.108 units remaining) + [ {} @x + (Some False) @y ] + - location: 18 (remaining gas: 1039992.093 units remaining) + [ (Pair {} (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair True False)-(Some False)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair True False)-(Some False)].out new file mode 100644 index 000000000000..a84494efcab4 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair True False)-(Some False)].out @@ -0,0 +1,31 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair True False)-(Some False)] + +storage + (Some False) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039992.203 units remaining) + [ (Pair (Pair True False) None) ] + - location: 10 (remaining gas: 1039992.193 units remaining) + [ (Pair True False) @param ] + - location: 11 (remaining gas: 1039992.183 units remaining) + [ True + False ] + - location: 12 (remaining gas: 1039992.163 units remaining) + [ False @and ] + - location: 13 (remaining gas: 1039992.148 units remaining) + [ (Some False) @res ] + - location: 14 (remaining gas: 1039992.133 units remaining) + [ {} @noop + (Some False) @res ] + - location: 16 (remaining gas: 1039992.118 units remaining) + [ (Pair {} (Some False)) ] + - location: 17 (remaining gas: 1039992.108 units remaining) + [ {} @x + (Some False) @y ] + - location: 18 (remaining gas: 1039992.093 units remaining) + [ (Pair {} (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair True True)-(Some True)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair True True)-(Some True)].out new file mode 100644 index 000000000000..cff637e3e280 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair True True)-(Some True)].out @@ -0,0 +1,31 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[and.tz-None-(Pair True True)-(Some True)] + +storage + (Some True) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039992.203 units remaining) + [ (Pair (Pair True True) None) ] + - location: 10 (remaining gas: 1039992.193 units remaining) + [ (Pair True True) @param ] + - location: 11 (remaining gas: 1039992.183 units remaining) + [ True + True ] + - location: 12 (remaining gas: 1039992.163 units remaining) + [ True @and ] + - location: 13 (remaining gas: 1039992.148 units remaining) + [ (Some True) @res ] + - location: 14 (remaining gas: 1039992.133 units remaining) + [ {} @noop + (Some True) @res ] + - location: 16 (remaining gas: 1039992.118 units remaining) + [ (Pair {} (Some True)) ] + - location: 17 (remaining gas: 1039992.108 units remaining) + [ {} @x + (Some True) @y ] + - location: 18 (remaining gas: 1039992.093 units remaining) + [ (Pair {} (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_binary.tz-Unit-Unit-Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_binary.tz-Unit-Unit-Unit].out new file mode 100644 index 000000000000..1255a443bffc --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_binary.tz-Unit-Unit-Unit].out @@ -0,0 +1,93 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[and_binary.tz-Unit-Unit-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039961.891 units remaining) + [ (Pair Unit Unit) ] + - location: 7 (remaining gas: 1039961.881 units remaining) + [ ] + - location: 8 (remaining gas: 1039961.871 units remaining) + [ 5 ] + - location: 11 (remaining gas: 1039961.861 units remaining) + [ 6 + 5 ] + - location: 14 (remaining gas: 1039961.826 units remaining) + [ 4 ] + - location: 15 (remaining gas: 1039961.816 units remaining) + [ 4 + 4 ] + - location: 20 (remaining gas: 1039961.781 units remaining) + [ 0 ] + - location: 21 (remaining gas: 1039961.766 units remaining) + [ True ] + - location: 22 (remaining gas: 1039961.756 units remaining) + [ ] + - location: 22 (remaining gas: 1039961.741 units remaining) + [ ] + - location: 28 (remaining gas: 1039961.731 units remaining) + [ 6 ] + - location: 31 (remaining gas: 1039961.721 units remaining) + [ 5 + 6 ] + - location: 34 (remaining gas: 1039961.686 units remaining) + [ 4 ] + - location: 35 (remaining gas: 1039961.676 units remaining) + [ 4 + 4 ] + - location: 40 (remaining gas: 1039961.641 units remaining) + [ 0 ] + - location: 41 (remaining gas: 1039961.626 units remaining) + [ True ] + - location: 42 (remaining gas: 1039961.616 units remaining) + [ ] + - location: 42 (remaining gas: 1039961.601 units remaining) + [ ] + - location: 48 (remaining gas: 1039961.591 units remaining) + [ 12 ] + - location: 51 (remaining gas: 1039961.581 units remaining) + [ -1 + 12 ] + - location: 54 (remaining gas: 1039961.546 units remaining) + [ 12 ] + - location: 55 (remaining gas: 1039961.536 units remaining) + [ 12 + 12 ] + - location: 60 (remaining gas: 1039961.501 units remaining) + [ 0 ] + - location: 61 (remaining gas: 1039961.486 units remaining) + [ True ] + - location: 62 (remaining gas: 1039961.476 units remaining) + [ ] + - location: 62 (remaining gas: 1039961.461 units remaining) + [ ] + - location: 68 (remaining gas: 1039961.451 units remaining) + [ 12 ] + - location: 71 (remaining gas: 1039961.441 units remaining) + [ -5 + 12 ] + - location: 74 (remaining gas: 1039961.406 units remaining) + [ 8 ] + - location: 75 (remaining gas: 1039961.396 units remaining) + [ 8 + 8 ] + - location: 80 (remaining gas: 1039961.361 units remaining) + [ 0 ] + - location: 81 (remaining gas: 1039961.346 units remaining) + [ True ] + - location: 82 (remaining gas: 1039961.336 units remaining) + [ ] + - location: 82 (remaining gas: 1039961.321 units remaining) + [ ] + - location: 88 (remaining gas: 1039961.311 units remaining) + [ Unit ] + - location: 89 (remaining gas: 1039961.296 units remaining) + [ {} @noop + Unit ] + - location: 91 (remaining gas: 1039961.281 units remaining) + [ (Pair {} Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair False False)-False].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair False False)-False].out new file mode 100644 index 000000000000..be700b464e0b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair False False)-False].out @@ -0,0 +1,24 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair False False)-False] + +storage + False +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039994.524 units remaining) + [ (Pair (Pair False False) False) ] + - location: 9 (remaining gas: 1039994.514 units remaining) + [ (Pair False False) @parameter ] + - location: 10 (remaining gas: 1039994.504 units remaining) + [ False + False ] + - location: 11 (remaining gas: 1039994.484 units remaining) + [ False @and ] + - location: 12 (remaining gas: 1039994.469 units remaining) + [ {} @noop + False @and ] + - location: 14 (remaining gas: 1039994.454 units remaining) + [ (Pair {} False) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair False True)-False].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair False True)-False].out new file mode 100644 index 000000000000..e88189ef3e09 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair False True)-False].out @@ -0,0 +1,24 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair False True)-False] + +storage + False +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039994.524 units remaining) + [ (Pair (Pair False True) False) ] + - location: 9 (remaining gas: 1039994.514 units remaining) + [ (Pair False True) @parameter ] + - location: 10 (remaining gas: 1039994.504 units remaining) + [ False + True ] + - location: 11 (remaining gas: 1039994.484 units remaining) + [ False @and ] + - location: 12 (remaining gas: 1039994.469 units remaining) + [ {} @noop + False @and ] + - location: 14 (remaining gas: 1039994.454 units remaining) + [ (Pair {} False) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair True False)-False].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair True False)-False].out new file mode 100644 index 000000000000..cd7c513c067c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair True False)-False].out @@ -0,0 +1,24 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair True False)-False] + +storage + False +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039994.524 units remaining) + [ (Pair (Pair True False) False) ] + - location: 9 (remaining gas: 1039994.514 units remaining) + [ (Pair True False) @parameter ] + - location: 10 (remaining gas: 1039994.504 units remaining) + [ True + False ] + - location: 11 (remaining gas: 1039994.484 units remaining) + [ False @and ] + - location: 12 (remaining gas: 1039994.469 units remaining) + [ {} @noop + False @and ] + - location: 14 (remaining gas: 1039994.454 units remaining) + [ (Pair {} False) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair True True)-True].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair True True)-True].out new file mode 100644 index 000000000000..756488f4af18 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair True True)-True].out @@ -0,0 +1,24 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[and_logical_1.tz-False-(Pair True True)-True] + +storage + True +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039994.524 units remaining) + [ (Pair (Pair True True) False) ] + - location: 9 (remaining gas: 1039994.514 units remaining) + [ (Pair True True) @parameter ] + - location: 10 (remaining gas: 1039994.504 units remaining) + [ True + True ] + - location: 11 (remaining gas: 1039994.484 units remaining) + [ True @and ] + - location: 12 (remaining gas: 1039994.469 units remaining) + [ {} @noop + True @and ] + - location: 14 (remaining gas: 1039994.454 units remaining) + [ (Pair {} True) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[balance.tz-111-Unit-4000000000000].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[balance.tz-111-Unit-4000000000000].out new file mode 100644 index 000000000000..14bbafed9a1f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[balance.tz-111-Unit-4000000000000].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[balance.tz-111-Unit-4000000000000] + +storage + 4000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.668 units remaining) + [ (Pair Unit 111) ] + - location: 7 (remaining gas: 1039995.658 units remaining) + [ ] + - location: 8 (remaining gas: 1039775.642 units remaining) + [ 4000000000000 @balance ] + - location: 9 (remaining gas: 1039775.627 units remaining) + [ {} + 4000000000000 @balance ] + - location: 11 (remaining gas: 1039775.612 units remaining) + [ (Pair {} 4000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair 4 (S.2292d6ce17.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair 4 (S.2292d6ce17.out new file mode 100644 index 000000000000..ff40b9161556 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair 4 (S.2292d6ce17.out @@ -0,0 +1,43 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair 4 (Some False))1] + +storage + (Pair 4 (Some False)) +emitted operations + +big_map diff + New map(4) of type (big_map nat nat) + Set map(4)[0] to 1 +trace + - location: 12 (remaining gas: 1039988.632 units remaining) + [ (Pair 1 { Elt 0 1 } None) ] + - location: 12 (remaining gas: 1039988.622 units remaining) + [ 1 @parameter + (Pair { Elt 0 1 } None) @storage ] + - location: 13 (remaining gas: 1039988.607 units remaining) + [ (Pair { Elt 0 1 } None) @storage ] + - location: 15 (remaining gas: 1039988.597 units remaining) + [ { Elt 0 1 } ] + - location: 16 (remaining gas: 1039988.587 units remaining) + [ { Elt 0 1 } + { Elt 0 1 } ] + - location: 13 (remaining gas: 1039988.557 units remaining) + [ 1 @parameter + { Elt 0 1 } + { Elt 0 1 } ] + - location: 17 (remaining gas: 1039987.605 units remaining) + [ False + { Elt 0 1 } ] + - location: 18 (remaining gas: 1039987.590 units remaining) + [ (Some False) + { Elt 0 1 } ] + - location: 19 (remaining gas: 1039987.580 units remaining) + [ { Elt 0 1 } + (Some False) ] + - location: 20 (remaining gas: 1039987.565 units remaining) + [ (Pair { Elt 0 1 } (Some False)) ] + - location: 21 (remaining gas: 1039987.550 units remaining) + [ {} + (Pair { Elt 0 1 } (Some False)) ] + - location: 23 (remaining gas: 1039987.535 units remaining) + [ (Pair {} { Elt 0 1 } (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair 4 (S.dda583f5e9.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair 4 (S.dda583f5e9.out new file mode 100644 index 000000000000..0ce6144039a4 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair 4 (S.dda583f5e9.out @@ -0,0 +1,43 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair 4 (Some False))0] + +storage + (Pair 4 (Some False)) +emitted operations + +big_map diff + New map(4) of type (big_map nat nat) + Set map(4)[0] to 1 +trace + - location: 12 (remaining gas: 1039988.632 units remaining) + [ (Pair 1 { Elt 0 1 } None) ] + - location: 12 (remaining gas: 1039988.622 units remaining) + [ 1 @parameter + (Pair { Elt 0 1 } None) @storage ] + - location: 13 (remaining gas: 1039988.607 units remaining) + [ (Pair { Elt 0 1 } None) @storage ] + - location: 15 (remaining gas: 1039988.597 units remaining) + [ { Elt 0 1 } ] + - location: 16 (remaining gas: 1039988.587 units remaining) + [ { Elt 0 1 } + { Elt 0 1 } ] + - location: 13 (remaining gas: 1039988.557 units remaining) + [ 1 @parameter + { Elt 0 1 } + { Elt 0 1 } ] + - location: 17 (remaining gas: 1039987.605 units remaining) + [ False + { Elt 0 1 } ] + - location: 18 (remaining gas: 1039987.590 units remaining) + [ (Some False) + { Elt 0 1 } ] + - location: 19 (remaining gas: 1039987.580 units remaining) + [ { Elt 0 1 } + (Some False) ] + - location: 20 (remaining gas: 1039987.565 units remaining) + [ (Pair { Elt 0 1 } (Some False)) ] + - location: 21 (remaining gas: 1039987.550 units remaining) + [ {} + (Pair { Elt 0 1 } (Some False)) ] + - location: 23 (remaining gas: 1039987.535 units remaining) + [ (Pair {} { Elt 0 1 } (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair 4 (S.6d753598ba.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair 4 (S.6d753598ba.out new file mode 100644 index 000000000000..562333446488 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair 4 (S.6d753598ba.out @@ -0,0 +1,43 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair 4 (Some True))1] + +storage + (Pair 4 (Some True)) +emitted operations + +big_map diff + New map(4) of type (big_map nat nat) + Set map(4)[1] to 0 +trace + - location: 12 (remaining gas: 1039988.632 units remaining) + [ (Pair 1 { Elt 1 0 } None) ] + - location: 12 (remaining gas: 1039988.622 units remaining) + [ 1 @parameter + (Pair { Elt 1 0 } None) @storage ] + - location: 13 (remaining gas: 1039988.607 units remaining) + [ (Pair { Elt 1 0 } None) @storage ] + - location: 15 (remaining gas: 1039988.597 units remaining) + [ { Elt 1 0 } ] + - location: 16 (remaining gas: 1039988.587 units remaining) + [ { Elt 1 0 } + { Elt 1 0 } ] + - location: 13 (remaining gas: 1039988.557 units remaining) + [ 1 @parameter + { Elt 1 0 } + { Elt 1 0 } ] + - location: 17 (remaining gas: 1039987.605 units remaining) + [ True + { Elt 1 0 } ] + - location: 18 (remaining gas: 1039987.590 units remaining) + [ (Some True) + { Elt 1 0 } ] + - location: 19 (remaining gas: 1039987.580 units remaining) + [ { Elt 1 0 } + (Some True) ] + - location: 20 (remaining gas: 1039987.565 units remaining) + [ (Pair { Elt 1 0 } (Some True)) ] + - location: 21 (remaining gas: 1039987.550 units remaining) + [ {} + (Pair { Elt 1 0 } (Some True)) ] + - location: 23 (remaining gas: 1039987.535 units remaining) + [ (Pair {} { Elt 1 0 } (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair 4 (S.73700321f8.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair 4 (S.73700321f8.out new file mode 100644 index 000000000000..b600a3319b5e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair 4 (S.73700321f8.out @@ -0,0 +1,43 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair 4 (Some True))0] + +storage + (Pair 4 (Some True)) +emitted operations + +big_map diff + New map(4) of type (big_map nat nat) + Set map(4)[1] to 0 +trace + - location: 12 (remaining gas: 1039988.632 units remaining) + [ (Pair 1 { Elt 1 0 } None) ] + - location: 12 (remaining gas: 1039988.622 units remaining) + [ 1 @parameter + (Pair { Elt 1 0 } None) @storage ] + - location: 13 (remaining gas: 1039988.607 units remaining) + [ (Pair { Elt 1 0 } None) @storage ] + - location: 15 (remaining gas: 1039988.597 units remaining) + [ { Elt 1 0 } ] + - location: 16 (remaining gas: 1039988.587 units remaining) + [ { Elt 1 0 } + { Elt 1 0 } ] + - location: 13 (remaining gas: 1039988.557 units remaining) + [ 1 @parameter + { Elt 1 0 } + { Elt 1 0 } ] + - location: 17 (remaining gas: 1039987.605 units remaining) + [ True + { Elt 1 0 } ] + - location: 18 (remaining gas: 1039987.590 units remaining) + [ (Some True) + { Elt 1 0 } ] + - location: 19 (remaining gas: 1039987.580 units remaining) + [ { Elt 1 0 } + (Some True) ] + - location: 20 (remaining gas: 1039987.565 units remaining) + [ (Pair { Elt 1 0 } (Some True)) ] + - location: 21 (remaining gas: 1039987.550 units remaining) + [ {} + (Pair { Elt 1 0 } (Some True)) ] + - location: 23 (remaining gas: 1039987.535 units remaining) + [ (Pair {} { Elt 1 0 } (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1.1182eca937.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1.1182eca937.out new file mode 100644 index 000000000000..92b234be606c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1.1182eca937.out @@ -0,0 +1,44 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1-(Pair 4 (Some True))0] + +storage + (Pair 4 (Some True)) +emitted operations + +big_map diff + New map(4) of type (big_map nat nat) + Set map(4)[1] to 4 + Set map(4)[2] to 11 +trace + - location: 12 (remaining gas: 1039987.422 units remaining) + [ (Pair 1 { Elt 1 4 ; Elt 2 11 } None) ] + - location: 12 (remaining gas: 1039987.412 units remaining) + [ 1 @parameter + (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 13 (remaining gas: 1039987.397 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 15 (remaining gas: 1039987.387 units remaining) + [ { Elt 1 4 ; Elt 2 11 } ] + - location: 16 (remaining gas: 1039987.377 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 13 (remaining gas: 1039987.347 units remaining) + [ 1 @parameter + { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 17 (remaining gas: 1039986.394 units remaining) + [ True + { Elt 1 4 ; Elt 2 11 } ] + - location: 18 (remaining gas: 1039986.379 units remaining) + [ (Some True) + { Elt 1 4 ; Elt 2 11 } ] + - location: 19 (remaining gas: 1039986.369 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + (Some True) ] + - location: 20 (remaining gas: 1039986.354 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) ] + - location: 21 (remaining gas: 1039986.339 units remaining) + [ {} + (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) ] + - location: 23 (remaining gas: 1039986.324 units remaining) + [ (Pair {} { Elt 1 4 ; Elt 2 11 } (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1.2ea67af009.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1.2ea67af009.out new file mode 100644 index 000000000000..591a3ec2cb99 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1.2ea67af009.out @@ -0,0 +1,44 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1-(Pair 4 (Some True))1] + +storage + (Pair 4 (Some True)) +emitted operations + +big_map diff + New map(4) of type (big_map nat nat) + Set map(4)[1] to 4 + Set map(4)[2] to 11 +trace + - location: 12 (remaining gas: 1039987.422 units remaining) + [ (Pair 1 { Elt 1 4 ; Elt 2 11 } None) ] + - location: 12 (remaining gas: 1039987.412 units remaining) + [ 1 @parameter + (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 13 (remaining gas: 1039987.397 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 15 (remaining gas: 1039987.387 units remaining) + [ { Elt 1 4 ; Elt 2 11 } ] + - location: 16 (remaining gas: 1039987.377 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 13 (remaining gas: 1039987.347 units remaining) + [ 1 @parameter + { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 17 (remaining gas: 1039986.394 units remaining) + [ True + { Elt 1 4 ; Elt 2 11 } ] + - location: 18 (remaining gas: 1039986.379 units remaining) + [ (Some True) + { Elt 1 4 ; Elt 2 11 } ] + - location: 19 (remaining gas: 1039986.369 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + (Some True) ] + - location: 20 (remaining gas: 1039986.354 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) ] + - location: 21 (remaining gas: 1039986.339 units remaining) + [ {} + (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) ] + - location: 23 (remaining gas: 1039986.324 units remaining) + [ (Pair {} { Elt 1 4 ; Elt 2 11 } (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2.1eead33885.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2.1eead33885.out new file mode 100644 index 000000000000..331908e2740b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2.1eead33885.out @@ -0,0 +1,44 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2-(Pair 4 (Some True))1] + +storage + (Pair 4 (Some True)) +emitted operations + +big_map diff + New map(4) of type (big_map nat nat) + Set map(4)[1] to 4 + Set map(4)[2] to 11 +trace + - location: 12 (remaining gas: 1039987.422 units remaining) + [ (Pair 2 { Elt 1 4 ; Elt 2 11 } None) ] + - location: 12 (remaining gas: 1039987.412 units remaining) + [ 2 @parameter + (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 13 (remaining gas: 1039987.397 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 15 (remaining gas: 1039987.387 units remaining) + [ { Elt 1 4 ; Elt 2 11 } ] + - location: 16 (remaining gas: 1039987.377 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 13 (remaining gas: 1039987.347 units remaining) + [ 2 @parameter + { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 17 (remaining gas: 1039986.394 units remaining) + [ True + { Elt 1 4 ; Elt 2 11 } ] + - location: 18 (remaining gas: 1039986.379 units remaining) + [ (Some True) + { Elt 1 4 ; Elt 2 11 } ] + - location: 19 (remaining gas: 1039986.369 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + (Some True) ] + - location: 20 (remaining gas: 1039986.354 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) ] + - location: 21 (remaining gas: 1039986.339 units remaining) + [ {} + (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) ] + - location: 23 (remaining gas: 1039986.324 units remaining) + [ (Pair {} { Elt 1 4 ; Elt 2 11 } (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2.47f55c94c8.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2.47f55c94c8.out new file mode 100644 index 000000000000..5aaf5b5ae919 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2.47f55c94c8.out @@ -0,0 +1,44 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2-(Pair 4 (Some True))0] + +storage + (Pair 4 (Some True)) +emitted operations + +big_map diff + New map(4) of type (big_map nat nat) + Set map(4)[1] to 4 + Set map(4)[2] to 11 +trace + - location: 12 (remaining gas: 1039987.422 units remaining) + [ (Pair 2 { Elt 1 4 ; Elt 2 11 } None) ] + - location: 12 (remaining gas: 1039987.412 units remaining) + [ 2 @parameter + (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 13 (remaining gas: 1039987.397 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 15 (remaining gas: 1039987.387 units remaining) + [ { Elt 1 4 ; Elt 2 11 } ] + - location: 16 (remaining gas: 1039987.377 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 13 (remaining gas: 1039987.347 units remaining) + [ 2 @parameter + { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 17 (remaining gas: 1039986.394 units remaining) + [ True + { Elt 1 4 ; Elt 2 11 } ] + - location: 18 (remaining gas: 1039986.379 units remaining) + [ (Some True) + { Elt 1 4 ; Elt 2 11 } ] + - location: 19 (remaining gas: 1039986.369 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + (Some True) ] + - location: 20 (remaining gas: 1039986.354 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) ] + - location: 21 (remaining gas: 1039986.339 units remaining) + [ {} + (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) ] + - location: 23 (remaining gas: 1039986.324 units remaining) + [ (Pair {} { Elt 1 4 ; Elt 2 11 } (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3.7f1f2ab27d.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3.7f1f2ab27d.out new file mode 100644 index 000000000000..26afb92d7fe7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3.7f1f2ab27d.out @@ -0,0 +1,44 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3-(Pair 4 (Some False))1] + +storage + (Pair 4 (Some False)) +emitted operations + +big_map diff + New map(4) of type (big_map nat nat) + Set map(4)[1] to 4 + Set map(4)[2] to 11 +trace + - location: 12 (remaining gas: 1039987.422 units remaining) + [ (Pair 3 { Elt 1 4 ; Elt 2 11 } None) ] + - location: 12 (remaining gas: 1039987.412 units remaining) + [ 3 @parameter + (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 13 (remaining gas: 1039987.397 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 15 (remaining gas: 1039987.387 units remaining) + [ { Elt 1 4 ; Elt 2 11 } ] + - location: 16 (remaining gas: 1039987.377 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 13 (remaining gas: 1039987.347 units remaining) + [ 3 @parameter + { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 17 (remaining gas: 1039986.394 units remaining) + [ False + { Elt 1 4 ; Elt 2 11 } ] + - location: 18 (remaining gas: 1039986.379 units remaining) + [ (Some False) + { Elt 1 4 ; Elt 2 11 } ] + - location: 19 (remaining gas: 1039986.369 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + (Some False) ] + - location: 20 (remaining gas: 1039986.354 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } (Some False)) ] + - location: 21 (remaining gas: 1039986.339 units remaining) + [ {} + (Pair { Elt 1 4 ; Elt 2 11 } (Some False)) ] + - location: 23 (remaining gas: 1039986.324 units remaining) + [ (Pair {} { Elt 1 4 ; Elt 2 11 } (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3.a3c5c126ce.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3.a3c5c126ce.out new file mode 100644 index 000000000000..dc93be24a4b2 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3.a3c5c126ce.out @@ -0,0 +1,44 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3-(Pair 4 (Some False))0] + +storage + (Pair 4 (Some False)) +emitted operations + +big_map diff + New map(4) of type (big_map nat nat) + Set map(4)[1] to 4 + Set map(4)[2] to 11 +trace + - location: 12 (remaining gas: 1039987.422 units remaining) + [ (Pair 3 { Elt 1 4 ; Elt 2 11 } None) ] + - location: 12 (remaining gas: 1039987.412 units remaining) + [ 3 @parameter + (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 13 (remaining gas: 1039987.397 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 15 (remaining gas: 1039987.387 units remaining) + [ { Elt 1 4 ; Elt 2 11 } ] + - location: 16 (remaining gas: 1039987.377 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 13 (remaining gas: 1039987.347 units remaining) + [ 3 @parameter + { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 17 (remaining gas: 1039986.394 units remaining) + [ False + { Elt 1 4 ; Elt 2 11 } ] + - location: 18 (remaining gas: 1039986.379 units remaining) + [ (Some False) + { Elt 1 4 ; Elt 2 11 } ] + - location: 19 (remaining gas: 1039986.369 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + (Some False) ] + - location: 20 (remaining gas: 1039986.354 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } (Some False)) ] + - location: 21 (remaining gas: 1039986.339 units remaining) + [ {} + (Pair { Elt 1 4 ; Elt 2 11 } (Some False)) ] + - location: 23 (remaining gas: 1039986.324 units remaining) + [ (Pair {} { Elt 1 4 ; Elt 2 11 } (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair {} None)-1-(Pair 4 (Some False))0].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair {} None)-1-(Pair 4 (Some False))0].out new file mode 100644 index 000000000000..c41816b747ef --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair {} None)-1-(Pair 4 (Some False))0].out @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair {} None)-1-(Pair 4 (Some False))0] + +storage + (Pair 4 (Some False)) +emitted operations + +big_map diff + New map(4) of type (big_map nat nat) +trace + - location: 12 (remaining gas: 1039989.804 units remaining) + [ (Pair 1 {} None) ] + - location: 12 (remaining gas: 1039989.794 units remaining) + [ 1 @parameter + (Pair {} None) @storage ] + - location: 13 (remaining gas: 1039989.779 units remaining) + [ (Pair {} None) @storage ] + - location: 15 (remaining gas: 1039989.769 units remaining) + [ {} ] + - location: 16 (remaining gas: 1039989.759 units remaining) + [ {} + {} ] + - location: 13 (remaining gas: 1039989.729 units remaining) + [ 1 @parameter + {} + {} ] + - location: 17 (remaining gas: 1039988.779 units remaining) + [ False + {} ] + - location: 18 (remaining gas: 1039988.764 units remaining) + [ (Some False) + {} ] + - location: 19 (remaining gas: 1039988.754 units remaining) + [ {} + (Some False) ] + - location: 20 (remaining gas: 1039988.739 units remaining) + [ (Pair {} (Some False)) ] + - location: 21 (remaining gas: 1039988.724 units remaining) + [ {} + (Pair {} (Some False)) ] + - location: 23 (remaining gas: 1039988.709 units remaining) + [ (Pair {} {} (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair {} None)-1-(Pair 4 (Some False))1].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair {} None)-1-(Pair 4 (Some False))1].out new file mode 100644 index 000000000000..4f5b02f8ae1f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair {} None)-1-(Pair 4 (Some False))1].out @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_nat.tz-(Pair {} None)-1-(Pair 4 (Some False))1] + +storage + (Pair 4 (Some False)) +emitted operations + +big_map diff + New map(4) of type (big_map nat nat) +trace + - location: 12 (remaining gas: 1039989.804 units remaining) + [ (Pair 1 {} None) ] + - location: 12 (remaining gas: 1039989.794 units remaining) + [ 1 @parameter + (Pair {} None) @storage ] + - location: 13 (remaining gas: 1039989.779 units remaining) + [ (Pair {} None) @storage ] + - location: 15 (remaining gas: 1039989.769 units remaining) + [ {} ] + - location: 16 (remaining gas: 1039989.759 units remaining) + [ {} + {} ] + - location: 13 (remaining gas: 1039989.729 units remaining) + [ 1 @parameter + {} + {} ] + - location: 17 (remaining gas: 1039988.779 units remaining) + [ False + {} ] + - location: 18 (remaining gas: 1039988.764 units remaining) + [ (Some False) + {} ] + - location: 19 (remaining gas: 1039988.754 units remaining) + [ {} + (Some False) ] + - location: 20 (remaining gas: 1039988.739 units remaining) + [ (Pair {} (Some False)) ] + - location: 21 (remaining gas: 1039988.724 units remaining) + [ {} + (Pair {} (Some False)) ] + - location: 23 (remaining gas: 1039988.709 units remaining) + [ (Pair {} {} (Some False)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 1.4be99ce05d.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 1.4be99ce05d.out" new file mode 100644 index 000000000000..570d64dce8ae --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 1.4be99ce05d.out" @@ -0,0 +1,44 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt "bar" 4 ; Elt "foo" 11 } None)-"baz"-(Pair 4 (Some False))] + +storage + (Pair 4 (Some False)) +emitted operations + +big_map diff + New map(4) of type (big_map string nat) + Set map(4)["bar"] to 4 + Set map(4)["foo"] to 11 +trace + - location: 12 (remaining gas: 1039986.484 units remaining) + [ (Pair "baz" { Elt "bar" 4 ; Elt "foo" 11 } None) ] + - location: 12 (remaining gas: 1039986.474 units remaining) + [ "baz" @parameter + (Pair { Elt "bar" 4 ; Elt "foo" 11 } None) @storage ] + - location: 13 (remaining gas: 1039986.459 units remaining) + [ (Pair { Elt "bar" 4 ; Elt "foo" 11 } None) @storage ] + - location: 15 (remaining gas: 1039986.449 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 16 (remaining gas: 1039986.439 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 13 (remaining gas: 1039986.409 units remaining) + [ "baz" @parameter + { Elt "bar" 4 ; Elt "foo" 11 } + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 17 (remaining gas: 1039985.053 units remaining) + [ False + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 18 (remaining gas: 1039985.038 units remaining) + [ (Some False) + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 19 (remaining gas: 1039985.028 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } + (Some False) ] + - location: 20 (remaining gas: 1039985.013 units remaining) + [ (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some False)) ] + - location: 21 (remaining gas: 1039984.998 units remaining) + [ {} + (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some False)) ] + - location: 23 (remaining gas: 1039984.983 units remaining) + [ (Pair {} { Elt "bar" 4 ; Elt "foo" 11 } (Some False)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 1.50c0e0ff8b.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 1.50c0e0ff8b.out" new file mode 100644 index 000000000000..21799d99e2dd --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 1.50c0e0ff8b.out" @@ -0,0 +1,44 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt "bar" 4 ; Elt "foo" 11 } None)-"foo"-(Pair 4 (Some True))] + +storage + (Pair 4 (Some True)) +emitted operations + +big_map diff + New map(4) of type (big_map string nat) + Set map(4)["bar"] to 4 + Set map(4)["foo"] to 11 +trace + - location: 12 (remaining gas: 1039986.484 units remaining) + [ (Pair "foo" { Elt "bar" 4 ; Elt "foo" 11 } None) ] + - location: 12 (remaining gas: 1039986.474 units remaining) + [ "foo" @parameter + (Pair { Elt "bar" 4 ; Elt "foo" 11 } None) @storage ] + - location: 13 (remaining gas: 1039986.459 units remaining) + [ (Pair { Elt "bar" 4 ; Elt "foo" 11 } None) @storage ] + - location: 15 (remaining gas: 1039986.449 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 16 (remaining gas: 1039986.439 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 13 (remaining gas: 1039986.409 units remaining) + [ "foo" @parameter + { Elt "bar" 4 ; Elt "foo" 11 } + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 17 (remaining gas: 1039985.053 units remaining) + [ True + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 18 (remaining gas: 1039985.038 units remaining) + [ (Some True) + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 19 (remaining gas: 1039985.028 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } + (Some True) ] + - location: 20 (remaining gas: 1039985.013 units remaining) + [ (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) ] + - location: 21 (remaining gas: 1039984.998 units remaining) + [ {} + (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) ] + - location: 23 (remaining gas: 1039984.983 units remaining) + [ (Pair {} { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 1.775c22b027.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 1.775c22b027.out" new file mode 100644 index 000000000000..8a395be8e8db --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 1.775c22b027.out" @@ -0,0 +1,44 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt "bar" 4 ; Elt "foo" 11 } None)-"bar"-(Pair 4 (Some True))] + +storage + (Pair 4 (Some True)) +emitted operations + +big_map diff + New map(4) of type (big_map string nat) + Set map(4)["bar"] to 4 + Set map(4)["foo"] to 11 +trace + - location: 12 (remaining gas: 1039986.484 units remaining) + [ (Pair "bar" { Elt "bar" 4 ; Elt "foo" 11 } None) ] + - location: 12 (remaining gas: 1039986.474 units remaining) + [ "bar" @parameter + (Pair { Elt "bar" 4 ; Elt "foo" 11 } None) @storage ] + - location: 13 (remaining gas: 1039986.459 units remaining) + [ (Pair { Elt "bar" 4 ; Elt "foo" 11 } None) @storage ] + - location: 15 (remaining gas: 1039986.449 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 16 (remaining gas: 1039986.439 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 13 (remaining gas: 1039986.409 units remaining) + [ "bar" @parameter + { Elt "bar" 4 ; Elt "foo" 11 } + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 17 (remaining gas: 1039985.053 units remaining) + [ True + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 18 (remaining gas: 1039985.038 units remaining) + [ (Some True) + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 19 (remaining gas: 1039985.028 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } + (Some True) ] + - location: 20 (remaining gas: 1039985.013 units remaining) + [ (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) ] + - location: 21 (remaining gas: 1039984.998 units remaining) + [ {} + (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) ] + - location: 23 (remaining gas: 1039984.983 units remaining) + [ (Pair {} { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"foo\" 0 } None)-\"foo\".968709d39d.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"foo\" 0 } None)-\"foo\".968709d39d.out" new file mode 100644 index 000000000000..883719d612ef --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"foo\" 0 } None)-\"foo\".968709d39d.out" @@ -0,0 +1,43 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt "foo" 0 } None)-"foo"-(Pair 4 (Some True))] + +storage + (Pair 4 (Some True)) +emitted operations + +big_map diff + New map(4) of type (big_map string nat) + Set map(4)["foo"] to 0 +trace + - location: 12 (remaining gas: 1039988.141 units remaining) + [ (Pair "foo" { Elt "foo" 0 } None) ] + - location: 12 (remaining gas: 1039988.131 units remaining) + [ "foo" @parameter + (Pair { Elt "foo" 0 } None) @storage ] + - location: 13 (remaining gas: 1039988.116 units remaining) + [ (Pair { Elt "foo" 0 } None) @storage ] + - location: 15 (remaining gas: 1039988.106 units remaining) + [ { Elt "foo" 0 } ] + - location: 16 (remaining gas: 1039988.096 units remaining) + [ { Elt "foo" 0 } + { Elt "foo" 0 } ] + - location: 13 (remaining gas: 1039988.066 units remaining) + [ "foo" @parameter + { Elt "foo" 0 } + { Elt "foo" 0 } ] + - location: 17 (remaining gas: 1039986.711 units remaining) + [ True + { Elt "foo" 0 } ] + - location: 18 (remaining gas: 1039986.696 units remaining) + [ (Some True) + { Elt "foo" 0 } ] + - location: 19 (remaining gas: 1039986.686 units remaining) + [ { Elt "foo" 0 } + (Some True) ] + - location: 20 (remaining gas: 1039986.671 units remaining) + [ (Pair { Elt "foo" 0 } (Some True)) ] + - location: 21 (remaining gas: 1039986.656 units remaining) + [ {} + (Pair { Elt "foo" 0 } (Some True)) ] + - location: 23 (remaining gas: 1039986.641 units remaining) + [ (Pair {} { Elt "foo" 0 } (Some True)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"foo\" 1 } None)-\"bar\".cdcfaf9d09.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"foo\" 1 } None)-\"bar\".cdcfaf9d09.out" new file mode 100644 index 000000000000..2432f5b1cd23 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt \"foo\" 1 } None)-\"bar\".cdcfaf9d09.out" @@ -0,0 +1,43 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair { Elt "foo" 1 } None)-"bar"-(Pair 4 (Some False))] + +storage + (Pair 4 (Some False)) +emitted operations + +big_map diff + New map(4) of type (big_map string nat) + Set map(4)["foo"] to 1 +trace + - location: 12 (remaining gas: 1039988.141 units remaining) + [ (Pair "bar" { Elt "foo" 1 } None) ] + - location: 12 (remaining gas: 1039988.131 units remaining) + [ "bar" @parameter + (Pair { Elt "foo" 1 } None) @storage ] + - location: 13 (remaining gas: 1039988.116 units remaining) + [ (Pair { Elt "foo" 1 } None) @storage ] + - location: 15 (remaining gas: 1039988.106 units remaining) + [ { Elt "foo" 1 } ] + - location: 16 (remaining gas: 1039988.096 units remaining) + [ { Elt "foo" 1 } + { Elt "foo" 1 } ] + - location: 13 (remaining gas: 1039988.066 units remaining) + [ "bar" @parameter + { Elt "foo" 1 } + { Elt "foo" 1 } ] + - location: 17 (remaining gas: 1039986.711 units remaining) + [ False + { Elt "foo" 1 } ] + - location: 18 (remaining gas: 1039986.696 units remaining) + [ (Some False) + { Elt "foo" 1 } ] + - location: 19 (remaining gas: 1039986.686 units remaining) + [ { Elt "foo" 1 } + (Some False) ] + - location: 20 (remaining gas: 1039986.671 units remaining) + [ (Pair { Elt "foo" 1 } (Some False)) ] + - location: 21 (remaining gas: 1039986.656 units remaining) + [ {} + (Pair { Elt "foo" 1 } (Some False)) ] + - location: 23 (remaining gas: 1039986.641 units remaining) + [ (Pair {} { Elt "foo" 1 } (Some False)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair {} None)-\"bar\"-(Pair 4 (Some False))].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair {} None)-\"bar\"-(Pair 4 (Some False))].out" new file mode 100644 index 000000000000..8f2ff0f7c6c8 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair {} None)-\"bar\"-(Pair 4 (Some False))].out" @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[big_map_mem_string.tz-(Pair {} None)-"bar"-(Pair 4 (Some False))] + +storage + (Pair 4 (Some False)) +emitted operations + +big_map diff + New map(4) of type (big_map string nat) +trace + - location: 12 (remaining gas: 1039989.760 units remaining) + [ (Pair "bar" {} None) ] + - location: 12 (remaining gas: 1039989.750 units remaining) + [ "bar" @parameter + (Pair {} None) @storage ] + - location: 13 (remaining gas: 1039989.735 units remaining) + [ (Pair {} None) @storage ] + - location: 15 (remaining gas: 1039989.725 units remaining) + [ {} ] + - location: 16 (remaining gas: 1039989.715 units remaining) + [ {} + {} ] + - location: 13 (remaining gas: 1039989.685 units remaining) + [ "bar" @parameter + {} + {} ] + - location: 17 (remaining gas: 1039988.332 units remaining) + [ False + {} ] + - location: 18 (remaining gas: 1039988.317 units remaining) + [ (Some False) + {} ] + - location: 19 (remaining gas: 1039988.307 units remaining) + [ {} + (Some False) ] + - location: 20 (remaining gas: 1039988.292 units remaining) + [ (Pair {} (Some False)) ] + - location: 21 (remaining gas: 1039988.277 units remaining) + [ {} + (Pair {} (Some False)) ] + - location: 23 (remaining gas: 1039988.262 units remaining) + [ (Pair {} {} (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_push_bytes_not_padded.tz-None-Unit-(Some 0.9b6e8bcbd3.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_push_bytes_not_padded.tz-None-Unit-(Some 0.9b6e8bcbd3.out new file mode 100644 index 000000000000..3213b73025ec --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_push_bytes_not_padded.tz-None-Unit-(Some 0.9b6e8bcbd3.out @@ -0,0 +1,24 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_push_bytes_not_padded.tz-None-Unit-(Some 0x0000000000000000000000000000000000000000000000000000000000000000)] + +storage + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.391 units remaining) + [ (Pair Unit None) ] + - location: 8 (remaining gas: 1039994.381 units remaining) + [ ] + - location: 9 (remaining gas: 1039994.371 units remaining) + [ 0x0000000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039994.356 units remaining) + [ (Some 0x0000000000000000000000000000000000000000000000000000000000000000) ] + - location: 13 (remaining gas: 1039994.341 units remaining) + [ {} + (Some 0x0000000000000000000000000000000000000000000000000000000000000000) ] + - location: 15 (remaining gas: 1039994.326 units remaining) + [ (Pair {} + (Some 0x0000000000000000000000000000000000000000000000000000000000000000)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_push_nat.tz-None-Unit-(Some 0x100000000000.d1219ca789.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_push_nat.tz-None-Unit-(Some 0x100000000000.d1219ca789.out new file mode 100644 index 000000000000..da1ab4ec9891 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_push_nat.tz-None-Unit-(Some 0x100000000000.d1219ca789.out @@ -0,0 +1,24 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_push_nat.tz-None-Unit-(Some 0x1000000000000000000000000000000000000000000000000000000000000000)] + +storage + (Some 0x1000000000000000000000000000000000000000000000000000000000000000) +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.391 units remaining) + [ (Pair Unit None) ] + - location: 8 (remaining gas: 1039994.381 units remaining) + [ ] + - location: 9 (remaining gas: 1039994.371 units remaining) + [ 0x1000000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039994.356 units remaining) + [ (Some 0x1000000000000000000000000000000000000000000000000000000000000000) ] + - location: 13 (remaining gas: 1039994.341 units remaining) + [ {} + (Some 0x1000000000000000000000000000000000000000000000000000000000000000) ] + - location: 15 (remaining gas: 1039994.326 units remaining) + [ (Pair {} + (Some 0x1000000000000000000000000000000000000000000000000000000000000000)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x00-0].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x00-0].out new file mode 100644 index 000000000000..79a1c382ffb9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x00-0].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x00-0] + +storage + 0 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 0x0000000000000000000000000000000000000000000000000000000000000000 0) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 0x0000000000000000000000000000000000000000000000000000000000000000 @parameter ] + - location: 8 (remaining gas: 1039995.568 units remaining) + [ 0 ] + - location: 9 (remaining gas: 1039995.553 units remaining) + [ {} + 0 ] + - location: 11 (remaining gas: 1039995.538 units remaining) + [ (Pair {} 0) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x01-1].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x01-1].out new file mode 100644 index 000000000000..2bc1bb40f3fb --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x01-1].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x01-1] + +storage + 1 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 0x0100000000000000000000000000000000000000000000000000000000000000 0) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 @parameter ] + - location: 8 (remaining gas: 1039995.568 units remaining) + [ 1 ] + - location: 9 (remaining gas: 1039995.553 units remaining) + [ {} + 1 ] + - location: 11 (remaining gas: 1039995.538 units remaining) + [ (Pair {} 1) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x28db8e57af88d9576acd181b89f2.7a85c336ff.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x28db8e57af88d9576acd181b89f2.7a85c336ff.out new file mode 100644 index 000000000000..373cba50e695 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x28db8e57af88d9576acd181b89f2.7a85c336ff.out @@ -0,0 +1,22 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0x28db8e57af88d9576acd181b89f24e50a89a6423f939026ed91349fc9af16c27-17832688077013577776524784494464728518213913213412866604053735695200962927400] + +storage + 17832688077013577776524784494464728518213913213412866604053735695200962927400 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 0x28db8e57af88d9576acd181b89f24e50a89a6423f939026ed91349fc9af16c27 0) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 0x28db8e57af88d9576acd181b89f24e50a89a6423f939026ed91349fc9af16c27 @parameter ] + - location: 8 (remaining gas: 1039995.568 units remaining) + [ 17832688077013577776524784494464728518213913213412866604053735695200962927400 ] + - location: 9 (remaining gas: 1039995.553 units remaining) + [ {} + 17832688077013577776524784494464728518213913213412866604053735695200962927400 ] + - location: 11 (remaining gas: 1039995.538 units remaining) + [ (Pair {} + 17832688077013577776524784494464728518213913213412866604053735695200962927400) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0xb9e8abf8dc324a010007addde986.b821eb26b3.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0xb9e8abf8dc324a010007addde986.b821eb26b3.out new file mode 100644 index 000000000000..79c70ab5be36 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0xb9e8abf8dc324a010007addde986.b821eb26b3.out @@ -0,0 +1,22 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_int.tz-0-0xb9e8abf8dc324a010007addde986fe0f7c81fab16d26819d0534b7691c0b0719-11320265829256585830781521966149529460476767408210445238902869222031333517497] + +storage + 11320265829256585830781521966149529460476767408210445238902869222031333517497 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 0xb9e8abf8dc324a010007addde986fe0f7c81fab16d26819d0534b7691c0b0719 0) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 0xb9e8abf8dc324a010007addde986fe0f7c81fab16d26819d0534b7691c0b0719 @parameter ] + - location: 8 (remaining gas: 1039995.568 units remaining) + [ 11320265829256585830781521966149529460476767408210445238902869222031333517497 ] + - location: 9 (remaining gas: 1039995.553 units remaining) + [ {} + 11320265829256585830781521966149529460476767408210445238902869222031333517497 ] + - location: 11 (remaining gas: 1039995.538 units remaining) + [ (Pair {} + 11320265829256585830781521966149529460476767408210445238902869222031333517497) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_mutez.tz-0-0x10-16].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_mutez.tz-0-0x10-16].out new file mode 100644 index 000000000000..1ea5cf02439b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_mutez.tz-0-0x10-16].out @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_to_mutez.tz-0-0x10-16] + +storage + 16 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039990.329 units remaining) + [ (Pair 0x1000000000000000000000000000000000000000000000000000000000000000 0) ] + - location: 7 (remaining gas: 1039990.319 units remaining) + [ 0x1000000000000000000000000000000000000000000000000000000000000000 @parameter ] + - location: 8 (remaining gas: 1039990.279 units remaining) + [ 16 ] + - location: 9 (remaining gas: 1039990.264 units remaining) + [ (Some 16) ] + - location: 11 (remaining gas: 1039990.254 units remaining) + [ 16 @some ] + - location: 11 (remaining gas: 1039990.239 units remaining) + [ 16 @some ] + - location: 17 (remaining gas: 1039990.229 units remaining) + [ 1 + 16 @some ] + - location: 20 (remaining gas: 1039990.229 units remaining) + [ 16 ] + - location: 21 (remaining gas: 1039990.214 units remaining) + [ {} + 16 ] + - location: 23 (remaining gas: 1039990.199 units remaining) + [ (Pair {} 16) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.0accef5bef.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.0accef5bef.out new file mode 100644 index 000000000000..7d32ad7cadb0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.0accef5bef.out @@ -0,0 +1,22 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000000000000000000000000000000000000--42-0xd7fffffffefffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73] + +storage + 0xd7fffffffefffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair -42 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ -42 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995.337 units remaining) + [ 0xd7fffffffefffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73 ] + - location: 9 (remaining gas: 1039995.322 units remaining) + [ {} + 0xd7fffffffefffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73 ] + - location: 11 (remaining gas: 1039995.307 units remaining) + [ (Pair {} 0xd7fffffffefffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.0ecc537252.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.0ecc537252.out new file mode 100644 index 000000000000..0d35962019ba --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.0ecc537252.out @@ -0,0 +1,22 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000000000000000000000000000000000000-2-0x0200000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0200000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 2 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 2 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995.337 units remaining) + [ 0x0200000000000000000000000000000000000000000000000000000000000000 ] + - location: 9 (remaining gas: 1039995.322 units remaining) + [ {} + 0x0200000000000000000000000000000000000000000000000000000000000000 ] + - location: 11 (remaining gas: 1039995.307 units remaining) + [ (Pair {} 0x0200000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.2229b767cd.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.2229b767cd.out new file mode 100644 index 000000000000..846ed0e64a4b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.2229b767cd.out @@ -0,0 +1,22 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000000000000000000000000000000000000--1-0x00000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73] + +storage + 0x00000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair -1 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ -1 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995.337 units remaining) + [ 0x00000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73 ] + - location: 9 (remaining gas: 1039995.322 units remaining) + [ {} + 0x00000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73 ] + - location: 11 (remaining gas: 1039995.307 units remaining) + [ (Pair {} 0x00000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.2ff549b46b.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.2ff549b46b.out new file mode 100644 index 000000000000..f8b67c48fdca --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.2ff549b46b.out @@ -0,0 +1,22 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000000000000000000000000000000000000-0-0x0000000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0000000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 0 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 0 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995.338 units remaining) + [ 0x0000000000000000000000000000000000000000000000000000000000000000 ] + - location: 9 (remaining gas: 1039995.323 units remaining) + [ {} + 0x0000000000000000000000000000000000000000000000000000000000000000 ] + - location: 11 (remaining gas: 1039995.308 units remaining) + [ (Pair {} 0x0000000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.bf8a711be6.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.bf8a711be6.out new file mode 100644 index 000000000000..cf9fd6cdcbe6 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.bf8a711be6.out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000000000000000000000000000000000000-52435875175126190479447740508185965837690552500527637822603658699938581184514-0x0100000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0100000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 52435875175126190479447740508185965837690552500527637822603658699938581184514 + 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 52435875175126190479447740508185965837690552500527637822603658699938581184514 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995.304 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 9 (remaining gas: 1039995.289 units remaining) + [ {} + 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 11 (remaining gas: 1039995.274 units remaining) + [ (Pair {} 0x0100000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.d41cbb044b.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.d41cbb044b.out new file mode 100644 index 000000000000..daea6a71ee9c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000.d41cbb044b.out @@ -0,0 +1,22 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x0100000000000000000000000000000000000000000000000000000000000000-1-0x0100000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0100000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 1 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 1 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995.337 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 9 (remaining gas: 1039995.322 units remaining) + [ {} + 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 11 (remaining gas: 1039995.307 units remaining) + [ (Pair {} 0x0100000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x4147a5ad0a633e4880d2296f08ec5c1.a50412e458.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x4147a5ad0a633e4880d2296f08ec5c1.a50412e458.out new file mode 100644 index 000000000000..c907d4e20dd5 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x4147a5ad0a633e4880d2296f08ec5c1.a50412e458.out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f-22620284817922784902564672469917992996328211127984472897491698543785655336309-0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62] + +storage + 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 22620284817922784902564672469917992996328211127984472897491698543785655336309 + 0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 22620284817922784902564672469917992996328211127984472897491698543785655336309 @parameter + 0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f @storage ] + - location: 8 (remaining gas: 1039995.304 units remaining) + [ 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62 ] + - location: 9 (remaining gas: 1039995.289 units remaining) + [ {} + 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62 ] + - location: 11 (remaining gas: 1039995.274 units remaining) + [ (Pair {} 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x5b0ecd0fa853810e356f1eb79721e80.f3a349c4a7.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x5b0ecd0fa853810e356f1eb79721e80.f3a349c4a7.out new file mode 100644 index 000000000000..239ed583e973 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x5b0ecd0fa853810e356f1eb79721e80.f3a349c4a7.out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f-33644916630334844239120348434626468649534186770809802792596996408934105684394-0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221] + +storage + 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 33644916630334844239120348434626468649534186770809802792596996408934105684394 + 0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 33644916630334844239120348434626468649534186770809802792596996408934105684394 @parameter + 0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f @storage ] + - location: 8 (remaining gas: 1039995.304 units remaining) + [ 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221 ] + - location: 9 (remaining gas: 1039995.289 units remaining) + [ {} + 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221 ] + - location: 11 (remaining gas: 1039995.274 units remaining) + [ (Pair {} 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x8578be1766f92cd82c5e5135c374a03.1b9676e4c2.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x8578be1766f92cd82c5e5135c374a03.1b9676e4c2.out new file mode 100644 index 000000000000..043d364646cd --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x8578be1766f92cd82c5e5135c374a03.1b9676e4c2.out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d-69615968247920749285624776342583898043608129789011377475114141186797415307882-0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221] + +storage + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 69615968247920749285624776342583898043608129789011377475114141186797415307882 + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 69615968247920749285624776342583898043608129789011377475114141186797415307882 @parameter + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d @storage ] + - location: 8 (remaining gas: 1039995.304 units remaining) + [ 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 9 (remaining gas: 1039995.289 units remaining) + [ {} + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 11 (remaining gas: 1039995.274 units remaining) + [ (Pair {} 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x8578be1766f92cd82c5e5135c374a03.e966dc6de5.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x8578be1766f92cd82c5e5135c374a03.e966dc6de5.out new file mode 100644 index 000000000000..c7ea6f16e05f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x8578be1766f92cd82c5e5135c374a03.e966dc6de5.out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_int.tz-0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d-17180093072794558806177035834397932205917577288483739652510482486858834123369-0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221] + +storage + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 17180093072794558806177035834397932205917577288483739652510482486858834123369 + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 17180093072794558806177035834397932205917577288483739652510482486858834123369 @parameter + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d @storage ] + - location: 8 (remaining gas: 1039995.304 units remaining) + [ 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 9 (remaining gas: 1039995.289 units remaining) + [ {} + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 11 (remaining gas: 1039995.274 units remaining) + [ (Pair {} 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.964835cc43.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.964835cc43.out new file mode 100644 index 000000000000..0ff658f250db --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.964835cc43.out @@ -0,0 +1,22 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000000000000000000000000000000000000-1-0x0100000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0100000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 1 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 1 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995.337 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 9 (remaining gas: 1039995.322 units remaining) + [ {} + 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 11 (remaining gas: 1039995.307 units remaining) + [ (Pair {} 0x0100000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.b25ea709fb.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.b25ea709fb.out new file mode 100644 index 000000000000..e7734be404a0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.b25ea709fb.out @@ -0,0 +1,22 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000000000000000000000000000000000000-0-0x0000000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0000000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 0 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 0 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995.338 units remaining) + [ 0x0000000000000000000000000000000000000000000000000000000000000000 ] + - location: 9 (remaining gas: 1039995.323 units remaining) + [ {} + 0x0000000000000000000000000000000000000000000000000000000000000000 ] + - location: 11 (remaining gas: 1039995.308 units remaining) + [ (Pair {} 0x0000000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.eae36753ea.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.eae36753ea.out new file mode 100644 index 000000000000..2a1ff9188d01 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.eae36753ea.out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000000000000000000000000000000000000-52435875175126190479447740508185965837690552500527637822603658699938581184514-0x0100000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0100000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 52435875175126190479447740508185965837690552500527637822603658699938581184514 + 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 52435875175126190479447740508185965837690552500527637822603658699938581184514 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995.304 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 9 (remaining gas: 1039995.289 units remaining) + [ {} + 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 11 (remaining gas: 1039995.274 units remaining) + [ (Pair {} 0x0100000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.ee57dac8f7.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.ee57dac8f7.out new file mode 100644 index 000000000000..04bf0f294f42 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000.ee57dac8f7.out @@ -0,0 +1,22 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x0100000000000000000000000000000000000000000000000000000000000000-2-0x0200000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0200000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 2 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 2 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995.337 units remaining) + [ 0x0200000000000000000000000000000000000000000000000000000000000000 ] + - location: 9 (remaining gas: 1039995.322 units remaining) + [ {} + 0x0200000000000000000000000000000000000000000000000000000000000000 ] + - location: 11 (remaining gas: 1039995.307 units remaining) + [ (Pair {} 0x0200000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x4147a5ad0a633e4880d2296f08ec5c1.928f6d4b93.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x4147a5ad0a633e4880d2296f08ec5c1.928f6d4b93.out new file mode 100644 index 000000000000..e9011872336f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x4147a5ad0a633e4880d2296f08ec5c1.928f6d4b93.out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f-22620284817922784902564672469917992996328211127984472897491698543785655336309-0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62] + +storage + 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 22620284817922784902564672469917992996328211127984472897491698543785655336309 + 0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 22620284817922784902564672469917992996328211127984472897491698543785655336309 @parameter + 0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f @storage ] + - location: 8 (remaining gas: 1039995.304 units remaining) + [ 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62 ] + - location: 9 (remaining gas: 1039995.289 units remaining) + [ {} + 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62 ] + - location: 11 (remaining gas: 1039995.274 units remaining) + [ (Pair {} 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x5b0ecd0fa853810e356f1eb79721e80.bd5800f6b8.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x5b0ecd0fa853810e356f1eb79721e80.bd5800f6b8.out new file mode 100644 index 000000000000..bb5f1878e2a5 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x5b0ecd0fa853810e356f1eb79721e80.bd5800f6b8.out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f-33644916630334844239120348434626468649534186770809802792596996408934105684394-0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221] + +storage + 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 33644916630334844239120348434626468649534186770809802792596996408934105684394 + 0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 33644916630334844239120348434626468649534186770809802792596996408934105684394 @parameter + 0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f @storage ] + - location: 8 (remaining gas: 1039995.304 units remaining) + [ 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221 ] + - location: 9 (remaining gas: 1039995.289 units remaining) + [ {} + 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221 ] + - location: 11 (remaining gas: 1039995.274 units remaining) + [ (Pair {} 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x8578be1766f92cd82c5e5135c374a03.00e897789a.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x8578be1766f92cd82c5e5135c374a03.00e897789a.out new file mode 100644 index 000000000000..0b963ac5bf55 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x8578be1766f92cd82c5e5135c374a03.00e897789a.out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d-17180093072794558806177035834397932205917577288483739652510482486858834123369-0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221] + +storage + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 17180093072794558806177035834397932205917577288483739652510482486858834123369 + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 17180093072794558806177035834397932205917577288483739652510482486858834123369 @parameter + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d @storage ] + - location: 8 (remaining gas: 1039995.304 units remaining) + [ 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 9 (remaining gas: 1039995.289 units remaining) + [ {} + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 11 (remaining gas: 1039995.274 units remaining) + [ (Pair {} 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x8578be1766f92cd82c5e5135c374a03.a4697eaa13.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x8578be1766f92cd82c5e5135c374a03.a4697eaa13.out new file mode 100644 index 000000000000..579d108406ca --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x8578be1766f92cd82c5e5135c374a03.a4697eaa13.out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_fr_z_nat.tz-0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d-69615968247920749285624776342583898043608129789011377475114141186797415307882-0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221] + +storage + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.618 units remaining) + [ (Pair 69615968247920749285624776342583898043608129789011377475114141186797415307882 + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d) ] + - location: 7 (remaining gas: 1039995.608 units remaining) + [ 69615968247920749285624776342583898043608129789011377475114141186797415307882 @parameter + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d @storage ] + - location: 8 (remaining gas: 1039995.304 units remaining) + [ 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 9 (remaining gas: 1039995.289 units remaining) + [ {} + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 11 (remaining gas: 1039995.274 units remaining) + [ (Pair {} 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.0177355bbf.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.0177355bbf.out new file mode 100644 index 000000000000..ee306ffbfab2 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.0177355bbf.out @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000000000000000000000000000000000000-2-0x0200000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0200000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 2 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 2 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 @storage + 2 @parameter ] + - location: 9 (remaining gas: 1039994.729 units remaining) + [ 0x0200000000000000000000000000000000000000000000000000000000000000 ] + - location: 10 (remaining gas: 1039994.714 units remaining) + [ {} + 0x0200000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039994.699 units remaining) + [ (Pair {} 0x0200000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.744166c609.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.744166c609.out new file mode 100644 index 000000000000..fd1129602382 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.744166c609.out @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000000000000000000000000000000000000--1-0x00000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73] + +storage + 0x00000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair -1 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ -1 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 @storage + -1 @parameter ] + - location: 9 (remaining gas: 1039994.729 units remaining) + [ 0x00000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73 ] + - location: 10 (remaining gas: 1039994.714 units remaining) + [ {} + 0x00000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73 ] + - location: 12 (remaining gas: 1039994.699 units remaining) + [ (Pair {} 0x00000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.9f3c5cdc6a.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.9f3c5cdc6a.out new file mode 100644 index 000000000000..31f3d724e984 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.9f3c5cdc6a.out @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000000000000000000000000000000000000-0-0x0000000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0000000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 0 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 0 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 @storage + 0 @parameter ] + - location: 9 (remaining gas: 1039994.730 units remaining) + [ 0x0000000000000000000000000000000000000000000000000000000000000000 ] + - location: 10 (remaining gas: 1039994.715 units remaining) + [ {} + 0x0000000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039994.700 units remaining) + [ (Pair {} 0x0000000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.a54cb341ba.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.a54cb341ba.out new file mode 100644 index 000000000000..cc5ebd0ce6c2 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.a54cb341ba.out @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000000000000000000000000000000000000--42-0xd7fffffffefffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73] + +storage + 0xd7fffffffefffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair -42 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ -42 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 @storage + -42 @parameter ] + - location: 9 (remaining gas: 1039994.729 units remaining) + [ 0xd7fffffffefffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73 ] + - location: 10 (remaining gas: 1039994.714 units remaining) + [ {} + 0xd7fffffffefffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73 ] + - location: 12 (remaining gas: 1039994.699 units remaining) + [ (Pair {} 0xd7fffffffefffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.b0dc584c94.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.b0dc584c94.out new file mode 100644 index 000000000000..dd0bba15ee71 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.b0dc584c94.out @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000000000000000000000000000000000000-1-0x0100000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0100000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 1 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 1 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 @storage + 1 @parameter ] + - location: 9 (remaining gas: 1039994.729 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 10 (remaining gas: 1039994.714 units remaining) + [ {} + 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039994.699 units remaining) + [ (Pair {} 0x0100000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.bddcad090c.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.bddcad090c.out new file mode 100644 index 000000000000..13e0c2ac93df --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000.bddcad090c.out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x0100000000000000000000000000000000000000000000000000000000000000-52435875175126190479447740508185965837690552500527637822603658699938581184514-0x0100000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0100000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 52435875175126190479447740508185965837690552500527637822603658699938581184514 + 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 52435875175126190479447740508185965837690552500527637822603658699938581184514 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 @storage + 52435875175126190479447740508185965837690552500527637822603658699938581184514 @parameter ] + - location: 9 (remaining gas: 1039994.696 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 10 (remaining gas: 1039994.681 units remaining) + [ {} + 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039994.666 units remaining) + [ (Pair {} 0x0100000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x4147a5ad0a633e4880d2296f08ec5c1.92c153eb47.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x4147a5ad0a633e4880d2296f08ec5c1.92c153eb47.out new file mode 100644 index 000000000000..8e73c56d732d --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x4147a5ad0a633e4880d2296f08ec5c1.92c153eb47.out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f-22620284817922784902564672469917992996328211127984472897491698543785655336309-0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62] + +storage + 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 22620284817922784902564672469917992996328211127984472897491698543785655336309 + 0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 22620284817922784902564672469917992996328211127984472897491698543785655336309 @parameter + 0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f @storage + 22620284817922784902564672469917992996328211127984472897491698543785655336309 @parameter ] + - location: 9 (remaining gas: 1039994.696 units remaining) + [ 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62 ] + - location: 10 (remaining gas: 1039994.681 units remaining) + [ {} + 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62 ] + - location: 12 (remaining gas: 1039994.666 units remaining) + [ (Pair {} 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x5b0ecd0fa853810e356f1eb79721e80.290ab49d11.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x5b0ecd0fa853810e356f1eb79721e80.290ab49d11.out new file mode 100644 index 000000000000..76af244a91b0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x5b0ecd0fa853810e356f1eb79721e80.290ab49d11.out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f-33644916630334844239120348434626468649534186770809802792596996408934105684394-0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221] + +storage + 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 33644916630334844239120348434626468649534186770809802792596996408934105684394 + 0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 33644916630334844239120348434626468649534186770809802792596996408934105684394 @parameter + 0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f @storage + 33644916630334844239120348434626468649534186770809802792596996408934105684394 @parameter ] + - location: 9 (remaining gas: 1039994.696 units remaining) + [ 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221 ] + - location: 10 (remaining gas: 1039994.681 units remaining) + [ {} + 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221 ] + - location: 12 (remaining gas: 1039994.666 units remaining) + [ (Pair {} 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x8578be1766f92cd82c5e5135c374a03.69f3589a06.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x8578be1766f92cd82c5e5135c374a03.69f3589a06.out new file mode 100644 index 000000000000..13df5e50ca33 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x8578be1766f92cd82c5e5135c374a03.69f3589a06.out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d-17180093072794558806177035834397932205917577288483739652510482486858834123369-0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221] + +storage + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 17180093072794558806177035834397932205917577288483739652510482486858834123369 + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 17180093072794558806177035834397932205917577288483739652510482486858834123369 @parameter + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d @storage + 17180093072794558806177035834397932205917577288483739652510482486858834123369 @parameter ] + - location: 9 (remaining gas: 1039994.696 units remaining) + [ 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 10 (remaining gas: 1039994.681 units remaining) + [ {} + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 12 (remaining gas: 1039994.666 units remaining) + [ (Pair {} 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x8578be1766f92cd82c5e5135c374a03.fee3c5cf43.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x8578be1766f92cd82c5e5135c374a03.fee3c5cf43.out new file mode 100644 index 000000000000..f4a61e5ed405 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x8578be1766f92cd82c5e5135c374a03.fee3c5cf43.out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_int.tz-0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d-69615968247920749285624776342583898043608129789011377475114141186797415307882-0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221] + +storage + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 69615968247920749285624776342583898043608129789011377475114141186797415307882 + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 69615968247920749285624776342583898043608129789011377475114141186797415307882 @parameter + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d @storage + 69615968247920749285624776342583898043608129789011377475114141186797415307882 @parameter ] + - location: 9 (remaining gas: 1039994.696 units remaining) + [ 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 10 (remaining gas: 1039994.681 units remaining) + [ {} + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 12 (remaining gas: 1039994.666 units remaining) + [ (Pair {} 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.1bccc033e8.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.1bccc033e8.out new file mode 100644 index 000000000000..532df659a81c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.1bccc033e8.out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000000000000000000000000000000000000-52435875175126190479447740508185965837690552500527637822603658699938581184514-0x0100000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0100000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 52435875175126190479447740508185965837690552500527637822603658699938581184514 + 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 52435875175126190479447740508185965837690552500527637822603658699938581184514 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 @storage + 52435875175126190479447740508185965837690552500527637822603658699938581184514 @parameter ] + - location: 9 (remaining gas: 1039994.696 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 10 (remaining gas: 1039994.681 units remaining) + [ {} + 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039994.666 units remaining) + [ (Pair {} 0x0100000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.40958700fe.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.40958700fe.out new file mode 100644 index 000000000000..c2627ab6f7a4 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.40958700fe.out @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000000000000000000000000000000000000-0-0x0000000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0000000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 0 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 0 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 @storage + 0 @parameter ] + - location: 9 (remaining gas: 1039994.730 units remaining) + [ 0x0000000000000000000000000000000000000000000000000000000000000000 ] + - location: 10 (remaining gas: 1039994.715 units remaining) + [ {} + 0x0000000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039994.700 units remaining) + [ (Pair {} 0x0000000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.6c62b03d78.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.6c62b03d78.out new file mode 100644 index 000000000000..12b4e9bd33bb --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.6c62b03d78.out @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000000000000000000000000000000000000-1-0x0100000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0100000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 1 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 1 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 @storage + 1 @parameter ] + - location: 9 (remaining gas: 1039994.729 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 10 (remaining gas: 1039994.714 units remaining) + [ {} + 0x0100000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039994.699 units remaining) + [ (Pair {} 0x0100000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.d23f269341.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.d23f269341.out new file mode 100644 index 000000000000..6d15ee4583a2 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000.d23f269341.out @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x0100000000000000000000000000000000000000000000000000000000000000-2-0x0200000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0200000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 2 0x0100000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 2 @parameter + 0x0100000000000000000000000000000000000000000000000000000000000000 @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 @storage + 2 @parameter ] + - location: 9 (remaining gas: 1039994.729 units remaining) + [ 0x0200000000000000000000000000000000000000000000000000000000000000 ] + - location: 10 (remaining gas: 1039994.714 units remaining) + [ {} + 0x0200000000000000000000000000000000000000000000000000000000000000 ] + - location: 12 (remaining gas: 1039994.699 units remaining) + [ (Pair {} 0x0200000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x4147a5ad0a633e4880d2296f08ec5c1.927f808504.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x4147a5ad0a633e4880d2296f08ec5c1.927f808504.out new file mode 100644 index 000000000000..465a9c08357a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x4147a5ad0a633e4880d2296f08ec5c1.927f808504.out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f-22620284817922784902564672469917992996328211127984472897491698543785655336309-0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62] + +storage + 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 22620284817922784902564672469917992996328211127984472897491698543785655336309 + 0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 22620284817922784902564672469917992996328211127984472897491698543785655336309 @parameter + 0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfcdbe3f @storage + 22620284817922784902564672469917992996328211127984472897491698543785655336309 @parameter ] + - location: 9 (remaining gas: 1039994.696 units remaining) + [ 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62 ] + - location: 10 (remaining gas: 1039994.681 units remaining) + [ {} + 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62 ] + - location: 12 (remaining gas: 1039994.666 units remaining) + [ (Pair {} 0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe677c62) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x5b0ecd0fa853810e356f1eb79721e80.0c114c956a.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x5b0ecd0fa853810e356f1eb79721e80.0c114c956a.out new file mode 100644 index 000000000000..64cd79ba7519 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x5b0ecd0fa853810e356f1eb79721e80.0c114c956a.out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f-33644916630334844239120348434626468649534186770809802792596996408934105684394-0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221] + +storage + 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 33644916630334844239120348434626468649534186770809802792596996408934105684394 + 0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 33644916630334844239120348434626468649534186770809802792596996408934105684394 @parameter + 0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c5401f @storage + 33644916630334844239120348434626468649534186770809802792596996408934105684394 @parameter ] + - location: 9 (remaining gas: 1039994.696 units remaining) + [ 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221 ] + - location: 10 (remaining gas: 1039994.681 units remaining) + [ {} + 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221 ] + - location: 12 (remaining gas: 1039994.666 units remaining) + [ (Pair {} 0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x8578be1766f92cd82c5e5135c374a03.03c4f38e68.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x8578be1766f92cd82c5e5135c374a03.03c4f38e68.out new file mode 100644 index 000000000000..bb345c3230c6 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x8578be1766f92cd82c5e5135c374a03.03c4f38e68.out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d-69615968247920749285624776342583898043608129789011377475114141186797415307882-0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221] + +storage + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 69615968247920749285624776342583898043608129789011377475114141186797415307882 + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 69615968247920749285624776342583898043608129789011377475114141186797415307882 @parameter + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d @storage + 69615968247920749285624776342583898043608129789011377475114141186797415307882 @parameter ] + - location: 9 (remaining gas: 1039994.696 units remaining) + [ 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 10 (remaining gas: 1039994.681 units remaining) + [ {} + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 12 (remaining gas: 1039994.666 units remaining) + [ (Pair {} 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x8578be1766f92cd82c5e5135c374a03.8ed19cfdd9.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x8578be1766f92cd82c5e5135c374a03.8ed19cfdd9.out new file mode 100644 index 000000000000..fd8931a3e160 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x8578be1766f92cd82c5e5135c374a03.8ed19cfdd9.out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[bls12_381_z_fr_nat.tz-0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d-17180093072794558806177035834397932205917577288483739652510482486858834123369-0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221] + +storage + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.020 units remaining) + [ (Pair 17180093072794558806177035834397932205917577288483739652510482486858834123369 + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d) ] + - location: 7 (remaining gas: 1039995.010 units remaining) + [ 17180093072794558806177035834397932205917577288483739652510482486858834123369 @parameter + 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d @storage ] + - location: 8 (remaining gas: 1039995 units remaining) + [ 0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7fcf2d @storage + 17180093072794558806177035834397932205917577288483739652510482486858834123369 @parameter ] + - location: 9 (remaining gas: 1039994.696 units remaining) + [ 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 10 (remaining gas: 1039994.681 units remaining) + [ {} + 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221 ] + - location: 12 (remaining gas: 1039994.666 units remaining) + [ (Pair {} 0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddecbf221) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[car.tz-0-(Pair 34 17)-34].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[car.tz-0-(Pair 34 17)-34].out new file mode 100644 index 000000000000..58033e51a855 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[car.tz-0-(Pair 34 17)-34].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[car.tz-0-(Pair 34 17)-34] + +storage + 34 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039995.212 units remaining) + [ (Pair (Pair 34 17) 0) ] + - location: 9 (remaining gas: 1039995.202 units remaining) + [ (Pair 34 17) @parameter ] + - location: 10 (remaining gas: 1039995.192 units remaining) + [ 34 ] + - location: 11 (remaining gas: 1039995.177 units remaining) + [ {} + 34 ] + - location: 13 (remaining gas: 1039995.162 units remaining) + [ (Pair {} 34) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cdr.tz-0-(Pair 34 17)-17].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cdr.tz-0-(Pair 34 17)-17].out new file mode 100644 index 000000000000..e5bd58733352 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cdr.tz-0-(Pair 34 17)-17].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[cdr.tz-0-(Pair 34 17)-17] + +storage + 17 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039995.212 units remaining) + [ (Pair (Pair 34 17) 0) ] + - location: 9 (remaining gas: 1039995.202 units remaining) + [ (Pair 34 17) @parameter ] + - location: 10 (remaining gas: 1039995.192 units remaining) + [ 17 ] + - location: 11 (remaining gas: 1039995.177 units remaining) + [ {} + 17 ] + - location: 13 (remaining gas: 1039995.162 units remaining) + [ (Pair {} 17) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[chain_id_store.tz-(Some \"NetXdQprcVkpaWU\")-Unit-(Some \".8420090f97.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[chain_id_store.tz-(Some \"NetXdQprcVkpaWU\")-Unit-(Some \".8420090f97.out" new file mode 100644 index 000000000000..a6fd182e3a04 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[chain_id_store.tz-(Some \"NetXdQprcVkpaWU\")-Unit-(Some \".8420090f97.out" @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[chain_id_store.tz-(Some "NetXdQprcVkpaWU")-Unit-(Some "NetXdQprcVkpaWU")] + +storage + (Some "NetXdQprcVkpaWU") +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039993.357 units remaining) + [ (Pair Unit (Some "NetXdQprcVkpaWU")) ] + - location: 8 (remaining gas: 1039993.347 units remaining) + [ ] + - location: 9 (remaining gas: 1039993.332 units remaining) + [ "NetXdQprcVkpaWU" ] + - location: 10 (remaining gas: 1039993.317 units remaining) + [ (Some "NetXdQprcVkpaWU") ] + - location: 11 (remaining gas: 1039993.302 units remaining) + [ {} + (Some "NetXdQprcVkpaWU") ] + - location: 13 (remaining gas: 1039993.287 units remaining) + [ (Pair {} (Some "NetXdQprcVkpaWU")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[chain_id_store.tz-(Some 0x7a06a770)-Unit-(Some \"NetXdQprcVkpaWU\")].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[chain_id_store.tz-(Some 0x7a06a770)-Unit-(Some \"NetXdQprcVkpaWU\")].out" new file mode 100644 index 000000000000..b86d253d9b0a --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[chain_id_store.tz-(Some 0x7a06a770)-Unit-(Some \"NetXdQprcVkpaWU\")].out" @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[chain_id_store.tz-(Some 0x7a06a770)-Unit-(Some "NetXdQprcVkpaWU")] + +storage + (Some "NetXdQprcVkpaWU") +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.707 units remaining) + [ (Pair Unit (Some "NetXdQprcVkpaWU")) ] + - location: 8 (remaining gas: 1039994.697 units remaining) + [ ] + - location: 9 (remaining gas: 1039994.682 units remaining) + [ "NetXdQprcVkpaWU" ] + - location: 10 (remaining gas: 1039994.667 units remaining) + [ (Some "NetXdQprcVkpaWU") ] + - location: 11 (remaining gas: 1039994.652 units remaining) + [ {} + (Some "NetXdQprcVkpaWU") ] + - location: 13 (remaining gas: 1039994.637 units remaining) + [ (Pair {} (Some "NetXdQprcVkpaWU")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[chain_id_store.tz-None-Unit-(Some \"NetXdQprcVkpaWU\")].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[chain_id_store.tz-None-Unit-(Some \"NetXdQprcVkpaWU\")].out" new file mode 100644 index 000000000000..3525b0aa7fb3 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[chain_id_store.tz-None-Unit-(Some \"NetXdQprcVkpaWU\")].out" @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[chain_id_store.tz-None-Unit-(Some "NetXdQprcVkpaWU")] + +storage + (Some "NetXdQprcVkpaWU") +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.857 units remaining) + [ (Pair Unit None) ] + - location: 8 (remaining gas: 1039994.847 units remaining) + [ ] + - location: 9 (remaining gas: 1039994.832 units remaining) + [ "NetXdQprcVkpaWU" ] + - location: 10 (remaining gas: 1039994.817 units remaining) + [ (Some "NetXdQprcVkpaWU") ] + - location: 11 (remaining gas: 1039994.802 units remaining) + [ {} + (Some "NetXdQprcVkpaWU") ] + - location: 13 (remaining gas: 1039994.787 units remaining) + [ (Pair {} (Some "NetXdQprcVkpaWU")) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb-get.tz-Unit-(Pair 1 4 2 Unit)-Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb-get.tz-Unit-(Pair 1 4 2 Unit)-Unit].out new file mode 100644 index 000000000000..b26de172561b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb-get.tz-Unit-(Pair 1 4 2 Unit)-Unit].out @@ -0,0 +1,123 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[comb-get.tz-Unit-(Pair 1 4 2 Unit)-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039952.262 units remaining) + [ (Pair (Pair 1 4 2 Unit) Unit) ] + - location: 11 (remaining gas: 1039952.252 units remaining) + [ (Pair 1 4 2 Unit) @parameter ] + - location: 12 (remaining gas: 1039952.242 units remaining) + [ (Pair 1 4 2 Unit) @parameter + (Pair 1 4 2 Unit) @parameter ] + - location: 13 (remaining gas: 1039952.232 units remaining) + [ 1 + (Pair 1 4 2 Unit) @parameter ] + - location: 14 (remaining gas: 1039952.222 units remaining) + [ 1 + 1 + (Pair 1 4 2 Unit) @parameter ] + - location: 19 (remaining gas: 1039952.187 units remaining) + [ 0 + (Pair 1 4 2 Unit) @parameter ] + - location: 20 (remaining gas: 1039952.172 units remaining) + [ True + (Pair 1 4 2 Unit) @parameter ] + - location: 21 (remaining gas: 1039952.162 units remaining) + [ (Pair 1 4 2 Unit) @parameter ] + - location: 21 (remaining gas: 1039952.147 units remaining) + [ (Pair 1 4 2 Unit) @parameter ] + - location: 27 (remaining gas: 1039952.137 units remaining) + [ (Pair 1 4 2 Unit) @parameter + (Pair 1 4 2 Unit) @parameter ] + - location: 28 (remaining gas: 1039952.107 units remaining) + [ 1 + (Pair 1 4 2 Unit) @parameter ] + - location: 30 (remaining gas: 1039952.097 units remaining) + [ 1 + 1 + (Pair 1 4 2 Unit) @parameter ] + - location: 35 (remaining gas: 1039952.062 units remaining) + [ 0 + (Pair 1 4 2 Unit) @parameter ] + - location: 36 (remaining gas: 1039952.047 units remaining) + [ True + (Pair 1 4 2 Unit) @parameter ] + - location: 37 (remaining gas: 1039952.037 units remaining) + [ (Pair 1 4 2 Unit) @parameter ] + - location: 37 (remaining gas: 1039952.022 units remaining) + [ (Pair 1 4 2 Unit) @parameter ] + - location: 43 (remaining gas: 1039952.012 units remaining) + [ (Pair 1 4 2 Unit) @parameter + (Pair 1 4 2 Unit) @parameter ] + - location: 44 (remaining gas: 1039951.981 units remaining) + [ 4 + (Pair 1 4 2 Unit) @parameter ] + - location: 46 (remaining gas: 1039951.971 units remaining) + [ 4 + 4 + (Pair 1 4 2 Unit) @parameter ] + - location: 51 (remaining gas: 1039951.936 units remaining) + [ 0 + (Pair 1 4 2 Unit) @parameter ] + - location: 52 (remaining gas: 1039951.921 units remaining) + [ True + (Pair 1 4 2 Unit) @parameter ] + - location: 53 (remaining gas: 1039951.911 units remaining) + [ (Pair 1 4 2 Unit) @parameter ] + - location: 53 (remaining gas: 1039951.896 units remaining) + [ (Pair 1 4 2 Unit) @parameter ] + - location: 59 (remaining gas: 1039951.886 units remaining) + [ (Pair 1 4 2 Unit) @parameter + (Pair 1 4 2 Unit) @parameter ] + - location: 60 (remaining gas: 1039951.854 units remaining) + [ 2 + (Pair 1 4 2 Unit) @parameter ] + - location: 62 (remaining gas: 1039951.844 units remaining) + [ 2 + 2 + (Pair 1 4 2 Unit) @parameter ] + - location: 67 (remaining gas: 1039951.809 units remaining) + [ 0 + (Pair 1 4 2 Unit) @parameter ] + - location: 68 (remaining gas: 1039951.794 units remaining) + [ True + (Pair 1 4 2 Unit) @parameter ] + - location: 69 (remaining gas: 1039951.784 units remaining) + [ (Pair 1 4 2 Unit) @parameter ] + - location: 69 (remaining gas: 1039951.769 units remaining) + [ (Pair 1 4 2 Unit) @parameter ] + - location: 75 (remaining gas: 1039951.759 units remaining) + [ (Pair 1 4 2 Unit) @parameter + (Pair 1 4 2 Unit) @parameter ] + - location: 76 (remaining gas: 1039951.726 units remaining) + [ Unit + (Pair 1 4 2 Unit) @parameter ] + - location: 78 (remaining gas: 1039951.716 units remaining) + [ Unit + Unit + (Pair 1 4 2 Unit) @parameter ] + - location: 81 (remaining gas: 1039951.706 units remaining) + [ 0 + (Pair 1 4 2 Unit) @parameter ] + - location: 82 (remaining gas: 1039951.691 units remaining) + [ True + (Pair 1 4 2 Unit) @parameter ] + - location: 83 (remaining gas: 1039951.681 units remaining) + [ (Pair 1 4 2 Unit) @parameter ] + - location: 83 (remaining gas: 1039951.666 units remaining) + [ (Pair 1 4 2 Unit) @parameter ] + - location: 89 (remaining gas: 1039951.656 units remaining) + [ ] + - location: 90 (remaining gas: 1039951.646 units remaining) + [ Unit ] + - location: 91 (remaining gas: 1039951.631 units remaining) + [ {} + Unit ] + - location: 93 (remaining gas: 1039951.616 units remaining) + [ (Pair {} Unit) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb-set-2.tz-None-(Pair 1 4 2 Unit)-(Some (Pair 2 4 \"t.886cc365c6.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb-set-2.tz-None-(Pair 1 4 2 Unit)-(Some (Pair 2 4 \"t.886cc365c6.out" new file mode 100644 index 000000000000..a17d00f3a7d1 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb-set-2.tz-None-(Pair 1 4 2 Unit)-(Some (Pair 2 4 \"t.886cc365c6.out" @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[comb-set-2.tz-None-(Pair 1 4 2 Unit)-(Some (Pair 2 4 "toto" 0x01))] + +storage + (Some (Pair 2 4 "toto" 0x01)) +emitted operations + +big_map diff + +trace + - location: 16 (remaining gas: 1039987.096 units remaining) + [ (Pair (Pair 1 4 2 Unit) None) ] + - location: 16 (remaining gas: 1039987.086 units remaining) + [ (Pair 1 4 2 Unit) @parameter ] + - location: 17 (remaining gas: 1039987.076 units remaining) + [ 2 + (Pair 1 4 2 Unit) @parameter ] + - location: 20 (remaining gas: 1039987.065 units remaining) + [ (Pair 2 4 2 Unit) ] + - location: 22 (remaining gas: 1039987.055 units remaining) + [ "toto" + (Pair 2 4 2 Unit) ] + - location: 25 (remaining gas: 1039987.039 units remaining) + [ (Pair 2 4 "toto" Unit) ] + - location: 27 (remaining gas: 1039987.029 units remaining) + [ 0x01 + (Pair 2 4 "toto" Unit) ] + - location: 30 (remaining gas: 1039987.012 units remaining) + [ (Pair 2 4 "toto" 0x01) ] + - location: 32 (remaining gas: 1039986.997 units remaining) + [ (Some (Pair 2 4 "toto" 0x01)) ] + - location: 33 (remaining gas: 1039986.982 units remaining) + [ {} + (Some (Pair 2 4 "toto" 0x01)) ] + - location: 35 (remaining gas: 1039986.967 units remaining) + [ (Pair {} (Some (Pair 2 4 "toto" 0x01))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb-set.tz-(Pair 1 4 2 Unit)-Unit-(Pair 2 12 8 Unit)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb-set.tz-(Pair 1 4 2 Unit)-Unit-(Pair 2 12 8 Unit)].out new file mode 100644 index 000000000000..bff0f1800b24 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb-set.tz-(Pair 1 4 2 Unit)-Unit-(Pair 2 12 8 Unit)].out @@ -0,0 +1,39 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[comb-set.tz-(Pair 1 4 2 Unit)-Unit-(Pair 2 12 8 Unit)] + +storage + (Pair 2 12 8 Unit) +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039987.253 units remaining) + [ (Pair Unit 1 4 2 Unit) ] + - location: 11 (remaining gas: 1039987.243 units remaining) + [ (Pair 1 4 2 Unit) @storage ] + - location: 12 (remaining gas: 1039987.233 units remaining) + [ 2 + (Pair 1 4 2 Unit) @storage ] + - location: 15 (remaining gas: 1039987.222 units remaining) + [ (Pair 2 4 2 Unit) ] + - location: 17 (remaining gas: 1039987.212 units remaining) + [ 12 + (Pair 2 4 2 Unit) ] + - location: 20 (remaining gas: 1039987.199 units remaining) + [ (Pair 2 12 2 Unit) ] + - location: 22 (remaining gas: 1039987.189 units remaining) + [ 8 + (Pair 2 12 2 Unit) ] + - location: 25 (remaining gas: 1039987.173 units remaining) + [ (Pair 2 12 8 Unit) ] + - location: 27 (remaining gas: 1039987.163 units remaining) + [ Unit + (Pair 2 12 8 Unit) ] + - location: 28 (remaining gas: 1039987.146 units remaining) + [ (Pair 2 12 8 Unit) ] + - location: 30 (remaining gas: 1039987.131 units remaining) + [ {} + (Pair 2 12 8 Unit) ] + - location: 32 (remaining gas: 1039987.116 units remaining) + [ (Pair {} 2 12 8 Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb.tz-(Pair 0 0 0)-Unit-(Pair 1 2 3)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb.tz-(Pair 0 0 0)-Unit-(Pair 1 2 3)].out new file mode 100644 index 000000000000..9464ef9b372b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comb.tz-(Pair 0 0 0)-Unit-(Pair 1 2 3)].out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[comb.tz-(Pair 0 0 0)-Unit-(Pair 1 2 3)] + +storage + (Pair 1 2 3) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039991.839 units remaining) + [ (Pair Unit 0 0 0) ] + - location: 10 (remaining gas: 1039991.829 units remaining) + [ ] + - location: 11 (remaining gas: 1039991.819 units remaining) + [ 3 ] + - location: 14 (remaining gas: 1039991.809 units remaining) + [ 2 + 3 ] + - location: 17 (remaining gas: 1039991.799 units remaining) + [ 1 + 2 + 3 ] + - location: 20 (remaining gas: 1039991.784 units remaining) + [ {} + 1 + 2 + 3 ] + - location: 22 (remaining gas: 1039991.770 units remaining) + [ (Pair {} 1 2 3) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[compare.tz-Unit-Unit-Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[compare.tz-Unit-Unit-Unit].out new file mode 100644 index 000000000000..68efed25aef8 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[compare.tz-Unit-Unit-Unit].out @@ -0,0 +1,398 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[compare.tz-Unit-Unit-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039789.508 units remaining) + [ (Pair Unit Unit) ] + - location: 7 (remaining gas: 1039789.498 units remaining) + [ ] + - location: 8 (remaining gas: 1039789.488 units remaining) + [ True ] + - location: 11 (remaining gas: 1039789.478 units remaining) + [ True + True ] + - location: 12 (remaining gas: 1039789.443 units remaining) + [ 0 ] + - location: 14 (remaining gas: 1039789.428 units remaining) + [ True ] + - location: 15 (remaining gas: 1039789.418 units remaining) + [ ] + - location: 15 (remaining gas: 1039789.403 units remaining) + [ ] + - location: 21 (remaining gas: 1039789.393 units remaining) + [ False ] + - location: 24 (remaining gas: 1039789.383 units remaining) + [ False + False ] + - location: 25 (remaining gas: 1039789.348 units remaining) + [ 0 ] + - location: 27 (remaining gas: 1039789.333 units remaining) + [ True ] + - location: 28 (remaining gas: 1039789.323 units remaining) + [ ] + - location: 28 (remaining gas: 1039789.308 units remaining) + [ ] + - location: 34 (remaining gas: 1039789.298 units remaining) + [ False ] + - location: 37 (remaining gas: 1039789.288 units remaining) + [ True + False ] + - location: 40 (remaining gas: 1039789.253 units remaining) + [ 1 ] + - location: 42 (remaining gas: 1039789.238 units remaining) + [ True ] + - location: 43 (remaining gas: 1039789.228 units remaining) + [ ] + - location: 43 (remaining gas: 1039789.213 units remaining) + [ ] + - location: 49 (remaining gas: 1039789.203 units remaining) + [ True ] + - location: 52 (remaining gas: 1039789.193 units remaining) + [ False + True ] + - location: 55 (remaining gas: 1039789.158 units remaining) + [ -1 ] + - location: 57 (remaining gas: 1039789.143 units remaining) + [ True ] + - location: 58 (remaining gas: 1039789.133 units remaining) + [ ] + - location: 58 (remaining gas: 1039789.118 units remaining) + [ ] + - location: 64 (remaining gas: 1039789.108 units remaining) + [ 0xaabbcc ] + - location: 67 (remaining gas: 1039789.098 units remaining) + [ 0xaabbcc + 0xaabbcc ] + - location: 68 (remaining gas: 1039789.063 units remaining) + [ 0 ] + - location: 70 (remaining gas: 1039789.048 units remaining) + [ True ] + - location: 71 (remaining gas: 1039789.038 units remaining) + [ ] + - location: 71 (remaining gas: 1039789.023 units remaining) + [ ] + - location: 77 (remaining gas: 1039789.013 units remaining) + [ 0x ] + - location: 80 (remaining gas: 1039789.003 units remaining) + [ 0x + 0x ] + - location: 83 (remaining gas: 1039788.968 units remaining) + [ 0 ] + - location: 85 (remaining gas: 1039788.953 units remaining) + [ True ] + - location: 86 (remaining gas: 1039788.943 units remaining) + [ ] + - location: 86 (remaining gas: 1039788.928 units remaining) + [ ] + - location: 92 (remaining gas: 1039788.918 units remaining) + [ 0x ] + - location: 95 (remaining gas: 1039788.908 units remaining) + [ 0x01 + 0x ] + - location: 98 (remaining gas: 1039788.873 units remaining) + [ 1 ] + - location: 100 (remaining gas: 1039788.858 units remaining) + [ True ] + - location: 101 (remaining gas: 1039788.848 units remaining) + [ ] + - location: 101 (remaining gas: 1039788.833 units remaining) + [ ] + - location: 107 (remaining gas: 1039788.823 units remaining) + [ 0x01 ] + - location: 110 (remaining gas: 1039788.813 units remaining) + [ 0x02 + 0x01 ] + - location: 113 (remaining gas: 1039788.778 units remaining) + [ 1 ] + - location: 115 (remaining gas: 1039788.763 units remaining) + [ True ] + - location: 116 (remaining gas: 1039788.753 units remaining) + [ ] + - location: 116 (remaining gas: 1039788.738 units remaining) + [ ] + - location: 122 (remaining gas: 1039788.728 units remaining) + [ 0x02 ] + - location: 125 (remaining gas: 1039788.718 units remaining) + [ 0x01 + 0x02 ] + - location: 128 (remaining gas: 1039788.683 units remaining) + [ -1 ] + - location: 130 (remaining gas: 1039788.668 units remaining) + [ True ] + - location: 131 (remaining gas: 1039788.658 units remaining) + [ ] + - location: 131 (remaining gas: 1039788.643 units remaining) + [ ] + - location: 137 (remaining gas: 1039788.633 units remaining) + [ 1 ] + - location: 140 (remaining gas: 1039788.623 units remaining) + [ 1 + 1 ] + - location: 141 (remaining gas: 1039788.588 units remaining) + [ 0 ] + - location: 143 (remaining gas: 1039788.573 units remaining) + [ True ] + - location: 144 (remaining gas: 1039788.563 units remaining) + [ ] + - location: 144 (remaining gas: 1039788.548 units remaining) + [ ] + - location: 150 (remaining gas: 1039788.538 units remaining) + [ 10 ] + - location: 153 (remaining gas: 1039788.528 units remaining) + [ 5 + 10 ] + - location: 156 (remaining gas: 1039788.493 units remaining) + [ -1 ] + - location: 158 (remaining gas: 1039788.478 units remaining) + [ True ] + - location: 159 (remaining gas: 1039788.468 units remaining) + [ ] + - location: 159 (remaining gas: 1039788.453 units remaining) + [ ] + - location: 165 (remaining gas: 1039788.443 units remaining) + [ -4 ] + - location: 168 (remaining gas: 1039788.433 units remaining) + [ 1923 + -4 ] + - location: 171 (remaining gas: 1039788.398 units remaining) + [ 1 ] + - location: 173 (remaining gas: 1039788.383 units remaining) + [ True ] + - location: 174 (remaining gas: 1039788.373 units remaining) + [ ] + - location: 174 (remaining gas: 1039788.358 units remaining) + [ ] + - location: 180 (remaining gas: 1039788.348 units remaining) + [ 1 ] + - location: 183 (remaining gas: 1039788.338 units remaining) + [ 1 + 1 ] + - location: 184 (remaining gas: 1039788.303 units remaining) + [ 0 ] + - location: 186 (remaining gas: 1039788.288 units remaining) + [ True ] + - location: 187 (remaining gas: 1039788.278 units remaining) + [ ] + - location: 187 (remaining gas: 1039788.263 units remaining) + [ ] + - location: 193 (remaining gas: 1039788.253 units remaining) + [ 10 ] + - location: 196 (remaining gas: 1039788.243 units remaining) + [ 5 + 10 ] + - location: 199 (remaining gas: 1039788.208 units remaining) + [ -1 ] + - location: 201 (remaining gas: 1039788.193 units remaining) + [ True ] + - location: 202 (remaining gas: 1039788.183 units remaining) + [ ] + - location: 202 (remaining gas: 1039788.168 units remaining) + [ ] + - location: 208 (remaining gas: 1039788.158 units remaining) + [ 4 ] + - location: 211 (remaining gas: 1039788.148 units remaining) + [ 1923 + 4 ] + - location: 214 (remaining gas: 1039788.113 units remaining) + [ 1 ] + - location: 216 (remaining gas: 1039788.098 units remaining) + [ True ] + - location: 217 (remaining gas: 1039788.088 units remaining) + [ ] + - location: 217 (remaining gas: 1039788.073 units remaining) + [ ] + - location: 223 (remaining gas: 1039788.063 units remaining) + [ "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" ] + - location: 226 (remaining gas: 1039788.053 units remaining) + [ "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" + "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" ] + - location: 227 (remaining gas: 1039788.017 units remaining) + [ 0 ] + - location: 229 (remaining gas: 1039788.002 units remaining) + [ True ] + - location: 230 (remaining gas: 1039787.992 units remaining) + [ ] + - location: 230 (remaining gas: 1039787.977 units remaining) + [ ] + - location: 236 (remaining gas: 1039787.967 units remaining) + [ "tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv" ] + - location: 239 (remaining gas: 1039787.957 units remaining) + [ "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" + "tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv" ] + - location: 242 (remaining gas: 1039787.921 units remaining) + [ -1 ] + - location: 244 (remaining gas: 1039787.906 units remaining) + [ True ] + - location: 245 (remaining gas: 1039787.896 units remaining) + [ ] + - location: 245 (remaining gas: 1039787.881 units remaining) + [ ] + - location: 251 (remaining gas: 1039787.871 units remaining) + [ "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" ] + - location: 254 (remaining gas: 1039787.861 units remaining) + [ "tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv" + "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" ] + - location: 257 (remaining gas: 1039787.825 units remaining) + [ 1 ] + - location: 259 (remaining gas: 1039787.810 units remaining) + [ True ] + - location: 260 (remaining gas: 1039787.800 units remaining) + [ ] + - location: 260 (remaining gas: 1039787.785 units remaining) + [ ] + - location: 266 (remaining gas: 1039787.775 units remaining) + [ 1 ] + - location: 269 (remaining gas: 1039787.765 units remaining) + [ 1 + 1 ] + - location: 270 (remaining gas: 1039787.730 units remaining) + [ 0 ] + - location: 272 (remaining gas: 1039787.715 units remaining) + [ True ] + - location: 273 (remaining gas: 1039787.705 units remaining) + [ ] + - location: 273 (remaining gas: 1039787.690 units remaining) + [ ] + - location: 279 (remaining gas: 1039787.680 units remaining) + [ 10 ] + - location: 282 (remaining gas: 1039787.670 units remaining) + [ 5 + 10 ] + - location: 285 (remaining gas: 1039787.635 units remaining) + [ -1 ] + - location: 287 (remaining gas: 1039787.620 units remaining) + [ True ] + - location: 288 (remaining gas: 1039787.610 units remaining) + [ ] + - location: 288 (remaining gas: 1039787.595 units remaining) + [ ] + - location: 294 (remaining gas: 1039787.585 units remaining) + [ 4 ] + - location: 297 (remaining gas: 1039787.575 units remaining) + [ 1923 + 4 ] + - location: 300 (remaining gas: 1039787.540 units remaining) + [ 1 ] + - location: 302 (remaining gas: 1039787.525 units remaining) + [ True ] + - location: 303 (remaining gas: 1039787.515 units remaining) + [ ] + - location: 303 (remaining gas: 1039787.500 units remaining) + [ ] + - location: 309 (remaining gas: 1039787.490 units remaining) + [ "AABBCC" ] + - location: 312 (remaining gas: 1039787.480 units remaining) + [ "AABBCC" + "AABBCC" ] + - location: 313 (remaining gas: 1039787.445 units remaining) + [ 0 ] + - location: 315 (remaining gas: 1039787.430 units remaining) + [ True ] + - location: 316 (remaining gas: 1039787.420 units remaining) + [ ] + - location: 316 (remaining gas: 1039787.405 units remaining) + [ ] + - location: 322 (remaining gas: 1039787.395 units remaining) + [ "" ] + - location: 325 (remaining gas: 1039787.385 units remaining) + [ "" + "" ] + - location: 328 (remaining gas: 1039787.350 units remaining) + [ 0 ] + - location: 330 (remaining gas: 1039787.335 units remaining) + [ True ] + - location: 331 (remaining gas: 1039787.325 units remaining) + [ ] + - location: 331 (remaining gas: 1039787.310 units remaining) + [ ] + - location: 337 (remaining gas: 1039787.300 units remaining) + [ "" ] + - location: 340 (remaining gas: 1039787.290 units remaining) + [ "a" + "" ] + - location: 343 (remaining gas: 1039787.255 units remaining) + [ 1 ] + - location: 345 (remaining gas: 1039787.240 units remaining) + [ True ] + - location: 346 (remaining gas: 1039787.230 units remaining) + [ ] + - location: 346 (remaining gas: 1039787.215 units remaining) + [ ] + - location: 352 (remaining gas: 1039787.205 units remaining) + [ "a" ] + - location: 355 (remaining gas: 1039787.195 units remaining) + [ "b" + "a" ] + - location: 358 (remaining gas: 1039787.160 units remaining) + [ 1 ] + - location: 360 (remaining gas: 1039787.145 units remaining) + [ True ] + - location: 361 (remaining gas: 1039787.135 units remaining) + [ ] + - location: 361 (remaining gas: 1039787.120 units remaining) + [ ] + - location: 367 (remaining gas: 1039787.110 units remaining) + [ "b" ] + - location: 370 (remaining gas: 1039787.100 units remaining) + [ "a" + "b" ] + - location: 373 (remaining gas: 1039787.065 units remaining) + [ -1 ] + - location: 375 (remaining gas: 1039787.050 units remaining) + [ True ] + - location: 376 (remaining gas: 1039787.040 units remaining) + [ ] + - location: 376 (remaining gas: 1039787.025 units remaining) + [ ] + - location: 382 (remaining gas: 1039787.015 units remaining) + [ "2019-09-16T08:38:05Z" ] + - location: 385 (remaining gas: 1039787.005 units remaining) + [ "2019-09-16T08:38:05Z" + "2019-09-16T08:38:05Z" ] + - location: 386 (remaining gas: 1039786.970 units remaining) + [ 0 ] + - location: 388 (remaining gas: 1039786.955 units remaining) + [ True ] + - location: 389 (remaining gas: 1039786.945 units remaining) + [ ] + - location: 389 (remaining gas: 1039786.930 units remaining) + [ ] + - location: 395 (remaining gas: 1039786.920 units remaining) + [ "2017-09-16T08:38:04Z" ] + - location: 398 (remaining gas: 1039786.910 units remaining) + [ "2019-09-16T08:38:05Z" + "2017-09-16T08:38:04Z" ] + - location: 401 (remaining gas: 1039786.875 units remaining) + [ 1 ] + - location: 403 (remaining gas: 1039786.860 units remaining) + [ True ] + - location: 404 (remaining gas: 1039786.850 units remaining) + [ ] + - location: 404 (remaining gas: 1039786.835 units remaining) + [ ] + - location: 410 (remaining gas: 1039786.825 units remaining) + [ "2019-09-16T08:38:05Z" ] + - location: 413 (remaining gas: 1039786.815 units remaining) + [ "2019-09-16T08:38:04Z" + "2019-09-16T08:38:05Z" ] + - location: 416 (remaining gas: 1039786.780 units remaining) + [ -1 ] + - location: 418 (remaining gas: 1039786.765 units remaining) + [ True ] + - location: 419 (remaining gas: 1039786.755 units remaining) + [ ] + - location: 419 (remaining gas: 1039786.740 units remaining) + [ ] + - location: 425 (remaining gas: 1039786.730 units remaining) + [ Unit ] + - location: 426 (remaining gas: 1039786.715 units remaining) + [ {} + Unit ] + - location: 428 (remaining gas: 1039786.700 units remaining) + [ (Pair {} Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comparisons.tz-{}-{ -9999999; -1 ; 0 ; 1 ; 9999999 }-{ .bbaa8924d2.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comparisons.tz-{}-{ -9999999; -1 ; 0 ; 1 ; 9999999 }-{ .bbaa8924d2.out new file mode 100644 index 000000000000..70c37e3da752 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[comparisons.tz-{}-{ -9999999; -1 ; 0 ; 1 ; 9999999 }-{ .bbaa8924d2.out @@ -0,0 +1,350 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[comparisons.tz-{}-{ -9999999; -1 ; 0 ; 1 ; 9999999 }-{ { False ; False ; False ; True ; True } ;\n { False ; False ; True ; True ; True } ;\n { True ; True ; False ; False ; False } ;\n { True ; True ; True ; False ; False } ;\n { True ; True ; False ; True ; True } ;\n { False ; False ; True ; False ; False } }] + +storage + { { False ; False ; False ; True ; True } ; + { False ; False ; True ; True ; True } ; + { True ; True ; False ; False ; False } ; + { True ; True ; True ; False ; False } ; + { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039967.677 units remaining) + [ (Pair { -9999999 ; -1 ; 0 ; 1 ; 9999999 } {}) ] + - location: 10 (remaining gas: 1039967.667 units remaining) + [ { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 11 (remaining gas: 1039967.652 units remaining) + [ {} + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 14 (remaining gas: 1039967.637 units remaining) + [ { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 16 (remaining gas: 1039967.627 units remaining) + [ { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 17 (remaining gas: 1039967.627 units remaining) + [ -9999999 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 19 (remaining gas: 1039967.612 units remaining) + [ False + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 17 (remaining gas: 1039967.597 units remaining) + [ -1 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 19 (remaining gas: 1039967.582 units remaining) + [ False + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 17 (remaining gas: 1039967.567 units remaining) + [ 0 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 19 (remaining gas: 1039967.552 units remaining) + [ True + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 17 (remaining gas: 1039967.537 units remaining) + [ 1 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 19 (remaining gas: 1039967.522 units remaining) + [ False + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 17 (remaining gas: 1039967.507 units remaining) + [ 9999999 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 19 (remaining gas: 1039967.492 units remaining) + [ False + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 17 (remaining gas: 1039967.477 units remaining) + [ { False ; False ; True ; False ; False } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 14 (remaining gas: 1039967.447 units remaining) + [ {} + { False ; False ; True ; False ; False } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 20 (remaining gas: 1039967.437 units remaining) + [ { False ; False ; True ; False ; False } + {} + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 21 (remaining gas: 1039967.422 units remaining) + [ { { False ; False ; True ; False ; False } } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 22 (remaining gas: 1039967.407 units remaining) + [ { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 24 (remaining gas: 1039967.397 units remaining) + [ { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 25 (remaining gas: 1039967.397 units remaining) + [ -9999999 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 27 (remaining gas: 1039967.382 units remaining) + [ True + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 25 (remaining gas: 1039967.367 units remaining) + [ -1 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 27 (remaining gas: 1039967.352 units remaining) + [ True + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 25 (remaining gas: 1039967.337 units remaining) + [ 0 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 27 (remaining gas: 1039967.322 units remaining) + [ False + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 25 (remaining gas: 1039967.307 units remaining) + [ 1 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 27 (remaining gas: 1039967.292 units remaining) + [ True + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 25 (remaining gas: 1039967.277 units remaining) + [ 9999999 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 27 (remaining gas: 1039967.262 units remaining) + [ True + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 25 (remaining gas: 1039967.247 units remaining) + [ { True ; True ; False ; True ; True } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 22 (remaining gas: 1039967.217 units remaining) + [ { { False ; False ; True ; False ; False } } + { True ; True ; False ; True ; True } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 28 (remaining gas: 1039967.207 units remaining) + [ { True ; True ; False ; True ; True } + { { False ; False ; True ; False ; False } } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 29 (remaining gas: 1039967.192 units remaining) + [ { { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 30 (remaining gas: 1039967.177 units remaining) + [ { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 32 (remaining gas: 1039967.167 units remaining) + [ { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 33 (remaining gas: 1039967.167 units remaining) + [ -9999999 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 35 (remaining gas: 1039967.152 units remaining) + [ True + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 33 (remaining gas: 1039967.137 units remaining) + [ -1 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 35 (remaining gas: 1039967.122 units remaining) + [ True + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 33 (remaining gas: 1039967.107 units remaining) + [ 0 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 35 (remaining gas: 1039967.092 units remaining) + [ True + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 33 (remaining gas: 1039967.077 units remaining) + [ 1 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 35 (remaining gas: 1039967.062 units remaining) + [ False + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 33 (remaining gas: 1039967.047 units remaining) + [ 9999999 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 35 (remaining gas: 1039967.032 units remaining) + [ False + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 33 (remaining gas: 1039967.017 units remaining) + [ { True ; True ; True ; False ; False } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 30 (remaining gas: 1039966.987 units remaining) + [ { { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } + { True ; True ; True ; False ; False } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 36 (remaining gas: 1039966.977 units remaining) + [ { True ; True ; True ; False ; False } + { { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 37 (remaining gas: 1039966.962 units remaining) + [ { { True ; True ; True ; False ; False } ; + { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 38 (remaining gas: 1039966.947 units remaining) + [ { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 40 (remaining gas: 1039966.937 units remaining) + [ { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 41 (remaining gas: 1039966.937 units remaining) + [ -9999999 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 43 (remaining gas: 1039966.922 units remaining) + [ True + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 41 (remaining gas: 1039966.907 units remaining) + [ -1 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 43 (remaining gas: 1039966.892 units remaining) + [ True + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 41 (remaining gas: 1039966.877 units remaining) + [ 0 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 43 (remaining gas: 1039966.862 units remaining) + [ False + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 41 (remaining gas: 1039966.847 units remaining) + [ 1 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 43 (remaining gas: 1039966.832 units remaining) + [ False + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 41 (remaining gas: 1039966.817 units remaining) + [ 9999999 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 43 (remaining gas: 1039966.802 units remaining) + [ False + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 41 (remaining gas: 1039966.787 units remaining) + [ { True ; True ; False ; False ; False } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 38 (remaining gas: 1039966.757 units remaining) + [ { { True ; True ; True ; False ; False } ; + { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } + { True ; True ; False ; False ; False } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 44 (remaining gas: 1039966.747 units remaining) + [ { True ; True ; False ; False ; False } + { { True ; True ; True ; False ; False } ; + { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 45 (remaining gas: 1039966.732 units remaining) + [ { { True ; True ; False ; False ; False } ; + { True ; True ; True ; False ; False } ; + { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 46 (remaining gas: 1039966.717 units remaining) + [ { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 48 (remaining gas: 1039966.707 units remaining) + [ { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 49 (remaining gas: 1039966.707 units remaining) + [ -9999999 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 51 (remaining gas: 1039966.692 units remaining) + [ False + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 49 (remaining gas: 1039966.677 units remaining) + [ -1 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 51 (remaining gas: 1039966.662 units remaining) + [ False + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 49 (remaining gas: 1039966.647 units remaining) + [ 0 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 51 (remaining gas: 1039966.632 units remaining) + [ True + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 49 (remaining gas: 1039966.617 units remaining) + [ 1 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 51 (remaining gas: 1039966.602 units remaining) + [ True + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 49 (remaining gas: 1039966.587 units remaining) + [ 9999999 @parameter.elt + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 51 (remaining gas: 1039966.572 units remaining) + [ True + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 49 (remaining gas: 1039966.557 units remaining) + [ { False ; False ; True ; True ; True } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 46 (remaining gas: 1039966.527 units remaining) + [ { { True ; True ; False ; False ; False } ; + { True ; True ; True ; False ; False } ; + { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } + { False ; False ; True ; True ; True } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 52 (remaining gas: 1039966.517 units remaining) + [ { False ; False ; True ; True ; True } + { { True ; True ; False ; False ; False } ; + { True ; True ; True ; False ; False } ; + { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 53 (remaining gas: 1039966.502 units remaining) + [ { { False ; False ; True ; True ; True } ; + { True ; True ; False ; False ; False } ; + { True ; True ; True ; False ; False } ; + { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } + { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 54 (remaining gas: 1039966.487 units remaining) + [ { -9999999 ; -1 ; 0 ; 1 ; 9999999 } @parameter ] + - location: 56 (remaining gas: 1039966.487 units remaining) + [ -9999999 @parameter.elt ] + - location: 58 (remaining gas: 1039966.472 units remaining) + [ False ] + - location: 56 (remaining gas: 1039966.457 units remaining) + [ -1 @parameter.elt ] + - location: 58 (remaining gas: 1039966.442 units remaining) + [ False ] + - location: 56 (remaining gas: 1039966.427 units remaining) + [ 0 @parameter.elt ] + - location: 58 (remaining gas: 1039966.412 units remaining) + [ False ] + - location: 56 (remaining gas: 1039966.397 units remaining) + [ 1 @parameter.elt ] + - location: 58 (remaining gas: 1039966.382 units remaining) + [ True ] + - location: 56 (remaining gas: 1039966.367 units remaining) + [ 9999999 @parameter.elt ] + - location: 58 (remaining gas: 1039966.352 units remaining) + [ True ] + - location: 56 (remaining gas: 1039966.337 units remaining) + [ { False ; False ; False ; True ; True } ] + - location: 54 (remaining gas: 1039966.307 units remaining) + [ { { False ; False ; True ; True ; True } ; + { True ; True ; False ; False ; False } ; + { True ; True ; True ; False ; False } ; + { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } + { False ; False ; False ; True ; True } ] + - location: 59 (remaining gas: 1039966.297 units remaining) + [ { False ; False ; False ; True ; True } + { { False ; False ; True ; True ; True } ; + { True ; True ; False ; False ; False } ; + { True ; True ; True ; False ; False } ; + { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } ] + - location: 60 (remaining gas: 1039966.282 units remaining) + [ { { False ; False ; False ; True ; True } ; + { False ; False ; True ; True ; True } ; + { True ; True ; False ; False ; False } ; + { True ; True ; True ; False ; False } ; + { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } ] + - location: 61 (remaining gas: 1039966.267 units remaining) + [ {} + { { False ; False ; False ; True ; True } ; + { False ; False ; True ; True ; True } ; + { True ; True ; False ; False ; False } ; + { True ; True ; True ; False ; False } ; + { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } } ] + - location: 63 (remaining gas: 1039966.252 units remaining) + [ (Pair {} + { { False ; False ; False ; True ; True } ; + { False ; False ; True ; True ; True } ; + { True ; True ; False ; False ; False } ; + { True ; True ; True ; False ; False } ; + { True ; True ; False ; True ; True } ; + { False ; False ; True ; False ; False } }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{ \"World!\" }-{ \"Hello World!\" }].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{ \"World!\" }-{ \"Hello World!\" }].out" new file mode 100644 index 000000000000..d6fec64a5e48 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{ \"World!\" }-{ \"Hello World!\" }].out" @@ -0,0 +1,28 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{ "World!" }-{ "Hello World!" }] + +storage + { "Hello World!" } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039993.205 units remaining) + [ (Pair { "World!" } {}) ] + - location: 9 (remaining gas: 1039993.195 units remaining) + [ { "World!" } @parameter ] + - location: 10 (remaining gas: 1039993.195 units remaining) + [ "World!" @parameter.elt ] + - location: 12 (remaining gas: 1039993.185 units remaining) + [ "Hello " @hello + "World!" @parameter.elt ] + - location: 15 (remaining gas: 1039993.120 units remaining) + [ "Hello World!" ] + - location: 10 (remaining gas: 1039993.105 units remaining) + [ { "Hello World!" } ] + - location: 16 (remaining gas: 1039993.090 units remaining) + [ {} + { "Hello World!" } ] + - location: 18 (remaining gas: 1039993.075 units remaining) + [ (Pair {} { "Hello World!" }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{ \"test1\" ; \"test2\" }-{ \"Hello test1.c27e8c3ee6.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{ \"test1\" ; \"test2\" }-{ \"Hello test1.c27e8c3ee6.out" new file mode 100644 index 000000000000..300545719360 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{ \"test1\" ; \"test2\" }-{ \"Hello test1.c27e8c3ee6.out" @@ -0,0 +1,35 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{ "test1" ; "test2" }-{ "Hello test1" ; "Hello test2" }] + +storage + { "Hello test1" ; "Hello test2" } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039993.051 units remaining) + [ (Pair { "test1" ; "test2" } {}) ] + - location: 9 (remaining gas: 1039993.041 units remaining) + [ { "test1" ; "test2" } @parameter ] + - location: 10 (remaining gas: 1039993.041 units remaining) + [ "test1" @parameter.elt ] + - location: 12 (remaining gas: 1039993.031 units remaining) + [ "Hello " @hello + "test1" @parameter.elt ] + - location: 15 (remaining gas: 1039992.966 units remaining) + [ "Hello test1" ] + - location: 10 (remaining gas: 1039992.951 units remaining) + [ "test2" @parameter.elt ] + - location: 12 (remaining gas: 1039992.941 units remaining) + [ "Hello " @hello + "test2" @parameter.elt ] + - location: 15 (remaining gas: 1039992.876 units remaining) + [ "Hello test2" ] + - location: 10 (remaining gas: 1039992.861 units remaining) + [ { "Hello test1" ; "Hello test2" } ] + - location: 16 (remaining gas: 1039992.846 units remaining) + [ {} + { "Hello test1" ; "Hello test2" } ] + - location: 18 (remaining gas: 1039992.831 units remaining) + [ (Pair {} { "Hello test1" ; "Hello test2" }) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{}-{}].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{}-{}].out new file mode 100644 index 000000000000..eb4c5491d480 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{}-{}].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[concat_hello.tz-{}-{}-{}] + +storage + {} +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039993.379 units remaining) + [ (Pair {} {}) ] + - location: 9 (remaining gas: 1039993.369 units remaining) + [ {} @parameter ] + - location: 10 (remaining gas: 1039993.369 units remaining) + [ {} ] + - location: 16 (remaining gas: 1039993.354 units remaining) + [ {} + {} ] + - location: 18 (remaining gas: 1039993.339 units remaining) + [ (Pair {} {}) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{ 0xab ; 0xcd }-{ 0xffab ; 0xffcd }].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{ 0xab ; 0xcd }-{ 0xffab ; 0xffcd }].out new file mode 100644 index 000000000000..2beb9a9cc374 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{ 0xab ; 0xcd }-{ 0xffab ; 0xffcd }].out @@ -0,0 +1,35 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{ 0xab ; 0xcd }-{ 0xffab ; 0xffcd }] + +storage + { 0xffab ; 0xffcd } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039993.298 units remaining) + [ (Pair { 0xab ; 0xcd } {}) ] + - location: 9 (remaining gas: 1039993.288 units remaining) + [ { 0xab ; 0xcd } @parameter ] + - location: 10 (remaining gas: 1039993.288 units remaining) + [ 0xab @parameter.elt ] + - location: 12 (remaining gas: 1039993.278 units remaining) + [ 0xff + 0xab @parameter.elt ] + - location: 15 (remaining gas: 1039993.213 units remaining) + [ 0xffab ] + - location: 10 (remaining gas: 1039993.198 units remaining) + [ 0xcd @parameter.elt ] + - location: 12 (remaining gas: 1039993.188 units remaining) + [ 0xff + 0xcd @parameter.elt ] + - location: 15 (remaining gas: 1039993.123 units remaining) + [ 0xffcd ] + - location: 10 (remaining gas: 1039993.108 units remaining) + [ { 0xffab ; 0xffcd } ] + - location: 16 (remaining gas: 1039993.093 units remaining) + [ {} + { 0xffab ; 0xffcd } ] + - location: 18 (remaining gas: 1039993.078 units remaining) + [ (Pair {} { 0xffab ; 0xffcd }) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{ 0xcd }-{ 0xffcd }].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{ 0xcd }-{ 0xffcd }].out new file mode 100644 index 000000000000..751d5c8dbcef --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{ 0xcd }-{ 0xffcd }].out @@ -0,0 +1,28 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{ 0xcd }-{ 0xffcd }] + +storage + { 0xffcd } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039993.398 units remaining) + [ (Pair { 0xcd } {}) ] + - location: 9 (remaining gas: 1039993.388 units remaining) + [ { 0xcd } @parameter ] + - location: 10 (remaining gas: 1039993.388 units remaining) + [ 0xcd @parameter.elt ] + - location: 12 (remaining gas: 1039993.378 units remaining) + [ 0xff + 0xcd @parameter.elt ] + - location: 15 (remaining gas: 1039993.313 units remaining) + [ 0xffcd ] + - location: 10 (remaining gas: 1039993.298 units remaining) + [ { 0xffcd } ] + - location: 16 (remaining gas: 1039993.283 units remaining) + [ {} + { 0xffcd } ] + - location: 18 (remaining gas: 1039993.268 units remaining) + [ (Pair {} { 0xffcd }) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{}-{}].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{}-{}].out new file mode 100644 index 000000000000..13bf7c286bfb --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{}-{}].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[concat_hello_bytes.tz-{}-{}-{}] + +storage + {} +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039993.498 units remaining) + [ (Pair {} {}) ] + - location: 9 (remaining gas: 1039993.488 units remaining) + [ {} @parameter ] + - location: 10 (remaining gas: 1039993.488 units remaining) + [ {} ] + - location: 16 (remaining gas: 1039993.473 units remaining) + [ {} + {} ] + - location: 18 (remaining gas: 1039993.458 units remaining) + [ (Pair {} {}) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_list.tz-\"\"-{ \"Hello\" ; \" \" ; \"World\" ; \"!\" }-\"He.0c7b4cd53c.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_list.tz-\"\"-{ \"Hello\" ; \" \" ; \"World\" ; \"!\" }-\"He.0c7b4cd53c.out" new file mode 100644 index 000000000000..bcdc55bbc21d --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_list.tz-\"\"-{ \"Hello\" ; \" \" ; \"World\" ; \"!\" }-\"He.0c7b4cd53c.out" @@ -0,0 +1,119 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[concat_list.tz-""-{ "Hello" ; " " ; "World" ; "!" }-"Hello World!"] + +storage + "Hello World!" +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039988.297 units remaining) + [ (Pair { "Hello" ; " " ; "World" ; "!" } "") ] + - location: 8 (remaining gas: 1039988.287 units remaining) + [ { "Hello" ; " " ; "World" ; "!" } @parameter ] + - location: 9 (remaining gas: 1039988.277 units remaining) + [ "" + { "Hello" ; " " ; "World" ; "!" } @parameter ] + - location: 12 (remaining gas: 1039988.267 units remaining) + [ { "Hello" ; " " ; "World" ; "!" } @parameter + "" ] + - location: 13 (remaining gas: 1039988.267 units remaining) + [ "Hello" @parameter.elt + "" ] + - location: 15 (remaining gas: 1039988.257 units remaining) + [ "" + "Hello" @parameter.elt ] + - location: 16 (remaining gas: 1039988.242 units remaining) + [ "Hello" @parameter.elt ] + - location: 18 (remaining gas: 1039988.227 units remaining) + [ {} + "Hello" @parameter.elt ] + - location: 20 (remaining gas: 1039988.217 units remaining) + [ "Hello" @parameter.elt + {} ] + - location: 21 (remaining gas: 1039988.202 units remaining) + [ { "Hello" } ] + - location: 16 (remaining gas: 1039988.172 units remaining) + [ "" + { "Hello" } ] + - location: 22 (remaining gas: 1039988.157 units remaining) + [ { "" ; "Hello" } ] + - location: 23 (remaining gas: 1039988.037 units remaining) + [ "Hello" ] + - location: 13 (remaining gas: 1039988.022 units remaining) + [ " " @parameter.elt + "Hello" ] + - location: 15 (remaining gas: 1039988.012 units remaining) + [ "Hello" + " " @parameter.elt ] + - location: 16 (remaining gas: 1039987.997 units remaining) + [ " " @parameter.elt ] + - location: 18 (remaining gas: 1039987.982 units remaining) + [ {} + " " @parameter.elt ] + - location: 20 (remaining gas: 1039987.972 units remaining) + [ " " @parameter.elt + {} ] + - location: 21 (remaining gas: 1039987.957 units remaining) + [ { " " } ] + - location: 16 (remaining gas: 1039987.927 units remaining) + [ "Hello" + { " " } ] + - location: 22 (remaining gas: 1039987.912 units remaining) + [ { "Hello" ; " " } ] + - location: 23 (remaining gas: 1039987.792 units remaining) + [ "Hello " ] + - location: 13 (remaining gas: 1039987.777 units remaining) + [ "World" @parameter.elt + "Hello " ] + - location: 15 (remaining gas: 1039987.767 units remaining) + [ "Hello " + "World" @parameter.elt ] + - location: 16 (remaining gas: 1039987.752 units remaining) + [ "World" @parameter.elt ] + - location: 18 (remaining gas: 1039987.737 units remaining) + [ {} + "World" @parameter.elt ] + - location: 20 (remaining gas: 1039987.727 units remaining) + [ "World" @parameter.elt + {} ] + - location: 21 (remaining gas: 1039987.712 units remaining) + [ { "World" } ] + - location: 16 (remaining gas: 1039987.682 units remaining) + [ "Hello " + { "World" } ] + - location: 22 (remaining gas: 1039987.667 units remaining) + [ { "Hello " ; "World" } ] + - location: 23 (remaining gas: 1039987.546 units remaining) + [ "Hello World" ] + - location: 13 (remaining gas: 1039987.531 units remaining) + [ "!" @parameter.elt + "Hello World" ] + - location: 15 (remaining gas: 1039987.521 units remaining) + [ "Hello World" + "!" @parameter.elt ] + - location: 16 (remaining gas: 1039987.506 units remaining) + [ "!" @parameter.elt ] + - location: 18 (remaining gas: 1039987.491 units remaining) + [ {} + "!" @parameter.elt ] + - location: 20 (remaining gas: 1039987.481 units remaining) + [ "!" @parameter.elt + {} ] + - location: 21 (remaining gas: 1039987.466 units remaining) + [ { "!" } ] + - location: 16 (remaining gas: 1039987.436 units remaining) + [ "Hello World" + { "!" } ] + - location: 22 (remaining gas: 1039987.421 units remaining) + [ { "Hello World" ; "!" } ] + - location: 23 (remaining gas: 1039987.300 units remaining) + [ "Hello World!" ] + - location: 13 (remaining gas: 1039987.285 units remaining) + [ "Hello World!" ] + - location: 24 (remaining gas: 1039987.270 units remaining) + [ {} + "Hello World!" ] + - location: 26 (remaining gas: 1039987.255 units remaining) + [ (Pair {} "Hello World!") ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_list.tz-\"\"-{ \"a\" ; \"b\" ; \"c\" }-\"abc\"].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_list.tz-\"\"-{ \"a\" ; \"b\" ; \"c\" }-\"abc\"].out" new file mode 100644 index 000000000000..748f20764278 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_list.tz-\"\"-{ \"a\" ; \"b\" ; \"c\" }-\"abc\"].out" @@ -0,0 +1,96 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[concat_list.tz-""-{ "a" ; "b" ; "c" }-"abc"] + +storage + "abc" +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039988.501 units remaining) + [ (Pair { "a" ; "b" ; "c" } "") ] + - location: 8 (remaining gas: 1039988.491 units remaining) + [ { "a" ; "b" ; "c" } @parameter ] + - location: 9 (remaining gas: 1039988.481 units remaining) + [ "" + { "a" ; "b" ; "c" } @parameter ] + - location: 12 (remaining gas: 1039988.471 units remaining) + [ { "a" ; "b" ; "c" } @parameter + "" ] + - location: 13 (remaining gas: 1039988.471 units remaining) + [ "a" @parameter.elt + "" ] + - location: 15 (remaining gas: 1039988.461 units remaining) + [ "" + "a" @parameter.elt ] + - location: 16 (remaining gas: 1039988.446 units remaining) + [ "a" @parameter.elt ] + - location: 18 (remaining gas: 1039988.431 units remaining) + [ {} + "a" @parameter.elt ] + - location: 20 (remaining gas: 1039988.421 units remaining) + [ "a" @parameter.elt + {} ] + - location: 21 (remaining gas: 1039988.406 units remaining) + [ { "a" } ] + - location: 16 (remaining gas: 1039988.376 units remaining) + [ "" + { "a" } ] + - location: 22 (remaining gas: 1039988.361 units remaining) + [ { "" ; "a" } ] + - location: 23 (remaining gas: 1039988.241 units remaining) + [ "a" ] + - location: 13 (remaining gas: 1039988.226 units remaining) + [ "b" @parameter.elt + "a" ] + - location: 15 (remaining gas: 1039988.216 units remaining) + [ "a" + "b" @parameter.elt ] + - location: 16 (remaining gas: 1039988.201 units remaining) + [ "b" @parameter.elt ] + - location: 18 (remaining gas: 1039988.186 units remaining) + [ {} + "b" @parameter.elt ] + - location: 20 (remaining gas: 1039988.176 units remaining) + [ "b" @parameter.elt + {} ] + - location: 21 (remaining gas: 1039988.161 units remaining) + [ { "b" } ] + - location: 16 (remaining gas: 1039988.131 units remaining) + [ "a" + { "b" } ] + - location: 22 (remaining gas: 1039988.116 units remaining) + [ { "a" ; "b" } ] + - location: 23 (remaining gas: 1039987.996 units remaining) + [ "ab" ] + - location: 13 (remaining gas: 1039987.981 units remaining) + [ "c" @parameter.elt + "ab" ] + - location: 15 (remaining gas: 1039987.971 units remaining) + [ "ab" + "c" @parameter.elt ] + - location: 16 (remaining gas: 1039987.956 units remaining) + [ "c" @parameter.elt ] + - location: 18 (remaining gas: 1039987.941 units remaining) + [ {} + "c" @parameter.elt ] + - location: 20 (remaining gas: 1039987.931 units remaining) + [ "c" @parameter.elt + {} ] + - location: 21 (remaining gas: 1039987.916 units remaining) + [ { "c" } ] + - location: 16 (remaining gas: 1039987.886 units remaining) + [ "ab" + { "c" } ] + - location: 22 (remaining gas: 1039987.871 units remaining) + [ { "ab" ; "c" } ] + - location: 23 (remaining gas: 1039987.751 units remaining) + [ "abc" ] + - location: 13 (remaining gas: 1039987.736 units remaining) + [ "abc" ] + - location: 24 (remaining gas: 1039987.721 units remaining) + [ {} + "abc" ] + - location: 26 (remaining gas: 1039987.706 units remaining) + [ (Pair {} "abc") ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_list.tz-\"\"-{}-\"\"].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_list.tz-\"\"-{}-\"\"].out" new file mode 100644 index 000000000000..c640a0181455 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[concat_list.tz-\"\"-{}-\"\"].out" @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[concat_list.tz-""-{}-""] + +storage + "" +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039988.873 units remaining) + [ (Pair {} "") ] + - location: 8 (remaining gas: 1039988.863 units remaining) + [ {} @parameter ] + - location: 9 (remaining gas: 1039988.853 units remaining) + [ "" + {} @parameter ] + - location: 12 (remaining gas: 1039988.843 units remaining) + [ {} @parameter + "" ] + - location: 13 (remaining gas: 1039988.843 units remaining) + [ "" ] + - location: 24 (remaining gas: 1039988.828 units remaining) + [ {} + "" ] + - location: 26 (remaining gas: 1039988.813 units remaining) + [ (Pair {} "") ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cons.tz-{ -5 ; 10 }-99-{ 99 ; -5 ; 10 }].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cons.tz-{ -5 ; 10 }-99-{ 99 ; -5 ; 10 }].out new file mode 100644 index 000000000000..82ed927be691 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cons.tz-{ -5 ; 10 }-99-{ 99 ; -5 ; 10 }].out @@ -0,0 +1,22 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[cons.tz-{ -5 ; 10 }-99-{ 99 ; -5 ; 10 }] + +storage + { 99 ; -5 ; 10 } +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039995.125 units remaining) + [ (Pair 99 { -5 ; 10 }) ] + - location: 8 (remaining gas: 1039995.115 units remaining) + [ 99 @parameter + { -5 ; 10 } @storage ] + - location: 9 (remaining gas: 1039995.100 units remaining) + [ { 99 ; -5 ; 10 } ] + - location: 10 (remaining gas: 1039995.085 units remaining) + [ {} + { 99 ; -5 ; 10 } ] + - location: 12 (remaining gas: 1039995.070 units remaining) + [ (Pair {} { 99 ; -5 ; 10 }) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cons.tz-{ 10 }--5-{ -5 ; 10 }].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cons.tz-{ 10 }--5-{ -5 ; 10 }].out new file mode 100644 index 000000000000..e21e467b715d --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cons.tz-{ 10 }--5-{ -5 ; 10 }].out @@ -0,0 +1,22 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[cons.tz-{ 10 }--5-{ -5 ; 10 }] + +storage + { -5 ; 10 } +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039995.225 units remaining) + [ (Pair -5 { 10 }) ] + - location: 8 (remaining gas: 1039995.215 units remaining) + [ -5 @parameter + { 10 } @storage ] + - location: 9 (remaining gas: 1039995.200 units remaining) + [ { -5 ; 10 } ] + - location: 10 (remaining gas: 1039995.185 units remaining) + [ {} + { -5 ; 10 } ] + - location: 12 (remaining gas: 1039995.170 units remaining) + [ (Pair {} { -5 ; 10 }) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cons.tz-{}-10-{ 10 }].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cons.tz-{}-10-{ 10 }].out new file mode 100644 index 000000000000..2773d3649fd2 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[cons.tz-{}-10-{ 10 }].out @@ -0,0 +1,22 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[cons.tz-{}-10-{ 10 }] + +storage + { 10 } +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039995.325 units remaining) + [ (Pair 10 {}) ] + - location: 8 (remaining gas: 1039995.315 units remaining) + [ 10 @parameter + {} @storage ] + - location: 9 (remaining gas: 1039995.300 units remaining) + [ { 10 } ] + - location: 10 (remaining gas: 1039995.285 units remaining) + [ {} + { 10 } ] + - location: 12 (remaining gas: 1039995.270 units remaining) + [ (Pair {} { 10 }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"A\" } { \"B\" })-(Some False)].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"A\" } { \"B\" })-(Some False)].out" new file mode 100644 index 000000000000..d1f37fae7d5f --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"A\" } { \"B\" })-(Some False)].out" @@ -0,0 +1,166 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { "A" } { "B" })-(Some False)] + +storage + (Some False) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039965.879 units remaining) + [ (Pair (Pair { "A" } { "B" }) None) ] + - location: 12 (remaining gas: 1039965.869 units remaining) + [ (Pair { "A" } { "B" }) @parameter ] + - location: 13 (remaining gas: 1039965.859 units remaining) + [ (Pair { "A" } { "B" }) @parameter + (Pair { "A" } { "B" }) @parameter ] + - location: 14 (remaining gas: 1039965.849 units remaining) + [ { "A" } + (Pair { "A" } { "B" }) @parameter ] + - location: 15 (remaining gas: 1039965.834 units remaining) + [ (Pair { "A" } { "B" }) @parameter ] + - location: 17 (remaining gas: 1039965.824 units remaining) + [ { "B" } ] + - location: 15 (remaining gas: 1039965.794 units remaining) + [ { "A" } + { "B" } ] + - location: 18 (remaining gas: 1039965.639 units remaining) + [ {} + { "A" } + { "B" } ] + - location: 20 (remaining gas: 1039965.629 units remaining) + [ { "A" } + {} + { "B" } ] + - location: 21 (remaining gas: 1039965.629 units remaining) + [ "A" @elt + {} + { "B" } ] + - location: 23 (remaining gas: 1039965.614 units remaining) + [ (Pair "A" {}) + { "B" } ] + - location: 24 (remaining gas: 1039965.604 units remaining) + [ (Pair "A" {}) + (Pair "A" {}) + { "B" } ] + - location: 25 (remaining gas: 1039965.594 units remaining) + [ "A" @elt + (Pair "A" {}) + { "B" } ] + - location: 26 (remaining gas: 1039965.579 units remaining) + [ (Pair "A" {}) + { "B" } ] + - location: 28 (remaining gas: 1039965.569 units remaining) + [ {} + { "B" } ] + - location: 26 (remaining gas: 1039965.539 units remaining) + [ "A" @elt + {} + { "B" } ] + - location: 29 (remaining gas: 1039965.529 units remaining) + [ True + "A" @elt + {} + { "B" } ] + - location: 32 (remaining gas: 1039965.519 units remaining) + [ "A" @elt + True + {} + { "B" } ] + - location: 33 (remaining gas: 1039965.369 units remaining) + [ { "A" } + { "B" } ] + - location: 21 (remaining gas: 1039965.354 units remaining) + [ { "A" } + { "B" } ] + - location: 34 (remaining gas: 1039965.344 units remaining) + [ True + { "A" } + { "B" } ] + - location: 37 (remaining gas: 1039965.334 units remaining) + [ { "A" } + True + { "B" } ] + - location: 38 (remaining gas: 1039965.319 units remaining) + [ (Pair { "A" } True) + { "B" } ] + - location: 39 (remaining gas: 1039965.309 units remaining) + [ { "B" } + (Pair { "A" } True) ] + - location: 40 (remaining gas: 1039965.309 units remaining) + [ "B" @elt + (Pair { "A" } True) ] + - location: 42 (remaining gas: 1039965.294 units remaining) + [ (Pair "B" { "A" } True) ] + - location: 43 (remaining gas: 1039965.284 units remaining) + [ (Pair "B" { "A" } True) + (Pair "B" { "A" } True) ] + - location: 44 (remaining gas: 1039965.274 units remaining) + [ (Pair "B" { "A" } True) + (Pair "B" { "A" } True) + (Pair "B" { "A" } True) ] + - location: 45 (remaining gas: 1039965.264 units remaining) + [ "B" @elt + (Pair "B" { "A" } True) + (Pair "B" { "A" } True) ] + - location: 46 (remaining gas: 1039965.249 units remaining) + [ (Pair "B" { "A" } True) + (Pair "B" { "A" } True) ] + - location: 49 (remaining gas: 1039965.239 units remaining) + [ (Pair { "A" } True) + (Pair "B" { "A" } True) ] + - location: 50 (remaining gas: 1039965.229 units remaining) + [ { "A" } + (Pair "B" { "A" } True) ] + - location: 51 (remaining gas: 1039965.214 units remaining) + [ (Pair "B" { "A" } True) ] + - location: 54 (remaining gas: 1039965.204 units remaining) + [ (Pair { "A" } True) ] + - location: 55 (remaining gas: 1039965.194 units remaining) + [ True ] + - location: 51 (remaining gas: 1039965.164 units remaining) + [ { "A" } + True ] + - location: 56 (remaining gas: 1039965.154 units remaining) + [ { "A" } + { "A" } + True ] + - location: 46 (remaining gas: 1039965.124 units remaining) + [ "B" @elt + { "A" } + { "A" } + True ] + - location: 57 (remaining gas: 1039964.974 units remaining) + [ False + { "A" } + True ] + - location: 58 (remaining gas: 1039964.959 units remaining) + [ { "A" } + True ] + - location: 60 (remaining gas: 1039964.949 units remaining) + [ True + { "A" } ] + - location: 58 (remaining gas: 1039964.919 units remaining) + [ False + True + { "A" } ] + - location: 61 (remaining gas: 1039964.899 units remaining) + [ False + { "A" } ] + - location: 62 (remaining gas: 1039964.889 units remaining) + [ { "A" } + False ] + - location: 63 (remaining gas: 1039964.874 units remaining) + [ (Pair { "A" } False) ] + - location: 40 (remaining gas: 1039964.859 units remaining) + [ (Pair { "A" } False) ] + - location: 64 (remaining gas: 1039964.849 units remaining) + [ False ] + - location: 65 (remaining gas: 1039964.834 units remaining) + [ (Some False) ] + - location: 66 (remaining gas: 1039964.819 units remaining) + [ {} + (Some False) ] + - location: 68 (remaining gas: 1039964.804 units remaining) + [ (Pair {} (Some False)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"B\" ; \"B\" ; \"asdf\" ; \"C\" }.4360bbe5d0.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"B\" ; \"B\" ; \"asdf\" ; \"C\" }.4360bbe5d0.out" new file mode 100644 index 000000000000..c3b26b991b24 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"B\" ; \"B\" ; \"asdf\" ; \"C\" }.4360bbe5d0.out" @@ -0,0 +1,410 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { "B" ; "B" ; "asdf" ; "C" } { "B" ; "C" ; "asdf" })-(Some True)] + +storage + (Some True) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039965.199 units remaining) + [ (Pair (Pair { "B" ; "B" ; "asdf" ; "C" } { "B" ; "C" ; "asdf" }) None) ] + - location: 12 (remaining gas: 1039965.189 units remaining) + [ (Pair { "B" ; "B" ; "asdf" ; "C" } { "B" ; "C" ; "asdf" }) @parameter ] + - location: 13 (remaining gas: 1039965.179 units remaining) + [ (Pair { "B" ; "B" ; "asdf" ; "C" } { "B" ; "C" ; "asdf" }) @parameter + (Pair { "B" ; "B" ; "asdf" ; "C" } { "B" ; "C" ; "asdf" }) @parameter ] + - location: 14 (remaining gas: 1039965.169 units remaining) + [ { "B" ; "B" ; "asdf" ; "C" } + (Pair { "B" ; "B" ; "asdf" ; "C" } { "B" ; "C" ; "asdf" }) @parameter ] + - location: 15 (remaining gas: 1039965.154 units remaining) + [ (Pair { "B" ; "B" ; "asdf" ; "C" } { "B" ; "C" ; "asdf" }) @parameter ] + - location: 17 (remaining gas: 1039965.144 units remaining) + [ { "B" ; "C" ; "asdf" } ] + - location: 15 (remaining gas: 1039965.114 units remaining) + [ { "B" ; "B" ; "asdf" ; "C" } + { "B" ; "C" ; "asdf" } ] + - location: 18 (remaining gas: 1039964.959 units remaining) + [ {} + { "B" ; "B" ; "asdf" ; "C" } + { "B" ; "C" ; "asdf" } ] + - location: 20 (remaining gas: 1039964.949 units remaining) + [ { "B" ; "B" ; "asdf" ; "C" } + {} + { "B" ; "C" ; "asdf" } ] + - location: 21 (remaining gas: 1039964.949 units remaining) + [ "B" @elt + {} + { "B" ; "C" ; "asdf" } ] + - location: 23 (remaining gas: 1039964.934 units remaining) + [ (Pair "B" {}) + { "B" ; "C" ; "asdf" } ] + - location: 24 (remaining gas: 1039964.924 units remaining) + [ (Pair "B" {}) + (Pair "B" {}) + { "B" ; "C" ; "asdf" } ] + - location: 25 (remaining gas: 1039964.914 units remaining) + [ "B" @elt + (Pair "B" {}) + { "B" ; "C" ; "asdf" } ] + - location: 26 (remaining gas: 1039964.899 units remaining) + [ (Pair "B" {}) + { "B" ; "C" ; "asdf" } ] + - location: 28 (remaining gas: 1039964.889 units remaining) + [ {} + { "B" ; "C" ; "asdf" } ] + - location: 26 (remaining gas: 1039964.859 units remaining) + [ "B" @elt + {} + { "B" ; "C" ; "asdf" } ] + - location: 29 (remaining gas: 1039964.849 units remaining) + [ True + "B" @elt + {} + { "B" ; "C" ; "asdf" } ] + - location: 32 (remaining gas: 1039964.839 units remaining) + [ "B" @elt + True + {} + { "B" ; "C" ; "asdf" } ] + - location: 33 (remaining gas: 1039964.689 units remaining) + [ { "B" } + { "B" ; "C" ; "asdf" } ] + - location: 21 (remaining gas: 1039964.674 units remaining) + [ "B" @elt + { "B" } + { "B" ; "C" ; "asdf" } ] + - location: 23 (remaining gas: 1039964.659 units remaining) + [ (Pair "B" { "B" }) + { "B" ; "C" ; "asdf" } ] + - location: 24 (remaining gas: 1039964.649 units remaining) + [ (Pair "B" { "B" }) + (Pair "B" { "B" }) + { "B" ; "C" ; "asdf" } ] + - location: 25 (remaining gas: 1039964.639 units remaining) + [ "B" @elt + (Pair "B" { "B" }) + { "B" ; "C" ; "asdf" } ] + - location: 26 (remaining gas: 1039964.624 units remaining) + [ (Pair "B" { "B" }) + { "B" ; "C" ; "asdf" } ] + - location: 28 (remaining gas: 1039964.614 units remaining) + [ { "B" } + { "B" ; "C" ; "asdf" } ] + - location: 26 (remaining gas: 1039964.584 units remaining) + [ "B" @elt + { "B" } + { "B" ; "C" ; "asdf" } ] + - location: 29 (remaining gas: 1039964.574 units remaining) + [ True + "B" @elt + { "B" } + { "B" ; "C" ; "asdf" } ] + - location: 32 (remaining gas: 1039964.564 units remaining) + [ "B" @elt + True + { "B" } + { "B" ; "C" ; "asdf" } ] + - location: 33 (remaining gas: 1039964.344 units remaining) + [ { "B" } + { "B" ; "C" ; "asdf" } ] + - location: 21 (remaining gas: 1039964.329 units remaining) + [ "asdf" @elt + { "B" } + { "B" ; "C" ; "asdf" } ] + - location: 23 (remaining gas: 1039964.314 units remaining) + [ (Pair "asdf" { "B" }) + { "B" ; "C" ; "asdf" } ] + - location: 24 (remaining gas: 1039964.304 units remaining) + [ (Pair "asdf" { "B" }) + (Pair "asdf" { "B" }) + { "B" ; "C" ; "asdf" } ] + - location: 25 (remaining gas: 1039964.294 units remaining) + [ "asdf" @elt + (Pair "asdf" { "B" }) + { "B" ; "C" ; "asdf" } ] + - location: 26 (remaining gas: 1039964.279 units remaining) + [ (Pair "asdf" { "B" }) + { "B" ; "C" ; "asdf" } ] + - location: 28 (remaining gas: 1039964.269 units remaining) + [ { "B" } + { "B" ; "C" ; "asdf" } ] + - location: 26 (remaining gas: 1039964.239 units remaining) + [ "asdf" @elt + { "B" } + { "B" ; "C" ; "asdf" } ] + - location: 29 (remaining gas: 1039964.229 units remaining) + [ True + "asdf" @elt + { "B" } + { "B" ; "C" ; "asdf" } ] + - location: 32 (remaining gas: 1039964.219 units remaining) + [ "asdf" @elt + True + { "B" } + { "B" ; "C" ; "asdf" } ] + - location: 33 (remaining gas: 1039963.999 units remaining) + [ { "B" ; "asdf" } + { "B" ; "C" ; "asdf" } ] + - location: 21 (remaining gas: 1039963.984 units remaining) + [ "C" @elt + { "B" ; "asdf" } + { "B" ; "C" ; "asdf" } ] + - location: 23 (remaining gas: 1039963.969 units remaining) + [ (Pair "C" { "B" ; "asdf" }) + { "B" ; "C" ; "asdf" } ] + - location: 24 (remaining gas: 1039963.959 units remaining) + [ (Pair "C" { "B" ; "asdf" }) + (Pair "C" { "B" ; "asdf" }) + { "B" ; "C" ; "asdf" } ] + - location: 25 (remaining gas: 1039963.949 units remaining) + [ "C" @elt + (Pair "C" { "B" ; "asdf" }) + { "B" ; "C" ; "asdf" } ] + - location: 26 (remaining gas: 1039963.934 units remaining) + [ (Pair "C" { "B" ; "asdf" }) + { "B" ; "C" ; "asdf" } ] + - location: 28 (remaining gas: 1039963.924 units remaining) + [ { "B" ; "asdf" } + { "B" ; "C" ; "asdf" } ] + - location: 26 (remaining gas: 1039963.894 units remaining) + [ "C" @elt + { "B" ; "asdf" } + { "B" ; "C" ; "asdf" } ] + - location: 29 (remaining gas: 1039963.884 units remaining) + [ True + "C" @elt + { "B" ; "asdf" } + { "B" ; "C" ; "asdf" } ] + - location: 32 (remaining gas: 1039963.874 units remaining) + [ "C" @elt + True + { "B" ; "asdf" } + { "B" ; "C" ; "asdf" } ] + - location: 33 (remaining gas: 1039963.584 units remaining) + [ { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } ] + - location: 21 (remaining gas: 1039963.569 units remaining) + [ { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } ] + - location: 34 (remaining gas: 1039963.559 units remaining) + [ True + { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } ] + - location: 37 (remaining gas: 1039963.549 units remaining) + [ { "B" ; "C" ; "asdf" } + True + { "B" ; "C" ; "asdf" } ] + - location: 38 (remaining gas: 1039963.534 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) + { "B" ; "C" ; "asdf" } ] + - location: 39 (remaining gas: 1039963.524 units remaining) + [ { "B" ; "C" ; "asdf" } + (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 40 (remaining gas: 1039963.524 units remaining) + [ "B" @elt + (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 42 (remaining gas: 1039963.509 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 43 (remaining gas: 1039963.499 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 44 (remaining gas: 1039963.489 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 45 (remaining gas: 1039963.479 units remaining) + [ "B" @elt + (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 46 (remaining gas: 1039963.464 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 49 (remaining gas: 1039963.454 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 50 (remaining gas: 1039963.444 units remaining) + [ { "B" ; "C" ; "asdf" } + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 51 (remaining gas: 1039963.429 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 54 (remaining gas: 1039963.419 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 55 (remaining gas: 1039963.409 units remaining) + [ True ] + - location: 51 (remaining gas: 1039963.379 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 56 (remaining gas: 1039963.369 units remaining) + [ { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 46 (remaining gas: 1039963.339 units remaining) + [ "B" @elt + { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 57 (remaining gas: 1039963.154 units remaining) + [ True + { "B" ; "C" ; "asdf" } + True ] + - location: 58 (remaining gas: 1039963.139 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 60 (remaining gas: 1039963.129 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 58 (remaining gas: 1039963.099 units remaining) + [ True + True + { "B" ; "C" ; "asdf" } ] + - location: 61 (remaining gas: 1039963.079 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 62 (remaining gas: 1039963.069 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 63 (remaining gas: 1039963.054 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 40 (remaining gas: 1039963.039 units remaining) + [ "C" @elt + (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 42 (remaining gas: 1039963.024 units remaining) + [ (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 43 (remaining gas: 1039963.014 units remaining) + [ (Pair "C" { "B" ; "C" ; "asdf" } True) + (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 44 (remaining gas: 1039963.004 units remaining) + [ (Pair "C" { "B" ; "C" ; "asdf" } True) + (Pair "C" { "B" ; "C" ; "asdf" } True) + (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 45 (remaining gas: 1039962.994 units remaining) + [ "C" @elt + (Pair "C" { "B" ; "C" ; "asdf" } True) + (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 46 (remaining gas: 1039962.979 units remaining) + [ (Pair "C" { "B" ; "C" ; "asdf" } True) + (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 49 (remaining gas: 1039962.969 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) + (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 50 (remaining gas: 1039962.959 units remaining) + [ { "B" ; "C" ; "asdf" } + (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 51 (remaining gas: 1039962.944 units remaining) + [ (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 54 (remaining gas: 1039962.934 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 55 (remaining gas: 1039962.924 units remaining) + [ True ] + - location: 51 (remaining gas: 1039962.894 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 56 (remaining gas: 1039962.884 units remaining) + [ { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 46 (remaining gas: 1039962.854 units remaining) + [ "C" @elt + { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 57 (remaining gas: 1039962.669 units remaining) + [ True + { "B" ; "C" ; "asdf" } + True ] + - location: 58 (remaining gas: 1039962.654 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 60 (remaining gas: 1039962.644 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 58 (remaining gas: 1039962.614 units remaining) + [ True + True + { "B" ; "C" ; "asdf" } ] + - location: 61 (remaining gas: 1039962.594 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 62 (remaining gas: 1039962.584 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 63 (remaining gas: 1039962.569 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 40 (remaining gas: 1039962.554 units remaining) + [ "asdf" @elt + (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 42 (remaining gas: 1039962.539 units remaining) + [ (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 43 (remaining gas: 1039962.529 units remaining) + [ (Pair "asdf" { "B" ; "C" ; "asdf" } True) + (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 44 (remaining gas: 1039962.519 units remaining) + [ (Pair "asdf" { "B" ; "C" ; "asdf" } True) + (Pair "asdf" { "B" ; "C" ; "asdf" } True) + (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 45 (remaining gas: 1039962.509 units remaining) + [ "asdf" @elt + (Pair "asdf" { "B" ; "C" ; "asdf" } True) + (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 46 (remaining gas: 1039962.494 units remaining) + [ (Pair "asdf" { "B" ; "C" ; "asdf" } True) + (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 49 (remaining gas: 1039962.484 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) + (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 50 (remaining gas: 1039962.474 units remaining) + [ { "B" ; "C" ; "asdf" } + (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 51 (remaining gas: 1039962.459 units remaining) + [ (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 54 (remaining gas: 1039962.449 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 55 (remaining gas: 1039962.439 units remaining) + [ True ] + - location: 51 (remaining gas: 1039962.409 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 56 (remaining gas: 1039962.399 units remaining) + [ { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 46 (remaining gas: 1039962.369 units remaining) + [ "asdf" @elt + { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 57 (remaining gas: 1039962.184 units remaining) + [ True + { "B" ; "C" ; "asdf" } + True ] + - location: 58 (remaining gas: 1039962.169 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 60 (remaining gas: 1039962.159 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 58 (remaining gas: 1039962.129 units remaining) + [ True + True + { "B" ; "C" ; "asdf" } ] + - location: 61 (remaining gas: 1039962.109 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 62 (remaining gas: 1039962.099 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 63 (remaining gas: 1039962.084 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 40 (remaining gas: 1039962.069 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 64 (remaining gas: 1039962.059 units remaining) + [ True ] + - location: 65 (remaining gas: 1039962.044 units remaining) + [ (Some True) ] + - location: 66 (remaining gas: 1039962.029 units remaining) + [ {} + (Some True) ] + - location: 68 (remaining gas: 1039962.014 units remaining) + [ (Pair {} (Some True)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"B\" ; \"C\" ; \"asdf\" } { \"B\".ff6e4785ee.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"B\" ; \"C\" ; \"asdf\" } { \"B\".ff6e4785ee.out" new file mode 100644 index 000000000000..bc5d0359a9fa --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"B\" ; \"C\" ; \"asdf\" } { \"B\".ff6e4785ee.out" @@ -0,0 +1,437 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { "B" ; "C" ; "asdf" } { "B" ; "B" ; "asdf" ; "C" })-(Some True)] + +storage + (Some True) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039965.199 units remaining) + [ (Pair (Pair { "B" ; "C" ; "asdf" } { "B" ; "B" ; "asdf" ; "C" }) None) ] + - location: 12 (remaining gas: 1039965.189 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } { "B" ; "B" ; "asdf" ; "C" }) @parameter ] + - location: 13 (remaining gas: 1039965.179 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } { "B" ; "B" ; "asdf" ; "C" }) @parameter + (Pair { "B" ; "C" ; "asdf" } { "B" ; "B" ; "asdf" ; "C" }) @parameter ] + - location: 14 (remaining gas: 1039965.169 units remaining) + [ { "B" ; "C" ; "asdf" } + (Pair { "B" ; "C" ; "asdf" } { "B" ; "B" ; "asdf" ; "C" }) @parameter ] + - location: 15 (remaining gas: 1039965.154 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } { "B" ; "B" ; "asdf" ; "C" }) @parameter ] + - location: 17 (remaining gas: 1039965.144 units remaining) + [ { "B" ; "B" ; "asdf" ; "C" } ] + - location: 15 (remaining gas: 1039965.114 units remaining) + [ { "B" ; "C" ; "asdf" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 18 (remaining gas: 1039964.959 units remaining) + [ {} + { "B" ; "C" ; "asdf" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 20 (remaining gas: 1039964.949 units remaining) + [ { "B" ; "C" ; "asdf" } + {} + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 21 (remaining gas: 1039964.949 units remaining) + [ "B" @elt + {} + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 23 (remaining gas: 1039964.934 units remaining) + [ (Pair "B" {}) + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 24 (remaining gas: 1039964.924 units remaining) + [ (Pair "B" {}) + (Pair "B" {}) + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 25 (remaining gas: 1039964.914 units remaining) + [ "B" @elt + (Pair "B" {}) + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 26 (remaining gas: 1039964.899 units remaining) + [ (Pair "B" {}) + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 28 (remaining gas: 1039964.889 units remaining) + [ {} + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 26 (remaining gas: 1039964.859 units remaining) + [ "B" @elt + {} + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 29 (remaining gas: 1039964.849 units remaining) + [ True + "B" @elt + {} + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 32 (remaining gas: 1039964.839 units remaining) + [ "B" @elt + True + {} + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 33 (remaining gas: 1039964.689 units remaining) + [ { "B" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 21 (remaining gas: 1039964.674 units remaining) + [ "C" @elt + { "B" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 23 (remaining gas: 1039964.659 units remaining) + [ (Pair "C" { "B" }) + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 24 (remaining gas: 1039964.649 units remaining) + [ (Pair "C" { "B" }) + (Pair "C" { "B" }) + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 25 (remaining gas: 1039964.639 units remaining) + [ "C" @elt + (Pair "C" { "B" }) + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 26 (remaining gas: 1039964.624 units remaining) + [ (Pair "C" { "B" }) + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 28 (remaining gas: 1039964.614 units remaining) + [ { "B" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 26 (remaining gas: 1039964.584 units remaining) + [ "C" @elt + { "B" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 29 (remaining gas: 1039964.574 units remaining) + [ True + "C" @elt + { "B" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 32 (remaining gas: 1039964.564 units remaining) + [ "C" @elt + True + { "B" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 33 (remaining gas: 1039964.344 units remaining) + [ { "B" ; "C" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 21 (remaining gas: 1039964.329 units remaining) + [ "asdf" @elt + { "B" ; "C" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 23 (remaining gas: 1039964.314 units remaining) + [ (Pair "asdf" { "B" ; "C" }) + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 24 (remaining gas: 1039964.304 units remaining) + [ (Pair "asdf" { "B" ; "C" }) + (Pair "asdf" { "B" ; "C" }) + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 25 (remaining gas: 1039964.294 units remaining) + [ "asdf" @elt + (Pair "asdf" { "B" ; "C" }) + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 26 (remaining gas: 1039964.279 units remaining) + [ (Pair "asdf" { "B" ; "C" }) + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 28 (remaining gas: 1039964.269 units remaining) + [ { "B" ; "C" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 26 (remaining gas: 1039964.239 units remaining) + [ "asdf" @elt + { "B" ; "C" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 29 (remaining gas: 1039964.229 units remaining) + [ True + "asdf" @elt + { "B" ; "C" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 32 (remaining gas: 1039964.219 units remaining) + [ "asdf" @elt + True + { "B" ; "C" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 33 (remaining gas: 1039963.929 units remaining) + [ { "B" ; "C" ; "asdf" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 21 (remaining gas: 1039963.914 units remaining) + [ { "B" ; "C" ; "asdf" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 34 (remaining gas: 1039963.904 units remaining) + [ True + { "B" ; "C" ; "asdf" } + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 37 (remaining gas: 1039963.894 units remaining) + [ { "B" ; "C" ; "asdf" } + True + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 38 (remaining gas: 1039963.879 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) + { "B" ; "B" ; "asdf" ; "C" } ] + - location: 39 (remaining gas: 1039963.869 units remaining) + [ { "B" ; "B" ; "asdf" ; "C" } + (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 40 (remaining gas: 1039963.869 units remaining) + [ "B" @elt + (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 42 (remaining gas: 1039963.854 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 43 (remaining gas: 1039963.844 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 44 (remaining gas: 1039963.834 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 45 (remaining gas: 1039963.824 units remaining) + [ "B" @elt + (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 46 (remaining gas: 1039963.809 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 49 (remaining gas: 1039963.799 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 50 (remaining gas: 1039963.789 units remaining) + [ { "B" ; "C" ; "asdf" } + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 51 (remaining gas: 1039963.774 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 54 (remaining gas: 1039963.764 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 55 (remaining gas: 1039963.754 units remaining) + [ True ] + - location: 51 (remaining gas: 1039963.724 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 56 (remaining gas: 1039963.714 units remaining) + [ { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 46 (remaining gas: 1039963.684 units remaining) + [ "B" @elt + { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 57 (remaining gas: 1039963.499 units remaining) + [ True + { "B" ; "C" ; "asdf" } + True ] + - location: 58 (remaining gas: 1039963.484 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 60 (remaining gas: 1039963.474 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 58 (remaining gas: 1039963.444 units remaining) + [ True + True + { "B" ; "C" ; "asdf" } ] + - location: 61 (remaining gas: 1039963.424 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 62 (remaining gas: 1039963.414 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 63 (remaining gas: 1039963.399 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 40 (remaining gas: 1039963.384 units remaining) + [ "B" @elt + (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 42 (remaining gas: 1039963.369 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 43 (remaining gas: 1039963.359 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 44 (remaining gas: 1039963.349 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 45 (remaining gas: 1039963.339 units remaining) + [ "B" @elt + (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 46 (remaining gas: 1039963.324 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 49 (remaining gas: 1039963.314 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 50 (remaining gas: 1039963.304 units remaining) + [ { "B" ; "C" ; "asdf" } + (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 51 (remaining gas: 1039963.289 units remaining) + [ (Pair "B" { "B" ; "C" ; "asdf" } True) ] + - location: 54 (remaining gas: 1039963.279 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 55 (remaining gas: 1039963.269 units remaining) + [ True ] + - location: 51 (remaining gas: 1039963.239 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 56 (remaining gas: 1039963.229 units remaining) + [ { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 46 (remaining gas: 1039963.199 units remaining) + [ "B" @elt + { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 57 (remaining gas: 1039963.014 units remaining) + [ True + { "B" ; "C" ; "asdf" } + True ] + - location: 58 (remaining gas: 1039962.999 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 60 (remaining gas: 1039962.989 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 58 (remaining gas: 1039962.959 units remaining) + [ True + True + { "B" ; "C" ; "asdf" } ] + - location: 61 (remaining gas: 1039962.939 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 62 (remaining gas: 1039962.929 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 63 (remaining gas: 1039962.914 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 40 (remaining gas: 1039962.899 units remaining) + [ "asdf" @elt + (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 42 (remaining gas: 1039962.884 units remaining) + [ (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 43 (remaining gas: 1039962.874 units remaining) + [ (Pair "asdf" { "B" ; "C" ; "asdf" } True) + (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 44 (remaining gas: 1039962.864 units remaining) + [ (Pair "asdf" { "B" ; "C" ; "asdf" } True) + (Pair "asdf" { "B" ; "C" ; "asdf" } True) + (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 45 (remaining gas: 1039962.854 units remaining) + [ "asdf" @elt + (Pair "asdf" { "B" ; "C" ; "asdf" } True) + (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 46 (remaining gas: 1039962.839 units remaining) + [ (Pair "asdf" { "B" ; "C" ; "asdf" } True) + (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 49 (remaining gas: 1039962.829 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) + (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 50 (remaining gas: 1039962.819 units remaining) + [ { "B" ; "C" ; "asdf" } + (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 51 (remaining gas: 1039962.804 units remaining) + [ (Pair "asdf" { "B" ; "C" ; "asdf" } True) ] + - location: 54 (remaining gas: 1039962.794 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 55 (remaining gas: 1039962.784 units remaining) + [ True ] + - location: 51 (remaining gas: 1039962.754 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 56 (remaining gas: 1039962.744 units remaining) + [ { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 46 (remaining gas: 1039962.714 units remaining) + [ "asdf" @elt + { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 57 (remaining gas: 1039962.529 units remaining) + [ True + { "B" ; "C" ; "asdf" } + True ] + - location: 58 (remaining gas: 1039962.514 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 60 (remaining gas: 1039962.504 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 58 (remaining gas: 1039962.474 units remaining) + [ True + True + { "B" ; "C" ; "asdf" } ] + - location: 61 (remaining gas: 1039962.454 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 62 (remaining gas: 1039962.444 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 63 (remaining gas: 1039962.429 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 40 (remaining gas: 1039962.414 units remaining) + [ "C" @elt + (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 42 (remaining gas: 1039962.399 units remaining) + [ (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 43 (remaining gas: 1039962.389 units remaining) + [ (Pair "C" { "B" ; "C" ; "asdf" } True) + (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 44 (remaining gas: 1039962.379 units remaining) + [ (Pair "C" { "B" ; "C" ; "asdf" } True) + (Pair "C" { "B" ; "C" ; "asdf" } True) + (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 45 (remaining gas: 1039962.369 units remaining) + [ "C" @elt + (Pair "C" { "B" ; "C" ; "asdf" } True) + (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 46 (remaining gas: 1039962.354 units remaining) + [ (Pair "C" { "B" ; "C" ; "asdf" } True) + (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 49 (remaining gas: 1039962.344 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) + (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 50 (remaining gas: 1039962.334 units remaining) + [ { "B" ; "C" ; "asdf" } + (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 51 (remaining gas: 1039962.319 units remaining) + [ (Pair "C" { "B" ; "C" ; "asdf" } True) ] + - location: 54 (remaining gas: 1039962.309 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 55 (remaining gas: 1039962.299 units remaining) + [ True ] + - location: 51 (remaining gas: 1039962.269 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 56 (remaining gas: 1039962.259 units remaining) + [ { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 46 (remaining gas: 1039962.229 units remaining) + [ "C" @elt + { "B" ; "C" ; "asdf" } + { "B" ; "C" ; "asdf" } + True ] + - location: 57 (remaining gas: 1039962.044 units remaining) + [ True + { "B" ; "C" ; "asdf" } + True ] + - location: 58 (remaining gas: 1039962.029 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 60 (remaining gas: 1039962.019 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 58 (remaining gas: 1039961.989 units remaining) + [ True + True + { "B" ; "C" ; "asdf" } ] + - location: 61 (remaining gas: 1039961.969 units remaining) + [ True + { "B" ; "C" ; "asdf" } ] + - location: 62 (remaining gas: 1039961.959 units remaining) + [ { "B" ; "C" ; "asdf" } + True ] + - location: 63 (remaining gas: 1039961.944 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 40 (remaining gas: 1039961.929 units remaining) + [ (Pair { "B" ; "C" ; "asdf" } True) ] + - location: 64 (remaining gas: 1039961.919 units remaining) + [ True ] + - location: 65 (remaining gas: 1039961.904 units remaining) + [ (Some True) ] + - location: 66 (remaining gas: 1039961.889 units remaining) + [ {} + (Some True) ] + - location: 68 (remaining gas: 1039961.874 units remaining) + [ (Pair {} (Some True)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"B\" } { \"B\" })-(Some True)].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"B\" } { \"B\" })-(Some True)].out" new file mode 100644 index 000000000000..1a7d8671d213 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"B\" } { \"B\" })-(Some True)].out" @@ -0,0 +1,166 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { "B" } { "B" })-(Some True)] + +storage + (Some True) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039965.879 units remaining) + [ (Pair (Pair { "B" } { "B" }) None) ] + - location: 12 (remaining gas: 1039965.869 units remaining) + [ (Pair { "B" } { "B" }) @parameter ] + - location: 13 (remaining gas: 1039965.859 units remaining) + [ (Pair { "B" } { "B" }) @parameter + (Pair { "B" } { "B" }) @parameter ] + - location: 14 (remaining gas: 1039965.849 units remaining) + [ { "B" } + (Pair { "B" } { "B" }) @parameter ] + - location: 15 (remaining gas: 1039965.834 units remaining) + [ (Pair { "B" } { "B" }) @parameter ] + - location: 17 (remaining gas: 1039965.824 units remaining) + [ { "B" } ] + - location: 15 (remaining gas: 1039965.794 units remaining) + [ { "B" } + { "B" } ] + - location: 18 (remaining gas: 1039965.639 units remaining) + [ {} + { "B" } + { "B" } ] + - location: 20 (remaining gas: 1039965.629 units remaining) + [ { "B" } + {} + { "B" } ] + - location: 21 (remaining gas: 1039965.629 units remaining) + [ "B" @elt + {} + { "B" } ] + - location: 23 (remaining gas: 1039965.614 units remaining) + [ (Pair "B" {}) + { "B" } ] + - location: 24 (remaining gas: 1039965.604 units remaining) + [ (Pair "B" {}) + (Pair "B" {}) + { "B" } ] + - location: 25 (remaining gas: 1039965.594 units remaining) + [ "B" @elt + (Pair "B" {}) + { "B" } ] + - location: 26 (remaining gas: 1039965.579 units remaining) + [ (Pair "B" {}) + { "B" } ] + - location: 28 (remaining gas: 1039965.569 units remaining) + [ {} + { "B" } ] + - location: 26 (remaining gas: 1039965.539 units remaining) + [ "B" @elt + {} + { "B" } ] + - location: 29 (remaining gas: 1039965.529 units remaining) + [ True + "B" @elt + {} + { "B" } ] + - location: 32 (remaining gas: 1039965.519 units remaining) + [ "B" @elt + True + {} + { "B" } ] + - location: 33 (remaining gas: 1039965.369 units remaining) + [ { "B" } + { "B" } ] + - location: 21 (remaining gas: 1039965.354 units remaining) + [ { "B" } + { "B" } ] + - location: 34 (remaining gas: 1039965.344 units remaining) + [ True + { "B" } + { "B" } ] + - location: 37 (remaining gas: 1039965.334 units remaining) + [ { "B" } + True + { "B" } ] + - location: 38 (remaining gas: 1039965.319 units remaining) + [ (Pair { "B" } True) + { "B" } ] + - location: 39 (remaining gas: 1039965.309 units remaining) + [ { "B" } + (Pair { "B" } True) ] + - location: 40 (remaining gas: 1039965.309 units remaining) + [ "B" @elt + (Pair { "B" } True) ] + - location: 42 (remaining gas: 1039965.294 units remaining) + [ (Pair "B" { "B" } True) ] + - location: 43 (remaining gas: 1039965.284 units remaining) + [ (Pair "B" { "B" } True) + (Pair "B" { "B" } True) ] + - location: 44 (remaining gas: 1039965.274 units remaining) + [ (Pair "B" { "B" } True) + (Pair "B" { "B" } True) + (Pair "B" { "B" } True) ] + - location: 45 (remaining gas: 1039965.264 units remaining) + [ "B" @elt + (Pair "B" { "B" } True) + (Pair "B" { "B" } True) ] + - location: 46 (remaining gas: 1039965.249 units remaining) + [ (Pair "B" { "B" } True) + (Pair "B" { "B" } True) ] + - location: 49 (remaining gas: 1039965.239 units remaining) + [ (Pair { "B" } True) + (Pair "B" { "B" } True) ] + - location: 50 (remaining gas: 1039965.229 units remaining) + [ { "B" } + (Pair "B" { "B" } True) ] + - location: 51 (remaining gas: 1039965.214 units remaining) + [ (Pair "B" { "B" } True) ] + - location: 54 (remaining gas: 1039965.204 units remaining) + [ (Pair { "B" } True) ] + - location: 55 (remaining gas: 1039965.194 units remaining) + [ True ] + - location: 51 (remaining gas: 1039965.164 units remaining) + [ { "B" } + True ] + - location: 56 (remaining gas: 1039965.154 units remaining) + [ { "B" } + { "B" } + True ] + - location: 46 (remaining gas: 1039965.124 units remaining) + [ "B" @elt + { "B" } + { "B" } + True ] + - location: 57 (remaining gas: 1039964.974 units remaining) + [ True + { "B" } + True ] + - location: 58 (remaining gas: 1039964.959 units remaining) + [ { "B" } + True ] + - location: 60 (remaining gas: 1039964.949 units remaining) + [ True + { "B" } ] + - location: 58 (remaining gas: 1039964.919 units remaining) + [ True + True + { "B" } ] + - location: 61 (remaining gas: 1039964.899 units remaining) + [ True + { "B" } ] + - location: 62 (remaining gas: 1039964.889 units remaining) + [ { "B" } + True ] + - location: 63 (remaining gas: 1039964.874 units remaining) + [ (Pair { "B" } True) ] + - location: 40 (remaining gas: 1039964.859 units remaining) + [ (Pair { "B" } True) ] + - location: 64 (remaining gas: 1039964.849 units remaining) + [ True ] + - location: 65 (remaining gas: 1039964.834 units remaining) + [ (Some True) ] + - location: 66 (remaining gas: 1039964.819 units remaining) + [ {} + (Some True) ] + - location: 68 (remaining gas: 1039964.804 units remaining) + [ (Pair {} (Some True)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"c\" } { \"B\" })-(Some False)].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"c\" } { \"B\" })-(Some False)].out" new file mode 100644 index 000000000000..1715197b16c9 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { \"c\" } { \"B\" })-(Some False)].out" @@ -0,0 +1,166 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair { "c" } { "B" })-(Some False)] + +storage + (Some False) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039965.879 units remaining) + [ (Pair (Pair { "c" } { "B" }) None) ] + - location: 12 (remaining gas: 1039965.869 units remaining) + [ (Pair { "c" } { "B" }) @parameter ] + - location: 13 (remaining gas: 1039965.859 units remaining) + [ (Pair { "c" } { "B" }) @parameter + (Pair { "c" } { "B" }) @parameter ] + - location: 14 (remaining gas: 1039965.849 units remaining) + [ { "c" } + (Pair { "c" } { "B" }) @parameter ] + - location: 15 (remaining gas: 1039965.834 units remaining) + [ (Pair { "c" } { "B" }) @parameter ] + - location: 17 (remaining gas: 1039965.824 units remaining) + [ { "B" } ] + - location: 15 (remaining gas: 1039965.794 units remaining) + [ { "c" } + { "B" } ] + - location: 18 (remaining gas: 1039965.639 units remaining) + [ {} + { "c" } + { "B" } ] + - location: 20 (remaining gas: 1039965.629 units remaining) + [ { "c" } + {} + { "B" } ] + - location: 21 (remaining gas: 1039965.629 units remaining) + [ "c" @elt + {} + { "B" } ] + - location: 23 (remaining gas: 1039965.614 units remaining) + [ (Pair "c" {}) + { "B" } ] + - location: 24 (remaining gas: 1039965.604 units remaining) + [ (Pair "c" {}) + (Pair "c" {}) + { "B" } ] + - location: 25 (remaining gas: 1039965.594 units remaining) + [ "c" @elt + (Pair "c" {}) + { "B" } ] + - location: 26 (remaining gas: 1039965.579 units remaining) + [ (Pair "c" {}) + { "B" } ] + - location: 28 (remaining gas: 1039965.569 units remaining) + [ {} + { "B" } ] + - location: 26 (remaining gas: 1039965.539 units remaining) + [ "c" @elt + {} + { "B" } ] + - location: 29 (remaining gas: 1039965.529 units remaining) + [ True + "c" @elt + {} + { "B" } ] + - location: 32 (remaining gas: 1039965.519 units remaining) + [ "c" @elt + True + {} + { "B" } ] + - location: 33 (remaining gas: 1039965.369 units remaining) + [ { "c" } + { "B" } ] + - location: 21 (remaining gas: 1039965.354 units remaining) + [ { "c" } + { "B" } ] + - location: 34 (remaining gas: 1039965.344 units remaining) + [ True + { "c" } + { "B" } ] + - location: 37 (remaining gas: 1039965.334 units remaining) + [ { "c" } + True + { "B" } ] + - location: 38 (remaining gas: 1039965.319 units remaining) + [ (Pair { "c" } True) + { "B" } ] + - location: 39 (remaining gas: 1039965.309 units remaining) + [ { "B" } + (Pair { "c" } True) ] + - location: 40 (remaining gas: 1039965.309 units remaining) + [ "B" @elt + (Pair { "c" } True) ] + - location: 42 (remaining gas: 1039965.294 units remaining) + [ (Pair "B" { "c" } True) ] + - location: 43 (remaining gas: 1039965.284 units remaining) + [ (Pair "B" { "c" } True) + (Pair "B" { "c" } True) ] + - location: 44 (remaining gas: 1039965.274 units remaining) + [ (Pair "B" { "c" } True) + (Pair "B" { "c" } True) + (Pair "B" { "c" } True) ] + - location: 45 (remaining gas: 1039965.264 units remaining) + [ "B" @elt + (Pair "B" { "c" } True) + (Pair "B" { "c" } True) ] + - location: 46 (remaining gas: 1039965.249 units remaining) + [ (Pair "B" { "c" } True) + (Pair "B" { "c" } True) ] + - location: 49 (remaining gas: 1039965.239 units remaining) + [ (Pair { "c" } True) + (Pair "B" { "c" } True) ] + - location: 50 (remaining gas: 1039965.229 units remaining) + [ { "c" } + (Pair "B" { "c" } True) ] + - location: 51 (remaining gas: 1039965.214 units remaining) + [ (Pair "B" { "c" } True) ] + - location: 54 (remaining gas: 1039965.204 units remaining) + [ (Pair { "c" } True) ] + - location: 55 (remaining gas: 1039965.194 units remaining) + [ True ] + - location: 51 (remaining gas: 1039965.164 units remaining) + [ { "c" } + True ] + - location: 56 (remaining gas: 1039965.154 units remaining) + [ { "c" } + { "c" } + True ] + - location: 46 (remaining gas: 1039965.124 units remaining) + [ "B" @elt + { "c" } + { "c" } + True ] + - location: 57 (remaining gas: 1039964.974 units remaining) + [ False + { "c" } + True ] + - location: 58 (remaining gas: 1039964.959 units remaining) + [ { "c" } + True ] + - location: 60 (remaining gas: 1039964.949 units remaining) + [ True + { "c" } ] + - location: 58 (remaining gas: 1039964.919 units remaining) + [ False + True + { "c" } ] + - location: 61 (remaining gas: 1039964.899 units remaining) + [ False + { "c" } ] + - location: 62 (remaining gas: 1039964.889 units remaining) + [ { "c" } + False ] + - location: 63 (remaining gas: 1039964.874 units remaining) + [ (Pair { "c" } False) ] + - location: 40 (remaining gas: 1039964.859 units remaining) + [ (Pair { "c" } False) ] + - location: 64 (remaining gas: 1039964.849 units remaining) + [ False ] + - location: 65 (remaining gas: 1039964.834 units remaining) + [ (Some False) ] + - location: 66 (remaining gas: 1039964.819 units remaining) + [ {} + (Some False) ] + - location: 68 (remaining gas: 1039964.804 units remaining) + [ (Pair {} (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair {} {})-(Some True)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair {} {})-(Some True)].out new file mode 100644 index 000000000000..a62686eccbd8 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair {} {})-(Some True)].out @@ -0,0 +1,63 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[contains_all.tz-None-(Pair {} {})-(Some True)] + +storage + (Some True) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039966.127 units remaining) + [ (Pair (Pair {} {}) None) ] + - location: 12 (remaining gas: 1039966.117 units remaining) + [ (Pair {} {}) @parameter ] + - location: 13 (remaining gas: 1039966.107 units remaining) + [ (Pair {} {}) @parameter + (Pair {} {}) @parameter ] + - location: 14 (remaining gas: 1039966.097 units remaining) + [ {} + (Pair {} {}) @parameter ] + - location: 15 (remaining gas: 1039966.082 units remaining) + [ (Pair {} {}) @parameter ] + - location: 17 (remaining gas: 1039966.072 units remaining) + [ {} ] + - location: 15 (remaining gas: 1039966.042 units remaining) + [ {} + {} ] + - location: 18 (remaining gas: 1039965.887 units remaining) + [ {} + {} + {} ] + - location: 20 (remaining gas: 1039965.877 units remaining) + [ {} + {} + {} ] + - location: 21 (remaining gas: 1039965.877 units remaining) + [ {} + {} ] + - location: 34 (remaining gas: 1039965.867 units remaining) + [ True + {} + {} ] + - location: 37 (remaining gas: 1039965.857 units remaining) + [ {} + True + {} ] + - location: 38 (remaining gas: 1039965.842 units remaining) + [ (Pair {} True) + {} ] + - location: 39 (remaining gas: 1039965.832 units remaining) + [ {} + (Pair {} True) ] + - location: 40 (remaining gas: 1039965.832 units remaining) + [ (Pair {} True) ] + - location: 64 (remaining gas: 1039965.822 units remaining) + [ True ] + - location: 65 (remaining gas: 1039965.807 units remaining) + [ (Some True) ] + - location: 66 (remaining gas: 1039965.792 units remaining) + [ {} + (Some True) ] + - location: 68 (remaining gas: 1039965.777 units remaining) + [ (Pair {} (Some True)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contract.tz-Unit-\"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5\"-Unit].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contract.tz-Unit-\"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5\"-Unit].out" new file mode 100644 index 000000000000..dda689046d00 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[contract.tz-Unit-\"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5\"-Unit].out" @@ -0,0 +1,29 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[contract.tz-Unit-"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5"-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039937.065 units remaining) + [ (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" Unit) ] + - location: 7 (remaining gas: 1039937.055 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" @parameter ] + - location: 8 (remaining gas: 1039936.985 units remaining) + [ (Some "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @parameter.contract ] + - location: 11 (remaining gas: 1039936.975 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" @parameter.contract.some ] + - location: 11 (remaining gas: 1039936.960 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" @parameter.contract.some ] + - location: 17 (remaining gas: 1039936.950 units remaining) + [ ] + - location: 18 (remaining gas: 1039936.940 units remaining) + [ Unit ] + - location: 19 (remaining gas: 1039936.925 units remaining) + [ {} + Unit ] + - location: 21 (remaining gas: 1039936.910 units remaining) + [ (Pair {} Unit) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[create_contract.tz-None-Unit-(Some \"KT1Mjjcb6tmSsLm7Cb3.c3984fbc14.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[create_contract.tz-None-Unit-(Some \"KT1Mjjcb6tmSsLm7Cb3.c3984fbc14.out" new file mode 100644 index 000000000000..765f617defe4 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[create_contract.tz-None-Unit-(Some \"KT1Mjjcb6tmSsLm7Cb3.c3984fbc14.out" @@ -0,0 +1,49 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[create_contract.tz-None-Unit-(Some "KT1Mjjcb6tmSsLm7Cb3DSQszePjfchPM4Uxm")] + +storage + (Some "KT1Mjjcb6tmSsLm7Cb3DSQszePjfchPM4Uxm") +emitted operations + Internal origination: + From: KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi + Credit: ꜩ0.05 + Script: + { parameter unit ; storage unit ; code { CDR ; NIL operation ; PAIR } } + Initial storage: Unit + No delegate for this contract + big_map diff + + trace + - location: 8 (remaining gas: 1039987.434 units remaining) + [ (Pair Unit None) ] + - location: 8 (remaining gas: 1039987.424 units remaining) + [ ] + - location: 9 (remaining gas: 1039987.414 units remaining) + [ Unit ] + - location: 10 (remaining gas: 1039987.399 units remaining) + [ 50000 @amount + Unit ] + - location: 11 (remaining gas: 1039987.384 units remaining) + [ None + 50000 @amount + Unit ] + - location: 13 (remaining gas: 1039986.778 units remaining) + [ 0x011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600000002d08603000000001c02000000170500036c0501036c050202000000080317053d036d034200000002030b + "KT1Mjjcb6tmSsLm7Cb3DSQszePjfchPM4Uxm" ] + - location: 25 (remaining gas: 1039986.763 units remaining) + [ "KT1Mjjcb6tmSsLm7Cb3DSQszePjfchPM4Uxm" ] + - location: 27 (remaining gas: 1039986.748 units remaining) + [ (Some "KT1Mjjcb6tmSsLm7Cb3DSQszePjfchPM4Uxm") ] + - location: 28 (remaining gas: 1039986.733 units remaining) + [ {} + (Some "KT1Mjjcb6tmSsLm7Cb3DSQszePjfchPM4Uxm") ] + - location: 25 (remaining gas: 1039986.703 units remaining) + [ 0x011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600000002d08603000000001c02000000170500036c0501036c050202000000080317053d036d034200000002030b + {} + (Some "KT1Mjjcb6tmSsLm7Cb3DSQszePjfchPM4Uxm") ] + - location: 30 (remaining gas: 1039986.688 units remaining) + [ { 0x011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600000002d08603000000001c02000000170500036c0501036c050202000000080317053d036d034200000002030b } + (Some "KT1Mjjcb6tmSsLm7Cb3DSQszePjfchPM4Uxm") ] + - location: 31 (remaining gas: 1039986.673 units remaining) + [ (Pair { 0x011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600000002d08603000000001c02000000170500036c0501036c050202000000080317053d036d034200000002030b } + (Some "KT1Mjjcb6tmSsLm7Cb3DSQszePjfchPM4Uxm")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair \"1970-01-01T00:03:20Z\" \"19.90e9215d17.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair \"1970-01-01T00:03:20Z\" \"19.90e9215d17.out" new file mode 100644 index 000000000000..c7e844e280a9 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair \"1970-01-01T00:03:20Z\" \"19.90e9215d17.out" @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair "1970-01-01T00:03:20Z" "1970-01-01T00:00:00Z")-200] + +storage + 200 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039992.033 units remaining) + [ (Pair (Pair "1970-01-01T00:03:20Z" "1970-01-01T00:00:00Z") 111) ] + - location: 9 (remaining gas: 1039992.023 units remaining) + [ (Pair "1970-01-01T00:03:20Z" "1970-01-01T00:00:00Z") @parameter ] + - location: 10 (remaining gas: 1039992.013 units remaining) + [ (Pair "1970-01-01T00:03:20Z" "1970-01-01T00:00:00Z") @parameter + (Pair "1970-01-01T00:03:20Z" "1970-01-01T00:00:00Z") @parameter ] + - location: 11 (remaining gas: 1039992.003 units remaining) + [ "1970-01-01T00:03:20Z" + (Pair "1970-01-01T00:03:20Z" "1970-01-01T00:00:00Z") @parameter ] + - location: 12 (remaining gas: 1039991.988 units remaining) + [ (Pair "1970-01-01T00:03:20Z" "1970-01-01T00:00:00Z") @parameter ] + - location: 14 (remaining gas: 1039991.978 units remaining) + [ "1970-01-01T00:00:00Z" ] + - location: 12 (remaining gas: 1039991.948 units remaining) + [ "1970-01-01T00:03:20Z" + "1970-01-01T00:00:00Z" ] + - location: 15 (remaining gas: 1039991.913 units remaining) + [ 200 ] + - location: 16 (remaining gas: 1039991.898 units remaining) + [ {} + 200 ] + - location: 18 (remaining gas: 1039991.883 units remaining) + [ (Pair {} 200) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 0 0)-0].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 0 0)-0].out new file mode 100644 index 000000000000..3f79f5366056 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 0 0)-0].out @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 0 0)-0] + +storage + 0 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039992.273 units remaining) + [ (Pair (Pair "1970-01-01T00:00:00Z" "1970-01-01T00:00:00Z") 111) ] + - location: 9 (remaining gas: 1039992.263 units remaining) + [ (Pair "1970-01-01T00:00:00Z" "1970-01-01T00:00:00Z") @parameter ] + - location: 10 (remaining gas: 1039992.253 units remaining) + [ (Pair "1970-01-01T00:00:00Z" "1970-01-01T00:00:00Z") @parameter + (Pair "1970-01-01T00:00:00Z" "1970-01-01T00:00:00Z") @parameter ] + - location: 11 (remaining gas: 1039992.243 units remaining) + [ "1970-01-01T00:00:00Z" + (Pair "1970-01-01T00:00:00Z" "1970-01-01T00:00:00Z") @parameter ] + - location: 12 (remaining gas: 1039992.228 units remaining) + [ (Pair "1970-01-01T00:00:00Z" "1970-01-01T00:00:00Z") @parameter ] + - location: 14 (remaining gas: 1039992.218 units remaining) + [ "1970-01-01T00:00:00Z" ] + - location: 12 (remaining gas: 1039992.188 units remaining) + [ "1970-01-01T00:00:00Z" + "1970-01-01T00:00:00Z" ] + - location: 15 (remaining gas: 1039992.153 units remaining) + [ 0 ] + - location: 16 (remaining gas: 1039992.138 units remaining) + [ {} + 0 ] + - location: 18 (remaining gas: 1039992.123 units remaining) + [ (Pair {} 0) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 0 1)--1].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 0 1)--1].out new file mode 100644 index 000000000000..31db8b41765e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 0 1)--1].out @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 0 1)--1] + +storage + -1 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039992.273 units remaining) + [ (Pair (Pair "1970-01-01T00:00:00Z" "1970-01-01T00:00:01Z") 111) ] + - location: 9 (remaining gas: 1039992.263 units remaining) + [ (Pair "1970-01-01T00:00:00Z" "1970-01-01T00:00:01Z") @parameter ] + - location: 10 (remaining gas: 1039992.253 units remaining) + [ (Pair "1970-01-01T00:00:00Z" "1970-01-01T00:00:01Z") @parameter + (Pair "1970-01-01T00:00:00Z" "1970-01-01T00:00:01Z") @parameter ] + - location: 11 (remaining gas: 1039992.243 units remaining) + [ "1970-01-01T00:00:00Z" + (Pair "1970-01-01T00:00:00Z" "1970-01-01T00:00:01Z") @parameter ] + - location: 12 (remaining gas: 1039992.228 units remaining) + [ (Pair "1970-01-01T00:00:00Z" "1970-01-01T00:00:01Z") @parameter ] + - location: 14 (remaining gas: 1039992.218 units remaining) + [ "1970-01-01T00:00:01Z" ] + - location: 12 (remaining gas: 1039992.188 units remaining) + [ "1970-01-01T00:00:00Z" + "1970-01-01T00:00:01Z" ] + - location: 15 (remaining gas: 1039992.153 units remaining) + [ -1 ] + - location: 16 (remaining gas: 1039992.138 units remaining) + [ {} + -1 ] + - location: 18 (remaining gas: 1039992.123 units remaining) + [ (Pair {} -1) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 1 0)-1].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 1 0)-1].out new file mode 100644 index 000000000000..05edecdc9012 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 1 0)-1].out @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[diff_timestamps.tz-111-(Pair 1 0)-1] + +storage + 1 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039992.273 units remaining) + [ (Pair (Pair "1970-01-01T00:00:01Z" "1970-01-01T00:00:00Z") 111) ] + - location: 9 (remaining gas: 1039992.263 units remaining) + [ (Pair "1970-01-01T00:00:01Z" "1970-01-01T00:00:00Z") @parameter ] + - location: 10 (remaining gas: 1039992.253 units remaining) + [ (Pair "1970-01-01T00:00:01Z" "1970-01-01T00:00:00Z") @parameter + (Pair "1970-01-01T00:00:01Z" "1970-01-01T00:00:00Z") @parameter ] + - location: 11 (remaining gas: 1039992.243 units remaining) + [ "1970-01-01T00:00:01Z" + (Pair "1970-01-01T00:00:01Z" "1970-01-01T00:00:00Z") @parameter ] + - location: 12 (remaining gas: 1039992.228 units remaining) + [ (Pair "1970-01-01T00:00:01Z" "1970-01-01T00:00:00Z") @parameter ] + - location: 14 (remaining gas: 1039992.218 units remaining) + [ "1970-01-01T00:00:00Z" ] + - location: 12 (remaining gas: 1039992.188 units remaining) + [ "1970-01-01T00:00:01Z" + "1970-01-01T00:00:00Z" ] + - location: 15 (remaining gas: 1039992.153 units remaining) + [ 1 ] + - location: 16 (remaining gas: 1039992.138 units remaining) + [ {} + 1 ] + - location: 18 (remaining gas: 1039992.123 units remaining) + [ (Pair {} 1) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dig_eq.tz-Unit-(Pair 17 (Pair 16 (Pair 15 (Pair 14 (Pai.2794d4782e.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dig_eq.tz-Unit-(Pair 17 (Pair 16 (Pair 15 (Pair 14 (Pai.2794d4782e.out new file mode 100644 index 000000000000..6521ef57b9c4 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dig_eq.tz-Unit-(Pair 17 (Pair 16 (Pair 15 (Pair 14 (Pai.2794d4782e.out @@ -0,0 +1,3431 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[dig_eq.tz-Unit-(Pair 17 (Pair 16 (Pair 15 (Pair 14 (Pair 13 (Pair 12 (Pair 11 (Pair 10 (Pair 9 (Pair 8 (Pair 7 (Pair 6 (Pair 5 (Pair 4 (Pair 3 (Pair 2 1))))))))))))))))-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 24 (remaining gas: 1039875.367 units remaining) + [ (Pair (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) Unit) ] + - location: 24 (remaining gas: 1039875.357 units remaining) + [ (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 25 (remaining gas: 1039875.347 units remaining) + [ (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 27 (remaining gas: 1039875.337 units remaining) + [ 17 + (Pair 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 28 (remaining gas: 1039875.322 units remaining) + [ (Pair 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 30 (remaining gas: 1039875.312 units remaining) + [ 16 + (Pair 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 28 (remaining gas: 1039875.282 units remaining) + [ 17 + 16 + (Pair 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 31 (remaining gas: 1039875.259 units remaining) + [ (Pair 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 34 (remaining gas: 1039875.249 units remaining) + [ 15 + (Pair 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 31 (remaining gas: 1039875.224 units remaining) + [ 16 + 15 + (Pair 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 31 (remaining gas: 1039875.214 units remaining) + [ 17 + 16 + 15 + (Pair 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 31 (remaining gas: 1039875.214 units remaining) + [ 17 + 16 + 15 + (Pair 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 35 (remaining gas: 1039875.190 units remaining) + [ (Pair 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 38 (remaining gas: 1039875.180 units remaining) + [ 14 + (Pair 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 35 (remaining gas: 1039875.155 units remaining) + [ 15 + 14 + (Pair 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 35 (remaining gas: 1039875.145 units remaining) + [ 16 + 15 + 14 + (Pair 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 35 (remaining gas: 1039875.135 units remaining) + [ 17 + 16 + 15 + 14 + (Pair 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 35 (remaining gas: 1039875.135 units remaining) + [ 17 + 16 + 15 + 14 + (Pair 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 39 (remaining gas: 1039875.109 units remaining) + [ (Pair 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 42 (remaining gas: 1039875.099 units remaining) + [ 13 + (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 39 (remaining gas: 1039875.074 units remaining) + [ 14 + 13 + (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 39 (remaining gas: 1039875.064 units remaining) + [ 15 + 14 + 13 + (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 39 (remaining gas: 1039875.054 units remaining) + [ 16 + 15 + 14 + 13 + (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 39 (remaining gas: 1039875.044 units remaining) + [ 17 + 16 + 15 + 14 + 13 + (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 39 (remaining gas: 1039875.044 units remaining) + [ 17 + 16 + 15 + 14 + 13 + (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 43 (remaining gas: 1039875.017 units remaining) + [ (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 46 (remaining gas: 1039875.007 units remaining) + [ 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 43 (remaining gas: 1039874.982 units remaining) + [ 13 + 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 43 (remaining gas: 1039874.972 units remaining) + [ 14 + 13 + 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 43 (remaining gas: 1039874.962 units remaining) + [ 15 + 14 + 13 + 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 43 (remaining gas: 1039874.952 units remaining) + [ 16 + 15 + 14 + 13 + 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 43 (remaining gas: 1039874.942 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 43 (remaining gas: 1039874.942 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 47 (remaining gas: 1039874.913 units remaining) + [ (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 50 (remaining gas: 1039874.903 units remaining) + [ 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 47 (remaining gas: 1039874.878 units remaining) + [ 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 47 (remaining gas: 1039874.868 units remaining) + [ 13 + 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 47 (remaining gas: 1039874.858 units remaining) + [ 14 + 13 + 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 47 (remaining gas: 1039874.848 units remaining) + [ 15 + 14 + 13 + 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 47 (remaining gas: 1039874.838 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 47 (remaining gas: 1039874.828 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 47 (remaining gas: 1039874.828 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 51 (remaining gas: 1039874.798 units remaining) + [ (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 54 (remaining gas: 1039874.788 units remaining) + [ 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 51 (remaining gas: 1039874.763 units remaining) + [ 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 51 (remaining gas: 1039874.753 units remaining) + [ 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 51 (remaining gas: 1039874.743 units remaining) + [ 13 + 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 51 (remaining gas: 1039874.733 units remaining) + [ 14 + 13 + 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 51 (remaining gas: 1039874.723 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 51 (remaining gas: 1039874.713 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 51 (remaining gas: 1039874.703 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 51 (remaining gas: 1039874.703 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 55 (remaining gas: 1039874.670 units remaining) + [ (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 58 (remaining gas: 1039874.660 units remaining) + [ 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 55 (remaining gas: 1039874.635 units remaining) + [ 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 55 (remaining gas: 1039874.625 units remaining) + [ 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 55 (remaining gas: 1039874.615 units remaining) + [ 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 55 (remaining gas: 1039874.605 units remaining) + [ 13 + 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 55 (remaining gas: 1039874.595 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 55 (remaining gas: 1039874.585 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 55 (remaining gas: 1039874.575 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 55 (remaining gas: 1039874.565 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 55 (remaining gas: 1039874.565 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 59 (remaining gas: 1039874.531 units remaining) + [ (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 62 (remaining gas: 1039874.521 units remaining) + [ 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 59 (remaining gas: 1039874.496 units remaining) + [ 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 59 (remaining gas: 1039874.486 units remaining) + [ 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 59 (remaining gas: 1039874.476 units remaining) + [ 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 59 (remaining gas: 1039874.466 units remaining) + [ 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 59 (remaining gas: 1039874.456 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 59 (remaining gas: 1039874.446 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 59 (remaining gas: 1039874.436 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 59 (remaining gas: 1039874.426 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 59 (remaining gas: 1039874.416 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 59 (remaining gas: 1039874.416 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 63 (remaining gas: 1039874.380 units remaining) + [ (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 66 (remaining gas: 1039874.370 units remaining) + [ 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 63 (remaining gas: 1039874.345 units remaining) + [ 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 63 (remaining gas: 1039874.335 units remaining) + [ 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 63 (remaining gas: 1039874.325 units remaining) + [ 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 63 (remaining gas: 1039874.315 units remaining) + [ 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 63 (remaining gas: 1039874.305 units remaining) + [ 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 63 (remaining gas: 1039874.295 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 63 (remaining gas: 1039874.285 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 63 (remaining gas: 1039874.275 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 63 (remaining gas: 1039874.265 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 63 (remaining gas: 1039874.255 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 63 (remaining gas: 1039874.255 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 67 (remaining gas: 1039874.218 units remaining) + [ (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 70 (remaining gas: 1039874.208 units remaining) + [ 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 67 (remaining gas: 1039874.183 units remaining) + [ 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 67 (remaining gas: 1039874.173 units remaining) + [ 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 67 (remaining gas: 1039874.163 units remaining) + [ 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 67 (remaining gas: 1039874.153 units remaining) + [ 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 67 (remaining gas: 1039874.143 units remaining) + [ 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 67 (remaining gas: 1039874.133 units remaining) + [ 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 67 (remaining gas: 1039874.123 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 67 (remaining gas: 1039874.113 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 67 (remaining gas: 1039874.103 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 67 (remaining gas: 1039874.093 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 67 (remaining gas: 1039874.083 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 67 (remaining gas: 1039874.083 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039874.044 units remaining) + [ (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 74 (remaining gas: 1039874.034 units remaining) + [ 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039874.009 units remaining) + [ 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039873.999 units remaining) + [ 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039873.989 units remaining) + [ 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039873.979 units remaining) + [ 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039873.969 units remaining) + [ 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039873.959 units remaining) + [ 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039873.949 units remaining) + [ 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039873.939 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039873.929 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039873.919 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039873.909 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039873.899 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 71 (remaining gas: 1039873.899 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.859 units remaining) + [ (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 78 (remaining gas: 1039873.849 units remaining) + [ 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.824 units remaining) + [ 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.814 units remaining) + [ 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.804 units remaining) + [ 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.794 units remaining) + [ 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.784 units remaining) + [ 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.774 units remaining) + [ 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.764 units remaining) + [ 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.754 units remaining) + [ 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.744 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.734 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.724 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.714 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.704 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 75 (remaining gas: 1039873.704 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.662 units remaining) + [ (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 82 (remaining gas: 1039873.652 units remaining) + [ 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.627 units remaining) + [ 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.617 units remaining) + [ 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.607 units remaining) + [ 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.597 units remaining) + [ 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.587 units remaining) + [ 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.577 units remaining) + [ 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.567 units remaining) + [ 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.557 units remaining) + [ 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.547 units remaining) + [ 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.537 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.527 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.517 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.507 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.497 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 79 (remaining gas: 1039873.497 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.454 units remaining) + [ (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 86 (remaining gas: 1039873.444 units remaining) + [ 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.419 units remaining) + [ 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.409 units remaining) + [ 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.399 units remaining) + [ 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.389 units remaining) + [ 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.379 units remaining) + [ 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.369 units remaining) + [ 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.359 units remaining) + [ 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.349 units remaining) + [ 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.339 units remaining) + [ 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.329 units remaining) + [ 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.319 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.309 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.299 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.289 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.279 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 83 (remaining gas: 1039873.279 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 87 (remaining gas: 1039873.259 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 89 (remaining gas: 1039873.233 units remaining) + [ 16 + 17 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 91 (remaining gas: 1039873.200 units remaining) + [ 15 + 16 + 17 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 93 (remaining gas: 1039873.161 units remaining) + [ 14 + 15 + 16 + 17 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 95 (remaining gas: 1039873.114 units remaining) + [ 13 + 14 + 15 + 16 + 17 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 97 (remaining gas: 1039873.061 units remaining) + [ 12 + 13 + 14 + 15 + 16 + 17 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 99 (remaining gas: 1039873.001 units remaining) + [ 11 + 12 + 13 + 14 + 15 + 16 + 17 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 101 (remaining gas: 1039872.935 units remaining) + [ 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 103 (remaining gas: 1039872.861 units remaining) + [ 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 105 (remaining gas: 1039872.781 units remaining) + [ 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 107 (remaining gas: 1039872.694 units remaining) + [ 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 109 (remaining gas: 1039872.601 units remaining) + [ 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 111 (remaining gas: 1039872.500 units remaining) + [ 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 113 (remaining gas: 1039872.393 units remaining) + [ 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 115 (remaining gas: 1039872.279 units remaining) + [ 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 117 (remaining gas: 1039872.159 units remaining) + [ 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 119 (remaining gas: 1039872.031 units remaining) + [ 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 121 (remaining gas: 1039872.011 units remaining) + [ 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 123 (remaining gas: 1039871.985 units remaining) + [ 2 + 1 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 125 (remaining gas: 1039871.952 units remaining) + [ 3 + 2 + 1 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 127 (remaining gas: 1039871.913 units remaining) + [ 4 + 3 + 2 + 1 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 129 (remaining gas: 1039871.866 units remaining) + [ 5 + 4 + 3 + 2 + 1 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 131 (remaining gas: 1039871.813 units remaining) + [ 6 + 5 + 4 + 3 + 2 + 1 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 133 (remaining gas: 1039871.753 units remaining) + [ 7 + 6 + 5 + 4 + 3 + 2 + 1 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 135 (remaining gas: 1039871.687 units remaining) + [ 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 137 (remaining gas: 1039871.613 units remaining) + [ 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 139 (remaining gas: 1039871.533 units remaining) + [ 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 141 (remaining gas: 1039871.446 units remaining) + [ 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 12 + 13 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 143 (remaining gas: 1039871.353 units remaining) + [ 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 13 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 145 (remaining gas: 1039871.252 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 14 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 147 (remaining gas: 1039871.145 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 15 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 149 (remaining gas: 1039871.031 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 16 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 151 (remaining gas: 1039870.911 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 17 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 153 (remaining gas: 1039870.783 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.740 units remaining) + [ 2 + 1 + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 159 (remaining gas: 1039870.725 units remaining) + [ (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.700 units remaining) + [ 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.690 units remaining) + [ 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.680 units remaining) + [ 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.670 units remaining) + [ 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.660 units remaining) + [ 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.650 units remaining) + [ 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.640 units remaining) + [ 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.630 units remaining) + [ 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.620 units remaining) + [ 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.610 units remaining) + [ 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.600 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.590 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.580 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.570 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.560 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 156 (remaining gas: 1039870.560 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.518 units remaining) + [ 3 + (Pair 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 163 (remaining gas: 1039870.503 units remaining) + [ (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.478 units remaining) + [ 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.468 units remaining) + [ 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.458 units remaining) + [ 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.448 units remaining) + [ 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.438 units remaining) + [ 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.428 units remaining) + [ 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.418 units remaining) + [ 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.408 units remaining) + [ 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.398 units remaining) + [ 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.388 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.378 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.368 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.358 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.348 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 160 (remaining gas: 1039870.348 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.308 units remaining) + [ 4 + (Pair 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 167 (remaining gas: 1039870.293 units remaining) + [ (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.268 units remaining) + [ 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.258 units remaining) + [ 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.248 units remaining) + [ 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.238 units remaining) + [ 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.228 units remaining) + [ 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.218 units remaining) + [ 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.208 units remaining) + [ 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.198 units remaining) + [ 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.188 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.178 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.168 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.158 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.148 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 164 (remaining gas: 1039870.148 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039870.109 units remaining) + [ 5 + (Pair 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 171 (remaining gas: 1039870.094 units remaining) + [ (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039870.069 units remaining) + [ 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039870.059 units remaining) + [ 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039870.049 units remaining) + [ 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039870.039 units remaining) + [ 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039870.029 units remaining) + [ 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039870.019 units remaining) + [ 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039870.009 units remaining) + [ 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039869.999 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039869.989 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039869.979 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039869.969 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039869.959 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 168 (remaining gas: 1039869.959 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 172 (remaining gas: 1039869.922 units remaining) + [ 6 + (Pair 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 175 (remaining gas: 1039869.907 units remaining) + [ (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 172 (remaining gas: 1039869.882 units remaining) + [ 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 172 (remaining gas: 1039869.872 units remaining) + [ 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 172 (remaining gas: 1039869.862 units remaining) + [ 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 172 (remaining gas: 1039869.852 units remaining) + [ 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 172 (remaining gas: 1039869.842 units remaining) + [ 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 172 (remaining gas: 1039869.832 units remaining) + [ 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 172 (remaining gas: 1039869.822 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 172 (remaining gas: 1039869.812 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 172 (remaining gas: 1039869.802 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 172 (remaining gas: 1039869.792 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 172 (remaining gas: 1039869.782 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 172 (remaining gas: 1039869.782 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 176 (remaining gas: 1039869.746 units remaining) + [ 7 + (Pair 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 179 (remaining gas: 1039869.731 units remaining) + [ (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 176 (remaining gas: 1039869.706 units remaining) + [ 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 176 (remaining gas: 1039869.696 units remaining) + [ 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 176 (remaining gas: 1039869.686 units remaining) + [ 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 176 (remaining gas: 1039869.676 units remaining) + [ 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 176 (remaining gas: 1039869.666 units remaining) + [ 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 176 (remaining gas: 1039869.656 units remaining) + [ 13 + 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 176 (remaining gas: 1039869.646 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 176 (remaining gas: 1039869.636 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 176 (remaining gas: 1039869.626 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 176 (remaining gas: 1039869.616 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 176 (remaining gas: 1039869.616 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 180 (remaining gas: 1039869.582 units remaining) + [ 8 + (Pair 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 183 (remaining gas: 1039869.567 units remaining) + [ (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 180 (remaining gas: 1039869.542 units remaining) + [ 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 180 (remaining gas: 1039869.532 units remaining) + [ 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 180 (remaining gas: 1039869.522 units remaining) + [ 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 180 (remaining gas: 1039869.512 units remaining) + [ 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 180 (remaining gas: 1039869.502 units remaining) + [ 13 + 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 180 (remaining gas: 1039869.492 units remaining) + [ 14 + 13 + 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 180 (remaining gas: 1039869.482 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 180 (remaining gas: 1039869.472 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 180 (remaining gas: 1039869.462 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 180 (remaining gas: 1039869.462 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 184 (remaining gas: 1039869.429 units remaining) + [ 9 + (Pair 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 187 (remaining gas: 1039869.414 units remaining) + [ (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 184 (remaining gas: 1039869.389 units remaining) + [ 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 184 (remaining gas: 1039869.379 units remaining) + [ 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 184 (remaining gas: 1039869.369 units remaining) + [ 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 184 (remaining gas: 1039869.359 units remaining) + [ 13 + 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 184 (remaining gas: 1039869.349 units remaining) + [ 14 + 13 + 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 184 (remaining gas: 1039869.339 units remaining) + [ 15 + 14 + 13 + 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 184 (remaining gas: 1039869.329 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 184 (remaining gas: 1039869.319 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 184 (remaining gas: 1039869.319 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 188 (remaining gas: 1039869.289 units remaining) + [ 10 + (Pair 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 191 (remaining gas: 1039869.274 units remaining) + [ (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 188 (remaining gas: 1039869.249 units remaining) + [ 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 188 (remaining gas: 1039869.239 units remaining) + [ 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 188 (remaining gas: 1039869.229 units remaining) + [ 13 + 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 188 (remaining gas: 1039869.219 units remaining) + [ 14 + 13 + 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 188 (remaining gas: 1039869.209 units remaining) + [ 15 + 14 + 13 + 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 188 (remaining gas: 1039869.199 units remaining) + [ 16 + 15 + 14 + 13 + 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 188 (remaining gas: 1039869.189 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 188 (remaining gas: 1039869.189 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 192 (remaining gas: 1039869.160 units remaining) + [ 11 + (Pair 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 195 (remaining gas: 1039869.145 units remaining) + [ (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 192 (remaining gas: 1039869.120 units remaining) + [ 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 192 (remaining gas: 1039869.110 units remaining) + [ 13 + 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 192 (remaining gas: 1039869.100 units remaining) + [ 14 + 13 + 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 192 (remaining gas: 1039869.090 units remaining) + [ 15 + 14 + 13 + 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 192 (remaining gas: 1039869.080 units remaining) + [ 16 + 15 + 14 + 13 + 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 192 (remaining gas: 1039869.070 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 192 (remaining gas: 1039869.070 units remaining) + [ 17 + 16 + 15 + 14 + 13 + 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 196 (remaining gas: 1039869.043 units remaining) + [ 12 + (Pair 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 199 (remaining gas: 1039869.028 units remaining) + [ (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 196 (remaining gas: 1039869.003 units remaining) + [ 13 + (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 196 (remaining gas: 1039868.993 units remaining) + [ 14 + 13 + (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 196 (remaining gas: 1039868.983 units remaining) + [ 15 + 14 + 13 + (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 196 (remaining gas: 1039868.973 units remaining) + [ 16 + 15 + 14 + 13 + (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 196 (remaining gas: 1039868.963 units remaining) + [ 17 + 16 + 15 + 14 + 13 + (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 196 (remaining gas: 1039868.963 units remaining) + [ 17 + 16 + 15 + 14 + 13 + (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 200 (remaining gas: 1039868.937 units remaining) + [ 13 + (Pair 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 203 (remaining gas: 1039868.922 units remaining) + [ (Pair 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 200 (remaining gas: 1039868.897 units remaining) + [ 14 + (Pair 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 200 (remaining gas: 1039868.887 units remaining) + [ 15 + 14 + (Pair 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 200 (remaining gas: 1039868.877 units remaining) + [ 16 + 15 + 14 + (Pair 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 200 (remaining gas: 1039868.867 units remaining) + [ 17 + 16 + 15 + 14 + (Pair 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 200 (remaining gas: 1039868.867 units remaining) + [ 17 + 16 + 15 + 14 + (Pair 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 204 (remaining gas: 1039868.843 units remaining) + [ 14 + (Pair 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 207 (remaining gas: 1039868.828 units remaining) + [ (Pair 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 204 (remaining gas: 1039868.803 units remaining) + [ 15 + (Pair 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 204 (remaining gas: 1039868.793 units remaining) + [ 16 + 15 + (Pair 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 204 (remaining gas: 1039868.783 units remaining) + [ 17 + 16 + 15 + (Pair 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 204 (remaining gas: 1039868.783 units remaining) + [ 17 + 16 + 15 + (Pair 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 208 (remaining gas: 1039868.760 units remaining) + [ 15 + (Pair 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 211 (remaining gas: 1039868.745 units remaining) + [ (Pair 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 208 (remaining gas: 1039868.720 units remaining) + [ 16 + (Pair 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 208 (remaining gas: 1039868.710 units remaining) + [ 17 + 16 + (Pair 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 208 (remaining gas: 1039868.710 units remaining) + [ 17 + 16 + (Pair 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 212 (remaining gas: 1039868.695 units remaining) + [ 16 + (Pair 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 214 (remaining gas: 1039868.680 units remaining) + [ (Pair 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 212 (remaining gas: 1039868.650 units remaining) + [ 17 + (Pair 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 215 (remaining gas: 1039868.635 units remaining) + [ (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) + (Pair 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) @parameter ] + - location: 218 (remaining gas: 1039867.880 units remaining) + [ 0 ] + - location: 219 (remaining gas: 1039867.865 units remaining) + [ True ] + - location: 220 (remaining gas: 1039867.855 units remaining) + [ ] + - location: 220 (remaining gas: 1039867.840 units remaining) + [ ] + - location: 226 (remaining gas: 1039867.830 units remaining) + [ Unit ] + - location: 227 (remaining gas: 1039867.815 units remaining) + [ {} + Unit ] + - location: 229 (remaining gas: 1039867.800 units remaining) + [ (Pair {} Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dig_eq.tz-Unit-(Pair 2 (Pair 3 (Pair 12 (Pair 16 (Pair .d473151c0f.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dig_eq.tz-Unit-(Pair 2 (Pair 3 (Pair 12 (Pair 16 (Pair .d473151c0f.out new file mode 100644 index 000000000000..74dee5776495 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dig_eq.tz-Unit-(Pair 2 (Pair 3 (Pair 12 (Pair 16 (Pair .d473151c0f.out @@ -0,0 +1,3431 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[dig_eq.tz-Unit-(Pair 2 (Pair 3 (Pair 12 (Pair 16 (Pair 10 (Pair 14 (Pair 19 (Pair 9 (Pair 18 (Pair 6 (Pair 8 (Pair 11 (Pair 4 (Pair 13 (Pair 15 (Pair 5 1))))))))))))))))-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 24 (remaining gas: 1039875.367 units remaining) + [ (Pair (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) Unit) ] + - location: 24 (remaining gas: 1039875.357 units remaining) + [ (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 25 (remaining gas: 1039875.347 units remaining) + [ (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 27 (remaining gas: 1039875.337 units remaining) + [ 2 + (Pair 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 28 (remaining gas: 1039875.322 units remaining) + [ (Pair 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 30 (remaining gas: 1039875.312 units remaining) + [ 3 + (Pair 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 28 (remaining gas: 1039875.282 units remaining) + [ 2 + 3 + (Pair 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 31 (remaining gas: 1039875.259 units remaining) + [ (Pair 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 34 (remaining gas: 1039875.249 units remaining) + [ 12 + (Pair 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 31 (remaining gas: 1039875.224 units remaining) + [ 3 + 12 + (Pair 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 31 (remaining gas: 1039875.214 units remaining) + [ 2 + 3 + 12 + (Pair 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 31 (remaining gas: 1039875.214 units remaining) + [ 2 + 3 + 12 + (Pair 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 35 (remaining gas: 1039875.190 units remaining) + [ (Pair 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 38 (remaining gas: 1039875.180 units remaining) + [ 16 + (Pair 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 35 (remaining gas: 1039875.155 units remaining) + [ 12 + 16 + (Pair 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 35 (remaining gas: 1039875.145 units remaining) + [ 3 + 12 + 16 + (Pair 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 35 (remaining gas: 1039875.135 units remaining) + [ 2 + 3 + 12 + 16 + (Pair 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 35 (remaining gas: 1039875.135 units remaining) + [ 2 + 3 + 12 + 16 + (Pair 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 39 (remaining gas: 1039875.109 units remaining) + [ (Pair 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 42 (remaining gas: 1039875.099 units remaining) + [ 10 + (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 39 (remaining gas: 1039875.074 units remaining) + [ 16 + 10 + (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 39 (remaining gas: 1039875.064 units remaining) + [ 12 + 16 + 10 + (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 39 (remaining gas: 1039875.054 units remaining) + [ 3 + 12 + 16 + 10 + (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 39 (remaining gas: 1039875.044 units remaining) + [ 2 + 3 + 12 + 16 + 10 + (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 39 (remaining gas: 1039875.044 units remaining) + [ 2 + 3 + 12 + 16 + 10 + (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 43 (remaining gas: 1039875.017 units remaining) + [ (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 46 (remaining gas: 1039875.007 units remaining) + [ 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 43 (remaining gas: 1039874.982 units remaining) + [ 10 + 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 43 (remaining gas: 1039874.972 units remaining) + [ 16 + 10 + 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 43 (remaining gas: 1039874.962 units remaining) + [ 12 + 16 + 10 + 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 43 (remaining gas: 1039874.952 units remaining) + [ 3 + 12 + 16 + 10 + 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 43 (remaining gas: 1039874.942 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 43 (remaining gas: 1039874.942 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 47 (remaining gas: 1039874.913 units remaining) + [ (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 50 (remaining gas: 1039874.903 units remaining) + [ 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 47 (remaining gas: 1039874.878 units remaining) + [ 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 47 (remaining gas: 1039874.868 units remaining) + [ 10 + 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 47 (remaining gas: 1039874.858 units remaining) + [ 16 + 10 + 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 47 (remaining gas: 1039874.848 units remaining) + [ 12 + 16 + 10 + 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 47 (remaining gas: 1039874.838 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 47 (remaining gas: 1039874.828 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 47 (remaining gas: 1039874.828 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 51 (remaining gas: 1039874.798 units remaining) + [ (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 54 (remaining gas: 1039874.788 units remaining) + [ 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 51 (remaining gas: 1039874.763 units remaining) + [ 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 51 (remaining gas: 1039874.753 units remaining) + [ 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 51 (remaining gas: 1039874.743 units remaining) + [ 10 + 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 51 (remaining gas: 1039874.733 units remaining) + [ 16 + 10 + 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 51 (remaining gas: 1039874.723 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 51 (remaining gas: 1039874.713 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 51 (remaining gas: 1039874.703 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 51 (remaining gas: 1039874.703 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 55 (remaining gas: 1039874.670 units remaining) + [ (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 58 (remaining gas: 1039874.660 units remaining) + [ 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 55 (remaining gas: 1039874.635 units remaining) + [ 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 55 (remaining gas: 1039874.625 units remaining) + [ 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 55 (remaining gas: 1039874.615 units remaining) + [ 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 55 (remaining gas: 1039874.605 units remaining) + [ 10 + 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 55 (remaining gas: 1039874.595 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 55 (remaining gas: 1039874.585 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 55 (remaining gas: 1039874.575 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 55 (remaining gas: 1039874.565 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 55 (remaining gas: 1039874.565 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 59 (remaining gas: 1039874.531 units remaining) + [ (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 62 (remaining gas: 1039874.521 units remaining) + [ 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 59 (remaining gas: 1039874.496 units remaining) + [ 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 59 (remaining gas: 1039874.486 units remaining) + [ 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 59 (remaining gas: 1039874.476 units remaining) + [ 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 59 (remaining gas: 1039874.466 units remaining) + [ 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 59 (remaining gas: 1039874.456 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 59 (remaining gas: 1039874.446 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 59 (remaining gas: 1039874.436 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 59 (remaining gas: 1039874.426 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 59 (remaining gas: 1039874.416 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 59 (remaining gas: 1039874.416 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 63 (remaining gas: 1039874.380 units remaining) + [ (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 66 (remaining gas: 1039874.370 units remaining) + [ 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 63 (remaining gas: 1039874.345 units remaining) + [ 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 63 (remaining gas: 1039874.335 units remaining) + [ 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 63 (remaining gas: 1039874.325 units remaining) + [ 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 63 (remaining gas: 1039874.315 units remaining) + [ 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 63 (remaining gas: 1039874.305 units remaining) + [ 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 63 (remaining gas: 1039874.295 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 63 (remaining gas: 1039874.285 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 63 (remaining gas: 1039874.275 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 63 (remaining gas: 1039874.265 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 63 (remaining gas: 1039874.255 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 63 (remaining gas: 1039874.255 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 67 (remaining gas: 1039874.218 units remaining) + [ (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 70 (remaining gas: 1039874.208 units remaining) + [ 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 67 (remaining gas: 1039874.183 units remaining) + [ 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 67 (remaining gas: 1039874.173 units remaining) + [ 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 67 (remaining gas: 1039874.163 units remaining) + [ 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 67 (remaining gas: 1039874.153 units remaining) + [ 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 67 (remaining gas: 1039874.143 units remaining) + [ 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 67 (remaining gas: 1039874.133 units remaining) + [ 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 67 (remaining gas: 1039874.123 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 67 (remaining gas: 1039874.113 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 67 (remaining gas: 1039874.103 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 67 (remaining gas: 1039874.093 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 67 (remaining gas: 1039874.083 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 67 (remaining gas: 1039874.083 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039874.044 units remaining) + [ (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 74 (remaining gas: 1039874.034 units remaining) + [ 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039874.009 units remaining) + [ 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039873.999 units remaining) + [ 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039873.989 units remaining) + [ 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039873.979 units remaining) + [ 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039873.969 units remaining) + [ 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039873.959 units remaining) + [ 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039873.949 units remaining) + [ 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039873.939 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039873.929 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039873.919 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039873.909 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039873.899 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 71 (remaining gas: 1039873.899 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.859 units remaining) + [ (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 78 (remaining gas: 1039873.849 units remaining) + [ 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.824 units remaining) + [ 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.814 units remaining) + [ 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.804 units remaining) + [ 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.794 units remaining) + [ 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.784 units remaining) + [ 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.774 units remaining) + [ 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.764 units remaining) + [ 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.754 units remaining) + [ 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.744 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.734 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.724 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.714 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.704 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 75 (remaining gas: 1039873.704 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.662 units remaining) + [ (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 82 (remaining gas: 1039873.652 units remaining) + [ 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.627 units remaining) + [ 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.617 units remaining) + [ 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.607 units remaining) + [ 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.597 units remaining) + [ 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.587 units remaining) + [ 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.577 units remaining) + [ 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.567 units remaining) + [ 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.557 units remaining) + [ 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.547 units remaining) + [ 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.537 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.527 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.517 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.507 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.497 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 79 (remaining gas: 1039873.497 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.454 units remaining) + [ (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 86 (remaining gas: 1039873.444 units remaining) + [ 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.419 units remaining) + [ 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.409 units remaining) + [ 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.399 units remaining) + [ 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.389 units remaining) + [ 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.379 units remaining) + [ 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.369 units remaining) + [ 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.359 units remaining) + [ 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.349 units remaining) + [ 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.339 units remaining) + [ 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.329 units remaining) + [ 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.319 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.309 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.299 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.289 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.279 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 83 (remaining gas: 1039873.279 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 87 (remaining gas: 1039873.259 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 89 (remaining gas: 1039873.233 units remaining) + [ 3 + 2 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 91 (remaining gas: 1039873.200 units remaining) + [ 12 + 3 + 2 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 93 (remaining gas: 1039873.161 units remaining) + [ 16 + 12 + 3 + 2 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 95 (remaining gas: 1039873.114 units remaining) + [ 10 + 16 + 12 + 3 + 2 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 97 (remaining gas: 1039873.061 units remaining) + [ 14 + 10 + 16 + 12 + 3 + 2 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 99 (remaining gas: 1039873.001 units remaining) + [ 19 + 14 + 10 + 16 + 12 + 3 + 2 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 101 (remaining gas: 1039872.935 units remaining) + [ 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 103 (remaining gas: 1039872.861 units remaining) + [ 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 105 (remaining gas: 1039872.781 units remaining) + [ 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 107 (remaining gas: 1039872.694 units remaining) + [ 8 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 109 (remaining gas: 1039872.601 units remaining) + [ 11 + 8 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 111 (remaining gas: 1039872.500 units remaining) + [ 4 + 11 + 8 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 113 (remaining gas: 1039872.393 units remaining) + [ 13 + 4 + 11 + 8 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 115 (remaining gas: 1039872.279 units remaining) + [ 15 + 13 + 4 + 11 + 8 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 117 (remaining gas: 1039872.159 units remaining) + [ 5 + 15 + 13 + 4 + 11 + 8 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 119 (remaining gas: 1039872.031 units remaining) + [ 1 + 5 + 15 + 13 + 4 + 11 + 8 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 121 (remaining gas: 1039872.011 units remaining) + [ 1 + 5 + 15 + 13 + 4 + 11 + 8 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 123 (remaining gas: 1039871.985 units remaining) + [ 5 + 1 + 15 + 13 + 4 + 11 + 8 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 125 (remaining gas: 1039871.952 units remaining) + [ 15 + 5 + 1 + 13 + 4 + 11 + 8 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 127 (remaining gas: 1039871.913 units remaining) + [ 13 + 15 + 5 + 1 + 4 + 11 + 8 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 129 (remaining gas: 1039871.866 units remaining) + [ 4 + 13 + 15 + 5 + 1 + 11 + 8 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 131 (remaining gas: 1039871.813 units remaining) + [ 11 + 4 + 13 + 15 + 5 + 1 + 8 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 133 (remaining gas: 1039871.753 units remaining) + [ 8 + 11 + 4 + 13 + 15 + 5 + 1 + 6 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 135 (remaining gas: 1039871.687 units remaining) + [ 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + 18 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 137 (remaining gas: 1039871.613 units remaining) + [ 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + 9 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 139 (remaining gas: 1039871.533 units remaining) + [ 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + 19 + 14 + 10 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 141 (remaining gas: 1039871.446 units remaining) + [ 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + 14 + 10 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 143 (remaining gas: 1039871.353 units remaining) + [ 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + 10 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 145 (remaining gas: 1039871.252 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + 16 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 147 (remaining gas: 1039871.145 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + 12 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 149 (remaining gas: 1039871.031 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + 3 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 151 (remaining gas: 1039870.911 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + 2 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 153 (remaining gas: 1039870.783 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.740 units remaining) + [ 5 + 1 + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 159 (remaining gas: 1039870.725 units remaining) + [ (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.700 units remaining) + [ 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.690 units remaining) + [ 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.680 units remaining) + [ 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.670 units remaining) + [ 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.660 units remaining) + [ 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.650 units remaining) + [ 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.640 units remaining) + [ 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.630 units remaining) + [ 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.620 units remaining) + [ 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.610 units remaining) + [ 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.600 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.590 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.580 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.570 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.560 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 156 (remaining gas: 1039870.560 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.518 units remaining) + [ 15 + (Pair 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 163 (remaining gas: 1039870.503 units remaining) + [ (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.478 units remaining) + [ 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.468 units remaining) + [ 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.458 units remaining) + [ 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.448 units remaining) + [ 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.438 units remaining) + [ 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.428 units remaining) + [ 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.418 units remaining) + [ 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.408 units remaining) + [ 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.398 units remaining) + [ 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.388 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.378 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.368 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.358 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.348 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 160 (remaining gas: 1039870.348 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.308 units remaining) + [ 13 + (Pair 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 167 (remaining gas: 1039870.293 units remaining) + [ (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.268 units remaining) + [ 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.258 units remaining) + [ 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.248 units remaining) + [ 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.238 units remaining) + [ 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.228 units remaining) + [ 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.218 units remaining) + [ 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.208 units remaining) + [ 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.198 units remaining) + [ 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.188 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.178 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.168 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.158 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.148 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 164 (remaining gas: 1039870.148 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039870.109 units remaining) + [ 4 + (Pair 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 171 (remaining gas: 1039870.094 units remaining) + [ (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039870.069 units remaining) + [ 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039870.059 units remaining) + [ 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039870.049 units remaining) + [ 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039870.039 units remaining) + [ 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039870.029 units remaining) + [ 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039870.019 units remaining) + [ 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039870.009 units remaining) + [ 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039869.999 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039869.989 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039869.979 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039869.969 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039869.959 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 168 (remaining gas: 1039869.959 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 172 (remaining gas: 1039869.922 units remaining) + [ 11 + (Pair 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 175 (remaining gas: 1039869.907 units remaining) + [ (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 172 (remaining gas: 1039869.882 units remaining) + [ 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 172 (remaining gas: 1039869.872 units remaining) + [ 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 172 (remaining gas: 1039869.862 units remaining) + [ 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 172 (remaining gas: 1039869.852 units remaining) + [ 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 172 (remaining gas: 1039869.842 units remaining) + [ 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 172 (remaining gas: 1039869.832 units remaining) + [ 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 172 (remaining gas: 1039869.822 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 172 (remaining gas: 1039869.812 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 172 (remaining gas: 1039869.802 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 172 (remaining gas: 1039869.792 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 172 (remaining gas: 1039869.782 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 172 (remaining gas: 1039869.782 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 176 (remaining gas: 1039869.746 units remaining) + [ 8 + (Pair 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 179 (remaining gas: 1039869.731 units remaining) + [ (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 176 (remaining gas: 1039869.706 units remaining) + [ 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 176 (remaining gas: 1039869.696 units remaining) + [ 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 176 (remaining gas: 1039869.686 units remaining) + [ 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 176 (remaining gas: 1039869.676 units remaining) + [ 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 176 (remaining gas: 1039869.666 units remaining) + [ 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 176 (remaining gas: 1039869.656 units remaining) + [ 10 + 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 176 (remaining gas: 1039869.646 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 176 (remaining gas: 1039869.636 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 176 (remaining gas: 1039869.626 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 176 (remaining gas: 1039869.616 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 176 (remaining gas: 1039869.616 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 180 (remaining gas: 1039869.582 units remaining) + [ 6 + (Pair 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 183 (remaining gas: 1039869.567 units remaining) + [ (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 180 (remaining gas: 1039869.542 units remaining) + [ 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 180 (remaining gas: 1039869.532 units remaining) + [ 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 180 (remaining gas: 1039869.522 units remaining) + [ 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 180 (remaining gas: 1039869.512 units remaining) + [ 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 180 (remaining gas: 1039869.502 units remaining) + [ 10 + 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 180 (remaining gas: 1039869.492 units remaining) + [ 16 + 10 + 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 180 (remaining gas: 1039869.482 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 180 (remaining gas: 1039869.472 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 180 (remaining gas: 1039869.462 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 180 (remaining gas: 1039869.462 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 184 (remaining gas: 1039869.429 units remaining) + [ 18 + (Pair 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 187 (remaining gas: 1039869.414 units remaining) + [ (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 184 (remaining gas: 1039869.389 units remaining) + [ 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 184 (remaining gas: 1039869.379 units remaining) + [ 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 184 (remaining gas: 1039869.369 units remaining) + [ 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 184 (remaining gas: 1039869.359 units remaining) + [ 10 + 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 184 (remaining gas: 1039869.349 units remaining) + [ 16 + 10 + 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 184 (remaining gas: 1039869.339 units remaining) + [ 12 + 16 + 10 + 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 184 (remaining gas: 1039869.329 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 184 (remaining gas: 1039869.319 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 184 (remaining gas: 1039869.319 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 188 (remaining gas: 1039869.289 units remaining) + [ 9 + (Pair 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 191 (remaining gas: 1039869.274 units remaining) + [ (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 188 (remaining gas: 1039869.249 units remaining) + [ 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 188 (remaining gas: 1039869.239 units remaining) + [ 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 188 (remaining gas: 1039869.229 units remaining) + [ 10 + 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 188 (remaining gas: 1039869.219 units remaining) + [ 16 + 10 + 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 188 (remaining gas: 1039869.209 units remaining) + [ 12 + 16 + 10 + 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 188 (remaining gas: 1039869.199 units remaining) + [ 3 + 12 + 16 + 10 + 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 188 (remaining gas: 1039869.189 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 188 (remaining gas: 1039869.189 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 192 (remaining gas: 1039869.160 units remaining) + [ 19 + (Pair 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 195 (remaining gas: 1039869.145 units remaining) + [ (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 192 (remaining gas: 1039869.120 units remaining) + [ 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 192 (remaining gas: 1039869.110 units remaining) + [ 10 + 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 192 (remaining gas: 1039869.100 units remaining) + [ 16 + 10 + 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 192 (remaining gas: 1039869.090 units remaining) + [ 12 + 16 + 10 + 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 192 (remaining gas: 1039869.080 units remaining) + [ 3 + 12 + 16 + 10 + 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 192 (remaining gas: 1039869.070 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 192 (remaining gas: 1039869.070 units remaining) + [ 2 + 3 + 12 + 16 + 10 + 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 196 (remaining gas: 1039869.043 units remaining) + [ 14 + (Pair 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 199 (remaining gas: 1039869.028 units remaining) + [ (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 196 (remaining gas: 1039869.003 units remaining) + [ 10 + (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 196 (remaining gas: 1039868.993 units remaining) + [ 16 + 10 + (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 196 (remaining gas: 1039868.983 units remaining) + [ 12 + 16 + 10 + (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 196 (remaining gas: 1039868.973 units remaining) + [ 3 + 12 + 16 + 10 + (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 196 (remaining gas: 1039868.963 units remaining) + [ 2 + 3 + 12 + 16 + 10 + (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 196 (remaining gas: 1039868.963 units remaining) + [ 2 + 3 + 12 + 16 + 10 + (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 200 (remaining gas: 1039868.937 units remaining) + [ 10 + (Pair 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 203 (remaining gas: 1039868.922 units remaining) + [ (Pair 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 200 (remaining gas: 1039868.897 units remaining) + [ 16 + (Pair 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 200 (remaining gas: 1039868.887 units remaining) + [ 12 + 16 + (Pair 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 200 (remaining gas: 1039868.877 units remaining) + [ 3 + 12 + 16 + (Pair 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 200 (remaining gas: 1039868.867 units remaining) + [ 2 + 3 + 12 + 16 + (Pair 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 200 (remaining gas: 1039868.867 units remaining) + [ 2 + 3 + 12 + 16 + (Pair 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 204 (remaining gas: 1039868.843 units remaining) + [ 16 + (Pair 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 207 (remaining gas: 1039868.828 units remaining) + [ (Pair 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 204 (remaining gas: 1039868.803 units remaining) + [ 12 + (Pair 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 204 (remaining gas: 1039868.793 units remaining) + [ 3 + 12 + (Pair 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 204 (remaining gas: 1039868.783 units remaining) + [ 2 + 3 + 12 + (Pair 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 204 (remaining gas: 1039868.783 units remaining) + [ 2 + 3 + 12 + (Pair 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 208 (remaining gas: 1039868.760 units remaining) + [ 12 + (Pair 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 211 (remaining gas: 1039868.745 units remaining) + [ (Pair 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 208 (remaining gas: 1039868.720 units remaining) + [ 3 + (Pair 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 208 (remaining gas: 1039868.710 units remaining) + [ 2 + 3 + (Pair 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 208 (remaining gas: 1039868.710 units remaining) + [ 2 + 3 + (Pair 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 212 (remaining gas: 1039868.695 units remaining) + [ 3 + (Pair 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 214 (remaining gas: 1039868.680 units remaining) + [ (Pair 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 212 (remaining gas: 1039868.650 units remaining) + [ 2 + (Pair 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 215 (remaining gas: 1039868.635 units remaining) + [ (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) + (Pair 2 3 12 16 10 14 19 9 18 6 8 11 4 13 15 5 1) @parameter ] + - location: 218 (remaining gas: 1039867.880 units remaining) + [ 0 ] + - location: 219 (remaining gas: 1039867.865 units remaining) + [ True ] + - location: 220 (remaining gas: 1039867.855 units remaining) + [ ] + - location: 220 (remaining gas: 1039867.840 units remaining) + [ ] + - location: 226 (remaining gas: 1039867.830 units remaining) + [ Unit ] + - location: 227 (remaining gas: 1039867.815 units remaining) + [ {} + Unit ] + - location: 229 (remaining gas: 1039867.800 units remaining) + [ (Pair {} Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dign.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-5].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dign.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-5].out new file mode 100644 index 000000000000..67aa01b5a3c1 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dign.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-5].out @@ -0,0 +1,61 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[dign.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-5] + +storage + 5 +emitted operations + +big_map diff + +trace + - location: 15 (remaining gas: 1039987.890 units remaining) + [ (Pair (Pair (Pair (Pair (Pair 1 2) 3) 4) 5) 0) ] + - location: 15 (remaining gas: 1039987.880 units remaining) + [ (Pair (Pair (Pair (Pair 1 2) 3) 4) 5) @parameter ] + - location: 16 (remaining gas: 1039987.870 units remaining) + [ (Pair (Pair (Pair 1 2) 3) 4) + 5 ] + - location: 17 (remaining gas: 1039987.860 units remaining) + [ (Pair (Pair 1 2) 3) + 4 + 5 ] + - location: 18 (remaining gas: 1039987.850 units remaining) + [ (Pair 1 2) + 3 + 4 + 5 ] + - location: 19 (remaining gas: 1039987.840 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 20 (remaining gas: 1039987.793 units remaining) + [ 5 + 1 + 2 + 3 + 4 ] + - location: 22 (remaining gas: 1039987.778 units remaining) + [ 1 + 2 + 3 + 4 ] + - location: 24 (remaining gas: 1039987.768 units remaining) + [ 2 + 3 + 4 ] + - location: 25 (remaining gas: 1039987.758 units remaining) + [ 3 + 4 ] + - location: 26 (remaining gas: 1039987.748 units remaining) + [ 4 ] + - location: 27 (remaining gas: 1039987.738 units remaining) + [ ] + - location: 22 (remaining gas: 1039987.708 units remaining) + [ 5 ] + - location: 28 (remaining gas: 1039987.693 units remaining) + [ {} + 5 ] + - location: 30 (remaining gas: 1039987.678 units remaining) + [ (Pair {} 5) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dip.tz-(Pair 0 0)-(Pair 1 1)-(Pair 1 2)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dip.tz-(Pair 0 0)-(Pair 1 1)-(Pair 1 2)].out new file mode 100644 index 000000000000..6d8793d615da --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dip.tz-(Pair 0 0)-(Pair 1 1)-(Pair 1 2)].out @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[dip.tz-(Pair 0 0)-(Pair 1 1)-(Pair 1 2)] + +storage + (Pair 1 2) +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039991.838 units remaining) + [ (Pair (Pair 1 1) 0 0) ] + - location: 11 (remaining gas: 1039991.828 units remaining) + [ (Pair 1 1) @parameter ] + - location: 12 (remaining gas: 1039991.818 units remaining) + [ 1 + 1 ] + - location: 13 (remaining gas: 1039991.808 units remaining) + [ 1 + 1 + 1 ] + - location: 14 (remaining gas: 1039991.793 units remaining) + [ 1 + 1 ] + - location: 16 (remaining gas: 1039991.758 units remaining) + [ 2 ] + - location: 14 (remaining gas: 1039991.728 units remaining) + [ 1 + 2 ] + - location: 17 (remaining gas: 1039991.713 units remaining) + [ (Pair 1 2) ] + - location: 18 (remaining gas: 1039991.698 units remaining) + [ {} + (Pair 1 2) ] + - location: 20 (remaining gas: 1039991.683 units remaining) + [ (Pair {} 1 2) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dip.tz-(Pair 0 0)-(Pair 15 9)-(Pair 15 24)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dip.tz-(Pair 0 0)-(Pair 15 9)-(Pair 15 24)].out new file mode 100644 index 000000000000..ba8f1d3ebba3 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dip.tz-(Pair 0 0)-(Pair 15 9)-(Pair 15 24)].out @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[dip.tz-(Pair 0 0)-(Pair 15 9)-(Pair 15 24)] + +storage + (Pair 15 24) +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039991.838 units remaining) + [ (Pair (Pair 15 9) 0 0) ] + - location: 11 (remaining gas: 1039991.828 units remaining) + [ (Pair 15 9) @parameter ] + - location: 12 (remaining gas: 1039991.818 units remaining) + [ 15 + 9 ] + - location: 13 (remaining gas: 1039991.808 units remaining) + [ 15 + 15 + 9 ] + - location: 14 (remaining gas: 1039991.793 units remaining) + [ 15 + 9 ] + - location: 16 (remaining gas: 1039991.758 units remaining) + [ 24 ] + - location: 14 (remaining gas: 1039991.728 units remaining) + [ 15 + 24 ] + - location: 17 (remaining gas: 1039991.713 units remaining) + [ (Pair 15 24) ] + - location: 18 (remaining gas: 1039991.698 units remaining) + [ {} + (Pair 15 24) ] + - location: 20 (remaining gas: 1039991.683 units remaining) + [ (Pair {} 15 24) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dipn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-6].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dipn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-6].out new file mode 100644 index 000000000000..f629070d440d --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dipn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-6].out @@ -0,0 +1,93 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[dipn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-6] + +storage + 6 +emitted operations + +big_map diff + +trace + - location: 15 (remaining gas: 1039986.730 units remaining) + [ (Pair (Pair (Pair (Pair (Pair 1 2) 3) 4) 5) 0) ] + - location: 15 (remaining gas: 1039986.720 units remaining) + [ (Pair (Pair (Pair (Pair 1 2) 3) 4) 5) @parameter ] + - location: 16 (remaining gas: 1039986.710 units remaining) + [ (Pair (Pair (Pair 1 2) 3) 4) + 5 ] + - location: 17 (remaining gas: 1039986.700 units remaining) + [ (Pair (Pair 1 2) 3) + 4 + 5 ] + - location: 18 (remaining gas: 1039986.690 units remaining) + [ (Pair 1 2) + 3 + 4 + 5 ] + - location: 19 (remaining gas: 1039986.680 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 20 (remaining gas: 1039986.653 units remaining) + [ ] + - location: 23 (remaining gas: 1039986.643 units remaining) + [ 6 ] + - location: 20 (remaining gas: 1039986.618 units remaining) + [ 5 + 6 ] + - location: 20 (remaining gas: 1039986.608 units remaining) + [ 4 + 5 + 6 ] + - location: 20 (remaining gas: 1039986.598 units remaining) + [ 3 + 4 + 5 + 6 ] + - location: 20 (remaining gas: 1039986.588 units remaining) + [ 2 + 3 + 4 + 5 + 6 ] + - location: 20 (remaining gas: 1039986.578 units remaining) + [ 1 + 2 + 3 + 4 + 5 + 6 ] + - location: 20 (remaining gas: 1039986.578 units remaining) + [ 1 + 2 + 3 + 4 + 5 + 6 ] + - location: 26 (remaining gas: 1039986.568 units remaining) + [ 2 + 3 + 4 + 5 + 6 ] + - location: 27 (remaining gas: 1039986.558 units remaining) + [ 3 + 4 + 5 + 6 ] + - location: 28 (remaining gas: 1039986.548 units remaining) + [ 4 + 5 + 6 ] + - location: 29 (remaining gas: 1039986.538 units remaining) + [ 5 + 6 ] + - location: 30 (remaining gas: 1039986.528 units remaining) + [ 6 ] + - location: 31 (remaining gas: 1039986.513 units remaining) + [ {} + 6 ] + - location: 33 (remaining gas: 1039986.498 units remaining) + [ (Pair {} 6) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dropn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-5].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dropn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-5].out new file mode 100644 index 000000000000..72330b793f31 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dropn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-5].out @@ -0,0 +1,39 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[dropn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-5] + +storage + 5 +emitted operations + +big_map diff + +trace + - location: 15 (remaining gas: 1039991.067 units remaining) + [ (Pair (Pair (Pair (Pair (Pair 1 2) 3) 4) 5) 0) ] + - location: 15 (remaining gas: 1039991.057 units remaining) + [ (Pair (Pair (Pair (Pair 1 2) 3) 4) 5) @parameter ] + - location: 16 (remaining gas: 1039991.047 units remaining) + [ (Pair (Pair (Pair 1 2) 3) 4) + 5 ] + - location: 17 (remaining gas: 1039991.037 units remaining) + [ (Pair (Pair 1 2) 3) + 4 + 5 ] + - location: 18 (remaining gas: 1039991.027 units remaining) + [ (Pair 1 2) + 3 + 4 + 5 ] + - location: 19 (remaining gas: 1039991.017 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 20 (remaining gas: 1039990.987 units remaining) + [ 5 ] + - location: 22 (remaining gas: 1039990.972 units remaining) + [ {} + 5 ] + - location: 24 (remaining gas: 1039990.957 units remaining) + [ (Pair {} 5) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dugn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-1].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dugn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-1].out new file mode 100644 index 000000000000..fe25bf8802ae --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dugn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-1].out @@ -0,0 +1,57 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[dugn.tz-0-(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)-1] + +storage + 1 +emitted operations + +big_map diff + +trace + - location: 15 (remaining gas: 1039988.656 units remaining) + [ (Pair (Pair (Pair (Pair (Pair 1 2) 3) 4) 5) 0) ] + - location: 15 (remaining gas: 1039988.646 units remaining) + [ (Pair (Pair (Pair (Pair 1 2) 3) 4) 5) @parameter ] + - location: 16 (remaining gas: 1039988.636 units remaining) + [ (Pair (Pair (Pair 1 2) 3) 4) + 5 ] + - location: 17 (remaining gas: 1039988.626 units remaining) + [ (Pair (Pair 1 2) 3) + 4 + 5 ] + - location: 18 (remaining gas: 1039988.616 units remaining) + [ (Pair 1 2) + 3 + 4 + 5 ] + - location: 19 (remaining gas: 1039988.606 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 20 (remaining gas: 1039988.559 units remaining) + [ 2 + 3 + 4 + 5 + 1 ] + - location: 22 (remaining gas: 1039988.549 units remaining) + [ 3 + 4 + 5 + 1 ] + - location: 23 (remaining gas: 1039988.539 units remaining) + [ 4 + 5 + 1 ] + - location: 24 (remaining gas: 1039988.529 units remaining) + [ 5 + 1 ] + - location: 25 (remaining gas: 1039988.519 units remaining) + [ 1 ] + - location: 26 (remaining gas: 1039988.504 units remaining) + [ {} + 1 ] + - location: 28 (remaining gas: 1039988.489 units remaining) + [ (Pair {} 1) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dup-n.tz-Unit-Unit-Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dup-n.tz-Unit-Unit-Unit].out new file mode 100644 index 000000000000..8aebf81500f7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[dup-n.tz-Unit-Unit-Unit].out @@ -0,0 +1,248 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[dup-n.tz-Unit-Unit-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039953.607 units remaining) + [ (Pair Unit Unit) ] + - location: 7 (remaining gas: 1039953.597 units remaining) + [ ] + - location: 8 (remaining gas: 1039953.587 units remaining) + [ 5 ] + - location: 11 (remaining gas: 1039953.577 units remaining) + [ 4 + 5 ] + - location: 14 (remaining gas: 1039953.567 units remaining) + [ 3 + 4 + 5 ] + - location: 17 (remaining gas: 1039953.557 units remaining) + [ 2 + 3 + 4 + 5 ] + - location: 20 (remaining gas: 1039953.547 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 23 (remaining gas: 1039953.526 units remaining) + [ 1 + 1 + 2 + 3 + 4 + 5 ] + - location: 25 (remaining gas: 1039953.516 units remaining) + [ 1 + 1 + 1 + 2 + 3 + 4 + 5 ] + - location: 30 (remaining gas: 1039953.481 units remaining) + [ 0 + 1 + 2 + 3 + 4 + 5 ] + - location: 31 (remaining gas: 1039953.466 units remaining) + [ True + 1 + 2 + 3 + 4 + 5 ] + - location: 32 (remaining gas: 1039953.456 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 32 (remaining gas: 1039953.441 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 38 (remaining gas: 1039953.419 units remaining) + [ 2 + 1 + 2 + 3 + 4 + 5 ] + - location: 40 (remaining gas: 1039953.409 units remaining) + [ 2 + 2 + 1 + 2 + 3 + 4 + 5 ] + - location: 45 (remaining gas: 1039953.374 units remaining) + [ 0 + 1 + 2 + 3 + 4 + 5 ] + - location: 46 (remaining gas: 1039953.359 units remaining) + [ True + 1 + 2 + 3 + 4 + 5 ] + - location: 47 (remaining gas: 1039953.349 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 47 (remaining gas: 1039953.334 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 53 (remaining gas: 1039953.311 units remaining) + [ 3 + 1 + 2 + 3 + 4 + 5 ] + - location: 55 (remaining gas: 1039953.301 units remaining) + [ 3 + 3 + 1 + 2 + 3 + 4 + 5 ] + - location: 60 (remaining gas: 1039953.266 units remaining) + [ 0 + 1 + 2 + 3 + 4 + 5 ] + - location: 61 (remaining gas: 1039953.251 units remaining) + [ True + 1 + 2 + 3 + 4 + 5 ] + - location: 62 (remaining gas: 1039953.241 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 62 (remaining gas: 1039953.226 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 68 (remaining gas: 1039953.202 units remaining) + [ 4 + 1 + 2 + 3 + 4 + 5 ] + - location: 70 (remaining gas: 1039953.192 units remaining) + [ 4 + 4 + 1 + 2 + 3 + 4 + 5 ] + - location: 75 (remaining gas: 1039953.157 units remaining) + [ 0 + 1 + 2 + 3 + 4 + 5 ] + - location: 76 (remaining gas: 1039953.142 units remaining) + [ True + 1 + 2 + 3 + 4 + 5 ] + - location: 77 (remaining gas: 1039953.132 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 77 (remaining gas: 1039953.117 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 83 (remaining gas: 1039953.092 units remaining) + [ 5 + 1 + 2 + 3 + 4 + 5 ] + - location: 85 (remaining gas: 1039953.082 units remaining) + [ 5 + 5 + 1 + 2 + 3 + 4 + 5 ] + - location: 90 (remaining gas: 1039953.047 units remaining) + [ 0 + 1 + 2 + 3 + 4 + 5 ] + - location: 91 (remaining gas: 1039953.032 units remaining) + [ True + 1 + 2 + 3 + 4 + 5 ] + - location: 92 (remaining gas: 1039953.022 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 92 (remaining gas: 1039953.007 units remaining) + [ 1 + 2 + 3 + 4 + 5 ] + - location: 98 (remaining gas: 1039952.975 units remaining) + [ ] + - location: 100 (remaining gas: 1039952.965 units remaining) + [ Unit ] + - location: 101 (remaining gas: 1039952.950 units remaining) + [ {} + Unit ] + - location: 103 (remaining gas: 1039952.935 units remaining) + [ (Pair {} Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair -8 2)-(Pair (S.ecc0e72cbb.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair -8 2)-(Pair (S.ecc0e72cbb.out new file mode 100644 index 000000000000..b0d5f44eab64 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair -8 2)-(Pair (S.ecc0e72cbb.out @@ -0,0 +1,142 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair -8 2)-(Pair (Some (Pair -4 0)) (Some (Pair -4 0)) (Some (Pair 4 0)) (Some (Pair 4 0)))] + +storage + (Pair (Some (Pair -4 0)) (Some (Pair -4 0)) (Some (Pair 4 0)) (Some (Pair 4 0))) +emitted operations + +big_map diff + +trace + - location: 25 (remaining gas: 1039973.923 units remaining) + [ (Pair (Pair -8 2) None None None None) ] + - location: 25 (remaining gas: 1039973.913 units remaining) + [ (Pair -8 2) @parameter ] + - location: 26 (remaining gas: 1039973.903 units remaining) + [ (Pair -8 2) @parameter + (Pair -8 2) @parameter ] + - location: 27 (remaining gas: 1039973.893 units remaining) + [ -8 + 2 + (Pair -8 2) @parameter ] + - location: 28 (remaining gas: 1039973.868 units remaining) + [ 8 + 2 + (Pair -8 2) @parameter ] + - location: 29 (remaining gas: 1039973.853 units remaining) + [ 2 + (Pair -8 2) @parameter ] + - location: 31 (remaining gas: 1039973.828 units remaining) + [ 2 + (Pair -8 2) @parameter ] + - location: 29 (remaining gas: 1039973.798 units remaining) + [ 8 + 2 + (Pair -8 2) @parameter ] + - location: 32 (remaining gas: 1039973.688 units remaining) + [ (Some (Pair 4 0)) + (Pair -8 2) @parameter ] + - location: 33 (remaining gas: 1039973.678 units remaining) + [ (Pair -8 2) @parameter + (Some (Pair 4 0)) ] + - location: 34 (remaining gas: 1039973.668 units remaining) + [ (Pair -8 2) @parameter + (Pair -8 2) @parameter + (Some (Pair 4 0)) ] + - location: 35 (remaining gas: 1039973.658 units remaining) + [ -8 + 2 + (Pair -8 2) @parameter + (Some (Pair 4 0)) ] + - location: 36 (remaining gas: 1039973.633 units remaining) + [ 8 + 2 + (Pair -8 2) @parameter + (Some (Pair 4 0)) ] + - location: 37 (remaining gas: 1039973.523 units remaining) + [ (Some (Pair 4 0)) + (Pair -8 2) @parameter + (Some (Pair 4 0)) ] + - location: 38 (remaining gas: 1039973.513 units remaining) + [ (Pair -8 2) @parameter + (Some (Pair 4 0)) + (Some (Pair 4 0)) ] + - location: 39 (remaining gas: 1039973.503 units remaining) + [ (Pair -8 2) @parameter + (Pair -8 2) @parameter + (Some (Pair 4 0)) + (Some (Pair 4 0)) ] + - location: 40 (remaining gas: 1039973.493 units remaining) + [ -8 + 2 + (Pair -8 2) @parameter + (Some (Pair 4 0)) + (Some (Pair 4 0)) ] + - location: 41 (remaining gas: 1039973.478 units remaining) + [ 2 + (Pair -8 2) @parameter + (Some (Pair 4 0)) + (Some (Pair 4 0)) ] + - location: 43 (remaining gas: 1039973.453 units remaining) + [ 2 + (Pair -8 2) @parameter + (Some (Pair 4 0)) + (Some (Pair 4 0)) ] + - location: 41 (remaining gas: 1039973.423 units remaining) + [ -8 + 2 + (Pair -8 2) @parameter + (Some (Pair 4 0)) + (Some (Pair 4 0)) ] + - location: 44 (remaining gas: 1039973.313 units remaining) + [ (Some (Pair -4 0)) + (Pair -8 2) @parameter + (Some (Pair 4 0)) + (Some (Pair 4 0)) ] + - location: 45 (remaining gas: 1039973.303 units remaining) + [ (Pair -8 2) @parameter + (Some (Pair -4 0)) + (Some (Pair 4 0)) + (Some (Pair 4 0)) ] + - location: 46 (remaining gas: 1039973.293 units remaining) + [ -8 + 2 + (Some (Pair -4 0)) + (Some (Pair 4 0)) + (Some (Pair 4 0)) ] + - location: 47 (remaining gas: 1039973.183 units remaining) + [ (Some (Pair -4 0)) + (Some (Pair -4 0)) + (Some (Pair 4 0)) + (Some (Pair 4 0)) ] + - location: 49 (remaining gas: 1039973.160 units remaining) + [ (Some (Pair 4 0)) + (Some (Pair 4 0)) ] + - location: 52 (remaining gas: 1039973.145 units remaining) + [ (Pair (Some (Pair 4 0)) (Some (Pair 4 0))) ] + - location: 49 (remaining gas: 1039973.120 units remaining) + [ (Some (Pair -4 0)) + (Pair (Some (Pair 4 0)) (Some (Pair 4 0))) ] + - location: 49 (remaining gas: 1039973.110 units remaining) + [ (Some (Pair -4 0)) + (Some (Pair -4 0)) + (Pair (Some (Pair 4 0)) (Some (Pair 4 0))) ] + - location: 49 (remaining gas: 1039973.110 units remaining) + [ (Some (Pair -4 0)) + (Some (Pair -4 0)) + (Pair (Some (Pair 4 0)) (Some (Pair 4 0))) ] + - location: 53 (remaining gas: 1039973.095 units remaining) + [ (Some (Pair -4 0)) + (Pair (Some (Pair 4 0)) (Some (Pair 4 0))) ] + - location: 55 (remaining gas: 1039973.080 units remaining) + [ (Pair (Some (Pair -4 0)) (Some (Pair 4 0)) (Some (Pair 4 0))) ] + - location: 53 (remaining gas: 1039973.050 units remaining) + [ (Some (Pair -4 0)) + (Pair (Some (Pair -4 0)) (Some (Pair 4 0)) (Some (Pair 4 0))) ] + - location: 56 (remaining gas: 1039973.035 units remaining) + [ (Pair (Some (Pair -4 0)) (Some (Pair -4 0)) (Some (Pair 4 0)) (Some (Pair 4 0))) ] + - location: 57 (remaining gas: 1039973.020 units remaining) + [ {} + (Pair (Some (Pair -4 0)) (Some (Pair -4 0)) (Some (Pair 4 0)) (Some (Pair 4 0))) ] + - location: 59 (remaining gas: 1039973.005 units remaining) + [ (Pair {} (Some (Pair -4 0)) (Some (Pair -4 0)) (Some (Pair 4 0)) (Some (Pair 4 0))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair 10 -3)-(Pair (.3caea50555.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair 10 -3)-(Pair (.3caea50555.out new file mode 100644 index 000000000000..440e2d86259e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair 10 -3)-(Pair (.3caea50555.out @@ -0,0 +1,142 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair 10 -3)-(Pair (Some (Pair -3 1)) (Some (Pair 3 1)) (Some (Pair -3 1)) (Some (Pair 3 1)))] + +storage + (Pair (Some (Pair -3 1)) (Some (Pair 3 1)) (Some (Pair -3 1)) (Some (Pair 3 1))) +emitted operations + +big_map diff + +trace + - location: 25 (remaining gas: 1039973.923 units remaining) + [ (Pair (Pair 10 -3) None None None None) ] + - location: 25 (remaining gas: 1039973.913 units remaining) + [ (Pair 10 -3) @parameter ] + - location: 26 (remaining gas: 1039973.903 units remaining) + [ (Pair 10 -3) @parameter + (Pair 10 -3) @parameter ] + - location: 27 (remaining gas: 1039973.893 units remaining) + [ 10 + -3 + (Pair 10 -3) @parameter ] + - location: 28 (remaining gas: 1039973.868 units remaining) + [ 10 + -3 + (Pair 10 -3) @parameter ] + - location: 29 (remaining gas: 1039973.853 units remaining) + [ -3 + (Pair 10 -3) @parameter ] + - location: 31 (remaining gas: 1039973.828 units remaining) + [ 3 + (Pair 10 -3) @parameter ] + - location: 29 (remaining gas: 1039973.798 units remaining) + [ 10 + 3 + (Pair 10 -3) @parameter ] + - location: 32 (remaining gas: 1039973.688 units remaining) + [ (Some (Pair 3 1)) + (Pair 10 -3) @parameter ] + - location: 33 (remaining gas: 1039973.678 units remaining) + [ (Pair 10 -3) @parameter + (Some (Pair 3 1)) ] + - location: 34 (remaining gas: 1039973.668 units remaining) + [ (Pair 10 -3) @parameter + (Pair 10 -3) @parameter + (Some (Pair 3 1)) ] + - location: 35 (remaining gas: 1039973.658 units remaining) + [ 10 + -3 + (Pair 10 -3) @parameter + (Some (Pair 3 1)) ] + - location: 36 (remaining gas: 1039973.633 units remaining) + [ 10 + -3 + (Pair 10 -3) @parameter + (Some (Pair 3 1)) ] + - location: 37 (remaining gas: 1039973.523 units remaining) + [ (Some (Pair -3 1)) + (Pair 10 -3) @parameter + (Some (Pair 3 1)) ] + - location: 38 (remaining gas: 1039973.513 units remaining) + [ (Pair 10 -3) @parameter + (Some (Pair -3 1)) + (Some (Pair 3 1)) ] + - location: 39 (remaining gas: 1039973.503 units remaining) + [ (Pair 10 -3) @parameter + (Pair 10 -3) @parameter + (Some (Pair -3 1)) + (Some (Pair 3 1)) ] + - location: 40 (remaining gas: 1039973.493 units remaining) + [ 10 + -3 + (Pair 10 -3) @parameter + (Some (Pair -3 1)) + (Some (Pair 3 1)) ] + - location: 41 (remaining gas: 1039973.478 units remaining) + [ -3 + (Pair 10 -3) @parameter + (Some (Pair -3 1)) + (Some (Pair 3 1)) ] + - location: 43 (remaining gas: 1039973.453 units remaining) + [ 3 + (Pair 10 -3) @parameter + (Some (Pair -3 1)) + (Some (Pair 3 1)) ] + - location: 41 (remaining gas: 1039973.423 units remaining) + [ 10 + 3 + (Pair 10 -3) @parameter + (Some (Pair -3 1)) + (Some (Pair 3 1)) ] + - location: 44 (remaining gas: 1039973.313 units remaining) + [ (Some (Pair 3 1)) + (Pair 10 -3) @parameter + (Some (Pair -3 1)) + (Some (Pair 3 1)) ] + - location: 45 (remaining gas: 1039973.303 units remaining) + [ (Pair 10 -3) @parameter + (Some (Pair 3 1)) + (Some (Pair -3 1)) + (Some (Pair 3 1)) ] + - location: 46 (remaining gas: 1039973.293 units remaining) + [ 10 + -3 + (Some (Pair 3 1)) + (Some (Pair -3 1)) + (Some (Pair 3 1)) ] + - location: 47 (remaining gas: 1039973.183 units remaining) + [ (Some (Pair -3 1)) + (Some (Pair 3 1)) + (Some (Pair -3 1)) + (Some (Pair 3 1)) ] + - location: 49 (remaining gas: 1039973.160 units remaining) + [ (Some (Pair -3 1)) + (Some (Pair 3 1)) ] + - location: 52 (remaining gas: 1039973.145 units remaining) + [ (Pair (Some (Pair -3 1)) (Some (Pair 3 1))) ] + - location: 49 (remaining gas: 1039973.120 units remaining) + [ (Some (Pair 3 1)) + (Pair (Some (Pair -3 1)) (Some (Pair 3 1))) ] + - location: 49 (remaining gas: 1039973.110 units remaining) + [ (Some (Pair -3 1)) + (Some (Pair 3 1)) + (Pair (Some (Pair -3 1)) (Some (Pair 3 1))) ] + - location: 49 (remaining gas: 1039973.110 units remaining) + [ (Some (Pair -3 1)) + (Some (Pair 3 1)) + (Pair (Some (Pair -3 1)) (Some (Pair 3 1))) ] + - location: 53 (remaining gas: 1039973.095 units remaining) + [ (Some (Pair 3 1)) + (Pair (Some (Pair -3 1)) (Some (Pair 3 1))) ] + - location: 55 (remaining gas: 1039973.080 units remaining) + [ (Pair (Some (Pair 3 1)) (Some (Pair -3 1)) (Some (Pair 3 1))) ] + - location: 53 (remaining gas: 1039973.050 units remaining) + [ (Some (Pair -3 1)) + (Pair (Some (Pair 3 1)) (Some (Pair -3 1)) (Some (Pair 3 1))) ] + - location: 56 (remaining gas: 1039973.035 units remaining) + [ (Pair (Some (Pair -3 1)) (Some (Pair 3 1)) (Some (Pair -3 1)) (Some (Pair 3 1))) ] + - location: 57 (remaining gas: 1039973.020 units remaining) + [ {} + (Pair (Some (Pair -3 1)) (Some (Pair 3 1)) (Some (Pair -3 1)) (Some (Pair 3 1))) ] + - location: 59 (remaining gas: 1039973.005 units remaining) + [ (Pair {} (Some (Pair -3 1)) (Some (Pair 3 1)) (Some (Pair -3 1)) (Some (Pair 3 1))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair 10 0)-(Pair No.f9448c04fb.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair 10 0)-(Pair No.f9448c04fb.out new file mode 100644 index 000000000000..14ba161316ea --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair 10 0)-(Pair No.f9448c04fb.out @@ -0,0 +1,142 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[ediv.tz-(Pair None None None None)-(Pair 10 0)-(Pair None None None None)] + +storage + (Pair None None None None) +emitted operations + +big_map diff + +trace + - location: 25 (remaining gas: 1039973.923 units remaining) + [ (Pair (Pair 10 0) None None None None) ] + - location: 25 (remaining gas: 1039973.913 units remaining) + [ (Pair 10 0) @parameter ] + - location: 26 (remaining gas: 1039973.903 units remaining) + [ (Pair 10 0) @parameter + (Pair 10 0) @parameter ] + - location: 27 (remaining gas: 1039973.893 units remaining) + [ 10 + 0 + (Pair 10 0) @parameter ] + - location: 28 (remaining gas: 1039973.868 units remaining) + [ 10 + 0 + (Pair 10 0) @parameter ] + - location: 29 (remaining gas: 1039973.853 units remaining) + [ 0 + (Pair 10 0) @parameter ] + - location: 31 (remaining gas: 1039973.828 units remaining) + [ 0 + (Pair 10 0) @parameter ] + - location: 29 (remaining gas: 1039973.798 units remaining) + [ 10 + 0 + (Pair 10 0) @parameter ] + - location: 32 (remaining gas: 1039973.688 units remaining) + [ None + (Pair 10 0) @parameter ] + - location: 33 (remaining gas: 1039973.678 units remaining) + [ (Pair 10 0) @parameter + None ] + - location: 34 (remaining gas: 1039973.668 units remaining) + [ (Pair 10 0) @parameter + (Pair 10 0) @parameter + None ] + - location: 35 (remaining gas: 1039973.658 units remaining) + [ 10 + 0 + (Pair 10 0) @parameter + None ] + - location: 36 (remaining gas: 1039973.633 units remaining) + [ 10 + 0 + (Pair 10 0) @parameter + None ] + - location: 37 (remaining gas: 1039973.523 units remaining) + [ None + (Pair 10 0) @parameter + None ] + - location: 38 (remaining gas: 1039973.513 units remaining) + [ (Pair 10 0) @parameter + None + None ] + - location: 39 (remaining gas: 1039973.503 units remaining) + [ (Pair 10 0) @parameter + (Pair 10 0) @parameter + None + None ] + - location: 40 (remaining gas: 1039973.493 units remaining) + [ 10 + 0 + (Pair 10 0) @parameter + None + None ] + - location: 41 (remaining gas: 1039973.478 units remaining) + [ 0 + (Pair 10 0) @parameter + None + None ] + - location: 43 (remaining gas: 1039973.453 units remaining) + [ 0 + (Pair 10 0) @parameter + None + None ] + - location: 41 (remaining gas: 1039973.423 units remaining) + [ 10 + 0 + (Pair 10 0) @parameter + None + None ] + - location: 44 (remaining gas: 1039973.313 units remaining) + [ None + (Pair 10 0) @parameter + None + None ] + - location: 45 (remaining gas: 1039973.303 units remaining) + [ (Pair 10 0) @parameter + None + None + None ] + - location: 46 (remaining gas: 1039973.293 units remaining) + [ 10 + 0 + None + None + None ] + - location: 47 (remaining gas: 1039973.183 units remaining) + [ None + None + None + None ] + - location: 49 (remaining gas: 1039973.160 units remaining) + [ None + None ] + - location: 52 (remaining gas: 1039973.145 units remaining) + [ (Pair None None) ] + - location: 49 (remaining gas: 1039973.120 units remaining) + [ None + (Pair None None) ] + - location: 49 (remaining gas: 1039973.110 units remaining) + [ None + None + (Pair None None) ] + - location: 49 (remaining gas: 1039973.110 units remaining) + [ None + None + (Pair None None) ] + - location: 53 (remaining gas: 1039973.095 units remaining) + [ None + (Pair None None) ] + - location: 55 (remaining gas: 1039973.080 units remaining) + [ (Pair None None None) ] + - location: 53 (remaining gas: 1039973.050 units remaining) + [ None + (Pair None None None) ] + - location: 56 (remaining gas: 1039973.035 units remaining) + [ (Pair None None None None) ] + - location: 57 (remaining gas: 1039973.020 units remaining) + [ {} + (Pair None None None None) ] + - location: 59 (remaining gas: 1039973.005 units remaining) + [ (Pair {} None None None None) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 0))-(Left None)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 0))-(Left None)].out new file mode 100644 index 000000000000..04f732c013ff --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 0))-(Left None)].out @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 0))-(Left None)] + +storage + (Left None) +emitted operations + +big_map diff + +trace + - location: 19 (remaining gas: 1039985.681 units remaining) + [ (Pair (Pair 10 (Left 0)) (Left None)) ] + - location: 19 (remaining gas: 1039985.671 units remaining) + [ (Pair 10 (Left 0)) @parameter ] + - location: 20 (remaining gas: 1039985.661 units remaining) + [ 10 + (Left 0) ] + - location: 21 (remaining gas: 1039985.651 units remaining) + [ (Left 0) + 10 ] + - location: 22 (remaining gas: 1039985.641 units remaining) + [ 0 + 10 ] + - location: 24 (remaining gas: 1039985.631 units remaining) + [ 10 + 0 ] + - location: 25 (remaining gas: 1039985.566 units remaining) + [ None ] + - location: 26 (remaining gas: 1039985.551 units remaining) + [ (Left None) ] + - location: 22 (remaining gas: 1039985.536 units remaining) + [ (Left None) ] + - location: 39 (remaining gas: 1039985.521 units remaining) + [ {} + (Left None) ] + - location: 41 (remaining gas: 1039985.506 units remaining) + [ (Pair {} (Left None)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 10))-(Left (So.f782cc1dec.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 10))-(Left (So.f782cc1dec.out new file mode 100644 index 000000000000..3a65b14bf42c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 10))-(Left (So.f782cc1dec.out @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 10))-(Left (Some (Pair 1 0)))] + +storage + (Left (Some (Pair 1 0))) +emitted operations + +big_map diff + +trace + - location: 19 (remaining gas: 1039985.681 units remaining) + [ (Pair (Pair 10 (Left 10)) (Left None)) ] + - location: 19 (remaining gas: 1039985.671 units remaining) + [ (Pair 10 (Left 10)) @parameter ] + - location: 20 (remaining gas: 1039985.661 units remaining) + [ 10 + (Left 10) ] + - location: 21 (remaining gas: 1039985.651 units remaining) + [ (Left 10) + 10 ] + - location: 22 (remaining gas: 1039985.641 units remaining) + [ 10 + 10 ] + - location: 24 (remaining gas: 1039985.631 units remaining) + [ 10 + 10 ] + - location: 25 (remaining gas: 1039985.566 units remaining) + [ (Some (Pair 1 0)) ] + - location: 26 (remaining gas: 1039985.551 units remaining) + [ (Left (Some (Pair 1 0))) ] + - location: 22 (remaining gas: 1039985.536 units remaining) + [ (Left (Some (Pair 1 0))) ] + - location: 39 (remaining gas: 1039985.521 units remaining) + [ {} + (Left (Some (Pair 1 0))) ] + - location: 41 (remaining gas: 1039985.506 units remaining) + [ (Pair {} (Left (Some (Pair 1 0)))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 3))-(Left (Som.016b4db96c.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 3))-(Left (Som.016b4db96c.out new file mode 100644 index 000000000000..fafcbfe51bf1 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 3))-(Left (Som.016b4db96c.out @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Left 3))-(Left (Some (Pair 3 1)))] + +storage + (Left (Some (Pair 3 1))) +emitted operations + +big_map diff + +trace + - location: 19 (remaining gas: 1039985.681 units remaining) + [ (Pair (Pair 10 (Left 3)) (Left None)) ] + - location: 19 (remaining gas: 1039985.671 units remaining) + [ (Pair 10 (Left 3)) @parameter ] + - location: 20 (remaining gas: 1039985.661 units remaining) + [ 10 + (Left 3) ] + - location: 21 (remaining gas: 1039985.651 units remaining) + [ (Left 3) + 10 ] + - location: 22 (remaining gas: 1039985.641 units remaining) + [ 3 + 10 ] + - location: 24 (remaining gas: 1039985.631 units remaining) + [ 10 + 3 ] + - location: 25 (remaining gas: 1039985.566 units remaining) + [ (Some (Pair 3 1)) ] + - location: 26 (remaining gas: 1039985.551 units remaining) + [ (Left (Some (Pair 3 1))) ] + - location: 22 (remaining gas: 1039985.536 units remaining) + [ (Left (Some (Pair 3 1))) ] + - location: 39 (remaining gas: 1039985.521 units remaining) + [ {} + (Left (Some (Pair 3 1))) ] + - location: 41 (remaining gas: 1039985.506 units remaining) + [ (Pair {} (Left (Some (Pair 3 1)))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 0))-(Right None)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 0))-(Right None)].out new file mode 100644 index 000000000000..570364ab8807 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 0))-(Right None)].out @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 0))-(Right None)] + +storage + (Right None) +emitted operations + +big_map diff + +trace + - location: 19 (remaining gas: 1039985.681 units remaining) + [ (Pair (Pair 10 (Right 0)) (Left None)) ] + - location: 19 (remaining gas: 1039985.671 units remaining) + [ (Pair 10 (Right 0)) @parameter ] + - location: 20 (remaining gas: 1039985.661 units remaining) + [ 10 + (Right 0) ] + - location: 21 (remaining gas: 1039985.651 units remaining) + [ (Right 0) + 10 ] + - location: 22 (remaining gas: 1039985.641 units remaining) + [ 0 + 10 ] + - location: 32 (remaining gas: 1039985.631 units remaining) + [ 10 + 0 ] + - location: 33 (remaining gas: 1039985.561 units remaining) + [ None ] + - location: 34 (remaining gas: 1039985.546 units remaining) + [ (Right None) ] + - location: 22 (remaining gas: 1039985.531 units remaining) + [ (Right None) ] + - location: 39 (remaining gas: 1039985.516 units remaining) + [ {} + (Right None) ] + - location: 41 (remaining gas: 1039985.501 units remaining) + [ (Pair {} (Right None)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 10))-(Right (.e705a30e07.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 10))-(Right (.e705a30e07.out new file mode 100644 index 000000000000..0b8549166657 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 10))-(Right (.e705a30e07.out @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 10))-(Right (Some (Pair 1 0)))] + +storage + (Right (Some (Pair 1 0))) +emitted operations + +big_map diff + +trace + - location: 19 (remaining gas: 1039985.681 units remaining) + [ (Pair (Pair 10 (Right 10)) (Left None)) ] + - location: 19 (remaining gas: 1039985.671 units remaining) + [ (Pair 10 (Right 10)) @parameter ] + - location: 20 (remaining gas: 1039985.661 units remaining) + [ 10 + (Right 10) ] + - location: 21 (remaining gas: 1039985.651 units remaining) + [ (Right 10) + 10 ] + - location: 22 (remaining gas: 1039985.641 units remaining) + [ 10 + 10 ] + - location: 32 (remaining gas: 1039985.631 units remaining) + [ 10 + 10 ] + - location: 33 (remaining gas: 1039985.561 units remaining) + [ (Some (Pair 1 0)) ] + - location: 34 (remaining gas: 1039985.546 units remaining) + [ (Right (Some (Pair 1 0))) ] + - location: 22 (remaining gas: 1039985.531 units remaining) + [ (Right (Some (Pair 1 0))) ] + - location: 39 (remaining gas: 1039985.516 units remaining) + [ {} + (Right (Some (Pair 1 0))) ] + - location: 41 (remaining gas: 1039985.501 units remaining) + [ (Pair {} (Right (Some (Pair 1 0)))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 3))-(Right (S.44485eda6a.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 3))-(Right (S.44485eda6a.out new file mode 100644 index 000000000000..0dce6d3a9a42 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 3))-(Right (S.44485eda6a.out @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 10 (Right 3))-(Right (Some (Pair 3 1)))] + +storage + (Right (Some (Pair 3 1))) +emitted operations + +big_map diff + +trace + - location: 19 (remaining gas: 1039985.681 units remaining) + [ (Pair (Pair 10 (Right 3)) (Left None)) ] + - location: 19 (remaining gas: 1039985.671 units remaining) + [ (Pair 10 (Right 3)) @parameter ] + - location: 20 (remaining gas: 1039985.661 units remaining) + [ 10 + (Right 3) ] + - location: 21 (remaining gas: 1039985.651 units remaining) + [ (Right 3) + 10 ] + - location: 22 (remaining gas: 1039985.641 units remaining) + [ 3 + 10 ] + - location: 32 (remaining gas: 1039985.631 units remaining) + [ 10 + 3 ] + - location: 33 (remaining gas: 1039985.561 units remaining) + [ (Some (Pair 3 1)) ] + - location: 34 (remaining gas: 1039985.546 units remaining) + [ (Right (Some (Pair 3 1))) ] + - location: 22 (remaining gas: 1039985.531 units remaining) + [ (Right (Some (Pair 3 1))) ] + - location: 39 (remaining gas: 1039985.516 units remaining) + [ {} + (Right (Some (Pair 3 1))) ] + - location: 41 (remaining gas: 1039985.501 units remaining) + [ (Pair {} (Right (Some (Pair 3 1)))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 5 (Right 10))-(Right (S.8ab987af15.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 5 (Right 10))-(Right (S.8ab987af15.out new file mode 100644 index 000000000000..bc34b3ab458f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 5 (Right 10))-(Right (S.8ab987af15.out @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[ediv_mutez.tz-(Left None)-(Pair 5 (Right 10))-(Right (Some (Pair 0 5)))] + +storage + (Right (Some (Pair 0 5))) +emitted operations + +big_map diff + +trace + - location: 19 (remaining gas: 1039985.681 units remaining) + [ (Pair (Pair 5 (Right 10)) (Left None)) ] + - location: 19 (remaining gas: 1039985.671 units remaining) + [ (Pair 5 (Right 10)) @parameter ] + - location: 20 (remaining gas: 1039985.661 units remaining) + [ 5 + (Right 10) ] + - location: 21 (remaining gas: 1039985.651 units remaining) + [ (Right 10) + 5 ] + - location: 22 (remaining gas: 1039985.641 units remaining) + [ 10 + 5 ] + - location: 32 (remaining gas: 1039985.631 units remaining) + [ 5 + 10 ] + - location: 33 (remaining gas: 1039985.561 units remaining) + [ (Some (Pair 0 5)) ] + - location: 34 (remaining gas: 1039985.546 units remaining) + [ (Right (Some (Pair 0 5))) ] + - location: 22 (remaining gas: 1039985.531 units remaining) + [ (Right (Some (Pair 0 5))) ] + - location: 39 (remaining gas: 1039985.516 units remaining) + [ {} + (Right (Some (Pair 0 5))) ] + - location: 41 (remaining gas: 1039985.501 units remaining) + [ (Pair {} (Right (Some (Pair 0 5)))) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[empty_map.tz-{}-Unit-{ Elt \"hello\" \"world\" }].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[empty_map.tz-{}-Unit-{ Elt \"hello\" \"world\" }].out" new file mode 100644 index 000000000000..41eaaaf65c78 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[empty_map.tz-{}-Unit-{ Elt \"hello\" \"world\" }].out" @@ -0,0 +1,33 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[empty_map.tz-{}-Unit-{ Elt "hello" "world" }] + +storage + { Elt "hello" "world" } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039991.411 units remaining) + [ (Pair Unit {}) ] + - location: 9 (remaining gas: 1039991.401 units remaining) + [ ] + - location: 10 (remaining gas: 1039991.246 units remaining) + [ {} ] + - location: 13 (remaining gas: 1039991.236 units remaining) + [ "world" + {} ] + - location: 16 (remaining gas: 1039991.221 units remaining) + [ (Some "world") + {} ] + - location: 17 (remaining gas: 1039991.211 units remaining) + [ "hello" + (Some "world") + {} ] + - location: 20 (remaining gas: 1039991.061 units remaining) + [ { Elt "hello" "world" } ] + - location: 21 (remaining gas: 1039991.046 units remaining) + [ {} + { Elt "hello" "world" } ] + - location: 23 (remaining gas: 1039991.031 units remaining) + [ (Pair {} { Elt "hello" "world" }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[exec_concat.tz-\"?\"-\"\"-\"_abc\"].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[exec_concat.tz-\"?\"-\"\"-\"_abc\"].out" new file mode 100644 index 000000000000..4e26c22834e8 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[exec_concat.tz-\"?\"-\"\"-\"_abc\"].out" @@ -0,0 +1,48 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[exec_concat.tz-"?"-""-"_abc"] + +storage + "_abc" +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039988.574 units remaining) + [ (Pair "" "?") ] + - location: 7 (remaining gas: 1039988.564 units remaining) + [ "" @parameter ] + - location: 8 (remaining gas: 1039988.554 units remaining) + [ { PUSH string "_abc" ; NIL string ; SWAP ; CONS ; SWAP ; CONS ; CONCAT } + "" @parameter ] + - location: 22 (remaining gas: 1039988.544 units remaining) + [ "" @parameter + { PUSH string "_abc" ; NIL string ; SWAP ; CONS ; SWAP ; CONS ; CONCAT } ] + - location: 12 (remaining gas: 1039988.534 units remaining) + [ "_abc" + "" @arg ] + - location: 15 (remaining gas: 1039988.519 units remaining) + [ {} + "_abc" + "" @arg ] + - location: 17 (remaining gas: 1039988.509 units remaining) + [ "_abc" + {} + "" @arg ] + - location: 18 (remaining gas: 1039988.494 units remaining) + [ { "_abc" } + "" @arg ] + - location: 19 (remaining gas: 1039988.484 units remaining) + [ "" @arg + { "_abc" } ] + - location: 20 (remaining gas: 1039988.469 units remaining) + [ { "" ; "_abc" } ] + - location: 21 (remaining gas: 1039988.349 units remaining) + [ "_abc" ] + - location: 23 (remaining gas: 1039988.319 units remaining) + [ "_abc" ] + - location: 24 (remaining gas: 1039988.304 units remaining) + [ {} + "_abc" ] + - location: 26 (remaining gas: 1039988.289 units remaining) + [ (Pair {} "_abc") ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[exec_concat.tz-\"?\"-\"test\"-\"test_abc\"].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[exec_concat.tz-\"?\"-\"test\"-\"test_abc\"].out" new file mode 100644 index 000000000000..36bdb8ec1f5f --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[exec_concat.tz-\"?\"-\"test\"-\"test_abc\"].out" @@ -0,0 +1,48 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[exec_concat.tz-"?"-"test"-"test_abc"] + +storage + "test_abc" +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039988.534 units remaining) + [ (Pair "test" "?") ] + - location: 7 (remaining gas: 1039988.524 units remaining) + [ "test" @parameter ] + - location: 8 (remaining gas: 1039988.514 units remaining) + [ { PUSH string "_abc" ; NIL string ; SWAP ; CONS ; SWAP ; CONS ; CONCAT } + "test" @parameter ] + - location: 22 (remaining gas: 1039988.504 units remaining) + [ "test" @parameter + { PUSH string "_abc" ; NIL string ; SWAP ; CONS ; SWAP ; CONS ; CONCAT } ] + - location: 12 (remaining gas: 1039988.494 units remaining) + [ "_abc" + "test" @arg ] + - location: 15 (remaining gas: 1039988.479 units remaining) + [ {} + "_abc" + "test" @arg ] + - location: 17 (remaining gas: 1039988.469 units remaining) + [ "_abc" + {} + "test" @arg ] + - location: 18 (remaining gas: 1039988.454 units remaining) + [ { "_abc" } + "test" @arg ] + - location: 19 (remaining gas: 1039988.444 units remaining) + [ "test" @arg + { "_abc" } ] + - location: 20 (remaining gas: 1039988.429 units remaining) + [ { "test" ; "_abc" } ] + - location: 21 (remaining gas: 1039988.309 units remaining) + [ "test_abc" ] + - location: 23 (remaining gas: 1039988.279 units remaining) + [ "test_abc" ] + - location: 24 (remaining gas: 1039988.264 units remaining) + [ {} + "test_abc" ] + - location: 26 (remaining gas: 1039988.249 units remaining) + [ (Pair {} "test_abc") ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[first.tz-111-{ 1 ; 2 ; 3 ; 4 }-1].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[first.tz-111-{ 1 ; 2 ; 3 ; 4 }-1].out new file mode 100644 index 000000000000..6446bf5c56cd --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[first.tz-111-{ 1 ; 2 ; 3 ; 4 }-1].out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[first.tz-111-{ 1 ; 2 ; 3 ; 4 }-1] + +storage + 1 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039991.753 units remaining) + [ (Pair { 1 ; 2 ; 3 ; 4 } 111) ] + - location: 8 (remaining gas: 1039991.743 units remaining) + [ { 1 ; 2 ; 3 ; 4 } @parameter ] + - location: 9 (remaining gas: 1039991.733 units remaining) + [ 1 @parameter.hd + { 2 ; 3 ; 4 } @parameter.tl ] + - location: 11 (remaining gas: 1039991.718 units remaining) + [ { 2 ; 3 ; 4 } @parameter.tl ] + - location: 13 (remaining gas: 1039991.708 units remaining) + [ ] + - location: 11 (remaining gas: 1039991.678 units remaining) + [ 1 @parameter.hd ] + - location: 9 (remaining gas: 1039991.663 units remaining) + [ 1 @parameter.hd ] + - location: 18 (remaining gas: 1039991.648 units remaining) + [ {} + 1 @parameter.hd ] + - location: 20 (remaining gas: 1039991.633 units remaining) + [ (Pair {} 1) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[first.tz-111-{ 4 }-4].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[first.tz-111-{ 4 }-4].out new file mode 100644 index 000000000000..be559c38deb5 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[first.tz-111-{ 4 }-4].out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[first.tz-111-{ 4 }-4] + +storage + 4 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039992.053 units remaining) + [ (Pair { 4 } 111) ] + - location: 8 (remaining gas: 1039992.043 units remaining) + [ { 4 } @parameter ] + - location: 9 (remaining gas: 1039992.033 units remaining) + [ 4 @parameter.hd + {} @parameter.tl ] + - location: 11 (remaining gas: 1039992.018 units remaining) + [ {} @parameter.tl ] + - location: 13 (remaining gas: 1039992.008 units remaining) + [ ] + - location: 11 (remaining gas: 1039991.978 units remaining) + [ 4 @parameter.hd ] + - location: 9 (remaining gas: 1039991.963 units remaining) + [ 4 @parameter.hd ] + - location: 18 (remaining gas: 1039991.948 units remaining) + [ {} + 4 @parameter.hd ] + - location: 20 (remaining gas: 1039991.933 units remaining) + [ (Pair {} 4) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 4) {})-\"hello\"-(Pair .161d86cef6.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 4) {})-\"hello\"-(Pair .161d86cef6.out" new file mode 100644 index 000000000000..f819c62c7224 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 4) {})-\"hello\"-(Pair .161d86cef6.out" @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 4) {})-"hello"-(Pair None { Elt "hello" 4 })] + +storage + (Pair None { Elt "hello" 4 }) +emitted operations + +big_map diff + +trace + - location: 13 (remaining gas: 1039991.726 units remaining) + [ (Pair "hello" (Some 4) {}) ] + - location: 13 (remaining gas: 1039991.716 units remaining) + [ "hello" @parameter + (Pair (Some 4) {}) @storage ] + - location: 14 (remaining gas: 1039991.701 units remaining) + [ (Pair (Some 4) {}) @storage ] + - location: 16 (remaining gas: 1039991.691 units remaining) + [ (Some 4) + {} ] + - location: 14 (remaining gas: 1039991.661 units remaining) + [ "hello" @parameter + (Some 4) + {} ] + - location: 17 (remaining gas: 1039991.476 units remaining) + [ None + { Elt "hello" 4 } ] + - location: 18 (remaining gas: 1039991.461 units remaining) + [ (Pair None { Elt "hello" 4 }) ] + - location: 19 (remaining gas: 1039991.446 units remaining) + [ {} + (Pair None { Elt "hello" 4 }) ] + - location: 21 (remaining gas: 1039991.431 units remaining) + [ (Pair {} None { Elt "hello" 4 }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 5) { Elt \"hello\" 4 }).684ab7e326.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 5) { Elt \"hello\" 4 }).684ab7e326.out" new file mode 100644 index 000000000000..32f834c95b90 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 5) { Elt \"hello\" 4 }).684ab7e326.out" @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 5) { Elt "hello" 4 })-"hi"-(Pair None { Elt "hello" 4 ; Elt "hi" 5 })] + +storage + (Pair None { Elt "hello" 4 ; Elt "hi" 5 }) +emitted operations + +big_map diff + +trace + - location: 13 (remaining gas: 1039991.342 units remaining) + [ (Pair "hi" (Some 5) { Elt "hello" 4 }) ] + - location: 13 (remaining gas: 1039991.332 units remaining) + [ "hi" @parameter + (Pair (Some 5) { Elt "hello" 4 }) @storage ] + - location: 14 (remaining gas: 1039991.317 units remaining) + [ (Pair (Some 5) { Elt "hello" 4 }) @storage ] + - location: 16 (remaining gas: 1039991.307 units remaining) + [ (Some 5) + { Elt "hello" 4 } ] + - location: 14 (remaining gas: 1039991.277 units remaining) + [ "hi" @parameter + (Some 5) + { Elt "hello" 4 } ] + - location: 17 (remaining gas: 1039990.987 units remaining) + [ None + { Elt "hello" 4 ; Elt "hi" 5 } ] + - location: 18 (remaining gas: 1039990.972 units remaining) + [ (Pair None { Elt "hello" 4 ; Elt "hi" 5 }) ] + - location: 19 (remaining gas: 1039990.957 units remaining) + [ {} + (Pair None { Elt "hello" 4 ; Elt "hi" 5 }) ] + - location: 21 (remaining gas: 1039990.942 units remaining) + [ (Pair {} None { Elt "hello" 4 ; Elt "hi" 5 }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 5) { Elt \"hello\" 4 }).d49817fb83.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 5) { Elt \"hello\" 4 }).d49817fb83.out" new file mode 100644 index 000000000000..7cea33573000 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 5) { Elt \"hello\" 4 }).d49817fb83.out" @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair (Some 5) { Elt "hello" 4 })-"hello"-(Pair (Some 4) { Elt "hello" 5 })] + +storage + (Pair (Some 4) { Elt "hello" 5 }) +emitted operations + +big_map diff + +trace + - location: 13 (remaining gas: 1039991.312 units remaining) + [ (Pair "hello" (Some 5) { Elt "hello" 4 }) ] + - location: 13 (remaining gas: 1039991.302 units remaining) + [ "hello" @parameter + (Pair (Some 5) { Elt "hello" 4 }) @storage ] + - location: 14 (remaining gas: 1039991.287 units remaining) + [ (Pair (Some 5) { Elt "hello" 4 }) @storage ] + - location: 16 (remaining gas: 1039991.277 units remaining) + [ (Some 5) + { Elt "hello" 4 } ] + - location: 14 (remaining gas: 1039991.247 units remaining) + [ "hello" @parameter + (Some 5) + { Elt "hello" 4 } ] + - location: 17 (remaining gas: 1039990.957 units remaining) + [ (Some 4) + { Elt "hello" 5 } ] + - location: 18 (remaining gas: 1039990.942 units remaining) + [ (Pair (Some 4) { Elt "hello" 5 }) ] + - location: 19 (remaining gas: 1039990.927 units remaining) + [ {} + (Pair (Some 4) { Elt "hello" 5 }) ] + - location: 21 (remaining gas: 1039990.912 units remaining) + [ (Pair {} (Some 4) { Elt "hello" 5 }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt \"1\" 1 ; .6900b1da14.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt \"1\" 1 ; .6900b1da14.out" new file mode 100644 index 000000000000..e5e5b543e1ba --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt \"1\" 1 ; .6900b1da14.out" @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt "1" 1 ; Elt "2" 2 })-"1"-(Pair (Some 1) { Elt "2" 2 })1] + +storage + (Pair (Some 1) { Elt "2" 2 }) +emitted operations + +big_map diff + +trace + - location: 13 (remaining gas: 1039991.013 units remaining) + [ (Pair "1" None { Elt "1" 1 ; Elt "2" 2 }) ] + - location: 13 (remaining gas: 1039991.003 units remaining) + [ "1" @parameter + (Pair None { Elt "1" 1 ; Elt "2" 2 }) @storage ] + - location: 14 (remaining gas: 1039990.988 units remaining) + [ (Pair None { Elt "1" 1 ; Elt "2" 2 }) @storage ] + - location: 16 (remaining gas: 1039990.978 units remaining) + [ None + { Elt "1" 1 ; Elt "2" 2 } ] + - location: 14 (remaining gas: 1039990.948 units remaining) + [ "1" @parameter + None + { Elt "1" 1 ; Elt "2" 2 } ] + - location: 17 (remaining gas: 1039990.553 units remaining) + [ (Some 1) + { Elt "2" 2 } ] + - location: 18 (remaining gas: 1039990.538 units remaining) + [ (Pair (Some 1) { Elt "2" 2 }) ] + - location: 19 (remaining gas: 1039990.523 units remaining) + [ {} + (Pair (Some 1) { Elt "2" 2 }) ] + - location: 21 (remaining gas: 1039990.508 units remaining) + [ (Pair {} (Some 1) { Elt "2" 2 }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt \"1\" 1 ; .bca0ede8be.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt \"1\" 1 ; .bca0ede8be.out" new file mode 100644 index 000000000000..c295784192de --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt \"1\" 1 ; .bca0ede8be.out" @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt "1" 1 ; Elt "2" 2 })-"1"-(Pair (Some 1) { Elt "2" 2 })0] + +storage + (Pair (Some 1) { Elt "2" 2 }) +emitted operations + +big_map diff + +trace + - location: 13 (remaining gas: 1039991.013 units remaining) + [ (Pair "1" None { Elt "1" 1 ; Elt "2" 2 }) ] + - location: 13 (remaining gas: 1039991.003 units remaining) + [ "1" @parameter + (Pair None { Elt "1" 1 ; Elt "2" 2 }) @storage ] + - location: 14 (remaining gas: 1039990.988 units remaining) + [ (Pair None { Elt "1" 1 ; Elt "2" 2 }) @storage ] + - location: 16 (remaining gas: 1039990.978 units remaining) + [ None + { Elt "1" 1 ; Elt "2" 2 } ] + - location: 14 (remaining gas: 1039990.948 units remaining) + [ "1" @parameter + None + { Elt "1" 1 ; Elt "2" 2 } ] + - location: 17 (remaining gas: 1039990.553 units remaining) + [ (Some 1) + { Elt "2" 2 } ] + - location: 18 (remaining gas: 1039990.538 units remaining) + [ (Pair (Some 1) { Elt "2" 2 }) ] + - location: 19 (remaining gas: 1039990.523 units remaining) + [ {} + (Pair (Some 1) { Elt "2" 2 }) ] + - location: 21 (remaining gas: 1039990.508 units remaining) + [ (Pair {} (Some 1) { Elt "2" 2 }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt \"hello\" 4 })-\"he.c1b4e1d6dc.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt \"hello\" 4 })-\"he.c1b4e1d6dc.out" new file mode 100644 index 000000000000..e748cd24630d --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt \"hello\" 4 })-\"he.c1b4e1d6dc.out" @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None { Elt "hello" 4 })-"hello"-(Pair (Some 4) {})] + +storage + (Pair (Some 4) {}) +emitted operations + +big_map diff + +trace + - location: 13 (remaining gas: 1039991.412 units remaining) + [ (Pair "hello" None { Elt "hello" 4 }) ] + - location: 13 (remaining gas: 1039991.402 units remaining) + [ "hello" @parameter + (Pair None { Elt "hello" 4 }) @storage ] + - location: 14 (remaining gas: 1039991.387 units remaining) + [ (Pair None { Elt "hello" 4 }) @storage ] + - location: 16 (remaining gas: 1039991.377 units remaining) + [ None + { Elt "hello" 4 } ] + - location: 14 (remaining gas: 1039991.347 units remaining) + [ "hello" @parameter + None + { Elt "hello" 4 } ] + - location: 17 (remaining gas: 1039991.057 units remaining) + [ (Some 4) + {} ] + - location: 18 (remaining gas: 1039991.042 units remaining) + [ (Pair (Some 4) {}) ] + - location: 19 (remaining gas: 1039991.027 units remaining) + [ {} + (Pair (Some 4) {}) ] + - location: 21 (remaining gas: 1039991.012 units remaining) + [ (Pair {} (Some 4) {}) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None {})-\"hello\"-(Pair None {})].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None {})-\"hello\"-(Pair None {})].out" new file mode 100644 index 000000000000..fa454fe351f2 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None {})-\"hello\"-(Pair None {})].out" @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[get_and_update_map.tz-(Pair None {})-"hello"-(Pair None {})] + +storage + (Pair None {}) +emitted operations + +big_map diff + +trace + - location: 13 (remaining gas: 1039991.826 units remaining) + [ (Pair "hello" None {}) ] + - location: 13 (remaining gas: 1039991.816 units remaining) + [ "hello" @parameter + (Pair None {}) @storage ] + - location: 14 (remaining gas: 1039991.801 units remaining) + [ (Pair None {}) @storage ] + - location: 16 (remaining gas: 1039991.791 units remaining) + [ None + {} ] + - location: 14 (remaining gas: 1039991.761 units remaining) + [ "hello" @parameter + None + {} ] + - location: 17 (remaining gas: 1039991.576 units remaining) + [ None + {} ] + - location: 18 (remaining gas: 1039991.561 units remaining) + [ (Pair None {}) ] + - location: 19 (remaining gas: 1039991.546 units remaining) + [ {} + (Pair None {}) ] + - location: 21 (remaining gas: 1039991.531 units remaining) + [ (Pair {} None {}) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt \"1\" \"one\" ; .bc4127094e.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt \"1\" \"one\" ; .bc4127094e.out" new file mode 100644 index 000000000000..2d4d59fdbcc0 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt \"1\" \"one\" ; .bc4127094e.out" @@ -0,0 +1,41 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt "1" "one" ; Elt "2" "two" })-"1"-(Pair (Some "one") { Elt "1" "one" ; Elt "2" "two" })] + +storage + (Pair (Some "one") { Elt "1" "one" ; Elt "2" "two" }) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039988.347 units remaining) + [ (Pair "1" None { Elt "1" "one" ; Elt "2" "two" }) ] + - location: 12 (remaining gas: 1039988.337 units remaining) + [ (Pair "1" None { Elt "1" "one" ; Elt "2" "two" }) + (Pair "1" None { Elt "1" "one" ; Elt "2" "two" }) ] + - location: 13 (remaining gas: 1039988.327 units remaining) + [ "1" @parameter + (Pair "1" None { Elt "1" "one" ; Elt "2" "two" }) ] + - location: 14 (remaining gas: 1039988.312 units remaining) + [ (Pair "1" None { Elt "1" "one" ; Elt "2" "two" }) ] + - location: 17 (remaining gas: 1039988.302 units remaining) + [ (Pair None { Elt "1" "one" ; Elt "2" "two" }) @storage ] + - location: 18 (remaining gas: 1039988.292 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } ] + - location: 19 (remaining gas: 1039988.282 units remaining) + [ { Elt "1" "one" ; Elt "2" "two" } + { Elt "1" "one" ; Elt "2" "two" } ] + - location: 14 (remaining gas: 1039988.252 units remaining) + [ "1" @parameter + { Elt "1" "one" ; Elt "2" "two" } + { Elt "1" "one" ; Elt "2" "two" } ] + - location: 20 (remaining gas: 1039988.067 units remaining) + [ (Some "one") + { Elt "1" "one" ; Elt "2" "two" } ] + - location: 21 (remaining gas: 1039988.052 units remaining) + [ (Pair (Some "one") { Elt "1" "one" ; Elt "2" "two" }) ] + - location: 22 (remaining gas: 1039988.037 units remaining) + [ {} + (Pair (Some "one") { Elt "1" "one" ; Elt "2" "two" }) ] + - location: 24 (remaining gas: 1039988.022 units remaining) + [ (Pair {} (Some "one") { Elt "1" "one" ; Elt "2" "two" }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt \"hello\" \"hi\" })-\"\"-(P.0c03056487.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt \"hello\" \"hi\" })-\"\"-(P.0c03056487.out" new file mode 100644 index 000000000000..b341b5ae423b --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt \"hello\" \"hi\" })-\"\"-(P.0c03056487.out" @@ -0,0 +1,41 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt "hello" "hi" })-""-(Pair None { Elt "hello" "hi" })] + +storage + (Pair None { Elt "hello" "hi" }) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039988.850 units remaining) + [ (Pair "" None { Elt "hello" "hi" }) ] + - location: 12 (remaining gas: 1039988.840 units remaining) + [ (Pair "" None { Elt "hello" "hi" }) + (Pair "" None { Elt "hello" "hi" }) ] + - location: 13 (remaining gas: 1039988.830 units remaining) + [ "" @parameter + (Pair "" None { Elt "hello" "hi" }) ] + - location: 14 (remaining gas: 1039988.815 units remaining) + [ (Pair "" None { Elt "hello" "hi" }) ] + - location: 17 (remaining gas: 1039988.805 units remaining) + [ (Pair None { Elt "hello" "hi" }) @storage ] + - location: 18 (remaining gas: 1039988.795 units remaining) + [ { Elt "hello" "hi" } ] + - location: 19 (remaining gas: 1039988.785 units remaining) + [ { Elt "hello" "hi" } + { Elt "hello" "hi" } ] + - location: 14 (remaining gas: 1039988.755 units remaining) + [ "" @parameter + { Elt "hello" "hi" } + { Elt "hello" "hi" } ] + - location: 20 (remaining gas: 1039988.605 units remaining) + [ None + { Elt "hello" "hi" } ] + - location: 21 (remaining gas: 1039988.590 units remaining) + [ (Pair None { Elt "hello" "hi" }) ] + - location: 22 (remaining gas: 1039988.575 units remaining) + [ {} + (Pair None { Elt "hello" "hi" }) ] + - location: 24 (remaining gas: 1039988.560 units remaining) + [ (Pair {} None { Elt "hello" "hi" }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt \"hello\" \"hi\" })-\"hell.cc45544c66.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt \"hello\" \"hi\" })-\"hell.cc45544c66.out" new file mode 100644 index 000000000000..a622cf833484 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt \"hello\" \"hi\" })-\"hell.cc45544c66.out" @@ -0,0 +1,41 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[get_map_value.tz-(Pair None { Elt "hello" "hi" })-"hello"-(Pair (Some "hi") { Elt "hello" "hi" })] + +storage + (Pair (Some "hi") { Elt "hello" "hi" }) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039988.800 units remaining) + [ (Pair "hello" None { Elt "hello" "hi" }) ] + - location: 12 (remaining gas: 1039988.790 units remaining) + [ (Pair "hello" None { Elt "hello" "hi" }) + (Pair "hello" None { Elt "hello" "hi" }) ] + - location: 13 (remaining gas: 1039988.780 units remaining) + [ "hello" @parameter + (Pair "hello" None { Elt "hello" "hi" }) ] + - location: 14 (remaining gas: 1039988.765 units remaining) + [ (Pair "hello" None { Elt "hello" "hi" }) ] + - location: 17 (remaining gas: 1039988.755 units remaining) + [ (Pair None { Elt "hello" "hi" }) @storage ] + - location: 18 (remaining gas: 1039988.745 units remaining) + [ { Elt "hello" "hi" } ] + - location: 19 (remaining gas: 1039988.735 units remaining) + [ { Elt "hello" "hi" } + { Elt "hello" "hi" } ] + - location: 14 (remaining gas: 1039988.705 units remaining) + [ "hello" @parameter + { Elt "hello" "hi" } + { Elt "hello" "hi" } ] + - location: 20 (remaining gas: 1039988.555 units remaining) + [ (Some "hi") + { Elt "hello" "hi" } ] + - location: 21 (remaining gas: 1039988.540 units remaining) + [ (Pair (Some "hi") { Elt "hello" "hi" }) ] + - location: 22 (remaining gas: 1039988.525 units remaining) + [ {} + (Pair (Some "hi") { Elt "hello" "hi" }) ] + - location: 24 (remaining gas: 1039988.510 units remaining) + [ (Pair {} (Some "hi") { Elt "hello" "hi" }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_key.tz-None-\"edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAb.613ad6b637.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_key.tz-None-\"edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAb.613ad6b637.out" new file mode 100644 index 000000000000..820a0c7f12a0 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_key.tz-None-\"edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAb.613ad6b637.out" @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[hash_key.tz-None-"edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav"-(Some "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx")] + +storage + (Some "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx") +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039967.857 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" None) ] + - location: 8 (remaining gas: 1039967.847 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" @parameter ] + - location: 9 (remaining gas: 1039967.192 units remaining) + [ "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" ] + - location: 10 (remaining gas: 1039967.177 units remaining) + [ (Some "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx") ] + - location: 11 (remaining gas: 1039967.162 units remaining) + [ {} + (Some "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx") ] + - location: 13 (remaining gas: 1039967.147 units remaining) + [ (Pair {} (Some "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_key.tz-None-\"edpkuJqtDcA2m2muMxViSM47MPsGQzmyjnNTa.da50984e8d.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_key.tz-None-\"edpkuJqtDcA2m2muMxViSM47MPsGQzmyjnNTa.da50984e8d.out" new file mode 100644 index 000000000000..3d0fa4c3e2f5 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_key.tz-None-\"edpkuJqtDcA2m2muMxViSM47MPsGQzmyjnNTa.da50984e8d.out" @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[hash_key.tz-None-"edpkuJqtDcA2m2muMxViSM47MPsGQzmyjnNTawUPqR8vZTAMcx61ES"-(Some "tz1XPTDmvT3vVE5Uunngmixm7gj7zmdbPq6k")] + +storage + (Some "tz1XPTDmvT3vVE5Uunngmixm7gj7zmdbPq6k") +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039967.857 units remaining) + [ (Pair "edpkuJqtDcA2m2muMxViSM47MPsGQzmyjnNTawUPqR8vZTAMcx61ES" None) ] + - location: 8 (remaining gas: 1039967.847 units remaining) + [ "edpkuJqtDcA2m2muMxViSM47MPsGQzmyjnNTawUPqR8vZTAMcx61ES" @parameter ] + - location: 9 (remaining gas: 1039967.192 units remaining) + [ "tz1XPTDmvT3vVE5Uunngmixm7gj7zmdbPq6k" ] + - location: 10 (remaining gas: 1039967.177 units remaining) + [ (Some "tz1XPTDmvT3vVE5Uunngmixm7gj7zmdbPq6k") ] + - location: 11 (remaining gas: 1039967.162 units remaining) + [ {} + (Some "tz1XPTDmvT3vVE5Uunngmixm7gj7zmdbPq6k") ] + - location: 13 (remaining gas: 1039967.147 units remaining) + [ (Pair {} (Some "tz1XPTDmvT3vVE5Uunngmixm7gj7zmdbPq6k")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_string.tz-0x00-\"12345\"-0xb4c26c20de52a4eaf0d8a340d.2bba28b0bf.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_string.tz-0x00-\"12345\"-0xb4c26c20de52a4eaf0d8a340d.2bba28b0bf.out" new file mode 100644 index 000000000000..5403115ff4ca --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_string.tz-0x00-\"12345\"-0xb4c26c20de52a4eaf0d8a340d.2bba28b0bf.out" @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[hash_string.tz-0x00-"12345"-0xb4c26c20de52a4eaf0d8a340db47ad8cb1e74049570859c9a9a3952b204c772f] + +storage + 0xb4c26c20de52a4eaf0d8a340db47ad8cb1e74049570859c9a9a3952b204c772f +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039994.961 units remaining) + [ (Pair "12345" 0x00) ] + - location: 7 (remaining gas: 1039994.951 units remaining) + [ "12345" @parameter ] + - location: 8 (remaining gas: 1039994.162 units remaining) + [ 0x0501000000053132333435 @parameter.packed ] + - location: 9 (remaining gas: 1039993.545 units remaining) + [ 0xb4c26c20de52a4eaf0d8a340db47ad8cb1e74049570859c9a9a3952b204c772f ] + - location: 10 (remaining gas: 1039993.530 units remaining) + [ {} + 0xb4c26c20de52a4eaf0d8a340db47ad8cb1e74049570859c9a9a3952b204c772f ] + - location: 12 (remaining gas: 1039993.515 units remaining) + [ (Pair {} 0xb4c26c20de52a4eaf0d8a340db47ad8cb1e74049570859c9a9a3952b204c772f) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_string.tz-0x00-\"abcdefg\"-0x46fdbcb4ea4eadad5615cda.acc82cd954.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_string.tz-0x00-\"abcdefg\"-0x46fdbcb4ea4eadad5615cda.acc82cd954.out" new file mode 100644 index 000000000000..89a4f1d863c5 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[hash_string.tz-0x00-\"abcdefg\"-0x46fdbcb4ea4eadad5615cda.acc82cd954.out" @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[hash_string.tz-0x00-"abcdefg"-0x46fdbcb4ea4eadad5615cdaa17d67f783e01e21149ce2b27de497600b4cd8f4e] + +storage + 0x46fdbcb4ea4eadad5615cdaa17d67f783e01e21149ce2b27de497600b4cd8f4e +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039994.941 units remaining) + [ (Pair "abcdefg" 0x00) ] + - location: 7 (remaining gas: 1039994.931 units remaining) + [ "abcdefg" @parameter ] + - location: 8 (remaining gas: 1039994.010 units remaining) + [ 0x05010000000761626364656667 @parameter.packed ] + - location: 9 (remaining gas: 1039993.391 units remaining) + [ 0x46fdbcb4ea4eadad5615cdaa17d67f783e01e21149ce2b27de497600b4cd8f4e ] + - location: 10 (remaining gas: 1039993.376 units remaining) + [ {} + 0x46fdbcb4ea4eadad5615cdaa17d67f783e01e21149ce2b27de497600b4cd8f4e ] + - location: 12 (remaining gas: 1039993.361 units remaining) + [ (Pair {} 0x46fdbcb4ea4eadad5615cdaa17d67f783e01e21149ce2b27de497600b4cd8f4e) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if.tz-None-False-(Some False)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if.tz-None-False-(Some False)].out new file mode 100644 index 000000000000..7eecc0c552a0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if.tz-None-False-(Some False)].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[if.tz-None-False-(Some False)] + +storage + (Some False) +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039992.385 units remaining) + [ (Pair False None) ] + - location: 8 (remaining gas: 1039992.375 units remaining) + [ False @parameter ] + - location: 9 (remaining gas: 1039992.365 units remaining) + [ ] + - location: 15 (remaining gas: 1039992.355 units remaining) + [ False ] + - location: 9 (remaining gas: 1039992.340 units remaining) + [ False ] + - location: 18 (remaining gas: 1039992.325 units remaining) + [ (Some False) ] + - location: 19 (remaining gas: 1039992.310 units remaining) + [ {} + (Some False) ] + - location: 21 (remaining gas: 1039992.295 units remaining) + [ (Pair {} (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if.tz-None-True-(Some True)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if.tz-None-True-(Some True)].out new file mode 100644 index 000000000000..5fa78abf68cf --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if.tz-None-True-(Some True)].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[if.tz-None-True-(Some True)] + +storage + (Some True) +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039992.385 units remaining) + [ (Pair True None) ] + - location: 8 (remaining gas: 1039992.375 units remaining) + [ True @parameter ] + - location: 9 (remaining gas: 1039992.365 units remaining) + [ ] + - location: 11 (remaining gas: 1039992.355 units remaining) + [ True ] + - location: 9 (remaining gas: 1039992.340 units remaining) + [ True ] + - location: 18 (remaining gas: 1039992.325 units remaining) + [ (Some True) ] + - location: 19 (remaining gas: 1039992.310 units remaining) + [ {} + (Some True) ] + - location: 21 (remaining gas: 1039992.295 units remaining) + [ (Pair {} (Some True)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if_some.tz-\"?\"-(Some \"hello\")-\"hello\"].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if_some.tz-\"?\"-(Some \"hello\")-\"hello\"].out" new file mode 100644 index 000000000000..17c64a0ea3da --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if_some.tz-\"?\"-(Some \"hello\")-\"hello\"].out" @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[if_some.tz-"?"-(Some "hello")-"hello"] + +storage + "hello" +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039993.311 units remaining) + [ (Pair (Some "hello") "?") ] + - location: 8 (remaining gas: 1039993.301 units remaining) + [ (Some "hello") @parameter ] + - location: 10 (remaining gas: 1039993.291 units remaining) + [ "hello" ] + - location: 10 (remaining gas: 1039993.276 units remaining) + [ "hello" ] + - location: 16 (remaining gas: 1039993.261 units remaining) + [ {} + "hello" ] + - location: 18 (remaining gas: 1039993.246 units remaining) + [ (Pair {} "hello") ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if_some.tz-\"?\"-None-\"\"].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if_some.tz-\"?\"-None-\"\"].out" new file mode 100644 index 000000000000..de8b77186028 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[if_some.tz-\"?\"-None-\"\"].out" @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[if_some.tz-"?"-None-""] + +storage + "" +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039993.475 units remaining) + [ (Pair None "?") ] + - location: 8 (remaining gas: 1039993.465 units remaining) + [ None @parameter ] + - location: 10 (remaining gas: 1039993.455 units remaining) + [ ] + - location: 12 (remaining gas: 1039993.445 units remaining) + [ "" ] + - location: 10 (remaining gas: 1039993.430 units remaining) + [ "" ] + - location: 16 (remaining gas: 1039993.415 units remaining) + [ {} + "" ] + - location: 18 (remaining gas: 1039993.400 units remaining) + [ (Pair {} "") ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[int.tz-None-0-(Some 0)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[int.tz-None-0-(Some 0)].out new file mode 100644 index 000000000000..3e80ece1a0ee --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[int.tz-None-0-(Some 0)].out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[int.tz-None-0-(Some 0)] + +storage + (Some 0) +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.857 units remaining) + [ (Pair 0 None) ] + - location: 8 (remaining gas: 1039994.847 units remaining) + [ 0 @parameter ] + - location: 9 (remaining gas: 1039994.832 units remaining) + [ 0 ] + - location: 10 (remaining gas: 1039994.817 units remaining) + [ (Some 0) ] + - location: 11 (remaining gas: 1039994.802 units remaining) + [ {} + (Some 0) ] + - location: 13 (remaining gas: 1039994.787 units remaining) + [ (Pair {} (Some 0)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[int.tz-None-1-(Some 1)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[int.tz-None-1-(Some 1)].out new file mode 100644 index 000000000000..f8980a5ec426 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[int.tz-None-1-(Some 1)].out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[int.tz-None-1-(Some 1)] + +storage + (Some 1) +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.857 units remaining) + [ (Pair 1 None) ] + - location: 8 (remaining gas: 1039994.847 units remaining) + [ 1 @parameter ] + - location: 9 (remaining gas: 1039994.832 units remaining) + [ 1 ] + - location: 10 (remaining gas: 1039994.817 units remaining) + [ (Some 1) ] + - location: 11 (remaining gas: 1039994.802 units remaining) + [ {} + (Some 1) ] + - location: 13 (remaining gas: 1039994.787 units remaining) + [ (Pair {} (Some 1)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[int.tz-None-9999-(Some 9999)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[int.tz-None-9999-(Some 9999)].out new file mode 100644 index 000000000000..e9d8f02ef969 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[int.tz-None-9999-(Some 9999)].out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[int.tz-None-9999-(Some 9999)] + +storage + (Some 9999) +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.857 units remaining) + [ (Pair 9999 None) ] + - location: 8 (remaining gas: 1039994.847 units remaining) + [ 9999 @parameter ] + - location: 9 (remaining gas: 1039994.832 units remaining) + [ 9999 ] + - location: 10 (remaining gas: 1039994.817 units remaining) + [ (Some 9999) ] + - location: 11 (remaining gas: 1039994.802 units remaining) + [ {} + (Some 9999) ] + - location: 13 (remaining gas: 1039994.787 units remaining) + [ (Pair {} (Some 9999)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[keccak.tz-None-0x48656c6c6f2c20776f726c6421-(Some 0xb6e.34c02678c9.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[keccak.tz-None-0x48656c6c6f2c20776f726c6421-(Some 0xb6e.34c02678c9.out new file mode 100644 index 000000000000..6bab286f1e39 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[keccak.tz-None-0x48656c6c6f2c20776f726c6421-(Some 0xb6e.34c02678c9.out @@ -0,0 +1,24 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[keccak.tz-None-0x48656c6c6f2c20776f726c6421-(Some 0xb6e16d27ac5ab427a7f68900ac5559ce272dc6c37c82b3e052246c82244c50e4)] + +storage + (Some 0xb6e16d27ac5ab427a7f68900ac5559ce272dc6c37c82b3e052246c82244c50e4) +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.857 units remaining) + [ (Pair 0x48656c6c6f2c20776f726c6421 None) ] + - location: 8 (remaining gas: 1039994.847 units remaining) + [ 0x48656c6c6f2c20776f726c6421 @parameter ] + - location: 9 (remaining gas: 1039989.322 units remaining) + [ 0xb6e16d27ac5ab427a7f68900ac5559ce272dc6c37c82b3e052246c82244c50e4 ] + - location: 10 (remaining gas: 1039989.307 units remaining) + [ (Some 0xb6e16d27ac5ab427a7f68900ac5559ce272dc6c37c82b3e052246c82244c50e4) ] + - location: 11 (remaining gas: 1039989.292 units remaining) + [ {} + (Some 0xb6e16d27ac5ab427a7f68900ac5559ce272dc6c37c82b3e052246c82244c50e4) ] + - location: 13 (remaining gas: 1039989.277 units remaining) + [ (Pair {} + (Some 0xb6e16d27ac5ab427a7f68900ac5559ce272dc6c37c82b3e052246c82244c50e4)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[left_right.tz-(Left \"X\")-(Left True)-(Right True)].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[left_right.tz-(Left \"X\")-(Left True)-(Right True)].out" new file mode 100644 index 000000000000..7b69d76e7704 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[left_right.tz-(Left \"X\")-(Left True)-(Right True)].out" @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[left_right.tz-(Left "X")-(Left True)-(Right True)] + +storage + (Right True) +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039992.546 units remaining) + [ (Pair (Left True) (Left "X")) ] + - location: 11 (remaining gas: 1039992.536 units remaining) + [ (Left True) @parameter ] + - location: 12 (remaining gas: 1039992.526 units remaining) + [ True @parameter.left ] + - location: 14 (remaining gas: 1039992.511 units remaining) + [ (Right True) ] + - location: 12 (remaining gas: 1039992.496 units remaining) + [ (Right True) ] + - location: 19 (remaining gas: 1039992.481 units remaining) + [ {} + (Right True) ] + - location: 21 (remaining gas: 1039992.466 units remaining) + [ (Pair {} (Right True)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[left_right.tz-(Left \"X\")-(Right \"a\")-(Left \"a\")].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[left_right.tz-(Left \"X\")-(Right \"a\")-(Left \"a\")].out" new file mode 100644 index 000000000000..2c30c89ac5ee --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[left_right.tz-(Left \"X\")-(Right \"a\")-(Left \"a\")].out" @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[left_right.tz-(Left "X")-(Right "a")-(Left "a")] + +storage + (Left "a") +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039992.522 units remaining) + [ (Pair (Right "a") (Left "X")) ] + - location: 11 (remaining gas: 1039992.512 units remaining) + [ (Right "a") @parameter ] + - location: 12 (remaining gas: 1039992.502 units remaining) + [ "a" @parameter.right ] + - location: 17 (remaining gas: 1039992.487 units remaining) + [ (Left "a") ] + - location: 12 (remaining gas: 1039992.472 units remaining) + [ (Left "a") ] + - location: 19 (remaining gas: 1039992.457 units remaining) + [ {} + (Left "a") ] + - location: 21 (remaining gas: 1039992.442 units remaining) + [ (Pair {} (Left "a")) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[level.tz-111-Unit-1].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[level.tz-111-Unit-1].out new file mode 100644 index 000000000000..51bd08e1c5cc --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[level.tz-111-Unit-1].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[level.tz-111-Unit-1] + +storage + 1 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039995.668 units remaining) + [ (Pair Unit 111) ] + - location: 7 (remaining gas: 1039995.658 units remaining) + [ ] + - location: 8 (remaining gas: 1039995.633 units remaining) + [ 1 @level ] + - location: 9 (remaining gas: 1039995.618 units remaining) + [ {} + 1 @level ] + - location: 11 (remaining gas: 1039995.603 units remaining) + [ (Pair {} 1) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat.tz-\"abc\"-{ \"d\" ; \"e\" ; \"f\" }-\"abcdef\"].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat.tz-\"abc\"-{ \"d\" ; \"e\" ; \"f\" }-\"abcdef\"].out" new file mode 100644 index 000000000000..843f1d603aa2 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat.tz-\"abc\"-{ \"d\" ; \"e\" ; \"f\" }-\"abcdef\"].out" @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_concat.tz-"abc"-{ "d" ; "e" ; "f" }-"abcdef"] + +storage + "abcdef" +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039993.798 units remaining) + [ (Pair { "d" ; "e" ; "f" } "abc") ] + - location: 8 (remaining gas: 1039993.788 units remaining) + [ { "d" ; "e" ; "f" } @parameter + "abc" @storage ] + - location: 9 (remaining gas: 1039993.778 units remaining) + [ "abc" @storage + { "d" ; "e" ; "f" } @parameter ] + - location: 10 (remaining gas: 1039993.763 units remaining) + [ { "abc" ; "d" ; "e" ; "f" } ] + - location: 11 (remaining gas: 1039993.623 units remaining) + [ "abcdef" ] + - location: 12 (remaining gas: 1039993.608 units remaining) + [ {} + "abcdef" ] + - location: 14 (remaining gas: 1039993.593 units remaining) + [ (Pair {} "abcdef") ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat.tz-\"abc\"-{}-\"abc\"].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat.tz-\"abc\"-{}-\"abc\"].out" new file mode 100644 index 000000000000..7cee97207f7e --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat.tz-\"abc\"-{}-\"abc\"].out" @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_concat.tz-"abc"-{}-"abc"] + +storage + "abc" +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.170 units remaining) + [ (Pair {} "abc") ] + - location: 8 (remaining gas: 1039994.160 units remaining) + [ {} @parameter + "abc" @storage ] + - location: 9 (remaining gas: 1039994.150 units remaining) + [ "abc" @storage + {} @parameter ] + - location: 10 (remaining gas: 1039994.135 units remaining) + [ { "abc" } ] + - location: 11 (remaining gas: 1039994.025 units remaining) + [ "abc" ] + - location: 12 (remaining gas: 1039994.010 units remaining) + [ {} + "abc" ] + - location: 14 (remaining gas: 1039993.995 units remaining) + [ (Pair {} "abc") ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x-{ 0x00 ; 0x11 ; 0x00 }-0x001100].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x-{ 0x00 ; 0x11 ; 0x00 }-0x001100].out new file mode 100644 index 000000000000..37754899fad7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x-{ 0x00 ; 0x11 ; 0x00 }-0x001100].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x-{ 0x00 ; 0x11 ; 0x00 }-0x001100] + +storage + 0x001100 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039993.914 units remaining) + [ (Pair { 0x00 ; 0x11 ; 0x00 } 0x) ] + - location: 8 (remaining gas: 1039993.904 units remaining) + [ { 0x00 ; 0x11 ; 0x00 } @parameter + 0x @storage ] + - location: 9 (remaining gas: 1039993.894 units remaining) + [ 0x @storage + { 0x00 ; 0x11 ; 0x00 } @parameter ] + - location: 10 (remaining gas: 1039993.879 units remaining) + [ { 0x ; 0x00 ; 0x11 ; 0x00 } ] + - location: 11 (remaining gas: 1039993.739 units remaining) + [ 0x001100 ] + - location: 12 (remaining gas: 1039993.724 units remaining) + [ {} + 0x001100 ] + - location: 14 (remaining gas: 1039993.709 units remaining) + [ (Pair {} 0x001100) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x-{}-0x].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x-{}-0x].out new file mode 100644 index 000000000000..731d84a18ed0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x-{}-0x].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x-{}-0x] + +storage + 0x +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.214 units remaining) + [ (Pair {} 0x) ] + - location: 8 (remaining gas: 1039994.204 units remaining) + [ {} @parameter + 0x @storage ] + - location: 9 (remaining gas: 1039994.194 units remaining) + [ 0x @storage + {} @parameter ] + - location: 10 (remaining gas: 1039994.179 units remaining) + [ { 0x } ] + - location: 11 (remaining gas: 1039994.069 units remaining) + [ 0x ] + - location: 12 (remaining gas: 1039994.054 units remaining) + [ {} + 0x ] + - location: 14 (remaining gas: 1039994.039 units remaining) + [ (Pair {} 0x) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x00ab-{ 0xcd ; 0xef ; 0x00 }-0x00abcdef00].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x00ab-{ 0xcd ; 0xef ; 0x00 }-0x00abcdef00].out new file mode 100644 index 000000000000..3f49574a57b7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x00ab-{ 0xcd ; 0xef ; 0x00 }-0x00abcdef00].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0x00ab-{ 0xcd ; 0xef ; 0x00 }-0x00abcdef00] + +storage + 0x00abcdef00 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039993.914 units remaining) + [ (Pair { 0xcd ; 0xef ; 0x00 } 0x00ab) ] + - location: 8 (remaining gas: 1039993.904 units remaining) + [ { 0xcd ; 0xef ; 0x00 } @parameter + 0x00ab @storage ] + - location: 9 (remaining gas: 1039993.894 units remaining) + [ 0x00ab @storage + { 0xcd ; 0xef ; 0x00 } @parameter ] + - location: 10 (remaining gas: 1039993.879 units remaining) + [ { 0x00ab ; 0xcd ; 0xef ; 0x00 } ] + - location: 11 (remaining gas: 1039993.739 units remaining) + [ 0x00abcdef00 ] + - location: 12 (remaining gas: 1039993.724 units remaining) + [ {} + 0x00abcdef00 ] + - location: 14 (remaining gas: 1039993.709 units remaining) + [ (Pair {} 0x00abcdef00) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0xabcd-{}-0xabcd].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0xabcd-{}-0xabcd].out new file mode 100644 index 000000000000..8ca54a4b2d5b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0xabcd-{}-0xabcd].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_concat_bytes.tz-0xabcd-{}-0xabcd] + +storage + 0xabcd +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.214 units remaining) + [ (Pair {} 0xabcd) ] + - location: 8 (remaining gas: 1039994.204 units remaining) + [ {} @parameter + 0xabcd @storage ] + - location: 9 (remaining gas: 1039994.194 units remaining) + [ 0xabcd @storage + {} @parameter ] + - location: 10 (remaining gas: 1039994.179 units remaining) + [ { 0xabcd } ] + - location: 11 (remaining gas: 1039994.069 units remaining) + [ 0xabcd ] + - location: 12 (remaining gas: 1039994.054 units remaining) + [ {} + 0xabcd ] + - location: 14 (remaining gas: 1039994.039 units remaining) + [ (Pair {} 0xabcd) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id.tz-{\"\"}-{ \"1\" ; \"2\" ; \"3\" }-{ \"1\" ; \"2\" ; \"3\" }].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id.tz-{\"\"}-{ \"1\" ; \"2\" ; \"3\" }-{ \"1\" ; \"2\" ; \"3\" }].out" new file mode 100644 index 000000000000..373dec67b14d --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id.tz-{\"\"}-{ \"1\" ; \"2\" ; \"3\" }-{ \"1\" ; \"2\" ; \"3\" }].out" @@ -0,0 +1,19 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_id.tz-{""}-{ "1" ; "2" ; "3" }-{ "1" ; "2" ; "3" }] + +storage + { "1" ; "2" ; "3" } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039995.439 units remaining) + [ (Pair { "1" ; "2" ; "3" } { "" }) ] + - location: 9 (remaining gas: 1039995.429 units remaining) + [ { "1" ; "2" ; "3" } @parameter ] + - location: 10 (remaining gas: 1039995.414 units remaining) + [ {} + { "1" ; "2" ; "3" } @parameter ] + - location: 12 (remaining gas: 1039995.399 units remaining) + [ (Pair {} { "1" ; "2" ; "3" }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id.tz-{\"\"}-{ \"a\" ; \"b\" ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id.tz-{\"\"}-{ \"a\" ; \"b\" ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" new file mode 100644 index 000000000000..a5cb19b11e1d --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id.tz-{\"\"}-{ \"a\" ; \"b\" ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" @@ -0,0 +1,19 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_id.tz-{""}-{ "a" ; "b" ; "c" }-{ "a" ; "b" ; "c" }] + +storage + { "a" ; "b" ; "c" } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039995.439 units remaining) + [ (Pair { "a" ; "b" ; "c" } { "" }) ] + - location: 9 (remaining gas: 1039995.429 units remaining) + [ { "a" ; "b" ; "c" } @parameter ] + - location: 10 (remaining gas: 1039995.414 units remaining) + [ {} + { "a" ; "b" ; "c" } @parameter ] + - location: 12 (remaining gas: 1039995.399 units remaining) + [ (Pair {} { "a" ; "b" ; "c" }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id.tz-{\"\"}-{}-{}].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id.tz-{\"\"}-{}-{}].out" new file mode 100644 index 000000000000..a07792862759 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id.tz-{\"\"}-{}-{}].out" @@ -0,0 +1,19 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_id.tz-{""}-{}-{}] + +storage + {} +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039995.811 units remaining) + [ (Pair {} { "" }) ] + - location: 9 (remaining gas: 1039995.801 units remaining) + [ {} @parameter ] + - location: 10 (remaining gas: 1039995.786 units remaining) + [ {} + {} @parameter ] + - location: 12 (remaining gas: 1039995.771 units remaining) + [ (Pair {} {}) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id_map.tz-{\"\"}-{ \"1\" ; \"2\" ; \"3\" }-{ \"1\" ; \"2\" ; \"3\" }].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id_map.tz-{\"\"}-{ \"1\" ; \"2\" ; \"3\" }-{ \"1\" ; \"2\" ; \"3\" }].out" new file mode 100644 index 000000000000..18f435063aab --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id_map.tz-{\"\"}-{ \"1\" ; \"2\" ; \"3\" }-{ \"1\" ; \"2\" ; \"3\" }].out" @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_id_map.tz-{""}-{ "1" ; "2" ; "3" }-{ "1" ; "2" ; "3" }] + +storage + { "1" ; "2" ; "3" } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039994.418 units remaining) + [ (Pair { "1" ; "2" ; "3" } { "" }) ] + - location: 9 (remaining gas: 1039994.408 units remaining) + [ { "1" ; "2" ; "3" } @parameter ] + - location: 10 (remaining gas: 1039994.408 units remaining) + [ "1" ] + - location: 10 (remaining gas: 1039994.393 units remaining) + [ "2" ] + - location: 10 (remaining gas: 1039994.378 units remaining) + [ "3" ] + - location: 10 (remaining gas: 1039994.363 units remaining) + [ { "1" ; "2" ; "3" } ] + - location: 12 (remaining gas: 1039994.348 units remaining) + [ {} + { "1" ; "2" ; "3" } ] + - location: 14 (remaining gas: 1039994.333 units remaining) + [ (Pair {} { "1" ; "2" ; "3" }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id_map.tz-{\"\"}-{ \"a\" ; \"b\" ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id_map.tz-{\"\"}-{ \"a\" ; \"b\" ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" new file mode 100644 index 000000000000..8dda917f3ef0 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id_map.tz-{\"\"}-{ \"a\" ; \"b\" ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_id_map.tz-{""}-{ "a" ; "b" ; "c" }-{ "a" ; "b" ; "c" }] + +storage + { "a" ; "b" ; "c" } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039994.418 units remaining) + [ (Pair { "a" ; "b" ; "c" } { "" }) ] + - location: 9 (remaining gas: 1039994.408 units remaining) + [ { "a" ; "b" ; "c" } @parameter ] + - location: 10 (remaining gas: 1039994.408 units remaining) + [ "a" ] + - location: 10 (remaining gas: 1039994.393 units remaining) + [ "b" ] + - location: 10 (remaining gas: 1039994.378 units remaining) + [ "c" ] + - location: 10 (remaining gas: 1039994.363 units remaining) + [ { "a" ; "b" ; "c" } ] + - location: 12 (remaining gas: 1039994.348 units remaining) + [ {} + { "a" ; "b" ; "c" } ] + - location: 14 (remaining gas: 1039994.333 units remaining) + [ (Pair {} { "a" ; "b" ; "c" }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id_map.tz-{\"\"}-{}-{}].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id_map.tz-{\"\"}-{}-{}].out" new file mode 100644 index 000000000000..425588daf509 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_id_map.tz-{\"\"}-{}-{}].out" @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_id_map.tz-{""}-{}-{}] + +storage + {} +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039994.790 units remaining) + [ (Pair {} { "" }) ] + - location: 9 (remaining gas: 1039994.780 units remaining) + [ {} @parameter ] + - location: 10 (remaining gas: 1039994.780 units remaining) + [ {} ] + - location: 12 (remaining gas: 1039994.765 units remaining) + [ {} + {} ] + - location: 14 (remaining gas: 1039994.750 units remaining) + [ (Pair {} {}) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_iter.tz-0-{ 10 ; 2 ; 1 }-20].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_iter.tz-0-{ 10 ; 2 ; 1 }-20].out new file mode 100644 index 000000000000..7ad5a0991f68 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_iter.tz-0-{ 10 ; 2 ; 1 }-20].out @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_iter.tz-0-{ 10 ; 2 ; 1 }-20] + +storage + 20 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039992.773 units remaining) + [ (Pair { 10 ; 2 ; 1 } 0) ] + - location: 8 (remaining gas: 1039992.763 units remaining) + [ { 10 ; 2 ; 1 } @parameter ] + - location: 9 (remaining gas: 1039992.753 units remaining) + [ 1 + { 10 ; 2 ; 1 } @parameter ] + - location: 12 (remaining gas: 1039992.743 units remaining) + [ { 10 ; 2 ; 1 } @parameter + 1 ] + - location: 13 (remaining gas: 1039992.743 units remaining) + [ 10 @parameter.elt + 1 ] + - location: 15 (remaining gas: 1039992.664 units remaining) + [ 10 ] + - location: 13 (remaining gas: 1039992.649 units remaining) + [ 2 @parameter.elt + 10 ] + - location: 15 (remaining gas: 1039992.570 units remaining) + [ 20 ] + - location: 13 (remaining gas: 1039992.555 units remaining) + [ 1 @parameter.elt + 20 ] + - location: 15 (remaining gas: 1039992.476 units remaining) + [ 20 ] + - location: 13 (remaining gas: 1039992.461 units remaining) + [ 20 ] + - location: 16 (remaining gas: 1039992.446 units remaining) + [ {} + 20 ] + - location: 18 (remaining gas: 1039992.431 units remaining) + [ (Pair {} 20) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_iter.tz-0-{ 3 ; 6 ; 9 }-162].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_iter.tz-0-{ 3 ; 6 ; 9 }-162].out new file mode 100644 index 000000000000..0f91a83f0ed5 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_iter.tz-0-{ 3 ; 6 ; 9 }-162].out @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_iter.tz-0-{ 3 ; 6 ; 9 }-162] + +storage + 162 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039992.773 units remaining) + [ (Pair { 3 ; 6 ; 9 } 0) ] + - location: 8 (remaining gas: 1039992.763 units remaining) + [ { 3 ; 6 ; 9 } @parameter ] + - location: 9 (remaining gas: 1039992.753 units remaining) + [ 1 + { 3 ; 6 ; 9 } @parameter ] + - location: 12 (remaining gas: 1039992.743 units remaining) + [ { 3 ; 6 ; 9 } @parameter + 1 ] + - location: 13 (remaining gas: 1039992.743 units remaining) + [ 3 @parameter.elt + 1 ] + - location: 15 (remaining gas: 1039992.664 units remaining) + [ 3 ] + - location: 13 (remaining gas: 1039992.649 units remaining) + [ 6 @parameter.elt + 3 ] + - location: 15 (remaining gas: 1039992.570 units remaining) + [ 18 ] + - location: 13 (remaining gas: 1039992.555 units remaining) + [ 9 @parameter.elt + 18 ] + - location: 15 (remaining gas: 1039992.476 units remaining) + [ 162 ] + - location: 13 (remaining gas: 1039992.461 units remaining) + [ 162 ] + - location: 16 (remaining gas: 1039992.446 units remaining) + [ {} + 162 ] + - location: 18 (remaining gas: 1039992.431 units remaining) + [ (Pair {} 162) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{ 1 ; 1 ; 1 ; 1 }-{ 1 ; 2 ; 3 ; 4 }].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{ 1 ; 1 ; 1 ; 1 }-{ 1 ; 2 ; 3 ; 4 }].out new file mode 100644 index 000000000000..24db3baee5ed --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{ 1 ; 1 ; 1 ; 1 }-{ 1 ; 2 ; 3 ; 4 }].out @@ -0,0 +1,136 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{ 1 ; 1 ; 1 ; 1 }-{ 1 ; 2 ; 3 ; 4 }] + +storage + { 1 ; 2 ; 3 ; 4 } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039987.049 units remaining) + [ (Pair { 1 ; 1 ; 1 ; 1 } { 0 }) ] + - location: 9 (remaining gas: 1039987.039 units remaining) + [ { 1 ; 1 ; 1 ; 1 } @parameter ] + - location: 10 (remaining gas: 1039987.029 units remaining) + [ 0 + { 1 ; 1 ; 1 ; 1 } @parameter ] + - location: 13 (remaining gas: 1039987.019 units remaining) + [ { 1 ; 1 ; 1 ; 1 } @parameter + 0 ] + - location: 14 (remaining gas: 1039987.019 units remaining) + [ 1 @parameter.elt + 0 ] + - location: 16 (remaining gas: 1039987.004 units remaining) + [ 0 ] + - location: 18 (remaining gas: 1039986.994 units remaining) + [ 0 + 0 ] + - location: 16 (remaining gas: 1039986.964 units remaining) + [ 1 @parameter.elt + 0 + 0 ] + - location: 19 (remaining gas: 1039986.929 units remaining) + [ 1 + 0 ] + - location: 20 (remaining gas: 1039986.914 units remaining) + [ 0 ] + - location: 22 (remaining gas: 1039986.904 units remaining) + [ 1 + 0 ] + - location: 25 (remaining gas: 1039986.869 units remaining) + [ 1 ] + - location: 20 (remaining gas: 1039986.839 units remaining) + [ 1 + 1 ] + - location: 14 (remaining gas: 1039986.824 units remaining) + [ 1 @parameter.elt + 1 ] + - location: 16 (remaining gas: 1039986.809 units remaining) + [ 1 ] + - location: 18 (remaining gas: 1039986.799 units remaining) + [ 1 + 1 ] + - location: 16 (remaining gas: 1039986.769 units remaining) + [ 1 @parameter.elt + 1 + 1 ] + - location: 19 (remaining gas: 1039986.734 units remaining) + [ 2 + 1 ] + - location: 20 (remaining gas: 1039986.719 units remaining) + [ 1 ] + - location: 22 (remaining gas: 1039986.709 units remaining) + [ 1 + 1 ] + - location: 25 (remaining gas: 1039986.674 units remaining) + [ 2 ] + - location: 20 (remaining gas: 1039986.644 units remaining) + [ 2 + 2 ] + - location: 14 (remaining gas: 1039986.629 units remaining) + [ 1 @parameter.elt + 2 ] + - location: 16 (remaining gas: 1039986.614 units remaining) + [ 2 ] + - location: 18 (remaining gas: 1039986.604 units remaining) + [ 2 + 2 ] + - location: 16 (remaining gas: 1039986.574 units remaining) + [ 1 @parameter.elt + 2 + 2 ] + - location: 19 (remaining gas: 1039986.539 units remaining) + [ 3 + 2 ] + - location: 20 (remaining gas: 1039986.524 units remaining) + [ 2 ] + - location: 22 (remaining gas: 1039986.514 units remaining) + [ 1 + 2 ] + - location: 25 (remaining gas: 1039986.479 units remaining) + [ 3 ] + - location: 20 (remaining gas: 1039986.449 units remaining) + [ 3 + 3 ] + - location: 14 (remaining gas: 1039986.434 units remaining) + [ 1 @parameter.elt + 3 ] + - location: 16 (remaining gas: 1039986.419 units remaining) + [ 3 ] + - location: 18 (remaining gas: 1039986.409 units remaining) + [ 3 + 3 ] + - location: 16 (remaining gas: 1039986.379 units remaining) + [ 1 @parameter.elt + 3 + 3 ] + - location: 19 (remaining gas: 1039986.344 units remaining) + [ 4 + 3 ] + - location: 20 (remaining gas: 1039986.329 units remaining) + [ 3 ] + - location: 22 (remaining gas: 1039986.319 units remaining) + [ 1 + 3 ] + - location: 25 (remaining gas: 1039986.284 units remaining) + [ 4 ] + - location: 20 (remaining gas: 1039986.254 units remaining) + [ 4 + 4 ] + - location: 14 (remaining gas: 1039986.239 units remaining) + [ { 1 ; 2 ; 3 ; 4 } + 4 ] + - location: 26 (remaining gas: 1039986.224 units remaining) + [ {} + { 1 ; 2 ; 3 ; 4 } + 4 ] + - location: 28 (remaining gas: 1039986.209 units remaining) + [ (Pair {} { 1 ; 2 ; 3 ; 4 }) + 4 ] + - location: 29 (remaining gas: 1039986.194 units remaining) + [ 4 ] + - location: 31 (remaining gas: 1039986.184 units remaining) + [ ] + - location: 29 (remaining gas: 1039986.154 units remaining) + [ (Pair {} { 1 ; 2 ; 3 ; 4 }) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{ 1 ; 2 ; 3 ; 0 }-{ 1 ; 3 ; 5 ; 3 }].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{ 1 ; 2 ; 3 ; 0 }-{ 1 ; 3 ; 5 ; 3 }].out new file mode 100644 index 000000000000..d1bd1624bc61 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{ 1 ; 2 ; 3 ; 0 }-{ 1 ; 3 ; 5 ; 3 }].out @@ -0,0 +1,136 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{ 1 ; 2 ; 3 ; 0 }-{ 1 ; 3 ; 5 ; 3 }] + +storage + { 1 ; 3 ; 5 ; 3 } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039987.049 units remaining) + [ (Pair { 1 ; 2 ; 3 ; 0 } { 0 }) ] + - location: 9 (remaining gas: 1039987.039 units remaining) + [ { 1 ; 2 ; 3 ; 0 } @parameter ] + - location: 10 (remaining gas: 1039987.029 units remaining) + [ 0 + { 1 ; 2 ; 3 ; 0 } @parameter ] + - location: 13 (remaining gas: 1039987.019 units remaining) + [ { 1 ; 2 ; 3 ; 0 } @parameter + 0 ] + - location: 14 (remaining gas: 1039987.019 units remaining) + [ 1 @parameter.elt + 0 ] + - location: 16 (remaining gas: 1039987.004 units remaining) + [ 0 ] + - location: 18 (remaining gas: 1039986.994 units remaining) + [ 0 + 0 ] + - location: 16 (remaining gas: 1039986.964 units remaining) + [ 1 @parameter.elt + 0 + 0 ] + - location: 19 (remaining gas: 1039986.929 units remaining) + [ 1 + 0 ] + - location: 20 (remaining gas: 1039986.914 units remaining) + [ 0 ] + - location: 22 (remaining gas: 1039986.904 units remaining) + [ 1 + 0 ] + - location: 25 (remaining gas: 1039986.869 units remaining) + [ 1 ] + - location: 20 (remaining gas: 1039986.839 units remaining) + [ 1 + 1 ] + - location: 14 (remaining gas: 1039986.824 units remaining) + [ 2 @parameter.elt + 1 ] + - location: 16 (remaining gas: 1039986.809 units remaining) + [ 1 ] + - location: 18 (remaining gas: 1039986.799 units remaining) + [ 1 + 1 ] + - location: 16 (remaining gas: 1039986.769 units remaining) + [ 2 @parameter.elt + 1 + 1 ] + - location: 19 (remaining gas: 1039986.734 units remaining) + [ 3 + 1 ] + - location: 20 (remaining gas: 1039986.719 units remaining) + [ 1 ] + - location: 22 (remaining gas: 1039986.709 units remaining) + [ 1 + 1 ] + - location: 25 (remaining gas: 1039986.674 units remaining) + [ 2 ] + - location: 20 (remaining gas: 1039986.644 units remaining) + [ 3 + 2 ] + - location: 14 (remaining gas: 1039986.629 units remaining) + [ 3 @parameter.elt + 2 ] + - location: 16 (remaining gas: 1039986.614 units remaining) + [ 2 ] + - location: 18 (remaining gas: 1039986.604 units remaining) + [ 2 + 2 ] + - location: 16 (remaining gas: 1039986.574 units remaining) + [ 3 @parameter.elt + 2 + 2 ] + - location: 19 (remaining gas: 1039986.539 units remaining) + [ 5 + 2 ] + - location: 20 (remaining gas: 1039986.524 units remaining) + [ 2 ] + - location: 22 (remaining gas: 1039986.514 units remaining) + [ 1 + 2 ] + - location: 25 (remaining gas: 1039986.479 units remaining) + [ 3 ] + - location: 20 (remaining gas: 1039986.449 units remaining) + [ 5 + 3 ] + - location: 14 (remaining gas: 1039986.434 units remaining) + [ 0 @parameter.elt + 3 ] + - location: 16 (remaining gas: 1039986.419 units remaining) + [ 3 ] + - location: 18 (remaining gas: 1039986.409 units remaining) + [ 3 + 3 ] + - location: 16 (remaining gas: 1039986.379 units remaining) + [ 0 @parameter.elt + 3 + 3 ] + - location: 19 (remaining gas: 1039986.344 units remaining) + [ 3 + 3 ] + - location: 20 (remaining gas: 1039986.329 units remaining) + [ 3 ] + - location: 22 (remaining gas: 1039986.319 units remaining) + [ 1 + 3 ] + - location: 25 (remaining gas: 1039986.284 units remaining) + [ 4 ] + - location: 20 (remaining gas: 1039986.254 units remaining) + [ 3 + 4 ] + - location: 14 (remaining gas: 1039986.239 units remaining) + [ { 1 ; 3 ; 5 ; 3 } + 4 ] + - location: 26 (remaining gas: 1039986.224 units remaining) + [ {} + { 1 ; 3 ; 5 ; 3 } + 4 ] + - location: 28 (remaining gas: 1039986.209 units remaining) + [ (Pair {} { 1 ; 3 ; 5 ; 3 }) + 4 ] + - location: 29 (remaining gas: 1039986.194 units remaining) + [ 4 ] + - location: 31 (remaining gas: 1039986.184 units remaining) + [ ] + - location: 29 (remaining gas: 1039986.154 units remaining) + [ (Pair {} { 1 ; 3 ; 5 ; 3 }) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{}-{}].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{}-{}].out new file mode 100644 index 000000000000..c5a5e1cf6eb0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{}-{}].out @@ -0,0 +1,36 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_map_block.tz-{0}-{}-{}] + +storage + {} +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039987.449 units remaining) + [ (Pair {} { 0 }) ] + - location: 9 (remaining gas: 1039987.439 units remaining) + [ {} @parameter ] + - location: 10 (remaining gas: 1039987.429 units remaining) + [ 0 + {} @parameter ] + - location: 13 (remaining gas: 1039987.419 units remaining) + [ {} @parameter + 0 ] + - location: 14 (remaining gas: 1039987.419 units remaining) + [ {} + 0 ] + - location: 26 (remaining gas: 1039987.404 units remaining) + [ {} + {} + 0 ] + - location: 28 (remaining gas: 1039987.389 units remaining) + [ (Pair {} {}) + 0 ] + - location: 29 (remaining gas: 1039987.374 units remaining) + [ 0 ] + - location: 31 (remaining gas: 1039987.364 units remaining) + [ ] + - location: 29 (remaining gas: 1039987.334 units remaining) + [ (Pair {} {}) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }-6].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }-6].out new file mode 100644 index 000000000000..eb275493c028 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }-6].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }-6] + +storage + 6 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.940 units remaining) + [ (Pair { 1 ; 2 ; 3 ; 4 ; 5 ; 6 } 111) ] + - location: 8 (remaining gas: 1039994.930 units remaining) + [ { 1 ; 2 ; 3 ; 4 ; 5 ; 6 } @parameter ] + - location: 9 (remaining gas: 1039994.915 units remaining) + [ 6 ] + - location: 10 (remaining gas: 1039994.900 units remaining) + [ {} + 6 ] + - location: 12 (remaining gas: 1039994.885 units remaining) + [ (Pair {} 6) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 ; 2 ; 3 }-3].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 ; 2 ; 3 }-3].out new file mode 100644 index 000000000000..7eced34380ad --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 ; 2 ; 3 }-3].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 ; 2 ; 3 }-3] + +storage + 3 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039995.240 units remaining) + [ (Pair { 1 ; 2 ; 3 } 111) ] + - location: 8 (remaining gas: 1039995.230 units remaining) + [ { 1 ; 2 ; 3 } @parameter ] + - location: 9 (remaining gas: 1039995.215 units remaining) + [ 3 ] + - location: 10 (remaining gas: 1039995.200 units remaining) + [ {} + 3 ] + - location: 12 (remaining gas: 1039995.185 units remaining) + [ (Pair {} 3) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 }-1].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 }-1].out new file mode 100644 index 000000000000..c074e844c906 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 }-1].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_size.tz-111-{ 1 }-1] + +storage + 1 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039995.440 units remaining) + [ (Pair { 1 } 111) ] + - location: 8 (remaining gas: 1039995.430 units remaining) + [ { 1 } @parameter ] + - location: 9 (remaining gas: 1039995.415 units remaining) + [ 1 ] + - location: 10 (remaining gas: 1039995.400 units remaining) + [ {} + 1 ] + - location: 12 (remaining gas: 1039995.385 units remaining) + [ (Pair {} 1) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{}-0].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{}-0].out new file mode 100644 index 000000000000..982ac8288398 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[list_size.tz-111-{}-0].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[list_size.tz-111-{}-0] + +storage + 0 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039995.540 units remaining) + [ (Pair {} 111) ] + - location: 8 (remaining gas: 1039995.530 units remaining) + [ {} @parameter ] + - location: 9 (remaining gas: 1039995.515 units remaining) + [ 0 ] + - location: 10 (remaining gas: 1039995.500 units remaining) + [ {} + 0 ] + - location: 12 (remaining gas: 1039995.485 units remaining) + [ (Pair {} 0) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[loop_left.tz-{\"\"}-{ \"c\" ; \"b\" ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[loop_left.tz-{\"\"}-{ \"c\" ; \"b\" ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" new file mode 100644 index 000000000000..4909c65e64d6 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[loop_left.tz-{\"\"}-{ \"c\" ; \"b\" ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" @@ -0,0 +1,163 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[loop_left.tz-{""}-{ "c" ; "b" ; "a" }-{ "a" ; "b" ; "c" }] + +storage + { "a" ; "b" ; "c" } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039981.670 units remaining) + [ (Pair { "c" ; "b" ; "a" } { "" }) ] + - location: 9 (remaining gas: 1039981.660 units remaining) + [ { "c" ; "b" ; "a" } @parameter ] + - location: 10 (remaining gas: 1039981.645 units remaining) + [ {} + { "c" ; "b" ; "a" } @parameter ] + - location: 12 (remaining gas: 1039981.635 units remaining) + [ { "c" ; "b" ; "a" } @parameter + {} ] + - location: 13 (remaining gas: 1039981.620 units remaining) + [ (Pair { "c" ; "b" ; "a" } {}) ] + - location: 14 (remaining gas: 1039981.605 units remaining) + [ (Left (Pair { "c" ; "b" ; "a" } {})) ] + - location: 17 (remaining gas: 1039981.605 units remaining) + [ (Pair { "c" ; "b" ; "a" } {}) ] + - location: 19 (remaining gas: 1039981.595 units remaining) + [ (Pair { "c" ; "b" ; "a" } {}) + (Pair { "c" ; "b" ; "a" } {}) ] + - location: 20 (remaining gas: 1039981.585 units remaining) + [ { "c" ; "b" ; "a" } @parameter + (Pair { "c" ; "b" ; "a" } {}) ] + - location: 21 (remaining gas: 1039981.570 units remaining) + [ (Pair { "c" ; "b" ; "a" } {}) ] + - location: 23 (remaining gas: 1039981.560 units remaining) + [ {} ] + - location: 21 (remaining gas: 1039981.530 units remaining) + [ { "c" ; "b" ; "a" } @parameter + {} ] + - location: 24 (remaining gas: 1039981.520 units remaining) + [ "c" @parameter.hd + { "b" ; "a" } @parameter.tl + {} ] + - location: 26 (remaining gas: 1039981.510 units remaining) + [ { "b" ; "a" } @parameter.tl + "c" @parameter.hd + {} ] + - location: 27 (remaining gas: 1039981.495 units remaining) + [ "c" @parameter.hd + {} ] + - location: 29 (remaining gas: 1039981.480 units remaining) + [ { "c" } ] + - location: 27 (remaining gas: 1039981.450 units remaining) + [ { "b" ; "a" } @parameter.tl + { "c" } ] + - location: 30 (remaining gas: 1039981.435 units remaining) + [ (Pair { "b" ; "a" } { "c" }) ] + - location: 31 (remaining gas: 1039981.420 units remaining) + [ (Left (Pair { "b" ; "a" } { "c" })) ] + - location: 24 (remaining gas: 1039981.405 units remaining) + [ (Left (Pair { "b" ; "a" } { "c" })) ] + - location: 17 (remaining gas: 1039981.390 units remaining) + [ (Pair { "b" ; "a" } { "c" }) ] + - location: 19 (remaining gas: 1039981.380 units remaining) + [ (Pair { "b" ; "a" } { "c" }) + (Pair { "b" ; "a" } { "c" }) ] + - location: 20 (remaining gas: 1039981.370 units remaining) + [ { "b" ; "a" } @parameter + (Pair { "b" ; "a" } { "c" }) ] + - location: 21 (remaining gas: 1039981.355 units remaining) + [ (Pair { "b" ; "a" } { "c" }) ] + - location: 23 (remaining gas: 1039981.345 units remaining) + [ { "c" } ] + - location: 21 (remaining gas: 1039981.315 units remaining) + [ { "b" ; "a" } @parameter + { "c" } ] + - location: 24 (remaining gas: 1039981.305 units remaining) + [ "b" @parameter.hd + { "a" } @parameter.tl + { "c" } ] + - location: 26 (remaining gas: 1039981.295 units remaining) + [ { "a" } @parameter.tl + "b" @parameter.hd + { "c" } ] + - location: 27 (remaining gas: 1039981.280 units remaining) + [ "b" @parameter.hd + { "c" } ] + - location: 29 (remaining gas: 1039981.265 units remaining) + [ { "b" ; "c" } ] + - location: 27 (remaining gas: 1039981.235 units remaining) + [ { "a" } @parameter.tl + { "b" ; "c" } ] + - location: 30 (remaining gas: 1039981.220 units remaining) + [ (Pair { "a" } { "b" ; "c" }) ] + - location: 31 (remaining gas: 1039981.205 units remaining) + [ (Left (Pair { "a" } { "b" ; "c" })) ] + - location: 24 (remaining gas: 1039981.190 units remaining) + [ (Left (Pair { "a" } { "b" ; "c" })) ] + - location: 17 (remaining gas: 1039981.175 units remaining) + [ (Pair { "a" } { "b" ; "c" }) ] + - location: 19 (remaining gas: 1039981.165 units remaining) + [ (Pair { "a" } { "b" ; "c" }) + (Pair { "a" } { "b" ; "c" }) ] + - location: 20 (remaining gas: 1039981.155 units remaining) + [ { "a" } @parameter + (Pair { "a" } { "b" ; "c" }) ] + - location: 21 (remaining gas: 1039981.140 units remaining) + [ (Pair { "a" } { "b" ; "c" }) ] + - location: 23 (remaining gas: 1039981.130 units remaining) + [ { "b" ; "c" } ] + - location: 21 (remaining gas: 1039981.100 units remaining) + [ { "a" } @parameter + { "b" ; "c" } ] + - location: 24 (remaining gas: 1039981.090 units remaining) + [ "a" @parameter.hd + {} @parameter.tl + { "b" ; "c" } ] + - location: 26 (remaining gas: 1039981.080 units remaining) + [ {} @parameter.tl + "a" @parameter.hd + { "b" ; "c" } ] + - location: 27 (remaining gas: 1039981.065 units remaining) + [ "a" @parameter.hd + { "b" ; "c" } ] + - location: 29 (remaining gas: 1039981.050 units remaining) + [ { "a" ; "b" ; "c" } ] + - location: 27 (remaining gas: 1039981.020 units remaining) + [ {} @parameter.tl + { "a" ; "b" ; "c" } ] + - location: 30 (remaining gas: 1039981.005 units remaining) + [ (Pair {} { "a" ; "b" ; "c" }) ] + - location: 31 (remaining gas: 1039980.990 units remaining) + [ (Left (Pair {} { "a" ; "b" ; "c" })) ] + - location: 24 (remaining gas: 1039980.975 units remaining) + [ (Left (Pair {} { "a" ; "b" ; "c" })) ] + - location: 17 (remaining gas: 1039980.960 units remaining) + [ (Pair {} { "a" ; "b" ; "c" }) ] + - location: 19 (remaining gas: 1039980.950 units remaining) + [ (Pair {} { "a" ; "b" ; "c" }) + (Pair {} { "a" ; "b" ; "c" }) ] + - location: 20 (remaining gas: 1039980.940 units remaining) + [ {} @parameter + (Pair {} { "a" ; "b" ; "c" }) ] + - location: 21 (remaining gas: 1039980.925 units remaining) + [ (Pair {} { "a" ; "b" ; "c" }) ] + - location: 23 (remaining gas: 1039980.915 units remaining) + [ { "a" ; "b" ; "c" } ] + - location: 21 (remaining gas: 1039980.885 units remaining) + [ {} @parameter + { "a" ; "b" ; "c" } ] + - location: 24 (remaining gas: 1039980.875 units remaining) + [ { "a" ; "b" ; "c" } ] + - location: 35 (remaining gas: 1039980.860 units remaining) + [ (Right { "a" ; "b" ; "c" }) ] + - location: 24 (remaining gas: 1039980.845 units remaining) + [ (Right { "a" ; "b" ; "c" }) ] + - location: 17 (remaining gas: 1039980.830 units remaining) + [ { "a" ; "b" ; "c" } ] + - location: 41 (remaining gas: 1039980.815 units remaining) + [ {} + { "a" ; "b" ; "c" } ] + - location: 43 (remaining gas: 1039980.800 units remaining) + [ (Pair {} { "a" ; "b" ; "c" }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[loop_left.tz-{\"\"}-{}-{}].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[loop_left.tz-{\"\"}-{}-{}].out" new file mode 100644 index 000000000000..497b9c03f968 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[loop_left.tz-{\"\"}-{}-{}].out" @@ -0,0 +1,52 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[loop_left.tz-{""}-{}-{}] + +storage + {} +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039982.042 units remaining) + [ (Pair {} { "" }) ] + - location: 9 (remaining gas: 1039982.032 units remaining) + [ {} @parameter ] + - location: 10 (remaining gas: 1039982.017 units remaining) + [ {} + {} @parameter ] + - location: 12 (remaining gas: 1039982.007 units remaining) + [ {} @parameter + {} ] + - location: 13 (remaining gas: 1039981.992 units remaining) + [ (Pair {} {}) ] + - location: 14 (remaining gas: 1039981.977 units remaining) + [ (Left (Pair {} {})) ] + - location: 17 (remaining gas: 1039981.977 units remaining) + [ (Pair {} {}) ] + - location: 19 (remaining gas: 1039981.967 units remaining) + [ (Pair {} {}) + (Pair {} {}) ] + - location: 20 (remaining gas: 1039981.957 units remaining) + [ {} @parameter + (Pair {} {}) ] + - location: 21 (remaining gas: 1039981.942 units remaining) + [ (Pair {} {}) ] + - location: 23 (remaining gas: 1039981.932 units remaining) + [ {} ] + - location: 21 (remaining gas: 1039981.902 units remaining) + [ {} @parameter + {} ] + - location: 24 (remaining gas: 1039981.892 units remaining) + [ {} ] + - location: 35 (remaining gas: 1039981.877 units remaining) + [ (Right {}) ] + - location: 24 (remaining gas: 1039981.862 units remaining) + [ (Right {}) ] + - location: 17 (remaining gas: 1039981.847 units remaining) + [ {} ] + - location: 41 (remaining gas: 1039981.832 units remaining) + [ {} + {} ] + - location: 43 (remaining gas: 1039981.817 units remaining) + [ (Pair {} {}) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 0 ; Elt 3 4 }-{ Elt 0 0 ; Elt 3 4 }].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 0 ; Elt 3 4 }-{ Elt 0 0 ; Elt 3 4 }].out new file mode 100644 index 000000000000..48d0f9e505ab --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 0 ; Elt 3 4 }-{ Elt 0 0 ; Elt 3 4 }].out @@ -0,0 +1,19 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 0 ; Elt 3 4 }-{ Elt 0 0 ; Elt 3 4 }] + +storage + { Elt 0 0 ; Elt 3 4 } +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039994.779 units remaining) + [ (Pair { Elt 0 0 ; Elt 3 4 } {}) ] + - location: 11 (remaining gas: 1039994.769 units remaining) + [ { Elt 0 0 ; Elt 3 4 } @parameter ] + - location: 12 (remaining gas: 1039994.754 units remaining) + [ {} + { Elt 0 0 ; Elt 3 4 } @parameter ] + - location: 14 (remaining gas: 1039994.739 units remaining) + [ (Pair {} { Elt 0 0 ; Elt 3 4 }) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 0 }-{ Elt 0 0 }].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 0 }-{ Elt 0 0 }].out new file mode 100644 index 000000000000..4a3e3c95868d --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 0 }-{ Elt 0 0 }].out @@ -0,0 +1,19 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 0 }-{ Elt 0 0 }] + +storage + { Elt 0 0 } +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039995.234 units remaining) + [ (Pair { Elt 0 0 } {}) ] + - location: 11 (remaining gas: 1039995.224 units remaining) + [ { Elt 0 0 } @parameter ] + - location: 12 (remaining gas: 1039995.209 units remaining) + [ {} + { Elt 0 0 } @parameter ] + - location: 14 (remaining gas: 1039995.194 units remaining) + [ (Pair {} { Elt 0 0 }) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 1 }-{ Elt 0 1 }].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 1 }-{ Elt 0 1 }].out new file mode 100644 index 000000000000..792c85ba7975 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 1 }-{ Elt 0 1 }].out @@ -0,0 +1,19 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_id.tz-{}-{ Elt 0 1 }-{ Elt 0 1 }] + +storage + { Elt 0 1 } +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039995.234 units remaining) + [ (Pair { Elt 0 1 } {}) ] + - location: 11 (remaining gas: 1039995.224 units remaining) + [ { Elt 0 1 } @parameter ] + - location: 12 (remaining gas: 1039995.209 units remaining) + [ {} + { Elt 0 1 } @parameter ] + - location: 14 (remaining gas: 1039995.194 units remaining) + [ (Pair {} { Elt 0 1 }) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_iter.tz-(Pair 0 0)-{ Elt 0 100 ; Elt 2 100 }-(Pair 2 200)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_iter.tz-(Pair 0 0)-{ Elt 0 100 ; Elt 2 100 }-(Pair 2 200)].out new file mode 100644 index 000000000000..7b16860e03b1 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_iter.tz-(Pair 0 0)-{ Elt 0 100 ; Elt 2 100 }-(Pair 2 200)].out @@ -0,0 +1,152 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_iter.tz-(Pair 0 0)-{ Elt 0 100 ; Elt 2 100 }-(Pair 2 200)] + +storage + (Pair 2 200) +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039980.129 units remaining) + [ (Pair { Elt 0 100 ; Elt 2 100 } 0 0) ] + - location: 11 (remaining gas: 1039980.119 units remaining) + [ { Elt 0 100 ; Elt 2 100 } @parameter ] + - location: 12 (remaining gas: 1039980.109 units remaining) + [ 0 @acc_e + { Elt 0 100 ; Elt 2 100 } @parameter ] + - location: 15 (remaining gas: 1039980.099 units remaining) + [ 0 @acc_k + 0 @acc_e + { Elt 0 100 ; Elt 2 100 } @parameter ] + - location: 18 (remaining gas: 1039980.084 units remaining) + [ (Pair 0 0) + { Elt 0 100 ; Elt 2 100 } @parameter ] + - location: 19 (remaining gas: 1039980.074 units remaining) + [ { Elt 0 100 ; Elt 2 100 } @parameter + (Pair 0 0) ] + - location: 20 (remaining gas: 1039980.074 units remaining) + [ (Pair 0 100) + (Pair 0 0) ] + - location: 22 (remaining gas: 1039980.059 units remaining) + [ (Pair 0 0) ] + - location: 24 (remaining gas: 1039980.049 units remaining) + [ (Pair 0 0) + (Pair 0 0) ] + - location: 25 (remaining gas: 1039980.039 units remaining) + [ 0 @acc_k + (Pair 0 0) ] + - location: 26 (remaining gas: 1039980.024 units remaining) + [ (Pair 0 0) ] + - location: 28 (remaining gas: 1039980.014 units remaining) + [ 0 @acc_e ] + - location: 26 (remaining gas: 1039979.984 units remaining) + [ 0 @acc_k + 0 @acc_e ] + - location: 22 (remaining gas: 1039979.954 units remaining) + [ (Pair 0 100) + 0 @acc_k + 0 @acc_e ] + - location: 29 (remaining gas: 1039979.944 units remaining) + [ (Pair 0 100) + (Pair 0 100) + 0 @acc_k + 0 @acc_e ] + - location: 30 (remaining gas: 1039979.929 units remaining) + [ (Pair 0 100) + 0 @acc_k + 0 @acc_e ] + - location: 32 (remaining gas: 1039979.919 units remaining) + [ 0 @key + 0 @acc_k + 0 @acc_e ] + - location: 33 (remaining gas: 1039979.884 units remaining) + [ 0 + 0 @acc_e ] + - location: 30 (remaining gas: 1039979.854 units remaining) + [ (Pair 0 100) + 0 + 0 @acc_e ] + - location: 34 (remaining gas: 1039979.844 units remaining) + [ 0 + (Pair 0 100) + 0 @acc_e ] + - location: 35 (remaining gas: 1039979.829 units remaining) + [ (Pair 0 100) + 0 @acc_e ] + - location: 37 (remaining gas: 1039979.819 units remaining) + [ 100 @elt + 0 @acc_e ] + - location: 38 (remaining gas: 1039979.784 units remaining) + [ 100 ] + - location: 35 (remaining gas: 1039979.754 units remaining) + [ 0 + 100 ] + - location: 39 (remaining gas: 1039979.739 units remaining) + [ (Pair 0 100) ] + - location: 20 (remaining gas: 1039979.724 units remaining) + [ (Pair 2 100) + (Pair 0 100) ] + - location: 22 (remaining gas: 1039979.709 units remaining) + [ (Pair 0 100) ] + - location: 24 (remaining gas: 1039979.699 units remaining) + [ (Pair 0 100) + (Pair 0 100) ] + - location: 25 (remaining gas: 1039979.689 units remaining) + [ 0 @acc_k + (Pair 0 100) ] + - location: 26 (remaining gas: 1039979.674 units remaining) + [ (Pair 0 100) ] + - location: 28 (remaining gas: 1039979.664 units remaining) + [ 100 @acc_e ] + - location: 26 (remaining gas: 1039979.634 units remaining) + [ 0 @acc_k + 100 @acc_e ] + - location: 22 (remaining gas: 1039979.604 units remaining) + [ (Pair 2 100) + 0 @acc_k + 100 @acc_e ] + - location: 29 (remaining gas: 1039979.594 units remaining) + [ (Pair 2 100) + (Pair 2 100) + 0 @acc_k + 100 @acc_e ] + - location: 30 (remaining gas: 1039979.579 units remaining) + [ (Pair 2 100) + 0 @acc_k + 100 @acc_e ] + - location: 32 (remaining gas: 1039979.569 units remaining) + [ 2 @key + 0 @acc_k + 100 @acc_e ] + - location: 33 (remaining gas: 1039979.534 units remaining) + [ 2 + 100 @acc_e ] + - location: 30 (remaining gas: 1039979.504 units remaining) + [ (Pair 2 100) + 2 + 100 @acc_e ] + - location: 34 (remaining gas: 1039979.494 units remaining) + [ 2 + (Pair 2 100) + 100 @acc_e ] + - location: 35 (remaining gas: 1039979.479 units remaining) + [ (Pair 2 100) + 100 @acc_e ] + - location: 37 (remaining gas: 1039979.469 units remaining) + [ 100 @elt + 100 @acc_e ] + - location: 38 (remaining gas: 1039979.434 units remaining) + [ 200 ] + - location: 35 (remaining gas: 1039979.404 units remaining) + [ 2 + 200 ] + - location: 39 (remaining gas: 1039979.389 units remaining) + [ (Pair 2 200) ] + - location: 20 (remaining gas: 1039979.374 units remaining) + [ (Pair 2 200) ] + - location: 40 (remaining gas: 1039979.359 units remaining) + [ {} + (Pair 2 200) ] + - location: 42 (remaining gas: 1039979.344 units remaining) + [ (Pair {} 2 200) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_iter.tz-(Pair 0 0)-{ Elt 1 1 ; Elt 2 100 }-(Pair 3 101)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_iter.tz-(Pair 0 0)-{ Elt 1 1 ; Elt 2 100 }-(Pair 3 101)].out new file mode 100644 index 000000000000..126fcbee5240 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_iter.tz-(Pair 0 0)-{ Elt 1 1 ; Elt 2 100 }-(Pair 3 101)].out @@ -0,0 +1,152 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_iter.tz-(Pair 0 0)-{ Elt 1 1 ; Elt 2 100 }-(Pair 3 101)] + +storage + (Pair 3 101) +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039980.129 units remaining) + [ (Pair { Elt 1 1 ; Elt 2 100 } 0 0) ] + - location: 11 (remaining gas: 1039980.119 units remaining) + [ { Elt 1 1 ; Elt 2 100 } @parameter ] + - location: 12 (remaining gas: 1039980.109 units remaining) + [ 0 @acc_e + { Elt 1 1 ; Elt 2 100 } @parameter ] + - location: 15 (remaining gas: 1039980.099 units remaining) + [ 0 @acc_k + 0 @acc_e + { Elt 1 1 ; Elt 2 100 } @parameter ] + - location: 18 (remaining gas: 1039980.084 units remaining) + [ (Pair 0 0) + { Elt 1 1 ; Elt 2 100 } @parameter ] + - location: 19 (remaining gas: 1039980.074 units remaining) + [ { Elt 1 1 ; Elt 2 100 } @parameter + (Pair 0 0) ] + - location: 20 (remaining gas: 1039980.074 units remaining) + [ (Pair 1 1) + (Pair 0 0) ] + - location: 22 (remaining gas: 1039980.059 units remaining) + [ (Pair 0 0) ] + - location: 24 (remaining gas: 1039980.049 units remaining) + [ (Pair 0 0) + (Pair 0 0) ] + - location: 25 (remaining gas: 1039980.039 units remaining) + [ 0 @acc_k + (Pair 0 0) ] + - location: 26 (remaining gas: 1039980.024 units remaining) + [ (Pair 0 0) ] + - location: 28 (remaining gas: 1039980.014 units remaining) + [ 0 @acc_e ] + - location: 26 (remaining gas: 1039979.984 units remaining) + [ 0 @acc_k + 0 @acc_e ] + - location: 22 (remaining gas: 1039979.954 units remaining) + [ (Pair 1 1) + 0 @acc_k + 0 @acc_e ] + - location: 29 (remaining gas: 1039979.944 units remaining) + [ (Pair 1 1) + (Pair 1 1) + 0 @acc_k + 0 @acc_e ] + - location: 30 (remaining gas: 1039979.929 units remaining) + [ (Pair 1 1) + 0 @acc_k + 0 @acc_e ] + - location: 32 (remaining gas: 1039979.919 units remaining) + [ 1 @key + 0 @acc_k + 0 @acc_e ] + - location: 33 (remaining gas: 1039979.884 units remaining) + [ 1 + 0 @acc_e ] + - location: 30 (remaining gas: 1039979.854 units remaining) + [ (Pair 1 1) + 1 + 0 @acc_e ] + - location: 34 (remaining gas: 1039979.844 units remaining) + [ 1 + (Pair 1 1) + 0 @acc_e ] + - location: 35 (remaining gas: 1039979.829 units remaining) + [ (Pair 1 1) + 0 @acc_e ] + - location: 37 (remaining gas: 1039979.819 units remaining) + [ 1 @elt + 0 @acc_e ] + - location: 38 (remaining gas: 1039979.784 units remaining) + [ 1 ] + - location: 35 (remaining gas: 1039979.754 units remaining) + [ 1 + 1 ] + - location: 39 (remaining gas: 1039979.739 units remaining) + [ (Pair 1 1) ] + - location: 20 (remaining gas: 1039979.724 units remaining) + [ (Pair 2 100) + (Pair 1 1) ] + - location: 22 (remaining gas: 1039979.709 units remaining) + [ (Pair 1 1) ] + - location: 24 (remaining gas: 1039979.699 units remaining) + [ (Pair 1 1) + (Pair 1 1) ] + - location: 25 (remaining gas: 1039979.689 units remaining) + [ 1 @acc_k + (Pair 1 1) ] + - location: 26 (remaining gas: 1039979.674 units remaining) + [ (Pair 1 1) ] + - location: 28 (remaining gas: 1039979.664 units remaining) + [ 1 @acc_e ] + - location: 26 (remaining gas: 1039979.634 units remaining) + [ 1 @acc_k + 1 @acc_e ] + - location: 22 (remaining gas: 1039979.604 units remaining) + [ (Pair 2 100) + 1 @acc_k + 1 @acc_e ] + - location: 29 (remaining gas: 1039979.594 units remaining) + [ (Pair 2 100) + (Pair 2 100) + 1 @acc_k + 1 @acc_e ] + - location: 30 (remaining gas: 1039979.579 units remaining) + [ (Pair 2 100) + 1 @acc_k + 1 @acc_e ] + - location: 32 (remaining gas: 1039979.569 units remaining) + [ 2 @key + 1 @acc_k + 1 @acc_e ] + - location: 33 (remaining gas: 1039979.534 units remaining) + [ 3 + 1 @acc_e ] + - location: 30 (remaining gas: 1039979.504 units remaining) + [ (Pair 2 100) + 3 + 1 @acc_e ] + - location: 34 (remaining gas: 1039979.494 units remaining) + [ 3 + (Pair 2 100) + 1 @acc_e ] + - location: 35 (remaining gas: 1039979.479 units remaining) + [ (Pair 2 100) + 1 @acc_e ] + - location: 37 (remaining gas: 1039979.469 units remaining) + [ 100 @elt + 1 @acc_e ] + - location: 38 (remaining gas: 1039979.434 units remaining) + [ 101 ] + - location: 35 (remaining gas: 1039979.404 units remaining) + [ 3 + 101 ] + - location: 39 (remaining gas: 1039979.389 units remaining) + [ (Pair 3 101) ] + - location: 20 (remaining gas: 1039979.374 units remaining) + [ (Pair 3 101) ] + - location: 40 (remaining gas: 1039979.359 units remaining) + [ {} + (Pair 3 101) ] + - location: 42 (remaining gas: 1039979.344 units remaining) + [ (Pair {} 3 101) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_map.tz-{ Elt \"bar\" 5 ; Elt \"foo\" 1 }-15-{ Elt \"bar\".12b9d73d5a.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_map.tz-{ Elt \"bar\" 5 ; Elt \"foo\" 1 }-15-{ Elt \"bar\".12b9d73d5a.out" new file mode 100644 index 000000000000..5c6ea7fddd0e --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_map.tz-{ Elt \"bar\" 5 ; Elt \"foo\" 1 }-15-{ Elt \"bar\".12b9d73d5a.out" @@ -0,0 +1,68 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_map.tz-{ Elt "bar" 5 ; Elt "foo" 1 }-15-{ Elt "bar" 20 ; Elt "foo" 16 }] + +storage + { Elt "bar" 20 ; Elt "foo" 16 } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039989.301 units remaining) + [ (Pair 15 { Elt "bar" 5 ; Elt "foo" 1 }) ] + - location: 9 (remaining gas: 1039989.291 units remaining) + [ 15 @parameter + { Elt "bar" 5 ; Elt "foo" 1 } @storage ] + - location: 10 (remaining gas: 1039989.281 units remaining) + [ { Elt "bar" 5 ; Elt "foo" 1 } @storage + 15 @parameter ] + - location: 11 (remaining gas: 1039989.281 units remaining) + [ (Pair "bar" 5) + 15 @parameter ] + - location: 13 (remaining gas: 1039989.271 units remaining) + [ 5 @elt + 15 @parameter ] + - location: 14 (remaining gas: 1039989.256 units remaining) + [ 15 @parameter ] + - location: 16 (remaining gas: 1039989.246 units remaining) + [ 15 @parameter + 15 @parameter ] + - location: 14 (remaining gas: 1039989.216 units remaining) + [ 5 @elt + 15 @parameter + 15 @parameter ] + - location: 17 (remaining gas: 1039989.181 units remaining) + [ 20 + 15 @parameter ] + - location: 11 (remaining gas: 1039989.166 units remaining) + [ (Pair "foo" 1) + 15 @parameter ] + - location: 13 (remaining gas: 1039989.156 units remaining) + [ 1 @elt + 15 @parameter ] + - location: 14 (remaining gas: 1039989.141 units remaining) + [ 15 @parameter ] + - location: 16 (remaining gas: 1039989.131 units remaining) + [ 15 @parameter + 15 @parameter ] + - location: 14 (remaining gas: 1039989.101 units remaining) + [ 1 @elt + 15 @parameter + 15 @parameter ] + - location: 17 (remaining gas: 1039989.066 units remaining) + [ 16 + 15 @parameter ] + - location: 11 (remaining gas: 1039989.051 units remaining) + [ { Elt "bar" 20 ; Elt "foo" 16 } + 15 @parameter ] + - location: 18 (remaining gas: 1039989.036 units remaining) + [ 15 @parameter ] + - location: 20 (remaining gas: 1039989.026 units remaining) + [ ] + - location: 18 (remaining gas: 1039988.996 units remaining) + [ { Elt "bar" 20 ; Elt "foo" 16 } ] + - location: 21 (remaining gas: 1039988.981 units remaining) + [ {} + { Elt "bar" 20 ; Elt "foo" 16 } ] + - location: 23 (remaining gas: 1039988.966 units remaining) + [ (Pair {} { Elt "bar" 20 ; Elt "foo" 16 }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_map.tz-{ Elt \"foo\" 1 }-10-{ Elt \"foo\" 11 }].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_map.tz-{ Elt \"foo\" 1 }-10-{ Elt \"foo\" 11 }].out" new file mode 100644 index 000000000000..d2fdbcef71e5 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_map.tz-{ Elt \"foo\" 1 }-10-{ Elt \"foo\" 11 }].out" @@ -0,0 +1,50 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_map.tz-{ Elt "foo" 1 }-10-{ Elt "foo" 11 }] + +storage + { Elt "foo" 11 } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039989.800 units remaining) + [ (Pair 10 { Elt "foo" 1 }) ] + - location: 9 (remaining gas: 1039989.790 units remaining) + [ 10 @parameter + { Elt "foo" 1 } @storage ] + - location: 10 (remaining gas: 1039989.780 units remaining) + [ { Elt "foo" 1 } @storage + 10 @parameter ] + - location: 11 (remaining gas: 1039989.780 units remaining) + [ (Pair "foo" 1) + 10 @parameter ] + - location: 13 (remaining gas: 1039989.770 units remaining) + [ 1 @elt + 10 @parameter ] + - location: 14 (remaining gas: 1039989.755 units remaining) + [ 10 @parameter ] + - location: 16 (remaining gas: 1039989.745 units remaining) + [ 10 @parameter + 10 @parameter ] + - location: 14 (remaining gas: 1039989.715 units remaining) + [ 1 @elt + 10 @parameter + 10 @parameter ] + - location: 17 (remaining gas: 1039989.680 units remaining) + [ 11 + 10 @parameter ] + - location: 11 (remaining gas: 1039989.665 units remaining) + [ { Elt "foo" 11 } + 10 @parameter ] + - location: 18 (remaining gas: 1039989.650 units remaining) + [ 10 @parameter ] + - location: 20 (remaining gas: 1039989.640 units remaining) + [ ] + - location: 18 (remaining gas: 1039989.610 units remaining) + [ { Elt "foo" 11 } ] + - location: 21 (remaining gas: 1039989.595 units remaining) + [ {} + { Elt "foo" 11 } ] + - location: 23 (remaining gas: 1039989.580 units remaining) + [ (Pair {} { Elt "foo" 11 }) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_map.tz-{}-10-{}].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_map.tz-{}-10-{}].out new file mode 100644 index 000000000000..6146e3eae505 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_map.tz-{}-10-{}].out @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_map.tz-{}-10-{}] + +storage + {} +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039990.194 units remaining) + [ (Pair 10 {}) ] + - location: 9 (remaining gas: 1039990.184 units remaining) + [ 10 @parameter + {} @storage ] + - location: 10 (remaining gas: 1039990.174 units remaining) + [ {} @storage + 10 @parameter ] + - location: 11 (remaining gas: 1039990.174 units remaining) + [ {} + 10 @parameter ] + - location: 18 (remaining gas: 1039990.159 units remaining) + [ 10 @parameter ] + - location: 20 (remaining gas: 1039990.149 units remaining) + [ ] + - location: 18 (remaining gas: 1039990.119 units remaining) + [ {} ] + - location: 21 (remaining gas: 1039990.104 units remaining) + [ {} + {} ] + - location: 23 (remaining gas: 1039990.089 units remaining) + [ (Pair {} {}) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair { Elt 0 .7396e5f090.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair { Elt 0 .7396e5f090.out new file mode 100644 index 000000000000..0ed81a7056bd --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair { Elt 0 .7396e5f090.out @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 0 1 } None)-1-(Pair { Elt 0 1 } (Some False))] + +storage + (Pair { Elt 0 1 } (Some False)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039989.954 units remaining) + [ (Pair 1 { Elt 0 1 } None) ] + - location: 12 (remaining gas: 1039989.944 units remaining) + [ 1 @parameter + (Pair { Elt 0 1 } None) @storage ] + - location: 13 (remaining gas: 1039989.929 units remaining) + [ (Pair { Elt 0 1 } None) @storage ] + - location: 15 (remaining gas: 1039989.919 units remaining) + [ { Elt 0 1 } ] + - location: 16 (remaining gas: 1039989.909 units remaining) + [ { Elt 0 1 } + { Elt 0 1 } ] + - location: 13 (remaining gas: 1039989.879 units remaining) + [ 1 @parameter + { Elt 0 1 } + { Elt 0 1 } ] + - location: 17 (remaining gas: 1039989.729 units remaining) + [ False + { Elt 0 1 } ] + - location: 18 (remaining gas: 1039989.714 units remaining) + [ (Some False) + { Elt 0 1 } ] + - location: 19 (remaining gas: 1039989.704 units remaining) + [ { Elt 0 1 } + (Some False) ] + - location: 20 (remaining gas: 1039989.689 units remaining) + [ (Pair { Elt 0 1 } (Some False)) ] + - location: 21 (remaining gas: 1039989.674 units remaining) + [ {} + (Pair { Elt 0 1 } (Some False)) ] + - location: 23 (remaining gas: 1039989.659 units remaining) + [ (Pair {} { Elt 0 1 } (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair { Elt 1 .cef8ce601a.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair { Elt 1 .cef8ce601a.out new file mode 100644 index 000000000000..70e4be52f9e7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair { Elt 1 .cef8ce601a.out @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 0 } None)-1-(Pair { Elt 1 0 } (Some True))] + +storage + (Pair { Elt 1 0 } (Some True)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039989.954 units remaining) + [ (Pair 1 { Elt 1 0 } None) ] + - location: 12 (remaining gas: 1039989.944 units remaining) + [ 1 @parameter + (Pair { Elt 1 0 } None) @storage ] + - location: 13 (remaining gas: 1039989.929 units remaining) + [ (Pair { Elt 1 0 } None) @storage ] + - location: 15 (remaining gas: 1039989.919 units remaining) + [ { Elt 1 0 } ] + - location: 16 (remaining gas: 1039989.909 units remaining) + [ { Elt 1 0 } + { Elt 1 0 } ] + - location: 13 (remaining gas: 1039989.879 units remaining) + [ 1 @parameter + { Elt 1 0 } + { Elt 1 0 } ] + - location: 17 (remaining gas: 1039989.729 units remaining) + [ True + { Elt 1 0 } ] + - location: 18 (remaining gas: 1039989.714 units remaining) + [ (Some True) + { Elt 1 0 } ] + - location: 19 (remaining gas: 1039989.704 units remaining) + [ { Elt 1 0 } + (Some True) ] + - location: 20 (remaining gas: 1039989.689 units remaining) + [ (Pair { Elt 1 0 } (Some True)) ] + - location: 21 (remaining gas: 1039989.674 units remaining) + [ {} + (Pair { Elt 1 0 } (Some True)) ] + - location: 23 (remaining gas: 1039989.659 units remaining) + [ (Pair {} { Elt 1 0 } (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1-(Pa.1a55a5bfa5.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1-(Pa.1a55a5bfa5.out new file mode 100644 index 000000000000..0b3b3776e1cb --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1-(Pa.1a55a5bfa5.out @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-1-(Pair { Elt 1 4 ; Elt 2 11 } (Some True))] + +storage + (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039989.499 units remaining) + [ (Pair 1 { Elt 1 4 ; Elt 2 11 } None) ] + - location: 12 (remaining gas: 1039989.489 units remaining) + [ 1 @parameter + (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 13 (remaining gas: 1039989.474 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 15 (remaining gas: 1039989.464 units remaining) + [ { Elt 1 4 ; Elt 2 11 } ] + - location: 16 (remaining gas: 1039989.454 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 13 (remaining gas: 1039989.424 units remaining) + [ 1 @parameter + { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 17 (remaining gas: 1039989.239 units remaining) + [ True + { Elt 1 4 ; Elt 2 11 } ] + - location: 18 (remaining gas: 1039989.224 units remaining) + [ (Some True) + { Elt 1 4 ; Elt 2 11 } ] + - location: 19 (remaining gas: 1039989.214 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + (Some True) ] + - location: 20 (remaining gas: 1039989.199 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) ] + - location: 21 (remaining gas: 1039989.184 units remaining) + [ {} + (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) ] + - location: 23 (remaining gas: 1039989.169 units remaining) + [ (Pair {} { Elt 1 4 ; Elt 2 11 } (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2-(Pa.89cc24d256.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2-(Pa.89cc24d256.out new file mode 100644 index 000000000000..6f5f48a2705f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2-(Pa.89cc24d256.out @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-2-(Pair { Elt 1 4 ; Elt 2 11 } (Some True))] + +storage + (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039989.499 units remaining) + [ (Pair 2 { Elt 1 4 ; Elt 2 11 } None) ] + - location: 12 (remaining gas: 1039989.489 units remaining) + [ 2 @parameter + (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 13 (remaining gas: 1039989.474 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 15 (remaining gas: 1039989.464 units remaining) + [ { Elt 1 4 ; Elt 2 11 } ] + - location: 16 (remaining gas: 1039989.454 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 13 (remaining gas: 1039989.424 units remaining) + [ 2 @parameter + { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 17 (remaining gas: 1039989.239 units remaining) + [ True + { Elt 1 4 ; Elt 2 11 } ] + - location: 18 (remaining gas: 1039989.224 units remaining) + [ (Some True) + { Elt 1 4 ; Elt 2 11 } ] + - location: 19 (remaining gas: 1039989.214 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + (Some True) ] + - location: 20 (remaining gas: 1039989.199 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) ] + - location: 21 (remaining gas: 1039989.184 units remaining) + [ {} + (Pair { Elt 1 4 ; Elt 2 11 } (Some True)) ] + - location: 23 (remaining gas: 1039989.169 units remaining) + [ (Pair {} { Elt 1 4 ; Elt 2 11 } (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3-(Pa.2fba3165c0.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3-(Pa.2fba3165c0.out new file mode 100644 index 000000000000..dd8795ff0ea7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3-(Pa.2fba3165c0.out @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair { Elt 1 4 ; Elt 2 11 } None)-3-(Pair { Elt 1 4 ; Elt 2 11 } (Some False))] + +storage + (Pair { Elt 1 4 ; Elt 2 11 } (Some False)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039989.499 units remaining) + [ (Pair 3 { Elt 1 4 ; Elt 2 11 } None) ] + - location: 12 (remaining gas: 1039989.489 units remaining) + [ 3 @parameter + (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 13 (remaining gas: 1039989.474 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } None) @storage ] + - location: 15 (remaining gas: 1039989.464 units remaining) + [ { Elt 1 4 ; Elt 2 11 } ] + - location: 16 (remaining gas: 1039989.454 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 13 (remaining gas: 1039989.424 units remaining) + [ 3 @parameter + { Elt 1 4 ; Elt 2 11 } + { Elt 1 4 ; Elt 2 11 } ] + - location: 17 (remaining gas: 1039989.239 units remaining) + [ False + { Elt 1 4 ; Elt 2 11 } ] + - location: 18 (remaining gas: 1039989.224 units remaining) + [ (Some False) + { Elt 1 4 ; Elt 2 11 } ] + - location: 19 (remaining gas: 1039989.214 units remaining) + [ { Elt 1 4 ; Elt 2 11 } + (Some False) ] + - location: 20 (remaining gas: 1039989.199 units remaining) + [ (Pair { Elt 1 4 ; Elt 2 11 } (Some False)) ] + - location: 21 (remaining gas: 1039989.184 units remaining) + [ {} + (Pair { Elt 1 4 ; Elt 2 11 } (Some False)) ] + - location: 23 (remaining gas: 1039989.169 units remaining) + [ (Pair {} { Elt 1 4 ; Elt 2 11 } (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair {} None)-1-(Pair {} (Some False))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair {} None)-1-(Pair {} (Some False))].out new file mode 100644 index 000000000000..f1273aa655b0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair {} None)-1-(Pair {} (Some False))].out @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_mem_nat.tz-(Pair {} None)-1-(Pair {} (Some False))] + +storage + (Pair {} (Some False)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039990.304 units remaining) + [ (Pair 1 {} None) ] + - location: 12 (remaining gas: 1039990.294 units remaining) + [ 1 @parameter + (Pair {} None) @storage ] + - location: 13 (remaining gas: 1039990.279 units remaining) + [ (Pair {} None) @storage ] + - location: 15 (remaining gas: 1039990.269 units remaining) + [ {} ] + - location: 16 (remaining gas: 1039990.259 units remaining) + [ {} + {} ] + - location: 13 (remaining gas: 1039990.229 units remaining) + [ 1 @parameter + {} + {} ] + - location: 17 (remaining gas: 1039990.114 units remaining) + [ False + {} ] + - location: 18 (remaining gas: 1039990.099 units remaining) + [ (Some False) + {} ] + - location: 19 (remaining gas: 1039990.089 units remaining) + [ {} + (Some False) ] + - location: 20 (remaining gas: 1039990.074 units remaining) + [ (Pair {} (Some False)) ] + - location: 21 (remaining gas: 1039990.059 units remaining) + [ {} + (Pair {} (Some False)) ] + - location: 23 (remaining gas: 1039990.044 units remaining) + [ (Pair {} {} (Some False)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 11 } .6d625e02a5.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 11 } .6d625e02a5.out" new file mode 100644 index 000000000000..1db53c0e5dff --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 11 } .6d625e02a5.out" @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt "bar" 4 ; Elt "foo" 11 } None)-"bar"-(Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True))] + +storage + (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039989.367 units remaining) + [ (Pair "bar" { Elt "bar" 4 ; Elt "foo" 11 } None) ] + - location: 12 (remaining gas: 1039989.357 units remaining) + [ "bar" @parameter + (Pair { Elt "bar" 4 ; Elt "foo" 11 } None) @storage ] + - location: 13 (remaining gas: 1039989.342 units remaining) + [ (Pair { Elt "bar" 4 ; Elt "foo" 11 } None) @storage ] + - location: 15 (remaining gas: 1039989.332 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 16 (remaining gas: 1039989.322 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 13 (remaining gas: 1039989.292 units remaining) + [ "bar" @parameter + { Elt "bar" 4 ; Elt "foo" 11 } + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 17 (remaining gas: 1039989.107 units remaining) + [ True + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 18 (remaining gas: 1039989.092 units remaining) + [ (Some True) + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 19 (remaining gas: 1039989.082 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } + (Some True) ] + - location: 20 (remaining gas: 1039989.067 units remaining) + [ (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) ] + - location: 21 (remaining gas: 1039989.052 units remaining) + [ {} + (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) ] + - location: 23 (remaining gas: 1039989.037 units remaining) + [ (Pair {} { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 11 } .a7e3837a82.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 11 } .a7e3837a82.out" new file mode 100644 index 000000000000..7a165c8f6681 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 11 } .a7e3837a82.out" @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt "bar" 4 ; Elt "foo" 11 } None)-"foo"-(Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True))] + +storage + (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039989.367 units remaining) + [ (Pair "foo" { Elt "bar" 4 ; Elt "foo" 11 } None) ] + - location: 12 (remaining gas: 1039989.357 units remaining) + [ "foo" @parameter + (Pair { Elt "bar" 4 ; Elt "foo" 11 } None) @storage ] + - location: 13 (remaining gas: 1039989.342 units remaining) + [ (Pair { Elt "bar" 4 ; Elt "foo" 11 } None) @storage ] + - location: 15 (remaining gas: 1039989.332 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 16 (remaining gas: 1039989.322 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 13 (remaining gas: 1039989.292 units remaining) + [ "foo" @parameter + { Elt "bar" 4 ; Elt "foo" 11 } + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 17 (remaining gas: 1039989.107 units remaining) + [ True + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 18 (remaining gas: 1039989.092 units remaining) + [ (Some True) + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 19 (remaining gas: 1039989.082 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } + (Some True) ] + - location: 20 (remaining gas: 1039989.067 units remaining) + [ (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) ] + - location: 21 (remaining gas: 1039989.052 units remaining) + [ {} + (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) ] + - location: 23 (remaining gas: 1039989.037 units remaining) + [ (Pair {} { Elt "bar" 4 ; Elt "foo" 11 } (Some True)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 11 } .c7716fe79e.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 11 } .c7716fe79e.out" new file mode 100644 index 000000000000..0c4d9ed6ea24 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"bar\" 4 ; Elt \"foo\" 11 } .c7716fe79e.out" @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt "bar" 4 ; Elt "foo" 11 } None)-"baz"-(Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some False))] + +storage + (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some False)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039989.367 units remaining) + [ (Pair "baz" { Elt "bar" 4 ; Elt "foo" 11 } None) ] + - location: 12 (remaining gas: 1039989.357 units remaining) + [ "baz" @parameter + (Pair { Elt "bar" 4 ; Elt "foo" 11 } None) @storage ] + - location: 13 (remaining gas: 1039989.342 units remaining) + [ (Pair { Elt "bar" 4 ; Elt "foo" 11 } None) @storage ] + - location: 15 (remaining gas: 1039989.332 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 16 (remaining gas: 1039989.322 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 13 (remaining gas: 1039989.292 units remaining) + [ "baz" @parameter + { Elt "bar" 4 ; Elt "foo" 11 } + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 17 (remaining gas: 1039989.107 units remaining) + [ False + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 18 (remaining gas: 1039989.092 units remaining) + [ (Some False) + { Elt "bar" 4 ; Elt "foo" 11 } ] + - location: 19 (remaining gas: 1039989.082 units remaining) + [ { Elt "bar" 4 ; Elt "foo" 11 } + (Some False) ] + - location: 20 (remaining gas: 1039989.067 units remaining) + [ (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some False)) ] + - location: 21 (remaining gas: 1039989.052 units remaining) + [ {} + (Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some False)) ] + - location: 23 (remaining gas: 1039989.037 units remaining) + [ (Pair {} { Elt "bar" 4 ; Elt "foo" 11 } (Some False)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"foo\" 0 } None)-\"foo\"-(Pa.7861a3b1e2.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"foo\" 0 } None)-\"foo\"-(Pa.7861a3b1e2.out" new file mode 100644 index 000000000000..d5d39a25e98b --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"foo\" 0 } None)-\"foo\"-(Pa.7861a3b1e2.out" @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt "foo" 0 } None)-"foo"-(Pair { Elt "foo" 0 } (Some True))] + +storage + (Pair { Elt "foo" 0 } (Some True)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039989.866 units remaining) + [ (Pair "foo" { Elt "foo" 0 } None) ] + - location: 12 (remaining gas: 1039989.856 units remaining) + [ "foo" @parameter + (Pair { Elt "foo" 0 } None) @storage ] + - location: 13 (remaining gas: 1039989.841 units remaining) + [ (Pair { Elt "foo" 0 } None) @storage ] + - location: 15 (remaining gas: 1039989.831 units remaining) + [ { Elt "foo" 0 } ] + - location: 16 (remaining gas: 1039989.821 units remaining) + [ { Elt "foo" 0 } + { Elt "foo" 0 } ] + - location: 13 (remaining gas: 1039989.791 units remaining) + [ "foo" @parameter + { Elt "foo" 0 } + { Elt "foo" 0 } ] + - location: 17 (remaining gas: 1039989.641 units remaining) + [ True + { Elt "foo" 0 } ] + - location: 18 (remaining gas: 1039989.626 units remaining) + [ (Some True) + { Elt "foo" 0 } ] + - location: 19 (remaining gas: 1039989.616 units remaining) + [ { Elt "foo" 0 } + (Some True) ] + - location: 20 (remaining gas: 1039989.601 units remaining) + [ (Pair { Elt "foo" 0 } (Some True)) ] + - location: 21 (remaining gas: 1039989.586 units remaining) + [ {} + (Pair { Elt "foo" 0 } (Some True)) ] + - location: 23 (remaining gas: 1039989.571 units remaining) + [ (Pair {} { Elt "foo" 0 } (Some True)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"foo\" 1 } None)-\"bar\"-(Pa.fa8366e8a8.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"foo\" 1 } None)-\"bar\"-(Pa.fa8366e8a8.out" new file mode 100644 index 000000000000..3d6273c70141 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt \"foo\" 1 } None)-\"bar\"-(Pa.fa8366e8a8.out" @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair { Elt "foo" 1 } None)-"bar"-(Pair { Elt "foo" 1 } (Some False))] + +storage + (Pair { Elt "foo" 1 } (Some False)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039989.866 units remaining) + [ (Pair "bar" { Elt "foo" 1 } None) ] + - location: 12 (remaining gas: 1039989.856 units remaining) + [ "bar" @parameter + (Pair { Elt "foo" 1 } None) @storage ] + - location: 13 (remaining gas: 1039989.841 units remaining) + [ (Pair { Elt "foo" 1 } None) @storage ] + - location: 15 (remaining gas: 1039989.831 units remaining) + [ { Elt "foo" 1 } ] + - location: 16 (remaining gas: 1039989.821 units remaining) + [ { Elt "foo" 1 } + { Elt "foo" 1 } ] + - location: 13 (remaining gas: 1039989.791 units remaining) + [ "bar" @parameter + { Elt "foo" 1 } + { Elt "foo" 1 } ] + - location: 17 (remaining gas: 1039989.641 units remaining) + [ False + { Elt "foo" 1 } ] + - location: 18 (remaining gas: 1039989.626 units remaining) + [ (Some False) + { Elt "foo" 1 } ] + - location: 19 (remaining gas: 1039989.616 units remaining) + [ { Elt "foo" 1 } + (Some False) ] + - location: 20 (remaining gas: 1039989.601 units remaining) + [ (Pair { Elt "foo" 1 } (Some False)) ] + - location: 21 (remaining gas: 1039989.586 units remaining) + [ {} + (Pair { Elt "foo" 1 } (Some False)) ] + - location: 23 (remaining gas: 1039989.571 units remaining) + [ (Pair {} { Elt "foo" 1 } (Some False)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair {} None)-\"bar\"-(Pair {} (Some False))].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair {} None)-\"bar\"-(Pair {} (Some False))].out" new file mode 100644 index 000000000000..d0f0f87bd3fb --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair {} None)-\"bar\"-(Pair {} (Some False))].out" @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_mem_string.tz-(Pair {} None)-"bar"-(Pair {} (Some False))] + +storage + (Pair {} (Some False)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039990.260 units remaining) + [ (Pair "bar" {} None) ] + - location: 12 (remaining gas: 1039990.250 units remaining) + [ "bar" @parameter + (Pair {} None) @storage ] + - location: 13 (remaining gas: 1039990.235 units remaining) + [ (Pair {} None) @storage ] + - location: 15 (remaining gas: 1039990.225 units remaining) + [ {} ] + - location: 16 (remaining gas: 1039990.215 units remaining) + [ {} + {} ] + - location: 13 (remaining gas: 1039990.185 units remaining) + [ "bar" @parameter + {} + {} ] + - location: 17 (remaining gas: 1039990.070 units remaining) + [ False + {} ] + - location: 18 (remaining gas: 1039990.055 units remaining) + [ (Some False) + {} ] + - location: 19 (remaining gas: 1039990.045 units remaining) + [ {} + (Some False) ] + - location: 20 (remaining gas: 1039990.030 units remaining) + [ (Pair {} (Some False)) ] + - location: 21 (remaining gas: 1039990.015 units remaining) + [ {} + (Pair {} (Some False)) ] + - location: 23 (remaining gas: 1039990 units remaining) + [ (Pair {} {} (Some False)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt \"a\" 1 ; Elt \"b\" 2 ; Elt \"c\" 3 ; .1da2c2c3fa.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt \"a\" 1 ; Elt \"b\" 2 ; Elt \"c\" 3 ; .1da2c2c3fa.out" new file mode 100644 index 000000000000..56ad969793ed --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt \"a\" 1 ; Elt \"b\" 2 ; Elt \"c\" 3 ; .1da2c2c3fa.out" @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt "a" 1 ; Elt "b" 2 ; Elt "c" 3 ; Elt "d" 4 ; Elt "e" 5 ; Elt "f" 6 }-6] + +storage + 6 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039992.223 units remaining) + [ (Pair { Elt "a" 1 ; Elt "b" 2 ; Elt "c" 3 ; Elt "d" 4 ; Elt "e" 5 ; Elt "f" 6 } 111) ] + - location: 9 (remaining gas: 1039992.213 units remaining) + [ { Elt "a" 1 ; Elt "b" 2 ; Elt "c" 3 ; Elt "d" 4 ; Elt "e" 5 ; Elt "f" 6 } @parameter ] + - location: 10 (remaining gas: 1039992.198 units remaining) + [ 6 ] + - location: 11 (remaining gas: 1039992.183 units remaining) + [ {} + 6 ] + - location: 13 (remaining gas: 1039992.168 units remaining) + [ (Pair {} 6) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt \"a\" 1 ; Elt \"b\" 2 ; Elt \"c\" 3 }-3].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt \"a\" 1 ; Elt \"b\" 2 ; Elt \"c\" 3 }-3].out" new file mode 100644 index 000000000000..e03f0f7d9528 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt \"a\" 1 ; Elt \"b\" 2 ; Elt \"c\" 3 }-3].out" @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt "a" 1 ; Elt "b" 2 ; Elt "c" 3 }-3] + +storage + 3 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039994.010 units remaining) + [ (Pair { Elt "a" 1 ; Elt "b" 2 ; Elt "c" 3 } 111) ] + - location: 9 (remaining gas: 1039994 units remaining) + [ { Elt "a" 1 ; Elt "b" 2 ; Elt "c" 3 } @parameter ] + - location: 10 (remaining gas: 1039993.985 units remaining) + [ 3 ] + - location: 11 (remaining gas: 1039993.970 units remaining) + [ {} + 3 ] + - location: 13 (remaining gas: 1039993.955 units remaining) + [ (Pair {} 3) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt \"a\" 1 }-1].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt \"a\" 1 }-1].out" new file mode 100644 index 000000000000..99649393d7b3 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt \"a\" 1 }-1].out" @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_size.tz-111-{ Elt "a" 1 }-1] + +storage + 1 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039995.038 units remaining) + [ (Pair { Elt "a" 1 } 111) ] + - location: 9 (remaining gas: 1039995.028 units remaining) + [ { Elt "a" 1 } @parameter ] + - location: 10 (remaining gas: 1039995.013 units remaining) + [ 1 ] + - location: 11 (remaining gas: 1039994.998 units remaining) + [ {} + 1 ] + - location: 13 (remaining gas: 1039994.983 units remaining) + [ (Pair {} 1) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{}-0].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{}-0].out new file mode 100644 index 000000000000..1d0d19fbedc6 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[map_size.tz-111-{}-0].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[map_size.tz-111-{}-0] + +storage + 0 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039995.412 units remaining) + [ (Pair {} 111) ] + - location: 9 (remaining gas: 1039995.402 units remaining) + [ {} @parameter ] + - location: 10 (remaining gas: 1039995.387 units remaining) + [ 0 ] + - location: 11 (remaining gas: 1039995.372 units remaining) + [ {} + 0 ] + - location: 13 (remaining gas: 1039995.357 units remaining) + [ (Pair {} 0) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[mul.tz-Unit-Unit-Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[mul.tz-Unit-Unit-Unit].out new file mode 100644 index 000000000000..13d24c4d3ad8 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[mul.tz-Unit-Unit-Unit].out @@ -0,0 +1,131 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[mul.tz-Unit-Unit-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039946.376 units remaining) + [ (Pair Unit Unit) ] + - location: 7 (remaining gas: 1039946.366 units remaining) + [ Unit @parameter ] + - location: 8 (remaining gas: 1039946.356 units remaining) + [ ] + - location: 9 (remaining gas: 1039946.346 units remaining) + [ 7987 ] + - location: 12 (remaining gas: 1039946.336 units remaining) + [ 10 + 7987 ] + - location: 15 (remaining gas: 1039946.336 units remaining) + [ 79870 ] + - location: 16 (remaining gas: 1039946.326 units remaining) + [ 79870 + 79870 ] + - location: 19 (remaining gas: 1039946.291 units remaining) + [ 0 ] + - location: 21 (remaining gas: 1039946.276 units remaining) + [ True ] + - location: 22 (remaining gas: 1039946.266 units remaining) + [ ] + - location: 22 (remaining gas: 1039946.251 units remaining) + [ ] + - location: 28 (remaining gas: 1039946.241 units remaining) + [ 10 ] + - location: 31 (remaining gas: 1039946.231 units remaining) + [ 7987 + 10 ] + - location: 34 (remaining gas: 1039946.231 units remaining) + [ 79870 ] + - location: 35 (remaining gas: 1039946.221 units remaining) + [ 79870 + 79870 ] + - location: 38 (remaining gas: 1039946.186 units remaining) + [ 0 ] + - location: 40 (remaining gas: 1039946.171 units remaining) + [ True ] + - location: 41 (remaining gas: 1039946.161 units remaining) + [ ] + - location: 41 (remaining gas: 1039946.146 units remaining) + [ ] + - location: 47 (remaining gas: 1039946.136 units remaining) + [ 10 ] + - location: 50 (remaining gas: 1039946.126 units remaining) + [ -7987 + 10 ] + - location: 53 (remaining gas: 1039946.045 units remaining) + [ -79870 ] + - location: 54 (remaining gas: 1039946.035 units remaining) + [ -79870 + -79870 ] + - location: 57 (remaining gas: 1039946 units remaining) + [ 0 ] + - location: 59 (remaining gas: 1039945.985 units remaining) + [ True ] + - location: 60 (remaining gas: 1039945.975 units remaining) + [ ] + - location: 60 (remaining gas: 1039945.960 units remaining) + [ ] + - location: 66 (remaining gas: 1039945.950 units remaining) + [ 10 ] + - location: 69 (remaining gas: 1039945.940 units remaining) + [ -7987 + 10 ] + - location: 72 (remaining gas: 1039945.859 units remaining) + [ -79870 ] + - location: 73 (remaining gas: 1039945.849 units remaining) + [ -79870 + -79870 ] + - location: 76 (remaining gas: 1039945.814 units remaining) + [ 0 ] + - location: 78 (remaining gas: 1039945.799 units remaining) + [ True ] + - location: 79 (remaining gas: 1039945.789 units remaining) + [ ] + - location: 79 (remaining gas: 1039945.774 units remaining) + [ ] + - location: 85 (remaining gas: 1039945.764 units remaining) + [ -10 ] + - location: 88 (remaining gas: 1039945.754 units remaining) + [ 7987 + -10 ] + - location: 91 (remaining gas: 1039945.673 units remaining) + [ -79870 ] + - location: 92 (remaining gas: 1039945.663 units remaining) + [ -79870 + -79870 ] + - location: 95 (remaining gas: 1039945.628 units remaining) + [ 0 ] + - location: 97 (remaining gas: 1039945.613 units remaining) + [ True ] + - location: 98 (remaining gas: 1039945.603 units remaining) + [ ] + - location: 98 (remaining gas: 1039945.588 units remaining) + [ ] + - location: 104 (remaining gas: 1039945.578 units remaining) + [ 10 ] + - location: 107 (remaining gas: 1039945.568 units remaining) + [ 7987 + 10 ] + - location: 110 (remaining gas: 1039945.487 units remaining) + [ 79870 ] + - location: 111 (remaining gas: 1039945.477 units remaining) + [ 79870 + 79870 ] + - location: 114 (remaining gas: 1039945.442 units remaining) + [ 0 ] + - location: 116 (remaining gas: 1039945.427 units remaining) + [ True ] + - location: 117 (remaining gas: 1039945.417 units remaining) + [ ] + - location: 117 (remaining gas: 1039945.402 units remaining) + [ ] + - location: 123 (remaining gas: 1039945.392 units remaining) + [ Unit ] + - location: 124 (remaining gas: 1039945.377 units remaining) + [ {} + Unit ] + - location: 126 (remaining gas: 1039945.362 units remaining) + [ (Pair {} Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[mutez_to_bls12_381_fr.tz-0x00-257-0x0101000000000000000.be11332c7f.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[mutez_to_bls12_381_fr.tz-0x00-257-0x0101000000000000000.be11332c7f.out new file mode 100644 index 000000000000..d48b35da61ce --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[mutez_to_bls12_381_fr.tz-0x00-257-0x0101000000000000000.be11332c7f.out @@ -0,0 +1,38 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[mutez_to_bls12_381_fr.tz-0x00-257-0x0101000000000000000000000000000000000000000000000000000000000000] + +storage + 0x0101000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039988.633 units remaining) + [ (Pair 257 0x0000000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039988.623 units remaining) + [ 257 @parameter ] + - location: 8 (remaining gas: 1039988.613 units remaining) + [ 1 + 257 @parameter ] + - location: 11 (remaining gas: 1039988.603 units remaining) + [ 257 @parameter + 1 ] + - location: 12 (remaining gas: 1039988.538 units remaining) + [ (Some (Pair 257 0)) ] + - location: 14 (remaining gas: 1039988.528 units remaining) + [ (Pair 257 0) @some ] + - location: 14 (remaining gas: 1039988.513 units remaining) + [ (Pair 257 0) @some ] + - location: 20 (remaining gas: 1039988.503 units remaining) + [ 257 ] + - location: 21 (remaining gas: 1039988.493 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 + 257 ] + - location: 24 (remaining gas: 1039988.221 units remaining) + [ 0x0101000000000000000000000000000000000000000000000000000000000000 ] + - location: 25 (remaining gas: 1039988.206 units remaining) + [ {} + 0x0101000000000000000000000000000000000000000000000000000000000000 ] + - location: 27 (remaining gas: 1039988.191 units remaining) + [ (Pair {} 0x0101000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[mutez_to_bls12_381_fr.tz-0x02-16-0x10000000000000000000.8230fb4fac.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[mutez_to_bls12_381_fr.tz-0x02-16-0x10000000000000000000.8230fb4fac.out new file mode 100644 index 000000000000..eaa396724fd0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[mutez_to_bls12_381_fr.tz-0x02-16-0x10000000000000000000.8230fb4fac.out @@ -0,0 +1,38 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[mutez_to_bls12_381_fr.tz-0x02-16-0x1000000000000000000000000000000000000000000000000000000000000000] + +storage + 0x1000000000000000000000000000000000000000000000000000000000000000 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039988.633 units remaining) + [ (Pair 16 0x0200000000000000000000000000000000000000000000000000000000000000) ] + - location: 7 (remaining gas: 1039988.623 units remaining) + [ 16 @parameter ] + - location: 8 (remaining gas: 1039988.613 units remaining) + [ 1 + 16 @parameter ] + - location: 11 (remaining gas: 1039988.603 units remaining) + [ 16 @parameter + 1 ] + - location: 12 (remaining gas: 1039988.538 units remaining) + [ (Some (Pair 16 0)) ] + - location: 14 (remaining gas: 1039988.528 units remaining) + [ (Pair 16 0) @some ] + - location: 14 (remaining gas: 1039988.513 units remaining) + [ (Pair 16 0) @some ] + - location: 20 (remaining gas: 1039988.503 units remaining) + [ 16 ] + - location: 21 (remaining gas: 1039988.493 units remaining) + [ 0x0100000000000000000000000000000000000000000000000000000000000000 + 16 ] + - location: 24 (remaining gas: 1039988.222 units remaining) + [ 0x1000000000000000000000000000000000000000000000000000000000000000 ] + - location: 25 (remaining gas: 1039988.207 units remaining) + [ {} + 0x1000000000000000000000000000000000000000000000000000000000000000 ] + - location: 27 (remaining gas: 1039988.192 units remaining) + [ (Pair {} 0x1000000000000000000000000000000000000000000000000000000000000000) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left -2)-2].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left -2)-2].out new file mode 100644 index 000000000000..57b465ec7e80 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left -2)-2].out @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left -2)-2] + +storage + 2 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039993.541 units remaining) + [ (Pair (Left -2) 0) ] + - location: 9 (remaining gas: 1039993.531 units remaining) + [ (Left -2) @parameter ] + - location: 10 (remaining gas: 1039993.521 units remaining) + [ -2 @parameter.left ] + - location: 12 (remaining gas: 1039993.496 units remaining) + [ 2 ] + - location: 10 (remaining gas: 1039993.481 units remaining) + [ 2 ] + - location: 15 (remaining gas: 1039993.466 units remaining) + [ {} + 2 ] + - location: 17 (remaining gas: 1039993.451 units remaining) + [ (Pair {} 2) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left 0)-0].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left 0)-0].out new file mode 100644 index 000000000000..79ecd055d1b1 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left 0)-0].out @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left 0)-0] + +storage + 0 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039993.541 units remaining) + [ (Pair (Left 0) 0) ] + - location: 9 (remaining gas: 1039993.531 units remaining) + [ (Left 0) @parameter ] + - location: 10 (remaining gas: 1039993.521 units remaining) + [ 0 @parameter.left ] + - location: 12 (remaining gas: 1039993.496 units remaining) + [ 0 ] + - location: 10 (remaining gas: 1039993.481 units remaining) + [ 0 ] + - location: 15 (remaining gas: 1039993.466 units remaining) + [ {} + 0 ] + - location: 17 (remaining gas: 1039993.451 units remaining) + [ (Pair {} 0) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left 2)--2].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left 2)--2].out new file mode 100644 index 000000000000..8297a34441ba --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left 2)--2].out @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[neg.tz-0-(Left 2)--2] + +storage + -2 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039993.541 units remaining) + [ (Pair (Left 2) 0) ] + - location: 9 (remaining gas: 1039993.531 units remaining) + [ (Left 2) @parameter ] + - location: 10 (remaining gas: 1039993.521 units remaining) + [ 2 @parameter.left ] + - location: 12 (remaining gas: 1039993.496 units remaining) + [ -2 ] + - location: 10 (remaining gas: 1039993.481 units remaining) + [ -2 ] + - location: 15 (remaining gas: 1039993.466 units remaining) + [ {} + -2 ] + - location: 17 (remaining gas: 1039993.451 units remaining) + [ (Pair {} -2) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Right 0)-0].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Right 0)-0].out new file mode 100644 index 000000000000..5e8f1cc8389f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Right 0)-0].out @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[neg.tz-0-(Right 0)-0] + +storage + 0 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039993.541 units remaining) + [ (Pair (Right 0) 0) ] + - location: 9 (remaining gas: 1039993.531 units remaining) + [ (Right 0) @parameter ] + - location: 10 (remaining gas: 1039993.521 units remaining) + [ 0 @parameter.right ] + - location: 14 (remaining gas: 1039993.496 units remaining) + [ 0 ] + - location: 10 (remaining gas: 1039993.481 units remaining) + [ 0 ] + - location: 15 (remaining gas: 1039993.466 units remaining) + [ {} + 0 ] + - location: 17 (remaining gas: 1039993.451 units remaining) + [ (Pair {} 0) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Right 2)--2].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Right 2)--2].out new file mode 100644 index 000000000000..da34af024270 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[neg.tz-0-(Right 2)--2].out @@ -0,0 +1,25 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[neg.tz-0-(Right 2)--2] + +storage + -2 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039993.541 units remaining) + [ (Pair (Right 2) 0) ] + - location: 9 (remaining gas: 1039993.531 units remaining) + [ (Right 2) @parameter ] + - location: 10 (remaining gas: 1039993.521 units remaining) + [ 2 @parameter.right ] + - location: 14 (remaining gas: 1039993.496 units remaining) + [ -2 ] + - location: 10 (remaining gas: 1039993.481 units remaining) + [ -2 ] + - location: 15 (remaining gas: 1039993.466 units remaining) + [ {} + -2 ] + - location: 17 (remaining gas: 1039993.451 units remaining) + [ (Pair {} -2) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[none.tz-Some 10-Unit-None].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[none.tz-Some 10-Unit-None].out new file mode 100644 index 000000000000..dc383dbbf5ef --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[none.tz-Some 10-Unit-None].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[none.tz-Some 10-Unit-None] + +storage + None +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039995.227 units remaining) + [ (Pair Unit (Some 10)) ] + - location: 8 (remaining gas: 1039995.217 units remaining) + [ ] + - location: 9 (remaining gas: 1039995.202 units remaining) + [ None ] + - location: 11 (remaining gas: 1039995.187 units remaining) + [ {} + None ] + - location: 13 (remaining gas: 1039995.172 units remaining) + [ (Pair {} None) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not.tz-None-False-(Some True)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not.tz-None-False-(Some True)].out new file mode 100644 index 000000000000..24f733c3ec3c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not.tz-None-False-(Some True)].out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[not.tz-None-False-(Some True)] + +storage + (Some True) +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.857 units remaining) + [ (Pair False None) ] + - location: 8 (remaining gas: 1039994.847 units remaining) + [ False @parameter ] + - location: 9 (remaining gas: 1039994.837 units remaining) + [ True ] + - location: 10 (remaining gas: 1039994.822 units remaining) + [ (Some True) ] + - location: 11 (remaining gas: 1039994.807 units remaining) + [ {} + (Some True) ] + - location: 13 (remaining gas: 1039994.792 units remaining) + [ (Pair {} (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not.tz-None-True-(Some False)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not.tz-None-True-(Some False)].out new file mode 100644 index 000000000000..d05c59db69eb --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not.tz-None-True-(Some False)].out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[not.tz-None-True-(Some False)] + +storage + (Some False) +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.857 units remaining) + [ (Pair True None) ] + - location: 8 (remaining gas: 1039994.847 units remaining) + [ True @parameter ] + - location: 9 (remaining gas: 1039994.837 units remaining) + [ False ] + - location: 10 (remaining gas: 1039994.822 units remaining) + [ (Some False) ] + - location: 11 (remaining gas: 1039994.807 units remaining) + [ {} + (Some False) ] + - location: 13 (remaining gas: 1039994.792 units remaining) + [ (Pair {} (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left -8)-(Some 7)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left -8)-(Some 7)].out new file mode 100644 index 000000000000..6559bb7ccfdf --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left -8)-(Some 7)].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left -8)-(Some 7)] + +storage + (Some 7) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039992.720 units remaining) + [ (Pair (Left -8) None) ] + - location: 10 (remaining gas: 1039992.710 units remaining) + [ (Left -8) @parameter ] + - location: 11 (remaining gas: 1039992.700 units remaining) + [ -8 @parameter.left ] + - location: 13 (remaining gas: 1039992.675 units remaining) + [ 7 ] + - location: 11 (remaining gas: 1039992.660 units remaining) + [ 7 ] + - location: 16 (remaining gas: 1039992.645 units remaining) + [ (Some 7) ] + - location: 17 (remaining gas: 1039992.630 units remaining) + [ {} + (Some 7) ] + - location: 19 (remaining gas: 1039992.615 units remaining) + [ (Pair {} (Some 7)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left -9)-(Some 8)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left -9)-(Some 8)].out new file mode 100644 index 000000000000..7114c2c0ff5a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left -9)-(Some 8)].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left -9)-(Some 8)] + +storage + (Some 8) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039992.720 units remaining) + [ (Pair (Left -9) None) ] + - location: 10 (remaining gas: 1039992.710 units remaining) + [ (Left -9) @parameter ] + - location: 11 (remaining gas: 1039992.700 units remaining) + [ -9 @parameter.left ] + - location: 13 (remaining gas: 1039992.675 units remaining) + [ 8 ] + - location: 11 (remaining gas: 1039992.660 units remaining) + [ 8 ] + - location: 16 (remaining gas: 1039992.645 units remaining) + [ (Some 8) ] + - location: 17 (remaining gas: 1039992.630 units remaining) + [ {} + (Some 8) ] + - location: 19 (remaining gas: 1039992.615 units remaining) + [ (Pair {} (Some 8)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 0)-(Some -1)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 0)-(Some -1)].out new file mode 100644 index 000000000000..4592c47e32f5 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 0)-(Some -1)].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 0)-(Some -1)] + +storage + (Some -1) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039992.720 units remaining) + [ (Pair (Left 0) None) ] + - location: 10 (remaining gas: 1039992.710 units remaining) + [ (Left 0) @parameter ] + - location: 11 (remaining gas: 1039992.700 units remaining) + [ 0 @parameter.left ] + - location: 13 (remaining gas: 1039992.675 units remaining) + [ -1 ] + - location: 11 (remaining gas: 1039992.660 units remaining) + [ -1 ] + - location: 16 (remaining gas: 1039992.645 units remaining) + [ (Some -1) ] + - location: 17 (remaining gas: 1039992.630 units remaining) + [ {} + (Some -1) ] + - location: 19 (remaining gas: 1039992.615 units remaining) + [ (Pair {} (Some -1)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 7)-(Some -8)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 7)-(Some -8)].out new file mode 100644 index 000000000000..39b3c2123cdd --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 7)-(Some -8)].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 7)-(Some -8)] + +storage + (Some -8) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039992.720 units remaining) + [ (Pair (Left 7) None) ] + - location: 10 (remaining gas: 1039992.710 units remaining) + [ (Left 7) @parameter ] + - location: 11 (remaining gas: 1039992.700 units remaining) + [ 7 @parameter.left ] + - location: 13 (remaining gas: 1039992.675 units remaining) + [ -8 ] + - location: 11 (remaining gas: 1039992.660 units remaining) + [ -8 ] + - location: 16 (remaining gas: 1039992.645 units remaining) + [ (Some -8) ] + - location: 17 (remaining gas: 1039992.630 units remaining) + [ {} + (Some -8) ] + - location: 19 (remaining gas: 1039992.615 units remaining) + [ (Pair {} (Some -8)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 8)-(Some -9)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 8)-(Some -9)].out new file mode 100644 index 000000000000..49e82a95e87c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 8)-(Some -9)].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Left 8)-(Some -9)] + +storage + (Some -9) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039992.720 units remaining) + [ (Pair (Left 8) None) ] + - location: 10 (remaining gas: 1039992.710 units remaining) + [ (Left 8) @parameter ] + - location: 11 (remaining gas: 1039992.700 units remaining) + [ 8 @parameter.left ] + - location: 13 (remaining gas: 1039992.675 units remaining) + [ -9 ] + - location: 11 (remaining gas: 1039992.660 units remaining) + [ -9 ] + - location: 16 (remaining gas: 1039992.645 units remaining) + [ (Some -9) ] + - location: 17 (remaining gas: 1039992.630 units remaining) + [ {} + (Some -9) ] + - location: 19 (remaining gas: 1039992.615 units remaining) + [ (Pair {} (Some -9)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 0)-(Some -1)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 0)-(Some -1)].out new file mode 100644 index 000000000000..ad84f46e69ac --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 0)-(Some -1)].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 0)-(Some -1)] + +storage + (Some -1) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039992.720 units remaining) + [ (Pair (Right 0) None) ] + - location: 10 (remaining gas: 1039992.710 units remaining) + [ (Right 0) @parameter ] + - location: 11 (remaining gas: 1039992.700 units remaining) + [ 0 @parameter.right ] + - location: 15 (remaining gas: 1039992.675 units remaining) + [ -1 ] + - location: 11 (remaining gas: 1039992.660 units remaining) + [ -1 ] + - location: 16 (remaining gas: 1039992.645 units remaining) + [ (Some -1) ] + - location: 17 (remaining gas: 1039992.630 units remaining) + [ {} + (Some -1) ] + - location: 19 (remaining gas: 1039992.615 units remaining) + [ (Pair {} (Some -1)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 7)-(Some -8)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 7)-(Some -8)].out new file mode 100644 index 000000000000..ad9b3c794a69 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 7)-(Some -8)].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 7)-(Some -8)] + +storage + (Some -8) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039992.720 units remaining) + [ (Pair (Right 7) None) ] + - location: 10 (remaining gas: 1039992.710 units remaining) + [ (Right 7) @parameter ] + - location: 11 (remaining gas: 1039992.700 units remaining) + [ 7 @parameter.right ] + - location: 15 (remaining gas: 1039992.675 units remaining) + [ -8 ] + - location: 11 (remaining gas: 1039992.660 units remaining) + [ -8 ] + - location: 16 (remaining gas: 1039992.645 units remaining) + [ (Some -8) ] + - location: 17 (remaining gas: 1039992.630 units remaining) + [ {} + (Some -8) ] + - location: 19 (remaining gas: 1039992.615 units remaining) + [ (Pair {} (Some -8)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 8)-(Some -9)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 8)-(Some -9)].out new file mode 100644 index 000000000000..18aab398023e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 8)-(Some -9)].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[not_binary.tz-None-(Right 8)-(Some -9)] + +storage + (Some -9) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039992.720 units remaining) + [ (Pair (Right 8) None) ] + - location: 10 (remaining gas: 1039992.710 units remaining) + [ (Right 8) @parameter ] + - location: 11 (remaining gas: 1039992.700 units remaining) + [ 8 @parameter.right ] + - location: 15 (remaining gas: 1039992.675 units remaining) + [ -9 ] + - location: 11 (remaining gas: 1039992.660 units remaining) + [ -9 ] + - location: 16 (remaining gas: 1039992.645 units remaining) + [ (Some -9) ] + - location: 17 (remaining gas: 1039992.630 units remaining) + [ {} + (Some -9) ] + - location: 19 (remaining gas: 1039992.615 units remaining) + [ (Pair {} (Some -9)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair False False)-(Some False)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair False False)-(Some False)].out new file mode 100644 index 000000000000..52b0d947bd20 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair False False)-(Some False)].out @@ -0,0 +1,35 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair False False)-(Some False)] + +storage + (Some False) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039991.615 units remaining) + [ (Pair (Pair False False) None) ] + - location: 10 (remaining gas: 1039991.605 units remaining) + [ (Pair False False) @parameter ] + - location: 11 (remaining gas: 1039991.595 units remaining) + [ (Pair False False) @parameter + (Pair False False) @parameter ] + - location: 12 (remaining gas: 1039991.585 units remaining) + [ False + (Pair False False) @parameter ] + - location: 13 (remaining gas: 1039991.575 units remaining) + [ (Pair False False) @parameter + False ] + - location: 14 (remaining gas: 1039991.565 units remaining) + [ False + False ] + - location: 15 (remaining gas: 1039991.550 units remaining) + [ False ] + - location: 16 (remaining gas: 1039991.535 units remaining) + [ (Some False) ] + - location: 17 (remaining gas: 1039991.520 units remaining) + [ {} + (Some False) ] + - location: 19 (remaining gas: 1039991.505 units remaining) + [ (Pair {} (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair False True)-(Some True)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair False True)-(Some True)].out new file mode 100644 index 000000000000..c3a5f651b463 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair False True)-(Some True)].out @@ -0,0 +1,35 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair False True)-(Some True)] + +storage + (Some True) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039991.615 units remaining) + [ (Pair (Pair False True) None) ] + - location: 10 (remaining gas: 1039991.605 units remaining) + [ (Pair False True) @parameter ] + - location: 11 (remaining gas: 1039991.595 units remaining) + [ (Pair False True) @parameter + (Pair False True) @parameter ] + - location: 12 (remaining gas: 1039991.585 units remaining) + [ False + (Pair False True) @parameter ] + - location: 13 (remaining gas: 1039991.575 units remaining) + [ (Pair False True) @parameter + False ] + - location: 14 (remaining gas: 1039991.565 units remaining) + [ True + False ] + - location: 15 (remaining gas: 1039991.550 units remaining) + [ True ] + - location: 16 (remaining gas: 1039991.535 units remaining) + [ (Some True) ] + - location: 17 (remaining gas: 1039991.520 units remaining) + [ {} + (Some True) ] + - location: 19 (remaining gas: 1039991.505 units remaining) + [ (Pair {} (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair True False)-(Some True)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair True False)-(Some True)].out new file mode 100644 index 000000000000..b7690993d75e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair True False)-(Some True)].out @@ -0,0 +1,35 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair True False)-(Some True)] + +storage + (Some True) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039991.615 units remaining) + [ (Pair (Pair True False) None) ] + - location: 10 (remaining gas: 1039991.605 units remaining) + [ (Pair True False) @parameter ] + - location: 11 (remaining gas: 1039991.595 units remaining) + [ (Pair True False) @parameter + (Pair True False) @parameter ] + - location: 12 (remaining gas: 1039991.585 units remaining) + [ True + (Pair True False) @parameter ] + - location: 13 (remaining gas: 1039991.575 units remaining) + [ (Pair True False) @parameter + True ] + - location: 14 (remaining gas: 1039991.565 units remaining) + [ False + True ] + - location: 15 (remaining gas: 1039991.550 units remaining) + [ True ] + - location: 16 (remaining gas: 1039991.535 units remaining) + [ (Some True) ] + - location: 17 (remaining gas: 1039991.520 units remaining) + [ {} + (Some True) ] + - location: 19 (remaining gas: 1039991.505 units remaining) + [ (Pair {} (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair True True)-(Some True)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair True True)-(Some True)].out new file mode 100644 index 000000000000..f41ec2de9949 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair True True)-(Some True)].out @@ -0,0 +1,35 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[or.tz-None-(Pair True True)-(Some True)] + +storage + (Some True) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039991.615 units remaining) + [ (Pair (Pair True True) None) ] + - location: 10 (remaining gas: 1039991.605 units remaining) + [ (Pair True True) @parameter ] + - location: 11 (remaining gas: 1039991.595 units remaining) + [ (Pair True True) @parameter + (Pair True True) @parameter ] + - location: 12 (remaining gas: 1039991.585 units remaining) + [ True + (Pair True True) @parameter ] + - location: 13 (remaining gas: 1039991.575 units remaining) + [ (Pair True True) @parameter + True ] + - location: 14 (remaining gas: 1039991.565 units remaining) + [ True + True ] + - location: 15 (remaining gas: 1039991.550 units remaining) + [ True ] + - location: 16 (remaining gas: 1039991.535 units remaining) + [ (Some True) ] + - location: 17 (remaining gas: 1039991.520 units remaining) + [ {} + (Some True) ] + - location: 19 (remaining gas: 1039991.505 units remaining) + [ (Pair {} (Some True)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 0 8)-(Some 8)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 0 8)-(Some 8)].out new file mode 100644 index 000000000000..015a3cd08c93 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 0 8)-(Some 8)].out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 0 8)-(Some 8)] + +storage + (Some 8) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039993.724 units remaining) + [ (Pair (Pair 0 8) None) ] + - location: 10 (remaining gas: 1039993.714 units remaining) + [ (Pair 0 8) @parameter ] + - location: 11 (remaining gas: 1039993.704 units remaining) + [ 0 + 8 ] + - location: 12 (remaining gas: 1039993.669 units remaining) + [ 8 ] + - location: 13 (remaining gas: 1039993.654 units remaining) + [ (Some 8) ] + - location: 14 (remaining gas: 1039993.639 units remaining) + [ {} + (Some 8) ] + - location: 16 (remaining gas: 1039993.624 units remaining) + [ (Pair {} (Some 8)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 14 1)-(Some 15)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 14 1)-(Some 15)].out new file mode 100644 index 000000000000..a2e6ba6dfcd9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 14 1)-(Some 15)].out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 14 1)-(Some 15)] + +storage + (Some 15) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039993.724 units remaining) + [ (Pair (Pair 14 1) None) ] + - location: 10 (remaining gas: 1039993.714 units remaining) + [ (Pair 14 1) @parameter ] + - location: 11 (remaining gas: 1039993.704 units remaining) + [ 14 + 1 ] + - location: 12 (remaining gas: 1039993.669 units remaining) + [ 15 ] + - location: 13 (remaining gas: 1039993.654 units remaining) + [ (Some 15) ] + - location: 14 (remaining gas: 1039993.639 units remaining) + [ {} + (Some 15) ] + - location: 16 (remaining gas: 1039993.624 units remaining) + [ (Pair {} (Some 15)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 15 4)-(Some 15)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 15 4)-(Some 15)].out new file mode 100644 index 000000000000..ae6d6146ffaf --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 15 4)-(Some 15)].out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 15 4)-(Some 15)] + +storage + (Some 15) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039993.724 units remaining) + [ (Pair (Pair 15 4) None) ] + - location: 10 (remaining gas: 1039993.714 units remaining) + [ (Pair 15 4) @parameter ] + - location: 11 (remaining gas: 1039993.704 units remaining) + [ 15 + 4 ] + - location: 12 (remaining gas: 1039993.669 units remaining) + [ 15 ] + - location: 13 (remaining gas: 1039993.654 units remaining) + [ (Some 15) ] + - location: 14 (remaining gas: 1039993.639 units remaining) + [ {} + (Some 15) ] + - location: 16 (remaining gas: 1039993.624 units remaining) + [ (Pair {} (Some 15)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 4 8)-(Some 12)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 4 8)-(Some 12)].out new file mode 100644 index 000000000000..453fad79e5d9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 4 8)-(Some 12)].out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 4 8)-(Some 12)] + +storage + (Some 12) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039993.724 units remaining) + [ (Pair (Pair 4 8) None) ] + - location: 10 (remaining gas: 1039993.714 units remaining) + [ (Pair 4 8) @parameter ] + - location: 11 (remaining gas: 1039993.704 units remaining) + [ 4 + 8 ] + - location: 12 (remaining gas: 1039993.669 units remaining) + [ 12 ] + - location: 13 (remaining gas: 1039993.654 units remaining) + [ (Some 12) ] + - location: 14 (remaining gas: 1039993.639 units remaining) + [ {} + (Some 12) ] + - location: 16 (remaining gas: 1039993.624 units remaining) + [ (Pair {} (Some 12)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 7 7)-(Some 7)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 7 7)-(Some 7)].out new file mode 100644 index 000000000000..6c995d7e409b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 7 7)-(Some 7)].out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 7 7)-(Some 7)] + +storage + (Some 7) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039993.724 units remaining) + [ (Pair (Pair 7 7) None) ] + - location: 10 (remaining gas: 1039993.714 units remaining) + [ (Pair 7 7) @parameter ] + - location: 11 (remaining gas: 1039993.704 units remaining) + [ 7 + 7 ] + - location: 12 (remaining gas: 1039993.669 units remaining) + [ 7 ] + - location: 13 (remaining gas: 1039993.654 units remaining) + [ (Some 7) ] + - location: 14 (remaining gas: 1039993.639 units remaining) + [ {} + (Some 7) ] + - location: 16 (remaining gas: 1039993.624 units remaining) + [ (Pair {} (Some 7)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 8 0)-(Some 8)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 8 0)-(Some 8)].out new file mode 100644 index 000000000000..3655fe97b7d8 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 8 0)-(Some 8)].out @@ -0,0 +1,26 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[or_binary.tz-None-(Pair 8 0)-(Some 8)] + +storage + (Some 8) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039993.724 units remaining) + [ (Pair (Pair 8 0) None) ] + - location: 10 (remaining gas: 1039993.714 units remaining) + [ (Pair 8 0) @parameter ] + - location: 11 (remaining gas: 1039993.704 units remaining) + [ 8 + 0 ] + - location: 12 (remaining gas: 1039993.669 units remaining) + [ 8 ] + - location: 13 (remaining gas: 1039993.654 units remaining) + [ (Some 8) ] + - location: 14 (remaining gas: 1039993.639 units remaining) + [ {} + (Some 8) ] + - location: 16 (remaining gas: 1039993.624 units remaining) + [ (Pair {} (Some 8)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev.tz-Unit-(Pair -1 (Pair 1 (Pair \"foobar\".368bdfd73a.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev.tz-Unit-(Pair -1 (Pair 1 (Pair \"foobar\".368bdfd73a.out" new file mode 100644 index 000000000000..561b6ea6f244 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev.tz-Unit-(Pair -1 (Pair 1 (Pair \"foobar\".368bdfd73a.out" @@ -0,0 +1,845 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[packunpack_rev.tz-Unit-(Pair -1 (Pair 1 (Pair "foobar" (Pair 0x00AABBCC (Pair 1000 (Pair False (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5"))))))))-Unit1] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 16 (remaining gas: 1039783.825 units remaining) + [ (Pair (Pair -1 + 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + Unit) ] + - location: 16 (remaining gas: 1039783.815 units remaining) + [ (Pair -1 + 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @parameter ] + - location: 17 (remaining gas: 1039783.805 units remaining) + [ (Pair -1 + 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @parameter + (Pair -1 + 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @parameter ] + - location: 18 (remaining gas: 1039783.795 units remaining) + [ -1 + (Pair -1 + 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @parameter ] + - location: 19 (remaining gas: 1039783.780 units remaining) + [ (Pair -1 + 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @parameter ] + - location: 21 (remaining gas: 1039783.770 units remaining) + [ -1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 19 (remaining gas: 1039783.740 units remaining) + [ -1 + -1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 22 (remaining gas: 1039783.479 units remaining) + [ 0x050041 @packed + -1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 23 (remaining gas: 1039783.219 units remaining) + [ (Some -1) @packed.unpacked + -1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 26 (remaining gas: 1039783.209 units remaining) + [ -1 @packed.unpacked.some + -1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 26 (remaining gas: 1039783.194 units remaining) + [ -1 @packed.unpacked.some + -1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 34 (remaining gas: 1039783.159 units remaining) + [ 0 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 35 (remaining gas: 1039783.144 units remaining) + [ True + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 36 (remaining gas: 1039783.134 units remaining) + [ (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 36 (remaining gas: 1039783.119 units remaining) + [ (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 42 (remaining gas: 1039783.109 units remaining) + [ (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 43 (remaining gas: 1039783.099 units remaining) + [ 1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 44 (remaining gas: 1039783.084 units remaining) + [ (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 46 (remaining gas: 1039783.074 units remaining) + [ 1 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 44 (remaining gas: 1039783.044 units remaining) + [ 1 + 1 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 47 (remaining gas: 1039782.783 units remaining) + [ 0x050001 @packed + 1 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 48 (remaining gas: 1039782.523 units remaining) + [ (Some 1) @packed.unpacked + 1 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 51 (remaining gas: 1039782.513 units remaining) + [ 1 @packed.unpacked.some + 1 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 51 (remaining gas: 1039782.498 units remaining) + [ 1 @packed.unpacked.some + 1 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 59 (remaining gas: 1039782.463 units remaining) + [ 0 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 60 (remaining gas: 1039782.448 units remaining) + [ True + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 61 (remaining gas: 1039782.438 units remaining) + [ (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 61 (remaining gas: 1039782.423 units remaining) + [ (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 67 (remaining gas: 1039782.413 units remaining) + [ (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 68 (remaining gas: 1039782.403 units remaining) + [ "foobar" + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 69 (remaining gas: 1039782.388 units remaining) + [ (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 71 (remaining gas: 1039782.378 units remaining) + [ "foobar" + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 69 (remaining gas: 1039782.348 units remaining) + [ "foobar" + "foobar" + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 72 (remaining gas: 1039781.493 units remaining) + [ 0x050100000006666f6f626172 @packed + "foobar" + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 73 (remaining gas: 1039780.978 units remaining) + [ (Some "foobar") @packed.unpacked + "foobar" + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 76 (remaining gas: 1039780.968 units remaining) + [ "foobar" @packed.unpacked.some + "foobar" + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 76 (remaining gas: 1039780.953 units remaining) + [ "foobar" @packed.unpacked.some + "foobar" + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 84 (remaining gas: 1039780.918 units remaining) + [ 0 + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 85 (remaining gas: 1039780.903 units remaining) + [ True + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 86 (remaining gas: 1039780.893 units remaining) + [ (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 86 (remaining gas: 1039780.878 units remaining) + [ (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 92 (remaining gas: 1039780.868 units remaining) + [ (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 93 (remaining gas: 1039780.858 units remaining) + [ 0x00aabbcc + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 94 (remaining gas: 1039780.843 units remaining) + [ (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 96 (remaining gas: 1039780.833 units remaining) + [ 0x00aabbcc + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 94 (remaining gas: 1039780.803 units remaining) + [ 0x00aabbcc + 0x00aabbcc + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 97 (remaining gas: 1039780.080 units remaining) + [ 0x050a0000000400aabbcc @packed + 0x00aabbcc + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 98 (remaining gas: 1039779.679 units remaining) + [ (Some 0x00aabbcc) @packed.unpacked + 0x00aabbcc + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 101 (remaining gas: 1039779.669 units remaining) + [ 0x00aabbcc @packed.unpacked.some + 0x00aabbcc + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 101 (remaining gas: 1039779.654 units remaining) + [ 0x00aabbcc @packed.unpacked.some + 0x00aabbcc + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 109 (remaining gas: 1039779.619 units remaining) + [ 0 + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 110 (remaining gas: 1039779.604 units remaining) + [ True + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 111 (remaining gas: 1039779.594 units remaining) + [ (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 111 (remaining gas: 1039779.579 units remaining) + [ (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 117 (remaining gas: 1039779.569 units remaining) + [ (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 118 (remaining gas: 1039779.559 units remaining) + [ 1000 + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 119 (remaining gas: 1039779.544 units remaining) + [ (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 121 (remaining gas: 1039779.534 units remaining) + [ 1000 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 119 (remaining gas: 1039779.504 units remaining) + [ 1000 + 1000 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 122 (remaining gas: 1039779.177 units remaining) + [ 0x0500a80f @packed + 1000 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 123 (remaining gas: 1039778.897 units remaining) + [ (Some 1000) @packed.unpacked + 1000 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 126 (remaining gas: 1039778.887 units remaining) + [ 1000 @packed.unpacked.some + 1000 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 126 (remaining gas: 1039778.872 units remaining) + [ 1000 @packed.unpacked.some + 1000 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 134 (remaining gas: 1039778.837 units remaining) + [ 0 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 135 (remaining gas: 1039778.822 units remaining) + [ True + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 136 (remaining gas: 1039778.812 units remaining) + [ (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 136 (remaining gas: 1039778.797 units remaining) + [ (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 142 (remaining gas: 1039778.787 units remaining) + [ (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 143 (remaining gas: 1039778.777 units remaining) + [ False + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 144 (remaining gas: 1039778.762 units remaining) + [ (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 146 (remaining gas: 1039778.752 units remaining) + [ False + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 144 (remaining gas: 1039778.722 units remaining) + [ False + False + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 147 (remaining gas: 1039778.461 units remaining) + [ 0x050303 @packed + False + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 148 (remaining gas: 1039778.201 units remaining) + [ (Some False) @packed.unpacked + False + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 151 (remaining gas: 1039778.191 units remaining) + [ False @packed.unpacked.some + False + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 151 (remaining gas: 1039778.176 units remaining) + [ False @packed.unpacked.some + False + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 159 (remaining gas: 1039778.141 units remaining) + [ 0 + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 160 (remaining gas: 1039778.126 units remaining) + [ True + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 161 (remaining gas: 1039778.116 units remaining) + [ (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 161 (remaining gas: 1039778.101 units remaining) + [ (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 167 (remaining gas: 1039778.091 units remaining) + [ (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 168 (remaining gas: 1039778.081 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 169 (remaining gas: 1039778.066 units remaining) + [ (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 171 (remaining gas: 1039778.056 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 169 (remaining gas: 1039778.026 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 172 (remaining gas: 1039776.101 units remaining) + [ 0x050a0000001500bdfe3885e846fdea23c9acbe3bb1cfcca9c03e4a @packed + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 173 (remaining gas: 1039775.308 units remaining) + [ (Some "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @packed.unpacked + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 176 (remaining gas: 1039775.298 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" @packed.unpacked.some + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 176 (remaining gas: 1039775.283 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" @packed.unpacked.some + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 184 (remaining gas: 1039775.247 units remaining) + [ 0 + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 185 (remaining gas: 1039775.232 units remaining) + [ True + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 186 (remaining gas: 1039775.222 units remaining) + [ (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 186 (remaining gas: 1039775.207 units remaining) + [ (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 192 (remaining gas: 1039775.197 units remaining) + [ (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 193 (remaining gas: 1039775.187 units remaining) + [ "2019-09-09T08:35:33Z" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 194 (remaining gas: 1039775.172 units remaining) + [ (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 196 (remaining gas: 1039775.162 units remaining) + [ "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 194 (remaining gas: 1039775.132 units remaining) + [ "2019-09-09T08:35:33Z" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 197 (remaining gas: 1039774.607 units remaining) + [ 0x050095bbb0d70b @packed + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 198 (remaining gas: 1039774.267 units remaining) + [ (Some "2019-09-09T08:35:33Z") @packed.unpacked + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 201 (remaining gas: 1039774.257 units remaining) + [ "2019-09-09T08:35:33Z" @packed.unpacked.some + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 201 (remaining gas: 1039774.242 units remaining) + [ "2019-09-09T08:35:33Z" @packed.unpacked.some + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 209 (remaining gas: 1039774.207 units remaining) + [ 0 + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 210 (remaining gas: 1039774.192 units remaining) + [ True + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 211 (remaining gas: 1039774.182 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 211 (remaining gas: 1039774.167 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 217 (remaining gas: 1039774.157 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 218 (remaining gas: 1039762.846 units remaining) + [ 0x050a000000160000bdfe3885e846fdea23c9acbe3bb1cfcca9c03e4a @packed + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 219 (remaining gas: 1039708.083 units remaining) + [ (Some "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @packed.unpacked + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 222 (remaining gas: 1039708.073 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" @packed.unpacked.some + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 222 (remaining gas: 1039708.058 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" @packed.unpacked.some + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 230 (remaining gas: 1039708.022 units remaining) + [ 0 ] + - location: 231 (remaining gas: 1039708.007 units remaining) + [ True ] + - location: 232 (remaining gas: 1039707.997 units remaining) + [ ] + - location: 232 (remaining gas: 1039707.982 units remaining) + [ ] + - location: 238 (remaining gas: 1039707.972 units remaining) + [ 0 ] + - location: 241 (remaining gas: 1039707.711 units remaining) + [ 0x050000 @packed ] + - location: 242 (remaining gas: 1039707.451 units remaining) + [ (Some 0) @packed.unpacked ] + - location: 245 (remaining gas: 1039707.441 units remaining) + [ 0 @packed.unpacked.some ] + - location: 245 (remaining gas: 1039707.426 units remaining) + [ 0 @packed.unpacked.some ] + - location: 251 (remaining gas: 1039707.416 units remaining) + [ ] + - location: 252 (remaining gas: 1039707.406 units remaining) + [ -1 ] + - location: 255 (remaining gas: 1039707.145 units remaining) + [ 0x050041 @packed ] + - location: 256 (remaining gas: 1039610.985 units remaining) + [ None @packed.unpacked ] + - location: 259 (remaining gas: 1039610.975 units remaining) + [ ] + - location: 259 (remaining gas: 1039610.960 units remaining) + [ ] + - location: 265 (remaining gas: 1039610.950 units remaining) + [ 0x ] + - location: 268 (remaining gas: 1039610.850 units remaining) + [ None @unpacked ] + - location: 271 (remaining gas: 1039610.840 units remaining) + [ ] + - location: 271 (remaining gas: 1039610.825 units remaining) + [ ] + - location: 277 (remaining gas: 1039610.815 units remaining) + [ 0x04 ] + - location: 280 (remaining gas: 1039610.695 units remaining) + [ None @unpacked ] + - location: 283 (remaining gas: 1039610.685 units remaining) + [ ] + - location: 283 (remaining gas: 1039610.670 units remaining) + [ ] + - location: 289 (remaining gas: 1039610.660 units remaining) + [ 0x05 ] + - location: 292 (remaining gas: 1039610.540 units remaining) + [ None @unpacked ] + - location: 295 (remaining gas: 1039610.530 units remaining) + [ ] + - location: 295 (remaining gas: 1039610.515 units remaining) + [ ] + - location: 301 (remaining gas: 1039610.505 units remaining) + [ Unit ] + - location: 302 (remaining gas: 1039610.490 units remaining) + [ {} + Unit ] + - location: 304 (remaining gas: 1039610.475 units remaining) + [ (Pair {} Unit) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev.tz-Unit-(Pair -1 (Pair 1 (Pair \"foobar\".735d9ae802.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev.tz-Unit-(Pair -1 (Pair 1 (Pair \"foobar\".735d9ae802.out" new file mode 100644 index 000000000000..fa7514d5caa9 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev.tz-Unit-(Pair -1 (Pair 1 (Pair \"foobar\".735d9ae802.out" @@ -0,0 +1,845 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[packunpack_rev.tz-Unit-(Pair -1 (Pair 1 (Pair "foobar" (Pair 0x00AABBCC (Pair 1000 (Pair False (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5"))))))))-Unit0] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 16 (remaining gas: 1039783.825 units remaining) + [ (Pair (Pair -1 + 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + Unit) ] + - location: 16 (remaining gas: 1039783.815 units remaining) + [ (Pair -1 + 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @parameter ] + - location: 17 (remaining gas: 1039783.805 units remaining) + [ (Pair -1 + 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @parameter + (Pair -1 + 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @parameter ] + - location: 18 (remaining gas: 1039783.795 units remaining) + [ -1 + (Pair -1 + 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @parameter ] + - location: 19 (remaining gas: 1039783.780 units remaining) + [ (Pair -1 + 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @parameter ] + - location: 21 (remaining gas: 1039783.770 units remaining) + [ -1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 19 (remaining gas: 1039783.740 units remaining) + [ -1 + -1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 22 (remaining gas: 1039783.479 units remaining) + [ 0x050041 @packed + -1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 23 (remaining gas: 1039783.219 units remaining) + [ (Some -1) @packed.unpacked + -1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 26 (remaining gas: 1039783.209 units remaining) + [ -1 @packed.unpacked.some + -1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 26 (remaining gas: 1039783.194 units remaining) + [ -1 @packed.unpacked.some + -1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 34 (remaining gas: 1039783.159 units remaining) + [ 0 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 35 (remaining gas: 1039783.144 units remaining) + [ True + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 36 (remaining gas: 1039783.134 units remaining) + [ (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 36 (remaining gas: 1039783.119 units remaining) + [ (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 42 (remaining gas: 1039783.109 units remaining) + [ (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 43 (remaining gas: 1039783.099 units remaining) + [ 1 + (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 44 (remaining gas: 1039783.084 units remaining) + [ (Pair 1 + "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 46 (remaining gas: 1039783.074 units remaining) + [ 1 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 44 (remaining gas: 1039783.044 units remaining) + [ 1 + 1 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 47 (remaining gas: 1039782.783 units remaining) + [ 0x050001 @packed + 1 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 48 (remaining gas: 1039782.523 units remaining) + [ (Some 1) @packed.unpacked + 1 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 51 (remaining gas: 1039782.513 units remaining) + [ 1 @packed.unpacked.some + 1 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 51 (remaining gas: 1039782.498 units remaining) + [ 1 @packed.unpacked.some + 1 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 59 (remaining gas: 1039782.463 units remaining) + [ 0 + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 60 (remaining gas: 1039782.448 units remaining) + [ True + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 61 (remaining gas: 1039782.438 units remaining) + [ (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 61 (remaining gas: 1039782.423 units remaining) + [ (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 67 (remaining gas: 1039782.413 units remaining) + [ (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 68 (remaining gas: 1039782.403 units remaining) + [ "foobar" + (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 69 (remaining gas: 1039782.388 units remaining) + [ (Pair "foobar" + 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 71 (remaining gas: 1039782.378 units remaining) + [ "foobar" + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 69 (remaining gas: 1039782.348 units remaining) + [ "foobar" + "foobar" + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 72 (remaining gas: 1039781.493 units remaining) + [ 0x050100000006666f6f626172 @packed + "foobar" + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 73 (remaining gas: 1039780.978 units remaining) + [ (Some "foobar") @packed.unpacked + "foobar" + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 76 (remaining gas: 1039780.968 units remaining) + [ "foobar" @packed.unpacked.some + "foobar" + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 76 (remaining gas: 1039780.953 units remaining) + [ "foobar" @packed.unpacked.some + "foobar" + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 84 (remaining gas: 1039780.918 units remaining) + [ 0 + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 85 (remaining gas: 1039780.903 units remaining) + [ True + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 86 (remaining gas: 1039780.893 units remaining) + [ (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 86 (remaining gas: 1039780.878 units remaining) + [ (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 92 (remaining gas: 1039780.868 units remaining) + [ (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 93 (remaining gas: 1039780.858 units remaining) + [ 0x00aabbcc + (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 94 (remaining gas: 1039780.843 units remaining) + [ (Pair 0x00aabbcc + 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 96 (remaining gas: 1039780.833 units remaining) + [ 0x00aabbcc + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 94 (remaining gas: 1039780.803 units remaining) + [ 0x00aabbcc + 0x00aabbcc + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 97 (remaining gas: 1039780.080 units remaining) + [ 0x050a0000000400aabbcc @packed + 0x00aabbcc + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 98 (remaining gas: 1039779.679 units remaining) + [ (Some 0x00aabbcc) @packed.unpacked + 0x00aabbcc + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 101 (remaining gas: 1039779.669 units remaining) + [ 0x00aabbcc @packed.unpacked.some + 0x00aabbcc + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 101 (remaining gas: 1039779.654 units remaining) + [ 0x00aabbcc @packed.unpacked.some + 0x00aabbcc + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 109 (remaining gas: 1039779.619 units remaining) + [ 0 + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 110 (remaining gas: 1039779.604 units remaining) + [ True + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 111 (remaining gas: 1039779.594 units remaining) + [ (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 111 (remaining gas: 1039779.579 units remaining) + [ (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 117 (remaining gas: 1039779.569 units remaining) + [ (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 118 (remaining gas: 1039779.559 units remaining) + [ 1000 + (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 119 (remaining gas: 1039779.544 units remaining) + [ (Pair 1000 + False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 121 (remaining gas: 1039779.534 units remaining) + [ 1000 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 119 (remaining gas: 1039779.504 units remaining) + [ 1000 + 1000 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 122 (remaining gas: 1039779.177 units remaining) + [ 0x0500a80f @packed + 1000 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 123 (remaining gas: 1039778.897 units remaining) + [ (Some 1000) @packed.unpacked + 1000 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 126 (remaining gas: 1039778.887 units remaining) + [ 1000 @packed.unpacked.some + 1000 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 126 (remaining gas: 1039778.872 units remaining) + [ 1000 @packed.unpacked.some + 1000 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 134 (remaining gas: 1039778.837 units remaining) + [ 0 + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 135 (remaining gas: 1039778.822 units remaining) + [ True + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 136 (remaining gas: 1039778.812 units remaining) + [ (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 136 (remaining gas: 1039778.797 units remaining) + [ (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 142 (remaining gas: 1039778.787 units remaining) + [ (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 143 (remaining gas: 1039778.777 units remaining) + [ False + (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 144 (remaining gas: 1039778.762 units remaining) + [ (Pair False + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 146 (remaining gas: 1039778.752 units remaining) + [ False + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 144 (remaining gas: 1039778.722 units remaining) + [ False + False + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 147 (remaining gas: 1039778.461 units remaining) + [ 0x050303 @packed + False + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 148 (remaining gas: 1039778.201 units remaining) + [ (Some False) @packed.unpacked + False + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 151 (remaining gas: 1039778.191 units remaining) + [ False @packed.unpacked.some + False + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 151 (remaining gas: 1039778.176 units remaining) + [ False @packed.unpacked.some + False + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 159 (remaining gas: 1039778.141 units remaining) + [ 0 + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 160 (remaining gas: 1039778.126 units remaining) + [ True + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 161 (remaining gas: 1039778.116 units remaining) + [ (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 161 (remaining gas: 1039778.101 units remaining) + [ (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 167 (remaining gas: 1039778.091 units remaining) + [ (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 168 (remaining gas: 1039778.081 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 169 (remaining gas: 1039778.066 units remaining) + [ (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 171 (remaining gas: 1039778.056 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 169 (remaining gas: 1039778.026 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 172 (remaining gas: 1039776.101 units remaining) + [ 0x050a0000001500bdfe3885e846fdea23c9acbe3bb1cfcca9c03e4a @packed + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 173 (remaining gas: 1039775.308 units remaining) + [ (Some "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @packed.unpacked + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 176 (remaining gas: 1039775.298 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" @packed.unpacked.some + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 176 (remaining gas: 1039775.283 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" @packed.unpacked.some + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 184 (remaining gas: 1039775.247 units remaining) + [ 0 + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 185 (remaining gas: 1039775.232 units remaining) + [ True + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 186 (remaining gas: 1039775.222 units remaining) + [ (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 186 (remaining gas: 1039775.207 units remaining) + [ (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 192 (remaining gas: 1039775.197 units remaining) + [ (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 193 (remaining gas: 1039775.187 units remaining) + [ "2019-09-09T08:35:33Z" + (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 194 (remaining gas: 1039775.172 units remaining) + [ (Pair "2019-09-09T08:35:33Z" "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") ] + - location: 196 (remaining gas: 1039775.162 units remaining) + [ "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 194 (remaining gas: 1039775.132 units remaining) + [ "2019-09-09T08:35:33Z" + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 197 (remaining gas: 1039774.607 units remaining) + [ 0x050095bbb0d70b @packed + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 198 (remaining gas: 1039774.267 units remaining) + [ (Some "2019-09-09T08:35:33Z") @packed.unpacked + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 201 (remaining gas: 1039774.257 units remaining) + [ "2019-09-09T08:35:33Z" @packed.unpacked.some + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 201 (remaining gas: 1039774.242 units remaining) + [ "2019-09-09T08:35:33Z" @packed.unpacked.some + "2019-09-09T08:35:33Z" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 209 (remaining gas: 1039774.207 units remaining) + [ 0 + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 210 (remaining gas: 1039774.192 units remaining) + [ True + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 211 (remaining gas: 1039774.182 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 211 (remaining gas: 1039774.167 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 217 (remaining gas: 1039774.157 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 218 (remaining gas: 1039762.846 units remaining) + [ 0x050a000000160000bdfe3885e846fdea23c9acbe3bb1cfcca9c03e4a @packed + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 219 (remaining gas: 1039708.083 units remaining) + [ (Some "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @packed.unpacked + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 222 (remaining gas: 1039708.073 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" @packed.unpacked.some + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 222 (remaining gas: 1039708.058 units remaining) + [ "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" @packed.unpacked.some + "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ] + - location: 230 (remaining gas: 1039708.022 units remaining) + [ 0 ] + - location: 231 (remaining gas: 1039708.007 units remaining) + [ True ] + - location: 232 (remaining gas: 1039707.997 units remaining) + [ ] + - location: 232 (remaining gas: 1039707.982 units remaining) + [ ] + - location: 238 (remaining gas: 1039707.972 units remaining) + [ 0 ] + - location: 241 (remaining gas: 1039707.711 units remaining) + [ 0x050000 @packed ] + - location: 242 (remaining gas: 1039707.451 units remaining) + [ (Some 0) @packed.unpacked ] + - location: 245 (remaining gas: 1039707.441 units remaining) + [ 0 @packed.unpacked.some ] + - location: 245 (remaining gas: 1039707.426 units remaining) + [ 0 @packed.unpacked.some ] + - location: 251 (remaining gas: 1039707.416 units remaining) + [ ] + - location: 252 (remaining gas: 1039707.406 units remaining) + [ -1 ] + - location: 255 (remaining gas: 1039707.145 units remaining) + [ 0x050041 @packed ] + - location: 256 (remaining gas: 1039610.985 units remaining) + [ None @packed.unpacked ] + - location: 259 (remaining gas: 1039610.975 units remaining) + [ ] + - location: 259 (remaining gas: 1039610.960 units remaining) + [ ] + - location: 265 (remaining gas: 1039610.950 units remaining) + [ 0x ] + - location: 268 (remaining gas: 1039610.850 units remaining) + [ None @unpacked ] + - location: 271 (remaining gas: 1039610.840 units remaining) + [ ] + - location: 271 (remaining gas: 1039610.825 units remaining) + [ ] + - location: 277 (remaining gas: 1039610.815 units remaining) + [ 0x04 ] + - location: 280 (remaining gas: 1039610.695 units remaining) + [ None @unpacked ] + - location: 283 (remaining gas: 1039610.685 units remaining) + [ ] + - location: 283 (remaining gas: 1039610.670 units remaining) + [ ] + - location: 289 (remaining gas: 1039610.660 units remaining) + [ 0x05 ] + - location: 292 (remaining gas: 1039610.540 units remaining) + [ None @unpacked ] + - location: 295 (remaining gas: 1039610.530 units remaining) + [ ] + - location: 295 (remaining gas: 1039610.515 units remaining) + [ ] + - location: 301 (remaining gas: 1039610.505 units remaining) + [ Unit ] + - location: 302 (remaining gas: 1039610.490 units remaining) + [ {} + Unit ] + - location: 304 (remaining gas: 1039610.475 units remaining) + [ (Pair {} Unit) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev_cty.tz-Unit-(Pair \"edpkuBknW28nW72KG6RoH.1ac5de50fb.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev_cty.tz-Unit-(Pair \"edpkuBknW28nW72KG6RoH.1ac5de50fb.out" new file mode 100644 index 000000000000..156d3ecb8be5 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev_cty.tz-Unit-(Pair \"edpkuBknW28nW72KG6RoH.1ac5de50fb.out" @@ -0,0 +1,1194 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[packunpack_rev_cty.tz-Unit-(Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" (Pair Unit (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") (Pair { Unit } (Pair { True } (Pair (Pair 19 10) (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK } )))))))))-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 28 (remaining gas: 1039769.570 units remaining) + [ (Pair (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) + Unit) ] + - location: 28 (remaining gas: 1039769.560 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) @parameter ] + - location: 29 (remaining gas: 1039769.550 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) @parameter + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) @parameter ] + - location: 30 (remaining gas: 1039769.540 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) @parameter ] + - location: 31 (remaining gas: 1039769.525 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) @parameter ] + - location: 33 (remaining gas: 1039769.515 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 31 (remaining gas: 1039769.485 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 34 (remaining gas: 1039766.278 units remaining) + [ 0x050a00000021004798d2cc98473d7e250c898885718afd2e4efbcb1a1595ab9730761ed830de0f @packed + "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 35 (remaining gas: 1039766.263 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 37 (remaining gas: 1039763.056 units remaining) + [ 0x050a00000021004798d2cc98473d7e250c898885718afd2e4efbcb1a1595ab9730761ed830de0f @packed + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 38 (remaining gas: 1039739.072 units remaining) + [ (Some "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav") @packed.unpacked + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 41 (remaining gas: 1039739.062 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" @packed.unpacked.some + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 41 (remaining gas: 1039739.047 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" @packed.unpacked.some + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 47 (remaining gas: 1039735.840 units remaining) + [ 0x050a00000021004798d2cc98473d7e250c898885718afd2e4efbcb1a1595ab9730761ed830de0f @packed.unpacked.some.packed + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 35 (remaining gas: 1039735.810 units remaining) + [ 0x050a00000021004798d2cc98473d7e250c898885718afd2e4efbcb1a1595ab9730761ed830de0f @packed + 0x050a00000021004798d2cc98473d7e250c898885718afd2e4efbcb1a1595ab9730761ed830de0f @packed.unpacked.some.packed + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 50 (remaining gas: 1039735.775 units remaining) + [ 0 + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 51 (remaining gas: 1039735.760 units remaining) + [ True + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 52 (remaining gas: 1039735.750 units remaining) + [ (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 52 (remaining gas: 1039735.735 units remaining) + [ (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 58 (remaining gas: 1039735.725 units remaining) + [ (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 59 (remaining gas: 1039735.715 units remaining) + [ Unit + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 60 (remaining gas: 1039735.700 units remaining) + [ (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 62 (remaining gas: 1039735.690 units remaining) + [ Unit + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 60 (remaining gas: 1039735.660 units remaining) + [ Unit + Unit + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 63 (remaining gas: 1039735.399 units remaining) + [ 0x05030b @packed + Unit + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 64 (remaining gas: 1039735.384 units remaining) + [ Unit + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 66 (remaining gas: 1039735.123 units remaining) + [ 0x05030b @packed + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 67 (remaining gas: 1039734.863 units remaining) + [ (Some Unit) @packed.unpacked + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 70 (remaining gas: 1039734.853 units remaining) + [ Unit @packed.unpacked.some + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 70 (remaining gas: 1039734.838 units remaining) + [ Unit @packed.unpacked.some + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 76 (remaining gas: 1039734.577 units remaining) + [ 0x05030b @packed.unpacked.some.packed + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 64 (remaining gas: 1039734.547 units remaining) + [ 0x05030b @packed + 0x05030b @packed.unpacked.some.packed + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 79 (remaining gas: 1039734.512 units remaining) + [ 0 + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 80 (remaining gas: 1039734.497 units remaining) + [ True + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 81 (remaining gas: 1039734.487 units remaining) + [ (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 81 (remaining gas: 1039734.472 units remaining) + [ (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 87 (remaining gas: 1039734.462 units remaining) + [ (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 88 (remaining gas: 1039734.452 units remaining) + [ "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 89 (remaining gas: 1039734.437 units remaining) + [ (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 91 (remaining gas: 1039734.427 units remaining) + [ "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 89 (remaining gas: 1039734.397 units remaining) + [ "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 92 (remaining gas: 1039729.674 units remaining) + [ 0x050a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 93 (remaining gas: 1039729.659 units remaining) + [ "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 95 (remaining gas: 1039724.936 units remaining) + [ 0x050a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 96 (remaining gas: 1039723.298 units remaining) + [ (Some "sigXeXB5JD5TaLb3xgTPKjgf9W45judiCmNP9UBdZBdmtHSGBxL1M8ZSUb6LpjGP2MdfUBTB4WHs5APnvyRV1LooU6QHJuDe") @packed.unpacked + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 99 (remaining gas: 1039723.288 units remaining) + [ "sigXeXB5JD5TaLb3xgTPKjgf9W45judiCmNP9UBdZBdmtHSGBxL1M8ZSUb6LpjGP2MdfUBTB4WHs5APnvyRV1LooU6QHJuDe" @packed.unpacked.some + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 99 (remaining gas: 1039723.273 units remaining) + [ "sigXeXB5JD5TaLb3xgTPKjgf9W45judiCmNP9UBdZBdmtHSGBxL1M8ZSUb6LpjGP2MdfUBTB4WHs5APnvyRV1LooU6QHJuDe" @packed.unpacked.some + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 105 (remaining gas: 1039718.550 units remaining) + [ 0x050a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed.unpacked.some.packed + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 93 (remaining gas: 1039718.520 units remaining) + [ 0x050a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed + 0x050a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed.unpacked.some.packed + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 108 (remaining gas: 1039718.484 units remaining) + [ 0 + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 109 (remaining gas: 1039718.469 units remaining) + [ True + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 110 (remaining gas: 1039718.459 units remaining) + [ (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 110 (remaining gas: 1039718.444 units remaining) + [ (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 116 (remaining gas: 1039718.434 units remaining) + [ (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 117 (remaining gas: 1039718.424 units remaining) + [ (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 118 (remaining gas: 1039718.409 units remaining) + [ (Pair (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 120 (remaining gas: 1039718.399 units remaining) + [ (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 118 (remaining gas: 1039718.369 units remaining) + [ (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 121 (remaining gas: 1039713.418 units remaining) + [ 0x0505090a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed + (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 122 (remaining gas: 1039713.403 units remaining) + [ (Some "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 124 (remaining gas: 1039708.452 units remaining) + [ 0x0505090a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 125 (remaining gas: 1039706.673 units remaining) + [ (Some (Some "sigXeXB5JD5TaLb3xgTPKjgf9W45judiCmNP9UBdZBdmtHSGBxL1M8ZSUb6LpjGP2MdfUBTB4WHs5APnvyRV1LooU6QHJuDe")) @packed.unpacked + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 129 (remaining gas: 1039706.663 units remaining) + [ (Some "sigXeXB5JD5TaLb3xgTPKjgf9W45judiCmNP9UBdZBdmtHSGBxL1M8ZSUb6LpjGP2MdfUBTB4WHs5APnvyRV1LooU6QHJuDe") @packed.unpacked.some + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 129 (remaining gas: 1039706.648 units remaining) + [ (Some "sigXeXB5JD5TaLb3xgTPKjgf9W45judiCmNP9UBdZBdmtHSGBxL1M8ZSUb6LpjGP2MdfUBTB4WHs5APnvyRV1LooU6QHJuDe") @packed.unpacked.some + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 135 (remaining gas: 1039701.697 units remaining) + [ 0x0505090a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed.unpacked.some.packed + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 122 (remaining gas: 1039701.667 units remaining) + [ 0x0505090a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed + 0x0505090a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed.unpacked.some.packed + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 138 (remaining gas: 1039701.631 units remaining) + [ 0 + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 139 (remaining gas: 1039701.616 units remaining) + [ True + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 140 (remaining gas: 1039701.606 units remaining) + [ (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 140 (remaining gas: 1039701.591 units remaining) + [ (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 146 (remaining gas: 1039701.581 units remaining) + [ (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 147 (remaining gas: 1039701.571 units remaining) + [ { Unit } + (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 148 (remaining gas: 1039701.556 units remaining) + [ (Pair { Unit } + { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 150 (remaining gas: 1039701.546 units remaining) + [ { Unit } + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 148 (remaining gas: 1039701.516 units remaining) + [ { Unit } + { Unit } + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 151 (remaining gas: 1039700.829 units remaining) + [ 0x050200000002030b @packed + { Unit } + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 152 (remaining gas: 1039700.814 units remaining) + [ { Unit } + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 154 (remaining gas: 1039700.127 units remaining) + [ 0x050200000002030b @packed + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 155 (remaining gas: 1039699.666 units remaining) + [ (Some { Unit }) @packed.unpacked + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 159 (remaining gas: 1039699.656 units remaining) + [ { Unit } @packed.unpacked.some + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 159 (remaining gas: 1039699.641 units remaining) + [ { Unit } @packed.unpacked.some + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 165 (remaining gas: 1039698.954 units remaining) + [ 0x050200000002030b @packed.unpacked.some.packed + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 152 (remaining gas: 1039698.924 units remaining) + [ 0x050200000002030b @packed + 0x050200000002030b @packed.unpacked.some.packed + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 168 (remaining gas: 1039698.889 units remaining) + [ 0 + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 169 (remaining gas: 1039698.874 units remaining) + [ True + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 170 (remaining gas: 1039698.864 units remaining) + [ (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 170 (remaining gas: 1039698.849 units remaining) + [ (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 176 (remaining gas: 1039698.839 units remaining) + [ (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 177 (remaining gas: 1039698.829 units remaining) + [ { True } + (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 178 (remaining gas: 1039698.814 units remaining) + [ (Pair { True } + (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 180 (remaining gas: 1039698.804 units remaining) + [ { True } + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 178 (remaining gas: 1039698.774 units remaining) + [ { True } + { True } + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 181 (remaining gas: 1039698.087 units remaining) + [ 0x050200000002030a @packed + { True } + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 182 (remaining gas: 1039698.072 units remaining) + [ { True } + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 184 (remaining gas: 1039697.385 units remaining) + [ 0x050200000002030a @packed + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 185 (remaining gas: 1039696.774 units remaining) + [ (Some { True }) @packed.unpacked + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 189 (remaining gas: 1039696.764 units remaining) + [ { True } @packed.unpacked.some + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 189 (remaining gas: 1039696.749 units remaining) + [ { True } @packed.unpacked.some + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 195 (remaining gas: 1039696.062 units remaining) + [ 0x050200000002030a @packed.unpacked.some.packed + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 182 (remaining gas: 1039696.032 units remaining) + [ 0x050200000002030a @packed + 0x050200000002030a @packed.unpacked.some.packed + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 198 (remaining gas: 1039695.997 units remaining) + [ 0 + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 199 (remaining gas: 1039695.982 units remaining) + [ True + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 200 (remaining gas: 1039695.972 units remaining) + [ (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 200 (remaining gas: 1039695.957 units remaining) + [ (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 206 (remaining gas: 1039695.947 units remaining) + [ (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 207 (remaining gas: 1039695.937 units remaining) + [ (Pair 19 10) + (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 208 (remaining gas: 1039695.922 units remaining) + [ (Pair (Pair 19 10) + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 210 (remaining gas: 1039695.912 units remaining) + [ (Pair 19 10) + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 208 (remaining gas: 1039695.882 units remaining) + [ (Pair 19 10) + (Pair 19 10) + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 211 (remaining gas: 1039695.165 units remaining) + [ 0x0507070013000a @packed + (Pair 19 10) + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 212 (remaining gas: 1039695.150 units remaining) + [ (Pair 19 10) + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 214 (remaining gas: 1039694.433 units remaining) + [ 0x0507070013000a @packed + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 215 (remaining gas: 1039693.893 units remaining) + [ (Some (Pair 19 10)) @packed.unpacked + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 220 (remaining gas: 1039693.883 units remaining) + [ (Pair 19 10) @packed.unpacked.some + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 220 (remaining gas: 1039693.868 units remaining) + [ (Pair 19 10) @packed.unpacked.some + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 226 (remaining gas: 1039693.151 units remaining) + [ 0x0507070013000a @packed.unpacked.some.packed + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 212 (remaining gas: 1039693.121 units remaining) + [ 0x0507070013000a @packed + 0x0507070013000a @packed.unpacked.some.packed + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 229 (remaining gas: 1039693.086 units remaining) + [ 0 + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 230 (remaining gas: 1039693.071 units remaining) + [ True + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 231 (remaining gas: 1039693.061 units remaining) + [ (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 231 (remaining gas: 1039693.046 units remaining) + [ (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 237 (remaining gas: 1039693.036 units remaining) + [ (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 238 (remaining gas: 1039693.026 units remaining) + [ (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 239 (remaining gas: 1039693.011 units remaining) + [ (Pair (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK }) ] + - location: 241 (remaining gas: 1039693.001 units remaining) + [ (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 239 (remaining gas: 1039692.971 units remaining) + [ (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 242 (remaining gas: 1039690.818 units remaining) + [ 0x0505050a0000001500bdfe3885e846fdea23c9acbe3bb1cfcca9c03e4a @packed + (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 243 (remaining gas: 1039690.803 units remaining) + [ (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 245 (remaining gas: 1039688.650 units remaining) + [ 0x0505050a0000001500bdfe3885e846fdea23c9acbe3bb1cfcca9c03e4a @packed + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 246 (remaining gas: 1039687.717 units remaining) + [ (Some (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5")) @packed.unpacked + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 251 (remaining gas: 1039687.707 units remaining) + [ (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @packed.unpacked.some + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 251 (remaining gas: 1039687.692 units remaining) + [ (Left "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5") @packed.unpacked.some + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 257 (remaining gas: 1039685.539 units remaining) + [ 0x0505050a0000001500bdfe3885e846fdea23c9acbe3bb1cfcca9c03e4a @packed.unpacked.some.packed + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 243 (remaining gas: 1039685.509 units remaining) + [ 0x0505050a0000001500bdfe3885e846fdea23c9acbe3bb1cfcca9c03e4a @packed + 0x0505050a0000001500bdfe3885e846fdea23c9acbe3bb1cfcca9c03e4a @packed.unpacked.some.packed + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 260 (remaining gas: 1039685.474 units remaining) + [ 0 + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 261 (remaining gas: 1039685.459 units remaining) + [ True + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 262 (remaining gas: 1039685.449 units remaining) + [ (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 262 (remaining gas: 1039685.434 units remaining) + [ (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 268 (remaining gas: 1039685.424 units remaining) + [ (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 269 (remaining gas: 1039685.414 units remaining) + [ { Elt 0 "foo" ; Elt 1 "bar" } + (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 270 (remaining gas: 1039685.399 units remaining) + [ (Pair { Elt 0 "foo" ; Elt 1 "bar" } { PACK }) ] + - location: 272 (remaining gas: 1039685.389 units remaining) + [ { Elt 0 "foo" ; Elt 1 "bar" } + { PACK } ] + - location: 270 (remaining gas: 1039685.359 units remaining) + [ { Elt 0 "foo" ; Elt 1 "bar" } + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK } ] + - location: 273 (remaining gas: 1039682.830 units remaining) + [ 0x050200000018070400000100000003666f6f070400010100000003626172 @packed + { Elt 0 "foo" ; Elt 1 "bar" } + { PACK } ] + - location: 274 (remaining gas: 1039682.815 units remaining) + [ { Elt 0 "foo" ; Elt 1 "bar" } + { PACK } ] + - location: 276 (remaining gas: 1039680.286 units remaining) + [ 0x050200000018070400000100000003666f6f070400010100000003626172 @packed + { PACK } ] + - location: 277 (remaining gas: 1039678.590 units remaining) + [ (Some { Elt 0 "foo" ; Elt 1 "bar" }) @packed.unpacked + { PACK } ] + - location: 282 (remaining gas: 1039678.580 units remaining) + [ { Elt 0 "foo" ; Elt 1 "bar" } @packed.unpacked.some + { PACK } ] + - location: 282 (remaining gas: 1039678.565 units remaining) + [ { Elt 0 "foo" ; Elt 1 "bar" } @packed.unpacked.some + { PACK } ] + - location: 288 (remaining gas: 1039676.036 units remaining) + [ 0x050200000018070400000100000003666f6f070400010100000003626172 @packed.unpacked.some.packed + { PACK } ] + - location: 274 (remaining gas: 1039676.006 units remaining) + [ 0x050200000018070400000100000003666f6f070400010100000003626172 @packed + 0x050200000018070400000100000003666f6f070400010100000003626172 @packed.unpacked.some.packed + { PACK } ] + - location: 291 (remaining gas: 1039675.971 units remaining) + [ 0 + { PACK } ] + - location: 292 (remaining gas: 1039675.956 units remaining) + [ True + { PACK } ] + - location: 293 (remaining gas: 1039675.946 units remaining) + [ { PACK } ] + - location: 293 (remaining gas: 1039675.931 units remaining) + [ { PACK } ] + - location: 299 (remaining gas: 1039675.921 units remaining) + [ { PACK } + { PACK } ] + - location: 300 (remaining gas: 1039675.049 units remaining) + [ 0x050200000002030c @packed + { PACK } ] + - location: 301 (remaining gas: 1039675.034 units remaining) + [ { PACK } ] + - location: 303 (remaining gas: 1039674.162 units remaining) + [ 0x050200000002030c @packed ] + - location: 304 (remaining gas: 1039673.321 units remaining) + [ (Some { PACK }) @packed.unpacked ] + - location: 309 (remaining gas: 1039673.311 units remaining) + [ { PACK } @packed.unpacked.some ] + - location: 309 (remaining gas: 1039673.296 units remaining) + [ { PACK } @packed.unpacked.some ] + - location: 315 (remaining gas: 1039672.424 units remaining) + [ 0x050200000002030c @packed.unpacked.some.packed ] + - location: 301 (remaining gas: 1039672.394 units remaining) + [ 0x050200000002030c @packed + 0x050200000002030c @packed.unpacked.some.packed ] + - location: 318 (remaining gas: 1039672.359 units remaining) + [ 0 ] + - location: 319 (remaining gas: 1039672.344 units remaining) + [ True ] + - location: 320 (remaining gas: 1039672.334 units remaining) + [ ] + - location: 320 (remaining gas: 1039672.319 units remaining) + [ ] + - location: 326 (remaining gas: 1039672.309 units remaining) + [ Unit ] + - location: 327 (remaining gas: 1039672.294 units remaining) + [ {} + Unit ] + - location: 329 (remaining gas: 1039672.279 units remaining) + [ (Pair {} Unit) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev_cty.tz-Unit-(Pair \"edpkuBknW28nW72KG6RoH.4e20b52378.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev_cty.tz-Unit-(Pair \"edpkuBknW28nW72KG6RoH.4e20b52378.out" new file mode 100644 index 000000000000..baca1f21ea63 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[packunpack_rev_cty.tz-Unit-(Pair \"edpkuBknW28nW72KG6RoH.4e20b52378.out" @@ -0,0 +1,1032 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[packunpack_rev_cty.tz-Unit-(Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" (Pair Unit (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" (Pair None (Pair { } (Pair { } (Pair (Pair 40 -10) (Pair (Right "2019-09-09T08:35:33Z") (Pair { } { DUP ; DROP ; PACK } )))))))))-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 28 (remaining gas: 1039779.013 units remaining) + [ (Pair (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) + Unit) ] + - location: 28 (remaining gas: 1039779.003 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) @parameter ] + - location: 29 (remaining gas: 1039778.993 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) @parameter + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) @parameter ] + - location: 30 (remaining gas: 1039778.983 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) @parameter ] + - location: 31 (remaining gas: 1039778.968 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) @parameter ] + - location: 33 (remaining gas: 1039778.958 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 31 (remaining gas: 1039778.928 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 34 (remaining gas: 1039775.721 units remaining) + [ 0x050a00000021004798d2cc98473d7e250c898885718afd2e4efbcb1a1595ab9730761ed830de0f @packed + "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 35 (remaining gas: 1039775.706 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 37 (remaining gas: 1039772.499 units remaining) + [ 0x050a00000021004798d2cc98473d7e250c898885718afd2e4efbcb1a1595ab9730761ed830de0f @packed + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 38 (remaining gas: 1039748.515 units remaining) + [ (Some "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav") @packed.unpacked + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 41 (remaining gas: 1039748.505 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" @packed.unpacked.some + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 41 (remaining gas: 1039748.490 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" @packed.unpacked.some + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 47 (remaining gas: 1039745.283 units remaining) + [ 0x050a00000021004798d2cc98473d7e250c898885718afd2e4efbcb1a1595ab9730761ed830de0f @packed.unpacked.some.packed + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 35 (remaining gas: 1039745.253 units remaining) + [ 0x050a00000021004798d2cc98473d7e250c898885718afd2e4efbcb1a1595ab9730761ed830de0f @packed + 0x050a00000021004798d2cc98473d7e250c898885718afd2e4efbcb1a1595ab9730761ed830de0f @packed.unpacked.some.packed + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 50 (remaining gas: 1039745.218 units remaining) + [ 0 + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 51 (remaining gas: 1039745.203 units remaining) + [ True + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 52 (remaining gas: 1039745.193 units remaining) + [ (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 52 (remaining gas: 1039745.178 units remaining) + [ (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 58 (remaining gas: 1039745.168 units remaining) + [ (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 59 (remaining gas: 1039745.158 units remaining) + [ Unit + (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 60 (remaining gas: 1039745.143 units remaining) + [ (Pair Unit + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 62 (remaining gas: 1039745.133 units remaining) + [ Unit + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 60 (remaining gas: 1039745.103 units remaining) + [ Unit + Unit + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 63 (remaining gas: 1039744.842 units remaining) + [ 0x05030b @packed + Unit + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 64 (remaining gas: 1039744.827 units remaining) + [ Unit + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 66 (remaining gas: 1039744.566 units remaining) + [ 0x05030b @packed + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 67 (remaining gas: 1039744.306 units remaining) + [ (Some Unit) @packed.unpacked + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 70 (remaining gas: 1039744.296 units remaining) + [ Unit @packed.unpacked.some + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 70 (remaining gas: 1039744.281 units remaining) + [ Unit @packed.unpacked.some + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 76 (remaining gas: 1039744.020 units remaining) + [ 0x05030b @packed.unpacked.some.packed + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 64 (remaining gas: 1039743.990 units remaining) + [ 0x05030b @packed + 0x05030b @packed.unpacked.some.packed + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 79 (remaining gas: 1039743.955 units remaining) + [ 0 + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 80 (remaining gas: 1039743.940 units remaining) + [ True + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 81 (remaining gas: 1039743.930 units remaining) + [ (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 81 (remaining gas: 1039743.915 units remaining) + [ (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 87 (remaining gas: 1039743.905 units remaining) + [ (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 88 (remaining gas: 1039743.895 units remaining) + [ "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 89 (remaining gas: 1039743.880 units remaining) + [ (Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 91 (remaining gas: 1039743.870 units remaining) + [ "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 89 (remaining gas: 1039743.840 units remaining) + [ "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 92 (remaining gas: 1039739.117 units remaining) + [ 0x050a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed + "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 93 (remaining gas: 1039739.102 units remaining) + [ "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 95 (remaining gas: 1039734.379 units remaining) + [ 0x050a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 96 (remaining gas: 1039732.741 units remaining) + [ (Some "sigXeXB5JD5TaLb3xgTPKjgf9W45judiCmNP9UBdZBdmtHSGBxL1M8ZSUb6LpjGP2MdfUBTB4WHs5APnvyRV1LooU6QHJuDe") @packed.unpacked + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 99 (remaining gas: 1039732.731 units remaining) + [ "sigXeXB5JD5TaLb3xgTPKjgf9W45judiCmNP9UBdZBdmtHSGBxL1M8ZSUb6LpjGP2MdfUBTB4WHs5APnvyRV1LooU6QHJuDe" @packed.unpacked.some + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 99 (remaining gas: 1039732.716 units remaining) + [ "sigXeXB5JD5TaLb3xgTPKjgf9W45judiCmNP9UBdZBdmtHSGBxL1M8ZSUb6LpjGP2MdfUBTB4WHs5APnvyRV1LooU6QHJuDe" @packed.unpacked.some + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 105 (remaining gas: 1039727.993 units remaining) + [ 0x050a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed.unpacked.some.packed + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 93 (remaining gas: 1039727.963 units remaining) + [ 0x050a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed + 0x050a0000004049d47dba27bd76208b092f3e500f64818920c817491b8b9094f28c2c2b9c6721b257b8878ce47182122b8ea84aeacd84a8aa28cb1f1fe48a26355a7bca4b8306 @packed.unpacked.some.packed + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 108 (remaining gas: 1039727.927 units remaining) + [ 0 + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 109 (remaining gas: 1039727.912 units remaining) + [ True + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 110 (remaining gas: 1039727.902 units remaining) + [ (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 110 (remaining gas: 1039727.887 units remaining) + [ (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 116 (remaining gas: 1039727.877 units remaining) + [ (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 117 (remaining gas: 1039727.867 units remaining) + [ None + (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 118 (remaining gas: 1039727.852 units remaining) + [ (Pair None + {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 120 (remaining gas: 1039727.842 units remaining) + [ None + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 118 (remaining gas: 1039727.812 units remaining) + [ None + None + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 121 (remaining gas: 1039727.551 units remaining) + [ 0x050306 @packed + None + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 122 (remaining gas: 1039727.536 units remaining) + [ None + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 124 (remaining gas: 1039727.275 units remaining) + [ 0x050306 @packed + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 125 (remaining gas: 1039727.015 units remaining) + [ (Some None) @packed.unpacked + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 129 (remaining gas: 1039727.005 units remaining) + [ None @packed.unpacked.some + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 129 (remaining gas: 1039726.990 units remaining) + [ None @packed.unpacked.some + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 135 (remaining gas: 1039726.729 units remaining) + [ 0x050306 @packed.unpacked.some.packed + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 122 (remaining gas: 1039726.699 units remaining) + [ 0x050306 @packed + 0x050306 @packed.unpacked.some.packed + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 138 (remaining gas: 1039726.664 units remaining) + [ 0 + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 139 (remaining gas: 1039726.649 units remaining) + [ True + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 140 (remaining gas: 1039726.639 units remaining) + [ (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 140 (remaining gas: 1039726.624 units remaining) + [ (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 146 (remaining gas: 1039726.614 units remaining) + [ (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 147 (remaining gas: 1039726.604 units remaining) + [ {} + (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 148 (remaining gas: 1039726.589 units remaining) + [ (Pair {} + {} + (Pair 40 -10) + (Right "2019-09-09T08:35:33Z") + {} + { DUP ; DROP ; PACK }) ] + - location: 150 (remaining gas: 1039726.579 units remaining) + [ {} + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 148 (remaining gas: 1039726.549 units remaining) + [ {} + {} + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 151 (remaining gas: 1039726.090 units remaining) + [ 0x050200000000 @packed + {} + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 152 (remaining gas: 1039726.075 units remaining) + [ {} + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 154 (remaining gas: 1039725.616 units remaining) + [ 0x050200000000 @packed + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 155 (remaining gas: 1039725.296 units remaining) + [ (Some {}) @packed.unpacked + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 159 (remaining gas: 1039725.286 units remaining) + [ {} @packed.unpacked.some + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 159 (remaining gas: 1039725.271 units remaining) + [ {} @packed.unpacked.some + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 165 (remaining gas: 1039724.812 units remaining) + [ 0x050200000000 @packed.unpacked.some.packed + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 152 (remaining gas: 1039724.782 units remaining) + [ 0x050200000000 @packed + 0x050200000000 @packed.unpacked.some.packed + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 168 (remaining gas: 1039724.747 units remaining) + [ 0 + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 169 (remaining gas: 1039724.732 units remaining) + [ True + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 170 (remaining gas: 1039724.722 units remaining) + [ (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 170 (remaining gas: 1039724.707 units remaining) + [ (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 176 (remaining gas: 1039724.697 units remaining) + [ (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 177 (remaining gas: 1039724.687 units remaining) + [ {} + (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 178 (remaining gas: 1039724.672 units remaining) + [ (Pair {} (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 180 (remaining gas: 1039724.662 units remaining) + [ {} + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 178 (remaining gas: 1039724.632 units remaining) + [ {} + {} + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 181 (remaining gas: 1039724.173 units remaining) + [ 0x050200000000 @packed + {} + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 182 (remaining gas: 1039724.158 units remaining) + [ {} + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 184 (remaining gas: 1039723.699 units remaining) + [ 0x050200000000 @packed + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 185 (remaining gas: 1039723.379 units remaining) + [ (Some {}) @packed.unpacked + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 189 (remaining gas: 1039723.369 units remaining) + [ {} @packed.unpacked.some + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 189 (remaining gas: 1039723.354 units remaining) + [ {} @packed.unpacked.some + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 195 (remaining gas: 1039722.895 units remaining) + [ 0x050200000000 @packed.unpacked.some.packed + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 182 (remaining gas: 1039722.865 units remaining) + [ 0x050200000000 @packed + 0x050200000000 @packed.unpacked.some.packed + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 198 (remaining gas: 1039722.830 units remaining) + [ 0 + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 199 (remaining gas: 1039722.815 units remaining) + [ True + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 200 (remaining gas: 1039722.805 units remaining) + [ (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 200 (remaining gas: 1039722.790 units remaining) + [ (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 206 (remaining gas: 1039722.780 units remaining) + [ (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 207 (remaining gas: 1039722.770 units remaining) + [ (Pair 40 -10) + (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 208 (remaining gas: 1039722.755 units remaining) + [ (Pair (Pair 40 -10) (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 210 (remaining gas: 1039722.745 units remaining) + [ (Pair 40 -10) + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 208 (remaining gas: 1039722.715 units remaining) + [ (Pair 40 -10) + (Pair 40 -10) + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 211 (remaining gas: 1039721.998 units remaining) + [ 0x0507070028004a @packed + (Pair 40 -10) + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 212 (remaining gas: 1039721.983 units remaining) + [ (Pair 40 -10) + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 214 (remaining gas: 1039721.266 units remaining) + [ 0x0507070028004a @packed + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 215 (remaining gas: 1039720.726 units remaining) + [ (Some (Pair 40 -10)) @packed.unpacked + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 220 (remaining gas: 1039720.716 units remaining) + [ (Pair 40 -10) @packed.unpacked.some + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 220 (remaining gas: 1039720.701 units remaining) + [ (Pair 40 -10) @packed.unpacked.some + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 226 (remaining gas: 1039719.984 units remaining) + [ 0x0507070028004a @packed.unpacked.some.packed + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 212 (remaining gas: 1039719.954 units remaining) + [ 0x0507070028004a @packed + 0x0507070028004a @packed.unpacked.some.packed + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 229 (remaining gas: 1039719.919 units remaining) + [ 0 + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 230 (remaining gas: 1039719.904 units remaining) + [ True + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 231 (remaining gas: 1039719.894 units remaining) + [ (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 231 (remaining gas: 1039719.879 units remaining) + [ (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 237 (remaining gas: 1039719.869 units remaining) + [ (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 238 (remaining gas: 1039719.859 units remaining) + [ (Right "2019-09-09T08:35:33Z") + (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 239 (remaining gas: 1039719.844 units remaining) + [ (Pair (Right "2019-09-09T08:35:33Z") {} { DUP ; DROP ; PACK }) ] + - location: 241 (remaining gas: 1039719.834 units remaining) + [ (Right "2019-09-09T08:35:33Z") + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 239 (remaining gas: 1039719.804 units remaining) + [ (Right "2019-09-09T08:35:33Z") + (Right "2019-09-09T08:35:33Z") + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 242 (remaining gas: 1039719.051 units remaining) + [ 0x0505080095bbb0d70b @packed + (Right "2019-09-09T08:35:33Z") + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 243 (remaining gas: 1039719.036 units remaining) + [ (Right "2019-09-09T08:35:33Z") + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 245 (remaining gas: 1039718.283 units remaining) + [ 0x0505080095bbb0d70b @packed + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 246 (remaining gas: 1039717.802 units remaining) + [ (Some (Right "2019-09-09T08:35:33Z")) @packed.unpacked + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 251 (remaining gas: 1039717.792 units remaining) + [ (Right "2019-09-09T08:35:33Z") @packed.unpacked.some + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 251 (remaining gas: 1039717.777 units remaining) + [ (Right "2019-09-09T08:35:33Z") @packed.unpacked.some + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 257 (remaining gas: 1039717.024 units remaining) + [ 0x0505080095bbb0d70b @packed.unpacked.some.packed + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 243 (remaining gas: 1039716.994 units remaining) + [ 0x0505080095bbb0d70b @packed + 0x0505080095bbb0d70b @packed.unpacked.some.packed + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 260 (remaining gas: 1039716.959 units remaining) + [ 0 + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 261 (remaining gas: 1039716.944 units remaining) + [ True + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 262 (remaining gas: 1039716.934 units remaining) + [ (Pair {} { DUP ; DROP ; PACK }) ] + - location: 262 (remaining gas: 1039716.919 units remaining) + [ (Pair {} { DUP ; DROP ; PACK }) ] + - location: 268 (remaining gas: 1039716.909 units remaining) + [ (Pair {} { DUP ; DROP ; PACK }) + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 269 (remaining gas: 1039716.899 units remaining) + [ {} + (Pair {} { DUP ; DROP ; PACK }) ] + - location: 270 (remaining gas: 1039716.884 units remaining) + [ (Pair {} { DUP ; DROP ; PACK }) ] + - location: 272 (remaining gas: 1039716.874 units remaining) + [ {} + { DUP ; DROP ; PACK } ] + - location: 270 (remaining gas: 1039716.844 units remaining) + [ {} + {} + { DUP ; DROP ; PACK } ] + - location: 273 (remaining gas: 1039716.385 units remaining) + [ 0x050200000000 @packed + {} + { DUP ; DROP ; PACK } ] + - location: 274 (remaining gas: 1039716.370 units remaining) + [ {} + { DUP ; DROP ; PACK } ] + - location: 276 (remaining gas: 1039715.911 units remaining) + [ 0x050200000000 @packed + { DUP ; DROP ; PACK } ] + - location: 277 (remaining gas: 1039715.591 units remaining) + [ (Some {}) @packed.unpacked + { DUP ; DROP ; PACK } ] + - location: 282 (remaining gas: 1039715.581 units remaining) + [ {} @packed.unpacked.some + { DUP ; DROP ; PACK } ] + - location: 282 (remaining gas: 1039715.566 units remaining) + [ {} @packed.unpacked.some + { DUP ; DROP ; PACK } ] + - location: 288 (remaining gas: 1039715.107 units remaining) + [ 0x050200000000 @packed.unpacked.some.packed + { DUP ; DROP ; PACK } ] + - location: 274 (remaining gas: 1039715.077 units remaining) + [ 0x050200000000 @packed + 0x050200000000 @packed.unpacked.some.packed + { DUP ; DROP ; PACK } ] + - location: 291 (remaining gas: 1039715.042 units remaining) + [ 0 + { DUP ; DROP ; PACK } ] + - location: 292 (remaining gas: 1039715.027 units remaining) + [ True + { DUP ; DROP ; PACK } ] + - location: 293 (remaining gas: 1039715.017 units remaining) + [ { DUP ; DROP ; PACK } ] + - location: 293 (remaining gas: 1039715.002 units remaining) + [ { DUP ; DROP ; PACK } ] + - location: 299 (remaining gas: 1039714.992 units remaining) + [ { DUP ; DROP ; PACK } + { DUP ; DROP ; PACK } ] + - location: 300 (remaining gas: 1039713.524 units remaining) + [ 0x05020000000603210320030c @packed + { DUP ; DROP ; PACK } ] + - location: 301 (remaining gas: 1039713.509 units remaining) + [ { DUP ; DROP ; PACK } ] + - location: 303 (remaining gas: 1039712.041 units remaining) + [ 0x05020000000603210320030c @packed ] + - location: 304 (remaining gas: 1039710.140 units remaining) + [ (Some { DUP ; DROP ; PACK }) @packed.unpacked ] + - location: 309 (remaining gas: 1039710.130 units remaining) + [ { DUP ; DROP ; PACK } @packed.unpacked.some ] + - location: 309 (remaining gas: 1039710.115 units remaining) + [ { DUP ; DROP ; PACK } @packed.unpacked.some ] + - location: 315 (remaining gas: 1039708.647 units remaining) + [ 0x05020000000603210320030c @packed.unpacked.some.packed ] + - location: 301 (remaining gas: 1039708.617 units remaining) + [ 0x05020000000603210320030c @packed + 0x05020000000603210320030c @packed.unpacked.some.packed ] + - location: 318 (remaining gas: 1039708.582 units remaining) + [ 0 ] + - location: 319 (remaining gas: 1039708.567 units remaining) + [ True ] + - location: 320 (remaining gas: 1039708.557 units remaining) + [ ] + - location: 320 (remaining gas: 1039708.542 units remaining) + [ ] + - location: 326 (remaining gas: 1039708.532 units remaining) + [ Unit ] + - location: 327 (remaining gas: 1039708.517 units remaining) + [ {} + Unit ] + - location: 329 (remaining gas: 1039708.502 units remaining) + [ (Pair {} Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair False False)-(Some (Pair False False))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair False False)-(Some (Pair False False))].out new file mode 100644 index 000000000000..b87d17effcf3 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair False False)-(Some (Pair False False))].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair False False)-(Some (Pair False False))] + +storage + (Some (Pair False False)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039994.494 units remaining) + [ (Pair (Pair False False) None) ] + - location: 12 (remaining gas: 1039994.484 units remaining) + [ (Pair False False) @parameter ] + - location: 13 (remaining gas: 1039994.469 units remaining) + [ (Some (Pair False False)) ] + - location: 14 (remaining gas: 1039994.454 units remaining) + [ {} + (Some (Pair False False)) ] + - location: 16 (remaining gas: 1039994.439 units remaining) + [ (Pair {} (Some (Pair False False))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair False True)-(Some (Pair False True))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair False True)-(Some (Pair False True))].out new file mode 100644 index 000000000000..82c67dcc23ac --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair False True)-(Some (Pair False True))].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair False True)-(Some (Pair False True))] + +storage + (Some (Pair False True)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039994.494 units remaining) + [ (Pair (Pair False True) None) ] + - location: 12 (remaining gas: 1039994.484 units remaining) + [ (Pair False True) @parameter ] + - location: 13 (remaining gas: 1039994.469 units remaining) + [ (Some (Pair False True)) ] + - location: 14 (remaining gas: 1039994.454 units remaining) + [ {} + (Some (Pair False True)) ] + - location: 16 (remaining gas: 1039994.439 units remaining) + [ (Pair {} (Some (Pair False True))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair True False)-(Some (Pair True False))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair True False)-(Some (Pair True False))].out new file mode 100644 index 000000000000..a9ec169d004c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair True False)-(Some (Pair True False))].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair True False)-(Some (Pair True False))] + +storage + (Some (Pair True False)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039994.494 units remaining) + [ (Pair (Pair True False) None) ] + - location: 12 (remaining gas: 1039994.484 units remaining) + [ (Pair True False) @parameter ] + - location: 13 (remaining gas: 1039994.469 units remaining) + [ (Some (Pair True False)) ] + - location: 14 (remaining gas: 1039994.454 units remaining) + [ {} + (Some (Pair True False)) ] + - location: 16 (remaining gas: 1039994.439 units remaining) + [ (Pair {} (Some (Pair True False))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair True True)-(Some (Pair True True))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair True True)-(Some (Pair True True))].out new file mode 100644 index 000000000000..a766fb78d1f0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair True True)-(Some (Pair True True))].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[pair_id.tz-None-(Pair True True)-(Some (Pair True True))] + +storage + (Some (Pair True True)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039994.494 units remaining) + [ (Pair (Pair True True) None) ] + - location: 12 (remaining gas: 1039994.484 units remaining) + [ (Pair True True) @parameter ] + - location: 13 (remaining gas: 1039994.469 units remaining) + [ (Some (Pair True True)) ] + - location: 14 (remaining gas: 1039994.454 units remaining) + [ {} + (Some (Pair True True)) ] + - location: 16 (remaining gas: 1039994.439 units remaining) + [ (Pair {} (Some (Pair True True))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pexec.tz-14-38-52].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pexec.tz-14-38-52].out new file mode 100644 index 000000000000..8ecf8b9c087c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pexec.tz-14-38-52].out @@ -0,0 +1,47 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[pexec.tz-14-38-52] + +storage + 52 +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039990.569 units remaining) + [ (Pair 38 14) ] + - location: 7 (remaining gas: 1039990.559 units remaining) + [ { UNPAIR ; ADD } + (Pair 38 14) ] + - location: 15 (remaining gas: 1039990.549 units remaining) + [ (Pair 38 14) + { UNPAIR ; ADD } ] + - location: 16 (remaining gas: 1039990.539 units remaining) + [ 38 @parameter + 14 @storage + { UNPAIR ; ADD } ] + - location: 17 (remaining gas: 1039990.524 units remaining) + [ 14 @storage + { UNPAIR ; ADD } ] + - location: 19 (remaining gas: 1039990.324 units remaining) + [ { PUSH nat 14 ; PAIR ; { UNPAIR ; ADD } } ] + - location: 17 (remaining gas: 1039990.294 units remaining) + [ 38 @parameter + { PUSH nat 14 ; PAIR ; { UNPAIR ; ADD } } ] + - location: 12 (remaining gas: 1039990.284 units remaining) + [ 14 + 38 ] + - location: 12 (remaining gas: 1039990.269 units remaining) + [ (Pair 14 38) @arg ] + - location: 13 (remaining gas: 1039990.259 units remaining) + [ 14 + 38 ] + - location: 14 (remaining gas: 1039990.224 units remaining) + [ 52 ] + - location: 20 (remaining gas: 1039990.194 units remaining) + [ 52 ] + - location: 21 (remaining gas: 1039990.179 units remaining) + [ {} + 52 ] + - location: 23 (remaining gas: 1039990.164 units remaining) + [ (Pair {} 52) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pexec_2.tz-{ 0 ; 1 ; 2 ; 3}-4-{ 0 ; 7 ; 14 ; 21 }].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pexec_2.tz-{ 0 ; 1 ; 2 ; 3}-4-{ 0 ; 7 ; 14 ; 21 }].out new file mode 100644 index 000000000000..c401b1fc0d45 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[pexec_2.tz-{ 0 ; 1 ; 2 ; 3}-4-{ 0 ; 7 ; 14 ; 21 }].out @@ -0,0 +1,282 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[pexec_2.tz-{ 0 ; 1 ; 2 ; 3}-4-{ 0 ; 7 ; 14 ; 21 }] + +storage + { 0 ; 7 ; 14 ; 21 } +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039982.051 units remaining) + [ (Pair 4 { 0 ; 1 ; 2 ; 3 }) ] + - location: 8 (remaining gas: 1039982.041 units remaining) + [ 4 @p + { 0 ; 1 ; 2 ; 3 } @s ] + - location: 9 (remaining gas: 1039982.031 units remaining) + [ { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } + 4 @p + { 0 ; 1 ; 2 ; 3 } @s ] + - location: 23 (remaining gas: 1039982.021 units remaining) + [ 4 @p + { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } + { 0 ; 1 ; 2 ; 3 } @s ] + - location: 24 (remaining gas: 1039981.821 units remaining) + [ { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } + { 0 ; 1 ; 2 ; 3 } @s ] + - location: 25 (remaining gas: 1039981.811 units remaining) + [ 3 + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } + { 0 ; 1 ; 2 ; 3 } @s ] + - location: 28 (remaining gas: 1039981.611 units remaining) + [ { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } + { 0 ; 1 ; 2 ; 3 } @s ] + - location: 29 (remaining gas: 1039981.601 units remaining) + [ { 0 ; 1 ; 2 ; 3 } @s + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 30 (remaining gas: 1039981.601 units remaining) + [ 0 @s.elt + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 32 (remaining gas: 1039981.586 units remaining) + [ { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 34 (remaining gas: 1039981.576 units remaining) + [ { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 32 (remaining gas: 1039981.546 units remaining) + [ 0 @s.elt + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 16 (remaining gas: 1039981.536 units remaining) + [ 3 + 0 ] + - location: 16 (remaining gas: 1039981.521 units remaining) + [ (Pair 3 0) ] + - location: 16 (remaining gas: 1039981.511 units remaining) + [ 4 + (Pair 3 0) ] + - location: 16 (remaining gas: 1039981.496 units remaining) + [ (Pair 4 3 0) @arg ] + - location: 17 (remaining gas: 1039981.486 units remaining) + [ 4 + (Pair 3 0) ] + - location: 18 (remaining gas: 1039981.471 units remaining) + [ (Pair 3 0) ] + - location: 20 (remaining gas: 1039981.461 units remaining) + [ 3 + 0 ] + - location: 18 (remaining gas: 1039981.431 units remaining) + [ 4 + 3 + 0 ] + - location: 21 (remaining gas: 1039981.396 units remaining) + [ 7 + 0 ] + - location: 22 (remaining gas: 1039981.320 units remaining) + [ 0 ] + - location: 35 (remaining gas: 1039981.290 units remaining) + [ 0 + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 30 (remaining gas: 1039981.275 units remaining) + [ 1 @s.elt + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 32 (remaining gas: 1039981.260 units remaining) + [ { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 34 (remaining gas: 1039981.250 units remaining) + [ { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 32 (remaining gas: 1039981.220 units remaining) + [ 1 @s.elt + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 16 (remaining gas: 1039981.210 units remaining) + [ 3 + 1 ] + - location: 16 (remaining gas: 1039981.195 units remaining) + [ (Pair 3 1) ] + - location: 16 (remaining gas: 1039981.185 units remaining) + [ 4 + (Pair 3 1) ] + - location: 16 (remaining gas: 1039981.170 units remaining) + [ (Pair 4 3 1) @arg ] + - location: 17 (remaining gas: 1039981.160 units remaining) + [ 4 + (Pair 3 1) ] + - location: 18 (remaining gas: 1039981.145 units remaining) + [ (Pair 3 1) ] + - location: 20 (remaining gas: 1039981.135 units remaining) + [ 3 + 1 ] + - location: 18 (remaining gas: 1039981.105 units remaining) + [ 4 + 3 + 1 ] + - location: 21 (remaining gas: 1039981.070 units remaining) + [ 7 + 1 ] + - location: 22 (remaining gas: 1039980.991 units remaining) + [ 7 ] + - location: 35 (remaining gas: 1039980.961 units remaining) + [ 7 + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 30 (remaining gas: 1039980.946 units remaining) + [ 2 @s.elt + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 32 (remaining gas: 1039980.931 units remaining) + [ { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 34 (remaining gas: 1039980.921 units remaining) + [ { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 32 (remaining gas: 1039980.891 units remaining) + [ 2 @s.elt + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 16 (remaining gas: 1039980.881 units remaining) + [ 3 + 2 ] + - location: 16 (remaining gas: 1039980.866 units remaining) + [ (Pair 3 2) ] + - location: 16 (remaining gas: 1039980.856 units remaining) + [ 4 + (Pair 3 2) ] + - location: 16 (remaining gas: 1039980.841 units remaining) + [ (Pair 4 3 2) @arg ] + - location: 17 (remaining gas: 1039980.831 units remaining) + [ 4 + (Pair 3 2) ] + - location: 18 (remaining gas: 1039980.816 units remaining) + [ (Pair 3 2) ] + - location: 20 (remaining gas: 1039980.806 units remaining) + [ 3 + 2 ] + - location: 18 (remaining gas: 1039980.776 units remaining) + [ 4 + 3 + 2 ] + - location: 21 (remaining gas: 1039980.741 units remaining) + [ 7 + 2 ] + - location: 22 (remaining gas: 1039980.662 units remaining) + [ 14 ] + - location: 35 (remaining gas: 1039980.632 units remaining) + [ 14 + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 30 (remaining gas: 1039980.617 units remaining) + [ 3 @s.elt + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 32 (remaining gas: 1039980.602 units remaining) + [ { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 34 (remaining gas: 1039980.592 units remaining) + [ { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 32 (remaining gas: 1039980.562 units remaining) + [ 3 @s.elt + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 16 (remaining gas: 1039980.552 units remaining) + [ 3 + 3 ] + - location: 16 (remaining gas: 1039980.537 units remaining) + [ (Pair 3 3) ] + - location: 16 (remaining gas: 1039980.527 units remaining) + [ 4 + (Pair 3 3) ] + - location: 16 (remaining gas: 1039980.512 units remaining) + [ (Pair 4 3 3) @arg ] + - location: 17 (remaining gas: 1039980.502 units remaining) + [ 4 + (Pair 3 3) ] + - location: 18 (remaining gas: 1039980.487 units remaining) + [ (Pair 3 3) ] + - location: 20 (remaining gas: 1039980.477 units remaining) + [ 3 + 3 ] + - location: 18 (remaining gas: 1039980.447 units remaining) + [ 4 + 3 + 3 ] + - location: 21 (remaining gas: 1039980.412 units remaining) + [ 7 + 3 ] + - location: 22 (remaining gas: 1039980.333 units remaining) + [ 21 ] + - location: 35 (remaining gas: 1039980.303 units remaining) + [ 21 + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 30 (remaining gas: 1039980.288 units remaining) + [ { 0 ; 7 ; 14 ; 21 } + { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 36 (remaining gas: 1039980.273 units remaining) + [ { PUSH int 3 ; + PAIR ; + { PUSH int 4 ; PAIR ; { UNPAIR ; DIP { UNPAIR } ; ADD ; MUL } } } ] + - location: 38 (remaining gas: 1039980.263 units remaining) + [ ] + - location: 36 (remaining gas: 1039980.233 units remaining) + [ { 0 ; 7 ; 14 ; 21 } ] + - location: 39 (remaining gas: 1039980.218 units remaining) + [ {} + { 0 ; 7 ; 14 ; 21 } ] + - location: 41 (remaining gas: 1039980.203 units remaining) + [ (Pair {} { 0 ; 7 ; 14 ; 21 }) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ret_int.tz-None-Unit-(Some 300)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ret_int.tz-None-Unit-(Some 300)].out new file mode 100644 index 000000000000..bd138a010480 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[ret_int.tz-None-Unit-(Some 300)].out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[ret_int.tz-None-Unit-(Some 300)] + +storage + (Some 300) +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.441 units remaining) + [ (Pair Unit None) ] + - location: 8 (remaining gas: 1039994.431 units remaining) + [ ] + - location: 9 (remaining gas: 1039994.421 units remaining) + [ 300 ] + - location: 12 (remaining gas: 1039994.406 units remaining) + [ (Some 300) ] + - location: 13 (remaining gas: 1039994.391 units remaining) + [ {} + (Some 300) ] + - location: 15 (remaining gas: 1039994.376 units remaining) + [ (Pair {} (Some 300)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse.tz-{\"\"}-{ \"c\" ; \"b\" ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse.tz-{\"\"}-{ \"c\" ; \"b\" ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" new file mode 100644 index 000000000000..bef2d5ad4088 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse.tz-{\"\"}-{ \"c\" ; \"b\" ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" @@ -0,0 +1,42 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[reverse.tz-{""}-{ "c" ; "b" ; "a" }-{ "a" ; "b" ; "c" }] + +storage + { "a" ; "b" ; "c" } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039992.417 units remaining) + [ (Pair { "c" ; "b" ; "a" } { "" }) ] + - location: 9 (remaining gas: 1039992.407 units remaining) + [ { "c" ; "b" ; "a" } @parameter ] + - location: 10 (remaining gas: 1039992.392 units remaining) + [ {} + { "c" ; "b" ; "a" } @parameter ] + - location: 12 (remaining gas: 1039992.382 units remaining) + [ { "c" ; "b" ; "a" } @parameter + {} ] + - location: 13 (remaining gas: 1039992.382 units remaining) + [ "c" @parameter.elt + {} ] + - location: 15 (remaining gas: 1039992.367 units remaining) + [ { "c" } ] + - location: 13 (remaining gas: 1039992.352 units remaining) + [ "b" @parameter.elt + { "c" } ] + - location: 15 (remaining gas: 1039992.337 units remaining) + [ { "b" ; "c" } ] + - location: 13 (remaining gas: 1039992.322 units remaining) + [ "a" @parameter.elt + { "b" ; "c" } ] + - location: 15 (remaining gas: 1039992.307 units remaining) + [ { "a" ; "b" ; "c" } ] + - location: 13 (remaining gas: 1039992.292 units remaining) + [ { "a" ; "b" ; "c" } ] + - location: 16 (remaining gas: 1039992.277 units remaining) + [ {} + { "a" ; "b" ; "c" } ] + - location: 18 (remaining gas: 1039992.262 units remaining) + [ (Pair {} { "a" ; "b" ; "c" }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse.tz-{\"\"}-{}-{}].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse.tz-{\"\"}-{}-{}].out" new file mode 100644 index 000000000000..f034e59682d8 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse.tz-{\"\"}-{}-{}].out" @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[reverse.tz-{""}-{}-{}] + +storage + {} +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039992.789 units remaining) + [ (Pair {} { "" }) ] + - location: 9 (remaining gas: 1039992.779 units remaining) + [ {} @parameter ] + - location: 10 (remaining gas: 1039992.764 units remaining) + [ {} + {} @parameter ] + - location: 12 (remaining gas: 1039992.754 units remaining) + [ {} @parameter + {} ] + - location: 13 (remaining gas: 1039992.754 units remaining) + [ {} ] + - location: 16 (remaining gas: 1039992.739 units remaining) + [ {} + {} ] + - location: 18 (remaining gas: 1039992.724 units remaining) + [ (Pair {} {}) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse_loop.tz-{\"\"}-{ \"c\" ; \"b\" ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse_loop.tz-{\"\"}-{ \"c\" ; \"b\" ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" new file mode 100644 index 000000000000..2902eae96bf8 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse_loop.tz-{\"\"}-{ \"c\" ; \"b\" ; \"a\" }-{ \"a\" ; \"b\" ; \"c\" }].out" @@ -0,0 +1,131 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[reverse_loop.tz-{""}-{ "c" ; "b" ; "a" }-{ "a" ; "b" ; "c" }] + +storage + { "a" ; "b" ; "c" } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039985.072 units remaining) + [ (Pair { "c" ; "b" ; "a" } { "" }) ] + - location: 9 (remaining gas: 1039985.062 units remaining) + [ { "c" ; "b" ; "a" } @parameter ] + - location: 10 (remaining gas: 1039985.047 units remaining) + [ {} + { "c" ; "b" ; "a" } @parameter ] + - location: 12 (remaining gas: 1039985.037 units remaining) + [ { "c" ; "b" ; "a" } @parameter + {} ] + - location: 13 (remaining gas: 1039985.027 units remaining) + [ True + { "c" ; "b" ; "a" } @parameter + {} ] + - location: 16 (remaining gas: 1039985.027 units remaining) + [ { "c" ; "b" ; "a" } @parameter + {} ] + - location: 18 (remaining gas: 1039985.017 units remaining) + [ "c" @parameter.hd + { "b" ; "a" } @parameter.tl + {} ] + - location: 20 (remaining gas: 1039985.007 units remaining) + [ { "b" ; "a" } @parameter.tl + "c" @parameter.hd + {} ] + - location: 21 (remaining gas: 1039984.992 units remaining) + [ "c" @parameter.hd + {} ] + - location: 23 (remaining gas: 1039984.977 units remaining) + [ { "c" } ] + - location: 21 (remaining gas: 1039984.947 units remaining) + [ { "b" ; "a" } @parameter.tl + { "c" } ] + - location: 24 (remaining gas: 1039984.937 units remaining) + [ True + { "b" ; "a" } @parameter + { "c" } ] + - location: 18 (remaining gas: 1039984.922 units remaining) + [ True + { "b" ; "a" } @parameter + { "c" } ] + - location: 16 (remaining gas: 1039984.907 units remaining) + [ { "b" ; "a" } @parameter + { "c" } ] + - location: 18 (remaining gas: 1039984.897 units remaining) + [ "b" @parameter.hd + { "a" } @parameter.tl + { "c" } ] + - location: 20 (remaining gas: 1039984.887 units remaining) + [ { "a" } @parameter.tl + "b" @parameter.hd + { "c" } ] + - location: 21 (remaining gas: 1039984.872 units remaining) + [ "b" @parameter.hd + { "c" } ] + - location: 23 (remaining gas: 1039984.857 units remaining) + [ { "b" ; "c" } ] + - location: 21 (remaining gas: 1039984.827 units remaining) + [ { "a" } @parameter.tl + { "b" ; "c" } ] + - location: 24 (remaining gas: 1039984.817 units remaining) + [ True + { "a" } @parameter + { "b" ; "c" } ] + - location: 18 (remaining gas: 1039984.802 units remaining) + [ True + { "a" } @parameter + { "b" ; "c" } ] + - location: 16 (remaining gas: 1039984.787 units remaining) + [ { "a" } @parameter + { "b" ; "c" } ] + - location: 18 (remaining gas: 1039984.777 units remaining) + [ "a" @parameter.hd + {} @parameter.tl + { "b" ; "c" } ] + - location: 20 (remaining gas: 1039984.767 units remaining) + [ {} @parameter.tl + "a" @parameter.hd + { "b" ; "c" } ] + - location: 21 (remaining gas: 1039984.752 units remaining) + [ "a" @parameter.hd + { "b" ; "c" } ] + - location: 23 (remaining gas: 1039984.737 units remaining) + [ { "a" ; "b" ; "c" } ] + - location: 21 (remaining gas: 1039984.707 units remaining) + [ {} @parameter.tl + { "a" ; "b" ; "c" } ] + - location: 24 (remaining gas: 1039984.697 units remaining) + [ True + {} @parameter + { "a" ; "b" ; "c" } ] + - location: 18 (remaining gas: 1039984.682 units remaining) + [ True + {} @parameter + { "a" ; "b" ; "c" } ] + - location: 16 (remaining gas: 1039984.667 units remaining) + [ {} @parameter + { "a" ; "b" ; "c" } ] + - location: 18 (remaining gas: 1039984.657 units remaining) + [ { "a" ; "b" ; "c" } ] + - location: 28 (remaining gas: 1039984.642 units remaining) + [ {} + { "a" ; "b" ; "c" } ] + - location: 30 (remaining gas: 1039984.632 units remaining) + [ False + {} @parameter + { "a" ; "b" ; "c" } ] + - location: 18 (remaining gas: 1039984.617 units remaining) + [ False + {} @parameter + { "a" ; "b" ; "c" } ] + - location: 16 (remaining gas: 1039984.602 units remaining) + [ {} @parameter + { "a" ; "b" ; "c" } ] + - location: 33 (remaining gas: 1039984.592 units remaining) + [ { "a" ; "b" ; "c" } ] + - location: 34 (remaining gas: 1039984.577 units remaining) + [ {} + { "a" ; "b" ; "c" } ] + - location: 36 (remaining gas: 1039984.562 units remaining) + [ (Pair {} { "a" ; "b" ; "c" }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse_loop.tz-{\"\"}-{}-{}].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse_loop.tz-{\"\"}-{}-{}].out" new file mode 100644 index 000000000000..6358701563a5 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[reverse_loop.tz-{\"\"}-{}-{}].out" @@ -0,0 +1,50 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[reverse_loop.tz-{""}-{}-{}] + +storage + {} +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039985.444 units remaining) + [ (Pair {} { "" }) ] + - location: 9 (remaining gas: 1039985.434 units remaining) + [ {} @parameter ] + - location: 10 (remaining gas: 1039985.419 units remaining) + [ {} + {} @parameter ] + - location: 12 (remaining gas: 1039985.409 units remaining) + [ {} @parameter + {} ] + - location: 13 (remaining gas: 1039985.399 units remaining) + [ True + {} @parameter + {} ] + - location: 16 (remaining gas: 1039985.399 units remaining) + [ {} @parameter + {} ] + - location: 18 (remaining gas: 1039985.389 units remaining) + [ {} ] + - location: 28 (remaining gas: 1039985.374 units remaining) + [ {} + {} ] + - location: 30 (remaining gas: 1039985.364 units remaining) + [ False + {} @parameter + {} ] + - location: 18 (remaining gas: 1039985.349 units remaining) + [ False + {} @parameter + {} ] + - location: 16 (remaining gas: 1039985.334 units remaining) + [ {} @parameter + {} ] + - location: 33 (remaining gas: 1039985.324 units remaining) + [ {} ] + - location: 34 (remaining gas: 1039985.309 units remaining) + [ {} + {} ] + - location: 36 (remaining gas: 1039985.294 units remaining) + [ (Pair {} {}) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sapling_empty_state.tz-{}-Unit-0].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sapling_empty_state.tz-{}-Unit-0].out new file mode 100644 index 000000000000..dc1bff2670e9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sapling_empty_state.tz-{}-Unit-0].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[sapling_empty_state.tz-{}-Unit-0] + +storage + 0 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039995.577 units remaining) + [ (Pair Unit {}) ] + - location: 8 (remaining gas: 1039995.567 units remaining) + [ ] + - location: 9 (remaining gas: 1039995.552 units remaining) + [ {} @sapling ] + - location: 11 (remaining gas: 1039995.537 units remaining) + [ {} + {} @sapling ] + - location: 13 (remaining gas: 1039995.522 units remaining) + [ (Pair {} {}) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[self_address.tz-Unit-Unit-Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[self_address.tz-Unit-Unit-Unit].out new file mode 100644 index 000000000000..e33af9540249 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[self_address.tz-Unit-Unit-Unit].out @@ -0,0 +1,46 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[self_address.tz-Unit-Unit-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039985.599 units remaining) + [ (Pair Unit Unit) ] + - location: 7 (remaining gas: 1039985.589 units remaining) + [ ] + - location: 8 (remaining gas: 1039985.579 units remaining) + [ { DROP ; SELF_ADDRESS } ] + - location: 14 (remaining gas: 1039985.569 units remaining) + [ Unit + { DROP ; SELF_ADDRESS } ] + - location: 12 (remaining gas: 1039985.559 units remaining) + [ ] + - location: 13 (remaining gas: 1039985.544 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi" @self ] + - location: 15 (remaining gas: 1039985.514 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi" ] + - location: 16 (remaining gas: 1039985.499 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi" @self + "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi" ] + - location: 17 (remaining gas: 1039985.489 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi" @self.address + "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi" ] + - location: 20 (remaining gas: 1039985.453 units remaining) + [ 0 ] + - location: 21 (remaining gas: 1039985.438 units remaining) + [ True ] + - location: 22 (remaining gas: 1039985.428 units remaining) + [ ] + - location: 22 (remaining gas: 1039985.413 units remaining) + [ ] + - location: 28 (remaining gas: 1039985.403 units remaining) + [ Unit ] + - location: 29 (remaining gas: 1039985.388 units remaining) + [ {} + Unit ] + - location: 31 (remaining gas: 1039985.373 units remaining) + [ (Pair {} Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[self_with_default_entrypoint.tz-Unit-Unit-Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[self_with_default_entrypoint.tz-Unit-Unit-Unit].out new file mode 100644 index 000000000000..5ec75c7c3ebb --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[self_with_default_entrypoint.tz-Unit-Unit-Unit].out @@ -0,0 +1,47 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[self_with_default_entrypoint.tz-Unit-Unit-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 13 (remaining gas: 1039984.400 units remaining) + [ (Pair (Right (Left Unit)) Unit) ] + - location: 13 (remaining gas: 1039984.390 units remaining) + [ ] + - location: 14 (remaining gas: 1039984.375 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi" @self ] + - location: 15 (remaining gas: 1039984.365 units remaining) + [ ] + - location: 16 (remaining gas: 1039984.350 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi%A" @self ] + - location: 17 (remaining gas: 1039984.340 units remaining) + [ ] + - location: 18 (remaining gas: 1039984.325 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi" @self ] + - location: 19 (remaining gas: 1039973.014 units remaining) + [ 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @self.packed ] + - location: 20 (remaining gas: 1039972.999 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi" @self + 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @self.packed ] + - location: 21 (remaining gas: 1039961.688 units remaining) + [ 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @self.packed + 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @self.packed ] + - location: 24 (remaining gas: 1039961.653 units remaining) + [ 0 ] + - location: 25 (remaining gas: 1039961.638 units remaining) + [ True ] + - location: 26 (remaining gas: 1039961.628 units remaining) + [ ] + - location: 26 (remaining gas: 1039961.613 units remaining) + [ ] + - location: 32 (remaining gas: 1039961.603 units remaining) + [ Unit ] + - location: 33 (remaining gas: 1039961.588 units remaining) + [ {} + Unit ] + - location: 35 (remaining gas: 1039961.573 units remaining) + [ (Pair {} Unit) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[self_with_entrypoint.tz-Unit-Left (Left 0)-Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[self_with_entrypoint.tz-Unit-Left (Left 0)-Unit].out new file mode 100644 index 000000000000..336a1cbe9a89 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[self_with_entrypoint.tz-Unit-Left (Left 0)-Unit].out @@ -0,0 +1,93 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[self_with_entrypoint.tz-Unit-Left (Left 0)-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 13 (remaining gas: 1039960.391 units remaining) + [ (Pair (Left (Left 0)) Unit) ] + - location: 13 (remaining gas: 1039960.381 units remaining) + [ ] + - location: 14 (remaining gas: 1039960.366 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi%A" @self ] + - location: 15 (remaining gas: 1039948.989 units remaining) + [ 0x050a00000017011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe60041 @Apacked ] + - location: 16 (remaining gas: 1039948.974 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi" @self + 0x050a00000017011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe60041 @Apacked ] + - location: 17 (remaining gas: 1039937.663 units remaining) + [ 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @defpacked + 0x050a00000017011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe60041 @Apacked ] + - location: 18 (remaining gas: 1039937.653 units remaining) + [ 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @defpacked + 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @defpacked + 0x050a00000017011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe60041 @Apacked ] + - location: 19 (remaining gas: 1039937.638 units remaining) + [ 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @defpacked + 0x050a00000017011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe60041 @Apacked ] + - location: 21 (remaining gas: 1039937.628 units remaining) + [ 0x050a00000017011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe60041 @Apacked + 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @defpacked ] + - location: 19 (remaining gas: 1039937.598 units remaining) + [ 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @defpacked + 0x050a00000017011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe60041 @Apacked + 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @defpacked ] + - location: 24 (remaining gas: 1039937.563 units remaining) + [ -1 + 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @defpacked ] + - location: 25 (remaining gas: 1039937.548 units remaining) + [ True + 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @defpacked ] + - location: 26 (remaining gas: 1039937.538 units remaining) + [ 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @defpacked ] + - location: 26 (remaining gas: 1039937.523 units remaining) + [ 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @defpacked ] + - location: 32 (remaining gas: 1039937.508 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi" @self + 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @defpacked ] + - location: 33 (remaining gas: 1039926.197 units remaining) + [ 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @selfpacked + 0x050a00000016011d23c1d3d2f8a4ea5e8784b8f7ecf2ad304c0fe600 @defpacked ] + - location: 36 (remaining gas: 1039926.162 units remaining) + [ 0 ] + - location: 37 (remaining gas: 1039926.147 units remaining) + [ True ] + - location: 38 (remaining gas: 1039926.137 units remaining) + [ ] + - location: 38 (remaining gas: 1039926.122 units remaining) + [ ] + - location: 44 (remaining gas: 1039926.107 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi%A" @self ] + - location: 48 (remaining gas: 1039926.097 units remaining) + [ ] + - location: 49 (remaining gas: 1039926.082 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi%B" @self ] + - location: 53 (remaining gas: 1039926.072 units remaining) + [ ] + - location: 54 (remaining gas: 1039926.057 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi%maybe_C" @self ] + - location: 60 (remaining gas: 1039926.047 units remaining) + [ ] + - location: 61 (remaining gas: 1039926.032 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi%Z" @self ] + - location: 65 (remaining gas: 1039926.022 units remaining) + [ ] + - location: 66 (remaining gas: 1039926.007 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi" @self ] + - location: 76 (remaining gas: 1039925.997 units remaining) + [ ] + - location: 77 (remaining gas: 1039925.982 units remaining) + [ "KT1BEqzn5Wx8uJrZNvuS9DVHmLvG9td3fDLi" @self ] + - location: 87 (remaining gas: 1039925.972 units remaining) + [ ] + - location: 88 (remaining gas: 1039925.962 units remaining) + [ Unit ] + - location: 89 (remaining gas: 1039925.947 units remaining) + [ {} + Unit ] + - location: 91 (remaining gas: 1039925.932 units remaining) + [ (Pair {} Unit) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair \"hello\" 0)-\"\"-(Pair \"\" 0)].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair \"hello\" 0)-\"\"-(Pair \"\" 0)].out" new file mode 100644 index 000000000000..855afb563bf9 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair \"hello\" 0)-\"\"-(Pair \"\" 0)].out" @@ -0,0 +1,49 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair "hello" 0)-""-(Pair "" 0)] + +storage + (Pair "" 0) +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039988.641 units remaining) + [ (Pair "" "hello" 0) ] + - location: 9 (remaining gas: 1039988.631 units remaining) + [ (Pair "" "hello" 0) + (Pair "" "hello" 0) ] + - location: 10 (remaining gas: 1039988.621 units remaining) + [ (Pair "hello" 0) @storage + (Pair "" "hello" 0) ] + - location: 11 (remaining gas: 1039988.606 units remaining) + [ (Pair "" "hello" 0) ] + - location: 13 (remaining gas: 1039988.596 units remaining) + [ "" @parameter ] + - location: 11 (remaining gas: 1039988.566 units remaining) + [ (Pair "hello" 0) @storage + "" @parameter ] + - location: 15 (remaining gas: 1039988.556 units remaining) + [ (Pair "hello" 0) @storage + (Pair "hello" 0) @storage + "" @parameter ] + - location: 16 (remaining gas: 1039988.546 units remaining) + [ "hello" + (Pair "hello" 0) @storage + "" @parameter ] + - location: 17 (remaining gas: 1039988.536 units remaining) + [ (Pair "hello" 0) @storage + "" @parameter ] + - location: 18 (remaining gas: 1039988.526 units remaining) + [ 0 @storage.n + "" @parameter ] + - location: 19 (remaining gas: 1039988.516 units remaining) + [ "" @parameter + 0 @storage.n ] + - location: 20 (remaining gas: 1039988.501 units remaining) + [ (Pair "" 0) @storage ] + - location: 21 (remaining gas: 1039988.486 units remaining) + [ {} + (Pair "" 0) @storage ] + - location: 23 (remaining gas: 1039988.471 units remaining) + [ (Pair {} "" 0) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair \"hello\" 0)-\"abc\"-(Pair \"abc\" 0)].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair \"hello\" 0)-\"abc\"-(Pair \"abc\" 0)].out" new file mode 100644 index 000000000000..253572bdc089 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair \"hello\" 0)-\"abc\"-(Pair \"abc\" 0)].out" @@ -0,0 +1,49 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair "hello" 0)-"abc"-(Pair "abc" 0)] + +storage + (Pair "abc" 0) +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039988.611 units remaining) + [ (Pair "abc" "hello" 0) ] + - location: 9 (remaining gas: 1039988.601 units remaining) + [ (Pair "abc" "hello" 0) + (Pair "abc" "hello" 0) ] + - location: 10 (remaining gas: 1039988.591 units remaining) + [ (Pair "hello" 0) @storage + (Pair "abc" "hello" 0) ] + - location: 11 (remaining gas: 1039988.576 units remaining) + [ (Pair "abc" "hello" 0) ] + - location: 13 (remaining gas: 1039988.566 units remaining) + [ "abc" @parameter ] + - location: 11 (remaining gas: 1039988.536 units remaining) + [ (Pair "hello" 0) @storage + "abc" @parameter ] + - location: 15 (remaining gas: 1039988.526 units remaining) + [ (Pair "hello" 0) @storage + (Pair "hello" 0) @storage + "abc" @parameter ] + - location: 16 (remaining gas: 1039988.516 units remaining) + [ "hello" + (Pair "hello" 0) @storage + "abc" @parameter ] + - location: 17 (remaining gas: 1039988.506 units remaining) + [ (Pair "hello" 0) @storage + "abc" @parameter ] + - location: 18 (remaining gas: 1039988.496 units remaining) + [ 0 @storage.n + "abc" @parameter ] + - location: 19 (remaining gas: 1039988.486 units remaining) + [ "abc" @parameter + 0 @storage.n ] + - location: 20 (remaining gas: 1039988.471 units remaining) + [ (Pair "abc" 0) @storage ] + - location: 21 (remaining gas: 1039988.456 units remaining) + [ {} + (Pair "abc" 0) @storage ] + - location: 23 (remaining gas: 1039988.441 units remaining) + [ (Pair {} "abc" 0) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair \"hello\" 0)-\"world\"-(Pair \"world\" 0)].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair \"hello\" 0)-\"world\"-(Pair \"world\" 0)].out" new file mode 100644 index 000000000000..e6a5faca213f --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair \"hello\" 0)-\"world\"-(Pair \"world\" 0)].out" @@ -0,0 +1,49 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_car.tz-(Pair "hello" 0)-"world"-(Pair "world" 0)] + +storage + (Pair "world" 0) +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039988.591 units remaining) + [ (Pair "world" "hello" 0) ] + - location: 9 (remaining gas: 1039988.581 units remaining) + [ (Pair "world" "hello" 0) + (Pair "world" "hello" 0) ] + - location: 10 (remaining gas: 1039988.571 units remaining) + [ (Pair "hello" 0) @storage + (Pair "world" "hello" 0) ] + - location: 11 (remaining gas: 1039988.556 units remaining) + [ (Pair "world" "hello" 0) ] + - location: 13 (remaining gas: 1039988.546 units remaining) + [ "world" @parameter ] + - location: 11 (remaining gas: 1039988.516 units remaining) + [ (Pair "hello" 0) @storage + "world" @parameter ] + - location: 15 (remaining gas: 1039988.506 units remaining) + [ (Pair "hello" 0) @storage + (Pair "hello" 0) @storage + "world" @parameter ] + - location: 16 (remaining gas: 1039988.496 units remaining) + [ "hello" + (Pair "hello" 0) @storage + "world" @parameter ] + - location: 17 (remaining gas: 1039988.486 units remaining) + [ (Pair "hello" 0) @storage + "world" @parameter ] + - location: 18 (remaining gas: 1039988.476 units remaining) + [ 0 @storage.n + "world" @parameter ] + - location: 19 (remaining gas: 1039988.466 units remaining) + [ "world" @parameter + 0 @storage.n ] + - location: 20 (remaining gas: 1039988.451 units remaining) + [ (Pair "world" 0) @storage ] + - location: 21 (remaining gas: 1039988.436 units remaining) + [ {} + (Pair "world" 0) @storage ] + - location: 23 (remaining gas: 1039988.421 units remaining) + [ (Pair {} "world" 0) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair \"hello\" 0)-1-(Pair \"hello\" 1)].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair \"hello\" 0)-1-(Pair \"hello\" 1)].out" new file mode 100644 index 000000000000..51139c2ae0e6 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair \"hello\" 0)-1-(Pair \"hello\" 1)].out" @@ -0,0 +1,46 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair "hello" 0)-1-(Pair "hello" 1)] + +storage + (Pair "hello" 1) +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039989.258 units remaining) + [ (Pair 1 "hello" 0) ] + - location: 9 (remaining gas: 1039989.248 units remaining) + [ (Pair 1 "hello" 0) + (Pair 1 "hello" 0) ] + - location: 10 (remaining gas: 1039989.238 units remaining) + [ (Pair "hello" 0) @storage + (Pair 1 "hello" 0) ] + - location: 11 (remaining gas: 1039989.223 units remaining) + [ (Pair 1 "hello" 0) ] + - location: 13 (remaining gas: 1039989.213 units remaining) + [ 1 @parameter ] + - location: 11 (remaining gas: 1039989.183 units remaining) + [ (Pair "hello" 0) @storage + 1 @parameter ] + - location: 15 (remaining gas: 1039989.173 units remaining) + [ (Pair "hello" 0) @storage + (Pair "hello" 0) @storage + 1 @parameter ] + - location: 16 (remaining gas: 1039989.163 units remaining) + [ 0 + (Pair "hello" 0) @storage + 1 @parameter ] + - location: 17 (remaining gas: 1039989.153 units remaining) + [ (Pair "hello" 0) @storage + 1 @parameter ] + - location: 18 (remaining gas: 1039989.143 units remaining) + [ "hello" @storage.s + 1 @parameter ] + - location: 19 (remaining gas: 1039989.128 units remaining) + [ (Pair "hello" 1) @storage ] + - location: 20 (remaining gas: 1039989.113 units remaining) + [ {} + (Pair "hello" 1) @storage ] + - location: 22 (remaining gas: 1039989.098 units remaining) + [ (Pair {} "hello" 1) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair \"hello\" 500)-3-(Pair \"hello\" 3)].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair \"hello\" 500)-3-(Pair \"hello\" 3)].out" new file mode 100644 index 000000000000..d6831dc1a73d --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair \"hello\" 500)-3-(Pair \"hello\" 3)].out" @@ -0,0 +1,46 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair "hello" 500)-3-(Pair "hello" 3)] + +storage + (Pair "hello" 3) +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039989.258 units remaining) + [ (Pair 3 "hello" 500) ] + - location: 9 (remaining gas: 1039989.248 units remaining) + [ (Pair 3 "hello" 500) + (Pair 3 "hello" 500) ] + - location: 10 (remaining gas: 1039989.238 units remaining) + [ (Pair "hello" 500) @storage + (Pair 3 "hello" 500) ] + - location: 11 (remaining gas: 1039989.223 units remaining) + [ (Pair 3 "hello" 500) ] + - location: 13 (remaining gas: 1039989.213 units remaining) + [ 3 @parameter ] + - location: 11 (remaining gas: 1039989.183 units remaining) + [ (Pair "hello" 500) @storage + 3 @parameter ] + - location: 15 (remaining gas: 1039989.173 units remaining) + [ (Pair "hello" 500) @storage + (Pair "hello" 500) @storage + 3 @parameter ] + - location: 16 (remaining gas: 1039989.163 units remaining) + [ 500 + (Pair "hello" 500) @storage + 3 @parameter ] + - location: 17 (remaining gas: 1039989.153 units remaining) + [ (Pair "hello" 500) @storage + 3 @parameter ] + - location: 18 (remaining gas: 1039989.143 units remaining) + [ "hello" @storage.s + 3 @parameter ] + - location: 19 (remaining gas: 1039989.128 units remaining) + [ (Pair "hello" 3) @storage ] + - location: 20 (remaining gas: 1039989.113 units remaining) + [ {} + (Pair "hello" 3) @storage ] + - location: 22 (remaining gas: 1039989.098 units remaining) + [ (Pair {} "hello" 3) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair \"hello\" 7)-100-(Pair \"hello\" 100)].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair \"hello\" 7)-100-(Pair \"hello\" 100)].out" new file mode 100644 index 000000000000..e41970d581ff --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair \"hello\" 7)-100-(Pair \"hello\" 100)].out" @@ -0,0 +1,46 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_cdr.tz-(Pair "hello" 7)-100-(Pair "hello" 100)] + +storage + (Pair "hello" 100) +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039989.258 units remaining) + [ (Pair 100 "hello" 7) ] + - location: 9 (remaining gas: 1039989.248 units remaining) + [ (Pair 100 "hello" 7) + (Pair 100 "hello" 7) ] + - location: 10 (remaining gas: 1039989.238 units remaining) + [ (Pair "hello" 7) @storage + (Pair 100 "hello" 7) ] + - location: 11 (remaining gas: 1039989.223 units remaining) + [ (Pair 100 "hello" 7) ] + - location: 13 (remaining gas: 1039989.213 units remaining) + [ 100 @parameter ] + - location: 11 (remaining gas: 1039989.183 units remaining) + [ (Pair "hello" 7) @storage + 100 @parameter ] + - location: 15 (remaining gas: 1039989.173 units remaining) + [ (Pair "hello" 7) @storage + (Pair "hello" 7) @storage + 100 @parameter ] + - location: 16 (remaining gas: 1039989.163 units remaining) + [ 7 + (Pair "hello" 7) @storage + 100 @parameter ] + - location: 17 (remaining gas: 1039989.153 units remaining) + [ (Pair "hello" 7) @storage + 100 @parameter ] + - location: 18 (remaining gas: 1039989.143 units remaining) + [ "hello" @storage.s + 100 @parameter ] + - location: 19 (remaining gas: 1039989.128 units remaining) + [ (Pair "hello" 100) @storage ] + - location: 20 (remaining gas: 1039989.113 units remaining) + [ {} + (Pair "hello" 100) @storage ] + - location: 22 (remaining gas: 1039989.098 units remaining) + [ (Pair {} "hello" 100) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{ \"a\" ; \"b\" ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{ \"a\" ; \"b\" ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" new file mode 100644 index 000000000000..3ec43715344d --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{ \"a\" ; \"b\" ; \"c\" }-{ \"a\" ; \"b\" ; \"c\" }].out" @@ -0,0 +1,19 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{ "a" ; "b" ; "c" }-{ "a" ; "b" ; "c" }] + +storage + { "a" ; "b" ; "c" } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039994.823 units remaining) + [ (Pair { "a" ; "b" ; "c" } {}) ] + - location: 9 (remaining gas: 1039994.813 units remaining) + [ { "a" ; "b" ; "c" } @parameter ] + - location: 10 (remaining gas: 1039994.798 units remaining) + [ {} + { "a" ; "b" ; "c" } @parameter ] + - location: 12 (remaining gas: 1039994.783 units remaining) + [ (Pair {} { "a" ; "b" ; "c" }) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{ \"asdf\" ; \"bcde\" }-{ \"asdf\" ; \"bcde\" }].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{ \"asdf\" ; \"bcde\" }-{ \"asdf\" ; \"bcde\" }].out" new file mode 100644 index 000000000000..07bc30efb99f --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{ \"asdf\" ; \"bcde\" }-{ \"asdf\" ; \"bcde\" }].out" @@ -0,0 +1,19 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{ "asdf" ; "bcde" }-{ "asdf" ; "bcde" }] + +storage + { "asdf" ; "bcde" } +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039995.212 units remaining) + [ (Pair { "asdf" ; "bcde" } {}) ] + - location: 9 (remaining gas: 1039995.202 units remaining) + [ { "asdf" ; "bcde" } @parameter ] + - location: 10 (remaining gas: 1039995.187 units remaining) + [ {} + { "asdf" ; "bcde" } @parameter ] + - location: 12 (remaining gas: 1039995.172 units remaining) + [ (Pair {} { "asdf" ; "bcde" }) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{}-{}].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{}-{}].out new file mode 100644 index 000000000000..c730327f31b5 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{}-{}].out @@ -0,0 +1,19 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_id.tz-{}-{}-{}] + +storage + {} +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039995.925 units remaining) + [ (Pair {} {}) ] + - location: 9 (remaining gas: 1039995.915 units remaining) + [ {} @parameter ] + - location: 10 (remaining gas: 1039995.900 units remaining) + [ {} + {} @parameter ] + - location: 12 (remaining gas: 1039995.885 units remaining) + [ (Pair {} {}) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{ -100 ; 1 ; 2 ; 3 }--94].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{ -100 ; 1 ; 2 ; 3 }--94].out new file mode 100644 index 000000000000..96c47d1f1b83 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{ -100 ; 1 ; 2 ; 3 }--94].out @@ -0,0 +1,47 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{ -100 ; 1 ; 2 ; 3 }--94] + +storage + -94 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039991.618 units remaining) + [ (Pair { -100 ; 1 ; 2 ; 3 } 111) ] + - location: 8 (remaining gas: 1039991.608 units remaining) + [ { -100 ; 1 ; 2 ; 3 } @parameter ] + - location: 9 (remaining gas: 1039991.598 units remaining) + [ 0 + { -100 ; 1 ; 2 ; 3 } @parameter ] + - location: 12 (remaining gas: 1039991.588 units remaining) + [ { -100 ; 1 ; 2 ; 3 } @parameter + 0 ] + - location: 13 (remaining gas: 1039991.588 units remaining) + [ -100 @parameter.elt + 0 ] + - location: 15 (remaining gas: 1039991.553 units remaining) + [ -100 ] + - location: 13 (remaining gas: 1039991.538 units remaining) + [ 1 @parameter.elt + -100 ] + - location: 15 (remaining gas: 1039991.503 units remaining) + [ -99 ] + - location: 13 (remaining gas: 1039991.488 units remaining) + [ 2 @parameter.elt + -99 ] + - location: 15 (remaining gas: 1039991.453 units remaining) + [ -97 ] + - location: 13 (remaining gas: 1039991.438 units remaining) + [ 3 @parameter.elt + -97 ] + - location: 15 (remaining gas: 1039991.403 units remaining) + [ -94 ] + - location: 13 (remaining gas: 1039991.388 units remaining) + [ -94 ] + - location: 16 (remaining gas: 1039991.373 units remaining) + [ {} + -94 ] + - location: 18 (remaining gas: 1039991.358 units remaining) + [ (Pair {} -94) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{ 1 }-1].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{ 1 }-1].out new file mode 100644 index 000000000000..857807d36871 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{ 1 }-1].out @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{ 1 }-1] + +storage + 1 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039992.823 units remaining) + [ (Pair { 1 } 111) ] + - location: 8 (remaining gas: 1039992.813 units remaining) + [ { 1 } @parameter ] + - location: 9 (remaining gas: 1039992.803 units remaining) + [ 0 + { 1 } @parameter ] + - location: 12 (remaining gas: 1039992.793 units remaining) + [ { 1 } @parameter + 0 ] + - location: 13 (remaining gas: 1039992.793 units remaining) + [ 1 @parameter.elt + 0 ] + - location: 15 (remaining gas: 1039992.758 units remaining) + [ 1 ] + - location: 13 (remaining gas: 1039992.743 units remaining) + [ 1 ] + - location: 16 (remaining gas: 1039992.728 units remaining) + [ {} + 1 ] + - location: 18 (remaining gas: 1039992.713 units remaining) + [ (Pair {} 1) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{}-0].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{}-0].out new file mode 100644 index 000000000000..1b58e9e72c1a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{}-0].out @@ -0,0 +1,27 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_iter.tz-111-{}-0] + +storage + 0 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039993.073 units remaining) + [ (Pair {} 111) ] + - location: 8 (remaining gas: 1039993.063 units remaining) + [ {} @parameter ] + - location: 9 (remaining gas: 1039993.053 units remaining) + [ 0 + {} @parameter ] + - location: 12 (remaining gas: 1039993.043 units remaining) + [ {} @parameter + 0 ] + - location: 13 (remaining gas: 1039993.043 units remaining) + [ 0 ] + - location: 16 (remaining gas: 1039993.028 units remaining) + [ {} + 0 ] + - location: 18 (remaining gas: 1039993.013 units remaining) + [ (Pair {} 0) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair { \"Hello\" ; \"World\" } None)-\"\"-(Pai.3d2044726e.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair { \"Hello\" ; \"World\" } None)-\"\"-(Pai.3d2044726e.out" new file mode 100644 index 000000000000..002ab644be95 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair { \"Hello\" ; \"World\" } None)-\"\"-(Pai.3d2044726e.out" @@ -0,0 +1,61 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair { "Hello" ; "World" } None)-""-(Pair { "Hello" ; "World" } (Some False))] + +storage + (Pair { "Hello" ; "World" } (Some False)) +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039985.013 units remaining) + [ (Pair "" { "Hello" ; "World" } None) ] + - location: 11 (remaining gas: 1039985.003 units remaining) + [ (Pair "" { "Hello" ; "World" } None) + (Pair "" { "Hello" ; "World" } None) ] + - location: 12 (remaining gas: 1039984.993 units remaining) + [ (Pair "" { "Hello" ; "World" } None) + (Pair "" { "Hello" ; "World" } None) + (Pair "" { "Hello" ; "World" } None) ] + - location: 13 (remaining gas: 1039984.983 units remaining) + [ "" @parameter + (Pair "" { "Hello" ; "World" } None) + (Pair "" { "Hello" ; "World" } None) ] + - location: 14 (remaining gas: 1039984.968 units remaining) + [ (Pair "" { "Hello" ; "World" } None) + (Pair "" { "Hello" ; "World" } None) ] + - location: 17 (remaining gas: 1039984.958 units remaining) + [ (Pair { "Hello" ; "World" } None) @storage + (Pair "" { "Hello" ; "World" } None) ] + - location: 18 (remaining gas: 1039984.948 units remaining) + [ { "Hello" ; "World" } + (Pair "" { "Hello" ; "World" } None) ] + - location: 14 (remaining gas: 1039984.918 units remaining) + [ "" @parameter + { "Hello" ; "World" } + (Pair "" { "Hello" ; "World" } None) ] + - location: 19 (remaining gas: 1039984.733 units remaining) + [ False + (Pair "" { "Hello" ; "World" } None) ] + - location: 20 (remaining gas: 1039984.718 units remaining) + [ (Some False) + (Pair "" { "Hello" ; "World" } None) ] + - location: 21 (remaining gas: 1039984.703 units remaining) + [ (Pair "" { "Hello" ; "World" } None) ] + - location: 24 (remaining gas: 1039984.693 units remaining) + [ (Pair { "Hello" ; "World" } None) @storage ] + - location: 25 (remaining gas: 1039984.683 units remaining) + [ { "Hello" ; "World" } ] + - location: 21 (remaining gas: 1039984.653 units remaining) + [ (Some False) + { "Hello" ; "World" } ] + - location: 26 (remaining gas: 1039984.643 units remaining) + [ { "Hello" ; "World" } + (Some False) ] + - location: 27 (remaining gas: 1039984.628 units remaining) + [ (Pair { "Hello" ; "World" } (Some False)) ] + - location: 28 (remaining gas: 1039984.613 units remaining) + [ {} + (Pair { "Hello" ; "World" } (Some False)) ] + - location: 30 (remaining gas: 1039984.598 units remaining) + [ (Pair {} { "Hello" ; "World" } (Some False)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair { \"Hi\" } None)-\"Hi\"-(Pair { \"Hi\" } .564beb9251.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair { \"Hi\" } None)-\"Hi\"-(Pair { \"Hi\" } .564beb9251.out" new file mode 100644 index 000000000000..27b7bc64f147 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair { \"Hi\" } None)-\"Hi\"-(Pair { \"Hi\" } .564beb9251.out" @@ -0,0 +1,61 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair { "Hi" } None)-"Hi"-(Pair { "Hi" } (Some True))] + +storage + (Pair { "Hi" } (Some True)) +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039985.442 units remaining) + [ (Pair "Hi" { "Hi" } None) ] + - location: 11 (remaining gas: 1039985.432 units remaining) + [ (Pair "Hi" { "Hi" } None) + (Pair "Hi" { "Hi" } None) ] + - location: 12 (remaining gas: 1039985.422 units remaining) + [ (Pair "Hi" { "Hi" } None) + (Pair "Hi" { "Hi" } None) + (Pair "Hi" { "Hi" } None) ] + - location: 13 (remaining gas: 1039985.412 units remaining) + [ "Hi" @parameter + (Pair "Hi" { "Hi" } None) + (Pair "Hi" { "Hi" } None) ] + - location: 14 (remaining gas: 1039985.397 units remaining) + [ (Pair "Hi" { "Hi" } None) + (Pair "Hi" { "Hi" } None) ] + - location: 17 (remaining gas: 1039985.387 units remaining) + [ (Pair { "Hi" } None) @storage + (Pair "Hi" { "Hi" } None) ] + - location: 18 (remaining gas: 1039985.377 units remaining) + [ { "Hi" } + (Pair "Hi" { "Hi" } None) ] + - location: 14 (remaining gas: 1039985.347 units remaining) + [ "Hi" @parameter + { "Hi" } + (Pair "Hi" { "Hi" } None) ] + - location: 19 (remaining gas: 1039985.197 units remaining) + [ True + (Pair "Hi" { "Hi" } None) ] + - location: 20 (remaining gas: 1039985.182 units remaining) + [ (Some True) + (Pair "Hi" { "Hi" } None) ] + - location: 21 (remaining gas: 1039985.167 units remaining) + [ (Pair "Hi" { "Hi" } None) ] + - location: 24 (remaining gas: 1039985.157 units remaining) + [ (Pair { "Hi" } None) @storage ] + - location: 25 (remaining gas: 1039985.147 units remaining) + [ { "Hi" } ] + - location: 21 (remaining gas: 1039985.117 units remaining) + [ (Some True) + { "Hi" } ] + - location: 26 (remaining gas: 1039985.107 units remaining) + [ { "Hi" } + (Some True) ] + - location: 27 (remaining gas: 1039985.092 units remaining) + [ (Pair { "Hi" } (Some True)) ] + - location: 28 (remaining gas: 1039985.077 units remaining) + [ {} + (Pair { "Hi" } (Some True)) ] + - location: 30 (remaining gas: 1039985.062 units remaining) + [ (Pair {} { "Hi" } (Some True)) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair {} None)-\"Hi\"-(Pair {} (Some False))].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair {} None)-\"Hi\"-(Pair {} (Some False))].out" new file mode 100644 index 000000000000..a742e9e1c66c --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair {} None)-\"Hi\"-(Pair {} (Some False))].out" @@ -0,0 +1,61 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_member.tz-(Pair {} None)-"Hi"-(Pair {} (Some False))] + +storage + (Pair {} (Some False)) +emitted operations + +big_map diff + +trace + - location: 11 (remaining gas: 1039985.726 units remaining) + [ (Pair "Hi" {} None) ] + - location: 11 (remaining gas: 1039985.716 units remaining) + [ (Pair "Hi" {} None) + (Pair "Hi" {} None) ] + - location: 12 (remaining gas: 1039985.706 units remaining) + [ (Pair "Hi" {} None) + (Pair "Hi" {} None) + (Pair "Hi" {} None) ] + - location: 13 (remaining gas: 1039985.696 units remaining) + [ "Hi" @parameter + (Pair "Hi" {} None) + (Pair "Hi" {} None) ] + - location: 14 (remaining gas: 1039985.681 units remaining) + [ (Pair "Hi" {} None) + (Pair "Hi" {} None) ] + - location: 17 (remaining gas: 1039985.671 units remaining) + [ (Pair {} None) @storage + (Pair "Hi" {} None) ] + - location: 18 (remaining gas: 1039985.661 units remaining) + [ {} + (Pair "Hi" {} None) ] + - location: 14 (remaining gas: 1039985.631 units remaining) + [ "Hi" @parameter + {} + (Pair "Hi" {} None) ] + - location: 19 (remaining gas: 1039985.516 units remaining) + [ False + (Pair "Hi" {} None) ] + - location: 20 (remaining gas: 1039985.501 units remaining) + [ (Some False) + (Pair "Hi" {} None) ] + - location: 21 (remaining gas: 1039985.486 units remaining) + [ (Pair "Hi" {} None) ] + - location: 24 (remaining gas: 1039985.476 units remaining) + [ (Pair {} None) @storage ] + - location: 25 (remaining gas: 1039985.466 units remaining) + [ {} ] + - location: 21 (remaining gas: 1039985.436 units remaining) + [ (Some False) + {} ] + - location: 26 (remaining gas: 1039985.426 units remaining) + [ {} + (Some False) ] + - location: 27 (remaining gas: 1039985.411 units remaining) + [ (Pair {} (Some False)) ] + - location: 28 (remaining gas: 1039985.396 units remaining) + [ {} + (Pair {} (Some False)) ] + - location: 30 (remaining gas: 1039985.381 units remaining) + [ (Pair {} {} (Some False)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }-6].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }-6].out new file mode 100644 index 000000000000..cb53b422bb98 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }-6].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }-6] + +storage + 6 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039993.095 units remaining) + [ (Pair { 1 ; 2 ; 3 ; 4 ; 5 ; 6 } 111) ] + - location: 8 (remaining gas: 1039993.085 units remaining) + [ { 1 ; 2 ; 3 ; 4 ; 5 ; 6 } @parameter ] + - location: 9 (remaining gas: 1039993.070 units remaining) + [ 6 ] + - location: 10 (remaining gas: 1039993.055 units remaining) + [ {} + 6 ] + - location: 12 (remaining gas: 1039993.040 units remaining) + [ (Pair {} 6) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 ; 2 ; 3 }-3].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 ; 2 ; 3 }-3].out new file mode 100644 index 000000000000..bd8c5b17743e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 ; 2 ; 3 }-3].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 ; 2 ; 3 }-3] + +storage + 3 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.510 units remaining) + [ (Pair { 1 ; 2 ; 3 } 111) ] + - location: 8 (remaining gas: 1039994.500 units remaining) + [ { 1 ; 2 ; 3 } @parameter ] + - location: 9 (remaining gas: 1039994.485 units remaining) + [ 3 ] + - location: 10 (remaining gas: 1039994.470 units remaining) + [ {} + 3 ] + - location: 12 (remaining gas: 1039994.455 units remaining) + [ (Pair {} 3) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 }-1].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 }-1].out new file mode 100644 index 000000000000..1494c3d4894a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 }-1].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_size.tz-111-{ 1 }-1] + +storage + 1 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039995.290 units remaining) + [ (Pair { 1 } 111) ] + - location: 8 (remaining gas: 1039995.280 units remaining) + [ { 1 } @parameter ] + - location: 9 (remaining gas: 1039995.265 units remaining) + [ 1 ] + - location: 10 (remaining gas: 1039995.250 units remaining) + [ {} + 1 ] + - location: 12 (remaining gas: 1039995.235 units remaining) + [ (Pair {} 1) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{}-0].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{}-0].out new file mode 100644 index 000000000000..42606cbe0467 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[set_size.tz-111-{}-0].out @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[set_size.tz-111-{}-0] + +storage + 0 +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039995.540 units remaining) + [ (Pair {} 111) ] + - location: 8 (remaining gas: 1039995.530 units remaining) + [ {} @parameter ] + - location: 9 (remaining gas: 1039995.515 units remaining) + [ 0 ] + - location: 10 (remaining gas: 1039995.500 units remaining) + [ {} + 0 ] + - location: 12 (remaining gas: 1039995.485 units remaining) + [ (Pair {} 0) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sha3.tz-None-0x48656c6c6f2c20776f726c6421-(Some 0xf345a.a07ae9dddf.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sha3.tz-None-0x48656c6c6f2c20776f726c6421-(Some 0xf345a.a07ae9dddf.out new file mode 100644 index 000000000000..d26695a2a3a4 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sha3.tz-None-0x48656c6c6f2c20776f726c6421-(Some 0xf345a.a07ae9dddf.out @@ -0,0 +1,24 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[sha3.tz-None-0x48656c6c6f2c20776f726c6421-(Some 0xf345a219da005ebe9c1a1eaad97bbf38a10c8473e41d0af7fb617caa0c6aa722)] + +storage + (Some 0xf345a219da005ebe9c1a1eaad97bbf38a10c8473e41d0af7fb617caa0c6aa722) +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039994.857 units remaining) + [ (Pair 0x48656c6c6f2c20776f726c6421 None) ] + - location: 8 (remaining gas: 1039994.847 units remaining) + [ 0x48656c6c6f2c20776f726c6421 @parameter ] + - location: 9 (remaining gas: 1039989.322 units remaining) + [ 0xf345a219da005ebe9c1a1eaad97bbf38a10c8473e41d0af7fb617caa0c6aa722 ] + - location: 10 (remaining gas: 1039989.307 units remaining) + [ (Some 0xf345a219da005ebe9c1a1eaad97bbf38a10c8473e41d0af7fb617caa0c6aa722) ] + - location: 11 (remaining gas: 1039989.292 units remaining) + [ {} + (Some 0xf345a219da005ebe9c1a1eaad97bbf38a10c8473e41d0af7fb617caa0c6aa722) ] + - location: 13 (remaining gas: 1039989.277 units remaining) + [ (Pair {} + (Some 0xf345a219da005ebe9c1a1eaad97bbf38a10c8473e41d0af7fb617caa0c6aa722)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 0 0))-(Some 0)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 0 0))-(Some 0)].out new file mode 100644 index 000000000000..b1b97ba2ba14 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 0 0))-(Some 0)].out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 0 0))-(Some 0)] + +storage + (Some 0) +emitted operations + +big_map diff + +trace + - location: 14 (remaining gas: 1039990.784 units remaining) + [ (Pair (Left (Pair 0 0)) None) ] + - location: 14 (remaining gas: 1039990.774 units remaining) + [ (Left (Pair 0 0)) @parameter ] + - location: 15 (remaining gas: 1039990.764 units remaining) + [ (Pair 0 0) @parameter.left ] + - location: 17 (remaining gas: 1039990.754 units remaining) + [ 0 + 0 ] + - location: 18 (remaining gas: 1039990.754 units remaining) + [ 0 ] + - location: 15 (remaining gas: 1039990.739 units remaining) + [ 0 ] + - location: 22 (remaining gas: 1039990.724 units remaining) + [ (Some 0) ] + - location: 23 (remaining gas: 1039990.709 units remaining) + [ {} + (Some 0) ] + - location: 25 (remaining gas: 1039990.694 units remaining) + [ (Pair {} (Some 0)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 0 1))-(Some 0)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 0 1))-(Some 0)].out new file mode 100644 index 000000000000..706eb94b7e79 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 0 1))-(Some 0)].out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 0 1))-(Some 0)] + +storage + (Some 0) +emitted operations + +big_map diff + +trace + - location: 14 (remaining gas: 1039990.784 units remaining) + [ (Pair (Left (Pair 0 1)) None) ] + - location: 14 (remaining gas: 1039990.774 units remaining) + [ (Left (Pair 0 1)) @parameter ] + - location: 15 (remaining gas: 1039990.764 units remaining) + [ (Pair 0 1) @parameter.left ] + - location: 17 (remaining gas: 1039990.754 units remaining) + [ 0 + 1 ] + - location: 18 (remaining gas: 1039990.754 units remaining) + [ 0 ] + - location: 15 (remaining gas: 1039990.739 units remaining) + [ 0 ] + - location: 22 (remaining gas: 1039990.724 units remaining) + [ (Some 0) ] + - location: 23 (remaining gas: 1039990.709 units remaining) + [ {} + (Some 0) ] + - location: 25 (remaining gas: 1039990.694 units remaining) + [ (Pair {} (Some 0)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 1 2))-(Some 4)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 1 2))-(Some 4)].out new file mode 100644 index 000000000000..e6896f7c0fda --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 1 2))-(Some 4)].out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 1 2))-(Some 4)] + +storage + (Some 4) +emitted operations + +big_map diff + +trace + - location: 14 (remaining gas: 1039990.784 units remaining) + [ (Pair (Left (Pair 1 2)) None) ] + - location: 14 (remaining gas: 1039990.774 units remaining) + [ (Left (Pair 1 2)) @parameter ] + - location: 15 (remaining gas: 1039990.764 units remaining) + [ (Pair 1 2) @parameter.left ] + - location: 17 (remaining gas: 1039990.754 units remaining) + [ 1 + 2 ] + - location: 18 (remaining gas: 1039990.754 units remaining) + [ 4 ] + - location: 15 (remaining gas: 1039990.739 units remaining) + [ 4 ] + - location: 22 (remaining gas: 1039990.724 units remaining) + [ (Some 4) ] + - location: 23 (remaining gas: 1039990.709 units remaining) + [ {} + (Some 4) ] + - location: 25 (remaining gas: 1039990.694 units remaining) + [ (Pair {} (Some 4)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 15 2))-(Some 60)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 15 2))-(Some 60)].out new file mode 100644 index 000000000000..49f27dc18f9c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 15 2))-(Some 60)].out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 15 2))-(Some 60)] + +storage + (Some 60) +emitted operations + +big_map diff + +trace + - location: 14 (remaining gas: 1039990.784 units remaining) + [ (Pair (Left (Pair 15 2)) None) ] + - location: 14 (remaining gas: 1039990.774 units remaining) + [ (Left (Pair 15 2)) @parameter ] + - location: 15 (remaining gas: 1039990.764 units remaining) + [ (Pair 15 2) @parameter.left ] + - location: 17 (remaining gas: 1039990.754 units remaining) + [ 15 + 2 ] + - location: 18 (remaining gas: 1039990.754 units remaining) + [ 60 ] + - location: 15 (remaining gas: 1039990.739 units remaining) + [ 60 ] + - location: 22 (remaining gas: 1039990.724 units remaining) + [ (Some 60) ] + - location: 23 (remaining gas: 1039990.709 units remaining) + [ {} + (Some 60) ] + - location: 25 (remaining gas: 1039990.694 units remaining) + [ (Pair {} (Some 60)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 8 1))-(Some 16)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 8 1))-(Some 16)].out new file mode 100644 index 000000000000..c840f4a7b45f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 8 1))-(Some 16)].out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Left (Pair 8 1))-(Some 16)] + +storage + (Some 16) +emitted operations + +big_map diff + +trace + - location: 14 (remaining gas: 1039990.784 units remaining) + [ (Pair (Left (Pair 8 1)) None) ] + - location: 14 (remaining gas: 1039990.774 units remaining) + [ (Left (Pair 8 1)) @parameter ] + - location: 15 (remaining gas: 1039990.764 units remaining) + [ (Pair 8 1) @parameter.left ] + - location: 17 (remaining gas: 1039990.754 units remaining) + [ 8 + 1 ] + - location: 18 (remaining gas: 1039990.754 units remaining) + [ 16 ] + - location: 15 (remaining gas: 1039990.739 units remaining) + [ 16 ] + - location: 22 (remaining gas: 1039990.724 units remaining) + [ (Some 16) ] + - location: 23 (remaining gas: 1039990.709 units remaining) + [ {} + (Some 16) ] + - location: 25 (remaining gas: 1039990.694 units remaining) + [ (Pair {} (Some 16)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 0 0))-(Some 0)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 0 0))-(Some 0)].out new file mode 100644 index 000000000000..b8aa608f03f5 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 0 0))-(Some 0)].out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 0 0))-(Some 0)] + +storage + (Some 0) +emitted operations + +big_map diff + +trace + - location: 14 (remaining gas: 1039990.784 units remaining) + [ (Pair (Right (Pair 0 0)) None) ] + - location: 14 (remaining gas: 1039990.774 units remaining) + [ (Right (Pair 0 0)) @parameter ] + - location: 15 (remaining gas: 1039990.764 units remaining) + [ (Pair 0 0) @parameter.right ] + - location: 20 (remaining gas: 1039990.754 units remaining) + [ 0 + 0 ] + - location: 21 (remaining gas: 1039990.754 units remaining) + [ 0 ] + - location: 15 (remaining gas: 1039990.739 units remaining) + [ 0 ] + - location: 22 (remaining gas: 1039990.724 units remaining) + [ (Some 0) ] + - location: 23 (remaining gas: 1039990.709 units remaining) + [ {} + (Some 0) ] + - location: 25 (remaining gas: 1039990.694 units remaining) + [ (Pair {} (Some 0)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 0 1))-(Some 0)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 0 1))-(Some 0)].out new file mode 100644 index 000000000000..ba52098a6830 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 0 1))-(Some 0)].out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 0 1))-(Some 0)] + +storage + (Some 0) +emitted operations + +big_map diff + +trace + - location: 14 (remaining gas: 1039990.784 units remaining) + [ (Pair (Right (Pair 0 1)) None) ] + - location: 14 (remaining gas: 1039990.774 units remaining) + [ (Right (Pair 0 1)) @parameter ] + - location: 15 (remaining gas: 1039990.764 units remaining) + [ (Pair 0 1) @parameter.right ] + - location: 20 (remaining gas: 1039990.754 units remaining) + [ 0 + 1 ] + - location: 21 (remaining gas: 1039990.754 units remaining) + [ 0 ] + - location: 15 (remaining gas: 1039990.739 units remaining) + [ 0 ] + - location: 22 (remaining gas: 1039990.724 units remaining) + [ (Some 0) ] + - location: 23 (remaining gas: 1039990.709 units remaining) + [ {} + (Some 0) ] + - location: 25 (remaining gas: 1039990.694 units remaining) + [ (Pair {} (Some 0)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 1 2))-(Some 0)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 1 2))-(Some 0)].out new file mode 100644 index 000000000000..8b7fc71480a6 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 1 2))-(Some 0)].out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 1 2))-(Some 0)] + +storage + (Some 0) +emitted operations + +big_map diff + +trace + - location: 14 (remaining gas: 1039990.784 units remaining) + [ (Pair (Right (Pair 1 2)) None) ] + - location: 14 (remaining gas: 1039990.774 units remaining) + [ (Right (Pair 1 2)) @parameter ] + - location: 15 (remaining gas: 1039990.764 units remaining) + [ (Pair 1 2) @parameter.right ] + - location: 20 (remaining gas: 1039990.754 units remaining) + [ 1 + 2 ] + - location: 21 (remaining gas: 1039990.754 units remaining) + [ 0 ] + - location: 15 (remaining gas: 1039990.739 units remaining) + [ 0 ] + - location: 22 (remaining gas: 1039990.724 units remaining) + [ (Some 0) ] + - location: 23 (remaining gas: 1039990.709 units remaining) + [ {} + (Some 0) ] + - location: 25 (remaining gas: 1039990.694 units remaining) + [ (Pair {} (Some 0)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 15 2))-(Some 3)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 15 2))-(Some 3)].out new file mode 100644 index 000000000000..31a229e79d1a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 15 2))-(Some 3)].out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 15 2))-(Some 3)] + +storage + (Some 3) +emitted operations + +big_map diff + +trace + - location: 14 (remaining gas: 1039990.784 units remaining) + [ (Pair (Right (Pair 15 2)) None) ] + - location: 14 (remaining gas: 1039990.774 units remaining) + [ (Right (Pair 15 2)) @parameter ] + - location: 15 (remaining gas: 1039990.764 units remaining) + [ (Pair 15 2) @parameter.right ] + - location: 20 (remaining gas: 1039990.754 units remaining) + [ 15 + 2 ] + - location: 21 (remaining gas: 1039990.754 units remaining) + [ 3 ] + - location: 15 (remaining gas: 1039990.739 units remaining) + [ 3 ] + - location: 22 (remaining gas: 1039990.724 units remaining) + [ (Some 3) ] + - location: 23 (remaining gas: 1039990.709 units remaining) + [ {} + (Some 3) ] + - location: 25 (remaining gas: 1039990.694 units remaining) + [ (Pair {} (Some 3)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 8 1))-(Some 4)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 8 1))-(Some 4)].out new file mode 100644 index 000000000000..bcf23c383d3f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 8 1))-(Some 4)].out @@ -0,0 +1,30 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[shifts.tz-None-(Right (Pair 8 1))-(Some 4)] + +storage + (Some 4) +emitted operations + +big_map diff + +trace + - location: 14 (remaining gas: 1039990.784 units remaining) + [ (Pair (Right (Pair 8 1)) None) ] + - location: 14 (remaining gas: 1039990.774 units remaining) + [ (Right (Pair 8 1)) @parameter ] + - location: 15 (remaining gas: 1039990.764 units remaining) + [ (Pair 8 1) @parameter.right ] + - location: 20 (remaining gas: 1039990.754 units remaining) + [ 8 + 1 ] + - location: 21 (remaining gas: 1039990.754 units remaining) + [ 4 ] + - location: 15 (remaining gas: 1039990.739 units remaining) + [ 4 ] + - location: 22 (remaining gas: 1039990.724 units remaining) + [ (Some 4) ] + - location: 23 (remaining gas: 1039990.709 units remaining) + [ {} + (Some 4) ] + - location: 25 (remaining gas: 1039990.694 units remaining) + [ (Pair {} (Some 4)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-None-Pair 0 0-None].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-None-Pair 0 0-None].out new file mode 100644 index 000000000000..89bb5fd01d3f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-None-Pair 0 0-None].out @@ -0,0 +1,31 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice.tz-None-Pair 0 0-None] + +storage + None +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.302 units remaining) + [ (Pair (Pair 0 0) None) ] + - location: 10 (remaining gas: 1039990.292 units remaining) + [ (Pair 0 0) @parameter + None @storage ] + - location: 11 (remaining gas: 1039990.282 units remaining) + [ None @storage + (Pair 0 0) @parameter ] + - location: 13 (remaining gas: 1039990.272 units remaining) + [ (Pair 0 0) @parameter ] + - location: 15 (remaining gas: 1039990.262 units remaining) + [ ] + - location: 16 (remaining gas: 1039990.247 units remaining) + [ None ] + - location: 13 (remaining gas: 1039990.232 units remaining) + [ None ] + - location: 22 (remaining gas: 1039990.217 units remaining) + [ {} + None ] + - location: 24 (remaining gas: 1039990.202 units remaining) + [ (Pair {} None) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 0 0-(Some \"\")].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 0 0-(Some \"\")].out" new file mode 100644 index 000000000000..4a8f5a385a73 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 0 0-(Some \"\")].out" @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice.tz-Some "Foo"-Pair 0 0-(Some "")] + +storage + (Some "") +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.158 units remaining) + [ (Pair (Pair 0 0) (Some "Foo")) ] + - location: 10 (remaining gas: 1039990.148 units remaining) + [ (Pair 0 0) @parameter + (Some "Foo") @storage ] + - location: 11 (remaining gas: 1039990.138 units remaining) + [ (Some "Foo") @storage + (Pair 0 0) @parameter ] + - location: 13 (remaining gas: 1039990.128 units remaining) + [ "Foo" @storage.some + (Pair 0 0) @parameter ] + - location: 19 (remaining gas: 1039990.118 units remaining) + [ (Pair 0 0) @parameter + "Foo" @storage.some ] + - location: 20 (remaining gas: 1039990.108 units remaining) + [ 0 + 0 + "Foo" @storage.some ] + - location: 21 (remaining gas: 1039990.078 units remaining) + [ (Some "") ] + - location: 13 (remaining gas: 1039990.063 units remaining) + [ (Some "") ] + - location: 22 (remaining gas: 1039990.048 units remaining) + [ {} + (Some "") ] + - location: 24 (remaining gas: 1039990.033 units remaining) + [ (Pair {} (Some "")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 0 10-None].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 0 10-None].out" new file mode 100644 index 000000000000..86e6071a7082 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 0 10-None].out" @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice.tz-Some "Foo"-Pair 0 10-None] + +storage + None +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.158 units remaining) + [ (Pair (Pair 0 10) (Some "Foo")) ] + - location: 10 (remaining gas: 1039990.148 units remaining) + [ (Pair 0 10) @parameter + (Some "Foo") @storage ] + - location: 11 (remaining gas: 1039990.138 units remaining) + [ (Some "Foo") @storage + (Pair 0 10) @parameter ] + - location: 13 (remaining gas: 1039990.128 units remaining) + [ "Foo" @storage.some + (Pair 0 10) @parameter ] + - location: 19 (remaining gas: 1039990.118 units remaining) + [ (Pair 0 10) @parameter + "Foo" @storage.some ] + - location: 20 (remaining gas: 1039990.108 units remaining) + [ 0 + 10 + "Foo" @storage.some ] + - location: 21 (remaining gas: 1039990.078 units remaining) + [ None ] + - location: 13 (remaining gas: 1039990.063 units remaining) + [ None ] + - location: 22 (remaining gas: 1039990.048 units remaining) + [ {} + None ] + - location: 24 (remaining gas: 1039990.033 units remaining) + [ (Pair {} None) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 0 2-(Some \"Fo\")].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 0 2-(Some \"Fo\")].out" new file mode 100644 index 000000000000..ee4858b965ba --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 0 2-(Some \"Fo\")].out" @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice.tz-Some "Foo"-Pair 0 2-(Some "Fo")] + +storage + (Some "Fo") +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.158 units remaining) + [ (Pair (Pair 0 2) (Some "Foo")) ] + - location: 10 (remaining gas: 1039990.148 units remaining) + [ (Pair 0 2) @parameter + (Some "Foo") @storage ] + - location: 11 (remaining gas: 1039990.138 units remaining) + [ (Some "Foo") @storage + (Pair 0 2) @parameter ] + - location: 13 (remaining gas: 1039990.128 units remaining) + [ "Foo" @storage.some + (Pair 0 2) @parameter ] + - location: 19 (remaining gas: 1039990.118 units remaining) + [ (Pair 0 2) @parameter + "Foo" @storage.some ] + - location: 20 (remaining gas: 1039990.108 units remaining) + [ 0 + 2 + "Foo" @storage.some ] + - location: 21 (remaining gas: 1039990.078 units remaining) + [ (Some "Fo") ] + - location: 13 (remaining gas: 1039990.063 units remaining) + [ (Some "Fo") ] + - location: 22 (remaining gas: 1039990.048 units remaining) + [ {} + (Some "Fo") ] + - location: 24 (remaining gas: 1039990.033 units remaining) + [ (Pair {} (Some "Fo")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 1 1-(Some \"o\")].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 1 1-(Some \"o\")].out" new file mode 100644 index 000000000000..cf91e2e202c3 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 1 1-(Some \"o\")].out" @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice.tz-Some "Foo"-Pair 1 1-(Some "o")] + +storage + (Some "o") +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.158 units remaining) + [ (Pair (Pair 1 1) (Some "Foo")) ] + - location: 10 (remaining gas: 1039990.148 units remaining) + [ (Pair 1 1) @parameter + (Some "Foo") @storage ] + - location: 11 (remaining gas: 1039990.138 units remaining) + [ (Some "Foo") @storage + (Pair 1 1) @parameter ] + - location: 13 (remaining gas: 1039990.128 units remaining) + [ "Foo" @storage.some + (Pair 1 1) @parameter ] + - location: 19 (remaining gas: 1039990.118 units remaining) + [ (Pair 1 1) @parameter + "Foo" @storage.some ] + - location: 20 (remaining gas: 1039990.108 units remaining) + [ 1 + 1 + "Foo" @storage.some ] + - location: 21 (remaining gas: 1039990.078 units remaining) + [ (Some "o") ] + - location: 13 (remaining gas: 1039990.063 units remaining) + [ (Some "o") ] + - location: 22 (remaining gas: 1039990.048 units remaining) + [ {} + (Some "o") ] + - location: 24 (remaining gas: 1039990.033 units remaining) + [ (Pair {} (Some "o")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 1 3-None].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 1 3-None].out" new file mode 100644 index 000000000000..0d75b3542217 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 1 3-None].out" @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice.tz-Some "Foo"-Pair 1 3-None] + +storage + None +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.158 units remaining) + [ (Pair (Pair 1 3) (Some "Foo")) ] + - location: 10 (remaining gas: 1039990.148 units remaining) + [ (Pair 1 3) @parameter + (Some "Foo") @storage ] + - location: 11 (remaining gas: 1039990.138 units remaining) + [ (Some "Foo") @storage + (Pair 1 3) @parameter ] + - location: 13 (remaining gas: 1039990.128 units remaining) + [ "Foo" @storage.some + (Pair 1 3) @parameter ] + - location: 19 (remaining gas: 1039990.118 units remaining) + [ (Pair 1 3) @parameter + "Foo" @storage.some ] + - location: 20 (remaining gas: 1039990.108 units remaining) + [ 1 + 3 + "Foo" @storage.some ] + - location: 21 (remaining gas: 1039990.078 units remaining) + [ None ] + - location: 13 (remaining gas: 1039990.063 units remaining) + [ None ] + - location: 22 (remaining gas: 1039990.048 units remaining) + [ {} + None ] + - location: 24 (remaining gas: 1039990.033 units remaining) + [ (Pair {} None) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 10 5-None].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 10 5-None].out" new file mode 100644 index 000000000000..2dc34d4e5b5b --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some \"Foo\"-Pair 10 5-None].out" @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice.tz-Some "Foo"-Pair 10 5-None] + +storage + None +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.158 units remaining) + [ (Pair (Pair 10 5) (Some "Foo")) ] + - location: 10 (remaining gas: 1039990.148 units remaining) + [ (Pair 10 5) @parameter + (Some "Foo") @storage ] + - location: 11 (remaining gas: 1039990.138 units remaining) + [ (Some "Foo") @storage + (Pair 10 5) @parameter ] + - location: 13 (remaining gas: 1039990.128 units remaining) + [ "Foo" @storage.some + (Pair 10 5) @parameter ] + - location: 19 (remaining gas: 1039990.118 units remaining) + [ (Pair 10 5) @parameter + "Foo" @storage.some ] + - location: 20 (remaining gas: 1039990.108 units remaining) + [ 10 + 5 + "Foo" @storage.some ] + - location: 21 (remaining gas: 1039990.078 units remaining) + [ None ] + - location: 13 (remaining gas: 1039990.063 units remaining) + [ None ] + - location: 22 (remaining gas: 1039990.048 units remaining) + [ {} + None ] + - location: 24 (remaining gas: 1039990.033 units remaining) + [ (Pair {} None) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some\"FooFooFooFooFooFooFooFooFooFooFooFooFooFo.c508d67bb0.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some\"FooFooFooFooFooFooFooFooFooFooFooFooFooFo.c508d67bb0.out" new file mode 100644 index 000000000000..1b5d672e6803 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice.tz-Some\"FooFooFooFooFooFooFooFooFooFooFooFooFooFo.c508d67bb0.out" @@ -0,0 +1,38 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice.tz-Some"FooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFoo"-Pair 1 10000-None] + +storage + None +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039930.188 units remaining) + [ (Pair (Pair 1 10000) + (Some "FooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFoo")) ] + - location: 10 (remaining gas: 1039930.178 units remaining) + [ (Pair 1 10000) @parameter + (Some "FooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFoo") @storage ] + - location: 11 (remaining gas: 1039930.168 units remaining) + [ (Some "FooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFoo") @storage + (Pair 1 10000) @parameter ] + - location: 13 (remaining gas: 1039930.158 units remaining) + [ "FooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFoo" @storage.some + (Pair 1 10000) @parameter ] + - location: 19 (remaining gas: 1039930.148 units remaining) + [ (Pair 1 10000) @parameter + "FooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFoo" @storage.some ] + - location: 20 (remaining gas: 1039930.138 units remaining) + [ 1 + 10000 + "FooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFooFoo" @storage.some ] + - location: 21 (remaining gas: 1039929.733 units remaining) + [ None ] + - location: 13 (remaining gas: 1039929.718 units remaining) + [ None ] + - location: 22 (remaining gas: 1039929.703 units remaining) + [ {} + None ] + - location: 24 (remaining gas: 1039929.688 units remaining) + [ (Pair {} None) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-None-Pair 0 1-None].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-None-Pair 0 1-None].out new file mode 100644 index 000000000000..2b7bc337e74c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-None-Pair 0 1-None].out @@ -0,0 +1,31 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice_bytes.tz-None-Pair 0 1-None] + +storage + None +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.302 units remaining) + [ (Pair (Pair 0 1) None) ] + - location: 10 (remaining gas: 1039990.292 units remaining) + [ (Pair 0 1) @parameter + None @storage ] + - location: 11 (remaining gas: 1039990.282 units remaining) + [ None @storage + (Pair 0 1) @parameter ] + - location: 13 (remaining gas: 1039990.272 units remaining) + [ (Pair 0 1) @parameter ] + - location: 15 (remaining gas: 1039990.262 units remaining) + [ ] + - location: 16 (remaining gas: 1039990.247 units remaining) + [ None ] + - location: 13 (remaining gas: 1039990.232 units remaining) + [ None ] + - location: 22 (remaining gas: 1039990.217 units remaining) + [ {} + None ] + - location: 24 (remaining gas: 1039990.202 units remaining) + [ (Pair {} None) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 0 0-(Some 0x)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 0 0-(Some 0x)].out new file mode 100644 index 000000000000..ce2fea77a73f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 0 0-(Some 0x)].out @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 0 0-(Some 0x)] + +storage + (Some 0x) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.202 units remaining) + [ (Pair (Pair 0 0) (Some 0xaabbcc)) ] + - location: 10 (remaining gas: 1039990.192 units remaining) + [ (Pair 0 0) @parameter + (Some 0xaabbcc) @storage ] + - location: 11 (remaining gas: 1039990.182 units remaining) + [ (Some 0xaabbcc) @storage + (Pair 0 0) @parameter ] + - location: 13 (remaining gas: 1039990.172 units remaining) + [ 0xaabbcc @storage.some + (Pair 0 0) @parameter ] + - location: 19 (remaining gas: 1039990.162 units remaining) + [ (Pair 0 0) @parameter + 0xaabbcc @storage.some ] + - location: 20 (remaining gas: 1039990.152 units remaining) + [ 0 + 0 + 0xaabbcc @storage.some ] + - location: 21 (remaining gas: 1039990.122 units remaining) + [ (Some 0x) ] + - location: 13 (remaining gas: 1039990.107 units remaining) + [ (Some 0x) ] + - location: 22 (remaining gas: 1039990.092 units remaining) + [ {} + (Some 0x) ] + - location: 24 (remaining gas: 1039990.077 units remaining) + [ (Pair {} (Some 0x)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 0 1-(Some 0xaa)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 0 1-(Some 0xaa)].out new file mode 100644 index 000000000000..8b73cfd5666f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 0 1-(Some 0xaa)].out @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 0 1-(Some 0xaa)] + +storage + (Some 0xaa) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.202 units remaining) + [ (Pair (Pair 0 1) (Some 0xaabbcc)) ] + - location: 10 (remaining gas: 1039990.192 units remaining) + [ (Pair 0 1) @parameter + (Some 0xaabbcc) @storage ] + - location: 11 (remaining gas: 1039990.182 units remaining) + [ (Some 0xaabbcc) @storage + (Pair 0 1) @parameter ] + - location: 13 (remaining gas: 1039990.172 units remaining) + [ 0xaabbcc @storage.some + (Pair 0 1) @parameter ] + - location: 19 (remaining gas: 1039990.162 units remaining) + [ (Pair 0 1) @parameter + 0xaabbcc @storage.some ] + - location: 20 (remaining gas: 1039990.152 units remaining) + [ 0 + 1 + 0xaabbcc @storage.some ] + - location: 21 (remaining gas: 1039990.122 units remaining) + [ (Some 0xaa) ] + - location: 13 (remaining gas: 1039990.107 units remaining) + [ (Some 0xaa) ] + - location: 22 (remaining gas: 1039990.092 units remaining) + [ {} + (Some 0xaa) ] + - location: 24 (remaining gas: 1039990.077 units remaining) + [ (Pair {} (Some 0xaa)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 1-(Some 0xbb)0].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 1-(Some 0xbb)0].out new file mode 100644 index 000000000000..abc6ce1636bd --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 1-(Some 0xbb)0].out @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 1-(Some 0xbb)0] + +storage + (Some 0xbb) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.202 units remaining) + [ (Pair (Pair 1 1) (Some 0xaabbcc)) ] + - location: 10 (remaining gas: 1039990.192 units remaining) + [ (Pair 1 1) @parameter + (Some 0xaabbcc) @storage ] + - location: 11 (remaining gas: 1039990.182 units remaining) + [ (Some 0xaabbcc) @storage + (Pair 1 1) @parameter ] + - location: 13 (remaining gas: 1039990.172 units remaining) + [ 0xaabbcc @storage.some + (Pair 1 1) @parameter ] + - location: 19 (remaining gas: 1039990.162 units remaining) + [ (Pair 1 1) @parameter + 0xaabbcc @storage.some ] + - location: 20 (remaining gas: 1039990.152 units remaining) + [ 1 + 1 + 0xaabbcc @storage.some ] + - location: 21 (remaining gas: 1039990.122 units remaining) + [ (Some 0xbb) ] + - location: 13 (remaining gas: 1039990.107 units remaining) + [ (Some 0xbb) ] + - location: 22 (remaining gas: 1039990.092 units remaining) + [ {} + (Some 0xbb) ] + - location: 24 (remaining gas: 1039990.077 units remaining) + [ (Pair {} (Some 0xbb)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 1-(Some 0xbb)1].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 1-(Some 0xbb)1].out new file mode 100644 index 000000000000..0b06f5913e5c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 1-(Some 0xbb)1].out @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 1-(Some 0xbb)1] + +storage + (Some 0xbb) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.202 units remaining) + [ (Pair (Pair 1 1) (Some 0xaabbcc)) ] + - location: 10 (remaining gas: 1039990.192 units remaining) + [ (Pair 1 1) @parameter + (Some 0xaabbcc) @storage ] + - location: 11 (remaining gas: 1039990.182 units remaining) + [ (Some 0xaabbcc) @storage + (Pair 1 1) @parameter ] + - location: 13 (remaining gas: 1039990.172 units remaining) + [ 0xaabbcc @storage.some + (Pair 1 1) @parameter ] + - location: 19 (remaining gas: 1039990.162 units remaining) + [ (Pair 1 1) @parameter + 0xaabbcc @storage.some ] + - location: 20 (remaining gas: 1039990.152 units remaining) + [ 1 + 1 + 0xaabbcc @storage.some ] + - location: 21 (remaining gas: 1039990.122 units remaining) + [ (Some 0xbb) ] + - location: 13 (remaining gas: 1039990.107 units remaining) + [ (Some 0xbb) ] + - location: 22 (remaining gas: 1039990.092 units remaining) + [ {} + (Some 0xbb) ] + - location: 24 (remaining gas: 1039990.077 units remaining) + [ (Pair {} (Some 0xbb)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 2-(Some 0xbbcc)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 2-(Some 0xbbcc)].out new file mode 100644 index 000000000000..d5b104433dd7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 2-(Some 0xbbcc)].out @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 2-(Some 0xbbcc)] + +storage + (Some 0xbbcc) +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.202 units remaining) + [ (Pair (Pair 1 2) (Some 0xaabbcc)) ] + - location: 10 (remaining gas: 1039990.192 units remaining) + [ (Pair 1 2) @parameter + (Some 0xaabbcc) @storage ] + - location: 11 (remaining gas: 1039990.182 units remaining) + [ (Some 0xaabbcc) @storage + (Pair 1 2) @parameter ] + - location: 13 (remaining gas: 1039990.172 units remaining) + [ 0xaabbcc @storage.some + (Pair 1 2) @parameter ] + - location: 19 (remaining gas: 1039990.162 units remaining) + [ (Pair 1 2) @parameter + 0xaabbcc @storage.some ] + - location: 20 (remaining gas: 1039990.152 units remaining) + [ 1 + 2 + 0xaabbcc @storage.some ] + - location: 21 (remaining gas: 1039990.122 units remaining) + [ (Some 0xbbcc) ] + - location: 13 (remaining gas: 1039990.107 units remaining) + [ (Some 0xbbcc) ] + - location: 22 (remaining gas: 1039990.092 units remaining) + [ {} + (Some 0xbbcc) ] + - location: 24 (remaining gas: 1039990.077 units remaining) + [ (Pair {} (Some 0xbbcc)) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 3-None].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 3-None].out new file mode 100644 index 000000000000..4bb40234e8c1 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 3-None].out @@ -0,0 +1,37 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbcc-Pair 1 3-None] + +storage + None +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.202 units remaining) + [ (Pair (Pair 1 3) (Some 0xaabbcc)) ] + - location: 10 (remaining gas: 1039990.192 units remaining) + [ (Pair 1 3) @parameter + (Some 0xaabbcc) @storage ] + - location: 11 (remaining gas: 1039990.182 units remaining) + [ (Some 0xaabbcc) @storage + (Pair 1 3) @parameter ] + - location: 13 (remaining gas: 1039990.172 units remaining) + [ 0xaabbcc @storage.some + (Pair 1 3) @parameter ] + - location: 19 (remaining gas: 1039990.162 units remaining) + [ (Pair 1 3) @parameter + 0xaabbcc @storage.some ] + - location: 20 (remaining gas: 1039990.152 units remaining) + [ 1 + 3 + 0xaabbcc @storage.some ] + - location: 21 (remaining gas: 1039990.122 units remaining) + [ None ] + - location: 13 (remaining gas: 1039990.107 units remaining) + [ None ] + - location: 22 (remaining gas: 1039990.092 units remaining) + [ {} + None ] + - location: 24 (remaining gas: 1039990.077 units remaining) + [ (Pair {} None) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbccaabbccaabbccaabbccaabbccaab.df5895de85.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbccaabbccaabbccaabbccaabbccaab.df5895de85.out new file mode 100644 index 000000000000..0de06c590d60 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbccaabbccaabbccaabbccaabbccaab.df5895de85.out @@ -0,0 +1,38 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[slice_bytes.tz-Some 0xaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbcc-Pair 1 10000-None] + +storage + None +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039990.202 units remaining) + [ (Pair (Pair 1 10000) + (Some 0xaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbcc)) ] + - location: 10 (remaining gas: 1039990.192 units remaining) + [ (Pair 1 10000) @parameter + (Some 0xaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbcc) @storage ] + - location: 11 (remaining gas: 1039990.182 units remaining) + [ (Some 0xaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbcc) @storage + (Pair 1 10000) @parameter ] + - location: 13 (remaining gas: 1039990.172 units remaining) + [ 0xaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbcc @storage.some + (Pair 1 10000) @parameter ] + - location: 19 (remaining gas: 1039990.162 units remaining) + [ (Pair 1 10000) @parameter + 0xaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbcc @storage.some ] + - location: 20 (remaining gas: 1039990.152 units remaining) + [ 1 + 10000 + 0xaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbcc @storage.some ] + - location: 21 (remaining gas: 1039989.747 units remaining) + [ None ] + - location: 13 (remaining gas: 1039989.732 units remaining) + [ None ] + - location: 22 (remaining gas: 1039989.717 units remaining) + [ {} + None ] + - location: 24 (remaining gas: 1039989.702 units remaining) + [ (Pair {} None) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[str_id.tz-None-\"Hello\"-(Some \"Hello\")].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[str_id.tz-None-\"Hello\"-(Some \"Hello\")].out" new file mode 100644 index 000000000000..3a7836b4868c --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[str_id.tz-None-\"Hello\"-(Some \"Hello\")].out" @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[str_id.tz-None-"Hello"-(Some "Hello")] + +storage + (Some "Hello") +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039995.391 units remaining) + [ (Pair "Hello" None) ] + - location: 8 (remaining gas: 1039995.381 units remaining) + [ "Hello" @parameter ] + - location: 9 (remaining gas: 1039995.366 units remaining) + [ (Some "Hello") ] + - location: 10 (remaining gas: 1039995.351 units remaining) + [ {} + (Some "Hello") ] + - location: 12 (remaining gas: 1039995.336 units remaining) + [ (Pair {} (Some "Hello")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[str_id.tz-None-\"abcd\"-(Some \"abcd\")].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[str_id.tz-None-\"abcd\"-(Some \"abcd\")].out" new file mode 100644 index 000000000000..5074d1678923 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[str_id.tz-None-\"abcd\"-(Some \"abcd\")].out" @@ -0,0 +1,21 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[str_id.tz-None-"abcd"-(Some "abcd")] + +storage + (Some "abcd") +emitted operations + +big_map diff + +trace + - location: 8 (remaining gas: 1039995.401 units remaining) + [ (Pair "abcd" None) ] + - location: 8 (remaining gas: 1039995.391 units remaining) + [ "abcd" @parameter ] + - location: 9 (remaining gas: 1039995.376 units remaining) + [ (Some "abcd") ] + - location: 10 (remaining gas: 1039995.361 units remaining) + [ {} + (Some "abcd") ] + - location: 12 (remaining gas: 1039995.346 units remaining) + [ (Pair {} (Some "abcd")) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 -100)-\"1970-01-01T00:03:20Z\"].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 -100)-\"1970-01-01T00:03:20Z\"].out" new file mode 100644 index 000000000000..875a320b04be --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 -100)-\"1970-01-01T00:03:20Z\"].out" @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 -100)-"1970-01-01T00:03:20Z"] + +storage + "1970-01-01T00:03:20Z" +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039992.273 units remaining) + [ (Pair (Pair "1970-01-01T00:01:40Z" -100) "1970-01-01T00:01:51Z") ] + - location: 9 (remaining gas: 1039992.263 units remaining) + [ (Pair "1970-01-01T00:01:40Z" -100) @parameter ] + - location: 10 (remaining gas: 1039992.253 units remaining) + [ (Pair "1970-01-01T00:01:40Z" -100) @parameter + (Pair "1970-01-01T00:01:40Z" -100) @parameter ] + - location: 11 (remaining gas: 1039992.243 units remaining) + [ "1970-01-01T00:01:40Z" + (Pair "1970-01-01T00:01:40Z" -100) @parameter ] + - location: 12 (remaining gas: 1039992.228 units remaining) + [ (Pair "1970-01-01T00:01:40Z" -100) @parameter ] + - location: 14 (remaining gas: 1039992.218 units remaining) + [ -100 ] + - location: 12 (remaining gas: 1039992.188 units remaining) + [ "1970-01-01T00:01:40Z" + -100 ] + - location: 15 (remaining gas: 1039992.153 units remaining) + [ "1970-01-01T00:03:20Z" ] + - location: 16 (remaining gas: 1039992.138 units remaining) + [ {} + "1970-01-01T00:03:20Z" ] + - location: 18 (remaining gas: 1039992.123 units remaining) + [ (Pair {} "1970-01-01T00:03:20Z") ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 100)-\"1970-01-01T00:00:00Z\"].out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 100)-\"1970-01-01T00:00:00Z\"].out" new file mode 100644 index 000000000000..c9c50d093027 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 100)-\"1970-01-01T00:00:00Z\"].out" @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 100)-"1970-01-01T00:00:00Z"] + +storage + "1970-01-01T00:00:00Z" +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039992.273 units remaining) + [ (Pair (Pair "1970-01-01T00:01:40Z" 100) "1970-01-01T00:01:51Z") ] + - location: 9 (remaining gas: 1039992.263 units remaining) + [ (Pair "1970-01-01T00:01:40Z" 100) @parameter ] + - location: 10 (remaining gas: 1039992.253 units remaining) + [ (Pair "1970-01-01T00:01:40Z" 100) @parameter + (Pair "1970-01-01T00:01:40Z" 100) @parameter ] + - location: 11 (remaining gas: 1039992.243 units remaining) + [ "1970-01-01T00:01:40Z" + (Pair "1970-01-01T00:01:40Z" 100) @parameter ] + - location: 12 (remaining gas: 1039992.228 units remaining) + [ (Pair "1970-01-01T00:01:40Z" 100) @parameter ] + - location: 14 (remaining gas: 1039992.218 units remaining) + [ 100 ] + - location: 12 (remaining gas: 1039992.188 units remaining) + [ "1970-01-01T00:01:40Z" + 100 ] + - location: 15 (remaining gas: 1039992.153 units remaining) + [ "1970-01-01T00:00:00Z" ] + - location: 16 (remaining gas: 1039992.138 units remaining) + [ {} + "1970-01-01T00:00:00Z" ] + - location: 18 (remaining gas: 1039992.123 units remaining) + [ (Pair {} "1970-01-01T00:00:00Z") ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 200000000000000000.3db82d2c25.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 200000000000000000.3db82d2c25.out new file mode 100644 index 000000000000..a454a7ac233e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 200000000000000000.3db82d2c25.out @@ -0,0 +1,34 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[sub_timestamp_delta.tz-111-(Pair 100 2000000000000000000)--1999999999999999900] + +storage + -1999999999999999900 +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039992.273 units remaining) + [ (Pair (Pair "1970-01-01T00:01:40Z" 2000000000000000000) "1970-01-01T00:01:51Z") ] + - location: 9 (remaining gas: 1039992.263 units remaining) + [ (Pair "1970-01-01T00:01:40Z" 2000000000000000000) @parameter ] + - location: 10 (remaining gas: 1039992.253 units remaining) + [ (Pair "1970-01-01T00:01:40Z" 2000000000000000000) @parameter + (Pair "1970-01-01T00:01:40Z" 2000000000000000000) @parameter ] + - location: 11 (remaining gas: 1039992.243 units remaining) + [ "1970-01-01T00:01:40Z" + (Pair "1970-01-01T00:01:40Z" 2000000000000000000) @parameter ] + - location: 12 (remaining gas: 1039992.228 units remaining) + [ (Pair "1970-01-01T00:01:40Z" 2000000000000000000) @parameter ] + - location: 14 (remaining gas: 1039992.218 units remaining) + [ 2000000000000000000 ] + - location: 12 (remaining gas: 1039992.188 units remaining) + [ "1970-01-01T00:01:40Z" + 2000000000000000000 ] + - location: 15 (remaining gas: 1039992.153 units remaining) + [ -1999999999999999900 ] + - location: 16 (remaining gas: 1039992.138 units remaining) + [ {} + -1999999999999999900 ] + - location: 18 (remaining gas: 1039992.123 units remaining) + [ (Pair {} -1999999999999999900) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[tez_add_sub.tz-None-(Pair 2000000 1000000)-(Some (Pair .b461aa042b.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[tez_add_sub.tz-None-(Pair 2000000 1000000)-(Some (Pair .b461aa042b.out new file mode 100644 index 000000000000..fd54bfe6793b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[tez_add_sub.tz-None-(Pair 2000000 1000000)-(Some (Pair .b461aa042b.out @@ -0,0 +1,67 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[tez_add_sub.tz-None-(Pair 2000000 1000000)-(Some (Pair 3000000 1000000))] + +storage + (Some (Pair 3000000 1000000)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039985.118 units remaining) + [ (Pair (Pair 2000000 1000000) None) ] + - location: 12 (remaining gas: 1039985.108 units remaining) + [ (Pair 2000000 1000000) @parameter ] + - location: 13 (remaining gas: 1039985.098 units remaining) + [ (Pair 2000000 1000000) @parameter + (Pair 2000000 1000000) @parameter ] + - location: 14 (remaining gas: 1039985.088 units remaining) + [ (Pair 2000000 1000000) @parameter + (Pair 2000000 1000000) @parameter + (Pair 2000000 1000000) @parameter ] + - location: 15 (remaining gas: 1039985.078 units remaining) + [ 2000000 + (Pair 2000000 1000000) @parameter + (Pair 2000000 1000000) @parameter ] + - location: 16 (remaining gas: 1039985.063 units remaining) + [ (Pair 2000000 1000000) @parameter + (Pair 2000000 1000000) @parameter ] + - location: 18 (remaining gas: 1039985.053 units remaining) + [ 1000000 + (Pair 2000000 1000000) @parameter ] + - location: 16 (remaining gas: 1039985.023 units remaining) + [ 2000000 + 1000000 + (Pair 2000000 1000000) @parameter ] + - location: 19 (remaining gas: 1039984.998 units remaining) + [ 3000000 + (Pair 2000000 1000000) @parameter ] + - location: 20 (remaining gas: 1039984.983 units remaining) + [ (Pair 2000000 1000000) @parameter ] + - location: 22 (remaining gas: 1039984.973 units remaining) + [ (Pair 2000000 1000000) @parameter + (Pair 2000000 1000000) @parameter ] + - location: 23 (remaining gas: 1039984.963 units remaining) + [ 2000000 + (Pair 2000000 1000000) @parameter ] + - location: 24 (remaining gas: 1039984.948 units remaining) + [ (Pair 2000000 1000000) @parameter ] + - location: 26 (remaining gas: 1039984.938 units remaining) + [ 1000000 ] + - location: 24 (remaining gas: 1039984.908 units remaining) + [ 2000000 + 1000000 ] + - location: 27 (remaining gas: 1039984.883 units remaining) + [ 1000000 ] + - location: 20 (remaining gas: 1039984.853 units remaining) + [ 3000000 + 1000000 ] + - location: 28 (remaining gas: 1039984.838 units remaining) + [ (Pair 3000000 1000000) ] + - location: 29 (remaining gas: 1039984.823 units remaining) + [ (Some (Pair 3000000 1000000)) ] + - location: 30 (remaining gas: 1039984.808 units remaining) + [ {} + (Some (Pair 3000000 1000000)) ] + - location: 32 (remaining gas: 1039984.793 units remaining) + [ (Pair {} (Some (Pair 3000000 1000000))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[tez_add_sub.tz-None-(Pair 2310000 1010000)-(Some (Pair .1e8cf7679c.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[tez_add_sub.tz-None-(Pair 2310000 1010000)-(Some (Pair .1e8cf7679c.out new file mode 100644 index 000000000000..decc8a257d6c --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[tez_add_sub.tz-None-(Pair 2310000 1010000)-(Some (Pair .1e8cf7679c.out @@ -0,0 +1,67 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[tez_add_sub.tz-None-(Pair 2310000 1010000)-(Some (Pair 3320000 1300000))] + +storage + (Some (Pair 3320000 1300000)) +emitted operations + +big_map diff + +trace + - location: 12 (remaining gas: 1039985.118 units remaining) + [ (Pair (Pair 2310000 1010000) None) ] + - location: 12 (remaining gas: 1039985.108 units remaining) + [ (Pair 2310000 1010000) @parameter ] + - location: 13 (remaining gas: 1039985.098 units remaining) + [ (Pair 2310000 1010000) @parameter + (Pair 2310000 1010000) @parameter ] + - location: 14 (remaining gas: 1039985.088 units remaining) + [ (Pair 2310000 1010000) @parameter + (Pair 2310000 1010000) @parameter + (Pair 2310000 1010000) @parameter ] + - location: 15 (remaining gas: 1039985.078 units remaining) + [ 2310000 + (Pair 2310000 1010000) @parameter + (Pair 2310000 1010000) @parameter ] + - location: 16 (remaining gas: 1039985.063 units remaining) + [ (Pair 2310000 1010000) @parameter + (Pair 2310000 1010000) @parameter ] + - location: 18 (remaining gas: 1039985.053 units remaining) + [ 1010000 + (Pair 2310000 1010000) @parameter ] + - location: 16 (remaining gas: 1039985.023 units remaining) + [ 2310000 + 1010000 + (Pair 2310000 1010000) @parameter ] + - location: 19 (remaining gas: 1039984.998 units remaining) + [ 3320000 + (Pair 2310000 1010000) @parameter ] + - location: 20 (remaining gas: 1039984.983 units remaining) + [ (Pair 2310000 1010000) @parameter ] + - location: 22 (remaining gas: 1039984.973 units remaining) + [ (Pair 2310000 1010000) @parameter + (Pair 2310000 1010000) @parameter ] + - location: 23 (remaining gas: 1039984.963 units remaining) + [ 2310000 + (Pair 2310000 1010000) @parameter ] + - location: 24 (remaining gas: 1039984.948 units remaining) + [ (Pair 2310000 1010000) @parameter ] + - location: 26 (remaining gas: 1039984.938 units remaining) + [ 1010000 ] + - location: 24 (remaining gas: 1039984.908 units remaining) + [ 2310000 + 1010000 ] + - location: 27 (remaining gas: 1039984.883 units remaining) + [ 1300000 ] + - location: 20 (remaining gas: 1039984.853 units remaining) + [ 3320000 + 1300000 ] + - location: 28 (remaining gas: 1039984.838 units remaining) + [ (Pair 3320000 1300000) ] + - location: 29 (remaining gas: 1039984.823 units remaining) + [ (Some (Pair 3320000 1300000)) ] + - location: 30 (remaining gas: 1039984.808 units remaining) + [ {} + (Some (Pair 3320000 1300000)) ] + - location: 32 (remaining gas: 1039984.793 units remaining) + [ (Pair {} (Some (Pair 3320000 1300000))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[uncomb.tz-0-(Pair 1 4 2)-142].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[uncomb.tz-0-(Pair 1 4 2)-142].out new file mode 100644 index 000000000000..bac6c2b9fb61 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[uncomb.tz-0-(Pair 1 4 2)-142].out @@ -0,0 +1,50 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[uncomb.tz-0-(Pair 1 4 2)-142] + +storage + 142 +emitted operations + +big_map diff + +trace + - location: 10 (remaining gas: 1039989.566 units remaining) + [ (Pair (Pair 1 4 2) 0) ] + - location: 10 (remaining gas: 1039989.556 units remaining) + [ (Pair 1 4 2) @parameter ] + - location: 11 (remaining gas: 1039989.519 units remaining) + [ 1 + 4 + 2 ] + - location: 13 (remaining gas: 1039989.509 units remaining) + [ 100 + 1 + 4 + 2 ] + - location: 16 (remaining gas: 1039989.430 units remaining) + [ 100 + 4 + 2 ] + - location: 17 (remaining gas: 1039989.420 units remaining) + [ 4 + 100 + 2 ] + - location: 18 (remaining gas: 1039989.410 units remaining) + [ 10 + 4 + 100 + 2 ] + - location: 21 (remaining gas: 1039989.331 units remaining) + [ 40 + 100 + 2 ] + - location: 22 (remaining gas: 1039989.296 units remaining) + [ 140 + 2 ] + - location: 23 (remaining gas: 1039989.261 units remaining) + [ 142 ] + - location: 24 (remaining gas: 1039989.246 units remaining) + [ {} + 142 ] + - location: 26 (remaining gas: 1039989.231 units remaining) + [ (Pair {} 142) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[unpair.tz-Unit-Unit-Unit].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[unpair.tz-Unit-Unit-Unit].out new file mode 100644 index 000000000000..5e380f1c6a4f --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[unpair.tz-Unit-Unit-Unit].out @@ -0,0 +1,462 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[unpair.tz-Unit-Unit-Unit] + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 7 (remaining gas: 1039873.809 units remaining) + [ (Pair Unit Unit) ] + - location: 7 (remaining gas: 1039873.799 units remaining) + [ ] + - location: 8 (remaining gas: 1039873.789 units remaining) + [ Unit ] + - location: 9 (remaining gas: 1039873.779 units remaining) + [ Unit + Unit ] + - location: 10 (remaining gas: 1039873.764 units remaining) + [ (Pair Unit Unit) ] + - location: 11 (remaining gas: 1039873.754 units remaining) + [ Unit + Unit ] + - location: 12 (remaining gas: 1039873.729 units remaining) + [ ] + - location: 14 (remaining gas: 1039873.719 units remaining) + [ Unit @b ] + - location: 15 (remaining gas: 1039873.709 units remaining) + [ Unit @a + Unit @b ] + - location: 16 (remaining gas: 1039873.694 units remaining) + [ (Pair Unit Unit) ] + - location: 17 (remaining gas: 1039873.684 units remaining) + [ Unit @c + Unit @d ] + - location: 18 (remaining gas: 1039873.659 units remaining) + [ ] + - location: 20 (remaining gas: 1039873.649 units remaining) + [ Unit @b ] + - location: 21 (remaining gas: 1039873.639 units remaining) + [ Unit @a + Unit @b ] + - location: 22 (remaining gas: 1039873.624 units remaining) + [ (Pair Unit Unit) ] + - location: 23 (remaining gas: 1039873.614 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 24 (remaining gas: 1039873.604 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 25 (remaining gas: 1039873.579 units remaining) + [ (Pair Unit Unit) ] + - location: 27 (remaining gas: 1039873.569 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 28 (remaining gas: 1039873.559 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 29 (remaining gas: 1039873.534 units remaining) + [ (Pair Unit Unit) ] + - location: 31 (remaining gas: 1039873.524 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 32 (remaining gas: 1039873.514 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 33 (remaining gas: 1039873.489 units remaining) + [ (Pair Unit Unit) ] + - location: 35 (remaining gas: 1039873.479 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 36 (remaining gas: 1039873.469 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 37 (remaining gas: 1039873.444 units remaining) + [ (Pair Unit Unit) ] + - location: 39 (remaining gas: 1039873.434 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 40 (remaining gas: 1039873.424 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 41 (remaining gas: 1039873.399 units remaining) + [ (Pair Unit Unit) ] + - location: 43 (remaining gas: 1039873.389 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 44 (remaining gas: 1039873.379 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 45 (remaining gas: 1039873.354 units remaining) + [ (Pair Unit Unit) ] + - location: 47 (remaining gas: 1039873.344 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 48 (remaining gas: 1039873.334 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 49 (remaining gas: 1039873.309 units remaining) + [ (Pair Unit Unit) ] + - location: 51 (remaining gas: 1039873.299 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 52 (remaining gas: 1039873.289 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 53 (remaining gas: 1039873.264 units remaining) + [ (Pair Unit Unit) ] + - location: 55 (remaining gas: 1039873.254 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 56 (remaining gas: 1039873.244 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 57 (remaining gas: 1039873.219 units remaining) + [ (Pair Unit Unit) ] + - location: 59 (remaining gas: 1039873.209 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 60 (remaining gas: 1039873.199 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 61 (remaining gas: 1039873.174 units remaining) + [ (Pair Unit Unit) ] + - location: 63 (remaining gas: 1039873.164 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 64 (remaining gas: 1039873.154 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 65 (remaining gas: 1039873.129 units remaining) + [ (Pair Unit Unit) ] + - location: 67 (remaining gas: 1039873.119 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 68 (remaining gas: 1039873.109 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 69 (remaining gas: 1039873.084 units remaining) + [ (Pair Unit Unit) ] + - location: 71 (remaining gas: 1039873.074 units remaining) + [ ] + - location: 72 (remaining gas: 1039873.064 units remaining) + [ Unit @d ] + - location: 73 (remaining gas: 1039873.054 units remaining) + [ Unit @c + Unit @d ] + - location: 74 (remaining gas: 1039873.039 units remaining) + [ (Pair Unit Unit) ] + - location: 75 (remaining gas: 1039873.029 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 76 (remaining gas: 1039873.019 units remaining) + [ Unit @c + Unit @d + (Pair Unit Unit) ] + - location: 77 (remaining gas: 1039872.994 units remaining) + [ (Pair Unit Unit) ] + - location: 79 (remaining gas: 1039872.984 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 80 (remaining gas: 1039872.974 units remaining) + [ Unit @c + Unit @d + (Pair Unit Unit) ] + - location: 81 (remaining gas: 1039872.949 units remaining) + [ (Pair Unit Unit) ] + - location: 83 (remaining gas: 1039872.939 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 84 (remaining gas: 1039872.929 units remaining) + [ Unit @c + Unit @d + (Pair Unit Unit) ] + - location: 85 (remaining gas: 1039872.904 units remaining) + [ (Pair Unit Unit) ] + - location: 87 (remaining gas: 1039872.894 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 88 (remaining gas: 1039872.884 units remaining) + [ Unit @c + Unit @d + (Pair Unit Unit) ] + - location: 89 (remaining gas: 1039872.859 units remaining) + [ (Pair Unit Unit) ] + - location: 91 (remaining gas: 1039872.849 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 92 (remaining gas: 1039872.839 units remaining) + [ Unit @c + Unit @d + (Pair Unit Unit) ] + - location: 93 (remaining gas: 1039872.814 units remaining) + [ (Pair Unit Unit) ] + - location: 95 (remaining gas: 1039872.804 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 96 (remaining gas: 1039872.794 units remaining) + [ Unit @c + Unit @d + (Pair Unit Unit) ] + - location: 97 (remaining gas: 1039872.769 units remaining) + [ (Pair Unit Unit) ] + - location: 99 (remaining gas: 1039872.759 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 100 (remaining gas: 1039872.749 units remaining) + [ Unit @c + Unit @d + (Pair Unit Unit) ] + - location: 101 (remaining gas: 1039872.724 units remaining) + [ (Pair Unit Unit) ] + - location: 103 (remaining gas: 1039872.714 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 104 (remaining gas: 1039872.704 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 105 (remaining gas: 1039872.679 units remaining) + [ (Pair Unit Unit) ] + - location: 107 (remaining gas: 1039872.669 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 108 (remaining gas: 1039872.659 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 109 (remaining gas: 1039872.634 units remaining) + [ (Pair Unit Unit) ] + - location: 111 (remaining gas: 1039872.624 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 112 (remaining gas: 1039872.614 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 113 (remaining gas: 1039872.589 units remaining) + [ (Pair Unit Unit) ] + - location: 115 (remaining gas: 1039872.579 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 116 (remaining gas: 1039872.569 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 117 (remaining gas: 1039872.544 units remaining) + [ (Pair Unit Unit) ] + - location: 119 (remaining gas: 1039872.534 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 120 (remaining gas: 1039872.524 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 121 (remaining gas: 1039872.499 units remaining) + [ (Pair Unit Unit) ] + - location: 123 (remaining gas: 1039872.489 units remaining) + [ ] + - location: 124 (remaining gas: 1039872.479 units remaining) + [ Unit ] + - location: 125 (remaining gas: 1039872.469 units remaining) + [ Unit + Unit ] + - location: 126 (remaining gas: 1039872.454 units remaining) + [ (Pair Unit Unit) ] + - location: 127 (remaining gas: 1039872.444 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 128 (remaining gas: 1039872.434 units remaining) + [ Unit + Unit + (Pair Unit Unit) ] + - location: 129 (remaining gas: 1039872.409 units remaining) + [ (Pair Unit Unit) ] + - location: 131 (remaining gas: 1039872.399 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 132 (remaining gas: 1039872.389 units remaining) + [ Unit + Unit + (Pair Unit Unit) ] + - location: 133 (remaining gas: 1039872.364 units remaining) + [ (Pair Unit Unit) ] + - location: 135 (remaining gas: 1039872.354 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 136 (remaining gas: 1039872.344 units remaining) + [ Unit + Unit + (Pair Unit Unit) ] + - location: 137 (remaining gas: 1039872.319 units remaining) + [ (Pair Unit Unit) ] + - location: 139 (remaining gas: 1039872.309 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 140 (remaining gas: 1039872.299 units remaining) + [ Unit + Unit + (Pair Unit Unit) ] + - location: 141 (remaining gas: 1039872.274 units remaining) + [ (Pair Unit Unit) ] + - location: 143 (remaining gas: 1039872.264 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 144 (remaining gas: 1039872.254 units remaining) + [ Unit + Unit + (Pair Unit Unit) ] + - location: 145 (remaining gas: 1039872.229 units remaining) + [ (Pair Unit Unit) ] + - location: 147 (remaining gas: 1039872.219 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 148 (remaining gas: 1039872.209 units remaining) + [ Unit + Unit + (Pair Unit Unit) ] + - location: 149 (remaining gas: 1039872.184 units remaining) + [ (Pair Unit Unit) ] + - location: 151 (remaining gas: 1039872.174 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 152 (remaining gas: 1039872.164 units remaining) + [ Unit + Unit + (Pair Unit Unit) ] + - location: 153 (remaining gas: 1039872.139 units remaining) + [ (Pair Unit Unit) ] + - location: 155 (remaining gas: 1039872.129 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 156 (remaining gas: 1039872.119 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 157 (remaining gas: 1039872.094 units remaining) + [ (Pair Unit Unit) ] + - location: 159 (remaining gas: 1039872.084 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 160 (remaining gas: 1039872.074 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 161 (remaining gas: 1039872.049 units remaining) + [ (Pair Unit Unit) ] + - location: 163 (remaining gas: 1039872.039 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 164 (remaining gas: 1039872.029 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 165 (remaining gas: 1039872.004 units remaining) + [ (Pair Unit Unit) ] + - location: 167 (remaining gas: 1039871.994 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 168 (remaining gas: 1039871.984 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 169 (remaining gas: 1039871.959 units remaining) + [ (Pair Unit Unit) ] + - location: 171 (remaining gas: 1039871.949 units remaining) + [ (Pair Unit Unit) + (Pair Unit Unit) ] + - location: 172 (remaining gas: 1039871.939 units remaining) + [ Unit @a + Unit @b + (Pair Unit Unit) ] + - location: 173 (remaining gas: 1039871.914 units remaining) + [ (Pair Unit Unit) ] + - location: 175 (remaining gas: 1039871.904 units remaining) + [ ] + - location: 176 (remaining gas: 1039871.894 units remaining) + [ Unit ] + - location: 177 (remaining gas: 1039871.884 units remaining) + [ Unit + Unit ] + - location: 178 (remaining gas: 1039871.869 units remaining) + [ (Pair Unit Unit) @p ] + - location: 179 (remaining gas: 1039871.859 units remaining) + [ (Pair Unit Unit) @p + (Pair Unit Unit) @p ] + - location: 180 (remaining gas: 1039871.849 units remaining) + [ Unit @p.a + Unit @b + (Pair Unit Unit) @p ] + - location: 181 (remaining gas: 1039871.824 units remaining) + [ (Pair Unit Unit) @p ] + - location: 183 (remaining gas: 1039871.814 units remaining) + [ (Pair Unit Unit) @p + (Pair Unit Unit) @p ] + - location: 184 (remaining gas: 1039871.804 units remaining) + [ Unit @a + Unit @p.b + (Pair Unit Unit) @p ] + - location: 185 (remaining gas: 1039871.779 units remaining) + [ (Pair Unit Unit) @p ] + - location: 187 (remaining gas: 1039871.769 units remaining) + [ (Pair Unit Unit) @p + (Pair Unit Unit) @p ] + - location: 188 (remaining gas: 1039871.759 units remaining) + [ Unit @p.a + Unit @p.b + (Pair Unit Unit) @p ] + - location: 189 (remaining gas: 1039871.734 units remaining) + [ (Pair Unit Unit) @p ] + - location: 191 (remaining gas: 1039871.724 units remaining) + [ (Pair Unit Unit) @p + (Pair Unit Unit) @p ] + - location: 192 (remaining gas: 1039871.714 units remaining) + [ Unit @a + Unit @p.b + (Pair Unit Unit) @p ] + - location: 193 (remaining gas: 1039871.689 units remaining) + [ (Pair Unit Unit) @p ] + - location: 195 (remaining gas: 1039871.679 units remaining) + [ (Pair Unit Unit) @p + (Pair Unit Unit) @p ] + - location: 196 (remaining gas: 1039871.669 units remaining) + [ Unit @p.a + Unit @b + (Pair Unit Unit) @p ] + - location: 197 (remaining gas: 1039871.644 units remaining) + [ (Pair Unit Unit) @p ] + - location: 199 (remaining gas: 1039871.634 units remaining) + [ ] + - location: 200 (remaining gas: 1039871.624 units remaining) + [ Unit @b ] + - location: 201 (remaining gas: 1039871.614 units remaining) + [ Unit @a + Unit @b ] + - location: 202 (remaining gas: 1039871.599 units remaining) + [ (Pair Unit Unit) @c ] + - location: 203 (remaining gas: 1039871.589 units remaining) + [ Unit @b + Unit @a ] + - location: 204 (remaining gas: 1039871.564 units remaining) + [ ] + - location: 206 (remaining gas: 1039871.554 units remaining) + [ Unit ] + - location: 207 (remaining gas: 1039871.539 units remaining) + [ {} + Unit ] + - location: 209 (remaining gas: 1039871.524 units remaining) + [ (Pair {} Unit) ] + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[voting_power.tz-(Pair 0 0)-\"edpkuBknW28nW72KG6RoHtYW7p1.b2c677ad7b.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[voting_power.tz-(Pair 0 0)-\"edpkuBknW28nW72KG6RoHtYW7p1.b2c677ad7b.out" new file mode 100644 index 000000000000..311f9834824e --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[voting_power.tz-(Pair 0 0)-\"edpkuBknW28nW72KG6RoHtYW7p1.b2c677ad7b.out" @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[voting_power.tz-(Pair 0 0)-"edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav"-(Pair 500 2500)] + +storage + (Pair 500 2500) +emitted operations + +big_map diff + +trace + - location: 9 (remaining gas: 1039965.403 units remaining) + [ (Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" 0 0) ] + - location: 9 (remaining gas: 1039965.393 units remaining) + [ "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" @parameter ] + - location: 10 (remaining gas: 1039964.738 units remaining) + [ "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" ] + - location: 11 (remaining gas: 1039744.330 units remaining) + [ 500 ] + - location: 12 (remaining gas: 1039744.315 units remaining) + [ ] + - location: 14 (remaining gas: 1039534.007 units remaining) + [ 2500 ] + - location: 12 (remaining gas: 1039533.977 units remaining) + [ 500 + 2500 ] + - location: 15 (remaining gas: 1039533.962 units remaining) + [ (Pair 500 2500) ] + - location: 16 (remaining gas: 1039533.947 units remaining) + [ {} + (Pair 500 2500) ] + - location: 18 (remaining gas: 1039533.932 units remaining) + [ (Pair {} 500 2500) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair False False)-(Some (Left False))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair False False)-(Some (Left False))].out new file mode 100644 index 000000000000..1dac8fcb1030 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair False False)-(Some (Left False))].out @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair False False)-(Some (Left False))] + +storage + (Some (Left False)) +emitted operations + +big_map diff + +trace + - location: 16 (remaining gas: 1039988.559 units remaining) + [ (Pair (Left (Pair False False)) None) ] + - location: 16 (remaining gas: 1039988.549 units remaining) + [ (Left (Pair False False)) @parameter ] + - location: 17 (remaining gas: 1039988.539 units remaining) + [ (Pair False False) @parameter.left ] + - location: 19 (remaining gas: 1039988.529 units remaining) + [ False + False ] + - location: 20 (remaining gas: 1039988.509 units remaining) + [ False ] + - location: 21 (remaining gas: 1039988.494 units remaining) + [ (Left False) ] + - location: 17 (remaining gas: 1039988.479 units remaining) + [ (Left False) ] + - location: 28 (remaining gas: 1039988.464 units remaining) + [ (Some (Left False)) ] + - location: 29 (remaining gas: 1039988.449 units remaining) + [ {} + (Some (Left False)) ] + - location: 31 (remaining gas: 1039988.434 units remaining) + [ (Pair {} (Some (Left False))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair False True)-(Some (Left True))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair False True)-(Some (Left True))].out new file mode 100644 index 000000000000..fcafd22c3142 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair False True)-(Some (Left True))].out @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair False True)-(Some (Left True))] + +storage + (Some (Left True)) +emitted operations + +big_map diff + +trace + - location: 16 (remaining gas: 1039988.559 units remaining) + [ (Pair (Left (Pair False True)) None) ] + - location: 16 (remaining gas: 1039988.549 units remaining) + [ (Left (Pair False True)) @parameter ] + - location: 17 (remaining gas: 1039988.539 units remaining) + [ (Pair False True) @parameter.left ] + - location: 19 (remaining gas: 1039988.529 units remaining) + [ False + True ] + - location: 20 (remaining gas: 1039988.509 units remaining) + [ True ] + - location: 21 (remaining gas: 1039988.494 units remaining) + [ (Left True) ] + - location: 17 (remaining gas: 1039988.479 units remaining) + [ (Left True) ] + - location: 28 (remaining gas: 1039988.464 units remaining) + [ (Some (Left True)) ] + - location: 29 (remaining gas: 1039988.449 units remaining) + [ {} + (Some (Left True)) ] + - location: 31 (remaining gas: 1039988.434 units remaining) + [ (Pair {} (Some (Left True))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair True False)-(Some (Left True))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair True False)-(Some (Left True))].out new file mode 100644 index 000000000000..914de14c1b61 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair True False)-(Some (Left True))].out @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair True False)-(Some (Left True))] + +storage + (Some (Left True)) +emitted operations + +big_map diff + +trace + - location: 16 (remaining gas: 1039988.559 units remaining) + [ (Pair (Left (Pair True False)) None) ] + - location: 16 (remaining gas: 1039988.549 units remaining) + [ (Left (Pair True False)) @parameter ] + - location: 17 (remaining gas: 1039988.539 units remaining) + [ (Pair True False) @parameter.left ] + - location: 19 (remaining gas: 1039988.529 units remaining) + [ True + False ] + - location: 20 (remaining gas: 1039988.509 units remaining) + [ True ] + - location: 21 (remaining gas: 1039988.494 units remaining) + [ (Left True) ] + - location: 17 (remaining gas: 1039988.479 units remaining) + [ (Left True) ] + - location: 28 (remaining gas: 1039988.464 units remaining) + [ (Some (Left True)) ] + - location: 29 (remaining gas: 1039988.449 units remaining) + [ {} + (Some (Left True)) ] + - location: 31 (remaining gas: 1039988.434 units remaining) + [ (Pair {} (Some (Left True))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair True True)-(Some (Left False))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair True True)-(Some (Left False))].out new file mode 100644 index 000000000000..9093774f6c07 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair True True)-(Some (Left False))].out @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[xor.tz-None-Left (Pair True True)-(Some (Left False))] + +storage + (Some (Left False)) +emitted operations + +big_map diff + +trace + - location: 16 (remaining gas: 1039988.559 units remaining) + [ (Pair (Left (Pair True True)) None) ] + - location: 16 (remaining gas: 1039988.549 units remaining) + [ (Left (Pair True True)) @parameter ] + - location: 17 (remaining gas: 1039988.539 units remaining) + [ (Pair True True) @parameter.left ] + - location: 19 (remaining gas: 1039988.529 units remaining) + [ True + True ] + - location: 20 (remaining gas: 1039988.509 units remaining) + [ False ] + - location: 21 (remaining gas: 1039988.494 units remaining) + [ (Left False) ] + - location: 17 (remaining gas: 1039988.479 units remaining) + [ (Left False) ] + - location: 28 (remaining gas: 1039988.464 units remaining) + [ (Some (Left False)) ] + - location: 29 (remaining gas: 1039988.449 units remaining) + [ {} + (Some (Left False)) ] + - location: 31 (remaining gas: 1039988.434 units remaining) + [ (Pair {} (Some (Left False))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 0 0)-(Some (Right 0))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 0 0)-(Some (Right 0))].out new file mode 100644 index 000000000000..333dec83533d --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 0 0)-(Some (Right 0))].out @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 0 0)-(Some (Right 0))] + +storage + (Some (Right 0)) +emitted operations + +big_map diff + +trace + - location: 16 (remaining gas: 1039988.559 units remaining) + [ (Pair (Right (Pair 0 0)) None) ] + - location: 16 (remaining gas: 1039988.549 units remaining) + [ (Right (Pair 0 0)) @parameter ] + - location: 17 (remaining gas: 1039988.539 units remaining) + [ (Pair 0 0) @parameter.right ] + - location: 24 (remaining gas: 1039988.529 units remaining) + [ 0 + 0 ] + - location: 25 (remaining gas: 1039988.494 units remaining) + [ 0 ] + - location: 26 (remaining gas: 1039988.479 units remaining) + [ (Right 0) ] + - location: 17 (remaining gas: 1039988.464 units remaining) + [ (Right 0) ] + - location: 28 (remaining gas: 1039988.449 units remaining) + [ (Some (Right 0)) ] + - location: 29 (remaining gas: 1039988.434 units remaining) + [ {} + (Some (Right 0)) ] + - location: 31 (remaining gas: 1039988.419 units remaining) + [ (Pair {} (Some (Right 0))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 0 1)-(Some (Right 1))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 0 1)-(Some (Right 1))].out new file mode 100644 index 000000000000..beace1e9ecc0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 0 1)-(Some (Right 1))].out @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 0 1)-(Some (Right 1))] + +storage + (Some (Right 1)) +emitted operations + +big_map diff + +trace + - location: 16 (remaining gas: 1039988.559 units remaining) + [ (Pair (Right (Pair 0 1)) None) ] + - location: 16 (remaining gas: 1039988.549 units remaining) + [ (Right (Pair 0 1)) @parameter ] + - location: 17 (remaining gas: 1039988.539 units remaining) + [ (Pair 0 1) @parameter.right ] + - location: 24 (remaining gas: 1039988.529 units remaining) + [ 0 + 1 ] + - location: 25 (remaining gas: 1039988.494 units remaining) + [ 1 ] + - location: 26 (remaining gas: 1039988.479 units remaining) + [ (Right 1) ] + - location: 17 (remaining gas: 1039988.464 units remaining) + [ (Right 1) ] + - location: 28 (remaining gas: 1039988.449 units remaining) + [ (Some (Right 1)) ] + - location: 29 (remaining gas: 1039988.434 units remaining) + [ {} + (Some (Right 1)) ] + - location: 31 (remaining gas: 1039988.419 units remaining) + [ (Pair {} (Some (Right 1))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 1 0)-(Some (Right 1))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 1 0)-(Some (Right 1))].out new file mode 100644 index 000000000000..c295a7fea574 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 1 0)-(Some (Right 1))].out @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 1 0)-(Some (Right 1))] + +storage + (Some (Right 1)) +emitted operations + +big_map diff + +trace + - location: 16 (remaining gas: 1039988.559 units remaining) + [ (Pair (Right (Pair 1 0)) None) ] + - location: 16 (remaining gas: 1039988.549 units remaining) + [ (Right (Pair 1 0)) @parameter ] + - location: 17 (remaining gas: 1039988.539 units remaining) + [ (Pair 1 0) @parameter.right ] + - location: 24 (remaining gas: 1039988.529 units remaining) + [ 1 + 0 ] + - location: 25 (remaining gas: 1039988.494 units remaining) + [ 1 ] + - location: 26 (remaining gas: 1039988.479 units remaining) + [ (Right 1) ] + - location: 17 (remaining gas: 1039988.464 units remaining) + [ (Right 1) ] + - location: 28 (remaining gas: 1039988.449 units remaining) + [ (Some (Right 1)) ] + - location: 29 (remaining gas: 1039988.434 units remaining) + [ {} + (Some (Right 1)) ] + - location: 31 (remaining gas: 1039988.419 units remaining) + [ (Pair {} (Some (Right 1))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 1 1)-(Some (Right 0))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 1 1)-(Some (Right 0))].out new file mode 100644 index 000000000000..3bcc3b367f0a --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 1 1)-(Some (Right 0))].out @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 1 1)-(Some (Right 0))] + +storage + (Some (Right 0)) +emitted operations + +big_map diff + +trace + - location: 16 (remaining gas: 1039988.559 units remaining) + [ (Pair (Right (Pair 1 1)) None) ] + - location: 16 (remaining gas: 1039988.549 units remaining) + [ (Right (Pair 1 1)) @parameter ] + - location: 17 (remaining gas: 1039988.539 units remaining) + [ (Pair 1 1) @parameter.right ] + - location: 24 (remaining gas: 1039988.529 units remaining) + [ 1 + 1 ] + - location: 25 (remaining gas: 1039988.494 units remaining) + [ 0 ] + - location: 26 (remaining gas: 1039988.479 units remaining) + [ (Right 0) ] + - location: 17 (remaining gas: 1039988.464 units remaining) + [ (Right 0) ] + - location: 28 (remaining gas: 1039988.449 units remaining) + [ (Some (Right 0)) ] + - location: 29 (remaining gas: 1039988.434 units remaining) + [ {} + (Some (Right 0)) ] + - location: 31 (remaining gas: 1039988.419 units remaining) + [ (Pair {} (Some (Right 0))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 42 21)-(Some (Right 63))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 42 21)-(Some (Right 63))].out new file mode 100644 index 000000000000..bdc93b618824 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 42 21)-(Some (Right 63))].out @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 42 21)-(Some (Right 63))] + +storage + (Some (Right 63)) +emitted operations + +big_map diff + +trace + - location: 16 (remaining gas: 1039988.559 units remaining) + [ (Pair (Right (Pair 42 21)) None) ] + - location: 16 (remaining gas: 1039988.549 units remaining) + [ (Right (Pair 42 21)) @parameter ] + - location: 17 (remaining gas: 1039988.539 units remaining) + [ (Pair 42 21) @parameter.right ] + - location: 24 (remaining gas: 1039988.529 units remaining) + [ 42 + 21 ] + - location: 25 (remaining gas: 1039988.494 units remaining) + [ 63 ] + - location: 26 (remaining gas: 1039988.479 units remaining) + [ (Right 63) ] + - location: 17 (remaining gas: 1039988.464 units remaining) + [ (Right 63) ] + - location: 28 (remaining gas: 1039988.449 units remaining) + [ (Some (Right 63)) ] + - location: 29 (remaining gas: 1039988.434 units remaining) + [ {} + (Some (Right 63)) ] + - location: 31 (remaining gas: 1039988.419 units remaining) + [ (Pair {} (Some (Right 63))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 42 63)-(Some (Right 21))].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 42 63)-(Some (Right 21))].out new file mode 100644 index 000000000000..5e6363d53303 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 42 63)-(Some (Right 21))].out @@ -0,0 +1,32 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_contract_input_output[xor.tz-None-Right (Pair 42 63)-(Some (Right 21))] + +storage + (Some (Right 21)) +emitted operations + +big_map diff + +trace + - location: 16 (remaining gas: 1039988.559 units remaining) + [ (Pair (Right (Pair 42 63)) None) ] + - location: 16 (remaining gas: 1039988.549 units remaining) + [ (Right (Pair 42 63)) @parameter ] + - location: 17 (remaining gas: 1039988.539 units remaining) + [ (Pair 42 63) @parameter.right ] + - location: 24 (remaining gas: 1039988.529 units remaining) + [ 42 + 63 ] + - location: 25 (remaining gas: 1039988.494 units remaining) + [ 21 ] + - location: 26 (remaining gas: 1039988.479 units remaining) + [ (Right 21) ] + - location: 17 (remaining gas: 1039988.464 units remaining) + [ (Right 21) ] + - location: 28 (remaining gas: 1039988.449 units remaining) + [ (Some (Right 21)) ] + - location: 29 (remaining gas: 1039988.434 units remaining) + [ {} + (Some (Right 21)) ] + - location: 31 (remaining gas: 1039988.419 units remaining) + [ (Pair {} (Some (Right 21))) ] + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_hash_consistency_michelson_cli.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_hash_consistency_michelson_cli.out new file mode 100644 index 000000000000..05e2ff2bb505 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_hash_consistency_michelson_cli.out @@ -0,0 +1,23 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_hash_consistency_michelson_cli + +Raw packed data: 0x0507070080acd2c6a501070700bcc485a30b0022 +Script-expression-ID-Hash: expruenXhGp5JQoHJTGv4DzBR8Zm3HGvea8Q8BaMPywsY2bxrHAEgC +Raw Script-expression-ID-Hash: 0x95a69fcbbf773989333dc9b31e246575812dbea19d25089f83a2aeeea16ab4bc +Ledger Blake2b hash: B5B7PuGGVUrdHUW9Df8wPNJQRuUmx56aH1XVpvbUZvW7 +Raw Sha256 hash: 0x538634a0f81b55f1c946c1207a25c262479566d20bd3d5cd2cdbb2940fc45774 +Raw Sha512 hash: 0x49d5c19c2da4ee74f85225c95625a4b77b94724f4285b436b9d4be27d40491354bdc8e9d8a3d9b2857e5fb59b172605edd02fc4b61ce3cd3f84aa11ed1731ff6 +Gas remaining: 1039997.313 units remaining +storage + 0x95a69fcbbf773989333dc9b31e246575812dbea19d25089f83a2aeeea16ab4bc +emitted operations + +big_map diff + + +storage + 0x95a69fcbbf773989333dc9b31e246575812dbea19d25089f83a2aeeea16ab4bc +emitted operations + +big_map diff + + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair { Elt \"bar\" 5 ; Elt \"foo\" 1 } .480b9afc63.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair { Elt \"bar\" 5 ; Elt \"foo\" 1 } .480b9afc63.out" new file mode 100644 index 000000000000..efc9ee18e05a --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair { Elt \"bar\" 5 ; Elt \"foo\" 1 } .480b9afc63.out" @@ -0,0 +1,9 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair { Elt "bar" 5 ; Elt "foo" 1 } 6)-15-(Pair { Elt "bar" 20 ; Elt "foo" 16 } 36)] + +storage + (Pair { Elt "bar" 20 ; Elt "foo" 16 } 36) +emitted operations + +big_map diff + + diff --git "a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair { Elt \"foo\" 1 } 1)-10-(Pair { .811573b5a7.out" "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair { Elt \"foo\" 1 } 1)-10-(Pair { .811573b5a7.out" new file mode 100644 index 000000000000..c60786f27fc3 --- /dev/null +++ "b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair { Elt \"foo\" 1 } 1)-10-(Pair { .811573b5a7.out" @@ -0,0 +1,9 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair { Elt "foo" 1 } 1)-10-(Pair { Elt "foo" 11 } 11)] + +storage + (Pair { Elt "foo" 11 } 11) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair {} 0)-10-(Pair {} 0)].out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair {} 0)-10-(Pair {} 0)].out new file mode 100644 index 000000000000..6da63db7fcae --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair {} 0)-10-(Pair {} 0)].out @@ -0,0 +1,9 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_map_map_sideeffect[map_map_sideeffect.tz-(Pair {} 0)-10-(Pair {} 0)] + +storage + (Pair {} 0) +emitted operations + +big_map diff + + diff --git a/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_packunpack.out b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_packunpack.out new file mode 100644 index 000000000000..ce9f1ebc4138 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_contract_opcodes.TestContractOpcodes::test_packunpack.out @@ -0,0 +1,106 @@ +tests_011/test_contract_opcodes.py::TestContractOpcodes::test_packunpack + +storage + Unit +emitted operations + +big_map diff + +trace + - location: 15 (remaining gas: 1039978.581 units remaining) + [ (Pair (Pair (Pair (Pair "toto" { 3 ; 7 ; 9 ; 1 }) { 1 ; 2 ; 3 }) + 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003) + Unit) ] + - location: 15 (remaining gas: 1039978.571 units remaining) + [ (Pair (Pair (Pair "toto" { 3 ; 7 ; 9 ; 1 }) { 1 ; 2 ; 3 }) + 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003) @parameter ] + - location: 16 (remaining gas: 1039978.561 units remaining) + [ (Pair (Pair "toto" { 3 ; 7 ; 9 ; 1 }) { 1 ; 2 ; 3 }) + 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 ] + - location: 17 (remaining gas: 1039978.546 units remaining) + [ 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 ] + - location: 19 (remaining gas: 1039978.536 units remaining) + [ 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 + 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 ] + - location: 17 (remaining gas: 1039978.506 units remaining) + [ (Pair (Pair "toto" { 3 ; 7 ; 9 ; 1 }) { 1 ; 2 ; 3 }) + 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 + 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 ] + - location: 20 (remaining gas: 1039974.879 units remaining) + [ 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 @packed + 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 + 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 ] + - location: 23 (remaining gas: 1039974.844 units remaining) + [ 0 + 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 ] + - location: 24 (remaining gas: 1039974.829 units remaining) + [ True + 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 ] + - location: 25 (remaining gas: 1039974.819 units remaining) + [ 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 ] + - location: 25 (remaining gas: 1039974.804 units remaining) + [ 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 ] + - location: 31 (remaining gas: 1039971.956 units remaining) + [ (Some (Pair (Pair "toto" { 3 ; 7 ; 9 ; 1 }) { 1 ; 2 ; 3 })) @unpacked ] + - location: 40 (remaining gas: 1039971.946 units remaining) + [ (Pair (Pair "toto" { 3 ; 7 ; 9 ; 1 }) { 1 ; 2 ; 3 }) @unpacked.some ] + - location: 40 (remaining gas: 1039971.931 units remaining) + [ (Pair (Pair "toto" { 3 ; 7 ; 9 ; 1 }) { 1 ; 2 ; 3 }) @unpacked.some ] + - location: 46 (remaining gas: 1039971.921 units remaining) + [ ] + - location: 47 (remaining gas: 1039971.911 units remaining) + [ Unit ] + - location: 48 (remaining gas: 1039971.896 units remaining) + [ {} + Unit ] + - location: 50 (remaining gas: 1039971.881 units remaining) + [ (Pair {} Unit) ] + +Runtime error in contract [CONTRACT_HASH]: + 1: parameter (pair (pair (pair string (list int)) (set nat)) bytes) ; + 2: storage unit ; + 3: code { CAR ; UNPAIR ; DIP { DUP } ; + 4: PACK ; ASSERT_CMPEQ ; + 5: UNPACK (pair (pair string (list int)) (set nat)) ; ASSERT_SOME ; DROP ; + 6: UNIT ; NIL operation ; PAIR } + 7: +At line 4 characters 14 to 26, +script reached FAILWITH instruction +with Unit +trace + - location: 15 (remaining gas: 1039978.581 units remaining) + [ (Pair (Pair (Pair (Pair "toto" { 3 ; 7 ; 9 ; 1 }) { 1 ; 2 ; 3 }) + 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004) + Unit) ] + - location: 15 (remaining gas: 1039978.571 units remaining) + [ (Pair (Pair (Pair "toto" { 3 ; 7 ; 9 ; 1 }) { 1 ; 2 ; 3 }) + 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004) @parameter ] + - location: 16 (remaining gas: 1039978.561 units remaining) + [ (Pair (Pair "toto" { 3 ; 7 ; 9 ; 1 }) { 1 ; 2 ; 3 }) + 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004 ] + - location: 17 (remaining gas: 1039978.546 units remaining) + [ 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004 ] + - location: 19 (remaining gas: 1039978.536 units remaining) + [ 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004 + 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004 ] + - location: 17 (remaining gas: 1039978.506 units remaining) + [ (Pair (Pair "toto" { 3 ; 7 ; 9 ; 1 }) { 1 ; 2 ; 3 }) + 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004 + 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004 ] + - location: 20 (remaining gas: 1039974.879 units remaining) + [ 0x05070707070100000004746f746f020000000800030007000900010200000006000100020003 @packed + 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004 + 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004 ] + - location: 23 (remaining gas: 1039974.844 units remaining) + [ -1 + 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004 ] + - location: 24 (remaining gas: 1039974.829 units remaining) + [ False + 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004 ] + - location: 25 (remaining gas: 1039974.819 units remaining) + [ 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004 ] + - location: 29 (remaining gas: 1039974.809 units remaining) + [ Unit + 0x05070707070100000004746f746f0200000008000300070009000102000000060001000200030004 ] +Fatal error: + error running script diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_add_liquidity.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_add_liquidity.out new file mode 100644 index 000000000000..77370a50ce20 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_add_liquidity.out @@ -0,0 +1,80 @@ +tests_011/test_liquidity_baking.py::TestAddApproveTransferRemove::test_add_liquidity + +Node is bootstrapped. +Estimated gas: 8780.679 units (will add 100 for safety) +Estimated storage: 141 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.001244 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 8881 + Storage limit: 161 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.001244 + fees(the baker who will include this operation,0) ... +ꜩ0.001244 + Transaction: + Amount: ꜩ9001 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: addLiquidity + Parameter: (Pair "[CONTRACT_HASH]" 0 1000000000 "[TIMESTAMP]") + This transaction was successfully applied + Updated storage: + { 722 ; + 9013500100 ; + 72107 ; + 0x01e927f00ef734dfc85919635e9afc9166c83ef9fc00 ; + 0x0115eb0104481a6d7921160bc982c5e0a561cd8a3a00 } + Storage size: 4633 bytes + Paid storage size diff: 3 bytes + Consumed gas: 2308.066 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.00075 + [CONTRACT_HASH] ... -ꜩ9001 + [CONTRACT_HASH] ... +ꜩ9001 + Internal operations: + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: transfer + Parameter: (Pair 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 + (Pair 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600 721)) + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(1)[(Pair 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 + 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600)] to 999999279 + Set map(0)[0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78] to 99999279 + Set map(0)[0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600] to 721 + Storage size: 2263 bytes + Paid storage size diff: 68 bytes + Consumed gas: 3202.299 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.017 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: mintOrBurn + Parameter: (Pair 72007 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78) + This transaction was successfully applied + Updated storage: + { 2 ; 3 ; 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600 ; 72107 } + Updated big_maps: + Set map(2)[0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78] to 72007 + Storage size: 2048 bytes + Paid storage size diff: 70 bytes + Consumed gas: 3270.314 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0175 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_approval.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_approval.out new file mode 100644 index 000000000000..74a04c7537f2 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_approval.out @@ -0,0 +1,40 @@ +tests_011/test_liquidity_baking.py::TestAddApproveTransferRemove::test_approval + +Node is bootstrapped. +Estimated gas: 1778.324 units (will add 100 for safety) +Estimated storage: 68 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000495 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1879 + Storage limit: 88 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000495 + fees(the baker who will include this operation,0) ... +ꜩ0.000495 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: approve + Parameter: (Pair "[CONTRACT_HASH]" 1000) + This transaction was successfully applied + Updated storage: + { 2 ; 3 ; 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600 ; 72107 } + Updated big_maps: + Set map(3)[(Pair 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 + 0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c)] to 1000 + Storage size: 2116 bytes + Paid storage size diff: 68 bytes + Consumed gas: 1778.324 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.017 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_approved_transfer.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_approved_transfer.out new file mode 100644 index 000000000000..faf040063e6e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_approved_transfer.out @@ -0,0 +1,41 @@ +tests_011/test_liquidity_baking.py::TestAddApproveTransferRemove::test_approved_transfer + +Node is bootstrapped. +Estimated gas: 3172.143 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000685 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 3273 + Storage limit: 0 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000685 + fees(the baker who will include this operation,0) ... +ꜩ0.000685 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: transfer + Parameter: (Pair "[CONTRACT_HASH]" + "[CONTRACT_HASH]" + 1000) + This transaction was successfully applied + Updated storage: + { 2 ; 3 ; 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600 ; 72107 } + Updated big_maps: + Unset map(3)[(Pair 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 + 0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c)] + Set map(2)[0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78] to 71007 + Set map(2)[0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c] to 1000 + Storage size: 2116 bytes + Consumed gas: 3172.143 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_approve1.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_approve1.out new file mode 100644 index 000000000000..4595c7a0f0a9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_approve1.out @@ -0,0 +1,40 @@ +tests_011/test_liquidity_baking.py::TestAddApproveTransferRemove::test_call_approve1 + +Node is bootstrapped. +Estimated gas: 1778.340 units (will add 100 for safety) +Estimated storage: 71 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000498 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1879 + Storage limit: 91 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000498 + fees(the baker who will include this operation,0) ... +ꜩ0.000498 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: approve + Parameter: (Pair "[CONTRACT_HASH]" 1000000000) + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(1)[(Pair 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 + 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600)] to 1000000000 + Storage size: 2053 bytes + Paid storage size diff: 71 bytes + Consumed gas: 1778.340 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01775 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_approve2.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_approve2.out new file mode 100644 index 000000000000..19d16005e521 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_approve2.out @@ -0,0 +1,40 @@ +tests_011/test_liquidity_baking.py::TestAddApproveTransferRemove::test_call_approve2 + +Node is bootstrapped. +Estimated gas: 1778.340 units (will add 100 for safety) +Estimated storage: 71 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000498 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1879 + Storage limit: 91 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000498 + fees(the baker who will include this operation,0) ... +ꜩ0.000498 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: approve + Parameter: (Pair "[CONTRACT_HASH]" 1000000000) + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(1)[(Pair 0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c + 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600)] to 1000000000 + Storage size: 2124 bytes + Paid storage size diff: 71 bytes + Consumed gas: 1778.340 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01775 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_approve3.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_approve3.out new file mode 100644 index 000000000000..84195f411bad --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_approve3.out @@ -0,0 +1,40 @@ +tests_011/test_liquidity_baking.py::TestAddApproveTransferRemove::test_call_approve3 + +Node is bootstrapped. +Estimated gas: 1778.340 units (will add 100 for safety) +Estimated storage: 71 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000498 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1879 + Storage limit: 91 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000498 + fees(the baker who will include this operation,0) ... +ꜩ0.000498 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: approve + Parameter: (Pair "[CONTRACT_HASH]" 1000000000) + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(1)[(Pair 0x0000dac9f52543da1aed0bc1d6b46bf7c10db7014cd6 + 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600)] to 1000000000 + Storage size: 2195 bytes + Paid storage size diff: 71 bytes + Consumed gas: 1778.340 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01775 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_mint_or_burn.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_mint_or_burn.out new file mode 100644 index 000000000000..f393f838eb26 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_call_mint_or_burn.out @@ -0,0 +1,39 @@ +tests_011/test_liquidity_baking.py::TestAddApproveTransferRemove::test_call_mint_or_burn + +Node is bootstrapped. +Estimated gas: 3269.680 units (will add 100 for safety) +Estimated storage: 71 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000649 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 3370 + Storage limit: 91 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000649 + fees(the baker who will include this operation,0) ... +ꜩ0.000649 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: mintOrBurn + Parameter: (Pair 100000000 "[CONTRACT_HASH]") + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(0)[0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78] to 100000000 + Storage size: 1982 bytes + Paid storage size diff: 71 bytes + Consumed gas: 3270.307 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01775 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_dex_storage.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_dex_storage.out new file mode 100644 index 000000000000..a82a6c1dd82e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_dex_storage.out @@ -0,0 +1,7 @@ +tests_011/test_liquidity_baking.py::TestAddApproveTransferRemove::test_dex_storage + +Pair 712 + 8895894353 + 71107 + "[CONTRACT_HASH]" + "[CONTRACT_HASH]" diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_lqt_storage.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_lqt_storage.out new file mode 100644 index 000000000000..09c54fbcfda7 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_lqt_storage.out @@ -0,0 +1,3 @@ +tests_011/test_liquidity_baking.py::TestAddApproveTransferRemove::test_lqt_storage + +Pair 2 3 "[CONTRACT_HASH]" 71107 diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_remove_liquidity.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_remove_liquidity.out new file mode 100644 index 000000000000..7bfa221aa6e9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_remove_liquidity.out @@ -0,0 +1,79 @@ +tests_011/test_liquidity_baking.py::TestAddApproveTransferRemove::test_remove_liquidity + +Node is bootstrapped. +Estimated gas: 8140.454 units (will add 100 for safety) +Estimated storage: 67 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.001177 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 8241 + Storage limit: 87 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.001177 + fees(the baker who will include this operation,1) ... +ꜩ0.001177 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: removeLiquidity + Parameter: (Pair "[CONTRACT_HASH]" 1000 0 0 "[TIMESTAMP]") + This transaction was successfully applied + Updated storage: + { 712 ; + 8895894353 ; + 71107 ; + 0x01e927f00ef734dfc85919635e9afc9166c83ef9fc00 ; + 0x0115eb0104481a6d7921160bc982c5e0a561cd8a3a00 } + Storage size: 4633 bytes + Consumed gas: 2309.881 + Internal operations: + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: mintOrBurn + Parameter: (Pair -1000 0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c) + This transaction was successfully applied + Updated storage: + { 2 ; 3 ; 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600 ; 71107 } + Updated big_maps: + Unset map(2)[0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c] + Storage size: 2048 bytes + Consumed gas: 1925.935 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: transfer + Parameter: (Pair 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600 + (Pair 0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c 10)) + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(0)[0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600] to 711 + Set map(0)[0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c] to 10 + Storage size: 2330 bytes + Paid storage size diff: 67 bytes + Consumed gas: 2484.638 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01675 + Transaction: + Amount: ꜩ125.105747 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Consumed gas: 1420 + Balance updates: + [CONTRACT_HASH] ... -ꜩ125.105747 + [CONTRACT_HASH] ... +ꜩ125.105747 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_setup.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_setup.out new file mode 100644 index 000000000000..15b659c68c81 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_setup.out @@ -0,0 +1,8 @@ +tests_011/test_liquidity_baking.py::TestAddApproveTransferRemove::test_setup + +"[CONTRACT_HASH]" +Pair 1 + 100 + 100 + "[CONTRACT_HASH]" + "[CONTRACT_HASH]" diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_tok_storage.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_tok_storage.out new file mode 100644 index 000000000000..3c65d3bd6d2e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestAddApproveTransferRemove::test_tok_storage.out @@ -0,0 +1,3 @@ +tests_011/test_liquidity_baking.py::TestAddApproveTransferRemove::test_tok_storage + +Pair 0 1 "[CONTRACT_HASH]" 100010000 diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_add_liquidity.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_add_liquidity.out new file mode 100644 index 000000000000..ad9505285846 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_add_liquidity.out @@ -0,0 +1,80 @@ +tests_011/test_liquidity_baking.py::TestTrades::test_add_liquidity + +Node is bootstrapped. +Estimated gas: 8780.679 units (will add 100 for safety) +Estimated storage: 141 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.001244 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 8881 + Storage limit: 161 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.001244 + fees(the baker who will include this operation,0) ... +ꜩ0.001244 + Transaction: + Amount: ꜩ9001 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: addLiquidity + Parameter: (Pair "[CONTRACT_HASH]" 0 1000000000 "[TIMESTAMP]") + This transaction was successfully applied + Updated storage: + { 722 ; + 9013500100 ; + 72107 ; + 0x01e927f00ef734dfc85919635e9afc9166c83ef9fc00 ; + 0x0115eb0104481a6d7921160bc982c5e0a561cd8a3a00 } + Storage size: 4633 bytes + Paid storage size diff: 3 bytes + Consumed gas: 2308.066 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.00075 + [CONTRACT_HASH] ... -ꜩ9001 + [CONTRACT_HASH] ... +ꜩ9001 + Internal operations: + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: transfer + Parameter: (Pair 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 + (Pair 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600 721)) + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(1)[(Pair 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 + 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600)] to 999999279 + Set map(0)[0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78] to 99999279 + Set map(0)[0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600] to 721 + Storage size: 2263 bytes + Paid storage size diff: 68 bytes + Consumed gas: 3202.299 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.017 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: mintOrBurn + Parameter: (Pair 72007 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78) + This transaction was successfully applied + Updated storage: + { 2 ; 3 ; 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600 ; 72107 } + Updated big_maps: + Set map(2)[0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78] to 72007 + Storage size: 2048 bytes + Paid storage size diff: 70 bytes + Consumed gas: 3270.314 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.0175 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_buy_tok.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_buy_tok.out new file mode 100644 index 000000000000..3492415dc6f6 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_buy_tok.out @@ -0,0 +1,72 @@ +tests_011/test_liquidity_baking.py::TestTrades::test_buy_tok + +Node is bootstrapped. +Estimated gas: 5704.920 units (will add 100 for safety) +Estimated storage: 326 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000928 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 5805 + Storage limit: 346 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000928 + fees(the baker who will include this operation,0) ... +ꜩ0.000928 + Transaction: + Amount: ꜩ9001 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: xtzToToken + Parameter: (Pair "[CONTRACT_HASH]" 0 "[TIMESTAMP]") + This transaction was successfully applied + Updated storage: + { 362 ; + 18007999100 ; + 72107 ; + 0x01e927f00ef734dfc85919635e9afc9166c83ef9fc00 ; + 0x0115eb0104481a6d7921160bc982c5e0a561cd8a3a00 } + Storage size: 4634 bytes + Paid storage size diff: 1 bytes + Consumed gas: 1800.278 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.00025 + [CONTRACT_HASH] ... -ꜩ9001 + [CONTRACT_HASH] ... +ꜩ9001 + Internal operations: + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: transfer + Parameter: (Pair 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600 + (Pair 0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c 360)) + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(0)[0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600] to 361 + Set map(0)[0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c] to 360 + Storage size: 2331 bytes + Paid storage size diff: 68 bytes + Consumed gas: 2484.642 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.017 + Transaction: + Amount: ꜩ9.001 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Consumed gas: 1420 + Balance updates: + [CONTRACT_HASH] ... -ꜩ9.001 + [CONTRACT_HASH] ... +ꜩ9.001 + [CONTRACT_HASH] ... -ꜩ0.06425 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_approve1.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_approve1.out new file mode 100644 index 000000000000..412f3abeee18 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_approve1.out @@ -0,0 +1,40 @@ +tests_011/test_liquidity_baking.py::TestTrades::test_call_approve1 + +Node is bootstrapped. +Estimated gas: 1778.340 units (will add 100 for safety) +Estimated storage: 71 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000498 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1879 + Storage limit: 91 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000498 + fees(the baker who will include this operation,0) ... +ꜩ0.000498 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: approve + Parameter: (Pair "[CONTRACT_HASH]" 1000000000) + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(1)[(Pair 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 + 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600)] to 1000000000 + Storage size: 2053 bytes + Paid storage size diff: 71 bytes + Consumed gas: 1778.340 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01775 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_approve2.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_approve2.out new file mode 100644 index 000000000000..ccc686010dd0 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_approve2.out @@ -0,0 +1,40 @@ +tests_011/test_liquidity_baking.py::TestTrades::test_call_approve2 + +Node is bootstrapped. +Estimated gas: 1778.340 units (will add 100 for safety) +Estimated storage: 71 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000498 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1879 + Storage limit: 91 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000498 + fees(the baker who will include this operation,0) ... +ꜩ0.000498 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: approve + Parameter: (Pair "[CONTRACT_HASH]" 1000000000) + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(1)[(Pair 0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c + 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600)] to 1000000000 + Storage size: 2124 bytes + Paid storage size diff: 71 bytes + Consumed gas: 1778.340 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01775 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_approve3.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_approve3.out new file mode 100644 index 000000000000..2ea17a1dda28 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_approve3.out @@ -0,0 +1,40 @@ +tests_011/test_liquidity_baking.py::TestTrades::test_call_approve3 + +Node is bootstrapped. +Estimated gas: 1778.340 units (will add 100 for safety) +Estimated storage: 71 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000498 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 1879 + Storage limit: 91 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000498 + fees(the baker who will include this operation,0) ... +ꜩ0.000498 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: approve + Parameter: (Pair "[CONTRACT_HASH]" 1000000000) + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(1)[(Pair 0x0000dac9f52543da1aed0bc1d6b46bf7c10db7014cd6 + 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600)] to 1000000000 + Storage size: 2195 bytes + Paid storage size diff: 71 bytes + Consumed gas: 1778.340 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01775 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_mint_or_burn.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_mint_or_burn.out new file mode 100644 index 000000000000..683f0b2ead46 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_call_mint_or_burn.out @@ -0,0 +1,39 @@ +tests_011/test_liquidity_baking.py::TestTrades::test_call_mint_or_burn + +Node is bootstrapped. +Estimated gas: 3269.680 units (will add 100 for safety) +Estimated storage: 71 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000649 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 3370 + Storage limit: 91 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000649 + fees(the baker who will include this operation,0) ... +ꜩ0.000649 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: mintOrBurn + Parameter: (Pair 100000000 "[CONTRACT_HASH]") + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(0)[0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78] to 100000000 + Storage size: 1982 bytes + Paid storage size diff: 71 bytes + Consumed gas: 3270.307 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.01775 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_dex_storage.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_dex_storage.out new file mode 100644 index 000000000000..dcbe3af5f831 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_dex_storage.out @@ -0,0 +1,7 @@ +tests_011/test_liquidity_baking.py::TestTrades::test_dex_storage + +Pair 462 + 14117137204 + 72107 + "[CONTRACT_HASH]" + "[CONTRACT_HASH]" diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_lqt_storage.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_lqt_storage.out new file mode 100644 index 000000000000..8a12e0117c8e --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_lqt_storage.out @@ -0,0 +1,3 @@ +tests_011/test_liquidity_baking.py::TestTrades::test_lqt_storage + +Pair 2 3 "[CONTRACT_HASH]" 72107 diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_sell_tok.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_sell_tok.out new file mode 100644 index 000000000000..2005279614b9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_sell_tok.out @@ -0,0 +1,74 @@ +tests_011/test_liquidity_baking.py::TestTrades::test_sell_tok + +Node is bootstrapped. +Estimated gas: 8023.492 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.001158 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 8124 + Storage limit: 0 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.001158 + fees(the baker who will include this operation,1) ... +ꜩ0.001158 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: tokenToXtz + Parameter: (Pair "[CONTRACT_HASH]" 100 0 "[TIMESTAMP]") + This transaction was successfully applied + Updated storage: + { 462 ; + 14117137204 ; + 72107 ; + 0x01e927f00ef734dfc85919635e9afc9166c83ef9fc00 ; + 0x0115eb0104481a6d7921160bc982c5e0a561cd8a3a00 } + Storage size: 4633 bytes + Consumed gas: 1801.157 + Internal operations: + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: transfer + Parameter: (Pair 0x0000dac9f52543da1aed0bc1d6b46bf7c10db7014cd6 + (Pair 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600 100)) + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(1)[(Pair 0x0000dac9f52543da1aed0bc1d6b46bf7c10db7014cd6 + 0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600)] to 999999900 + Unset map(0)[0x0000dac9f52543da1aed0bc1d6b46bf7c10db7014cd6] + Set map(0)[0x01d496def47a3be89f5d54c6e6bb13cc6645d6e16600] to 461 + Storage size: 2331 bytes + Consumed gas: 3382.335 + Transaction: + Amount: ꜩ3891.966034 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Consumed gas: 1420 + Balance updates: + [CONTRACT_HASH] ... -ꜩ3891.966034 + [CONTRACT_HASH] ... +ꜩ3891.966034 + Transaction: + Amount: ꜩ3.895862 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + This transaction was successfully applied + Consumed gas: 1420 + Balance updates: + [CONTRACT_HASH] ... -ꜩ3.895862 + [CONTRACT_HASH] ... +ꜩ3.895862 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_setup.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_setup.out new file mode 100644 index 000000000000..760746505e31 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_setup.out @@ -0,0 +1,8 @@ +tests_011/test_liquidity_baking.py::TestTrades::test_setup + +"[CONTRACT_HASH]" +Pair 1 + 100 + 100 + "[CONTRACT_HASH]" + "[CONTRACT_HASH]" diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_tok_storage.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_tok_storage.out new file mode 100644 index 000000000000..35e7c50deb8b --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_tok_storage.out @@ -0,0 +1,3 @@ +tests_011/test_liquidity_baking.py::TestTrades::test_tok_storage + +Pair 0 1 "[CONTRACT_HASH]" 100010000 diff --git a/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_transfer.out b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_transfer.out new file mode 100644 index 000000000000..89d36c9ed8f9 --- /dev/null +++ b/tests_python/tests_011/_regtest_outputs/test_liquidity_baking.TestTrades::test_transfer.out @@ -0,0 +1,42 @@ +tests_011/test_liquidity_baking.py::TestTrades::test_transfer + +Node is bootstrapped. +Estimated gas: 2484.642 units (will add 100 for safety) +Estimated storage: 68 bytes added (will add 20 for safety) +Operation successfully injected in the node. +Operation hash is '[BLOCK_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [BLOCK_HASH] to be included --confirmations 5 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [CONTRACT_HASH] + Fee to the baker: ꜩ0.000616 + Expected counter: [EXPECTED_COUNTER] + Gas limit: 2585 + Storage limit: 88 bytes + Balance updates: + [CONTRACT_HASH] ................ -ꜩ0.000616 + fees(the baker who will include this operation,0) ... +ꜩ0.000616 + Transaction: + Amount: ꜩ0 + From: [CONTRACT_HASH] + To: [CONTRACT_HASH] + Entrypoint: transfer + Parameter: (Pair "[CONTRACT_HASH]" + "[CONTRACT_HASH]" + 100) + This transaction was successfully applied + Updated storage: + { 0 ; 1 ; 0x000002298c03ed7d454a101eb7022bc95f7e5f41ac78 ; 100010000 } + Updated big_maps: + Set map(0)[0x0000dac9f52543da1aed0bc1d6b46bf7c10db7014cd6] to 100 + Set map(0)[0x0000e7670f32038107a59a2b9cfefae36ea21f5aa63c] to 260 + Storage size: 2399 bytes + Paid storage size diff: 68 bytes + Consumed gas: 2484.642 + Balance updates: + [CONTRACT_HASH] ... -ꜩ0.017 + +Injected block [BLOCK_HASH] diff --git a/tests_python/tests_011/conftest.py b/tests_python/tests_011/conftest.py new file mode 100644 index 000000000000..19b68d81c525 --- /dev/null +++ b/tests_python/tests_011/conftest.py @@ -0,0 +1,146 @@ +"""Protocol-specific hooks and fixtures""" + +import tempfile +import shutil +from typing import Optional, Iterator, List +import pytest +from launchers.sandbox import Sandbox +from tools import constants, utils +from tools.client_regression import ClientRegression +from client.client import Client +from client.client_output import CreateMockupResult + +from . import protocol + + +@pytest.fixture(scope="class") +def client(sandbox: Sandbox) -> Iterator[Client]: + """One node with protocol 011. + + Activate protocol 011 one year in the past. This avoids waiting + when baking blocks manually from the client using `bake for` + """ + sandbox.add_node(0, params=constants.NODE_PARAMS) + client = sandbox.client(0) + protocol.activate(client, activate_in_the_past=True) + yield client + + +@pytest.fixture(scope="class") +def client_regtest_bis(sandbox: Sandbox) -> Iterator[Client]: + """One node with protocol 011, regression test enabled. + + Activate protocol 011 one year in the past. (see fixture client). + """ + + def reg_client_factory( + client_path: str, + admin_client_path: str, + host: Optional[str] = None, + base_dir: Optional[str] = None, + rpc_port: Optional[int] = None, + use_tls: Optional[bool] = None, + endpoint: Optional[str] = 'http://127.0.0.1:8732', + mode: str = None, + disable_disclaimer: bool = True, + ) -> ClientRegression: + client = ClientRegression( + client_path=client_path, + admin_client_path=admin_client_path, + host=host, + base_dir=base_dir, + rpc_port=rpc_port, + use_tls=use_tls, + endpoint=endpoint, + mode=mode, + disable_disclaimer=disable_disclaimer, + ) + return client + + sandbox.add_node( + 1, client_factory=reg_client_factory, params=constants.NODE_PARAMS + ) + client = sandbox.client(1) + protocol.activate(client, activate_in_the_past=True) + yield client + + +@pytest.fixture(scope="class") +def clients(sandbox: Sandbox, request) -> Iterator[List[Client]]: + """N node with protocol 011. Parameterized by the number of nodes. + + Number of nodes is specified as a class annotation. + @pytest.mark.parametrize('clients', [N], indirect=True) + + Activate protocol 011 one year in the past. (see fixture client). + """ + assert request.param is not None + num_nodes = request.param + for i in range(num_nodes): + # Large number may increases peers connection time + sandbox.add_node(i, params=constants.NODE_PARAMS) + protocol.activate(sandbox.client(0), activate_in_the_past=True) + clients = sandbox.all_clients() + for client in clients: + proto = protocol.HASH + assert utils.check_protocol(client, proto) + yield clients + + +@pytest.fixture +def mockup_client(sandbox: Sandbox) -> Iterator[Client]: + """ + Returns a mockup client with its persistent directory created + + This is done in two steps, because we want to create the mockup + with a client that doesn't have "--mode mockup" (as per + the public documentation) but we want to return a + client that has "--mode mockup" and uses the base-dir created + in the first step. + + There is no way around this pattern. If you want to create + a mockup using custom arguments; you MUST do the same + as this method. + """ + with tempfile.TemporaryDirectory(prefix='tezos-client.') as base_dir: + unmanaged_client = sandbox.create_client(base_dir=base_dir) + res = unmanaged_client.create_mockup( + protocol=protocol.HASH + ).create_mockup_result + assert res == CreateMockupResult.OK + yield sandbox.create_client(base_dir=base_dir, mode="mockup") + + +@pytest.fixture(scope="class") +def nodes_legacy_store(sandbox, legacy_stores): + nodes = {} + + # TODO would be cleaner to return couples (node, client) in order to + # avoid relying on the invariant that nodes are numbered 1, 2, 3 + # or just return the id? + i = 1 + for history_mode in ['archive', 'full', 'rolling']: + node_dir = legacy_stores[f'{history_mode}_path'] + # init config with up to date version + params = constants.NODE_PARAMS + ['--history-mode', history_mode] + node = sandbox.register_node(i, node_dir=node_dir, params=params) + # Workaround to allow generating an identity on an + # old 0.0.4 storage with a 0.0.6 node + version = open(node_dir + "/version.json", "w") + version.write('{ "version": "0.0.6" }') + version.close() + node.init_config() + # write version to upgrade + version = open(node_dir + "/version.json", "w") + version.write('{ "version": "0.0.4" }') + version.close() + + nodes[history_mode] = node + i += 1 + + yield nodes + + # TODO think of case of failure before `yield` + for history_mode in ['archive', 'full', 'rolling']: + node_dir = legacy_stores[f'{history_mode}_path'] + shutil.rmtree(node_dir) diff --git a/tests_python/tests_011/contract_paths.py b/tests_python/tests_011/contract_paths.py new file mode 100644 index 000000000000..0a90518b966c --- /dev/null +++ b/tests_python/tests_011/contract_paths.py @@ -0,0 +1,20 @@ +from os import path +from typing import List +from tools import paths + + +def all_contracts(directories: List[str] = None) -> List[str]: + return paths.all_contracts(CONTRACT_PATH, directories) + + +def all_legacy_contracts() -> List[str]: + return all_contracts(['legacy']) + + +CONTRACT_PATH = path.join(paths.TEZOS_HOME, 'tests_python', 'contracts_011') +ATTIC_CONTRACT_PATH = path.join(CONTRACT_PATH, 'attic') +MACROS_CONTRACT_PATH = path.join(CONTRACT_PATH, 'macros') +ILLTYPED_CONTRACT_PATH = path.join(CONTRACT_PATH, 'ill_typed') +LEGACY_CONTRACT_PATH = path.join(CONTRACT_PATH, 'legacy') +OPCODES_CONTRACT_PATH = path.join(CONTRACT_PATH, 'opcodes') +MINI_SCENARIOS_CONTRACT_PATH = path.join(CONTRACT_PATH, 'mini_scenarios') diff --git a/tests_python/tests_011/per_block_vote_files/false.json b/tests_python/tests_011/per_block_vote_files/false.json new file mode 100644 index 000000000000..af74e026a98a --- /dev/null +++ b/tests_python/tests_011/per_block_vote_files/false.json @@ -0,0 +1 @@ +{"liquidity_baking_escape_vote": false} diff --git a/tests_python/tests_011/per_block_vote_files/invalid.json b/tests_python/tests_011/per_block_vote_files/invalid.json new file mode 100644 index 000000000000..200b380f75f3 --- /dev/null +++ b/tests_python/tests_011/per_block_vote_files/invalid.json @@ -0,0 +1 @@ +{"liquidity_baking_escape_vote": true diff --git a/tests_python/tests_011/per_block_vote_files/non_boolean.json b/tests_python/tests_011/per_block_vote_files/non_boolean.json new file mode 100644 index 000000000000..a5de5f628964 --- /dev/null +++ b/tests_python/tests_011/per_block_vote_files/non_boolean.json @@ -0,0 +1 @@ +{"liquidity_baking_escape_vote": "true"} diff --git a/tests_python/tests_011/per_block_vote_files/true.json b/tests_python/tests_011/per_block_vote_files/true.json new file mode 100644 index 000000000000..cc092c95ad99 --- /dev/null +++ b/tests_python/tests_011/per_block_vote_files/true.json @@ -0,0 +1 @@ +{"liquidity_baking_escape_vote": true} diff --git a/tests_python/tests_011/per_block_vote_files/wrong_key.json b/tests_python/tests_011/per_block_vote_files/wrong_key.json new file mode 100644 index 000000000000..37863375f220 --- /dev/null +++ b/tests_python/tests_011/per_block_vote_files/wrong_key.json @@ -0,0 +1 @@ +{"liquidity_baking_escape": true } diff --git a/tests_python/tests_011/protocol.py b/tests_python/tests_011/protocol.py new file mode 100644 index 000000000000..bbe946cf0a39 --- /dev/null +++ b/tests_python/tests_011/protocol.py @@ -0,0 +1,22 @@ +from tools import constants, utils + +HASH = constants.HANGZHOU +DAEMON = constants.HANGZHOU_DAEMON +PARAMETERS = constants.HANGZHOU_PARAMETERS +FOLDER = constants.HANGZHOU_FOLDER + +PREV_HASH = constants.GRANADA +PREV_DAEMON = constants.GRANADA_DAEMON +PREV_PARAMETERS = constants.GRANADA_PARAMETERS + + +def activate( + client, + parameters=PARAMETERS, + proto=HASH, + timestamp=None, + activate_in_the_past=False, +): + utils.activate_protocol( + client, proto, parameters, timestamp, activate_in_the_past + ) diff --git a/tests_python/tests_011/test_accuser.py b/tests_python/tests_011/test_accuser.py new file mode 100644 index 000000000000..736a591d7a5b --- /dev/null +++ b/tests_python/tests_011/test_accuser.py @@ -0,0 +1,123 @@ +import time + +import pytest +from tools import utils, constants +from launchers.sandbox import Sandbox +from . import protocol + + +NUM_NODES = 2 + + +@pytest.mark.multinode +@pytest.mark.incremental +class TestAccuser: + """Constructs a double endorsement, and lets the accuser inject + the evidence.""" + + def test_init(self, sandbox: Sandbox): + for i in range(NUM_NODES): + sandbox.add_node(i, params=constants.NODE_PARAMS) + protocol.activate(sandbox.client(0), activate_in_the_past=True) + # We inject 3 blocks so that the double-endorsement-evidence operation + # is always branched from a known predecessor. (If the level of the + # evidence is smaller than 5, then the operation is branched from the + # head; however the node might change branch, and then the operation + # becomes invalid, namely "branch refused".) + for i in range(3): + utils.bake(sandbox.client(0)) + + def test_level(self, sandbox: Sandbox): + level = 4 + for client in sandbox.all_clients(): + assert utils.check_level(client, level) + + def test_terminate_node_1(self, sandbox: Sandbox): + sandbox.node(1).terminate() + + def test_bake_node_0(self, sandbox: Sandbox): + """Client 0 bakes block A at level 5, not communicated to node 1. + Inject an endorsement to ensure a different hash""" + sandbox.client(0).endorse('bootstrap1') + utils.bake(sandbox.client(0)) + + def test_endorse_node_0(self, sandbox: Sandbox, session: dict): + """bootstrap1 builds an endorsement for block A""" + client = sandbox.client(0) + client.endorse('bootstrap1') + mempool = client.get_mempool() + endorsement = mempool['applied'][0] + session['endorsement1'] = endorsement + utils.bake(client) + + def test_terminate_node_0(self, sandbox: Sandbox): + sandbox.node(0).terminate() + + def test_restart_node_1(self, sandbox: Sandbox): + sandbox.node(1).run() + assert sandbox.client(1).check_node_listening() + + def test_start_accuser(self, sandbox: Sandbox): + sandbox.add_accuser(1, proto=protocol.DAEMON) + # We make sure that there is enough time for the accuser to start + # listing to the node's block stream, otherwise the accuser might miss + # the next two blocks. + time.sleep(2) + + def test_bake_node_1(self, sandbox: Sandbox): + """Client 1 bakes block B at level 5, not communicated to node 0""" + utils.bake(sandbox.client(1)) + + def test_endorse_node_2(self, sandbox: Sandbox, session: dict): + """bootstrap1 builds an endorsement for block B, which is included in + a new block at level 6 by bootstrap2""" + client = sandbox.client(1) + client.endorse('bootstrap1') + mempool = client.get_mempool() + endorsement = mempool['applied'][0] + session['endorsement2'] = endorsement + utils.bake(client, 'bootstrap2') + client.get_operations("4") + + def test_restart_node_0(self, sandbox: Sandbox): + sandbox.node(0).run() + sandbox.client(0).check_node_listening() + + def test_check_level(self, sandbox: Sandbox): + """All nodes are at level 6, head is either block A or B""" + level = 6 + for client in sandbox.all_clients(): + assert utils.check_level(client, level) + + def test_bake_block(self, sandbox: Sandbox): + """Bake a block on node 0, which makes the chain on node 0 longer; in + this way, we make sure that node 1 sees the block at level 6, + which containts the conflicting endorsement. + """ + utils.bake(sandbox.client(0)) + + def test_double_endorsement_evidence_generated(self, sandbox: Sandbox): + """Check that the double endorsement evidence operation is in the + mempool of node 1 or in the block at level 7, depending on + whether the double endorsement operation has reached node 1 + before or after node 1 sees the block at level 7. + """ + in_mempool = False + in_block = False + mempool = sandbox.client(1).get_mempool() + if ( + len(mempool['applied']) > 0 + and len(mempool['applied'][0]['contents']) > 0 + ): + in_mempool = ( + mempool['applied'][0]['contents'][0]['kind'] + == "double_endorsement_evidence" + ) + if not in_mempool: + ops = sandbox.client(1).get_operations() + if len(ops[2]) > 0 and len(ops[2][0]['contents']) > 0: + in_block = ( + ops[2][0]['contents'][0]['kind'] + == "double_endorsement_evidence" + ) + assert in_mempool or in_block diff --git a/tests_python/tests_011/test_baker_endorser.py b/tests_python/tests_011/test_baker_endorser.py new file mode 100644 index 000000000000..ee3f476640e2 --- /dev/null +++ b/tests_python/tests_011/test_baker_endorser.py @@ -0,0 +1,117 @@ +import itertools +import random +import time +import subprocess +import pytest +from tools import utils, constants +from launchers.sandbox import Sandbox +from . import protocol + +random.seed(42) +KEYS = [f'bootstrap{i}' for i in range(1, 6)] +NEXT_KEY = itertools.cycle(KEYS) +NUM_NODES = 5 +NEW_NODES = 5 +REPLACE = False +NUM_CYCLES = 60 +TIME_BETWEEN_CYCLE = 1 +assert NEW_NODES <= NUM_CYCLES + + +def random_op(client): + sender = next(NEXT_KEY) + dest = random.choice([key for key in KEYS if key != sender]) + amount = random.randrange(10000) + return client.transfer(amount, sender, dest) + + +@pytest.mark.baker +@pytest.mark.endorser +@pytest.mark.multinode +@pytest.mark.slow +@pytest.mark.incremental +class TestAllDaemonsWithOperations: + """Runs two baker and two endorsers, generates random op, and + add (or replace) new nodes dynamically. After a little while, + we kill the bakers and check everyone synchronize to the same head.""" + + def test_setup_network(self, sandbox: Sandbox): + parameters = dict(protocol.PARAMETERS) + # each priority has a delay of 1 sec + parameters["time_between_blocks"] = ["1"] + for i in range(NUM_NODES): + sandbox.add_node(i, params=constants.NODE_PARAMS) + protocol.activate(sandbox.client(0), parameters) + sandbox.add_baker(0, 'bootstrap5', proto=protocol.DAEMON) + sandbox.add_baker(1, 'bootstrap4', proto=protocol.DAEMON) + sandbox.add_endorser( + 0, account='bootstrap1', endorsement_delay=1, proto=protocol.DAEMON + ) + sandbox.add_endorser( + 1, account='bootstrap2', endorsement_delay=1, proto=protocol.DAEMON + ) + + def test_wait_for_protocol(self, sandbox: Sandbox): + clients = sandbox.all_clients() + for client in clients: + proto = protocol.HASH + assert utils.check_protocol(client, proto) + + def test_network_gen_operations_and_add_nodes( + self, sandbox: Sandbox, session + ): + node_add_period = NUM_CYCLES // NEW_NODES + for cycle in range(NUM_CYCLES): + i = random.randrange(NUM_NODES) + client = sandbox.client(i) + try: + transfer = random_op(client) + session[f'op{cycle}'] = transfer.operation_hash + except subprocess.CalledProcessError: + # some operations may be invalid, e.g. the client sends + # several operation with the same counter + print('# IGNORED INVALID OPERATION') + + if cycle % node_add_period == 0: + # add node + running_nodes = list(sandbox.nodes.keys()) + new_node = max(running_nodes) + 1 + if REPLACE: + running_nodes.remove(0) + running_nodes.remove(1) + sandbox.rm_node(random.choice(running_nodes)) + sandbox.add_node(new_node, params=constants.NODE_PARAMS) + proto = protocol.HASH + assert utils.check_protocol(sandbox.client(new_node), proto) + time.sleep(TIME_BETWEEN_CYCLE) + + def test_kill_baker(self, sandbox: Sandbox): + sandbox.rm_baker(0, proto=protocol.DAEMON) + sandbox.rm_baker(1, proto=protocol.DAEMON) + + def test_synchronize(self, sandbox: Sandbox): + utils.synchronize(sandbox.all_clients()) + + def test_progress(self, sandbox: Sandbox): + level = sandbox.client(0).get_level() + assert level >= 5 + + def test_check_operations(self, sandbox: Sandbox): + min_level = min( + [client.get_level() for client in sandbox.all_clients()] + ) + heads_hash = set() + # check there is exactly one head + for client in sandbox.all_clients(): + block_hash = utils.get_block_hash(client, min_level) + heads_hash.add(block_hash) + assert len(heads_hash) == 1 + # TODO check for operations inclusion + + def test_check_logs(self, sandbox: Sandbox): + if not sandbox.log_dir: + pytest.skip() + assert sandbox.logs + # TODO check more things in the log! endorsement, baking... + error_pattern = r"Uncaught|registered" + assert utils.check_logs(sandbox.logs, error_pattern) diff --git a/tests_python/tests_011/test_basic.py b/tests_python/tests_011/test_basic.py new file mode 100644 index 000000000000..981985be96d5 --- /dev/null +++ b/tests_python/tests_011/test_basic.py @@ -0,0 +1,495 @@ +from os import path +import pytest +from client.client import Client +from tools import utils +from tools.paths import ACCOUNT_PATH +from tools.utils import assert_run_failure +from .contract_paths import CONTRACT_PATH + + +TRANSFER_ARGS = ['--burn-cap', '0.257'] + + +@pytest.mark.incremental +class TestRawContext: + def test_delegates(self, client: Client): + path = '/chains/main/blocks/head/context/raw/bytes/delegates/?depth=2' + res = client.rpc('get', path) + expected = { + "ed25519": { + "02298c03ed7d454a101eb7022bc95f7e5f41ac78": None, + "a9ceae0f8909125492a7c4700acc59274cc6c846": None, + "c55cf02dbeecc978d9c84625dcae72bb77ea4fbd": None, + "dac9f52543da1aed0bc1d6b46bf7c10db7014cd6": None, + "e7670f32038107a59a2b9cfefae36ea21f5aa63c": None, + } + } + assert res == expected + + def test_no_service_1(self, client: Client): + path = '/chains/main/blocks/head/context/raw/bytes/non-existent' + with assert_run_failure('No service found at this URL'): + client.rpc('get', path) + + def test_no_service_2(self, client: Client): + path = ( + '/chains/main/blocks/head/context/raw/bytes/' + 'non-existent?depth=-1' + ) + expected = 'Command failed: Extraction depth -1 is invalid' + with assert_run_failure(expected): + client.rpc('get', path) + + def test_no_service_3(self, client: Client): + path = '/chains/main/blocks/head/context/raw/bytes/non-existent?depth=0' + with assert_run_failure('No service found at this URL'): + client.rpc('get', path) + + def test_bake(self, client: Client): + utils.bake(client, 'bootstrap4') + + @pytest.mark.parametrize( + "identity, message, expected_signature", + [ + ( + 'bootstrap1', + 'msg1', + 'edsigtz68o4FdbpvycnAMDLaa7hpmmhjDx' + 'hx4Zu3QWHLYJtcY1mVhW9m6CCvsciFXwf1' + 'zLmah8fJP51cqaeaciBPGy5osH11AnR', + ), + ( + 'bootstrap2', + 'msg2', + 'edsigtZqhR5SW6vbRSmqwzfS1KiJZLYLe' + 'FhLcCEw7WxjBDxotVx83M2rLe4Baq52SUT' + 'jxfXhQ5J3TabCwqt78kNpoU8j42GDEk4', + ), + ( + 'bootstrap3', + 'msg3', + 'edsigu2PvAWxVYY3jQFVfBRW2Dg61xZMN' + 'esHiNbwCTmpJSyfcJMW8Ch9WABHqsgHQRB' + 'aSs6zZNHVGXfHSBnGCxT9x2b49L2zpMW', + ), + ( + 'bootstrap4', + 'msg4', + 'edsigu5jieost8eeD3JwVrpPuSnKzLLvR3' + 'aqezLPDTvxC3p41qwBEpxuViKriipxig5' + '2NQmJ7AFXTzhM3xgKM2ZaADcSMYWztuJ', + ), + ], + ) + def test_sign_message(self, client, identity, message, expected_signature): + assert client.sign_message(message, identity) == expected_signature + + @pytest.mark.parametrize( + "identity, message, signature", + [ + ( + 'bootstrap1', + 'msg1', + 'edsigtz68o4FdbpvycnAMDLaa7hpmmhjDx' + 'hx4Zu3QWHLYJtcY1mVhW9m6CCvsciFXwf1' + 'zLmah8fJP51cqaeaciBPGy5osH11AnR', + ), + ( + 'bootstrap2', + 'msg2', + 'edsigtZqhR5SW6vbRSmqwzfS1KiJZLYLe' + 'FhLcCEw7WxjBDxotVx83M2rLe4Baq52SUT' + 'jxfXhQ5J3TabCwqt78kNpoU8j42GDEk4', + ), + ( + 'bootstrap3', + 'msg3', + 'edsigu2PvAWxVYY3jQFVfBRW2Dg61xZMN' + 'esHiNbwCTmpJSyfcJMW8Ch9WABHqsgHQRB' + 'aSs6zZNHVGXfHSBnGCxT9x2b49L2zpMW', + ), + ( + 'bootstrap4', + 'msg4', + 'edsigu5jieost8eeD3JwVrpPuSnKzLLvR3' + 'aqezLPDTvxC3p41qwBEpxuViKriipxig5' + '2NQmJ7AFXTzhM3xgKM2ZaADcSMYWztuJ', + ), + ], + ) + def test_check_message(self, client, identity, message, signature): + assert client.check_message(message, identity, signature) + + @pytest.mark.parametrize( + "identity, message, head_block", + [ + ("bootstrap1", "msg1", False), + ("bootstrap2", "msg2", False), + ("bootstrap3", "msg3", True), + ("bootstrap4", "msg4", True), + ], + ) + def test_fail_inject_signed_arbitrary_ope( + self, client, identity, message, head_block + ): + if head_block: + signature = client.sign_message(message, identity, block="head") + else: + signature = client.sign_message(message, identity) + chain_id = client.rpc('get', '/chains/main/chain_id') + head_hash = client.rpc('get', '/chains/main/blocks/head/hash') + run_json = { + 'operation': { + "branch": head_hash, + "contents": [{"kind": "failing_noop", "arbitrary": message}], + 'signature': signature, + }, + 'chain_id': chain_id, + } + run_operation_path = ( + '/chains/main/blocks/head/helpers/scripts/run_operation' + ) + with assert_run_failure( + 'The failing_noop operation cannot be executed by the protocol' + ): + client.rpc('post', run_operation_path, data=run_json) + + def test_gen_keys(self, client: Client, session): + session['keys'] = ['foo', 'bar', 'boo'] + sigs = [None, 'secp256k1', 'ed25519'] + for key, sig in zip(session['keys'], sigs): + args = [] if sig is None else ['--sig', sig] + client.gen_key(key, args) + + def test_transfers(self, client: Client, session): + client.transfer(1000, 'bootstrap1', session['keys'][0], TRANSFER_ARGS) + utils.bake(client) + client.transfer(2000, 'bootstrap1', session['keys'][1], TRANSFER_ARGS) + utils.bake(client) + client.transfer(3000, 'bootstrap1', session['keys'][2], TRANSFER_ARGS) + utils.bake(client) + + def test_balances(self, client: Client, session): + assert client.get_balance(session['keys'][0]) == 1000 + assert client.get_balance(session['keys'][1]) == 2000 + assert client.get_balance(session['keys'][2]) == 3000 + + def test_transfer_bar_foo(self, client: Client, session): + client.reveal(session['keys'][1], ['--fee', '0', '--force-low-fee']) + utils.bake(client) + client.transfer( + 1000, + session['keys'][1], + session['keys'][0], + ['--fee', '0', '--force-low-fee'], + ) + utils.bake(client) + + def test_balances_bar_foo(self, client: Client, session): + assert client.get_balance(session['keys'][0]) == 2000 + assert client.get_balance(session['keys'][1]) == 1000 + + def test_transfer_foo_bar(self, client: Client, session): + client.reveal(session['keys'][0], ['--fee', '0', '--force-low-fee']) + utils.bake(client) + client.transfer( + 1000, session['keys'][0], session['keys'][1], ['--fee', '0.05'] + ) + utils.bake(client) + + def test_balances_foo_bar(self, client: Client, session): + # 999.95 = 1000 - transfer fees + assert client.get_balance(session['keys'][0]) == 999.95 + assert client.get_balance(session['keys'][1]) == 2000 + + def test_transfer_failure(self, client: Client, session): + with pytest.raises(Exception): + client.transfer(999.95, session['keys'][0], session['keys'][1]) + + def test_originate_contract_noop(self, client: Client): + contract = path.join(CONTRACT_PATH, 'opcodes', 'noop.tz') + client.remember('noop', contract) + client.typecheck(contract) + client.originate( + 'noop', 1000, 'bootstrap1', contract, ['--burn-cap', '0.295'] + ) + utils.bake(client) + + def test_transfer_to_noop(self, client: Client): + client.transfer(10, 'bootstrap1', 'noop', ['--arg', 'Unit']) + utils.bake(client) + + def test_contract_hardlimit(self, client: Client): + contract = path.join(CONTRACT_PATH, 'mini_scenarios', 'hardlimit.tz') + client.originate( + 'hardlimit', + 1000, + 'bootstrap1', + contract, + ['--init', '3', '--burn-cap', '0.341'], + ) + utils.bake(client) + client.transfer(10, 'bootstrap1', 'hardlimit', ['--arg', 'Unit']) + utils.bake(client) + client.transfer(10, 'bootstrap1', 'hardlimit', ['--arg', 'Unit']) + utils.bake(client) + + def test_transfers_bootstraps5_bootstrap1(self, client: Client): + assert client.get_balance('bootstrap5') == 4000000 + client.transfer( + 400000, + 'bootstrap5', + 'bootstrap1', + ['--fee', '0', '--force-low-fee'], + ) + utils.bake(client) + client.transfer( + 400000, + 'bootstrap1', + 'bootstrap5', + ['--fee', '0', '--force-low-fee'], + ) + utils.bake(client) + assert client.get_balance('bootstrap5') == 4000000 + + def test_activate_accounts(self, client: Client, session): + account = f"{ACCOUNT_PATH}/king_commitment.json" + session['keys'] += ['king', 'queen'] + client.activate_account(session['keys'][3], account) + utils.bake(client) + account = f"{ACCOUNT_PATH}/queen_commitment.json" + client.activate_account(session['keys'][4], account) + utils.bake(client) + assert client.get_balance(session['keys'][3]) == 23932454.669343 + assert client.get_balance(session['keys'][4]) == 72954577.464032 + + def test_transfer_king_queen(self, client: Client, session): + keys = session['keys'] + client.transfer(10, keys[3], keys[4], TRANSFER_ARGS) + utils.bake(client) + + def test_duplicate_alias(self, client: Client): + client.add_address("baz", "foo", force=True) + show_foo = client.show_address("foo", show_secret=True) + assert show_foo.secret_key is not None + + +@pytest.mark.incremental +class TestRememberContract: + @pytest.mark.parametrize( + "contract_name,non_originated_contract_address", + [ + ("test", "KT1BuEZtb68c1Q4yjtckcNjGELqWt56Xyesc"), + ("test-2", "KT1TZCh8fmUbuDqFxetPWC2fsQanAHzLx4W9"), + ], + ) + def test_non_originated_contract_no_forcing_not_saved_before( + self, + client, + contract_name, + non_originated_contract_address, + ): + client.remember_contract(contract_name, non_originated_contract_address) + + # As it is always the same client, the contracts have been saved + # before + @pytest.mark.parametrize( + "contract_name,non_originated_contract_address", + [ + ("test", "KT1BuEZtb68c1Q4yjtckcNjGELqWt56Xyesc"), + ("test-2", "KT1TZCh8fmUbuDqFxetPWC2fsQanAHzLx4W9"), + ], + ) + def test_non_originated_contract_with_forcing_and_saved_before( + self, + client, + contract_name, + non_originated_contract_address, + ): + client.remember_contract( + contract_name, non_originated_contract_address, force=True + ) + + # As it is always the same client, the contracts have been saved + # before + @pytest.mark.parametrize( + "contract_name,non_originated_contract_address", + [ + ("test", "KT1BuEZtb68c1Q4yjtckcNjGELqWt56Xyesc"), + ("test-2", "KT1TZCh8fmUbuDqFxetPWC2fsQanAHzLx4W9"), + ], + ) + def test_non_originated_contract_no_forcing_and_saved_before( + self, + client, + contract_name, + non_originated_contract_address, + ): + expected_error = f"The contract alias {contract_name} already exists" + + with assert_run_failure(expected_error): + client.remember_contract( + contract_name, non_originated_contract_address, force=False + ) + + # Test operation size. + def test_operation_size_originate_byte_contract(self, client: Client): + contract = path.join(CONTRACT_PATH, 'opcodes', 'bytes.tz') + client.remember('bytes', contract) + client.typecheck(contract) + client.originate( + 'bytes', 1000, 'bootstrap1', contract, ['--burn-cap', '0.295'] + ) + utils.bake(client) + + # Test that operations under 16KB can be injected in the node. + def test_operation_size_small(self, client: Client): + bytes_arg = "0x" + ("00" * 6 * 1024) # 6 KB of data. + + client.transfer(10, 'bootstrap1', 'bytes', ['--arg', bytes_arg]) + utils.bake(client) + + # Test that operations between 16KB and 32KB can be injected in the node. + def test_operation_size_medium(self, client: Client): + bytes_arg = "0x" + ("00" * 24 * 1024) # 24 KB of data. + + client.transfer(10, 'bootstrap1', 'bytes', ['--arg', bytes_arg]) + utils.bake(client) + + # Test that operations above 32KB fail to be injected. + def test_operation_size_oversized(self, client: Client): + bytes_arg = "0x" + ("00" * 36 * 1024) # 36 KB of data. + + expected_error = "Oversized operation" + with assert_run_failure(expected_error): + client.transfer(10, 'bootstrap1', 'bytes', ['--arg', bytes_arg]) + + # Test operation size with various data types. + def test_operation_size_originate_munch_contract(self, client: Client): + contract = path.join(CONTRACT_PATH, 'opcodes', 'munch.tz') + client.remember('munch', contract) + client.typecheck(contract) + client.originate( + 'munch', 1000, 'bootstrap1', contract, ['--burn-cap', '0.295'] + ) + utils.bake(client) + + # Test that a large operation under 32KB can be injected in the node + # (variant using a lambda with deep nesting). + def test_operation_size_with_lambda_ok(self, client: Client): + # Each pair of braces is encoded on 5 bytes so this takes + # 5 * 6 * 1024 = 30 KB < 32KB + big_arg = ("{" * 6 * 1024) + ("}" * 6 * 1024) + + client.transfer( + 10, + 'bootstrap1', + 'munch', + ['--arg', big_arg, "--entrypoint", "lambda"], + ) + utils.bake(client) + + # Test that a large operation over 32KB cannot be injected in the node, + # and the error is not a stack overflow + # (variant using a lambda with deep nesting). + def test_operation_size_with_lambda_fail(self, client: Client): + # Each pair of braces is encoded on 5 bytes so this takes + # 5 * 7 * 1024 = 35 KB > 32KB + big_arg = ("{" * 7 * 1024) + ("}" * 7 * 1024) + + expected_error = "Oversized operation" + with assert_run_failure(expected_error): + client.transfer( + 10, + 'bootstrap1', + 'munch', + ['--arg', big_arg, "--entrypoint", "lambda"], + ) + + # Test that a large operation under 32KB can be injected in the node + # (variant using a long list). + def test_operation_size_with_list_ok(self, client: Client): + # Each element in the list takes 2 bytes so about 30KB in total + big_arg = "{" + ("0; " * 15 * 1024) + "}" + + client.transfer( + 10, + 'bootstrap1', + 'munch', + ['--arg', big_arg, "--entrypoint", "list_nat"], + ) + utils.bake(client) + + def test_operation_size_with_list_syntax_error(self, client: Client): + # Each element in the list takes 2 bytes so about 30KB in total + big_arg = "{" + ("0; " * 15 * 1024) + "'foo;'" + "}" + + expected_error = "transfer simulation failed" + with assert_run_failure(expected_error): + client.transfer( + 10, + 'bootstrap1', + 'munch', + ['--arg', big_arg, "--entrypoint", "list_nat"], + ) + + def test_operation_size_with_list_ill_typed(self, client: Client): + # Each element in the list takes 2 bytes so about 30KB in total + big_arg = "{" + ("0; " * 15 * 1024) + "Unit;" + "}" + + expected_error = "transfer simulation failed" + with assert_run_failure(expected_error): + client.transfer( + 10, + 'bootstrap1', + 'munch', + ['--arg', big_arg, "--entrypoint", "list_nat"], + ) + + # Test that a large operation over 32KB cannot be injected in the node, + # and the error is not a stack overflow + # (variant using a long list). + def test_operation_size_with_list_fail(self, client: Client): + # Each element in the list takes 2 bytes so about 34KB in total + big_arg = "{" + ("0; " * 17 * 1024) + "}" + + expected_error = "Oversized operation" + with assert_run_failure(expected_error): + client.transfer( + 10, + 'bootstrap1', + 'munch', + ['--arg', big_arg, "--entrypoint", "list_nat"], + ) + + # Test that a large operation under 32KB can be injected in the node + # (variant using a big nat). + def test_operation_size_with_nat_ok(self, client: Client): + # The encoding for nat uses a byte to encode 7 bits of the number + # so the size of 2 ** (7 * n) is about n bytes + big_arg = 2 ** (7 * 30 * 1024) + + client.transfer( + 10, + 'bootstrap1', + 'munch', + ['--arg', f"{big_arg}", "--entrypoint", "nat"], + ) + utils.bake(client) + + # Test that a large operation over 32KB cannot be injected in the node, + # and the error is not a stack overflow + # (variant using a big nat). + def test_operation_size_with_nat_fail(self, client: Client): + # The encoding for nat uses a byte to encode 7 bits of the number + # so the size of 2 ** (7 * n) is about n bytes + big_arg = 2 ** (7 * 33 * 1024) + + expected_error = "Oversized operation" + with assert_run_failure(expected_error): + client.transfer( + 10, + 'bootstrap1', + 'munch', + ['--arg', f"{big_arg}", "--entrypoint", "nat"], + ) diff --git a/tests_python/tests_011/test_binaries.py b/tests_python/tests_011/test_binaries.py new file mode 100644 index 000000000000..b401b4b8cb39 --- /dev/null +++ b/tests_python/tests_011/test_binaries.py @@ -0,0 +1,48 @@ +""" +Tests common utility functionality of binaries shipped with Tezos. +""" + +import subprocess +from typing import List + +from process import process_utils +from tools import paths +from . import protocol + + +PROTO_BINARIES = [ + binary + "-" + protocol.DAEMON + for binary in ["tezos-baker", "tezos-endorser", "tezos-accuser"] +] + +BINARIES = [ + "tezos-codec", + "tezos-client", + "tezos-admin-client", + "tezos-protocol-compiler", + "tezos-node", + "tezos-snoop", + "tezos-validator", +] + PROTO_BINARIES + + +def run_cmd(cmd: List[str]) -> str: + """Pretty print a command. Execute it, print and return its standard + output.""" + print(process_utils.format_command(cmd)) + process_ret = subprocess.run( + cmd, check=True, capture_output=True, text=True + ) + print(process_ret.stdout) + return process_ret.stdout.strip() + + +class TestBinaries: + def test_version(self): + """Tests that all binaries accept the --version flag and that the + report the same version""" + versions = set() + for binary in BINARIES: + version = run_cmd([paths.TEZOS_HOME + binary, "--version"]) + versions.add(version) + assert len(versions) == 1, "All binaries should report the same version" diff --git a/tests_python/tests_011/test_block_times_ideal_scenario.py b/tests_python/tests_011/test_block_times_ideal_scenario.py new file mode 100644 index 000000000000..032549461a55 --- /dev/null +++ b/tests_python/tests_011/test_block_times_ideal_scenario.py @@ -0,0 +1,146 @@ +import random +import time +import pytest +from tools import utils, constants +from launchers.sandbox import Sandbox +from . import protocol + +random.seed(42) +NUM_NODES = 5 +TEST_DURATION = 10 +BD = 3 # base delay = time_between_blocks[0] +PD = 20 # priority delay = time_between_blocks[1] +IE = 2 # initial_endorsers +MD = 2 # base delay = time_between_blocks[0] + + +@pytest.mark.baker +@pytest.mark.multinode +@pytest.mark.slow +@pytest.mark.incremental +class TestBakers: + """Run NUM_NODES bakers and check that blocks are produced with the + expected timestamp. + + """ + + def test_setup_network(self, sandbox: Sandbox): + parameters = dict(protocol.PARAMETERS) + parameters["time_between_blocks"] = [str(BD), str(PD)] + parameters["initial_endorsers"] = IE + parameters["minimal_block_delay"] = "1" + assert parameters["delay_per_missing_endorsement"] == '1' + for i in range(NUM_NODES): + sandbox.add_node(i, params=constants.NODE_PARAMS) + + protocol.activate(sandbox.client(0), parameters) + + def test_wait_for_protocol(self, sandbox: Sandbox): + clients = sandbox.all_clients() + for client in clients: + proto = protocol.HASH + assert utils.check_protocol(client, proto) + assert client.get_level() == 1 + + def test_add_bakers(self, sandbox: Sandbox): + for i in range(NUM_NODES): + sandbox.add_baker(i, f'bootstrap{i+1}', proto=protocol.DAEMON) + + def test_check_level_and_timestamp(self, sandbox: Sandbox): + time.sleep(TEST_DURATION) + min_level = min( + [client.get_level() for client in sandbox.all_clients()] + ) + heads_hash = set() + # check there is exactly one block at the common level + for client in sandbox.all_clients(): + header = client.get_header(block=str(min_level)) + heads_hash.add(header['hash']) + assert len(heads_hash) == 1 + + # at least two new blocks should have been produced + assert min_level >= 3 + + # check that the timestamp difference is the expected one, + # use blocks at levels 2 and 3 (and not 1 and 2) because the + # one at level 2 may be baked late if the bakers start slowly + client = sandbox.client(0) + ts1 = client.get_block_timestamp(block=str(2)) + ts2 = client.get_block_timestamp(block=str(3)) + time_diff = (ts2 - ts1).total_seconds() + # there will be initial_endorsers missing endorsements + # so the block delay is BD + IE * 1 + assert time_diff == BD + IE + + +@pytest.mark.baker +@pytest.mark.endorser +@pytest.mark.multinode +@pytest.mark.slow +@pytest.mark.incremental +class TestBakersAndEndorsers: + """Run NUM_NODES bakers and endorsers and check that blocks are + produced with the expected timestamp.""" + + def test_setup_network(self, sandbox: Sandbox): + parameters = dict(protocol.PARAMETERS) + parameters["time_between_blocks"] = [str(BD), str(PD)] + parameters["minimal_block_delay"] = "2" + # we require all endorsements to be present + parameters["initial_endorsers"] = parameters["endorsers_per_block"] + for i in range(NUM_NODES): + sandbox.add_node(i, params=constants.NODE_PARAMS) + + protocol.activate(sandbox.client(0), parameters) + + def test_wait_for_protocol(self, sandbox: Sandbox): + clients = sandbox.all_clients() + for client in clients: + proto = protocol.HASH + assert utils.check_protocol(client, proto) + assert client.get_level() == 1 + + def test_add_bakers_and_endorsers(self, sandbox: Sandbox): + for i in range(NUM_NODES): + sandbox.add_baker(i, f'bootstrap{i+1}', proto=protocol.DAEMON) + for i in range(NUM_NODES): + sandbox.add_endorser( + i, + account=f'bootstrap{i+1}', + endorsement_delay=0, + proto=protocol.DAEMON, + ) + + def test_rm_bakers(self, sandbox: Sandbox): + time.sleep(TEST_DURATION) + for i in range(NUM_NODES): + sandbox.rm_baker(i, proto=protocol.DAEMON) + + def test_check_level_and_timestamp(self, sandbox: Sandbox): + client = sandbox.client(0) + levels = [client.get_level() for client in sandbox.all_clients()] + levels.sort() + min_level = levels[0] + max_level = levels[NUM_NODES - 1] + + heads_hash = set() + # check there is exactly one block at the common level + for client in sandbox.all_clients(): + header = client.get_header(block=str(min_level)) + heads_hash.add(header['hash']) + assert len(heads_hash) == 1 + + # There should be one block every MD seconds, so normally the level + # should have increased with TEST_DURATION / MD levels. + # We decrement by 1 "for safety". + assert max_level >= TEST_DURATION / MD + + # the RPCs should be quick wrt to the time between blocks, + # so nodes do not have time to diverge + assert levels[(NUM_NODES + 1) // 2] >= max_level - 2 + + # check that the timestamp difference is the expected one + ts0 = client.get_block_timestamp(block=str(2)) + ts1 = client.get_block_timestamp(block=str(max_level)) + time_diff = (ts1 - ts0).total_seconds() + assert time_diff == MD * (max_level - 2) diff --git a/tests_python/tests_011/test_bootstrap.py b/tests_python/tests_011/test_bootstrap.py new file mode 100644 index 000000000000..dcd8b966250e --- /dev/null +++ b/tests_python/tests_011/test_bootstrap.py @@ -0,0 +1,212 @@ +import time + +import pytest +from launchers.sandbox import Sandbox +from . import protocol + +LOG_LEVEL = {"validator.chain": "debug", "validator.peer": "debug"} + + +def params(threshold=0, latency=3): + return [ + '--sync-latency', + str(latency), + '--synchronisation-threshold', + str(threshold), + '--connections', + '100', + ] + + +@pytest.mark.baker +@pytest.mark.incremental +class TestThresholdZero: + """Threshold 0, peer always bootstrapped.""" + + def test_setup_network(self, sandbox: Sandbox): + sandbox.add_node(0, params=params(), log_levels=LOG_LEVEL) + sandbox.add_baker(0, 'bootstrap5', proto=protocol.DAEMON) + + def test_bootstrap(self, sandbox: Sandbox): + client = sandbox.client(0) + assert client.sync_state() == 'synced' + + +@pytest.mark.baker +@pytest.mark.multinode +@pytest.mark.incremental +class TestThresholdOne: + """First peer has threshold zero, second peer has threshold one""" + + def test_setup_network(self, sandbox: Sandbox): + sandbox.add_node(0, params=params(), log_levels=LOG_LEVEL) + protocol.activate(sandbox.client(0)) + sandbox.add_baker(0, 'bootstrap5', proto=protocol.DAEMON) + + def test_bootstrap(self, sandbox: Sandbox): + client = sandbox.client(0) + assert client.sync_state() == 'synced' + + def test_add_node(self, sandbox: Sandbox): + sandbox.add_node( + 1, params=params(1), log_levels=LOG_LEVEL, config_client=False + ) + sandbox.client(1).bootstrapped() + + +@pytest.mark.baker +@pytest.mark.multinode +@pytest.mark.incremental +class TestThresholdTwo: + def test_setup_network(self, sandbox: Sandbox): + sandbox.add_node(0, params=params(0), log_levels=LOG_LEVEL) + protocol.activate(sandbox.client(0)) + sandbox.add_baker(0, 'bootstrap5', proto=protocol.DAEMON) + + def test_add_nodes(self, sandbox: Sandbox): + sandbox.add_node( + 1, params=params(2), log_levels=LOG_LEVEL, config_client=False + ) + sandbox.add_node( + 2, params=params(2), log_levels=LOG_LEVEL, config_client=False + ) + sandbox.add_node( + 3, params=params(1), log_levels=LOG_LEVEL, config_client=False + ) + + @pytest.mark.timeout(5) + def test_node_3_bootstrapped(self, sandbox: Sandbox): + sandbox.client(3).bootstrapped() + + @pytest.mark.timeout(5) + def test_node_1_bootstrapped(self, sandbox: Sandbox): + sandbox.client(1).bootstrapped() + + +@pytest.mark.slow +@pytest.mark.baker +@pytest.mark.multinode +@pytest.mark.incremental +class TestStuck: + def test_setup_network(self, sandbox: Sandbox): + sandbox.add_node(0, params=params(), log_levels=LOG_LEVEL) + protocol.activate(sandbox.client(0)) + sandbox.add_baker(0, 'bootstrap5', proto=protocol.DAEMON) + + def test_kill_baker(self, sandbox: Sandbox): + """Bake a few blocks and kill baker""" + time.sleep(2) + sandbox.rm_baker(0, proto=protocol.DAEMON) + time.sleep(5) + + def test_progress(self, sandbox: Sandbox): + assert sandbox.client(0).get_level() >= 2 + + def test_add_node(self, sandbox: Sandbox): + sandbox.add_node( + 1, params=params(2), config_client=False, log_levels=LOG_LEVEL + ) + sandbox.add_node( + 2, params=params(2), config_client=False, log_levels=LOG_LEVEL + ) + + def test_all_nodes_boostrap(self, sandbox: Sandbox): + """Eventually, 1 and 2 are bootstrapped with the chain stuck. """ + sandbox.client(1).bootstrapped() + sandbox.client(2).bootstrapped() + assert sandbox.client(1).sync_state() == 'stuck' + assert sandbox.client(2).sync_state() == 'stuck' + + +@pytest.mark.baker +@pytest.mark.multinode +@pytest.mark.incremental +class TestSplitView: + def test_setup_network(self, sandbox: Sandbox): + sandbox.add_node(0, params=params(), log_levels=LOG_LEVEL) + protocol.activate(sandbox.client(0)) + sandbox.add_node( + 1, params=params(), config_client=False, log_levels=LOG_LEVEL + ) + sandbox.add_node( + 2, + params=params(2, latency=15), + config_client=False, + log_levels=LOG_LEVEL, + ) + sandbox.add_baker(0, 'bootstrap5', proto=protocol.DAEMON) + + @pytest.mark.timeout(10) + def test_all_nodes_boostrap(self, sandbox: Sandbox): + assert sandbox.client(0).sync_state() == 'synced' + assert sandbox.client(1).sync_state() == 'synced' + sandbox.client(2).bootstrapped() + + def test_pause(self): + time.sleep(2) + + def test_disconnect_node(self, sandbox: Sandbox): + """node 1 is disconnected from baker""" + sandbox.client(1).ban_peer(sandbox.node(0).p2p_port) + sandbox.client(0).ban_peer(sandbox.node(1).p2p_port) + + def test_sync_status(self, sandbox: Sandbox): + assert sandbox.client(0).sync_state() == 'synced' + assert sandbox.client(1).sync_state() == 'synced' + assert sandbox.client(2).sync_state() == 'synced' + + +NUM_NODES = 8 +RUNNING_TIME = 10 + + +@pytest.mark.baker +@pytest.mark.multinode +@pytest.mark.slow +@pytest.mark.incremental +class TestManyNodesBootstrap: + """Run many nodes, bake for a while, add a node and check it's bootstrapped + when it should be.""" + + def test_init(self, sandbox: Sandbox): + sandbox.add_node(0, params=params(), log_levels=LOG_LEVEL) + parameters = dict(protocol.PARAMETERS) + parameters["time_between_blocks"] = ["1", "0"] + protocol.activate(sandbox.client(0)) + sandbox.add_baker(0, 'bootstrap1', proto=protocol.DAEMON) + sandbox.add_node( + 1, params=params(), log_levels=LOG_LEVEL, config_client=False + ) + + def test_bootstrap(self, sandbox: Sandbox): + sandbox.client(0).bootstrapped() + sandbox.client(1).bootstrapped() + + def test_add_nodes(self, sandbox: Sandbox): + for i in range(2, NUM_NODES): + sandbox.add_node( + i, params=params(), config_client=False, log_levels=LOG_LEVEL + ) + + def test_let_baking(self): + time.sleep(RUNNING_TIME) + + def test_progress(self, sandbox, session): + cur_level = sandbox.client(NUM_NODES - 1).get_level() + assert cur_level > RUNNING_TIME // 2 # check progress + session['cur_level'] = cur_level + + @pytest.mark.timeout(50) + def test_add_one_more_node(self, sandbox, session): + new_node = NUM_NODES + sandbox.add_node( + new_node, + params=params(NUM_NODES), + config_client=False, + log_levels=LOG_LEVEL, + ) + time.sleep(1) + sandbox.client(new_node).p2p_stat() + sandbox.client(new_node).bootstrapped() + cur_level = session['cur_level'] + assert sandbox.client(new_node).get_level() >= cur_level diff --git a/tests_python/tests_011/test_client.py b/tests_python/tests_011/test_client.py new file mode 100644 index 000000000000..f42255fba442 --- /dev/null +++ b/tests_python/tests_011/test_client.py @@ -0,0 +1,35 @@ +import pytest +from client.client import Client +from tools.utils import assert_run_failure, bake + + +@pytest.mark.client +@pytest.mark.incremental +@pytest.mark.usefixtures("encrypted_account_with_tez") +class TestSimulation: + """ Tests the behavior of the --simulation flag. """ + + def test_transfer_simulation(self, client: Client): + """ Tests that --simulation does not ask for the key password. """ + client.transfer( + 0.1, "encrypted_account", "bootstrap1", ["--simulation"] + ) + + def test_transfer_without_simulation(self, client: Client): + """ Tests that the client asks for the password w/o --simulation. """ + with assert_run_failure("End_of_file", mode="stdout"): + client.transfer(0.1, "encrypted_account", "bootstrap1") + + def test_delegate_simulation(self, client: Client): + """ Tests that --simulation does not ask for the key password. """ + client.gen_key("delegate") + client.transfer(100, "bootstrap1", "delegate", ["--burn-cap", "1.0"]) + bake(client, bake_for="bootstrap1") + client.register_delegate("delegate") + bake(client, bake_for="bootstrap1") + client.set_delegate("encrypted_account", "delegate", ["--simulation"]) + + def test_delegate_without_simulation(self, client: Client): + """ Tests that the client asks for the password w/o --simulation. """ + with assert_run_failure("End_of_file", mode="stdout"): + client.set_delegate("encrypted_account", "delegate") diff --git a/tests_python/tests_011/test_client_without_node.py b/tests_python/tests_011/test_client_without_node.py new file mode 100644 index 000000000000..8e5a27bac845 --- /dev/null +++ b/tests_python/tests_011/test_client_without_node.py @@ -0,0 +1,450 @@ +"""Node-less tests for the client. + +Some client tests do not require a node running, nor a +persistent mockup environment. These can be placed here. +""" +import json +import os +import subprocess +import tempfile +from typing import List, Optional +import pytest +from client.client import Client +from tools.utils import assert_run_failure + +# Note that specifying "endpoint" and "web_port" is required +# for the final assertion of test_config_init_roundtrip to pass. That's because +# `config init -o` writes them even if unspecified by `--config-file` +# (it's a fine behavior, I just wanted to highlight it). +_INPUT_CONFIG_FILE = { + "confirmations": 1, + "endpoint": "http://127.0.0.1:8732", + "remote_signer": "http://127.0.0.2", + "web_port": 8080, + "password_filename": "/tmp/doesnt_exist", +} +_INPUT_CONFIG_FILES = [None, _INPUT_CONFIG_FILE] +_CMD_LINE_ARGS = { + "--endpoint": "http://127.0.0.1:9732", + "--wait": "3", + "--remote-signer": "http://10.0.0.2", + "--password-filename": "/tmp/doesnt_exist_either", +} +_CONFIG_FILE_FLAG = "--config-file" + + +@pytest.mark.client +class TestImportKeyMnemonic: + """ Checks that the keys are correctly imported from a mnemonic. """ + + @pytest.fixture + def mnemonic(self): + return ( + "seek paddle siege sting siege sick kidney " + + "detect coral because comfort long enforce napkin enter" + ) + + @pytest.fixture + def passphrase(self): + return "very_secure_passphrase" + + def test_import_simple(self, client: Client): + """ Tests a simple import. """ + mnemonic = "release easy pulp drop select attack false math cook \ +angry spin ostrich round dress acoustic" + prms = ["import", "keys", "from", "mnemonic", "zebra", "--force"] + stdin = mnemonic + "\n\n" + client.run_generic(prms, stdin=stdin) + addr = client.get_known_addresses() + assert addr.wallet["zebra"] == "tz1aGUKE72eN21iWztoDEeH4FeKaxWb7SAUb" + + def test_import_already_present_alias(self, client: Client, mnemonic): + """ Tests that importing fails if the alias is already present. """ + prms = [ + "import", + "keys", + "from", + "mnemonic", + "super_original", + "--force", + ] + stdin = mnemonic + "\n\n" + client.run_generic(prms, stdin=stdin) + prms = ["import", "keys", "from", "mnemonic", "super_original"] + expected_error = "The secret_key alias super_original already exists." + with assert_run_failure(expected_error): + client.run_generic(prms, stdin=stdin) + + def test_import_passphrase(self, client: Client, mnemonic, passphrase): + """ Tests an import where the user specifies a passphrase. """ + stdin = mnemonic + "\n" + passphrase + "\n" + prms = ["import", "keys", "from", "mnemonic", "key", "--force"] + client.run_generic(prms, stdin=stdin) + addr = client.get_known_addresses() + assert addr.wallet["key"] == "tz1QSF4TSVzaosgbaxnFJpRbs7798Skeb8Re" + + def test_encrypted(self, client: Client, mnemonic, passphrase): + """ Tests an import where the user wants to encrypt the key. """ + encrypt_pwd = "imgonnaencryptthiskeysohard" + stdin = ( + mnemonic + + "\n" + + passphrase + + "\n" + + encrypt_pwd + + "\n" + + encrypt_pwd + + "\n" + ) + prms = [ + "import", + "keys", + "from", + "mnemonic", + "cryptkey", + "--encrypt", + "--force", + ] + client.run_generic(prms, stdin=stdin) + addr = client.get_known_addresses() + pkh = addr.wallet["cryptkey"] + secret_key = client.show_address( + "cryptkey", show_secret=True + ).secret_key + assert secret_key is not None + assert secret_key.startswith("encrypted:") + assert pkh == "tz1QSF4TSVzaosgbaxnFJpRbs7798Skeb8Re" + + def test_gen_key_from_menmonic_bad_mnemonic(self, client: Client): + """ Tests that the command fails if the user gives a bad mnemonic. """ + prms = ["import", "keys", "from", "mnemonic", "alias", "--force"] + stdin = "hello\n\n" + expected_error = '"hello" is not a valid BIP39 mnemonic.' + with assert_run_failure(expected_error): + client.run_generic(prms, stdin=stdin) + + +@pytest.mark.usefixtures("encrypted_account_with_tez") +class TestStopLoopPassword: + """Tests that the client stops asking for the password after + three erroneous passwords given by the user""" + + @pytest.mark.parametrize('stdin', ["\n\n\n", "\n\n\nign", "\n\n\npassword"]) + def test_stops_after_three_tries(self, client: Client, stdin): + with assert_run_failure("3 incorrect password attempt"): + client.transfer(0.1, 'encrypted_account', 'bootstrap1', stdin=stdin) + + @pytest.mark.parametrize( + 'stdin', ["password\n", "\npassword\n", "\n\npassword\n"] + ) + def test_password_succeed_before_three_tries(self, client: Client, stdin): + client.transfer(0.1, 'encrypted_account', 'bootstrap1', stdin=stdin) + + +@pytest.mark.client +class TestChainId: + def test_chain_id_block_hash(self, nodeless_client: Client): + block_hash = 'BKyFui5WPY1n3e9aKF3qd2kGBKBtHu3rtm5miYFnUagJC1BdHTF' + prms = ['compute', 'chain', 'id', 'from', 'block', 'hash', block_hash] + assert nodeless_client.run(prms).strip() == 'NetXuwrXPL4VeX5' + + def test_chain_id_seed(self, nodeless_client: Client): + seed = 'choucroute' + prms = ['compute', 'chain', 'id', 'from', 'seed', seed] + assert nodeless_client.run(prms).strip() == 'NetXLGmPi3c5DXf' + + +def _write_config_file( + client: Client, filename: str, config_dict: Optional[dict] +): + """Writes `config_dict` to `filename`. Returns the json effectively + written""" + assert client is not None + assert filename is not None + assert config_dict is not None + + augmented_dict = dict(config_dict) # Copy for safety + # We need to set base_dir, it's required in the config file + augmented_dict["base_dir"] = client.base_dir + with open(filename, 'w') as handle: + json.dump(augmented_dict, handle) + + return augmented_dict + + +def _with_config_file_cmd(config_file: Optional[str], cmd: List[str]): + """Prefixes `cmd` with ["--config-file", config_file] if + config_file is not None""" + return ([_CONFIG_FILE_FLAG, config_file] if config_file else []) + cmd + + +def _gen_assert_msg(flag, sent, received): + result = f"Json sent with --{flag} differs from" + result += " json received" + result += f"\nJson sent is:\n{sent}" + result += f"\nwhile json received is:\n{received}" + + +@pytest.mark.client +@pytest.mark.parametrize('config_dict', _INPUT_CONFIG_FILES) +class TestConfigInit: + def test_config_init( + self, nodeless_client: Client, config_dict: Optional[dict] + ): + """ + Tests that calling + `[--config-file config_dict]? config init -o tmp_file` + works and yields valid json. + """ + try: + out_file = tempfile.mktemp(prefix='tezos-client.config_file') + in_file = None + + if config_dict is not None: + in_file = tempfile.mktemp(prefix='tezos-client.config_file') + _write_config_file(nodeless_client, in_file, config_dict) + + cmd = _with_config_file_cmd( + in_file, ["config", "init", "-o", out_file] + ) + nodeless_client.run(cmd) + # Try loading the file as json, to check it is valid + with open(out_file) as handle: + json.load(handle) + finally: + if in_file is not None: + os.remove(in_file) + os.remove(out_file) + + def test_config_init_roundtrip( + self, nodeless_client: Client, config_dict: Optional[dict] + ): + """Tests that calling `config init -o tmp_file` and + feeding its result to `tezos-client --config-file` works + and yields the same result (i.e. calling `tezos-client + --config-file tmp_file config init -o tmp_file2 yields + a `tmp_file2` that is similar to `tmp_file`). + + `config_dict` specifies the content of the initial config file + to use or None not to specify one. + """ + try: + if config_dict is None: + # Take initial json from default output of `config init` + + tmp_file1 = tempfile.mktemp(prefix='tezos-client.config_file') + cmd = ["config", "init", "-o", tmp_file1] + nodeless_client.run(cmd) + with open(tmp_file1) as handle: + json1 = json.load(handle) + + # Execute an arbitrary effectless command: + list_protos = ["list", "understood", "protocols"] + # This checks that + # `--config-file tmp_file1 arbitrary command` works + cmd = _with_config_file_cmd(tmp_file1, list_protos) + nodeless_client.run(cmd) + else: + # Take initial json from config_dict + + # Write config_dict to a file + tmp_file1 = tempfile.mktemp(prefix='tezos-client.config_file') + json1 = _write_config_file( + nodeless_client, tmp_file1, config_dict + ) + + # Execute `config init -o` + tmp_file2 = tempfile.mktemp(prefix='tezos-client.config_file') + cmd = _with_config_file_cmd( + tmp_file1, ["config", "init", "-o", tmp_file2] + ) + nodeless_client.run(cmd) + + # Load file generated by `config init -o` + with open(tmp_file2) as handle: + json2 = json.load(handle) + + # and finally check that the json generated by `config init -o` + # matches the input data (either the default one or the one + # specified with --config-file) + assert json1 == json2, _gen_assert_msg( + _CONFIG_FILE_FLAG, json1, json2 + ) + finally: + os.remove(tmp_file1) + os.remove(tmp_file2) + + +def _cmd_line_flag_to_json_field(cmd_line_flag: str): + if cmd_line_flag == "--wait": + return "confirmations" + result = cmd_line_flag + if cmd_line_flag.startswith("--"): + result = result[2:] + return result.replace("-", "_") + + +@pytest.mark.client +@pytest.mark.parametrize('config_dict', _INPUT_CONFIG_FILES) +class TestConfigShow: + """ Tests of `tezos-client config show` """ + + def test_config_show( + self, nodeless_client: Client, config_dict: Optional[dict] + ): + """ + Tests that calling `config show` works, with or without + specifying `--config-file` + """ + try: + tmp_file = None + if config_dict is not None: + tmp_file = tempfile.mktemp(prefix='tezos-client.config_file') + _write_config_file(nodeless_client, tmp_file, config_dict) + + cmd = _with_config_file_cmd(tmp_file, ["config", "show"]) + nodeless_client.run(cmd) + finally: + if tmp_file is not None: + os.remove(tmp_file) + + @pytest.mark.parametrize('cmd_line_args', [{}, _CMD_LINE_ARGS]) + def test_config_show_roundtrip( + self, + nodeless_client: Client, + config_dict: Optional[dict], + cmd_line_args: dict, + ): + """ + Tests calling `config show` with or without `--config-file` + and with some command line parameters (`cmd_line_arg`). It + then parses the output to check its valid json and to check + that command line parameters were honored. + + Then it feeds this output to a new call to `--config-file file + config show` and checks that the json returned by this second call + agrees with what was specified by `file`. + + This is a roundtrip test using a small matrix. + """ + try: + in_file1 = None + in_file2 = None + if config_dict is not None: + in_file1 = tempfile.mktemp(prefix='tezos-client.config_file') + _write_config_file(nodeless_client, in_file1, config_dict) + + cmd = [] + # Pass command line parameters + for (flag, value) in cmd_line_args.items(): + cmd += [flag, value] + cmd += ["config", "show"] + cmd = _with_config_file_cmd(in_file1, cmd) + # Take standard output + (stdout, _, _) = nodeless_client.run_generic(cmd) + + output_json1 = json.loads(stdout) + # Verify that command line parameters were honored + for (flag, value) in cmd_line_args.items(): + input_value = cmd_line_args[flag] + assert isinstance(input_value, str) + output_value = output_json1[_cmd_line_flag_to_json_field(flag)] + output_value = str(output_value) + err_msg = ( + f"Value of command line flag {flag} is not honored:" + f" passed {input_value} but" + f" config show yielded {output_value}" + ) + assert output_value == input_value, err_msg + in_file2 = tempfile.mktemp(prefix='tezos-client.config_file') + # Write output of first call to `config show` to disk, + # to pass it to second call below + with open(in_file2, 'w') as handle: + handle.write(json.dumps(output_json1)) + + # Use previous ouput file as input now + cmd = _with_config_file_cmd(in_file2, ["config", "show"]) + (stdout, _, _) = nodeless_client.run_generic(cmd) + + output_json2 = json.loads(stdout) + + # And finally check that the final output matches the input + assert output_json1 == output_json2, _gen_assert_msg( + _CONFIG_FILE_FLAG, output_json1, output_json2 + ) + finally: + for in_file in [in_file1, in_file2]: + if in_file is not None: + os.remove(in_file) + + +@pytest.mark.client +class TestConfigValid: + """ Tests of validity of tezos-client config """ + + def test_config_node_port(self, nodeless_client: Client): + """ + Tests that calling `config show` works, with a valid node port + """ + self._run_config_show_with_node_port(nodeless_client, 8732) + self._run_config_show_with_node_port(nodeless_client, 58732) + pytest.raises( + subprocess.CalledProcessError, + self._run_config_show_with_node_port, + nodeless_client, + 158732, + ) + pytest.raises( + subprocess.CalledProcessError, + self._run_config_show_with_node_port, + nodeless_client, + -8732, + ) + + def test_config_web_port(self, nodeless_client: Client): + """ + Tests that calling `config show` works, with a valid node port + """ + self._run_config_show_with_web_port(nodeless_client, 8732) + self._run_config_show_with_web_port(nodeless_client, 58732) + pytest.raises( + subprocess.CalledProcessError, + self._run_config_show_with_web_port, + nodeless_client, + 158732, + ) + pytest.raises( + subprocess.CalledProcessError, + self._run_config_show_with_web_port, + nodeless_client, + -8732, + ) + + def _run_config_show_with_temp_config_file( + self, nodeless_client: Client, config_dict: dict + ): + try: + tmp_file = tempfile.mktemp(prefix='tezos-client.config_file') + _write_config_file(nodeless_client, tmp_file, config_dict) + + cmd = _with_config_file_cmd(tmp_file, ["config", "show"]) + nodeless_client.run(cmd) + finally: + if tmp_file is not None: + os.remove(tmp_file) + + def _run_config_show_with_node_port( + self, nodeless_client: Client, port: int + ): + config_dict = {"node_port": port} + self._run_config_show_with_temp_config_file( + nodeless_client, config_dict + ) + + def _run_config_show_with_web_port( + self, nodeless_client: Client, port: int + ): + config_dict = {"web_port": port} + self._run_config_show_with_temp_config_file( + nodeless_client, config_dict + ) diff --git a/tests_python/tests_011/test_codec.py b/tests_python/tests_011/test_codec.py new file mode 100644 index 000000000000..bb87d8b037f7 --- /dev/null +++ b/tests_python/tests_011/test_codec.py @@ -0,0 +1,23 @@ +from typing import Any +import pytest +from codec.codec import Codec +from tools import paths + +CODEC_BIN = paths.TEZOS_HOME + "tezos-codec" + +ENCODINGS = [ + ( + "network_version", + {"p2p_version": 0, "distributed_db_version": 1, "chain_name": "main"}, + ) +] + + +@pytest.mark.codec +class TestCodec: + @pytest.mark.parametrize("encoding_name, data", ENCODINGS) + def test_codec_encode_decode(self, encoding_name: str, data: Any): + codec = Codec(CODEC_BIN) + data_encoded = codec.encode(encoding_name, data_json=data) + data_decoded = codec.decode(encoding_name, data=data_encoded) + assert data_decoded == data diff --git a/tests_python/tests_011/test_contract.py b/tests_python/tests_011/test_contract.py new file mode 100644 index 000000000000..ff41e632d856 --- /dev/null +++ b/tests_python/tests_011/test_contract.py @@ -0,0 +1,2134 @@ +import os +import re +import itertools +from typing import List, Union, Any +import pytest + +from client.client import Client +from tools import utils +from tools.constants import IDENTITIES +from tools.utils import originate +from .contract_paths import ( + CONTRACT_PATH, + ILLTYPED_CONTRACT_PATH, + all_contracts, + all_legacy_contracts, +) + + +ID_SCRIPT_LITERAL = ''' +parameter unit; storage unit; code {CAR; NIL operation; PAIR} +'''.strip() +ID_SCRIPT_HASH = ''' +exprtpyospPfMqcARmu5FGukprC7kbbe4jb4zxFd4Gxrp2vcCPjRNa +'''.strip() + + +@pytest.mark.contract +@pytest.mark.incremental +class TestManager: + def test_manager_origination(self, client: Client, session: dict): + path = os.path.join(CONTRACT_PATH, 'entrypoints', 'manager.tz') + pubkey = IDENTITIES['bootstrap2']['identity'] + originate(client, session, path, f'"{pubkey}"', 1000) + originate( + client, session, path, f'"{pubkey}"', 1000, contract_name="manager2" + ) + + def test_delegatable_origination(self, client: Client, session: dict): + path = os.path.join( + CONTRACT_PATH, 'entrypoints', 'delegatable_target.tz' + ) + pubkey = IDENTITIES['bootstrap2']['identity'] + originate( + client, session, path, f'Pair "{pubkey}" (Pair "hello" 45)', 1000 + ) + + def test_target_with_entrypoints_origination(self, client: Client, session): + path = os.path.join( + CONTRACT_PATH, 'entrypoints', 'big_map_entrypoints.tz' + ) + originate( + client, session, path, 'Pair {} {}', 1000, contract_name='target' + ) + + def test_target_without_entrypoints_origination( + self, client: Client, session + ): + path = os.path.join( + CONTRACT_PATH, 'entrypoints', 'no_entrypoint_target.tz' + ) + originate( + client, + session, + path, + 'Pair "hello" 42', + 1000, + contract_name='target_no_entrypoints', + ) + + def test_target_without_default_origination(self, client: Client, session): + path = os.path.join( + CONTRACT_PATH, 'entrypoints', 'no_default_target.tz' + ) + originate( + client, + session, + path, + 'Pair "hello" 42', + 1000, + contract_name='target_no_default', + ) + + def test_target_with_root_origination(self, client: Client, session): + path = os.path.join(CONTRACT_PATH, 'entrypoints', 'rooted_target.tz') + originate( + client, + session, + path, + 'Pair "hello" 42', + 1000, + contract_name='rooted_target', + ) + + def test_manager_set_delegate(self, client: Client): + client.set_delegate('manager', 'bootstrap2', []) + utils.bake(client, 'bootstrap5') + bootstrap2_pkh = IDENTITIES['bootstrap2']['identity'] + client.set_delegate('delegatable_target', bootstrap2_pkh, []) + utils.bake(client, 'bootstrap5') + delegate = IDENTITIES['bootstrap2']['identity'] + assert client.get_delegate('manager', []).delegate == delegate + assert ( + client.get_delegate('delegatable_target', []).delegate == delegate + ) + client.set_delegate('manager', 'bootstrap3', []) + utils.bake(client, 'bootstrap5') + client.set_delegate('delegatable_target', 'bootstrap3', []) + utils.bake(client, 'bootstrap5') + delegate = IDENTITIES['bootstrap3']['identity'] + assert client.get_delegate('manager', []).delegate == delegate + assert ( + client.get_delegate('delegatable_target', []).delegate == delegate + ) + + def test_manager_withdraw_delegate(self, client: Client): + client.withdraw_delegate('manager', []) + utils.bake(client, 'bootstrap5') + client.withdraw_delegate('delegatable_target', []) + utils.bake(client, 'bootstrap5') + assert client.get_delegate('manager', []).delegate is None + assert client.get_delegate('delegatable_target', []).delegate is None + + def test_transfer_to_manager(self, client: Client): + balance = client.get_mutez_balance('manager') + balance_bootstrap = client.get_mutez_balance('bootstrap2') + amount = 10.001 + amount_mutez = utils.mutez_of_tez(amount) + client.transfer( + amount, + 'bootstrap2', + 'manager', + ['--gas-limit', f'{128 * 15450 + 108}'], + ) + utils.bake(client, 'bootstrap5') + new_balance = client.get_mutez_balance('manager') + new_balance_bootstrap = client.get_mutez_balance('bootstrap2') + fee = 0.000382 + fee_mutez = utils.mutez_of_tez(fee) + assert balance + amount_mutez == new_balance + assert ( + balance_bootstrap - fee_mutez - amount_mutez + == new_balance_bootstrap + ) + + def test_simple_transfer_from_manager_to_implicit(self, client: Client): + balance = client.get_mutez_balance('manager') + balance_bootstrap = client.get_mutez_balance('bootstrap2') + amount = 10.1 + amount_mutez = utils.mutez_of_tez(amount) + client.transfer( + amount, + 'manager', + 'bootstrap2', + ['--gas-limit', f'{128 * 26350 + 12}'], + ) + utils.bake(client, 'bootstrap5') + new_balance = client.get_mutez_balance('manager') + new_balance_bootstrap = client.get_mutez_balance('bootstrap2') + fee = 0.000584 + fee_mutez = utils.mutez_of_tez(fee) + assert balance - amount_mutez == new_balance + assert ( + balance_bootstrap + amount_mutez - fee_mutez + == new_balance_bootstrap + ) + + def test_transfer_from_manager_to_manager(self, client: Client): + balance = client.get_mutez_balance('manager') + balance_dest = client.get_mutez_balance('manager2') + balance_bootstrap = client.get_mutez_balance('bootstrap2') + amount = 10 + amount_mutez = utils.mutez_of_tez(amount) + client.transfer( + amount, + 'manager', + 'manager2', + ['--gas-limit', f'{128 * 44950 + 112}'], + ) + utils.bake(client, 'bootstrap5') + new_balance = client.get_mutez_balance('manager') + new_balance_dest = client.get_mutez_balance('manager2') + new_balance_bootstrap = client.get_mutez_balance('bootstrap2') + fee = 0.000727 + fee_mutez = utils.mutez_of_tez(fee) + assert balance_bootstrap - fee_mutez == new_balance_bootstrap + assert balance - amount_mutez == new_balance + assert balance_dest + amount_mutez == new_balance_dest + + def test_transfer_from_manager_to_default(self, client: Client): + client.transfer( + 10, 'manager', 'bootstrap2', ['--entrypoint', 'default'] + ) + utils.bake(client, 'bootstrap5') + client.transfer(10, 'manager', 'manager', ['--entrypoint', 'default']) + utils.bake(client, 'bootstrap5') + + def test_transfer_from_manager_to_target(self, client: Client): + client.transfer(10, 'manager', 'target', ['--burn-cap', '0.356']) + utils.bake(client, 'bootstrap5') + + def test_transfer_from_manager_to_entrypoint_with_args( + self, client: Client + ): + arg = 'Pair "hello" 42' + # using 'transfer' + client.transfer( + 0, + 'manager', + 'target', + ['--entrypoint', 'add_left', '--arg', arg, '--burn-cap', '0.067'], + ) + utils.bake(client, 'bootstrap5') + client.transfer( + 0, + 'manager', + 'target', + ['--entrypoint', 'mem_left', '--arg', '"hello"'], + ) + utils.bake(client, 'bootstrap5') + + # using 'call' + client.call( + 'manager', + 'target', + ['--entrypoint', 'add_left', '--arg', arg, '--burn-cap', '0.067'], + ) + utils.bake(client, 'bootstrap5') + client.call( + 'manager', + 'target', + ['--entrypoint', 'mem_left', '--arg', '"hello"'], + ) + utils.bake(client, 'bootstrap5') + + def test_transfer_from_manager_no_entrypoint_with_args( + self, client: Client + ): + arg = 'Left Unit' + client.transfer(0, 'manager', 'target_no_entrypoints', ['--arg', arg]) + utils.bake(client, 'bootstrap5') + + client.call('manager', 'target_no_entrypoints', ['--arg', arg]) + utils.bake(client, 'bootstrap5') + + def test_transfer_from_manager_to_no_default_with_args( + self, client: Client + ): + arg = 'Left Unit' + client.transfer(0, 'manager', 'target_no_default', ['--arg', arg]) + utils.bake(client, 'bootstrap5') + + client.call('manager', 'target_no_default', ['--arg', arg]) + utils.bake(client, 'bootstrap5') + + def test_transfer_from_manager_to_rooted_target_with_args( + self, client: Client + ): + arg = 'Left Unit' + client.transfer( + 0, + 'manager', + 'rooted_target', + ['--arg', arg, '--entrypoint', 'root'], + ) + utils.bake(client, 'bootstrap5') + + client.call( + 'manager', 'rooted_target', ['--arg', arg, '--entrypoint', 'root'] + ) + utils.bake(client, 'bootstrap5') + + +# This test to verifies contract execution order. There are 3 +# contracts: Storer, Caller, and Appender. Storer appends its argument +# to storage. Caller calls the list of unit contracts in its +# storage. Appender calls the string contract in its storage with a +# stored argument. +# +# For each test, there is one unique Storer. Each test is +# parameterized by a tree and the expected final storage of the +# Storer. A leaf in the tree is a string. Inner nodes are lists of +# leafs/inner nodes. The test maps maps over this tree to build a +# tree of contracts. Leaf nodes map to Appender contracts calling +# the Storer. Inner nodes map to Caller contract that calling +# children. +# +# Example. Given the tree: ["A", ["B"], "C"], we obtain +# Caller([Appender("A"), Caller([Appender("B")]), Appender("C")]) +# Before the protocol 009, contract execution order was in BFS +# In BFS, Storer would've ended up with storage ACB. +# In DFS, Storer will end up with storage ABC. +@pytest.mark.contract +@pytest.mark.incremental +class TestExecutionOrdering: + STORER = f'{CONTRACT_PATH}/mini_scenarios/execution_order_storer.tz' + CALLER = f'{CONTRACT_PATH}/mini_scenarios/execution_order_caller.tz' + APPENDER = f'{CONTRACT_PATH}/mini_scenarios/execution_order_appender.tz' + + def originate_storer(self, client: Client, session: dict): + origination = originate( + client, session, self.STORER, '""', 0, arguments=['--force'] + ) + session['storer'] = origination.contract + utils.bake(client, 'bootstrap3') + return origination.contract + + def originate_appender( + self, client: Client, session: dict, storer: str, argument: str + ): + origination = originate( + client, + session, + self.APPENDER, + f'Pair "{storer}" "{argument}"', + 0, + contract_name=f'appender-{argument}', + arguments=['--force'], + ) + session[f'appender.{argument}'] = origination.contract + utils.bake(client, 'bootstrap3') + return origination.contract + + def originate_caller( + self, client: Client, session: dict, callees: List[str] + ): + storage = "{" + '; '.join(map('"{}"'.format, callees)) + "}" + origination = originate( + client, + session, + self.CALLER, + storage, + 0, + contract_name=f'caller-{hash(storage)}', + ) + utils.bake(client, 'bootstrap3') + return origination.contract + + @pytest.mark.parametrize( + "tree, expected", + [ + # before 009, the result should be "DABCEFG". + ([["A", "B", "C"], "D", ["E", "F", "G"]], "ABCDEFG"), + # before 009, the result should be "ACB". + ([["A", ["B"], "C"]], "ABC"), + # before 009, the result should be "ABDC". + ([["A", ["B", ["C"], "D"]]], "ABCD"), + ([], ""), + ], + ) + def test_ordering( + self, + client: Client, + session: dict, + # approximation of recursive type annotation + tree: Union[str, List[Any]], + expected: str, + ): + storer = self.originate_storer(client, session) + + def deploy_tree(tree: Union[str, List[Any]]) -> str: + # leaf + if isinstance(tree, str): + # deploy and return caller str + return self.originate_appender(client, session, storer, tree) + # inner node + children = list(map(deploy_tree, tree)) + return self.originate_caller(client, session, children) + + root = deploy_tree(tree) + + client.transfer( + 0, + 'bootstrap2', + root, + ["--burn-cap", "5"], + ) + utils.bake(client, 'bootstrap3') + assert client.get_storage(storer) == '"{}"'.format(expected) + + +@pytest.mark.slow +@pytest.mark.contract +class TestContracts: + """Test type checking and execution of a bunch of contracts""" + + @pytest.mark.parametrize("contract", all_contracts()) + def test_typecheck(self, client: Client, contract): + assert contract.endswith( + '.tz' + ), "test contract should have .tz extension" + client.typecheck(os.path.join(CONTRACT_PATH, contract)) + + @pytest.mark.parametrize("contract", all_legacy_contracts()) + def test_deprecated_typecheck_breaks(self, client, contract): + if contract in [ + "legacy/create_contract.tz", + "legacy/create_contract_flags.tz", + "legacy/create_contract_rootname.tz", + ]: + with utils.assert_run_failure(r'ill-typed script'): + client.typecheck(os.path.join(CONTRACT_PATH, contract)) + else: + with utils.assert_run_failure(r'Use of deprecated instruction'): + client.typecheck(os.path.join(CONTRACT_PATH, contract)) + + @pytest.mark.parametrize("contract", all_legacy_contracts()) + def test_deprecated_typecheck_in_legacy(self, client, contract): + if contract in [ + "legacy/create_contract.tz", + "legacy/create_contract_flags.tz", + "legacy/create_contract_rootname.tz", + ]: + with utils.assert_run_failure(r'ill-typed script'): + client.typecheck( + os.path.join(CONTRACT_PATH, contract), legacy=True + ) + else: + with utils.assert_run_failure(r'Use of deprecated instruction'): + client.typecheck( + os.path.join(CONTRACT_PATH, contract), legacy=True + ) + + @pytest.mark.parametrize( + "contract,error_pattern", + [ + # Even though the interpreter uses a nonempty stack internally, + # the typechecker should not be able to observe it. + ( + "stack_bottom_unfailwithable.tz", + r'wrong stack type for instruction FAILWITH', + ), + ( + "stack_bottom_unrightable.tz", + r'wrong stack type for instruction RIGHT', + ), + ( + "stack_bottom_unleftable.tz", + r'wrong stack type for instruction LEFT', + ), + ( + "stack_bottom_ungetable.tz", + r'wrong stack type for instruction GET', + ), + ( + "stack_bottom_unpairable.tz", + r'wrong stack type for instruction UNPAIR', + ), + ( + "stack_bottom_undug2able.tz", + r'wrong stack type for instruction DUG', + ), + ( + "stack_bottom_undugable.tz", + r'wrong stack type for instruction DUG', + ), + ( + "stack_bottom_undig2able.tz", + r'wrong stack type for instruction DIG', + ), + ( + "stack_bottom_undigable.tz", + r'wrong stack type for instruction DIG', + ), + ( + "stack_bottom_undip2able.tz", + r'wrong stack type for instruction DUP', + ), + ( + "stack_bottom_undipable.tz", + r'wrong stack type for instruction DUP', + ), + ( + "stack_bottom_undup2able.tz", + r'wrong stack type for instruction DUP', + ), + ( + "stack_bottom_undropable.tz", + r'wrong stack type for instruction DROP', + ), + ( + "stack_bottom_unpopable.tz", + r'wrong stack type for instruction DUP', + ), + ( + "stack_bottom_unpopable_in_lambda.tz", + r'wrong stack type for instruction DUP', + ), + # operations cannot be PACKed + ( + "pack_operation.tz", + r'operation type forbidden in parameter, storage and constants', + ), + # big_maps cannot be PACKed + ( + "pack_big_map.tz", + r'big_map or sapling_state type not expected here', + ), + ( + "invalid_self_entrypoint.tz", + r'Contract has no entrypoint named D', + ), + ("contract_annotation_default.tz", r'unexpected annotation'), + # Missing field + ( + "missing_only_storage_field.tz", + r'Missing contract field: storage', + ), + ("missing_only_code_field.tz", r'Missing contract field: code'), + ( + "missing_only_parameter_field.tz", + r'Missing contract field: parameter', + ), + ( + "missing_parameter_and_storage_fields.tz", + r'Missing contract field: parameter', + ), + # Duplicated field + ( + "multiple_parameter_field.tz", + r'duplicate contract field: parameter', + ), + ("multiple_code_field.tz", r'duplicate contract field: code'), + ("multiple_storage_field.tz", r'duplicate contract field: storage'), + # The first duplicated field is reported, storage in this case + ( + "multiple_storage_and_code_fields.tz", + r'duplicate contract field: storage', + ), + # error message for set update on non-comparable type + ( + "set_update_non_comparable.tz", + r'Type nat is not compatible with type list operation', + ), + # error message for the arity of the chain_id type + ( + "chain_id_arity.tz", + r'primitive chain_id expects 0 arguments but is given 1', + ), + # error message for DIP over the limit + ("big_dip.tz", r'expected a positive 10-bit integer'), + # error message for DROP over the limit + ("big_drop.tz", r'expected a positive 10-bit integer'), + # error message for set update on non-comparable type + ( + "set_update_non_comparable.tz", + r'Type nat is not compatible with type list operation', + ), + # error message for attempting to push a value of type never + ("never_literal.tz", r'type never has no inhabitant.'), + # field annotation mismatch with UNPAIR + ( + "unpair_field_annotation_mismatch.tz", + r'The field access annotation does not match', + ), + # COMB, UNCOMB, and DUP cannot take 0 as argument + ("comb0.tz", r"PAIR expects an argument of at least 2"), + ("comb1.tz", r"PAIR expects an argument of at least 2"), + ("uncomb0.tz", r"UNPAIR expects an argument of at least 2"), + ("uncomb1.tz", r"UNPAIR expects an argument of at least 2"), + ("dup0.tz", r"DUP n expects an argument of at least 1"), + ( + "push_big_map_with_id_with_parens.tz", + r"big_map or sapling_state type not expected here", + ), + ( + "push_big_map_with_id_without_parens.tz", + r"primitive PUSH expects 2 arguments but is given 4", + ), + # sapling_state is not packable + ( + "pack_sapling_state.tz", + r"big_map or sapling_state type not expected here", + ), + # sapling_state is not packable + ( + "unpack_sapling_state.tz", + r"big_map or sapling_state type not expected here", + ), + # Ticket duplication attempt + ( + "ticket_dup.tz", + r'ticket nat cannot be used here because it is not duplicable', + ), + # error message for ticket unpack + ("ticket_unpack.tz", r'Ticket in unauthorized position'), + # error message for attempting to use APPLY to capture a ticket + ("ticket_apply.tz", r'Ticket in unauthorized position'), + # error message for attempting to wrap a ticket in a ticket + ( + "ticket_in_ticket.tz", + r'comparable type expected.Type ticket unit is not comparable', + ), + ], + ) + def test_ill_typecheck(self, client: Client, contract, error_pattern): + with utils.assert_run_failure(error_pattern): + client.typecheck(os.path.join(ILLTYPED_CONTRACT_PATH, contract)) + + def test_zero_transfer_to_implicit_contract(self, client): + pubkey = IDENTITIES['bootstrap3']['identity'] + err = ( + 'Transaction of 0ꜩ towards a contract without code are ' + rf'forbidden \({pubkey}\).' + ) + with utils.assert_run_failure(err): + client.transfer(0, 'bootstrap2', 'bootstrap3', []) + + def test_zero_transfer_to_nonexistent_contract(self, client): + nonexistent = "KT1Fcq4inD44aMhmUiTEHR1QMQwJT7p2u641" + err = rf'Contract {nonexistent} does not exist' + with utils.assert_run_failure(err): + client.transfer(0, 'bootstrap2', nonexistent, []) + + +FIRST_EXPLOSION = ''' +{ parameter unit; + storage unit; + code{ DROP; PUSH nat 0 ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DROP ; UNIT ; NIL operation ; PAIR} } +''' + + +# FIRST_EXPLOSION costs a large amount of gas just for typechecking. +# FIRST_EXPLOSION_BIGTYPE type size exceeds the protocol set bound. +FIRST_EXPLOSION_BIGTYPE = ''' +{ parameter unit; + storage unit; + code{ DROP; PUSH nat 0 ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DUP ; PAIR ; + DROP ; UNIT ; NIL operation ; PAIR} } +''' + + +SECOND_EXPLOSION = ''' +{ parameter (list int) ; + storage (list (list (list int))) ; + code { CAR ; DIP { NIL (list int) } ; + DUP ; ITER { DROP ; DUP ; DIP { CONS } } ; + DROP ; DIP { NIL (list (list int)) } ; + DUP ; ITER { DROP ; DUP ; DIP { CONS } } ; + DROP ; NIL operation ; PAIR } } +''' + + +@pytest.mark.incremental +@pytest.mark.contract +class TestView: + def test_deploy_view_lib(self, client, session): + path = f'{CONTRACT_PATH}/opcodes/view_toplevel_lib.tz' + originate(client, session, path, '3', 999) + session['lib'] = session['contract'] + client.bake('bootstrap3', ["--minimal-timestamp"]) + + @pytest.mark.parametrize( + "contract,init_storage,expected", + [ + ('view_op_id', '(Pair 0 0)', 'Pair 10 3'), + ('view_op_add', '42', '13'), + ('view_fib', '0', '55'), + ('view_mutual_recursion', '0', '20'), + ('view_op_nonexistent_func', 'True', 'False'), + ('view_op_nonexistent_addr', 'True', 'False'), + ('view_op_toplevel_inconsistent_input_type', '5', '0'), + ('view_op_toplevel_inconsistent_output_type', 'True', 'False'), + ], + ) + def test_runtime(self, client, session, contract, init_storage, expected): + path = f'{CONTRACT_PATH}/opcodes/' + contract + '.tz' + originate(client, session, path, init_storage, 0) + client.transfer( + 0, + 'bootstrap1', + contract, + [ + "--arg", + "(Pair 10 \"" + session['lib'] + "\")", + '--gas-limit', + '1000000', + "--burn-cap", + "0.1", + ], + ) + client.bake('bootstrap2', ["--minimal-timestamp"]) + assert client.get_storage(contract) == expected + + def test_create_contract( + self, + client, + session, + ): + contract = 'create_contract_with_view' + path = f'{CONTRACT_PATH}/opcodes/{contract}.tz' + originate(client, session, path, 'None', 0) + client.transfer( + 0, + 'bootstrap1', + contract, + [ + "--arg", + "Unit", + "--burn-cap", + "0.1", + ], + ) + client.bake('bootstrap2', ["--minimal-timestamp"]) + + addr = client.get_storage(contract).split()[1] + contract = 'view_op_constant' + path = f'{CONTRACT_PATH}/opcodes/{contract}.tz' + originate(client, session, path, '2', 0) + expected = "10" + + client.transfer( + 0, + "bootstrap1", + contract, + [ + "--arg", + f"(Pair {expected} {addr})", + "--burn-cap", + "0.1", + ], + ) + client.bake('bootstrap2', ["--minimal-timestamp"]) + + assert client.get_storage(contract) == expected + + def test_step_constants(self, client, session): + contract = 'view_op_test_step_contants' + path = f'{CONTRACT_PATH}/opcodes/' + contract + '.tz' + originate(client, session, path, 'None', 0) + client.transfer( + 0, + 'bootstrap1', + contract, + [ + "--arg", + "\"" + session['lib'] + "\"", + '--gas-limit', + '5000', + "--burn-cap", + "0.1", + ], + ) + client.bake('bootstrap2', ["--minimal-timestamp"]) + + source = IDENTITIES['bootstrap1']['identity'] + self_address = session['lib'] + sender = session['contract'] + expected = ( + 'Some (Pair (Pair 0 999000000)\n' + + ' (Pair "' + + self_address + + '" "' + + sender + + '")\n' + + ' "' + + source + + '")' + ) + + assert client.get_storage(contract) == expected + + def test_recursion(self, client, session): + contract = 'view_rec' + path = f'{CONTRACT_PATH}/opcodes/' + contract + '.tz' + originate(client, session, path, 'Unit', 0) + with utils.assert_run_failure( + "Gas limit exceeded during typechecking or execution." + ): + client.transfer( + 0, + 'bootstrap1', + contract, + [ + "--arg", + "Unit", + '--gas-limit', + '5000', + ], + ) + client.bake('bootstrap2', ["--minimal-timestamp"]) + + @pytest.mark.parametrize( + "contract,expected_error", + [ + ( + 'view_toplevel_bad_type', + 'the return of a view block did not match the expected type.', + ), + ( + 'view_toplevel_bad_return_type', + 'the return of a view block did not match the expected type.', + ), + ( + 'view_toplevel_bad_input_type', + 'operator ADD is undefined between string', + ), + ( + 'view_toplevel_invalid_arity', + 'primitive view expects 4 arguments', + ), + ( + 'view_toplevel_bad_name_too_long', + 'exceeds the maximum length of 31 characters', + ), + ( + 'view_toplevel_bad_name_invalid_type', + 'only a string can be used here', + ), + ( + 'view_toplevel_bad_name_non_printable_char', + 'string \\[a-zA-Z0-9_.%@\\]', + ), + ( + 'view_toplevel_bad_name_invalid_char_set', + 'string \\[a-zA-Z0-9_.%@\\]', + ), + ( + 'view_toplevel_duplicated_name', + 'the name of view in toplevel should be unique', + ), + ( + 'view_toplevel_dupable_type_output', + 'Ticket in unauthorized position', + ), + ( + 'view_toplevel_dupable_type_input', + 'Ticket in unauthorized position', + ), + ( + 'view_toplevel_lazy_storage_input', + 'big_map or sapling_state type not expected here', + ), + ( + 'view_toplevel_lazy_storage_output', + 'big_map or sapling_state type not expected here', + ), + ('view_op_invalid_arity', 'primitive VIEW expects 2 arguments'), + ( + 'view_op_bad_name_invalid_type', + 'unexpected int, only a string', + ), + ( + 'view_op_bad_name_too_long', + 'exceeds the maximum length of 31 characters', + ), + ( + 'view_op_bad_name_non_printable_char', + 'string \\[a-zA-Z0-9_.%@\\]', + ), + ( + 'view_op_bad_name_invalid_char_set', + 'string \\[a-zA-Z0-9_.%@\\]', + ), + ( + 'view_op_bad_return_type', + 'two branches don\'t end with the same stack type', + ), + ( + 'view_op_dupable_type', + 'Ticket in unauthorized position', + ), + ( + 'view_op_lazy_storage', + 'big_map or sapling_state type not expected here', + ), + ], + ) + def test_typechecking_error( + self, client, session, contract, expected_error + ): + path = f'{CONTRACT_PATH}/ill_typed/' + contract + '.tz' + with utils.assert_run_failure(expected_error): + originate(client, session, path, '4', 0) + + +@pytest.mark.contract +class TestGasBound: + def test_write_contract(self, tmpdir, session: dict): + items = { + 'first_explosion.tz': FIRST_EXPLOSION, + 'first_explosion_bigtype.tz': FIRST_EXPLOSION_BIGTYPE, + 'second_explosion.tz': SECOND_EXPLOSION, + }.items() + for name, script in items: + contract = f'{tmpdir}/{name}' + with open(contract, 'w') as contract_file: + contract_file.write(script) + session[name] = contract + + def test_originate_first_explosion(self, client: Client, session: dict): + name = 'first_explosion.tz' + contract = session[name] + client.typecheck(contract) + args = ['-G', f'{1461}', '--burn-cap', '10'] + + expected_error = "Gas limit exceeded during typechecking or execution" + with utils.assert_run_failure(expected_error): + client.originate(f'{name}', 0, 'bootstrap1', contract, args) + + def test_originate_big_type(self, client: Client, session: dict): + name = 'first_explosion_bigtype.tz' + contract = session[name] + + expected_error = "type exceeded maximum type size" + with utils.assert_run_failure(expected_error): + client.typecheck(contract) + + def test_originate_second_explosion(self, client: Client, session: dict): + name = 'second_explosion.tz' + contract = session[name] + storage = '{}' + inp = '{1;2;3;4;5;6;7;8;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1}' + client.run_script(contract, storage, inp) + + def test_originate_second_explosion_fail( + self, client: Client, session: dict + ): + name = 'second_explosion.tz' + contract = session[name] + storage = '{}' + inp = ( + '{1;2;3;4;5;6;7;8;9;0;1;2;3;4;5;6;7;1;1;1;1;1;1;1;1;1;1;1' + + ';1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1}' + ) + + expected_error = ( + "Cannot serialize the resulting storage" + + " value within the provided gas bounds." + ) + with utils.assert_run_failure(expected_error): + client.run_script(contract, storage, inp, gas=9290) + + def test_typecheck_map_dup_key(self, client: Client): + + expected_error = ( + 'Map literals cannot contain duplicate' + + ' keys, however a duplicate key was found' + ) + with utils.assert_run_failure(expected_error): + client.typecheck_data('{ Elt 0 1 ; Elt 0 1}', '(map nat nat)') + + def test_typecheck_map_bad_ordering(self, client: Client): + + expected_error = ( + "Keys in a map literal must be in strictly" + + " ascending order, but they were unordered in literal" + ) + with utils.assert_run_failure(expected_error): + client.typecheck_data( + '{ Elt 0 1 ; Elt 10 1 ; Elt 5 1 }', '(map nat nat)' + ) + + def test_typecheck_set_bad_ordering(self, client: Client): + + expected_error = ( + "Values in a set literal must be in strictly" + + " ascending order, but they were unordered in literal" + ) + with utils.assert_run_failure(expected_error): + client.typecheck_data('{ "A" ; "C" ; "B" }', '(set string)') + + def test_typecheck_set_no_duplicates(self, client: Client): + expected_error = ( + "Set literals cannot contain duplicate values," + + " however a duplicate value was found" + ) + with utils.assert_run_failure(expected_error): + client.typecheck_data('{ "A" ; "B" ; "B" }', '(set string)') + + +@pytest.mark.incremental +@pytest.mark.contract +class TestChainId: + def test_chain_id_opcode(self, client: Client, session: dict): + path = os.path.join(CONTRACT_PATH, 'opcodes', 'chain_id.tz') + originate(client, session, path, 'Unit', 0) + client.call('bootstrap2', "chain_id", []) + utils.bake(client, 'bootstrap5') + + def test_chain_id_authentication_origination(self, client: Client, session): + path = os.path.join( + CONTRACT_PATH, 'mini_scenarios', 'authentication.tz' + ) + pubkey = IDENTITIES['bootstrap1']['public'] + originate(client, session, path, f'Pair 0 "{pubkey}"', 1000) + utils.bake(client, 'bootstrap5') + + def test_chain_id_authentication_first_run( + self, client: Client, session: dict + ): + destination = IDENTITIES['bootstrap2']['identity'] + operation = ( + '{DROP; NIL operation; ' + + f'PUSH address "{destination}"; ' + + 'CONTRACT unit; ASSERT_SOME; PUSH mutez 1000; UNIT; ' + + 'TRANSFER_TOKENS; CONS}' + ) + chain_id = client.rpc('get', 'chains/main/chain_id') + contract_address = session['contract'] + packed = client.pack( + f'Pair (Pair "{chain_id}" "{contract_address}") ' + + f'(Pair {operation} 0)', + 'pair (pair chain_id address)' + + '(pair (lambda unit (list operation)) nat)', + ) + signature = client.sign_bytes_of_string(packed, "bootstrap1") + client.call( + 'bootstrap2', + 'authentication', + ['--arg', f'Pair {operation} \"{signature}\"'], + ) + utils.bake(client, 'bootstrap5') + + +@pytest.mark.incremental +@pytest.mark.contract +class TestBigMapToSelf: + def test_big_map_to_self_origination(self, client: Client, session: dict): + path = os.path.join(CONTRACT_PATH, 'opcodes', 'big_map_to_self.tz') + originate(client, session, path, '{}', 0) + utils.bake(client, 'bootstrap5') + + def test_big_map_to_self_transfer(self, client: Client): + client.call('bootstrap2', "big_map_to_self", []) + utils.bake(client, 'bootstrap5') + + client.transfer(0, 'bootstrap2', "big_map_to_self", []) + utils.bake(client, 'bootstrap5') + + +@pytest.mark.incremental +@pytest.mark.contract +class TestNonRegression: + """Test contract-related non-regressions""" + + def test_issue_242_originate(self, client: Client, session: dict): + path = os.path.join(CONTRACT_PATH, 'non_regression', 'bug_262.tz') + originate(client, session, path, 'Unit', 1) + + def test_issue_242_assert_balance(self, client: Client): + assert client.get_balance('bug_262') == 1 + + +@pytest.mark.incremental +@pytest.mark.contract +class TestMiniScenarios: + """Test mini scenarios""" + + # replay.tz related tests + def test_replay_originate(self, client: Client, session: dict): + path = os.path.join(CONTRACT_PATH, 'mini_scenarios', 'replay.tz') + originate(client, session, path, 'Unit', 0) + + def test_replay_transfer_fail(self, client: Client): + with utils.assert_run_failure("Internal operation replay attempt"): + client.transfer(10, "bootstrap1", "replay", []) + + # create_contract.tz related tests + def test_create_contract_originate(self, client: Client, session: dict): + path = os.path.join( + CONTRACT_PATH, 'mini_scenarios', 'create_contract.tz' + ) + originate(client, session, path, 'Unit', 1000) + + def test_create_contract_balance(self, client: Client): + assert client.get_balance('create_contract') == 1000 + + def test_create_contract_perform_creation(self, client: Client): + transfer_result = client.transfer( + 0, + "bootstrap1", + "create_contract", + ['-arg', 'None', '--burn-cap', '10'], + ) + utils.bake(client, 'bootstrap5') + pattern = r"New contract (\w*) originated" + match = re.search(pattern, transfer_result.client_output) + assert match is not None + kt_1 = match.groups()[0] + assert client.get_storage(kt_1) == '"abcdefg"' + assert client.get_balance(kt_1) == 100 + assert client.get_balance('create_contract') == 900 + + # Originates a contract that when called, creates a contract with a + # rootname annotation. Such annotations comes in two flavors, thus the + # parameterization. Then calls the first contract and verifies the + # existence and type of the root entrypoint of the create contract. + @pytest.mark.parametrize( + "contract", + [ + 'create_contract_rootname.tz', + 'create_contract_rootname_alt.tz', + ], + ) + def test_create_contract_rootname_originate( + self, client: Client, session: dict, contract + ): + path = os.path.join(CONTRACT_PATH, 'opcodes', contract) + origination_res = originate(client, session, path, 'None', 1000) + + transfer_result = client.transfer( + 0, + "bootstrap1", + origination_res.contract, + ['-arg', 'Unit', '--burn-cap', '10'], + ) + utils.bake(client, 'bootstrap5') + + pattern = r"New contract (\w*) originated" + match = re.search(pattern, transfer_result.client_output) + assert match is not None + kt_1 = match.groups()[0] + + entrypoint_type = client.get_contract_entrypoint_type( + 'root', kt_1 + ).entrypoint_type + + assert entrypoint_type == 'unit', ( + 'the entrypoint my_root of the originated contract should exist' + 'with type unit' + ) + + # default_account.tz related tests + def test_default_account_originate(self, client: Client, session: dict): + path = os.path.join( + CONTRACT_PATH, 'mini_scenarios', 'default_account.tz' + ) + originate(client, session, path, 'Unit', 1000) + + def test_default_account_transfer_then_bake(self, client: Client): + tz1 = IDENTITIES['bootstrap4']['identity'] + client.transfer( + 0, + "bootstrap1", + "default_account", + ['-arg', f'"{tz1}"', '--burn-cap', '10'], + ) + utils.bake(client, 'bootstrap5') + account = 'tz1SuakBpFdG9b4twyfrSMqZzruxhpMeSrE5' + client.transfer( + 0, + "bootstrap1", + "default_account", + ['-arg', f'"{account}"', '--burn-cap', '10'], + ) + utils.bake(client, 'bootstrap5') + assert client.get_balance(account) == 100 + + # Test bytes, SHA252, CHECK_SIGNATURE + def test_reveal_signed_preimage_originate( + self, client: Client, session: dict + ): + path = os.path.join( + CONTRACT_PATH, 'mini_scenarios', 'reveal_signed_preimage.tz' + ) + byt = ( + '0x9995c2ef7bcc7ae3bd15bdd9b02' + + 'dc6e877c27b26732340d641a4cbc6524813bb' + ) + sign = 'p2pk66uq221795tFxT7jfNmXtBMdjMf6RAaxRTwv1dbuSHbH6yfqGwz' + storage = f'(Pair {byt} "{sign}")' + originate(client, session, path, storage, 1000) + + def test_wrong_preimage(self, client: Client): + byt = ( + '0x050100000027566f756c657a2d766f75732' + + '0636f75636865722061766563206d6f692c20636520736f6972' + ) + sign = ( + 'p2sigvgDSBnN1bUsfwyMvqpJA1cFhE5s5oi7SetJ' + + 'VQ6LJsbFrU2idPvnvwJhf5v9DhM9ZTX1euS9DgWozVw6BTHiK9VcQVpAU8' + ) + arg = f'(Pair {byt} "{sign}")' + + # We check failure of ASSERT_CMPEQ in the script. + with utils.assert_run_failure("At line 8 characters 9 to 21"): + client.transfer( + 0, + "bootstrap1", + "reveal_signed_preimage", + ['-arg', arg, '--burn-cap', '10'], + ) + + def test_wrong_signature(self, client: Client): + byt = ( + '0x050100000027566f756c657a2d766f757320636' + + 'f75636865722061766563206d6f692c20636520736f6972203f' + ) + sign = ( + 'p2sigvgDSBnN1bUsfwyMvqpJA1cFhE5s5oi7SetJVQ6' + + 'LJsbFrU2idPvnvwJhf5v9DhM9ZTX1euS9DgWozVw6BTHiK9VcQVpAU8' + ) + arg = f'(Pair {byt} "{sign}")' + + # We check failure of CHECK_SIGNATURE ; ASSERT in the script. + with utils.assert_run_failure("At line 15 characters 9 to 15"): + client.transfer( + 0, + "bootstrap1", + "reveal_signed_preimage", + ['-arg', arg, '--burn-cap', '10'], + ) + + def test_good_preimage_and_signature(self, client: Client): + byt = ( + '0x050100000027566f756c657a2d766f757320636f7563' + + '6865722061766563206d6f692c20636520736f6972203f' + ) + sign = ( + 'p2sigsceCzcDw2AeYDzUonj4JT341WC9Px4wdhHBxbZcG1F' + + 'hfqFVuG7f2fGCzrEHSAZgrsrQWpxduDPk9qZRgrpzwJnSHC3gZJ' + ) + arg = f'(Pair {byt} "{sign}")' + client.transfer( + 0, + "bootstrap1", + "reveal_signed_preimage", + ['-arg', arg, '--burn-cap', '10'], + ) + utils.bake(client, 'bootstrap5') + + # Test vote_for_delegate + def test_vote_for_delegate_originate(self, client: Client, session: dict): + b_3 = IDENTITIES['bootstrap3']['identity'] + b_4 = IDENTITIES['bootstrap4']['identity'] + path = os.path.join( + CONTRACT_PATH, 'mini_scenarios', 'vote_for_delegate.tz' + ) + storage = f'''(Pair (Pair "{b_3}" None) (Pair "{b_4}" None))''' + originate(client, session, path, storage, 1000) + assert client.get_delegate('vote_for_delegate').delegate is None + + def test_vote_for_delegate_wrong_identity1(self, client: Client): + # We check failure of CHECK_SIGNATURE ; ASSERT in the script. + with utils.assert_run_failure("At line 15 characters 57 to 61"): + client.transfer( + 0, + "bootstrap1", + "vote_for_delegate", + ['-arg', 'None', '--burn-cap', '10'], + ) + + def test_vote_for_delegate_wrong_identity2(self, client: Client): + # We check failure of CHECK_SIGNATURE ; ASSERT in the script. + with utils.assert_run_failure("At line 15 characters 57 to 61"): + client.transfer( + 0, + "bootstrap2", + "vote_for_delegate", + ['-arg', 'None', '--burn-cap', '10'], + ) + + def test_vote_for_delegate_b3_vote_for_b5(self, client: Client): + b_5 = IDENTITIES['bootstrap5']['identity'] + client.transfer( + 0, + "bootstrap3", + "vote_for_delegate", + ['-arg', f'(Some "{b_5}")', '--burn-cap', '10'], + ) + utils.bake(client, 'bootstrap5') + storage = client.get_storage('vote_for_delegate') + assert re.search(b_5, storage) + + def test_vote_for_delegate_still_no_delegate1(self, client: Client): + assert client.get_delegate('vote_for_delegate').delegate is None + + def test_vote_for_delegate_b4_vote_for_b2(self, client: Client): + b_2 = IDENTITIES['bootstrap2']['identity'] + client.transfer( + 0, + "bootstrap4", + "vote_for_delegate", + ['-arg', f'(Some "{b_2}")', '--burn-cap', '10'], + ) + utils.bake(client, 'bootstrap5') + storage = client.get_storage('vote_for_delegate') + assert re.search(b_2, storage) + + def test_vote_for_delegate_still_no_delegate2(self, client: Client): + assert client.get_delegate('vote_for_delegate').delegate is None + + def test_vote_for_delegate_b4_vote_for_b5(self, client: Client): + b_5 = IDENTITIES['bootstrap5']['identity'] + client.transfer( + 0, + "bootstrap4", + "vote_for_delegate", + ['-arg', f'(Some "{b_5}")', '--burn-cap', '10'], + ) + utils.bake(client, 'bootstrap5') + storage = client.get_storage('vote_for_delegate') + assert re.search(b_5, storage) + + def test_vote_for_delegate_has_delegate(self, client: Client): + b_5 = IDENTITIES['bootstrap5']['identity'] + result = client.get_delegate('vote_for_delegate') + assert result.delegate == b_5 + + def test_multiple_entrypoints_counter(self, session: dict, client: Client): + path = os.path.join( + CONTRACT_PATH, 'mini_scenarios', 'multiple_entrypoints_counter.tz' + ) + + storage = 'None' + + # originate contract + originate(client, session, path, storage, 0) + utils.bake(client, 'bootstrap5') + + # call contract: creates the internal contract and calls it. + client.transfer( + 0, + 'bootstrap1', + 'multiple_entrypoints_counter', + ['--burn-cap', '10'], + ) + utils.bake(client, 'bootstrap5') + assert client.get_storage('multiple_entrypoints_counter') == 'None', ( + "The storage of the multiple_entrypoints_counter contract" + " should be None" + ) + + # Test CONTRACT with/without entrypoint annotation on literal address + # parameters with/without entrypoint annotation + def test_originate_simple_entrypoints(self, session: dict, client: Client): + """originates the contract simple_entrypoints.tz + with entrypoint %A of type unit used in + test_simple_entrypoints""" + + contract_target = os.path.join( + CONTRACT_PATH, 'entrypoints', 'simple_entrypoints.tz' + ) + originate(client, session, contract_target, 'Unit', 0) + utils.bake(client, 'bootstrap5') + + @pytest.mark.parametrize( + 'contract_annotation, contract_type, param, expected_storage', + [ + # tests passing adr to CONTRACT %A unit + # where adr has an entrypoint %A of type unit, is allowed. + ('%A', 'unit', '"{adr}"', '(Some "{adr}%A")'), + ('%B', 'string', '"{adr}"', '(Some "{adr}%B")'), + ('%C', 'nat', '"{adr}"', '(Some "{adr}%C")'), + # tests passing adr%A to CONTRACT %A unit: redundant specification + # of entrypoint not allowed so CONTRACT returns None + ('%A', 'unit', '"{adr}%A"', 'None'), + ('%A', 'unit', '"{adr}%B"', 'None'), + ('%A', 'unit', '"{adr}%D"', 'None'), + ('%A', 'unit', '"{adr}%A"', 'None'), + ('%B', 'unit', '"{adr}%A"', 'None'), + ('%D', 'unit', '"{adr}%A"', 'None'), + # tests passing adr%A to CONTRACT unit: + # where adr has an entrypoint %A of type unit, is allowed. + ('', 'unit', '"{adr}%A"', '(Some "{adr}%A")'), + ('', 'string', '"{adr}%B"', '(Some "{adr}%B")'), + ('', 'nat', '"{adr}%C"', '(Some "{adr}%C")'), + # tests passing adr%B to CONTRACT unit: + # as entrypoint %B of simple_entrypoints.tz has type string, + # CONTRACT will return None. + ('', 'unit', '"{adr}%B"', 'None'), + # tests passing adr%D to CONTRACT unit: + # as entrypoint %D does not exist in simple_entrypoints.tz, + # CONTRACT will return None. + ('', 'unit', '"{adr}%D"', 'None'), + # tests passing adr to CONTRACT unit: + # as adr does not have type unit, CONTRACT returns None. + ('', 'unit', '"{adr}"', 'None'), + # entrypoint that does not exist + ('%D', 'unit', '"{adr}"', 'None'), + # ill-typed entrypoints + ('%A', 'int', '"{adr}"', 'None'), + ('%B', 'unit', '"{adr}"', 'None'), + ('%C', 'int', '"{adr}"', 'None'), + ], + ) + def test_simple_entrypoints( + self, + session, + client, + contract_annotation, + contract_type, + param, + expected_storage, + ): + contract = f'''parameter address; +storage (option address); +code {{ + CAR; + CONTRACT {contract_annotation} {contract_type}; + IF_SOME {{ ADDRESS; SOME }} {{ NONE address; }}; + NIL operation; + PAIR + }};''' + + param = param.format(adr=session['contract']) + expected_storage = expected_storage.format(adr=session['contract']) + run_script_res = client.run_script(contract, 'None', param, file=False) + assert run_script_res.storage == expected_storage + + +@pytest.mark.contract +class TestComparables: + def test_comparable_unit(self, client): + client.typecheck_data('{}', '(set unit)') + client.typecheck_data('{Unit}', '(set unit)') + + def test_comparable_options(self, client): + client.typecheck_data('{}', '(set (option nat))') + client.typecheck_data('{None; Some 1; Some 2}', '(set (option int))') + utils.assert_typecheck_data_failure( + client, '{Some "foo"; Some "bar"}', '(set (option string))' + ) + utils.assert_typecheck_data_failure( + client, '{Some Unit; None}', '(set (option unit))' + ) + + def test_comparable_unions(self, client): + client.typecheck_data('{}', '(set (or unit bool))') + client.typecheck_data( + '{Left 3; Left 4; Right "bar"; Right "foo"}', + '(set (or nat string))', + ) + utils.assert_typecheck_data_failure( + client, '{Left 2; Left 1}', '(set (or mutez unit))' + ) + utils.assert_typecheck_data_failure( + client, '{Right True; Right False}', '(set (or unit bool))' + ) + utils.assert_typecheck_data_failure( + client, '{Right 0; Left 1}', '(set (or nat nat))' + ) + + def test_comparable_pair(self, client: Client): + # tests that comb pairs are comparable and that the order is the + # expected one + client.typecheck_data('{}', '(set (pair nat string))') + client.typecheck_data('{Pair 0 "foo"}', '(set (pair nat string))') + client.typecheck_data( + '{Pair 0 "foo"; Pair 1 "bar"}', '(set (pair nat string))' + ) + client.typecheck_data( + '{Pair 0 "bar"; Pair 0 "foo"; \ + Pair 1 "bar"; Pair 1 "foo"}', + '(set (pair nat string))', + ) + client.typecheck_data('{}', '(set (pair nat (pair string bytes)))') + + client.typecheck_data('{}', '(map (pair nat string) unit)') + client.typecheck_data( + '{Elt (Pair 0 "foo") Unit}', '(map (pair nat string) unit)' + ) + client.typecheck_data( + '{Elt (Pair 0 "foo") Unit; \ + Elt (Pair 1 "bar") Unit}', + '(map (pair nat string) unit)', + ) + client.typecheck_data( + '{Elt (Pair 0 "bar") Unit; \ + Elt (Pair 0 "foo") Unit; \ + Elt (Pair 1 "bar") Unit; \ + Elt (Pair 1 "foo") Unit}', + '(map (pair nat string) unit)', + ) + client.typecheck_data('{}', '(map (pair nat (pair string bytes)) unit)') + + client.typecheck_data('{}', '(big_map (pair nat string) unit)') + client.typecheck_data( + '{Elt (Pair 0 "foo") Unit}', '(big_map (pair nat string) unit)' + ) + client.typecheck_data( + '{Elt (Pair 0 "foo") Unit; \ + Elt (Pair 1 "bar") Unit}', + '(big_map (pair nat string) unit)', + ) + client.typecheck_data( + '{Elt (Pair 0 "bar") Unit; \ + Elt (Pair 0 "foo") Unit; \ + Elt (Pair 1 "bar") Unit; \ + Elt (Pair 1 "foo") Unit}', + '(big_map (pair nat string) unit)', + ) + client.typecheck_data( + '{}', '(big_map (pair nat (pair string bytes)) unit)' + ) + client.typecheck_data('{}', '(set (pair (pair nat nat) nat))') + client.typecheck_data( + '{}', + '(set (pair (pair int nat) \ + (pair bool bytes)))', + ) + + def test_order_of_pairs(self, client: Client): + # tests that badly-ordered set literals are rejected + utils.assert_typecheck_data_failure( + client, '{Pair 0 "foo"; Pair 0 "bar"}', '(set (pair nat string))' + ) + utils.assert_typecheck_data_failure( + client, '{Pair 1 "bar"; Pair 0 "foo"}', '(set (pair nat string))' + ) + + def test_comparable_chain_id(self, client): + client.typecheck_data('{}', '(set chain_id)') + chain1 = client.rpc('get', 'chains/main/chain_id') + chain2 = 'NetXZVhNXbDTx5M' + utils.assert_typecheck_data_failure( + client, + '{"' + f'{chain1}' + '"; "' + f'{chain2}' + '"}', + '(set chain_id)', + ) + client.typecheck_data( + '{"' + f'{chain2}' + '"; "' + f'{chain1}' + '"}', '(set chain_id)' + ) + + def test_comparable_signature(self, client): + client.typecheck_data('{}', '(set signature)') + packed = client.pack('Unit', 'unit') + sig1 = client.sign_bytes_of_string(packed, "bootstrap1") + sig2 = client.sign_bytes_of_string(packed, "bootstrap2") + utils.assert_typecheck_data_failure( + client, + '{"' + f'{sig1}' + '"; "' + f'{sig2}' + '"}', + '(set signature)', + ) + client.typecheck_data( + '{"' + f'{sig2}' + '"; "' + f'{sig1}' + '"}', '(set signature)' + ) + + def test_comparable_key(self, client): + pubkey1 = IDENTITIES['bootstrap1']['public'] + pubkey2 = IDENTITIES['bootstrap2']['public'] + client.typecheck_data('{}', '(set key)') + utils.assert_typecheck_data_failure( + client, + '{"' + f'{pubkey1}' + '"; "' + f'{pubkey2}' + '"}', + '(set key)', + ) + client.typecheck_data( + '{"' + f'{pubkey2}' + '"; "' + f'{pubkey1}' + '"}', '(set key)' + ) + + def test_comparable_key_different_schemes(self, client): + client.gen_key('sk1', ['--sig', 'ed25519']) + key1 = client.show_address('sk1').public_key + + client.gen_key('sk2', ['--sig', 'secp256k1']) + key2 = client.show_address('sk2').public_key + + client.gen_key('sk3', ['--sig', 'p256']) + key3 = client.show_address('sk3').public_key + + # Three public keys of the three different signature schemes, ordered + client.typecheck_data( + '{"' + key1 + '"; "' + key2 + '"; "' + key3 + '"}', '(set key)' + ) + + # Test all orderings that do not respect the comparable order + utils.assert_typecheck_data_failure( + client, + '{"' + key1 + '"; "' + key3 + '"; "' + key2 + '"}', + '(set key)', + ) + + utils.assert_typecheck_data_failure( + client, + '{"' + key2 + '"; "' + key1 + '"; "' + key3 + '"}', + '(set key)', + ) + + utils.assert_typecheck_data_failure( + client, + '{"' + key2 + '"; "' + key3 + '"; "' + key1 + '"}', + '(set key)', + ) + + utils.assert_typecheck_data_failure( + client, + '{"' + key3 + '"; "' + key1 + '"; "' + key2 + '"}', + '(set key)', + ) + + utils.assert_typecheck_data_failure( + client, + '{"' + key3 + '"; "' + key2 + '"; "' + key1 + '"}', + '(set key)', + ) + + +@pytest.mark.contract +class TestTypecheckingErrors: + def test_big_map_arity_error(self, client: Client): + error_pattern = ( + 'primitive EMPTY_BIG_MAP expects 2 arguments but is given 1.' + ) + with utils.assert_run_failure(error_pattern): + client.typecheck( + os.path.join(CONTRACT_PATH, 'ill_typed', 'big_map_arity.tz') + ) + + +BAD_ANNOT_TEST = ''' +parameter bytes; +storage (option (lambda unit unit)); +code { CAR; UNPACK (lambda unit unit); NIL operation; PAIR} +''' + + +@pytest.mark.incremental +@pytest.mark.contract +class TestBadAnnotation: + def test_write_contract_bad_annot(self, tmpdir, session: dict): + name = 'bad_annot.tz' + contract = f'{tmpdir}/{name}' + script = BAD_ANNOT_TEST + with open(contract, 'w') as contract_file: + contract_file.write(script) + session[name] = contract + + def test_bad_annotation(self, client: Client, session: dict): + name = 'bad_annot.tz' + contract = session[name] + + # This was produced by running "tezos-client hash data '{ UNIT + # ; PAIR ; CAR %faa }' of type 'lambda unit unit'" and + # replacing the two last bytes (that correspond to the two + # 'a's at the end of the annotation) by the 0xff byte which is + # not a valid UTF8-encoding of a string + parameter = '0x05020000000e034f03420416000000042566ffff' + + res = client.run_script(contract, 'None', parameter) + assert res.storage == 'None' + + +@pytest.mark.contract +class TestOrderInTopLevelDoesNotMatter: + @pytest.fixture + def contract_splitted_in_top_level_elements(self): + return [ + "parameter nat", + "storage unit", + "code { CDR; NIL operation; PAIR }", + ] + + def test_shuffle( + self, client: Client, contract_splitted_in_top_level_elements + ): + """ + Test that the storage, code, and parameter sections can appear in any + order in a contract script. + """ + for shuffled_list in itertools.permutations( + contract_splitted_in_top_level_elements + ): + contract = ";\n".join(shuffled_list) + client.typecheck(contract, file=False) + + +@pytest.mark.incremental +@pytest.mark.contract +@pytest.mark.regression +class TestSelfAddressTransfer: + def test_self_address_originate_sender( + self, client_regtest_scrubbed, session + ): + client = client_regtest_scrubbed + path = os.path.join( + CONTRACT_PATH, 'mini_scenarios', 'self_address_sender.tz' + ) + originate(client, session, path, 'Unit', 0) + + def test_self_address_originate_receiver( + self, client_regtest_scrubbed, session + ): + client = client_regtest_scrubbed + path = os.path.join( + CONTRACT_PATH, 'mini_scenarios', 'self_address_receiver.tz' + ) + originate(client, session, path, 'Unit', 0) + session['receiver_address'] = session['contract'] + + def test_send_self_address(self, client_regtest_scrubbed, session): + client = client_regtest_scrubbed + receiver_address = session['receiver_address'] + client.transfer( + 0, + 'bootstrap2', + 'self_address_sender', + ['--arg', f'"{receiver_address}"', '--burn-cap', '2'], + ) + utils.bake(client, 'bootstrap5') + + +@pytest.mark.slow +@pytest.mark.contract +@pytest.mark.regression +class TestScriptHashRegression: + @pytest.mark.parametrize( + "client_regtest_custom_scrubber", + [[(re.escape(CONTRACT_PATH), '[CONTRACT_PATH]')]], + indirect=True, + ) + def test_contract_hash(self, client_regtest_custom_scrubber: Client): + client = client_regtest_custom_scrubber + contracts = all_contracts() + contracts.sort() + for contract in contracts: + assert contract.endswith( + '.tz' + ), "test contract should have .tz extension" + + client.hash_script( + [os.path.join(CONTRACT_PATH, contract) for contract in contracts], + display_names=True, + ) + + +@pytest.mark.contract +class TestScriptHashOrigination: + def test_contract_hash_with_origination( + self, client: Client, session: dict + ): + script = ID_SCRIPT_LITERAL + originate( + client, + session, + contract=script, + init_storage='Unit', + amount=1000, + contract_name='dummy_contract', + ) + [(hash1, _)] = client.hash_script([script]) + hash2 = client.get_script_hash('dummy_contract') + assert hash1 == hash2 + + +@pytest.mark.contract +class TestScriptHashMultiple: + """Test tezos-client hash script with diffent number and type of + arguments""" + + def test_contract_hashes_empty(self, client: Client): + assert client.hash_script([]) == [] + + def test_contract_hashes_single(self, client: Client): + assert client.hash_script([ID_SCRIPT_LITERAL]) == [ + (ID_SCRIPT_HASH, None) + ] + + def test_contract_hashes_single_display_names(self, client: Client): + assert client.hash_script([ID_SCRIPT_LITERAL], display_names=True,) == [ + ( + ID_SCRIPT_HASH, + 'Literal script 1', + ) + ] + + def test_contract_hashes_mixed(self, client: Client): + contract_path = os.path.join(CONTRACT_PATH, 'attic', 'empty.tz') + script_empty_hash = ''' +expruat2BS4KCwn9kbopeX1ZwxtrtJbyFhpnpnG6A5KdCBCwHNsdod + '''.strip() + with open(contract_path, 'r') as contract_file: + script = contract_file.read() + + hashes = client.hash_script([contract_path, script]) + + assert hashes == [ + ( + script_empty_hash, + None, + ), + ( + script_empty_hash, + None, + ), + ] + + hashes = client.hash_script( + [contract_path, script], display_names=True + ) + + assert hashes == [ + ( + script_empty_hash, + contract_path, + ), + ( + script_empty_hash, + 'Literal script 2', + ), + ] + + @pytest.mark.parametrize( + "for_script, display_names, results", + [ + ('csv', True, (ID_SCRIPT_HASH, 'Literal script 1')), + ('csv', False, (ID_SCRIPT_HASH, None)), + ('tsv', True, (ID_SCRIPT_HASH, 'Literal script 1')), + ('tsv', False, (ID_SCRIPT_HASH, None)), + ], + ) + def test_contract_hashes_for_script( + self, client: Client, for_script, display_names, results + ): + assert ( + client.hash_script( + [ID_SCRIPT_LITERAL], + display_names=display_names, + for_script=for_script, + ) + == [results] + ) + + +@pytest.mark.contract +@pytest.mark.regression +class TestNormalize: + """Regression tests for the "normalize data" command.""" + + modes = [None, 'Readable', 'Optimized', 'Optimized_legacy'] + + @pytest.mark.parametrize('mode', modes) + def test_normalize_unparsing_mode(self, client_regtest_scrubbed, mode): + client = client_regtest_scrubbed + input_data = ( + '{Pair 0 3 6 9; Pair 1 (Pair 4 (Pair 7 10)); {2; 5; 8; 11}}' + ) + input_type = 'list (pair nat nat nat nat)' + client.normalize(input_data, input_type, mode=mode) + + def test_normalize_legacy_flag(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + input_data = '{Elt %a 0 1}' + input_type = 'map nat nat' + client.normalize(input_data, input_type, legacy=True) + error_pattern = 'unexpected annotation.' + with utils.assert_run_failure(error_pattern): + client.normalize(input_data, input_type, legacy=False) + + @pytest.mark.parametrize('mode', modes) + def test_normalize_script(self, client_regtest_scrubbed, mode): + client = client_regtest_scrubbed + path = os.path.join(CONTRACT_PATH, 'opcodes', 'comb-literals.tz') + client.normalize_script(path, mode=mode) + + types = [ + 'nat', + 'list nat', + 'pair nat int', + 'list (pair nat int)', + 'pair nat int bool', + 'list (pair nat int bool)', + 'pair nat int bool bytes', + 'list (pair nat int bool bytes)', + ] + + @pytest.mark.parametrize('typ', types) + def test_normalize_type(self, client_regtest_scrubbed, typ): + client = client_regtest_scrubbed + client.normalize_type(typ) + + +@pytest.mark.contract +class TestTZIP4View: + """Tests for the "run tzip4 view" command.""" + + def test_run_view(self, client: Client, session: dict): + + path = os.path.join(CONTRACT_PATH, 'mini_scenarios', 'tzip4_view.tz') + originate( + client, + session, + contract=path, + init_storage='Unit', + amount=1000, + contract_name='view_contract', + ) + client.bake('bootstrap5') + + const_view_res = client.run_view( + "view_const", "view_contract", "Unit", [] + ) + add_view_res = client.run_view( + "view_add", "view_contract", "Pair 1 3", [] + ) + + assert const_view_res.result == "5\n" and add_view_res.result == "4\n" + + +@pytest.mark.contract +@pytest.mark.incremental +class TestBadIndentation: + """Tests for the "hash script" and "convert script" commands on + badly-indented scripts.""" + + BADLY_INDENTED = os.path.join(ILLTYPED_CONTRACT_PATH, 'badly_indented.tz') + + SCRIPT_HASH = "exprv8K6ceBpFH5SFjQm4BRYSLJCHQBFeQU6BFTdvQSRPaPkzdLyAL" + + def test_bad_indentation_ill_typed(self, client): + with utils.assert_run_failure('syntax error in program'): + client.typecheck(self.BADLY_INDENTED) + + def test_bad_indentation_hash(self, client): + assert client.hash_script([self.BADLY_INDENTED]) == [ + (self.SCRIPT_HASH, None) + ] + + def test_formatting(self, client, session): + session['formatted_script'] = client.convert_script( + self.BADLY_INDENTED, 'Michelson', 'Michelson' + ) + + def test_formatted_hash(self, client, session): + assert client.hash_script([session['formatted_script']]) == [ + (self.SCRIPT_HASH, None) + ] + + def test_formatted_typechecks(self, client, session): + client.typecheck(session['formatted_script'], file=False) + + +@pytest.mark.contract +@pytest.mark.incremental +class TestContractTypeChecking: + """Typechecking tests for the address and (contract _) types.""" + + def check_address(self, client, address): + """An address followed by an entrypoint typechecks at type address if + and only if the entrypoint is not "default".""" + + address_a = f'"{address}%a"' + address_opt = client.normalize( + f'"{address}"', 'address', 'Optimized' + ).strip() + address_opt_a = client.normalize( + address_a, 'address', 'Optimized' + ).strip() + + client.typecheck_data(f'"{address}"', 'address') + client.typecheck_data(f'{address_a}', 'address') + client.typecheck_data(f'{address_opt}', 'address') + client.typecheck_data(f'{address_opt_a}', 'address') + + unexpected_annotation_error = "unexpected annotation." + + with utils.assert_run_failure(unexpected_annotation_error): + client.typecheck_data(f'"{address}%default"', 'address') + + # 64656661756c74 is "default" in hexa + with utils.assert_run_failure(unexpected_annotation_error): + client.typecheck_data(address_opt + '64656661756c74', 'address') + + def check_contract_ok(self, client, address, entrypoint, typ): + """Helper to check that an address followed by an entrypoint typechecks + at type (contract typ) using both readable and optimised + representations.""" + + address_readable = f'"{address}"' + if entrypoint is not None: + address_readable = f'"{address}%{entrypoint}"' + + address_opt = client.normalize( + address_readable, 'address', 'Optimized' + ).strip() + + client.typecheck_data(address_readable, f'contract ({typ})') + client.typecheck_data(address_opt, f'contract ({typ})') + + client.run_script( + f""" +parameter unit; +storage address; +code {{ + CDR; + CONTRACT ({typ}); + ASSERT_SOME; + ADDRESS; + NIL operation; + PAIR }}""", + address_readable, + 'Unit', + file=False, + ) + + def check_contract_ko( + self, client, address, entrypoint, typ, expected_error + ): + """Helper to check that an address followed by an entrypoint does not + typecheck at type (contract typ) using both readable and optimised + representations.""" + + address_readable = f'"{address}"' + if entrypoint is not None: + address_readable = f'"{address}%{entrypoint}"' + + address_opt = client.normalize( + address_readable, 'address', 'Optimized' + ).strip() + + with utils.assert_run_failure(expected_error): + client.typecheck_data(address_readable, f'contract ({typ})') + with utils.assert_run_failure(expected_error): + client.typecheck_data(address_opt, f'contract ({typ})') + + client.run_script( + f""" +parameter unit; +storage address; +code {{ + CDR; + DUP; + CONTRACT ({typ}); + ASSERT_NONE; + NIL operation; + PAIR }}""", + address_readable, + 'Unit', + file=False, + ) + + def test_implicit(self, client): + """The address of an implicit account followed by some entrypoint + typechecks: + - at type address if the entrypoint is not "default", + - at type (contract ) if the entrypoint is empty and ty is unit.""" + + tz1 = 'tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx' + + self.check_address(client, tz1) + self.check_contract_ok(client, tz1, None, 'unit') + + no_entrypoint_error = 'Contract has no entrypoint named a' + type_mismatch_error = 'Type nat is not compatible with type unit.' + self.check_contract_ko(client, tz1, 'a', 'unit', no_entrypoint_error) + self.check_contract_ko(client, tz1, 'a', 'nat', no_entrypoint_error) + self.check_contract_ko(client, tz1, None, 'nat', type_mismatch_error) + + def test_originated_inexistent(self, client): + """The address of an inexistent originated account followed by some + entrypoint typechecks: + - at type address if the entrypoint is not "default", + - at no (contract _) type.""" + + kt1 = 'KT1RvwLgpxVv9ANCKsDb5vBgTaZRG1W4bKWP' + + self.check_address(client, kt1) + + invalid_contract_error = 'invalid contract.' + self.check_contract_ko( + client, kt1, None, 'unit', invalid_contract_error + ) + self.check_contract_ko(client, kt1, 'a', 'unit', invalid_contract_error) + self.check_contract_ko(client, kt1, None, 'nat', invalid_contract_error) + self.check_contract_ko(client, kt1, 'a', 'nat', invalid_contract_error) + + def test_originated_no_default(self, client, session): + """The address of an existent originated account that does not specify + a default entrypoint followed by some entrypoint typechecks: + - at type address if the entrypoint is not "default", + - at type (contract ) if + - the entrypoint is empty and is the root type + - the entrypoint is non-empty, one of the declared entrypoints, and + is the type associated to that entrypoint.""" + + path = os.path.join( + CONTRACT_PATH, 'entrypoints', 'simple_entrypoints.tz' + ) + origination = originate(client, session, path, 'Unit', 0) + kt1 = origination.contract + root_type = 'or (unit %A) (or (string %B) (nat %C))' + a_type = 'unit' + b_type = 'string' + + self.check_address(client, kt1) + self.check_contract_ok(client, kt1, None, root_type) + self.check_contract_ok(client, kt1, 'A', a_type) + self.check_contract_ok(client, kt1, 'B', b_type) + + no_entrypoint_error = 'Contract has no entrypoint named a' + self.check_contract_ko(client, kt1, 'a', a_type, no_entrypoint_error) + + def test_originated_with_default(self, client, session): + """The address of an existent originated account that specifies + a default entrypoint followed by some entrypoint typechecks: + - at type address if the entrypoint is not "default", + - at type (contract ) if + - the entrypoint is empty and is the type of the default + entrypoint + - the entrypoint is non-empty, one of the declared entrypoints, and + is the type associated to that entrypoint.""" + + path = os.path.join( + CONTRACT_PATH, 'entrypoints', 'delegatable_target.tz' + ) + initial_storage = 'Pair "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" "" 0' + origination = originate(client, session, path, initial_storage, 0) + kt1 = origination.contract + root_type = ( + 'or (or (key_hash %set_delegate) (unit %remove_delegate))' + '(or %default string nat)' + ) + default_type = 'or string nat' + + self.check_address(client, kt1) + self.check_contract_ok(client, kt1, None, default_type) + self.check_contract_ok(client, kt1, 'set_delegate', 'key_hash') + + no_entrypoint_error = 'Contract has no entrypoint named a' + self.check_contract_ko(client, kt1, 'a', root_type, no_entrypoint_error) + + type_mismatch_error = 'is not compatible with type' + self.check_contract_ko( + client, kt1, None, root_type, type_mismatch_error + ) diff --git a/tests_python/tests_011/test_contract_annotations.py b/tests_python/tests_011/test_contract_annotations.py new file mode 100644 index 000000000000..c34dcc016ee1 --- /dev/null +++ b/tests_python/tests_011/test_contract_annotations.py @@ -0,0 +1,88 @@ +import pytest +from tools.utils import assert_typecheck_data_failure, assert_typecheck_failure +from client.client import Client + + +@pytest.mark.slow +@pytest.mark.contract +class TestAnnotations: + """Tests of Michelson annotations.""" + + def test_annotation_length_success(self, client: Client): + client.typecheck_data('3', f"(int :{'a' * 254})") + + def test_annotation_length_failure(self, client: Client): + assert_typecheck_data_failure( + client, + '3', + f"(int :{'a' * 255})", + r'annotation exceeded maximum length \(255 chars\)', + ) + + def test_field_annotation_in_type_alphabetic(self, client): + client.typecheck_data('Pair 0 0', 'pair (nat %x) (int %y)') + + def test_field_annotation_in_type_numeral(self, client): + client.typecheck_data('Pair 0 0', 'pair (nat %1) (int %2)') + + def test_field_annotation_in_type_invalid_character(self, client): + assert_typecheck_data_failure( + client, + 'Pair 0 0', + 'pair (nat %.) (int %.)', + 'unexpected annotation', + ) + + def test_field_annotation_in_instruction_alphabetic(self, client): + client.typecheck_data( + '{ CAR %x }', 'lambda (pair (nat %x) (int %y)) nat' + ) + + def test_field_annotation_in_instruction_numeral(self, client): + client.typecheck_data( + '{ CAR %1 }', 'lambda (pair (nat %1) (int %2)) nat' + ) + + def test_field_annotation_in_instruction_invalid_character(self, client): + assert_typecheck_data_failure( + client, + '{ CAR %. }', + 'lambda (pair (nat %.) (int %.)) nat', + 'unexpected annotation', + ) + + def test_field_annotation_in_root_alphabetic(self, client): + client.typecheck( + 'parameter %r unit; storage unit; code {FAILWITH}', file=False + ) + + def test_field_annotation_in_root_numeral(self, client): + client.typecheck( + 'parameter %1 unit; storage unit; code {FAILWITH}', file=False + ) + + def test_field_annotation_in_root_invalid_character(self, client): + assert_typecheck_failure( + client, + 'parameter %. unit; storage unit; code {FAILWITH}', + 'unexpected annotation', + file=False, + ) + + def test_field_annotation_in_root_type_alphabetic(self, client): + client.typecheck( + 'parameter (unit %r); storage unit; code {FAILWITH}', file=False + ) + + def test_field_annotation_in_root_type_numeral(self, client): + client.typecheck( + 'parameter (unit %1); storage unit; code {FAILWITH}', file=False + ) + + def test_field_annotation_in_root_type_invalid_character(self, client): + assert_typecheck_failure( + client, + 'parameter (unit %.); storage unit; code {FAILWITH}', + 'unexpected annotation', + file=False, + ) diff --git a/tests_python/tests_011/test_contract_baker.py b/tests_python/tests_011/test_contract_baker.py new file mode 100644 index 000000000000..8d925d4552e5 --- /dev/null +++ b/tests_python/tests_011/test_contract_baker.py @@ -0,0 +1,52 @@ +import os +import pytest +from tools import utils +from client.client import Client +from . import contract_paths + + +@pytest.mark.contract +@pytest.mark.baker +@pytest.mark.incremental +class TestOriginationCall: + """Test a simple contract origination and call""" + + def test_originate(self, client: Client, session: dict): + initial_storage = 'Unit' + contract = os.path.join( + contract_paths.OPCODES_CONTRACT_PATH, 'transfer_tokens.tz' + ) + args = ['--init', initial_storage, '--burn-cap', '0.400'] + origination = client.originate( + 'foobar', 1000, 'bootstrap1', contract, args + ) + session['contract'] = origination.contract + utils.bake(client, 'bootstrap5') + + # Unsolved mystery: + # client.wait_for_inclusion(origination.operation_hash) + # fails sometimes with tezos-client crashing. Maybe caused with + # subprocess captured of forked process output? + # + # Safer to poll with `check_block_contain_operations` + assert utils.check_block_contains_operations( + client, [origination.operation_hash] + ) + + def test_call(self, client: Client, session: dict): + contract = session['contract'] + bootstrap3 = '"tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU"' + transfer = client.call('bootstrap2', contract, ['--arg', bootstrap3]) + utils.bake(client, 'bootstrap5') + assert utils.check_block_contains_operations( + client, [transfer.operation_hash] + ) + + def test_balance(self, client: Client): + assert client.get_balance("bootstrap3") == 4000100 + + def test_query_storage(self, client: Client, session: dict): + contract = session['contract'] + url = f'/chains/main/blocks/head/context/contracts/{contract}/storage' + res = client.rpc('get', url) + assert res['prim'] == 'Unit' diff --git a/tests_python/tests_011/test_contract_bls12_381.py b/tests_python/tests_011/test_contract_bls12_381.py new file mode 100644 index 000000000000..efdd739421fa --- /dev/null +++ b/tests_python/tests_011/test_contract_bls12_381.py @@ -0,0 +1,315 @@ +from os import path +import random +from hashlib import blake2b +import pytest + +from tools.bls12_381 import G1, G2, Fr, pairing_check +from tools.utils import assert_run_failure +from .contract_paths import MINI_SCENARIOS_CONTRACT_PATH, OPCODES_CONTRACT_PATH + + +def check_contract(client, contract_name, arg, expected_storage): + contract_path = path.join(OPCODES_CONTRACT_PATH, f'{contract_name}.tz') + result = client.run_script(contract_path, 'None', arg) + assert result.storage == f'(Some {expected_storage})' + + +def check_contract_binop(client, contract_name, arg0, arg1, expected_storage): + check_contract( + client, contract_name, f'Pair {arg0} {arg1}', expected_storage + ) + + +# prefix a type name with 'bls12_381_' +def bls(tname): + return f'bls12_381_{tname}' + + +# Store +def check_store(client, cls, arg): + arg = cls.to_hex(arg) + check_contract(client, f'store_{bls(cls.name)}', arg, arg) + + +# Add +def check_add(client, cls, xxx, yyy): + check_contract_binop( + client, + f'add_{bls(cls.name)}', + cls.to_hex(xxx), + cls.to_hex(yyy), + cls.to_hex(cls.add(xxx, yyy)), + ) + + +# Mul +def check_mul(client, cls, xxx, yyy): + check_contract_binop( + client, + f'mul_{bls(cls.name)}', + cls.to_hex(xxx), + Fr.to_hex(yyy), + cls.to_hex(cls.mul(xxx, yyy)), + ) + + +# Neg +def check_neg(client, cls, arg): + res = cls.to_hex(cls.neg(arg)) + arg = cls.to_hex(arg) + check_contract(client, f'neg_{bls(cls.name)}', arg, res) + + +# Pairing Check +def check_pairing_check(client, args): + res = pairing_check(args) + args = [(G1.to_hex(g1), G2.to_hex(g2)) for g1, g2 in args] + args = [f'Pair {g1} {g2}' for g1, g2 in args] + args = f'{{ {"; ".join(args)} }}' + check_contract(client, 'pairing_check', args, res) + + +# Setting this higher makes things rather slow +RANDOM_ITERATIONS = range(10) + +STORE_CLASSES = [G1, G2, Fr] +CURVES = [G1, G2] +ADD_CLASSES = [G1, G2, Fr] +MUL_CLASSES = [G1, G2, Fr] +NEG_CLASSES = [G1, G2, Fr] + + +@pytest.mark.incremental +@pytest.mark.contract +@pytest.mark.regression +class TestBls12_381: + + # Fix the random seed to ensure reproducibility + h = blake2b() + h.update(b'seed') + gen = random.Random() + gen.seed(bytes.fromhex(h.hexdigest())) + + # Store + @pytest.mark.parametrize("cls", STORE_CLASSES) + def test_store_zero(self, client_regtest, cls): + check_store(client_regtest, cls, cls.zero) + + @pytest.mark.parametrize("cls", STORE_CLASSES) + def test_store_one(self, client_regtest, cls): + check_store(client_regtest, cls, cls.one) + + @pytest.mark.parametrize("cls", STORE_CLASSES) + def test_store_random(self, client_regtest, cls): + for _ in RANDOM_ITERATIONS: + check_store(client_regtest, cls, cls.random(self.gen)) + + # Add + @pytest.mark.parametrize("cls", ADD_CLASSES) + def test_add_zero_zero(self, client_regtest, cls): + check_add(client_regtest, cls, cls.zero, cls.zero) + + @pytest.mark.parametrize("cls", ADD_CLASSES) + def test_add_zero_one(self, client_regtest, cls): + check_add(client_regtest, cls, cls.zero, cls.one) + + @pytest.mark.parametrize("cls", ADD_CLASSES) + def test_add_zero_random(self, client_regtest, cls): + for _ in RANDOM_ITERATIONS: + check_add(client_regtest, cls, cls.zero, cls.random(self.gen)) + + @pytest.mark.parametrize("cls", ADD_CLASSES) + def test_add_one_zero(self, client_regtest, cls): + check_add(client_regtest, cls, cls.one, cls.zero) + + @pytest.mark.parametrize("cls", ADD_CLASSES) + def test_add_one_one(self, client_regtest, cls): + check_add(client_regtest, cls, cls.one, cls.one) + + @pytest.mark.parametrize("cls", ADD_CLASSES) + def test_add_one_random(self, client_regtest, cls): + for _ in RANDOM_ITERATIONS: + check_add(client_regtest, cls, cls.one, cls.random(self.gen)) + + @pytest.mark.parametrize("cls", ADD_CLASSES) + def test_add_random_zero(self, client_regtest, cls): + for _ in RANDOM_ITERATIONS: + check_add(client_regtest, cls, cls.random(self.gen), cls.zero) + + @pytest.mark.parametrize("cls", ADD_CLASSES) + def test_add_random_one(self, client_regtest, cls): + for _ in RANDOM_ITERATIONS: + check_add(client_regtest, cls, cls.random(self.gen), cls.one) + + @pytest.mark.parametrize("cls", ADD_CLASSES) + def test_add_random_random(self, client_regtest, cls): + for _ in RANDOM_ITERATIONS: + check_add( + client_regtest, cls, cls.random(self.gen), cls.random(self.gen) + ) + + # Mul + @pytest.mark.parametrize("cls", MUL_CLASSES) + def test_mul_zero_zero(self, client_regtest, cls): + check_mul(client_regtest, cls, cls.zero, Fr.zero) + + @pytest.mark.parametrize("cls", MUL_CLASSES) + def test_mul_zero_one(self, client_regtest, cls): + check_mul(client_regtest, cls, cls.zero, Fr.one) + + @pytest.mark.parametrize("cls", MUL_CLASSES) + def test_mul_zero_random(self, client_regtest, cls): + for _ in RANDOM_ITERATIONS: + check_mul(client_regtest, cls, cls.zero, Fr.random(self.gen)) + + @pytest.mark.parametrize("cls", MUL_CLASSES) + def test_mul_one_zero(self, client_regtest, cls): + check_mul(client_regtest, cls, cls.one, Fr.zero) + + @pytest.mark.parametrize("cls", MUL_CLASSES) + def test_mul_one_one(self, client_regtest, cls): + check_mul(client_regtest, cls, cls.one, Fr.one) + + @pytest.mark.parametrize("cls", MUL_CLASSES) + def test_mul_one_random(self, client_regtest, cls): + for _ in RANDOM_ITERATIONS: + check_mul(client_regtest, cls, cls.one, Fr.random(self.gen)) + + @pytest.mark.parametrize("cls", MUL_CLASSES) + def test_mul_random_zero(self, client_regtest, cls): + for _ in RANDOM_ITERATIONS: + check_mul(client_regtest, cls, cls.random(self.gen), Fr.zero) + + @pytest.mark.parametrize("cls", MUL_CLASSES) + def test_mul_random_one(self, client_regtest, cls): + for _ in RANDOM_ITERATIONS: + check_mul(client_regtest, cls, cls.random(self.gen), Fr.one) + + @pytest.mark.parametrize("cls", MUL_CLASSES) + def test_mul_random_random(self, client_regtest, cls): + for _ in RANDOM_ITERATIONS: + check_mul( + client_regtest, cls, cls.random(self.gen), Fr.random(self.gen) + ) + + # Neg + @pytest.mark.parametrize("cls", NEG_CLASSES) + def test_neg_zero(self, client_regtest, cls): + check_neg(client_regtest, cls, cls.zero) + + @pytest.mark.parametrize("cls", NEG_CLASSES) + def test_neg_one(self, client_regtest, cls): + check_neg(client_regtest, cls, cls.one) + + @pytest.mark.parametrize("cls", NEG_CLASSES) + def test_neg_random(self, client_regtest, cls): + for _ in RANDOM_ITERATIONS: + check_neg(client_regtest, cls, cls.random(self.gen)) + + # Pairing checks + def test_pairing_nil(self, client_regtest): + check_pairing_check(client_regtest, []) + + def test_pairing_zero_zero(self, client_regtest): + args = [(G1.zero, G2.zero)] + check_pairing_check(client_regtest, args) + + def test_pairing_zero_one(self, client_regtest): + args = [(G1.zero, G2.one)] + check_pairing_check(client_regtest, args) + + def test_pairing_zero_random(self, client_regtest): + for _ in RANDOM_ITERATIONS: + args = [(G1.zero, G2.random(self.gen))] + check_pairing_check(client_regtest, args) + + def test_pairing_one_zero(self, client_regtest): + args = [(G1.one, G2.zero)] + check_pairing_check(client_regtest, args) + + def test_pairing_one_one(self, client_regtest): + args = [(G1.one, G2.one)] + check_pairing_check(client_regtest, args) + + def test_pairing_one_random(self, client_regtest): + for _ in RANDOM_ITERATIONS: + args = [(G1.one, G2.random(self.gen))] + check_pairing_check(client_regtest, args) + + def test_pairing_random_zero(self, client_regtest): + for _ in RANDOM_ITERATIONS: + args = [(G1.random(self.gen), G2.zero)] + check_pairing_check(client_regtest, args) + + def test_pairing_random_one(self, client_regtest): + for _ in RANDOM_ITERATIONS: + args = [(G1.random(self.gen), G2.one)] + check_pairing_check(client_regtest, args) + + def test_pairing_random_random(self, client_regtest): + for _ in RANDOM_ITERATIONS: + args = [(G1.random(self.gen), G2.random(self.gen))] + check_pairing_check(client_regtest, args) + + def test_pairing_neg_g1(self, client_regtest): + for _ in RANDOM_ITERATIONS: + g1_point = G1.random(self.gen) + g2_point = G2.random(self.gen) + args = [(g1_point, g2_point), (G1.neg(g1_point), g2_point)] + check_pairing_check(client_regtest, args) + + def test_pairing_neg_g2(self, client_regtest): + for _ in RANDOM_ITERATIONS: + g1_point = G1.random(self.gen) + g2_point = G2.random(self.gen) + args = [(g1_point, g2_point), (g1_point, G2.neg(g2_point))] + check_pairing_check(client_regtest, args) + + # Pairing Check test based on signature aggregation + def test_signature_aggregation(self, client_regtest): + for _ in RANDOM_ITERATIONS: + sk0 = Fr.random(self.gen) # secret key + pk0 = G2.mul(G2.one, sk0) # public key + # we don't have hash-to-curve on g1, so compute a random point + msg_hash = G1.random(self.gen) # message hash + sig0 = G1.mul(msg_hash, sk0) # signature + args0 = [(msg_hash, pk0), (G1.neg(sig0), G2.one)] + check_pairing_check(client_regtest, args0) + + sk1 = Fr.random(self.gen) # secret key + pk1 = G2.mul(G2.one, sk1) # public key + # we don't have hash-to-curve on g1, so compute a random point + sig1 = G1.mul(msg_hash, sk1) # signature + args1 = [ + (G1.add(msg_hash, msg_hash), G2.add(pk0, pk1)), + (G1.neg(G1.add(sig0, sig1)), G2.add(G2.one, G2.one)), + ] + check_pairing_check(client_regtest, args1) + + def test_groth16(self, client_regtest): + # pylint: disable=line-too-long + # The verifying key, proof, and inputs are generated from + # ZoKrates, modified to use BLS12-381. + # The circuit proves knowledge of a square root of 113569. + + input_x = "0xa1bb010000000000000000000000000000000000000000000000000000000000" # noqa + input_y = "0x0100000000000000000000000000000000000000000000000000000000000000" # noqa + proof_a = "0x0a2841423326ab08f5f406409775e43fa0f9a0b97631fa85d2dd9242507d25059e9cf48b8b98f99a0008671423a148ec106d70637056972ef49fb6f62de2e89ba3682b9972292b6bb4e6f53799a75d2f8001ccfde280d8ac05fc209352236cbd" # noqa + proof_b = "0x0fced939fb1ad733f99669f50a383ef632f6d41dfbde434a6715afd5c7dfbb7bc5835e058ad8b590c7b38dd137d0bd0f0e1540f1b45d8aa626c360e2ea484a116243f7c802034de915db6b18d5303946f676e423cbd6046d37a82208d500625a11c7250ccb953a7ee49d704ad14de4b727733cff7cf06875d8b6444f3c0a8cbf0bd980e539c74bd5b37bb15fe816f23407d269193105fda71adf35fae9309d9d46729fcd4685699097a86f0460a2bc8b16293940cabfdcfe0f27e4107e74e90c" # noqa + proof_c = "0x0a1fb5a144ca3bdfe4ad0f183cf71dd7fdd28cbef4fcd47b5b419f65186703f62ecaaa1255fa21a6ebdd917ab1f9bd9707de7066865e2ff3875e22088619125a0d4088a622ab42224425ef89a5a149ce2db9c8292b62c7e7aaa7e87f3535304b" # noqa + + inputs = f"Pair {input_x} {input_y}" + proof = f"Pair (Pair {proof_a} {proof_b}) {proof_c}" + arg = f"Pair ({inputs}) ({proof})" + + contract = path.join(MINI_SCENARIOS_CONTRACT_PATH, 'groth16.tz') + client_regtest.run_script(contract, 'Unit', arg) + + def test_fr_bytes_parameters_more_than_32_bytes(self, client_regtest): + random_bytes = ( + "0xf7ef66f95c90b2f953eb0555af65f22095d4f54b40ea8c6d" + + "cc2014740e8662c16bb8786723" + ) + contract = path.join(OPCODES_CONTRACT_PATH, 'bls12_381_fr_to_int.tz') + with assert_run_failure(r'error running script'): + client_regtest.run_script(contract, storage='0', inp=random_bytes) diff --git a/tests_python/tests_011/test_contract_macros.py b/tests_python/tests_011/test_contract_macros.py new file mode 100644 index 000000000000..8528f37165f7 --- /dev/null +++ b/tests_python/tests_011/test_contract_macros.py @@ -0,0 +1,447 @@ +from os import path +import pytest +from tools.utils import ( + assert_run_script_failwith, + assert_transfer_failwith, + init_with_transfer, + bake, + assert_storage_contains, +) +from tools.client_regression import ClientRegression +from client.client import Client +from .contract_paths import MACROS_CONTRACT_PATH, CONTRACT_PATH, all_contracts + + +@pytest.mark.contract +class TestContractMacros: + """Tests for contracts using macros that do not require origination.""" + + @pytest.mark.parametrize( + "contract,param,storage,expected", + [ # FORMAT: assert_output contract_file storage input expected_result + # Build list + ('build_list.tz', '{}', '0', '{ 0 }'), + ('build_list.tz', '{}', '3', '{ 0 ; 1 ; 2 ; 3 }'), + ( + 'build_list.tz', + '{}', + '10', + '{ 0 ; 1 ; 2 ; 3 ; 4 ; 5 ; 6 ; 7 ; 8 ; 9 ; 10 }', + ), + # Find maximum int in list -- returns None if not found + ('max_in_list.tz', 'None', '{}', 'None'), + ('max_in_list.tz', 'None', '{ 1 }', '(Some 1)'), + ('max_in_list.tz', 'None', '{ -1 }', '(Some -1)'), + ( + 'max_in_list.tz', + 'None', + '{ 10 ; -1 ; -20 ; 100 ; 0 }', + '(Some 100)', + ), + ( + 'max_in_list.tz', + 'None', + '{ 10 ; -1 ; -20 ; 100 ; 0 }', + '(Some 100)', + ), + ( + 'max_in_list.tz', + 'None', + '{ -10 ; -1 ; -20 ; -100 }', + '(Some -1)', + ), + # Test comparisons on tez { EQ ; GT ; LT ; GE ; LE } + ( + 'compare.tz', + '{}', + '(Pair 1000000 2000000)', + '{ False ; False ; True ; False ; True }', + ), + ( + 'compare.tz', + '{}', + '(Pair 2000000 1000000)', + '{ False ; True ; False ; True ; False }', + ), + ( + 'compare.tz', + '{}', + '(Pair 2370000 2370000)', + '{ True ; False ; False ; True ; True }', + ), + # Test ASSERT + ('assert.tz', 'Unit', 'True', 'Unit'), + # ASSERT_{OP} + ('assert_eq.tz', 'Unit', '(Pair -1 -1)', 'Unit'), + ('assert_eq.tz', 'Unit', '(Pair -1 -1)', 'Unit'), + ('assert_neq.tz', 'Unit', '(Pair 0 -1)', 'Unit'), + ('assert_lt.tz', 'Unit', '(Pair -1 0)', 'Unit'), + ('assert_le.tz', 'Unit', '(Pair 0 0)', 'Unit'), + ('assert_le.tz', 'Unit', '(Pair -1 0)', 'Unit'), + ('assert_gt.tz', 'Unit', '(Pair 0 -1)', 'Unit'), + ('assert_ge.tz', 'Unit', '(Pair 0 0)', 'Unit'), + ('assert_ge.tz', 'Unit', '(Pair 0 -1)', 'Unit'), + # ASSERT_CMP{OP} + ('assert_cmpeq.tz', 'Unit', '(Pair -1 -1)', 'Unit'), + ('assert_cmpneq.tz', 'Unit', '(Pair 0 -1)', 'Unit'), + ('assert_cmplt.tz', 'Unit', '(Pair -1 0)', 'Unit'), + ('assert_cmple.tz', 'Unit', '(Pair -1 0)', 'Unit'), + ('assert_cmple.tz', 'Unit', '(Pair 0 0)', 'Unit'), + ('assert_cmpgt.tz', 'Unit', '(Pair 0 -1)', 'Unit'), + ('assert_cmpge.tz', 'Unit', '(Pair 0 -1)', 'Unit'), + ('assert_cmpge.tz', 'Unit', '(Pair 0 0)', 'Unit'), + # Tests the SET_CAR and SET_CDR instructions + ( + 'set_caddaadr.tz', + '(Pair (Pair 1 2 (Pair (Pair 3 0) 4) 5) 6)', + '3000000', + '(Pair (Pair 1 2 (Pair (Pair 3 3000000) 4) 5) 6)', + ), + ( + 'map_caddaadr.tz', + '(Pair (Pair 1 2 (Pair (Pair 3 0) 4) 5) 6)', + 'Unit', + '(Pair (Pair 1 2 (Pair (Pair 3 1000000) 4) 5) 6)', + ), + # Test comparisons on bytes { EQ ; GT ; LT ; GE ; LE } + ( + 'compare_bytes.tz', + '{}', + '(Pair 0x33 0x34)', + '{ False ; False ; True ; False ; True }', + ), + ( + 'compare_bytes.tz', + '{}', + '(Pair 0x33 0x33aa)', + '{ False ; False ; True ; False ; True }', + ), + ( + 'compare_bytes.tz', + '{}', + '(Pair 0x33 0x33)', + '{ True ; False ; False ; True ; True }', + ), + ( + 'compare_bytes.tz', + '{}', + '(Pair 0x34 0x33)', + '{ False ; True ; False ; True ; False }', + ), + ], + ) + def test_contract_input_output( + self, + client: Client, + contract: str, + param: str, + storage: str, + expected: str, + ): + assert contract.endswith( + '.tz' + ), "test contract should have .tz extension" + contract = path.join(MACROS_CONTRACT_PATH, contract) + run_script_res = client.run_script(contract, param, storage) + assert run_script_res.storage == expected + + @pytest.mark.parametrize( + "contract,param,storage", + [ # FORMAT: assert_output contract_file storage input expected_result + ('assert.tz', 'Unit', 'False'), + ('assert_eq.tz', 'Unit', '(Pair 0 -1)'), + ('assert_eq.tz', 'Unit', '(Pair 0 -1)'), + ('assert_neq.tz', 'Unit', '(Pair -1 -1)'), + ('assert_lt.tz', 'Unit', '(Pair 0 -1)'), + ('assert_lt.tz', 'Unit', '(Pair 0 0)'), + ('assert_le.tz', 'Unit', '(Pair 0 -1)'), + ('assert_gt.tz', 'Unit', '(Pair -1 0)'), + ('assert_gt.tz', 'Unit', '(Pair 0 0)'), + ('assert_ge.tz', 'Unit', '(Pair -1 0)'), + ('assert_cmpeq.tz', 'Unit', '(Pair 0 -1)'), + ('assert_cmpneq.tz', 'Unit', '(Pair -1 -1)'), + ('assert_cmplt.tz', 'Unit', '(Pair 0 0)'), + ('assert_cmplt.tz', 'Unit', '(Pair 0 -1)'), + ('assert_cmple.tz', 'Unit', '(Pair 0 -1)'), + ('assert_cmpgt.tz', 'Unit', '(Pair 0 0)'), + ('assert_cmpgt.tz', 'Unit', '(Pair -1 0)'), + ('assert_cmpge.tz', 'Unit', '(Pair -1 0)'), + ], + ) + def test_contract_failures(self, client: Client, contract, param, storage): + contract = path.join(MACROS_CONTRACT_PATH, contract) + assert_run_script_failwith(client, contract, param, storage) + + +@pytest.mark.slow +@pytest.mark.contract +class TestGuestBook: + """Test on the guestbook contract.""" + + def test_guestbook(self, client: Client): + contract = path.join(MACROS_CONTRACT_PATH, 'guestbook.tz') + + init_with_transfer( + client, + contract, + '{ Elt "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" None }', + 100, + 'bootstrap1', + ) + + assert_transfer_failwith( + client, + 0, + 'bootstrap2', + 'guestbook', + ['--arg', '"Pas moi"', '--burn-cap', '10'], + ) + + client.transfer( + 0, + 'bootstrap1', + 'guestbook', + ['-arg', '"Coucou"', '--burn-cap', '10'], + ) + bake(client) + assert_storage_contains( + client, + 'guestbook', + '{ Elt "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" (Some "Coucou") }', + ) + + assert_transfer_failwith( + client, + 0, + 'bootstrap3', + 'guestbook', + ['--arg', '"Pas moi non plus"', '--burn-cap', '10'], + ) + assert_transfer_failwith( + client, + 0, + 'bootstrap1', + 'guestbook', + ['--arg', '"Recoucou ?"', '--burn-cap', '10'], + ) + + +@pytest.mark.slow +@pytest.mark.contract +class TestBigmap: + """Tests on the big_map_mem contract.""" + + def test_bigmap(self, client: Client): + contract = path.join(MACROS_CONTRACT_PATH, 'big_map_mem.tz') + + init_with_transfer( + client, + contract, + '(Pair { Elt 1 Unit ; Elt 2 Unit ; Elt 3 Unit } Unit)', + 100, + 'bootstrap1', + ) + + client.transfer( + 1, + 'bootstrap1', + 'big_map_mem', + ['-arg', '(Pair 0 False)', '--burn-cap', '10'], + ) + bake(client) + + assert_transfer_failwith( + client, + 0, + 'bootstrap1', + 'big_map_mem', + ['--arg', '(Pair 0 True)', '--burn-cap', '10'], + ) + + client.transfer( + 1, + 'bootstrap1', + 'big_map_mem', + ['--arg', '(Pair 0 False)', '--burn-cap', '10'], + ) + bake(client) + assert_transfer_failwith( + client, + 1, + 'bootstrap1', + 'big_map_mem', + ['--arg', '(Pair 0 True)', '--burn-cap', '10'], + ) + client.transfer( + 1, + 'bootstrap1', + 'big_map_mem', + ['--arg', '(Pair 1 True)', '--burn-cap', '10'], + ) + bake(client) + assert_transfer_failwith( + client, + 1, + 'bootstrap1', + 'big_map_mem', + ['--arg', '(Pair 1 False)', '--burn-cap', '10'], + ) + client.transfer( + 1, + 'bootstrap1', + 'big_map_mem', + ['--arg', '(Pair 2 True)', '--burn-cap', '10'], + ) + bake(client) + assert_transfer_failwith( + client, + 1, + 'bootstrap1', + 'big_map_mem', + ['--arg', '(Pair 2 False)', '--burn-cap', '10'], + ) + client.transfer( + 1, + 'bootstrap1', + 'big_map_mem', + ['--arg', '(Pair 3 True)', '--burn-cap', '10'], + ) + bake(client) + assert_transfer_failwith( + client, + 1, + 'bootstrap1', + 'big_map_mem', + ['--arg', '(Pair 3 False)', '--burn-cap', '10'], + ) + client.transfer( + 1, + 'bootstrap1', + 'big_map_mem', + ['--arg', '(Pair 4 False)', '--burn-cap', '10'], + ) + bake(client) + assert_transfer_failwith( + client, + 1, + 'bootstrap1', + 'big_map_mem', + ['--arg', '(Pair 4 True)', '--burn-cap', '10'], + ) + + +@pytest.mark.slow +@pytest.mark.contract +class TestBigmapGetAdd: + """Tests on the big_map_get_add contract.""" + + def test_bigmap(self, client: Client): + contract = path.join(MACROS_CONTRACT_PATH, 'big_map_get_add.tz') + + init_with_transfer( + client, + contract, + '(Pair { Elt 0 1 ; Elt 1 2 ; Elt 2 3 } Unit)', + 100, + 'bootstrap1', + ) + + client.transfer( + 1, + 'bootstrap1', + 'big_map_get_add', + [ + '--arg', + '(Pair (Pair 200 (Some 2)) (Pair 200 (Some 2)))', + '--burn-cap', + '10', + ], + ) + bake(client) + client.transfer( + 1, + 'bootstrap1', + 'big_map_get_add', + [ + '--arg', + '(Pair (Pair 200 None) (Pair 200 None))', + '--burn-cap', + '10', + ], + ) + bake(client) + client.transfer( + 1, + 'bootstrap1', + 'big_map_get_add', + [ + '--arg', + '(Pair (Pair 200 None) (Pair 300 None))', + '--burn-cap', + '10', + ], + ) + bake(client) + client.transfer( + 1, + 'bootstrap1', + 'big_map_get_add', + [ + '--arg', + '(Pair (Pair 1 None) (Pair 200 None))', + '--burn-cap', + '10', + ], + ) + bake(client) + client.transfer( + 1, + 'bootstrap1', + 'big_map_get_add', + [ + '--arg', + '(Pair (Pair 1 (Some 2)) (Pair 0 (Some 1)))', + '--burn-cap', + '10', + ], + ) + bake(client) + client.transfer( + 1, + 'bootstrap1', + 'big_map_get_add', + [ + '--arg', + '(Pair (Pair 400 (Some 1232)) (Pair 400 (Some 1232)))', + '--burn-cap', + '10', + ], + ) + bake(client) + client.transfer( + 1, + 'bootstrap1', + 'big_map_get_add', + [ + '--arg', + '(Pair (Pair 401 (Some 0)) (Pair 400 (Some 1232)))', + '--burn-cap', + '10', + ], + ) + bake(client) + + +@pytest.mark.regression +class TestMacroExpansion: + """Test expanding macros""" + + @pytest.mark.parametrize("contract", all_contracts(['macros'])) + def test_macro_expansion( + self, client_regtest: ClientRegression, contract: str + ): + """This test expands macros in all macro test contracts, with + regression detection enabled. This test should fail if the definition + of any macros change. + """ + client_regtest.expand_macros(path.join(CONTRACT_PATH, contract)) diff --git a/tests_python/tests_011/test_contract_onchain_opcodes.py b/tests_python/tests_011/test_contract_onchain_opcodes.py new file mode 100644 index 000000000000..5898a7e46bee --- /dev/null +++ b/tests_python/tests_011/test_contract_onchain_opcodes.py @@ -0,0 +1,1309 @@ +from os import path + +import pytest +from tools.client_regression import ClientRegression +from tools import paths +from tools.utils import ( + assert_run_failure, + assert_storage_contains, + bake, + init_with_transfer, + assert_balance, +) +from tools.constants import IDENTITIES +from .contract_paths import OPCODES_CONTRACT_PATH, MINI_SCENARIOS_CONTRACT_PATH + +KEY1 = 'foo' +KEY2 = 'bar' + + +@pytest.mark.incremental +@pytest.mark.slow +@pytest.mark.contract +@pytest.mark.regression +class TestContractOnchainOpcodes: + """Tests for individual opcodes that requires origination.""" + + def test_gen_keys(self, client_regtest_scrubbed: ClientRegression): + """Add keys used by later tests.""" + client = client_regtest_scrubbed + client.gen_key(KEY1) + client.gen_key(KEY2) + + def test_store_input(self, client_regtest_scrubbed: ClientRegression): + client = client_regtest_scrubbed + client.transfer(1000, "bootstrap1", KEY1, ['--burn-cap', '0.257']) + bake(client) + + client.transfer(2000, "bootstrap1", KEY2, ['--burn-cap', '0.257']) + bake(client) + + assert_balance(client, KEY1, 1000) + assert_balance(client, KEY2, 2000) + + # Create a contract and transfer 100 ꜩ to it + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'store_input.tz'), + '""', + 100, + 'bootstrap1', + ) + + client.transfer( + 100, + "bootstrap1", + "store_input", + ["-arg", '"abcdefg"', '--burn-cap', '10'], + ) + bake(client) + + assert_balance(client, "store_input", 200) + + assert_storage_contains(client, "store_input", '"abcdefg"') + + client.transfer( + 100, + "bootstrap1", + "store_input", + ["-arg", '"xyz"', '--burn-cap', '10'], + ) + bake(client) + + assert_storage_contains(client, "store_input", '"xyz"') + + def test_transfer_amount(self, client_regtest_scrubbed: ClientRegression): + client = client_regtest_scrubbed + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'transfer_amount.tz'), + '0', + 100, + 'bootstrap1', + ) + + client.transfer( + 500, + "bootstrap1", + 'transfer_amount', + ['-arg', 'Unit', '--burn-cap', '10'], + ) + + bake(client) + + assert_storage_contains(client, "transfer_amount", '500000000') + + def test_now(self, client_regtest_scrubbed: ClientRegression): + # Regtest is disabled for this test, since one would need to + # scrub storage for this one as it changes (the timestamp) + # on every run. + client = client_regtest_scrubbed + client.set_regtest(None) + + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'store_now.tz'), + '"2017-07-13T09:19:01Z"', + 100, + 'bootstrap1', + ) + + client.transfer( + 500, "bootstrap1", 'store_now', ['-arg', 'Unit', '--burn-cap', '10'] + ) + bake(client) + + assert_storage_contains(client, 'store_now', f'"{client.get_now()}"') + + def test_transfer_tokens(self, client_regtest_scrubbed: ClientRegression): + """Tests TRANSFER_TOKENS.""" + client = client_regtest_scrubbed + client.originate( + 'test_transfer_account1', + 100, + 'bootstrap1', + path.join(OPCODES_CONTRACT_PATH, 'noop.tz'), + ['--burn-cap', '10'], + ) + bake(client) + + client.originate( + 'test_transfer_account2', + 20, + 'bootstrap1', + path.join(OPCODES_CONTRACT_PATH, 'noop.tz'), + ['--burn-cap', '10'], + ) + bake(client) + + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'transfer_tokens.tz'), + 'Unit', + 1000, + 'bootstrap1', + ) + + assert_balance(client, 'test_transfer_account1', 100) + + account1_addr = client.get_contract_address('test_transfer_account1') + client.transfer( + 100, + 'bootstrap1', + 'transfer_tokens', + ['-arg', f'"{account1_addr}"', '--burn-cap', '10'], + ) + bake(client) + + # Why isn't this 200 ꜩ? Baking fee? + assert_balance(client, 'test_transfer_account1', 200) + + account2_addr = client.get_contract_address('test_transfer_account2') + client.transfer( + 100, + 'bootstrap1', + 'transfer_tokens', + ['-arg', f'"{account2_addr}"', '--burn-cap', '10'], + ) + bake(client) + + assert_balance(client, 'test_transfer_account2', 120) + + def test_self(self, client_regtest_scrubbed: ClientRegression): + # Regtest is disabled for this test, since one would need to + # scrub storage for this one as it changes (the contract + # address) on every run. + client = client_regtest_scrubbed + client.set_regtest(None) + + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'self.tz'), + '"tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"', + 1000, + 'bootstrap1', + ) + + client.transfer(0, 'bootstrap1', 'self', ['--burn-cap', '10']) + bake(client) + + self_addr = client.get_contract_address('self') + assert_storage_contains(client, 'self', f'"{self_addr}"') + + def test_contract_fails(self, client_regtest_scrubbed: ClientRegression): + client = client_regtest_scrubbed + client.set_regtest(None) + + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'contract.tz'), + 'Unit', + 1000, + 'bootstrap1', + ) + + client.transfer(0, 'bootstrap1', 'self', ['--burn-cap', '10']) + bake(client) + addr = client.get_contract_address('contract') + + with assert_run_failure(r'script reached FAILWITH instruction'): + client.transfer( + 0, + 'bootstrap1', + 'contract', + ['-arg', f'"{addr}"', '--burn-cap', '10'], + ) + + def test_init_proxy(self, client_regtest_scrubbed: ClientRegression): + client = client_regtest_scrubbed + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'proxy.tz'), + 'Unit', + 1000, + 'bootstrap1', + ) + + def test_source(self, client_regtest_scrubbed: ClientRegression): + client = client_regtest_scrubbed + init_store = IDENTITIES['bootstrap4']['identity'] + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'source.tz'), + f'"{init_store}"', + 1000, + 'bootstrap1', + ) + + # direct transfer to the contract + client.transfer(0, 'bootstrap2', 'source', ['--burn-cap', '10']) + bake(client) + + source_addr = IDENTITIES['bootstrap2']['identity'] + assert_storage_contains(client, 'source', f'"{source_addr}"') + + # indirect transfer to the contract through proxy + contract_addr = client.get_contract_address('source') + client.transfer( + 0, + 'bootstrap2', + 'proxy', + ['--burn-cap', '10', '--arg', f'"{contract_addr}"'], + ) + bake(client) + assert_storage_contains(client, 'source', f'"{source_addr}"') + + def test_sender(self, client_regtest_scrubbed: ClientRegression): + client = client_regtest_scrubbed + client.set_regtest(None) + + init_store = IDENTITIES['bootstrap4']['identity'] + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'sender.tz'), + f'"{init_store}"', + 1000, + 'bootstrap1', + ) + + # direct transfer to the contract + client.transfer(0, 'bootstrap2', 'sender', ['--burn-cap', '10']) + bake(client) + + sender_addr = IDENTITIES['bootstrap2']['identity'] + assert_storage_contains(client, 'sender', f'"{sender_addr}"') + + # indirect transfer to the contract through proxy + contract_addr = client.get_contract_address('sender') + proxy_addr = client.get_contract_address('proxy') + client.transfer( + 0, + 'bootstrap2', + 'proxy', + ['--burn-cap', '10', '--arg', f'"{contract_addr}"'], + ) + bake(client) + assert_storage_contains(client, 'sender', f'"{proxy_addr}"') + + def test_slice(self, client_regtest_scrubbed: ClientRegression): + client = client_regtest_scrubbed + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'slices.tz'), + '"sppk7dBPqMPjDjXgKbb5f7V3PuKUrA4Zuwc3c3H7XqQerqPUWbK7Hna"', + 1000, + 'bootstrap1', + ) + + @pytest.mark.parametrize( + 'contract_arg', + [ + line.rstrip('\n') + for line in open( + f'{paths.TEZOS_HOME}' + + '/tests_python/tests_011/' + + 'test_slice_fails_params.txt' + ) + ], + ) + def test_slice_fails( + self, client_regtest_scrubbed: ClientRegression, contract_arg: str + ): + client = client_regtest_scrubbed + + with assert_run_failure(r'script reached FAILWITH instruction'): + client.transfer( + 0, + 'bootstrap1', + 'slices', + ['-arg', contract_arg, '--burn-cap', '10'], + ) + # bake(client) + + @pytest.mark.parametrize( + 'contract_arg', + [ + line.rstrip('\n') + for line in open( + f'{paths.TEZOS_HOME}' + + '/tests_python/tests_011/' + + 'test_slice_success_params.txt' + ) + ], + ) + def test_slice_success( + self, client_regtest_scrubbed: ClientRegression, contract_arg: str + ): + client = client_regtest_scrubbed + client.transfer( + 0, + 'bootstrap1', + 'slices', + ['-arg', contract_arg, '--burn-cap', '10'], + ) + bake(client) + + def test_split_string(self, client_regtest_scrubbed: ClientRegression): + client = client_regtest_scrubbed + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'split_string.tz'), + '{}', + 1000, + 'bootstrap1', + ) + + client.transfer( + 0, + 'bootstrap1', + 'split_string', + ['-arg', '"abc"', '--burn-cap', '10'], + ) + bake(client) + assert_storage_contains(client, 'split_string', '{ "a" ; "b" ; "c" }') + + client.transfer( + 0, + 'bootstrap1', + 'split_string', + ['-arg', '"def"', '--burn-cap', '10'], + ) + bake(client) + assert_storage_contains( + client, 'split_string', '{ "a" ; "b" ; "c" ; "d" ; "e" ; "f" }' + ) + + def test_split_bytes(self, client_regtest_scrubbed: ClientRegression): + client = client_regtest_scrubbed + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'split_bytes.tz'), + '{}', + 1000, + 'bootstrap1', + ) + + client.transfer( + 0, + 'bootstrap1', + 'split_bytes', + ['-arg', '0xaabbcc', '--burn-cap', '10'], + ) + bake(client) + assert_storage_contains(client, 'split_bytes', '{ 0xaa ; 0xbb ; 0xcc }') + + client.transfer( + 0, + 'bootstrap1', + 'split_bytes', + ['-arg', '0xddeeff', '--burn-cap', '10'], + ) + bake(client) + assert_storage_contains( + client, 'split_bytes', '{ 0xaa ; 0xbb ; 0xcc ; 0xdd ; 0xee ; 0xff }' + ) + + def test_set_delegate(self, client_regtest_scrubbed: ClientRegression): + client = client_regtest_scrubbed + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'set_delegate.tz'), + 'Unit', + 1000, + 'bootstrap1', + ) + bake(client) + + assert client.get_delegate('set_delegate').delegate is None + + addr = IDENTITIES['bootstrap5']['identity'] + client.transfer( + 0, 'bootstrap1', 'set_delegate', ['-arg', f'(Some "{addr}")'] + ) + bake(client) + + assert client.get_delegate('set_delegate').delegate == addr + + client.transfer(0, 'bootstrap1', 'set_delegate', ['-arg', 'None']) + bake(client) + + assert client.get_delegate('set_delegate').delegate is None + + @pytest.mark.parametrize( + 'contract', + [ + 'compare_big_type.tz', + 'compare_big_type2.tz', + ], + ) + def test_trace_origination(self, client_regtest_scrubbed, contract): + client = client_regtest_scrubbed + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, contract), + 'Unit', + 1000, + 'bootstrap1', + ) + bake(client) + + +@pytest.mark.incremental +class TestTickets: + """Tests for tickets.""" + + def test_ticket_user_forge(self, client): + bake(client) + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticket_store-2.tz'), + 'None', + 100, + 'bootstrap1', + 'storer', + ) + + # Create parameter by hand with a ticket type but no ticket in it + client.transfer( + 100, 'bootstrap1', 'storer', ['-arg', 'None', '--burn-cap', '10'] + ) + + with assert_run_failure(r'Unexpected forged value'): + # Create parameter by hand with a ticket in it + client.transfer( + 100, + 'bootstrap1', + 'storer', + ['-arg', 'Some 1', '--burn-cap', '10'], + ) + + with assert_run_failure(r'Unexpected forged value'): + # Create storage by hand with a ticket in it + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticket_bad.tz'), + '1', + 100, + 'bootstrap1', + 'ticket_bad', + ) + + def test_ticket_user_big_forge(self, client): + bake(client) + contract_name = 'big_storer' + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticket_big_store.tz'), + '{}', + 100, + 'bootstrap1', + contract_name, + ) + bake(client) + client.transfer( + 100, 'bootstrap1', contract_name, ['-arg', '42', '--burn-cap', '10'] + ) + bake(client) + storage = client.get_storage(contract_name) + + with assert_run_failure(r'Unexpected forged value'): + # Create a storage with the ID of a big map that has tickets in it + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticket_big_store.tz'), + storage, + 100, + 'bootstrap1', + 'thief', + ) + + with assert_run_failure(r'Unexpected forged value'): + # Create a storage with the ID of a big map that has tickets in it + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticket_big_store.tz'), + '(Pair ' + storage + ' {})', + 100, + 'bootstrap1', + 'thief', + ) + + def test_ticket_read(self, client): + """Test TICKETS""" + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticketer.tz'), + '42', + 100, + 'bootstrap1', + 'ticketer_read', + ) + bake(client) + ticketer_addr = client.get_contract_address('ticketer_read') + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticket_read.tz'), + '"' + ticketer_addr + '"', + 100, + 'bootstrap1', + 'reader', + ) + bake(client) + reader_addr = client.get_contract_address('reader') + client.transfer( + 100, + 'bootstrap1', + 'ticketer_read', + ['-arg', '"' + reader_addr + '"', '--burn-cap', '10'], + ) + bake(client) + assert_storage_contains(client, "reader", '"' + ticketer_addr + '"') + + def test_bad_ticket(self, client): + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticketer.tz'), + '42', + 100, + 'bootstrap1', + 'ticketer_bad', + ) + bake(client) + ticketer_addr = client.get_contract_address('ticketer_bad') + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticket_read.tz'), + '"' + ticketer_addr + '"', + 100, + 'bootstrap1', + 'reader_bad', + ) + bake(client) + with assert_run_failure(r'Unexpected forged value'): + client.transfer( + 100, + 'bootstrap1', + 'reader_bad', + ['-arg', '1', '--burn-cap', '10'], + ) + bake(client) + + def test_ticket_utxo(self, client): + """Test UTXOs""" + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'utxor.tz'), + '42', + 100, + 'bootstrap1', + ) + bake(client) + utxor_addr = client.get_contract_address('utxor') + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'utxo_read.tz'), + '"' + utxor_addr + '"', + 100, + 'bootstrap1', + "reader_a", + ) + bake(client) + reader_a_addr = client.get_contract_address('reader_a') + utxor_addr = client.get_contract_address('utxor') + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'utxo_read.tz'), + '"' + utxor_addr + '"', + 100, + 'bootstrap1', + "reader_b", + ) + bake(client) + reader_b_addr = client.get_contract_address('reader_b') + client.transfer( + 100, + 'bootstrap1', + 'utxor', + [ + '-arg', + '(Pair "' + reader_a_addr + '" "' + reader_b_addr + '")', + '--burn-cap', + '10', + ], + ) + bake(client) + + def test_ticket_split(self, client): + def ticket(target_addr, param, utxo_amount): + param = ( + '(Pair (Pair "' + + target_addr + + '" ' + + str(param) + + ') ' + + str(utxo_amount) + + ')' + ) + client.transfer( + 100, + 'bootstrap1', + 'ticketer', + ['-arg', param, '--burn-cap', '10'], + ) + + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticketer-2.tz'), + 'Unit', + 100, + 'bootstrap1', + 'ticketer', + ) + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticket_split.tz'), + 'Unit', + 100, + 'bootstrap1', + 'splitter', + ) + bake(client) + splitter_addr = client.get_contract_address('splitter') + ticket(splitter_addr, 42, 3) + with assert_run_failure(r'script reached FAILWITH instruction'): + # Wrong Split Amount + ticket(splitter_addr, 42, 4) + bake(client) + + def test_ticket_join(self, client): + """Test JOIN""" + + def params(target_addr, utxo_amount, param): + return ( + '(Pair (Pair "' + + target_addr + + '" ' + + str(param) + + ') ' + + str(utxo_amount) + + ')' + ) + + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticketer-2.tz'), + 'Unit', + 100, + 'bootstrap1', + 'ticketer_a', + ) + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticketer-2.tz'), + 'Unit', + 100, + 'bootstrap1', + 'ticketer_b', + ) + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'ticket_join.tz'), + 'None', + 100, + 'bootstrap1', + 'joiner', + ) + bake(client) + joiner_addr = client.get_contract_address('joiner') + client.transfer( + 100, + 'bootstrap1', + 'ticketer_a', + ['-arg', params(joiner_addr, 42, 1), '--burn-cap', '10'], + ) + bake(client) + client.transfer( + 100, + 'bootstrap1', + 'ticketer_a', + ['-arg', params(joiner_addr, 144, 1), '--burn-cap', '10'], + ) + bake(client) + with assert_run_failure(r'script reached FAILWITH instruction'): + # Different Ticketer + client.transfer( + 100, + 'bootstrap1', + 'ticketer_b', + ['-arg', params(joiner_addr, 23, 1), '--burn-cap', '10'], + ) + with assert_run_failure(r'script reached FAILWITH instruction'): + # Different Content + client.transfer( + 100, + 'bootstrap1', + 'ticketer_a', + ['-arg', params(joiner_addr, 21, 23), '--burn-cap', '10'], + ) + + def test_ticket_fungible_originations(self, client, session): + """Test the origination of builder and wallet contracts for fungible + tokens implemented using tickets.""" + + builder_path = path.join( + MINI_SCENARIOS_CONTRACT_PATH, 'ticket_builder_fungible.tz' + ) + + wallet_path = path.join( + MINI_SCENARIOS_CONTRACT_PATH, 'ticket_wallet_fungible.tz' + ) + + manager_address = IDENTITIES['bootstrap1']['identity'] + + builders = {} + wallets = {} + + # Helper functions + def originate_builder(name): + """Create a fungible token contract managed by bootstrap1.""" + origination = client.originate( + contract_name=f'builder_{name}', + amount="0", + sender='bootstrap1', + contract=builder_path, + args=['--init', f'"{manager_address}"', '--burn-cap', "10"], + ) + builders[name] = origination.contract + bake(client) + + def originate_wallet(name): + """Create a fungible token wallet managed by bootstrap1.""" + origination = client.originate( + contract_name=f'wallet_{name}', + amount="0", + sender='bootstrap1', + contract=wallet_path, + args=[ + '--init', + f'Pair "{manager_address}" {{}}', + '--burn-cap', + "10", + ], + ) + wallets[name] = origination.contract + bake(client) + + # Create 3 token contracts "A", "B", and "C". + originate_builder("A") + originate_builder("B") + originate_builder("C") + + # Create 2 wallets "Alice" and "Bob". + originate_wallet("Alice") + originate_wallet("Bob") + + session['fungible_builders'] = builders + session['fungible_wallets'] = wallets + + def test_ticket_fungible_transfers(self, client, session): + """Test the life cycle of fungible tokens implemented using tickets.""" + + manager_address = IDENTITIES['bootstrap1']['identity'] + + builders = session['fungible_builders'] + wallets = session['fungible_wallets'] + + def mint(builder, wallet, amount): + """Mint fungible tokens.""" + wallet_address = wallets[wallet] + parameter = f'(Pair "{wallet_address}%receive" {amount})' + client.transfer( + amount=0, + giver=manager_address, + receiver=f'builder_{builder}', + args=[ + '--burn-cap', + '2', + '--entrypoint', + 'mint', + '--arg', + parameter, + ], + ) + bake(client) + + def burn(builder, wallet, amount): + """Burn fungible tokens.""" + builder_addr = builders[builder] + parameter = f'Pair "{builder_addr}%burn" {amount} "{builder_addr}"' + client.transfer( + amount=0, + giver=manager_address, + receiver=f'wallet_{wallet}', + args=[ + '--burn-cap', + '2', + '--entrypoint', + 'send', + '--arg', + parameter, + ], + ) + bake(client) + + def transfer(builder, source_wallet, destination_wallet, amount): + """Transfer fungible tokens.""" + builder_addr = builders[builder] + dest_addr = wallets[destination_wallet] + parameter = f'Pair "{dest_addr}%receive" {amount} "{builder_addr}"' + client.transfer( + amount=0, + giver=manager_address, + receiver=f'wallet_{source_wallet}', + args=[ + '--burn-cap', + '2', + '--entrypoint', + 'send', + '--arg', + parameter, + ], + ) + bake(client) + + # 100A --> Alice + mint(builder="A", wallet="Alice", amount=100) + # 100B --> Alice + mint(builder="B", wallet="Alice", amount=100) + + # Fail: Alice --1C--> Bob + with assert_run_failure(r'script reached FAILWITH instruction'): + transfer( + builder="C", + source_wallet="Alice", + destination_wallet="Bob", + amount=1, + ) + + # Fail: Alice --0C--> Bob + with assert_run_failure(r'script reached FAILWITH instruction'): + transfer( + builder="C", + source_wallet="Alice", + destination_wallet="Bob", + amount=0, + ) + + # Fail: Alice --150A--> Bob + with assert_run_failure(r'script reached FAILWITH instruction'): + transfer( + builder="A", + source_wallet="Alice", + destination_wallet="Bob", + amount=150, + ) + + # Fail: Bob --50A--> Alice + with assert_run_failure(r'script reached FAILWITH instruction'): + transfer( + builder="A", + source_wallet="Bob", + destination_wallet="Alice", + amount=50, + ) + + # Alice --50A--> Bob + transfer( + builder="A", + source_wallet="Alice", + destination_wallet="Bob", + amount=50, + ) + + # Alice --50A--> Bob + transfer( + builder="A", + source_wallet="Alice", + destination_wallet="Bob", + amount=50, + ) + + # Alice --0A--> Bob + transfer( + builder="A", + source_wallet="Alice", + destination_wallet="Bob", + amount=0, + ) + + # Fail: Alice --1A--> Bob + with assert_run_failure(r'script reached FAILWITH instruction'): + transfer( + builder="A", + source_wallet="Alice", + destination_wallet="Bob", + amount=1, + ) + + # Bob --100A--> Bob + transfer( + builder="A", + source_wallet="Bob", + destination_wallet="Bob", + amount=100, + ) + + # Fail: Bob --150A--> Bob + with assert_run_failure(r'script reached FAILWITH instruction'): + transfer( + builder="A", + source_wallet="Bob", + destination_wallet="Bob", + amount=150, + ) + + # Bob --100A--> + burn(builder="A", wallet="Bob", amount=100) + + # Bob --0A--> + burn(builder="A", wallet="Bob", amount=0) + + # Fail: Bob --1A--> + with assert_run_failure(r'script reached FAILWITH instruction'): + burn(builder="A", wallet="Bob", amount=1) + + def test_ticket_non_fungible_originations(self, client, session): + """Test the origination of builder and wallet contracts for + non-fungible tokens implemented using tickets.""" + + builder_path = path.join( + MINI_SCENARIOS_CONTRACT_PATH, 'ticket_builder_non_fungible.tz' + ) + + wallet_path = path.join( + MINI_SCENARIOS_CONTRACT_PATH, 'ticket_wallet_non_fungible.tz' + ) + + manager_address = IDENTITIES['bootstrap1']['identity'] + + builders = {} + wallets = {} + + # Helper functions + def originate_builder(name): + """Create a non-fungible token contract managed by bootstrap1.""" + storage = f'(Pair "{manager_address}" 0)' + origination = client.originate( + contract_name=f'nft_builder_{name}', + amount="0", + sender='bootstrap1', + contract=builder_path, + args=['--init', storage, '--burn-cap', "10"], + ) + builders[name] = origination.contract + bake(client) + + def originate_wallet(name): + """Create a non-fungible token wallet managed by bootstrap1.""" + origination = client.originate( + contract_name=f'nft_wallet_{name}', + amount="0", + sender='bootstrap1', + contract=wallet_path, + args=[ + '--init', + f'Pair "{manager_address}" {{}}', + '--burn-cap', + "10", + ], + ) + wallets[name] = origination.contract + bake(client) + + # Create 3 token contracts "A", "B", and "C". + originate_builder("A") + originate_builder("B") + originate_builder("C") + + # Create 2 wallets "Alice" and "Bob". + originate_wallet("Alice") + originate_wallet("Bob") + + session['non_fungible_builders'] = builders + session['non_fungible_wallets'] = wallets + + def test_ticket_non_fungible_transfers(self, client, session): + """Test the life cycle of non-fungible tokens implemented using + tickets.""" + + manager_address = IDENTITIES['bootstrap1']['identity'] + + builders = session['non_fungible_builders'] + wallets = session['non_fungible_wallets'] + + def mint(builder, wallet, token_id): + """Mint a non-fungible token and assert that it has the expected + id.""" + builder_alias = f'nft_builder_{builder}' + expected_builder_storage = f'Pair "{manager_address}" {token_id}' + actual_builder_storage = client.get_storage(builder_alias) + assert expected_builder_storage == actual_builder_storage + + wallet_address = wallets[wallet] + parameter = f'"{wallet_address}%receive"' + client.transfer( + amount=0, + giver=manager_address, + receiver=builder_alias, + args=[ + '--burn-cap', + '2', + '--entrypoint', + 'mint_destination', + '--arg', + parameter, + ], + ) + bake(client) + + def burn(builder, wallet, token_id): + """Burn a non-fungible token.""" + builder_addr = builders[builder] + parameter = ( + f'Pair "{builder_addr}%burn" "{builder_addr}" {token_id}' + ) + client.transfer( + amount=0, + giver=manager_address, + receiver=f'nft_wallet_{wallet}', + args=[ + '--burn-cap', + '2', + '--entrypoint', + 'send', + '--arg', + parameter, + ], + ) + bake(client) + + def transfer(builder, source_wallet, destination_wallet, token_id): + """Transfer fungible tokens.""" + builder_addr = builders[builder] + dest_addr = wallets[destination_wallet] + parameter = ( + f'Pair "{dest_addr}%receive" "{builder_addr}" {token_id}' + ) + client.transfer( + amount=0, + giver=manager_address, + receiver=f'nft_wallet_{source_wallet}', + args=[ + '--burn-cap', + '2', + '--entrypoint', + 'send', + '--arg', + parameter, + ], + ) + bake(client) + + # A0 --> Alice + mint(builder="A", wallet="Alice", token_id=0) + # A1 --> Alice + mint(builder="A", wallet="Alice", token_id=1) + # B0 --> Alice + mint(builder="B", wallet="Alice", token_id=0) + + # Fail: Alice --C0--> Bob + with assert_run_failure(r'script reached FAILWITH instruction'): + transfer( + builder="C", + source_wallet="Alice", + destination_wallet="Bob", + token_id=0, + ) + + # Fail: Alice --A2--> Bob + with assert_run_failure(r'script reached FAILWITH instruction'): + transfer( + builder="A", + source_wallet="Alice", + destination_wallet="Bob", + token_id=2, + ) + + # Fail: Bob --A0--> Alice + with assert_run_failure(r'script reached FAILWITH instruction'): + transfer( + builder="A", + source_wallet="Bob", + destination_wallet="Alice", + token_id=0, + ) + + # Fail: Bob --A1--> Bob + with assert_run_failure(r'script reached FAILWITH instruction'): + transfer( + builder="A", + source_wallet="Bob", + destination_wallet="Bob", + token_id=1, + ) + + # Alice --A1--> Bob + transfer( + builder="A", + source_wallet="Alice", + destination_wallet="Bob", + token_id=1, + ) + + # Alice --A0--> Bob + transfer( + builder="A", + source_wallet="Alice", + destination_wallet="Bob", + token_id=0, + ) + + # Fail: Alice --A1--> Bob + with assert_run_failure(r'script reached FAILWITH instruction'): + transfer( + builder="A", + source_wallet="Alice", + destination_wallet="Bob", + token_id=1, + ) + + # Bob --A0--> Bob + transfer( + builder="A", + source_wallet="Bob", + destination_wallet="Bob", + token_id=0, + ) + + # Bob --A0--> + burn(builder="A", wallet="Bob", token_id=0) + + # Bob --A1--> + burn(builder="A", wallet="Bob", token_id=1) + + # Fail: Bob --B0--> + with assert_run_failure(r'script reached FAILWITH instruction'): + burn(builder="B", wallet="Bob", token_id=0) + + # Alice --B0--> + burn(builder="B", wallet="Alice", token_id=0) + + +ORIGINATE_BIG_MAP_FILE = path.join( + OPCODES_CONTRACT_PATH, 'originate_big_map.tz' +) + + +@pytest.mark.incremental +@pytest.mark.contract +@pytest.mark.regression +class TestContractBigMapOrigination: + def test_big_map_origination_literal(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + # originate a first version of the contract from a literal so + # that a big_map with id 0 exists + init_with_transfer( + client, + ORIGINATE_BIG_MAP_FILE, + '{Elt 0 0}', + 1000, + 'bootstrap1', + contract_name='originate_big_map_literal', + ) + + def test_big_map_origination_id(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + # originate again the same script from the big-map id 0 + with assert_run_failure(r'Unexpected forged value'): + init_with_transfer( + client, + ORIGINATE_BIG_MAP_FILE, + '0', + 1000, + 'bootstrap1', + contract_name='originate_big_map_id', + ) + + def test_big_map_origination_diff(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + + # originate again the same script from a big-diff + with assert_run_failure(r'Unexpected forged value'): + init_with_transfer( + client, + ORIGINATE_BIG_MAP_FILE, + 'Pair 0 {Elt 1 (Some 4)}', + 1000, + 'bootstrap1', + contract_name='originate_big_map_diff', + ) + + def test_big_map_transfer_id(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + # call the first contract, passing an id as parameter + with assert_run_failure(r'Unexpected forged value'): + client.call( + source='bootstrap1', + destination='originate_big_map_literal', + args=['--arg', '0'], + ) + + def test_big_map_transfer_diff(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + # call the first contract, passing a diff as parameter + with assert_run_failure(r'Unexpected forged value'): + client.call( + source='bootstrap1', + destination='originate_big_map_literal', + args=['--arg', 'Pair 0 {Elt 1 (Some 4)}'], + ) + + +@pytest.mark.incremental +@pytest.mark.slow +@pytest.mark.contract +@pytest.mark.regression +class TestContractOnchainLevel: + """Onchain tests for LEVEL.""" + + # This test needs to be in a separate class to not depend on the number + # of operations happening before + + def test_level(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + + init_with_transfer( + client, + path.join(OPCODES_CONTRACT_PATH, 'level.tz'), + '9999999', + 100, + 'bootstrap1', + ) + bake(client) + client.transfer( + 500, "bootstrap1", 'level', ['-arg', 'Unit', '--burn-cap', '10'] + ) + bake(client) + level = client.get_level() + slevel = str(level) + assert_storage_contains(client, 'level', slevel) + bake(client) + bake(client) + # checks the storage hasn't changed even though the current level has + assert_storage_contains(client, 'level', slevel) + # Run again to check the storage gets updated + client.transfer( + 500, "bootstrap1", 'level', ['-arg', 'Unit', '--burn-cap', '10'] + ) + bake(client) + assert_storage_contains(client, 'level', str(level + 3)) diff --git a/tests_python/tests_011/test_contract_opcodes.py b/tests_python/tests_011/test_contract_opcodes.py new file mode 100644 index 000000000000..bcb81de070ec --- /dev/null +++ b/tests_python/tests_011/test_contract_opcodes.py @@ -0,0 +1,1905 @@ +from os import path + +import pytest + +from tools.client_regression import ClientRegression +from tools.constants import IDENTITIES +from tools.utils import ( + assert_run_failure, + assert_run_script_failwith, + assert_run_script_success, +) +from .contract_paths import MINI_SCENARIOS_CONTRACT_PATH, OPCODES_CONTRACT_PATH + + +PUBLIC_KEY = IDENTITIES['bootstrap1']['public'] + + +@pytest.mark.slow +@pytest.mark.contract +@pytest.mark.regression +class TestContractOpcodes: + """Tests for individual opcodes that do not require origination.""" + + @pytest.mark.parametrize( + "contract,param,storage,expected", + [ # FORMAT: assert_output contract_file storage input expected_result + # TODO add tests for map_car.tz, subset.tz + # NB: noop.tz is tested in test_basic.sh + ('cons.tz', '{}', '10', '{ 10 }'), + ('cons.tz', '{ 10 }', '-5', '{ -5 ; 10 }'), + ('cons.tz', '{ -5 ; 10 }', '99', '{ 99 ; -5 ; 10 }'), + # Tests on Options + ('none.tz', 'Some 10', 'Unit', 'None'), + ('ret_int.tz', 'None', 'Unit', '(Some 300)'), + # Map block on lists + ('list_map_block.tz', '{0}', '{}', '{}'), + ( + 'list_map_block.tz', + '{0}', + '{ 1 ; 1 ; 1 ; 1 }', + '{ 1 ; 2 ; 3 ; 4 }', + ), + ( + 'list_map_block.tz', + '{0}', + '{ 1 ; 2 ; 3 ; 0 }', + '{ 1 ; 3 ; 5 ; 3 }', + ), + # Reverse a list + ('reverse.tz', '{""}', '{}', '{}'), + ( + 'reverse.tz', + '{""}', + '{ "c" ; "b" ; "a" }', + '{ "a" ; "b" ; "c" }', + ), + # Reverse using LOOP_LEFT + ('loop_left.tz', '{""}', '{}', '{}'), + ( + 'loop_left.tz', + '{""}', + '{ "c" ; "b" ; "a" }', + '{ "a" ; "b" ; "c" }', + ), + # Identity on strings + ('str_id.tz', 'None', '"Hello"', '(Some "Hello")'), + ('str_id.tz', 'None', '"abcd"', '(Some "abcd")'), + # Slice strings + ('slice.tz', 'None', 'Pair 0 0', 'None'), + ('slice.tz', 'Some "Foo"', 'Pair 10 5', 'None'), + ('slice.tz', 'Some "Foo"', 'Pair 0 0', '(Some "")'), + ('slice.tz', 'Some "Foo"', 'Pair 0 10', 'None'), + ('slice.tz', 'Some "Foo"', 'Pair 0 2', '(Some "Fo")'), + ('slice.tz', 'Some "Foo"', 'Pair 1 3', 'None'), + ('slice.tz', 'Some "Foo"', 'Pair 1 1', '(Some "o")'), + # Stress-test the failure case of slice for a + # non-trivial gas consumption + ( + 'slice.tz', + 'Some' + '"' + 'Foo' * 2000 + '"', + 'Pair 1 10000', + 'None', + ), + # Slice bytes + ('slice_bytes.tz', 'None', 'Pair 0 1', 'None'), + ('slice_bytes.tz', 'Some 0xaabbcc', 'Pair 0 0', '(Some 0x)'), + ('slice_bytes.tz', 'Some 0xaabbcc', 'Pair 0 1', '(Some 0xaa)'), + ('slice_bytes.tz', 'Some 0xaabbcc', 'Pair 1 1', '(Some 0xbb)'), + ('slice_bytes.tz', 'Some 0xaabbcc', 'Pair 1 2', '(Some 0xbbcc)'), + ('slice_bytes.tz', 'Some 0xaabbcc', 'Pair 1 3', 'None'), + ('slice_bytes.tz', 'Some 0xaabbcc', 'Pair 1 1', '(Some 0xbb)'), + # Stress-test the failure case of slice for a + # non-trivial gas consumption + ( + 'slice_bytes.tz', + 'Some 0x' + 'aabbcc' * 2000, + 'Pair 1 10000', + 'None', + ), + # Identity on pairs + ( + 'pair_id.tz', + 'None', + '(Pair True False)', + '(Some (Pair True False))', + ), + ( + 'pair_id.tz', + 'None', + '(Pair False True)', + '(Some (Pair False True))', + ), + ( + 'pair_id.tz', + 'None', + '(Pair True True)', + '(Some (Pair True True))', + ), + ( + 'pair_id.tz', + 'None', + '(Pair False False)', + '(Some (Pair False False))', + ), + # Tests CAR and CDR instructions + ('car.tz', '0', '(Pair 34 17)', '34'), + ('cdr.tz', '0', '(Pair 34 17)', '17'), + # Logical not + ('not.tz', 'None', 'True', '(Some False)'), + ('not.tz', 'None', 'False', '(Some True)'), + # Logical and + ('and.tz', 'None', '(Pair False False)', '(Some False)'), + ('and.tz', 'None', '(Pair False True)', '(Some False)'), + ('and.tz', 'None', '(Pair True False)', '(Some False)'), + ('and.tz', 'None', '(Pair True True)', '(Some True)'), + # Logical or + ('or.tz', 'None', '(Pair False False)', '(Some False)'), + ('or.tz', 'None', '(Pair False True)', '(Some True)'), + ('or.tz', 'None', '(Pair True False)', '(Some True)'), + ('or.tz', 'None', '(Pair True True)', '(Some True)'), + # Logical and + ('and_logical_1.tz', 'False', "(Pair False False)", 'False'), + ('and_logical_1.tz', 'False', "(Pair False True)", 'False'), + ('and_logical_1.tz', 'False', "(Pair True False)", 'False'), + ('and_logical_1.tz', 'False', "(Pair True True)", 'True'), + # Binary and + ('and_binary.tz', 'Unit', 'Unit', 'Unit'), + # Binary or + ('or_binary.tz', 'None', '(Pair 4 8)', '(Some 12)'), + ('or_binary.tz', 'None', '(Pair 0 8)', '(Some 8)'), + ('or_binary.tz', 'None', '(Pair 8 0)', '(Some 8)'), + ('or_binary.tz', 'None', '(Pair 15 4)', '(Some 15)'), + ('or_binary.tz', 'None', '(Pair 14 1)', '(Some 15)'), + ('or_binary.tz', 'None', '(Pair 7 7)', '(Some 7)'), + # Binary not + ('not_binary.tz', 'None', '(Left 0)', '(Some -1)'), + ('not_binary.tz', 'None', '(Left 8)', '(Some -9)'), + ('not_binary.tz', 'None', '(Left 7)', '(Some -8)'), + ('not_binary.tz', 'None', '(Left -9)', '(Some 8)'), + ('not_binary.tz', 'None', '(Left -8)', '(Some 7)'), + ('not_binary.tz', 'None', '(Right 0)', '(Some -1)'), + ('not_binary.tz', 'None', '(Right 8)', '(Some -9)'), + ('not_binary.tz', 'None', '(Right 7)', '(Some -8)'), + # XOR + ( + 'xor.tz', + 'None', + 'Left (Pair False False)', + '(Some (Left False))', + ), + ('xor.tz', 'None', 'Left (Pair False True)', '(Some (Left True))'), + ('xor.tz', 'None', 'Left (Pair True False)', '(Some (Left True))'), + ('xor.tz', 'None', 'Left (Pair True True)', '(Some (Left False))'), + ('xor.tz', 'None', 'Right (Pair 0 0)', '(Some (Right 0))'), + ('xor.tz', 'None', 'Right (Pair 0 1)', '(Some (Right 1))'), + ('xor.tz', 'None', 'Right (Pair 1 0)', '(Some (Right 1))'), + ('xor.tz', 'None', 'Right (Pair 1 1)', '(Some (Right 0))'), + ('xor.tz', 'None', 'Right (Pair 42 21)', '(Some (Right 63))'), + ('xor.tz', 'None', 'Right (Pair 42 63)', '(Some (Right 21))'), + # test shifts: LSL & LSR + ('shifts.tz', 'None', '(Left (Pair 8 1))', '(Some 16)'), + ('shifts.tz', 'None', '(Left (Pair 0 0))', '(Some 0)'), + ('shifts.tz', 'None', '(Left (Pair 0 1))', '(Some 0)'), + ('shifts.tz', 'None', '(Left (Pair 1 2))', '(Some 4)'), + ('shifts.tz', 'None', '(Left (Pair 15 2))', '(Some 60)'), + ('shifts.tz', 'None', '(Right (Pair 8 1))', '(Some 4)'), + ('shifts.tz', 'None', '(Right (Pair 0 0))', '(Some 0)'), + ('shifts.tz', 'None', '(Right (Pair 0 1))', '(Some 0)'), + ('shifts.tz', 'None', '(Right (Pair 1 2))', '(Some 0)'), + ('shifts.tz', 'None', '(Right (Pair 15 2))', '(Some 3)'), + # Concatenate all strings of a list into one string + ('concat_list.tz', '""', '{ "a" ; "b" ; "c" }', '"abc"'), + ('concat_list.tz', '""', '{}', '""'), + ( + 'concat_list.tz', + '""', + '{ "Hello" ; " " ; "World" ; "!" }', + '"Hello World!"', + ), + # Concatenate the bytes in storage with all bytes in the given list + ('concat_hello_bytes.tz', '{}', '{ 0xcd }', '{ 0xffcd }'), + ('concat_hello_bytes.tz', '{}', '{}', '{}'), + ( + 'concat_hello_bytes.tz', + '{}', + '{ 0xab ; 0xcd }', + '{ 0xffab ; 0xffcd }', + ), + # Identity on lists + ( + 'list_id.tz', + '{""}', + '{ "1" ; "2" ; "3" }', + '{ "1" ; "2" ; "3" }', + ), + ('list_id.tz', '{""}', '{}', '{}'), + ( + 'list_id.tz', + '{""}', + '{ "a" ; "b" ; "c" }', + '{ "a" ; "b" ; "c" }', + ), + ( + 'list_id_map.tz', + '{""}', + '{ "1" ; "2" ; "3" }', + '{ "1" ; "2" ; "3" }', + ), + ('list_id_map.tz', '{""}', '{}', '{}'), + ( + 'list_id_map.tz', + '{""}', + '{ "a" ; "b" ; "c" }', + '{ "a" ; "b" ; "c" }', + ), + # Identity on maps + ('map_id.tz', '{}', '{ Elt 0 1 }', '{ Elt 0 1 }'), + ('map_id.tz', '{}', '{ Elt 0 0 }', '{ Elt 0 0 }'), + ( + 'map_id.tz', + '{}', + '{ Elt 0 0 ; Elt 3 4 }', + '{ Elt 0 0 ; Elt 3 4 }', + ), + # Memberships in maps + ( + 'map_mem_nat.tz', + '(Pair { Elt 0 1 } None)', + '1', + '(Pair { Elt 0 1 } (Some False))', + ), + ('map_mem_nat.tz', '(Pair {} None)', '1', '(Pair {} (Some False))'), + ( + 'map_mem_nat.tz', + '(Pair { Elt 1 0 } None)', + '1', + '(Pair { Elt 1 0 } (Some True))', + ), + ( + 'map_mem_nat.tz', + '(Pair { Elt 1 4 ; Elt 2 11 } None)', + '1', + '(Pair { Elt 1 4 ; Elt 2 11 } (Some True))', + ), + ( + 'map_mem_nat.tz', + '(Pair { Elt 1 4 ; Elt 2 11 } None)', + '2', + '(Pair { Elt 1 4 ; Elt 2 11 } (Some True))', + ), + ( + 'map_mem_nat.tz', + '(Pair { Elt 1 4 ; Elt 2 11 } None)', + '3', + '(Pair { Elt 1 4 ; Elt 2 11 } (Some False))', + ), + ( + 'map_mem_string.tz', + '(Pair { Elt "foo" 1 } None)', + '"bar"', + '(Pair { Elt "foo" 1 } (Some False))', + ), + ( + 'map_mem_string.tz', + '(Pair {} None)', + '"bar"', + '(Pair {} (Some False))', + ), + ( + 'map_mem_string.tz', + '(Pair { Elt "foo" 0 } None)', + '"foo"', + '(Pair { Elt "foo" 0 } (Some True))', + ), + ( + 'map_mem_string.tz', + '(Pair { Elt "bar" 4 ; Elt "foo" 11 } None)', + '"foo"', + '(Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True))', + ), + ( + 'map_mem_string.tz', + '(Pair { Elt "bar" 4 ; Elt "foo" 11 } None)', + '"bar"', + '(Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some True))', + ), + ( + 'map_mem_string.tz', + '(Pair { Elt "bar" 4 ; Elt "foo" 11 } None)', + '"baz"', + '(Pair { Elt "bar" 4 ; Elt "foo" 11 } (Some False))', + ), + # Mapping over maps + ('map_map.tz', '{}', '10', '{}'), + ('map_map.tz', '{ Elt "foo" 1 }', '10', '{ Elt "foo" 11 }'), + ( + 'map_map.tz', + '{ Elt "bar" 5 ; Elt "foo" 1 }', + '15', + '{ Elt "bar" 20 ; Elt "foo" 16 }', + ), + # Memberships in big maps + ( + 'big_map_mem_nat.tz', + '(Pair { Elt 0 1 } None)', + '1', + '(Pair 4 (Some False))', + ), + ( + 'big_map_mem_nat.tz', + '(Pair {} None)', + '1', + '(Pair 4 (Some False))', + ), + ( + 'big_map_mem_nat.tz', + '(Pair { Elt 1 0 } None)', + '1', + '(Pair 4 (Some True))', + ), + ( + 'big_map_mem_nat.tz', + '(Pair { Elt 1 4 ; Elt 2 11 } None)', + '1', + '(Pair 4 (Some True))', + ), + ( + 'big_map_mem_nat.tz', + '(Pair { Elt 1 4 ; Elt 2 11 } None)', + '2', + '(Pair 4 (Some True))', + ), + ( + 'big_map_mem_nat.tz', + '(Pair { Elt 1 4 ; Elt 2 11 } None)', + '3', + '(Pair 4 (Some False))', + ), + ( + 'big_map_mem_string.tz', + '(Pair { Elt "foo" 1 } None)', + '"bar"', + '(Pair 4 (Some False))', + ), + ( + 'big_map_mem_string.tz', + '(Pair {} None)', + '"bar"', + '(Pair 4 (Some False))', + ), + ( + 'big_map_mem_string.tz', + '(Pair { Elt "foo" 0 } None)', + '"foo"', + '(Pair 4 (Some True))', + ), + ( + 'big_map_mem_string.tz', + '(Pair { Elt "bar" 4 ; Elt "foo" 11 } None)', + '"foo"', + '(Pair 4 (Some True))', + ), + ( + 'big_map_mem_string.tz', + '(Pair { Elt "bar" 4 ; Elt "foo" 11 } None)', + '"bar"', + '(Pair 4 (Some True))', + ), + ( + 'big_map_mem_string.tz', + '(Pair { Elt "bar" 4 ; Elt "foo" 11 } None)', + '"baz"', + '(Pair 4 (Some False))', + ), + # Memberships in big maps + ( + 'big_map_mem_nat.tz', + '(Pair { Elt 0 1 } None)', + '1', + '(Pair 4 (Some False))', + ), + ( + 'big_map_mem_nat.tz', + '(Pair {} None)', + '1', + '(Pair 4 (Some False))', + ), + ( + 'big_map_mem_nat.tz', + '(Pair { Elt 1 0 } None)', + '1', + '(Pair 4 (Some True))', + ), + ( + 'big_map_mem_nat.tz', + '(Pair { Elt 1 4 ; Elt 2 11 } None)', + '1', + '(Pair 4 (Some True))', + ), + ( + 'big_map_mem_nat.tz', + '(Pair { Elt 1 4 ; Elt 2 11 } None)', + '2', + '(Pair 4 (Some True))', + ), + ( + 'big_map_mem_nat.tz', + '(Pair { Elt 1 4 ; Elt 2 11 } None)', + '3', + '(Pair 4 (Some False))', + ), + # Identity on sets + ('set_id.tz', '{}', '{ "a" ; "b" ; "c" }', '{ "a" ; "b" ; "c" }'), + ('set_id.tz', '{}', '{}', '{}'), + ('set_id.tz', '{}', '{ "asdf" ; "bcde" }', '{ "asdf" ; "bcde" }'), + # List concat + ('list_concat.tz', '"abc"', '{ "d" ; "e" ; "f" }', '"abcdef"'), + ('list_concat.tz', '"abc"', '{}', '"abc"'), + ( + 'list_concat_bytes.tz', + '0x00ab', + '{ 0xcd ; 0xef ; 0x00 }', + '0x00abcdef00', + ), + ( + 'list_concat_bytes.tz', + '0x', + '{ 0x00 ; 0x11 ; 0x00 }', + '0x001100', + ), + ('list_concat_bytes.tz', '0xabcd', '{}', '0xabcd'), + ('list_concat_bytes.tz', '0x', '{}', '0x'), + # List iter + ('list_iter.tz', '0', '{ 10 ; 2 ; 1 }', '20'), + ('list_iter.tz', '0', '{ 3 ; 6 ; 9 }', '162'), + # List size + ('list_size.tz', '111', '{}', '0'), + ('list_size.tz', '111', '{ 1 }', '1'), + ('list_size.tz', '111', '{ 1 ; 2 ; 3 }', '3'), + ('list_size.tz', '111', '{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }', '6'), + # Set member -- set is in storage + ( + 'set_member.tz', + '(Pair {} None)', + '"Hi"', + '(Pair {} (Some False))', + ), + ( + 'set_member.tz', + '(Pair { "Hi" } None)', + '"Hi"', + '(Pair { "Hi" } (Some True))', + ), + ( + 'set_member.tz', + '(Pair { "Hello" ; "World" } None)', + '""', + '(Pair { "Hello" ; "World" } (Some False))', + ), + # Set size + ('set_size.tz', '111', '{}', '0'), + ('set_size.tz', '111', '{ 1 }', '1'), + ('set_size.tz', '111', '{ 1 ; 2 ; 3 }', '3'), + ('set_size.tz', '111', '{ 1 ; 2 ; 3 ; 4 ; 5 ; 6 }', '6'), + # Set iter + ('set_iter.tz', '111', '{}', '0'), + ('set_iter.tz', '111', '{ 1 }', '1'), + ('set_iter.tz', '111', '{ -100 ; 1 ; 2 ; 3 }', '-94'), + # Map size + ('map_size.tz', '111', '{}', '0'), + ('map_size.tz', '111', '{ Elt "a" 1 }', '1'), + ( + 'map_size.tz', + '111', + '{ Elt "a" 1 ; Elt "b" 2 ; Elt "c" 3 }', + '3', + ), + ( + 'map_size.tz', + '111', + '{ Elt "a" 1 ; Elt "b" 2 ; Elt "c" 3 ; \ + Elt "d" 4 ; Elt "e" 5 ; Elt "f" 6 }', + '6', + ), + # Contains all elements -- does the second list contain + # all of the same elements as the first one? I'm ignoring + # element multiplicity + ('contains_all.tz', 'None', '(Pair {} {})', '(Some True)'), + ( + 'contains_all.tz', + 'None', + '(Pair { "c" } { "B" })', + '(Some False)', + ), + ( + 'contains_all.tz', + 'None', + '(Pair { "A" } { "B" })', + '(Some False)', + ), + ( + 'contains_all.tz', + 'None', + '(Pair { "B" } { "B" })', + '(Some True)', + ), + ( + 'contains_all.tz', + 'None', + '(Pair { "B" ; "C" ; "asdf" } { "B" ; "B" ; "asdf" ; "C" })', + '(Some True)', + ), + ( + 'contains_all.tz', + 'None', + '(Pair { "B" ; "B" ; "asdf" ; "C" } { "B" ; "C" ; "asdf" })', + '(Some True)', + ), + # Concatenate the string in storage with all strings in + # the given list + ('concat_hello.tz', '{}', '{ "World!" }', '{ "Hello World!" }'), + ('concat_hello.tz', '{}', '{}', '{}'), + ( + 'concat_hello.tz', + '{}', + '{ "test1" ; "test2" }', + '{ "Hello test1" ; "Hello test2" }', + ), + # Create an empty map and add a string to it + ('empty_map.tz', '{}', 'Unit', '{ Elt "hello" "world" }'), + # Get the value stored at the given key in the map + ( + 'get_map_value.tz', + '(Pair None { Elt "hello" "hi" })', + '"hello"', + '(Pair (Some "hi") { Elt "hello" "hi" })', + ), + ( + 'get_map_value.tz', + '(Pair None { Elt "hello" "hi" })', + '""', + '(Pair None { Elt "hello" "hi" })', + ), + ( + 'get_map_value.tz', + '(Pair None { Elt "1" "one" ; \ + Elt "2" "two" })', + '"1"', + '(Pair (Some "one") { Elt "1" "one" ; Elt "2" "two" })', + ), + # Get and update the value stored at the given key in the map + ( + 'get_and_update_map.tz', + '(Pair None {})', + '"hello"', + '(Pair None {})', + ), + ( + 'get_and_update_map.tz', + '(Pair (Some 4) {})', + '"hello"', + '(Pair None { Elt "hello" 4 })', + ), + ( + 'get_and_update_map.tz', + '(Pair None { Elt "hello" 4 })', + '"hello"', + '(Pair (Some 4) {})', + ), + ( + 'get_and_update_map.tz', + '(Pair (Some 5) { Elt "hello" 4 })', + '"hello"', + '(Pair (Some 4) { Elt "hello" 5 })', + ), + ( + 'get_and_update_map.tz', + '(Pair (Some 5) { Elt "hello" 4 })', + '"hi"', + '(Pair None { Elt "hello" 4 ; Elt "hi" 5 })', + ), + ( + 'get_and_update_map.tz', + '(Pair None { Elt "1" 1 ; \ + Elt "2" 2 })', + '"1"', + '(Pair (Some 1) { Elt "2" 2 })', + ), + ( + 'get_and_update_map.tz', + '(Pair None { Elt "1" 1 ; \ + Elt "2" 2 })', + '"1"', + '(Pair (Some 1) { Elt "2" 2 })', + ), + # Map iter + ( + 'map_iter.tz', + '(Pair 0 0)', + '{ Elt 0 100 ; Elt 2 100 }', + '(Pair 2 200)', + ), + ( + 'map_iter.tz', + '(Pair 0 0)', + '{ Elt 1 1 ; Elt 2 100 }', + '(Pair 3 101)', + ), + # Return True if True branch of if was taken and False otherwise + ('if.tz', 'None', 'True', '(Some True)'), + ('if.tz', 'None', 'False', '(Some False)'), + # Generate a pair of or types + ('left_right.tz', '(Left "X")', '(Left True)', '(Right True)'), + ('left_right.tz', '(Left "X")', '(Right "a")', '(Left "a")'), + # Reverse a list + ('reverse_loop.tz', '{""}', '{}', '{}'), + ( + 'reverse_loop.tz', + '{""}', + '{ "c" ; "b" ; "a" }', + '{ "a" ; "b" ; "c" }', + ), + # Exec concat contract + ('exec_concat.tz', '"?"', '""', '"_abc"'), + ('exec_concat.tz', '"?"', '"test"', '"test_abc"'), + # Get the current balance of the contract + ('balance.tz', '111', 'Unit', '4000000000000'), + # Get the current level of the block + # Test the produced variable annotation + ('level.tz', '111', 'Unit', '1'), + # Test addition and subtraction on tez + ( + 'tez_add_sub.tz', + 'None', + '(Pair 2000000 1000000)', + '(Some (Pair 3000000 1000000))', + ), + ( + 'tez_add_sub.tz', + 'None', + '(Pair 2310000 1010000)', + '(Some (Pair 3320000 1300000))', + ), + # Test various additions + ('add.tz', 'Unit', 'Unit', 'Unit'), + # Test ABS + ('abs.tz', 'Unit', '12039123919239192312931', 'Unit'), + ('abs.tz', 'Unit', '0', 'Unit'), + ('abs.tz', 'Unit', '948', 'Unit'), + # Test INT + ('int.tz', 'None', '0', '(Some 0)'), + ('int.tz', 'None', '1', '(Some 1)'), + ('int.tz', 'None', '9999', '(Some 9999)'), + # Test DIP + ('dip.tz', '(Pair 0 0)', '(Pair 15 9)', '(Pair 15 24)'), + ('dip.tz', '(Pair 0 0)', '(Pair 1 1)', '(Pair 1 2)'), + # Test get first element of list + ('first.tz', '111', '{ 1 ; 2 ; 3 ; 4 }', '1'), + ('first.tz', '111', '{ 4 }', '4'), + # Hash input string + # Test assumed to be correct -- hash is based on encoding of AST + ( + 'hash_string.tz', + '0x00', + '"abcdefg"', + '0x46fdbcb4ea4eadad5615c' + + 'daa17d67f783e01e21149ce2b27de497600b4cd8f4e', + ), + ( + 'hash_string.tz', + '0x00', + '"12345"', + '0xb4c26c20de52a4eaf0d8a34' + + '0db47ad8cb1e74049570859c9a9a3952b204c772f', + ), + # IF_SOME + ('if_some.tz', '"?"', '(Some "hello")', '"hello"'), + ('if_some.tz', '"?"', 'None', '""'), + # Tests the SET_CAR and SET_CDR instructions + ('set_car.tz', '(Pair "hello" 0)', '"world"', '(Pair "world" 0)'), + ('set_car.tz', '(Pair "hello" 0)', '"abc"', '(Pair "abc" 0)'), + ('set_car.tz', '(Pair "hello" 0)', '""', '(Pair "" 0)'), + ('set_cdr.tz', '(Pair "hello" 0)', '1', '(Pair "hello" 1)'), + ('set_cdr.tz', '(Pair "hello" 500)', '3', '(Pair "hello" 3)'), + ('set_cdr.tz', '(Pair "hello" 7)', '100', '(Pair "hello" 100)'), + # Convert a public key to a public key hash + ( + 'hash_key.tz', + 'None', + '"edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav"', + '(Some "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx")', + ), + ( + 'hash_key.tz', + 'None', + '"edpkuJqtDcA2m2muMxViSM47MPsGQzmyjnNTawUPqR8vZTAMcx61ES"', + '(Some "tz1XPTDmvT3vVE5Uunngmixm7gj7zmdbPq6k")', + ), + # Test timestamp operations + ( + 'add_timestamp_delta.tz', + 'None', + '(Pair 100 100)', + '(Some "1970-01-01T00:03:20Z")', + ), + ( + 'add_timestamp_delta.tz', + 'None', + '(Pair 100 -100)', + '(Some "1970-01-01T00:00:00Z")', + ), + ( + 'add_timestamp_delta.tz', + 'None', + '(Pair "1970-01-01T00:00:00Z" 0)', + '(Some "1970-01-01T00:00:00Z")', + ), + ( + 'add_delta_timestamp.tz', + 'None', + '(Pair 100 100)', + '(Some "1970-01-01T00:03:20Z")', + ), + ( + 'add_delta_timestamp.tz', + 'None', + '(Pair -100 100)', + '(Some "1970-01-01T00:00:00Z")', + ), + ( + 'add_delta_timestamp.tz', + 'None', + '(Pair 0 "1970-01-01T00:00:00Z")', + '(Some "1970-01-01T00:00:00Z")', + ), + ( + 'sub_timestamp_delta.tz', + '111', + '(Pair 100 100)', + '"1970-01-01T00:00:00Z"', + ), + ( + 'sub_timestamp_delta.tz', + '111', + '(Pair 100 -100)', + '"1970-01-01T00:03:20Z"', + ), + ( + 'sub_timestamp_delta.tz', + '111', + '(Pair 100 2000000000000000000)', + '-1999999999999999900', + ), + ('diff_timestamps.tz', '111', '(Pair 0 0)', '0'), + ('diff_timestamps.tz', '111', '(Pair 0 1)', '-1'), + ('diff_timestamps.tz', '111', '(Pair 1 0)', '1'), + ( + 'diff_timestamps.tz', + '111', + '(Pair "1970-01-01T00:03:20Z" "1970-01-01T00:00:00Z")', + '200', + ), + # Test pack/unpack + ( + 'packunpack_rev.tz', + 'Unit', + '(Pair -1 (Pair 1 (Pair "foobar" (Pair 0x00AABBCC (Pair 1000 ' + + '(Pair False (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ' + + '(Pair "2019-09-09T08:35:33Z" ' + + '"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5"))))))))', + 'Unit', + ), + ( + 'packunpack_rev.tz', + 'Unit', + '(Pair -1 (Pair 1 (Pair "foobar" (Pair 0x00AABBCC (Pair 1000 ' + + '(Pair False (Pair "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5" ' + + '(Pair "2019-09-09T08:35:33Z" ' + + '"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5"))))))))', + 'Unit', + ), + ( + 'packunpack_rev_cty.tz', + 'Unit', + '(Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9' + + 'sDVC9yav" (Pair Unit (Pair "edsigthTzJ8X7MPmNeEwybRAv' + + 'dxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8' + + 'V2w8ayB5dMJzrYCHhD8C7" (Pair (Some "edsigthTzJ8X7MPmN' + + 'eEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5' + + 'CwoNgqs8V2w8ayB5dMJzrYCHhD8C7") (Pair { Unit } (Pair' + + ' { True } (Pair (Pair 19 10) (Pair (Left "tz1cxcwwnz' + + 'ENRdhe2Kb8ZdTrdNy4bFNyScx5") (Pair { Elt 0 "foo" ; El' + + 't 1 "bar" } { PACK } )))))))))', + 'Unit', + ), + ( + 'packunpack_rev_cty.tz', + 'Unit', + '(Pair "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9' + + 'sDVC9yav" (Pair Unit (Pair "edsigthTzJ8X7MPmNeEwybRAv' + + 'dxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8' + + 'V2w8ayB5dMJzrYCHhD8C7" (Pair None (Pair { } (Pair {' + + ' } (Pair (Pair 40 -10) (Pair (Right "2019-09-09T08:' + + '35:33Z") (Pair { } { DUP ; DROP ; PACK } )))))))))', + 'Unit', + ), + # Test EDIV on nat and int + ( + 'ediv.tz', + '(Pair None None None None)', + '(Pair 10 -3)', + '(Pair (Some (Pair -3 1)) (Some (Pair 3 1)) ' + + '(Some (Pair -3 1)) (Some (Pair 3 1)))', + ), + ( + 'ediv.tz', + '(Pair None None None None)', + '(Pair 10 0)', + '(Pair None None None None)', + ), + ( + 'ediv.tz', + '(Pair None None None None)', + '(Pair -8 2)', + '(Pair (Some (Pair -4 0)) (Some (Pair -4 0)) ' + + '(Some (Pair 4 0)) (Some (Pair 4 0)))', + ), + # Test EDIV on mutez + ( + 'ediv_mutez.tz', + '(Left None)', + '(Pair 10 (Left 10))', + '(Left (Some (Pair 1 0)))', + ), + ( + 'ediv_mutez.tz', + '(Left None)', + '(Pair 10 (Left 3))', + '(Left (Some (Pair 3 1)))', + ), + ( + 'ediv_mutez.tz', + '(Left None)', + '(Pair 10 (Left 0))', + '(Left None)', + ), + ( + 'ediv_mutez.tz', + '(Left None)', + '(Pair 10 (Right 10))', + '(Right (Some (Pair 1 0)))', + ), + ( + 'ediv_mutez.tz', + '(Left None)', + '(Pair 10 (Right 3))', + '(Right (Some (Pair 3 1)))', + ), + ( + 'ediv_mutez.tz', + '(Left None)', + '(Pair 10 (Right 0))', + '(Right None)', + ), + ( + 'ediv_mutez.tz', + '(Left None)', + '(Pair 5 (Right 10))', + '(Right (Some (Pair 0 5)))', + ), + # Test compare + ('compare.tz', 'Unit', 'Unit', 'Unit'), + # Test comparison combinators: + # GT, GE, LT, LE, NEQ, EQ + ( + 'comparisons.tz', + '{}', + '{ -9999999; -1 ; 0 ; 1 ; 9999999 }', + '{ ' + '{ False ; False ; False ; True ; True } ;' + "\n" + ' { False ; False ; True ; True ; True } ;' + "\n" + ' { True ; True ; False ; False ; False } ;' + "\n" + ' { True ; True ; True ; False ; False } ;' + "\n" + ' { True ; True ; False ; True ; True } ;' + "\n" + ' { False ; False ; True ; False ; False }' + ' }', + ), + # Test ADDRESS + ( + 'address.tz', + 'None', + '"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5"', + '(Some "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5")', + ), + # Test (CONTRACT unit) + ( + 'contract.tz', + 'Unit', + '"tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5"', + 'Unit', + ), + # Test create_contract + ( + 'create_contract.tz', + 'None', + 'Unit', + '(Some "KT1Mjjcb6tmSsLm7Cb3DSQszePjfchPM4Uxm")', + ), + # Test multiplication - success case (no overflow) + # Failure case is tested in m̀ul_overflow.tz + ('mul.tz', 'Unit', 'Unit', 'Unit'), + # Test NEG + ('neg.tz', '0', '(Left 2)', '-2'), + ('neg.tz', '0', '(Right 2)', '-2'), + ('neg.tz', '0', '(Left 0)', '0'), + ('neg.tz', '0', '(Right 0)', '0'), + ('neg.tz', '0', '(Left -2)', '2'), + # Test DIGN, DUGN, DROPN, DIPN + ('dign.tz', '0', '(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)', '5'), + ('dugn.tz', '0', '(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)', '1'), + ('dropn.tz', '0', '(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)', '5'), + ('dipn.tz', '0', '(Pair (Pair (Pair (Pair 1 2) 3) 4) 5)', '6'), + # Test DIGN 17 times. + ( + 'dig_eq.tz', + 'Unit', + '(Pair 17 (Pair 16 (Pair 15 (Pair 14 (Pair 13 (Pair 12' + + ' (Pair 11 (Pair 10 (Pair 9 (Pair 8 (Pair 7 (Pair 6 (P' + + 'air 5 (Pair 4 (Pair 3 (Pair 2 1))))))))))))))))', + 'Unit', + ), + ( + 'dig_eq.tz', + 'Unit', + '(Pair 2 (Pair 3 (Pair 12 (Pair 16 (Pair 10 (Pair 14 (' + + 'Pair 19 (Pair 9 (Pair 18 (Pair 6 (Pair 8 (Pair 11 (Pa' + + 'ir 4 (Pair 13 (Pair 15 (Pair 5 1))))))))))))))))', + 'Unit', + ), + # Test Partial Exec + ('pexec.tz', '14', '38', '52'), + ('pexec_2.tz', "{ 0 ; 1 ; 2 ; 3}", '4', "{ 0 ; 7 ; 14 ; 21 }"), + # Test CHAIN_ID + ('chain_id_store.tz', 'None', 'Unit', '(Some "NetXdQprcVkpaWU")'), + ( + 'chain_id_store.tz', + '(Some 0x7a06a770)', + 'Unit', + '(Some "NetXdQprcVkpaWU")', + ), + ( + 'chain_id_store.tz', + '(Some "NetXdQprcVkpaWU")', + 'Unit', + '(Some "NetXdQprcVkpaWU")', + ), + # Test SELF + ('self_with_entrypoint.tz', 'Unit', 'Left (Left 0)', 'Unit'), + ('self_with_default_entrypoint.tz', 'Unit', 'Unit', 'Unit'), + # Test SELF_ADDRESS + ('self_address.tz', 'Unit', 'Unit', 'Unit'), + # Test UNPAIR + ('unpair.tz', 'Unit', 'Unit', 'Unit'), + # Test VOTING_POWER + ( + 'voting_power.tz', + '(Pair 0 0)', + f'"{PUBLIC_KEY}"', + '(Pair 500 2500)', + ), + # Test KECCAK + ( + 'keccak.tz', + 'None', + f'0x{b"Hello, world!".hex()}', + '(Some 0xb6e16d27ac5ab427a7f68900ac5559ce2' + + '72dc6c37c82b3e052246c82244c50e4)', + ), + # Test SHA3 + ( + 'sha3.tz', + 'None', + f'0x{b"Hello, world!".hex()}', + '(Some 0xf345a219da005ebe9c1a1eaad97bbf38' + + 'a10c8473e41d0af7fb617caa0c6aa722)', + ), + # Test COMBs + ('comb.tz', '(Pair 0 0 0)', 'Unit', '(Pair 1 2 3)'), + ('uncomb.tz', '0', '(Pair 1 4 2)', '142'), + ('comb-get.tz', 'Unit', '(Pair 1 4 2 Unit)', 'Unit'), + ('comb-set.tz', '(Pair 1 4 2 Unit)', 'Unit', '(Pair 2 12 8 Unit)'), + ( + 'comb-set-2.tz', + 'None', + '(Pair 1 4 2 Unit)', + '(Some (Pair 2 4 "toto" 0x01))', + ), + # Test DUP n + ('dup-n.tz', 'Unit', 'Unit', 'Unit'), + # Test Sapling + ('sapling_empty_state.tz', '{}', 'Unit', '0'), + # Test building Fr element from nat. + # The initial storage is dropped then any value is valid. + # Random values can be generated using the following OCaml program. + # let r = Bls12_381.Fr.(random ()) in + # let x = Bls12_381.Fr.random () in + # Printf.printf "Param = (Pair %s 0x%s). Result = 0x%s" + # (Bls12_381.Fr.to_string r) + # (Hex.(show (of_bytes (Bls12_381.Fr.to_bytes x)))) + # (Hex.(show (of_bytes (Bls12_381.Fr.(to_bytes (mul r x)))))) + ( + 'bls12_381_fr_z_nat.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '0', + '0x00000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_fr_z_nat.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '1', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + # The natural is 1 in Fr. + ( + 'bls12_381_fr_z_nat.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '524358751751261904794477405081859658376905525005276378226036' + '58699938581184514', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_fr_z_nat.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '2', + '0x02000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_fr_z_nat.tz', + '0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c' + + '5401f', + '3364491663033484423912034843462646864953418677080980279259699' + + '6408934105684394', + '0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca91' + + '8a221', + ), + ( + 'bls12_381_fr_z_nat.tz', + '0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfc' + + 'dbe3f', + '2262028481792278490256467246991799299632821112798447289749169' + + '8543785655336309', + '0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe6' + + '77c62', + ), + ( + 'bls12_381_fr_z_nat.tz', + '0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7' + + 'fcf2d', + '1718009307279455880617703583439793220591757728848373965251048' + + '2486858834123369', + '0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddec' + + 'bf221', + ), + # Same than previous one, but we added the order to the natural to + # verify the modulo is computed correctly and the multiplication + # computation does not fail. + ( + 'bls12_381_fr_z_nat.tz', + '0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7' + + 'fcf2d', + '69615968247920749285624776342583898043608129789011377475114141' + + '186797415307882', + '0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddec' + + 'bf221', + ), + # Test with (positive and negative) integers. + ( + 'bls12_381_fr_z_int.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '0', + '0x00000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_fr_z_int.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '1', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_fr_z_int.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '524358751751261904794477405081859658376905525005276378226036' + '58699938581184514', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_fr_z_int.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '2', + '0x02000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_fr_z_int.tz', + '0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c' + + '5401f', + '3364491663033484423912034843462646864953418677080980279259699' + + '6408934105684394', + '0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca91' + + '8a221', + ), + ( + 'bls12_381_fr_z_int.tz', + '0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfc' + + 'dbe3f', + '2262028481792278490256467246991799299632821112798447289749169' + + '8543785655336309', + '0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe6' + + '77c62', + ), + ( + 'bls12_381_fr_z_int.tz', + '0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7' + + 'fcf2d', + '1718009307279455880617703583439793220591757728848373965251048' + + '2486858834123369', + '0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddec' + + 'bf221', + ), + # Same than previous one, but we added the order to the natural to + # verify the modulo is computed correctly and the multiplication + # computation does not fail. + ( + 'bls12_381_fr_z_int.tz', + '0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7' + + 'fcf2d', + '69615968247920749285624776342583898043608129789011377475114141' + + '186797415307882', + '0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddec' + + 'bf221', + ), + ( + 'bls12_381_fr_z_int.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '-1', + '0x00000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953' + + 'a7ed73', + ), + ( + 'bls12_381_fr_z_int.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '-42', + '0xd7fffffffefffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a' + + '7ed73', + ), + # Test building Fr element from nat. + # The initial storage is dropped then any value is valid. + # Random values can be generated using the following OCaml program. + # let r = Bls12_381.Fr.(random ()) in + # let x = Bls12_381.Fr.random () in + # Printf.printf "Param = (Pair %s 0x%s). Result = 0x%s" + # (Bls12_381.Fr.to_string r) + # (Hex.(show (of_bytes (Bls12_381.Fr.to_bytes x)))) + # (Hex.(show (of_bytes (Bls12_381.Fr.(to_bytes (mul r x)))))) + ( + 'bls12_381_z_fr_nat.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '0', + '0x00000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_z_fr_nat.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '1', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + # The natural is 1 in Fr. + ( + 'bls12_381_z_fr_nat.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '524358751751261904794477405081859658376905525005276378226036' + '58699938581184514', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_z_fr_nat.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '2', + '0x02000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_z_fr_nat.tz', + '0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c' + + '5401f', + '3364491663033484423912034843462646864953418677080980279259699' + + '6408934105684394', + '0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca91' + + '8a221', + ), + ( + 'bls12_381_z_fr_nat.tz', + '0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfc' + + 'dbe3f', + '2262028481792278490256467246991799299632821112798447289749169' + + '8543785655336309', + '0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe6' + + '77c62', + ), + ( + 'bls12_381_z_fr_nat.tz', + '0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7' + + 'fcf2d', + '1718009307279455880617703583439793220591757728848373965251048' + + '2486858834123369', + '0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddec' + + 'bf221', + ), + # Same than previous one, but we added the order to the natural to + # verify the modulo is computed correctly and the multiplication + # computation does not fail. + ( + 'bls12_381_z_fr_nat.tz', + '0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7' + + 'fcf2d', + '69615968247920749285624776342583898043608129789011377475114141' + + '186797415307882', + '0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddec' + + 'bf221', + ), + # Test with (positive and negative) integers. + ( + 'bls12_381_z_fr_int.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '0', + '0x00000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_z_fr_int.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '1', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_z_fr_int.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '524358751751261904794477405081859658376905525005276378226036' + '58699938581184514', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_z_fr_int.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '2', + '0x02000000000000000000000000000000000000000000000000000000000' + + '00000', + ), + ( + 'bls12_381_z_fr_int.tz', + '0x5b0ecd0fa853810e356f1eb79721e80b30510fcc3a455f4fc02fdd9a90c' + + '5401f', + '3364491663033484423912034843462646864953418677080980279259699' + + '6408934105684394', + '0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca91' + + '8a221', + ), + ( + 'bls12_381_z_fr_int.tz', + '0x4147a5ad0a633e4880d2296f08ec5c12d03e3fa4a6b49ecbd16a30a3cfc' + + 'dbe3f', + '2262028481792278490256467246991799299632821112798447289749169' + + '8543785655336309', + '0x4e387e0ebfb3d1633153c195036e0c0b672955c4a0e420f93ec20a76fe6' + + '77c62', + ), + ( + 'bls12_381_z_fr_int.tz', + '0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7' + + 'fcf2d', + '1718009307279455880617703583439793220591757728848373965251048' + + '2486858834123369', + '0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddec' + + 'bf221', + ), + ( + 'bls12_381_z_fr_int.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '-1', + '0x00000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953' + + 'a7ed73', + ), + ( + 'bls12_381_z_fr_int.tz', + '0x01000000000000000000000000000000000000000000000000000000000' + + '00000', + '-42', + '0xd7fffffffefffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a' + + '7ed73', + ), + # Same than previous one, but we added the order to the natural to + # verify the modulo is computed correctly and the multiplication + # computation does not fail. + ( + 'bls12_381_z_fr_int.tz', + '0x8578be1766f92cd82c5e5135c374a03a8562e263ea953a3f9711b0153b7' + + 'fcf2d', + '69615968247920749285624776342583898043608129789011377475114141' + + '186797415307882', + '0xfaa60dacea8e26112e524d379720fe4f95fbc5a26f1b1a67e229e26ddec' + + 'bf221', + ), + # Test Fr bytes can be pushed without being padded + ( + 'add_bls12_381_fr.tz', + 'None', + 'Pair 0x00 0x00', + '(Some 0x000000000000000000000000000000000000000000000000000000' + + '0000000000)', + ), + ( + 'add_bls12_381_fr.tz', + 'None', + 'Pair 0x01 0x00', + '(Some 0x010000000000000000000000000000000000000000000000000000' + + '0000000000)', + ), + ( + 'add_bls12_381_fr.tz', + 'None', + 'Pair 0x010000 0x00', + '(Some 0x010000000000000000000000000000000000000000000000000000' + + '0000000000)', + ), + ( + 'add_bls12_381_fr.tz', + 'None', + 'Pair 0x010000 0x010000', + '(Some 0x020000000000000000000000000000000000000000000000000000' + + '0000000000)', + ), + ( + 'bls12_381_fr_push_bytes_not_padded.tz', + 'None', + 'Unit', + '(Some 0x000000000000000000000000000000000000000000000000000000' + + '0000000000)', + ), + ( + 'bls12_381_fr_push_nat.tz', + 'None', + 'Unit', + '(Some 0x100000000000000000000000000000000000000000000000000000' + + '0000000000)', + ), + ('bls12_381_fr_to_int.tz', '0', '0x00', '0'), + ('bls12_381_fr_to_int.tz', '0', '0x01', '1'), + # Generated using + # let r = Bls12_381.Fr.(random ()) in + # Printf.printf "%s = 0x%s" + # (Bls12_381.Fr.to_string r) + # (Hex.(show (of_bytes (Bls12_381.Fr.to_bytes r)))) + ( + 'bls12_381_fr_to_int.tz', + '0', + '0x28db8e57af88d9576acd181b89f24e50a89a6423f939026ed91349fc9' + + 'af16c27', + '1783268807701357777652478449446472851821391321341286660405373' + + '5695200962927400', + ), + ( + 'bls12_381_fr_to_int.tz', + '0', + '0xb9e8abf8dc324a010007addde986fe0f7c81fab16d26819d0534b7691c' + + '0b0719', + '1132026582925658583078152196614952946047676740821044523890286' + + '9222031333517497', + ), + # Mutez -> Fr + ( + 'mutez_to_bls12_381_fr.tz', + '0x02', + '16', + '0x100000000000000000000000000000000000000000000000000000000' + + '0000000', + ), + # # would fail if trying to PACK mutez and UNPACK to Fr + ( + 'mutez_to_bls12_381_fr.tz', + '0x00', + '257', + '0x010100000000000000000000000000000000000000000000000000000' + + '0000000', + ), + # Fr -> Mutez + ('bls12_381_fr_to_mutez.tz', '0', '0x10', '16'), + ], + ) + def test_contract_input_output( + self, + client_regtest: ClientRegression, + contract: str, + param: str, + storage: str, + expected: str, + ): + client = client_regtest + assert contract.endswith( + '.tz' + ), "test contract should have .tz extension" + contract = path.join(OPCODES_CONTRACT_PATH, contract) + run_script_res = client.run_script( + contract, param, storage, trace_stack=True + ) + assert run_script_res.storage == expected + + @pytest.mark.parametrize("balance", [0, 0.000001, 0.5, 1, 5, 1000, 8e12]) + def test_balance(self, client_regtest: ClientRegression, balance: float): + client = client_regtest + contract = 'balance.tz' + contract = path.join(OPCODES_CONTRACT_PATH, contract) + run_script_res = client.run_script( + contract, '0', 'Unit', balance=balance, trace_stack=True + ) + assert run_script_res.storage == str(int(1000000 * balance)) + + @pytest.mark.parametrize( + "contract,param,storage,expected,big_map_diff", + [ # FORMAT: assert_output contract_file storage input expected_result + # expected_diffs + # Get the value stored at the given key in the big map + ( + 'get_big_map_value.tz', + '(Pair { Elt "hello" "hi" } None)', + '"hello"', + '(Pair 4 (Some "hi"))', + [ + ["New map(4) of type (big_map string string)"], + ['Set map(4)["hello"] to "hi"'], + ], + ), + ( + 'get_big_map_value.tz', + '(Pair { Elt "hello" "hi" } None)', + '""', + '(Pair 4 None)', + [ + ["New map(4) of type (big_map string string)"], + ['Set map(4)["hello"] to "hi"'], + ], + ), + ( + 'get_big_map_value.tz', + '(Pair { Elt "1" "one" ; Elt "2" "two" } None)', + '"1"', + '(Pair 4 (Some "one"))', + [ + ["New map(4) of type (big_map string string)"], + ['Set map(4)["2"] to "two"'], + ['Set map(4)["1"] to "one"'], + ], + ), + # Test updating big maps + ( + 'update_big_map.tz', + '(Pair { Elt "1" "one" ; Elt "2" "two" } Unit)', + '{}', + '(Pair 4 Unit)', + [ + ["New map(4) of type (big_map string string)"], + ['Set map(4)["2"] to "two"'], + ['Set map(4)["1"] to "one"'], + ], + ), + ( + 'update_big_map.tz', + '(Pair { Elt "1" "one" ; Elt "2" "two" } Unit)', + '{ Elt "1" (Some "two") }', + '(Pair 4 Unit)', + [ + ["New map(4) of type (big_map string string)"], + ['Set map(4)["2"] to "two"'], + ['Set map(4)["1"] to "two"'], + ], + ), + ( + 'update_big_map.tz', + '(Pair { Elt "1" "one" ; Elt "2" "two" } Unit)', + '{ Elt "3" (Some "three") }', + '(Pair 4 Unit)', + [ + ["New map(4) of type (big_map string string)"], + ['Set map(4)["2"] to "two"'], + ['Set map(4)["3"] to "three"'], + ['Set map(4)["1"] to "one"'], + ], + ), + ( + 'update_big_map.tz', + '(Pair { Elt "1" "one" ; Elt "2" "two" } Unit)', + '{ Elt "3" None }', + '(Pair 4 Unit)', + [ + ["New map(4) of type (big_map string string)"], + ['Set map(4)["2"] to "two"'], + ['Unset map(4)["3"]'], + ['Set map(4)["1"] to "one"'], + ], + ), + ( + 'update_big_map.tz', + '(Pair { Elt "1" "one" ; Elt "2" "two" } Unit)', + '{ Elt "2" None }', + '(Pair 4 Unit)', + [ + ["New map(4) of type (big_map string string)"], + ['Unset map(4)["2"]'], + ['Set map(4)["1"] to "one"'], + ], + ), + ( + 'update_big_map.tz', + '(Pair { Elt "1" "one" ; Elt "2" "two" } Unit)', + '{ Elt "1" (Some "two") }', + '(Pair 4 Unit)', + [ + ["New map(4) of type (big_map string string)"], + ['Set map(4)["2"] to "two"'], + ['Set map(4)["1"] to "two"'], + ], + ), + # test the GET_AND_UPDATE instruction on big maps + # Get and update the value stored at the given key in the map + ( + 'get_and_update_big_map.tz', + '(Pair None {})', + '"hello"', + '(Pair None 4)', + [ + ["New map(4) of type (big_map string nat)"], + ['Unset map(4)["hello"]'], + ], + ), + ( + 'get_and_update_big_map.tz', + '(Pair (Some 4) {})', + '"hello"', + '(Pair None 4)', + [ + ["New map(4) of type (big_map string nat)"], + ['Set map(4)["hello"] to 4'], + ], + ), + ( + 'get_and_update_big_map.tz', + '(Pair None { Elt "hello" 4 })', + '"hello"', + '(Pair (Some 4) 4)', + [ + ["New map(4) of type (big_map string nat)"], + ['Unset map(4)["hello"]'], + ], + ), + ( + 'get_and_update_big_map.tz', + '(Pair (Some 5) { Elt "hello" 4 })', + '"hello"', + '(Pair (Some 4) 4)', + [ + ["New map(4) of type (big_map string nat)"], + ['Set map(4)["hello"] to 5'], + ], + ), + ( + 'get_and_update_big_map.tz', + '(Pair (Some 5) { Elt "hello" 4 })', + '"hi"', + '(Pair None 4)', + [ + ["New map(4) of type (big_map string nat)"], + ['Set map(4)["hello"] to 4'], + ['Set map(4)["hi"] to 5'], + ], + ), + ( + 'get_and_update_big_map.tz', + '(Pair None { Elt "1" 1 ; \ + Elt "2" 2 })', + '"1"', + '(Pair (Some 1) 4)', + [ + ["New map(4) of type (big_map string nat)"], + ['Set map(4)["2"] to 2'], + ['Unset map(4)["1"]'], + ], + ), + ( + 'get_and_update_big_map.tz', + '(Pair None { Elt "1" 1 ; \ + Elt "2" 2 })', + '"1"', + '(Pair (Some 1) 4)', + [ + ["New map(4) of type (big_map string nat)"], + ['Set map(4)["2"] to 2'], + ['Unset map(4)["1"]'], + ], + ), + ], + ) + def test__big_map_contract_io( + self, + client_regtest: ClientRegression, + contract: str, + param: str, + storage: str, + expected: str, + big_map_diff: str, + ): + client = client_regtest + contract = path.join(OPCODES_CONTRACT_PATH, contract) + run_script_res = client.run_script( + contract, param, storage, trace_stack=True + ) + assert run_script_res.storage == expected + assert run_script_res.big_map_diff == big_map_diff + + @pytest.mark.parametrize( + "storage,param,expected,big_map_diff", + [ # test swap + ( + '(Left (Pair { Elt "1" "one" } { Elt "2" "two" }))', + '(Left Unit)', + '(Left (Pair 4 5))', + [ + ['New map(5) of type (big_map string string)'], + ['Set map(5)["1"] to "one"'], + ['New map(4) of type (big_map string string)'], + ['Set map(4)["2"] to "two"'], + ], + ), + # test reset with new map + ( + '(Left (Pair { Elt "1" "one" } { Elt "2" "two" }))', + '(Right (Left (Left (Pair { Elt "3" "three" } ' + + '{ Elt "4" "four" }))))', + '(Left (Pair 4 5))', + [ + ['New map(5) of type (big_map string string)'], + ['Set map(5)["4"] to "four"'], + ['New map(4) of type (big_map string string)'], + ['Set map(4)["3"] to "three"'], + ], + ), + # test reset to unit + ( + '(Left (Pair { Elt "1" "one" } { Elt "2" "two" }))', + '(Right (Left (Right Unit)))', + '(Right Unit)', + [], + ), + # test import to big_map + ( + '(Right Unit)', + '(Right (Right (Left (Pair { Pair "foo" "bar" } ' + + '{ Pair "gaz" "baz" }) )))', + '(Left (Pair 4 5))', + [ + ['New map(5) of type (big_map string string)'], + ['Set map(5)["gaz"] to "baz"'], + ['New map(4) of type (big_map string string)'], + ['Set map(4)["foo"] to "bar"'], + ], + ), + # test add to big_map + ( + '(Left (Pair { Elt "1" "one" } { Elt "2" "two" }) )', + '(Right (Right (Right (Left { Pair "3" "three" }))))', + '(Left (Pair 4 5))', + [ + ['New map(5) of type (big_map string string)'], + ['Set map(5)["2"] to "two"'], + ['New map(4) of type (big_map string string)'], + ['Set map(4)["3"] to "three"'], + ['Set map(4)["1"] to "one"'], + ], + ), + # test remove from big_map + ( + '(Left (Pair { Elt "1" "one" } { Elt "2" "two" }))', + '(Right (Right (Right (Right { "1" }))))', + '(Left (Pair 4 5))', + [ + ['New map(5) of type (big_map string string)'], + ['Set map(5)["2"] to "two"'], + ['New map(4) of type (big_map string string)'], + ['Unset map(4)["1"]'], + ], + ), + ], + ) + def test_big_map_magic( + self, + client_regtest: ClientRegression, + storage: str, + param: str, + expected: str, + big_map_diff: str, + ): + client = client_regtest + contract = path.join(MINI_SCENARIOS_CONTRACT_PATH, 'big_map_magic.tz') + run_script_res = client.run_script( + contract, storage, param, trace_stack=True + ) + assert run_script_res.storage == expected + assert run_script_res.big_map_diff == big_map_diff + + def test_packunpack(self, client_regtest: ClientRegression): + """Test PACK/UNPACK and binary format.""" + client = client_regtest + assert_run_script_success( + client, + path.join(OPCODES_CONTRACT_PATH, 'packunpack.tz'), + 'Unit', + '(Pair (Pair (Pair "toto" {3;7;9;1}) {1;2;3}) ' + + '0x05070707070100000004746f746f020000000800030' + + '007000900010200000006000100020003)', + ) + assert_run_script_failwith( + client, + path.join(OPCODES_CONTRACT_PATH, 'packunpack.tz'), + 'Unit', + '(Pair (Pair (Pair "toto" {3;7;9;1}) {1;2;3}) ' + + '0x05070707070100000004746f746f020000000800030' + + '0070009000102000000060001000200030004)', + ) + + def test_check_signature(self, client_regtest: ClientRegression): + client = client_regtest + sig = ( + 'edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt' + + '9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF' + ) + assert_run_script_success( + client, + path.join(OPCODES_CONTRACT_PATH, 'check_signature.tz'), + f'(Pair "{sig}" "hello")', + '"edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav"', + ) + assert_run_script_failwith( + client, + path.join(OPCODES_CONTRACT_PATH, 'check_signature.tz'), + f'(Pair "{sig}" "abcd")', + '"edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav"', + ) + + def test_hash_consistency_michelson_cli( + self, client_regtest: ClientRegression + ): + client = client_regtest + hash_result = client.hash( + '(Pair 22220000000 (Pair "2017-12-13T04:49:00Z" 034))', + '(pair mutez (pair timestamp int))', + ).blake2b + hash_contract = path.join( + OPCODES_CONTRACT_PATH, 'hash_consistency_checker.tz' + ) + run_script_res = client.run_script( + hash_contract, + '0x00', + '(Pair 22220000000 (Pair "2017-12-13T04:49:00Z" 034))', + ) + assert run_script_res.storage == hash_result + run_script_res = client.run_script( + hash_contract, + '0x00', + '(Pair 22220000000 (Pair "2017-12-13T04:49:00Z" 034))', + ) + assert run_script_res.storage == hash_result + + @pytest.mark.parametrize( + "contract,param,storage", + [ # FORMAT: assert_output contract_file storage input + # Test overflow in shift + ('shifts.tz', 'None', '(Left (Pair 1 257))'), + ('shifts.tz', 'None', '(Left (Pair 123 257))'), + ('shifts.tz', 'None', '(Right (Pair 1 257))'), + ('shifts.tz', 'None', '(Right (Pair 123 257))'), + ('mul_overflow.tz', 'Unit', 'Left Unit'), + ('mul_overflow.tz', 'Unit', 'Right Unit'), + ], + ) + def test_arithmetic_overflow( + self, + client_regtest_scrubbed: ClientRegression, + contract: str, + param: str, + storage: str, + ): + client = client_regtest_scrubbed + contract = path.join(OPCODES_CONTRACT_PATH, contract) + + with assert_run_failure(r'unexpected arithmetic overflow'): + client.run_script(contract, param, storage) + + @pytest.mark.skip(reason="Bug in annotation system") + def test_fails_annotated_set_car_cdr( + self, client_regtest: ClientRegression + ): + """Tests the SET_CAR and SET_CDR instructions.""" + client = client_regtest + + with assert_run_failure(r'The two annotations do not match'): + client.run_script( + path.join(OPCODES_CONTRACT_PATH, 'set_car.tz'), + '(Pair %wrong %field "hello" 0)', + '""', + ) + + @pytest.mark.parametrize( + "contract,storage,param,expected", + [ # FORMAT: assert_output contract_file storage input expected_result + # Mapping over maps + ('map_map_sideeffect.tz', '(Pair {} 0)', '10', '(Pair {} 0)'), + ( + 'map_map_sideeffect.tz', + '(Pair { Elt "foo" 1 } 1)', + '10', + '(Pair { Elt "foo" 11 } 11)', + ), + ( + 'map_map_sideeffect.tz', + '(Pair { Elt "bar" 5 ; Elt "foo" 1 } 6)', + '15', + '(Pair { Elt "bar" 20 ; Elt "foo" 16 } 36)', + ), + ], + ) + def test_map_map_sideeffect( + self, + client_regtest: ClientRegression, + contract: str, + param: str, + storage: str, + expected: str, + ): + client = client_regtest + contract = path.join(OPCODES_CONTRACT_PATH, contract) + run_script_res = client.run_script(contract, storage, param) + assert run_script_res.storage == expected diff --git a/tests_python/tests_011/test_cors.py b/tests_python/tests_011/test_cors.py new file mode 100644 index 000000000000..80b064285d86 --- /dev/null +++ b/tests_python/tests_011/test_cors.py @@ -0,0 +1,47 @@ +import pytest +from daemons.node import Node +from launchers.sandbox import Sandbox +from tools import utils + + +@pytest.fixture(scope="class") +def node(sandbox: Sandbox): + """Launches one node in sandbox mode (genesis)""" + sandbox.add_node(0, params=['--cors-origin', '*']) + yield sandbox.node(0) + + +class TestCors: + def test_preflight(self, node: Node): + origin = 'localhost' + port = node.rpc_port + headers = { + 'Origin': origin, + 'Access-Control-Request-Method': 'GET', + 'Access-Control-Request-Headers': 'Content-Type', + } + res = utils.rpc( + origin, + port, + 'options', + '/chains/main/blocks/head/header/shell', + headers=headers, + ) + print(res.headers) + assert res.headers["access-control-allow-origin"] == '*' + assert res.headers["access-control-allow-methods"] == 'GET' + assert res.headers["access-control-allow-headers"] == 'Content-Type' + + def test_request(self, node: Node): + origin = 'localhost' + port = node.rpc_port + headers = {'Origin': origin, 'Content-Type': 'application/json'} + res = utils.rpc( + origin, + port, + 'get', + '/chains/main/blocks/head/header/shell', + headers=headers, + ) + print(res.headers) + assert res.headers["access-control-allow-origin"] == '*' diff --git a/tests_python/tests_011/test_crypto.py b/tests_python/tests_011/test_crypto.py new file mode 100644 index 000000000000..995b48fdf617 --- /dev/null +++ b/tests_python/tests_011/test_crypto.py @@ -0,0 +1,47 @@ +from random import getrandbits + +from os import path + +import pytest + +from Crypto.Hash import keccak, SHA3_256 + +from .contract_paths import OPCODES_CONTRACT_PATH + +RANDOM_ITERATIONS = 50 + +HASH_FUNCTIONS = { + "keccak": lambda bytes_to_hash: keccak.new(digest_bits=256) + .update(bytes_to_hash) + .hexdigest(), + "sha3": lambda bytes_to_hash: SHA3_256.new() + .update(bytes_to_hash) + .hexdigest(), +} + + +@pytest.fixture(params=HASH_FUNCTIONS.keys()) +def hash_fun(request): + return request.param + + +@pytest.mark.contract +class TestHash: + @pytest.mark.parametrize( + "bytes_to_hash", + [b"", b"a"] + + [ + getrandbits(bytes_length * 8).to_bytes( + bytes_length, byteorder="little" + ) + for bytes_length in [32] + for _ in range(RANDOM_ITERATIONS) + ], + ) + def test_hash(self, client, hash_fun, bytes_to_hash): + contract = path.join(OPCODES_CONTRACT_PATH, f"{hash_fun}.tz") + + hashed = HASH_FUNCTIONS[hash_fun](bytes_to_hash) + arg = f"0x{bytes_to_hash.hex()}" + result = client.run_script(contract, "None", arg) + assert result.storage == f"(Some 0x{hashed})" diff --git a/tests_python/tests_011/test_double_endorsement.py b/tests_python/tests_011/test_double_endorsement.py new file mode 100644 index 000000000000..0e3ee5c1e818 --- /dev/null +++ b/tests_python/tests_011/test_double_endorsement.py @@ -0,0 +1,115 @@ +import pytest +from tools import utils, constants +from launchers.sandbox import Sandbox +from . import protocol + +NUM_NODES = 3 +PATH_FORGE_OPERATION = '/chains/main/blocks/head/helpers/forge/operations' + + +@pytest.mark.multinode +@pytest.mark.incremental +class TestDoubleEndorsement: + """Constructs a double endorsement and builds evidence.""" + + def test_init(self, sandbox: Sandbox): + for i in range(NUM_NODES): + sandbox.add_node(i, params=constants.NODE_PARAMS) + protocol.activate(sandbox.client(0), activate_in_the_past=True) + utils.bake(sandbox.client(0)) + + def test_level(self, sandbox: Sandbox): + level = 2 + for client in sandbox.all_clients(): + assert utils.check_level(client, level) + + def test_terminate_nodes_1_and_2(self, sandbox: Sandbox): + sandbox.node(1).terminate() + sandbox.node(2).terminate() + + def test_bake_node_0(self, sandbox: Sandbox): + """Client 0 bakes block A at level 3, not communicated to 1 and 2 + Inject an endorsement to ensure a different hash""" + sandbox.client(0).endorse('bootstrap1') + utils.bake(sandbox.client(0)) + + def test_endorse_node_0(self, sandbox: Sandbox, session: dict): + """bootstrap1 builds an endorsement for block A""" + client = sandbox.client(0) + client.endorse('bootstrap1') + mempool = client.get_mempool() + endorsement = mempool['applied'][0] + session['endorsement1'] = endorsement + + def test_terminate_node_0(self, sandbox: Sandbox): + sandbox.node(0).terminate() + + def test_restart_node_2(self, sandbox: Sandbox): + sandbox.node(2).run() + assert sandbox.client(2).check_node_listening() + + def test_bake_node_2(self, sandbox: Sandbox): + """Client 2 bakes block B at level 3, not communicated to 0 and 1""" + utils.bake(sandbox.client(2)) + + def test_endorse_node_2(self, sandbox: Sandbox, session: dict): + """bootstrap1 builds an endorsement for block B""" + client = sandbox.client(2) + client.endorse('bootstrap1') + mempool = client.get_mempool() + endorsement = mempool['applied'][0] + session['endorsement2'] = endorsement + sandbox.client(2).endorse('bootstrap2') + + def test_restart_all(self, sandbox: Sandbox): + sandbox.node(0).run() + sandbox.node(1).run() + sandbox.client(0).check_node_listening() + sandbox.client(1).check_node_listening() + + def test_check_level(self, sandbox: Sandbox): + """All nodes are at level 3, head is either block A or B""" + level = 3 + for client in sandbox.all_clients(): + assert utils.check_level(client, level) + + def test_forge_accusation(self, sandbox: Sandbox, session: dict): + """Forge and inject a double endorsement evidence operation""" + client = sandbox.client(1) + head_hash = client.get_head()['hash'] + + # Extract the `Endorsement` ops and the slot out of the + # `Endorsement_with_slot` ops + endorsement1 = session['endorsement1']['contents'][0]['endorsement'] + endorsement2 = session['endorsement2']['contents'][0]['endorsement'] + slot = session['endorsement1']['contents'][0]['slot'] + + operation = { + 'branch': head_hash, + 'contents': [ + { + 'kind': 'double_endorsement_evidence', + 'op1': endorsement1, + 'op2': endorsement2, + 'slot': slot, + } + ], + } + + operation_hex_string = client.rpc( + 'post', PATH_FORGE_OPERATION, data=operation + ) + assert isinstance(operation_hex_string, str) + sender_sk_long = constants.IDENTITIES['bootstrap1']['secret'] + sender_sk = sender_sk_long[len('unencrypted:') :] + signed_op = utils.sign_operation(operation_hex_string, sender_sk) + op_hash = client.rpc('post', 'injection/operation', signed_op) + assert isinstance(op_hash, str) + session['operation'] = op_hash + + def test_operation_applied(self, sandbox: Sandbox, session: dict): + """Check operation is in mempool""" + client = sandbox.client(1) + assert utils.check_mempool_contains_operations( + client, [session['operation']] + ) diff --git a/tests_python/tests_011/test_fa12.py b/tests_python/tests_011/test_fa12.py new file mode 100644 index 000000000000..cb004ccb22f4 --- /dev/null +++ b/tests_python/tests_011/test_fa12.py @@ -0,0 +1,352 @@ +"""This file tests the tezos-client commands offering support for the +FA1.2 standard. Several implementations of the standard are tested.""" + +import json +import os +import pytest +from tools import utils +from tools.constants import IDENTITIES +from client.client import Client +from .contract_paths import CONTRACT_PATH + +BAKE_ARGS = ['--max-priority', '512', '--minimal-timestamp'] +BURN_CAP_ARGS = ['--burn-cap', '1.0'] + + +def reset_viewer(client: Client, contract: str): + args = ['--arg', '0'] + client.transfer(0.0, 'bootstrap2', contract, args) + client.bake('bootstrap5', BAKE_ARGS) + + +def check_expected_balance(client, token_contract, addr, expected): + bal = client.fa12_get_balance_offchain(token_contract, addr, []) + return bal.amount == expected + + +def check_expected_allowance(client, token_contract, src, dst, expected): + alw = client.fa12_get_allowance_offchain(token_contract, src, dst, []) + return alw.amount == expected + + +@pytest.fixture( + scope="class", + ids=[ + 'fa12_reference', + 'lqt_fa12', + ], + params=[ + ( + 'fa12_reference', + 'fa12_reference.tz', + lambda key: f'Pair {{}} (Pair "{key}" (Pair False 0))', + ), + ( + 'lqt_fa12', + 'lqt_fa12.mligo.tz', + lambda key: f'Pair {{}} {{}} "{key}" 0', + ), + ], +) +def token_contract(client: Client, session: dict, request): + (contract_alias, contract_path, init_fun) = request.param + + path = os.path.join(CONTRACT_PATH, 'mini_scenarios', contract_path) + identity = IDENTITIES['bootstrap2']['identity'] + init = init_fun(identity) + + utils.originate(client, session, path, init, 0, contract_alias) + + if contract_alias == 'fa12_reference': + identity = IDENTITIES['bootstrap2']['identity'] + param = f'(Pair "{identity}" 20000)' + args = [ + '--entrypoint', + 'mint', + '--arg', + param, + '--burn-cap', + '0.078', + ] + client.transfer(0, 'bootstrap2', contract_alias, args) + client.bake('bootstrap5', BAKE_ARGS) + elif contract_alias == 'lqt_fa12': + identity = IDENTITIES['bootstrap2']['identity'] + param = f'(Pair 20000 "{identity}")' + args = [ + '--entrypoint', + 'mintOrBurn', + '--arg', + param, + '--burn-cap', + '0.078', + ] + client.transfer(0, 'bootstrap2', contract_alias, args) + client.bake('bootstrap5', BAKE_ARGS) + + return contract_alias + + +@pytest.fixture(scope="class") +def view(client: Client, session: dict): + # Only deploy once, it can be used by any fa1.2 contract + contract_alias = 'nat-viewer' + args = ['--init', '0', '--burn-cap', '0.08'] + viewer = "parameter nat; storage nat; code { CAR; NIL operation; PAIR; }" + + origination = client.originate( + contract_alias, 0, 'bootstrap1', viewer, args + ) + session['contract'] = origination.contract + client.bake('bootstrap5', BAKE_ARGS) + return contract_alias + + +class TestFA12Basic: + def test_check_contract(self, client: Client, token_contract: str): + assert client.fa12_check(token_contract).check + + # NOTE: this test does not depend on the token_contract + # fixture (nor should it) + def test_check_contract_fail(self, client: Client, session: dict): + path = os.path.join(CONTRACT_PATH, 'entrypoints', 'manager.tz') + identity = IDENTITIES['bootstrap2']['identity'] + init = f'"{identity}"' + token_contract = 'manager-fail' + utils.originate(client, session, path, init, 0, token_contract) + + assert not client.fa12_check(token_contract).check + + def test_get_balance_offchain(self, client: Client, token_contract: str): + res = client.fa12_get_balance_offchain(token_contract, 'bootstrap2', []) + assert res.amount == 20000 + + def test_get_allowance_offchain(self, client: Client, token_contract: str): + res = client.fa12_get_allowance_offchain( + token_contract, 'bootstrap2', 'bootstrap3', [] + ) + assert res.amount == 0 + + def test_get_total_supply_offchain( + self, client: Client, token_contract: str + ): + res = client.fa12_get_total_supply_offchain(token_contract, []) + expected = 20000 + assert res.amount == expected + + def test_get_balance_callback( + self, client: Client, token_contract: str, view + ): + reset_viewer(client, view) + client.fa12_get_balance_callback( + token_contract, 'bootstrap2', view, BURN_CAP_ARGS + ) + client.bake('bootstrap5', BAKE_ARGS) + utils.assert_storage_contains(client, view, '20000') + + def test_get_allowance_callback( + self, client: Client, token_contract: str, view + ): + reset_viewer(client, view) + client.fa12_get_allowance_callback( + token_contract, 'bootstrap2', 'bootstrap3', view, BURN_CAP_ARGS + ) + client.bake('bootstrap5', BAKE_ARGS) + utils.assert_storage_contains(client, view, '0') + + def test_get_total_supply_callback( + self, client: Client, token_contract: str, view + ): + reset_viewer(client, view) + client.fa12_get_total_supply_callback( + token_contract, 'bootstrap2', view, BURN_CAP_ARGS + ) + client.bake('bootstrap5', BAKE_ARGS) + expected = '20000' + utils.assert_storage_contains(client, view, expected) + + +@pytest.mark.incremental +class TestFA12Incremental: + def test_transfer(self, client: Client, token_contract: str): + client.fa12_transfer( + token_contract, 100, 'bootstrap2', 'bootstrap3', BURN_CAP_ARGS + ) + client.bake('bootstrap5', BAKE_ARGS) + + assert check_expected_balance( + client, token_contract, 'bootstrap2', 19900 + ) and check_expected_balance(client, token_contract, 'bootstrap3', 100) + + def test_transfer_not_enough_balance( + self, client: Client, token_contract: str + ): + if token_contract == 'fa12_reference': + error_pattern = r'Not enough balance' + else: + error_pattern = '' + with utils.assert_run_failure(error_pattern): + client.fa12_transfer( + token_contract, 200, 'bootstrap3', 'bootstrap2', BURN_CAP_ARGS + ) + + def test_approve(self, client: Client, token_contract: str): + client.fa12_approve( + token_contract, 20, 'bootstrap2', 'bootstrap3', BURN_CAP_ARGS + ) + client.bake('bootstrap5', BAKE_ARGS) + + assert check_expected_allowance( + client, token_contract, 'bootstrap2', 'bootstrap3', 20 + ) + + def test_approve_unsafe_allowance_change( + self, client: Client, token_contract + ): + if token_contract == 'fa12_reference': + error_pattern = r'Unsafe allowance change' + else: + error_pattern = '' + with utils.assert_run_failure(error_pattern): + client.fa12_approve( + token_contract, 30, 'bootstrap2', 'bootstrap3', BURN_CAP_ARGS + ) + + def test_transfer_as(self, client: Client, token_contract: str): + client.fa12_transfer_as( + token_contract, + 10, + 'bootstrap2', + 'bootstrap3', + 'bootstrap3', + BURN_CAP_ARGS, + ) + client.bake('bootstrap5', BAKE_ARGS) + + assert ( + check_expected_balance(client, token_contract, 'bootstrap2', 19890) + and check_expected_balance( + client, token_contract, 'bootstrap3', 110 + ) + and check_expected_allowance( + client, token_contract, 'bootstrap2', 'bootstrap3', 10 + ) + ) + + def test_transfer_as_not_enough_allowance( + self, client: Client, token_contract + ): + if token_contract == 'fa12_reference': + error_pattern = r'Not enough allowance' + else: + error_pattern = '' + with utils.assert_run_failure(error_pattern): + client.fa12_transfer_as( + token_contract, + 20, + 'bootstrap2', + 'bootstrap3', + 'bootstrap3', + BURN_CAP_ARGS, + ) + + def test_multiple_transfers(self, client: Client, token_contract: str): + op1 = client.fa12_mk_batch_transfer('bootstrap4', token_contract, 100) + op2 = client.fa12_mk_batch_transfer('bootstrap5', token_contract, 10) + json_ops = json.dumps(op1 + op2, separators=(',', ':')) + client.fa12_multiple_tokens_transfers( + 'bootstrap2', json_ops, BURN_CAP_ARGS + ) + client.bake('bootstrap5', BAKE_ARGS) + + assert ( + check_expected_balance(client, token_contract, 'bootstrap2', 19780) + and check_expected_balance( + client, token_contract, 'bootstrap4', 100 + ) + and check_expected_balance(client, token_contract, 'bootstrap5', 10) + and check_expected_allowance( + client, token_contract, 'bootstrap2', 'bootstrap3', 10 + ) + ) + + def test_multiple_transfers_fail(self, client: Client, token_contract: str): + op1 = client.fa12_mk_batch_transfer('bootstrap4', token_contract, 100) + op2 = client.fa12_mk_batch_transfer( + 'bootstrap5', token_contract, 100000 + ) + json_ops = json.dumps(op1 + op2, separators=(',', ':')) + + bal_sender_before = client.fa12_get_balance_offchain( + token_contract, 'bootstrap2', [] + ) + bal_receiver1_before = client.fa12_get_balance_offchain( + token_contract, 'bootstrap4', [] + ) + bal_receiver2_before = client.fa12_get_balance_offchain( + token_contract, 'bootstrap5', [] + ) + + error_pattern = r'multiple transfers simulation failed' + with utils.assert_run_failure(error_pattern): + client.fa12_multiple_tokens_transfers( + 'bootstrap2', json_ops, BURN_CAP_ARGS + ) + + client.bake('bootstrap5', BAKE_ARGS) + + assert ( + check_expected_balance( + client, + token_contract, + 'bootstrap2', + bal_sender_before.amount, + ) + and check_expected_balance( + client, + token_contract, + 'bootstrap4', + bal_receiver1_before.amount, + ) + and check_expected_balance( + client, + token_contract, + 'bootstrap5', + bal_receiver2_before.amount, + ) + ) + + def test_multiple_transfers_as(self, client: Client, token_contract: str): + client.fa12_approve( + token_contract, 0, 'bootstrap2', 'bootstrap3', BURN_CAP_ARGS + ) + client.bake('bootstrap5', BAKE_ARGS) + + client.fa12_approve( + token_contract, 30, 'bootstrap2', 'bootstrap3', BURN_CAP_ARGS + ) + client.bake('bootstrap5', BAKE_ARGS) + check_allowance_before = check_expected_allowance( + client, token_contract, 'bootstrap2', 'bootstrap3', 30 + ) + + op1 = client.fa12_mk_batch_transfer('bootstrap4', token_contract, 10) + op2 = client.fa12_mk_batch_transfer('bootstrap5', token_contract, 20) + json_ops = json.dumps(op1 + op2, separators=(',', ':')) + + client.fa12_multiple_tokens_transfers_as( + 'bootstrap2', 'bootstrap3', json_ops, BURN_CAP_ARGS + ) + client.bake('bootstrap5', BAKE_ARGS) + + assert ( + check_expected_balance(client, token_contract, 'bootstrap2', 19750) + and check_expected_balance( + client, token_contract, 'bootstrap4', 110 + ) + and check_expected_balance(client, token_contract, 'bootstrap5', 30) + and check_allowance_before + and check_expected_allowance( + client, token_contract, 'bootstrap2', 'bootstrap3', 0 + ) + ) diff --git a/tests_python/tests_011/test_forge_block.py b/tests_python/tests_011/test_forge_block.py new file mode 100755 index 000000000000..b931cf986537 --- /dev/null +++ b/tests_python/tests_011/test_forge_block.py @@ -0,0 +1,46 @@ +import datetime +import pytest +from tools import constants +from tools.constants import PROTO_DEMO_NOOPS +from launchers.sandbox import Sandbox + + +@pytest.mark.slow +@pytest.mark.incremental +class TestForgeBlock: + """ Check that a block more than 5 seconds in the future is rejected """ + + def test_setup_network(self, sandbox: Sandbox): + sandbox.add_node(1, params=constants.NODE_PARAMS) + + def test_protocol_exists(self, sandbox: Sandbox): + client = sandbox.client(1) + protocols = client.list_protocols() + assert PROTO_DEMO_NOOPS in protocols + + def test_activate_proto_demo_time_shifted_ok(self, sandbox: Sandbox): + parameters = {} # type: dict + delta = datetime.timedelta(seconds=5) + sandbox.client(1).activate_protocol_json( + PROTO_DEMO_NOOPS, + parameters, + key='activator', + timestamp=(datetime.datetime.utcnow() + delta).strftime( + "%Y-%m-%dT%H:%M:%SZ" + ), + fitness='1', + ) + + @pytest.mark.xfail + def test_activate_proto_demo_time_shifted_ko(self, sandbox: Sandbox): + parameters = {} # type: dict + delta = datetime.timedelta(seconds=30) + sandbox.client(1).activate_protocol_json( + PROTO_DEMO_NOOPS, + parameters, + key='activator', + timestamp=(datetime.datetime.utcnow() + delta).strftime( + "%Y-%m-%dT%H:%M:%SZ" + ), + fitness='1', + ) diff --git a/tests_python/tests_011/test_fork.py b/tests_python/tests_011/test_fork.py new file mode 100644 index 000000000000..6e29a953793f --- /dev/null +++ b/tests_python/tests_011/test_fork.py @@ -0,0 +1,85 @@ +import pytest +from tools import utils, constants +from launchers.sandbox import Sandbox +from . import protocol + + +NUM_NODES = 3 + + +@pytest.mark.multinode +@pytest.mark.incremental +class TestFork: + """Constructs two independent branches on disconnected subsets of nodes, + one head has higher fitness. At reconnection, check the the highest + fitness head is the chosen one""" + + def test_init(self, sandbox: Sandbox): + for i in range(NUM_NODES): + sandbox.add_node(i, params=constants.NODE_PARAMS) + protocol.activate(sandbox.client(0)) + + def test_level(self, sandbox: Sandbox): + level = 1 + for client in sandbox.all_clients(): + assert utils.check_level(client, level) + + def test_terminate_nodes_1_and_2(self, sandbox: Sandbox): + sandbox.node(1).terminate() + sandbox.node(2).terminate() + + def test_bake_node_0(self, sandbox: Sandbox): + """Client 0 bakes block A at level 2, not communicated to 1 and 2""" + utils.bake(sandbox.client(0)) + + def test_endorse_node_0(self, sandbox: Sandbox, session: dict): + """bootstrap1 builds an endorsement for block A""" + client = sandbox.client(0) + client.endorse('bootstrap1') + mempool = client.get_mempool() + endorsement = mempool['applied'][0] + session['endorsement1'] = endorsement + + def test_bake_node_0_again(self, sandbox: Sandbox): + """Client 0 bakes block A' at level 3, not communicated to 1 and 2""" + utils.bake(sandbox.client(0)) + + def test_first_branch(self, sandbox: Sandbox, session: dict): + head = sandbox.client(0).get_head() + assert head['header']['level'] == 3 + session['hash1'] = head['hash'] + assert len(head['operations'][0]) == 1 + + def test_terminate_node_0(self, sandbox: Sandbox): + sandbox.node(0).terminate() + + def test_restart_node_2(self, sandbox: Sandbox): + sandbox.node(2).run() + assert sandbox.client(2).check_node_listening() + + def test_bake_node_2(self, sandbox: Sandbox): + """Client 2 bakes block B at level 2, not communicated to 0 and 1""" + utils.bake(sandbox.client(2)) + + def test_bake_node_2_again(self, sandbox: Sandbox): + """Client 2 bakes block B' at level 3, not communicated to 0 and 1""" + utils.bake(sandbox.client(2)) + + def test_second_branch(self, sandbox: Sandbox, session: dict): + head = sandbox.client(2).get_head() + session['hash2'] = head['hash'] + assert head['header']['level'] == 3 + assert not head['operations'][0] + + def test_restart_all(self, sandbox: Sandbox): + sandbox.node(0).run() + sandbox.node(1).run() + assert sandbox.client(0).check_node_listening() + assert sandbox.client(1).check_node_listening() + + +# def test_check_head(self, sandbox: Sandbox, session: dict): +# """All nodes are at level 3, head should be hash1""" +# for client in sandbox.all_clients(): +# head = client.get_head() +# assert session['hash1'] == head['hash'] diff --git a/tests_python/tests_011/test_injection.py b/tests_python/tests_011/test_injection.py new file mode 100644 index 000000000000..38850331b8c6 --- /dev/null +++ b/tests_python/tests_011/test_injection.py @@ -0,0 +1,103 @@ +import os +from typing import List +import subprocess +import pytest +from tools import utils, paths, constants +from tools.constants import PROTO_DEMO_NOOPS, PROTO_GENESIS +from client.client import Client + + +@pytest.fixture(scope="class") +def clients(sandbox): + """Launches 3 nodes in sandbox mode (genesis, doesn't activate 011).""" + num_nodes = 3 + for i in range(num_nodes): + sandbox.add_node(i, params=constants.NODE_PARAMS) + yield sandbox.all_clients() + + +PROTO = f'{paths.TEZOS_HOME}/src/bin_client/test/proto_test_injection' +COMPILER = ( + f'{paths.TEZOS_HOME}/_build/default/src/lib_protocol_compiler/' + 'main_native.exe' +) +PARAMS = ['-p', PROTO_GENESIS] + + +@pytest.mark.incremental +class TestInjectionAndActivation: + """Protocol injection and activation""" + + def test_check_resources(self): + assert os.path.isfile(COMPILER) + assert os.path.isdir(PROTO) + + def test_compute_hash(self, session: dict): + cmd = [COMPILER, '-hash-only', PROTO] + res = subprocess.run( + cmd, universal_newlines=True, check=True, stdout=subprocess.PIPE + ) + proto_hash = res.stdout[:-1] + assert len(proto_hash) == 51 + session['proto_hash'] = proto_hash + + def test_injection(self, clients: List[Client]): + clients[0].inject_protocol(PROTO) + + def test_check_injected(self, clients: List[Client], session: dict): + proto = session['proto_hash'] + protos = clients[0].list_protocols() + assert proto in protos + + def test_environment_version(self, clients: List[Client], session: dict): + proto = session['proto_hash'] + assert clients[0].environment_protocol(proto) == "V1" + + def test_activation(self, clients: List[Client], session: dict): + proto = session['proto_hash'] + parameters = {} # type: dict + res = clients[0].activate_protocol_json( + proto, parameters, key='activator', fitness='1' + ) + assert res.block_hash + + def test_check_protocol(self, clients: List[Client], session: dict): + proto = session['proto_hash'] + for client in clients: + assert utils.check_protocol(client, proto, params=PARAMS) + + +@pytest.fixture(scope="class") +def client(sandbox): + """One node in sandbox mode (genesis, doesn't activate 011).""" + sandbox.add_node(0) + client = sandbox.client(0) + yield client + + +@pytest.mark.incremental +class TestActivation: + """ Protocol activation (protocol already linked to the node) """ + + def test_proto_known(self, client: Client): + res = client.list_protocols() + assert PROTO_DEMO_NOOPS in res + + def test_first_protocol(self, client: Client): + proto = 'PrihK96nBAFSxVL1GLJTVhu9YnzkMFiBeuJRPA8NwuZVZCE1L6i' + assert client.get_protocol() == proto + + def test_activate_demo(self, client: Client): + proto = PROTO_DEMO_NOOPS + parameters = {} # type: dict + res = client.activate_protocol_json( + proto, parameters, key='activator', fitness='1' + ) + assert res.block_hash + + def test_level1(self, client: Client): + assert client.get_level(params=PARAMS) == 1 + + def test_protocol_genesis(self, client: Client): + proto = PROTO_GENESIS + assert client.get_protocol(params=PARAMS) == proto diff --git a/tests_python/tests_011/test_legacy_snapshots.py b/tests_python/tests_011/test_legacy_snapshots.py new file mode 100644 index 000000000000..5685ea360ef0 --- /dev/null +++ b/tests_python/tests_011/test_legacy_snapshots.py @@ -0,0 +1,353 @@ +import shutil +import pytest +from tools import utils, paths, constants + +PARAMS = constants.NODE_PARAMS + +# Defines the number of blocks to bake in the following test. This +# constant should be higher than max_op_ttl and should be a multiple +# of the cycle length (8 in sandboxed mode) +BATCH = 160 + +HOME = paths.TEZOS_HOME + +GROUP = [1, 2, 3, 4, 5] + +EXPECTED_LEVEL = BATCH + 1 + + +def check_expected_values(head): + assert head['header']['level'] == EXPECTED_LEVEL + + +def restart(sandbox, node_id): + sandbox.node(node_id).terminate_or_kill() + sandbox.node(node_id).run() + assert sandbox.client(node_id).check_node_listening() + + +def expect_wrong_version(sandbox, node): + pattern = 'Found \'0.0.4\', expected \'0.0.6\'' + with utils.assert_run_failure(pattern): + sandbox.init_node(node, snapshot=None, reconstruct=False) + + +def remove_lmdb(node): + shutil.rmtree(node.node_dir + '/lmdb_store_to_remove') + + +def clean(node): + shutil.rmtree(node.node_dir) + + +MAP = { + "batch": BATCH, + "home": paths.TEZOS_HOME, + "snapshot": True, +} + + +@pytest.mark.incremental +@pytest.mark.snapshot +@pytest.mark.slow +@pytest.mark.parametrize('legacy_stores', [MAP], indirect=True) +class TestLegacy: + + # Generate legacy stores and export all kind of snapshots + def test_generate_legacy_stores(self, legacy_stores, session): + # Store snapshot paths in session + for history_mode in ['archive', 'full']: + path_full = legacy_stores[f'from_{history_mode}.full'] + session[f'from_{history_mode}.full'] = path_full + path_rolling = legacy_stores[f'from_{history_mode}.rolling'] + session[f'from_{history_mode}.rolling'] = path_rolling + # Store the rolling path + tmp = legacy_stores['from_rolling.rolling'] + session['from_rolling.rolling'] = tmp + session['head_level'] = EXPECTED_LEVEL + + ########################################################################### + # Import all kinds of snapshots + # New node: 3 + def test_run_full_node_from_archive_1(self, sandbox, legacy_stores): + file = legacy_stores['from_archive.full'] + sandbox.add_node(3, snapshot=file, params=constants.NODE_PARAMS) + + # New node: 4 + def test_run_rolling_node_from_archive_1(self, sandbox, legacy_stores): + file = legacy_stores['from_archive.rolling'] + sandbox.add_node(4, snapshot=file, params=constants.NODE_PARAMS) + + # New node 1 + def test_reset_full_node_from_full_1(self, sandbox, legacy_stores): + file = legacy_stores['from_full.full'] + sandbox.add_node(1, snapshot=file, params=constants.NODE_PARAMS) + + # New node: 5 + def test_run_rolling_node_from_full_1(self, sandbox, legacy_stores): + file = legacy_stores['from_full.rolling'] + sandbox.add_node(5, snapshot=file, params=constants.NODE_PARAMS) + + # New node 2 + def test_reset_rolling_node_from_rolling_1(self, sandbox, legacy_stores): + file = legacy_stores['from_rolling.rolling'] + sandbox.add_node(2, snapshot=file, params=constants.NODE_PARAMS) + + ########################################################################### + # Check consistency of imported snapshots with > 5 cycles + + # For the full nodes + def test_node_1_consistency_1(self, sandbox, session, legacy_stores): + # pylint: disable=unused-argument + node_id = 1 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level + expected_savepoint = expected_checkpoint + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.full_node_blocks_availability( + node_id, sandbox, expected_savepoint, expected_level + ) + + def test_node_3_consistency_1(self, sandbox, session, legacy_stores): + # pylint: disable=unused-argument + node_id = 3 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level + expected_savepoint = expected_checkpoint + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.full_node_blocks_availability( + node_id, sandbox, expected_savepoint, expected_level + ) + + # For the rolling nodes + def test_node_2_consistency_1(self, sandbox, session, legacy_stores): + # pylint: disable=unused-argument + node_id = 2 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint + expected_caboose = expected_checkpoint - max_op_ttl + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + def test_node_4_consistency_1(self, sandbox, session, legacy_stores): + # pylint: disable=unused-argument + node_id = 4 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint + expected_caboose = expected_checkpoint - max_op_ttl + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + def test_node_5_consistency_1(self, sandbox, session, legacy_stores): + # pylint: disable=unused-argument + node_id = 5 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint + expected_caboose = expected_checkpoint - max_op_ttl + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + # Bake a few blocks to check if the Full and Rolling nodes catch up + def test_bake_to_catch_up(self, sandbox, session, legacy_stores): + # pylint: disable=unused-argument + for _ in range(BATCH): + utils.bake(sandbox.client(1)) + session['head_level'] = sandbox.client(1).get_head()['header']['level'] + for i in GROUP: + assert utils.check_level(sandbox.client(i), session['head_level']) + + ########################################################################### + # Check consistency of imported snapshots with > 5 cycles + + # For the full nodes + def test_node_1_consistency_2(self, sandbox, session, legacy_stores): + # pylint: disable=unused-argument + node_id = 1 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level - 2 * 8 # lafl(head) + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint - max_op_ttl + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.full_node_blocks_availability( + node_id, sandbox, expected_savepoint, expected_level + ) + + def test_node_3_consistency_2(self, sandbox, session, legacy_stores): + # pylint: disable=unused-argument + node_id = 3 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level - 2 * 8 # lafl(head) + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint - max_op_ttl + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.full_node_blocks_availability( + node_id, sandbox, expected_savepoint, expected_level + ) + + # For the rolling nodes + def test_node_2_consistency_2(self, sandbox, session, legacy_stores): + # pylint: disable=unused-argument + node_id = 2 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level - 2 * 8 # lafl(head) + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint - max_op_ttl + expected_caboose = expected_savepoint + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + def test_node_4_consistency_2(self, sandbox, session, legacy_stores): + # pylint: disable=unused-argument + node_id = 4 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level - 2 * 8 # lafl(head) + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint - max_op_ttl + expected_caboose = expected_savepoint + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + def test_node_5_consistency_2(self, sandbox, session, legacy_stores): + # pylint: disable=unused-argument + node_id = 5 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level - 2 * 8 # lafl(head) + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint - max_op_ttl + expected_caboose = expected_savepoint + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) diff --git a/tests_python/tests_011/test_legacy_upgrade.py b/tests_python/tests_011/test_legacy_upgrade.py new file mode 100644 index 000000000000..c724689773c1 --- /dev/null +++ b/tests_python/tests_011/test_legacy_upgrade.py @@ -0,0 +1,214 @@ +import pytest +from tools import utils, paths + +# Defines the number of blocks to bake in the following test. This +# constant should be higher than max_op_ttl and should be a multiple of +# the cycle length (8 in sandboxed mode) +BATCH = 160 + +EXPECTED_LEVEL = BATCH + 1 + +# FIXME: How to get this value? +MAX_OP_TTL = 120 + +# checkpoint = lafl(head) +EXPECTED_CHECKPOINT = EXPECTED_LEVEL - 16 +# savepoint = checkpoint (legacy's Full limitations) +EXPECTED_SAVEPOINT = EXPECTED_LEVEL - 16 +EXPECTED_CABOOSE = 0 +# savepoint - max_op_ttl(cp) +EXPECTED_ROLLING_CABOOSE = EXPECTED_SAVEPOINT - MAX_OP_TTL + +EXPECTED_SERVICE_ERROR = 'Did not find service' +EXPECTED_COMMAND_ERROR = 'Command failed: Unable to find block' + + +def check_expected_values(head): + assert head['header']['level'] == EXPECTED_LEVEL + + +def restart(sandbox, node_id): + sandbox.node(node_id).run() + assert sandbox.client(node_id).check_node_listening() + + +def expect_wrong_version(sandbox, node): + pattern = "Found '0.0.4', expected '0.0.6'" + with utils.assert_run_failure(pattern): + sandbox.init_node(node, snapshot=None, reconstruct=False) + + +MAP = { + "batch": BATCH, + "home": paths.TEZOS_HOME, + "snapshot": False, +} + + +@pytest.mark.incremental +@pytest.mark.snapshot +@pytest.mark.slow +@pytest.mark.parametrize("legacy_stores", [MAP], indirect=True) +class TestLegacy: + + # ARCHIVE + def test_upgrade_archive(self, sandbox, nodes_legacy_store): + node1 = nodes_legacy_store['archive'] + # We init the client + client1 = sandbox.register_client(1, rpc_port=node1.rpc_port) + expect_wrong_version(sandbox, node1) + # We now run the storage upgarde + sandbox.node(1).upgrade_storage() + # After upgrading, we restart the node + restart(sandbox, 1) + sandbox.init_client(client1) + + # Checkpoints + def test_archive_consistency_1(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + check_expected_values(sandbox.client(1).get_head()) + assert sandbox.client(1).get_savepoint() == 0 + assert sandbox.client(1).get_caboose() == 0 + + # All blocks must be available + def test_archive_consistency_2(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + for i in range(EXPECTED_LEVEL): + assert utils.get_block_at_level(sandbox.client(1), i) + + # FULL + def test_upgrade_full(self, sandbox, nodes_legacy_store): + node2 = nodes_legacy_store['full'] + # We init the client + client2 = sandbox.register_client(2, rpc_port=node2.rpc_port) + expect_wrong_version(sandbox, node2) + # We now run the storage upgarde + sandbox.node(2).upgrade_storage() + # After upgrading, we restart the node + restart(sandbox, 2) + sandbox.init_client(client2) + + # Checkpoints + def test_full_consistency_1(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + check_expected_values(sandbox.client(2).get_head()) + savepoint = sandbox.client(2).get_savepoint() + assert savepoint == EXPECTED_SAVEPOINT + caboose = sandbox.client(2).get_caboose() + assert caboose == 0 + # the metadata of genesis are available + assert utils.get_block_at_level(sandbox.client(2), 0) + + # All block in [1; CHECKPOINT] must non be available (only headers are) + def test_full_consistency_2(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + for i in range(1, EXPECTED_CHECKPOINT): + with utils.assert_run_failure(EXPECTED_COMMAND_ERROR): + utils.get_block_metadata_at_level(sandbox.client(2), i) + + # All block headers in [1; CHECKPOINT] must be available + def test_full_consistency_3(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + for i in range(1, EXPECTED_CHECKPOINT): + utils.get_block_header_at_level(sandbox.client(2), i) + + # All blocks in [CHECKPOINT + 1; HEAD] must be available + def test_full_consistency_4(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + for i in range(EXPECTED_CHECKPOINT + 1, EXPECTED_LEVEL): + assert utils.get_block_at_level(sandbox.client(2), i) + + # ROLLING + def test_upgrade_rolling(self, sandbox, nodes_legacy_store): + node3 = nodes_legacy_store['rolling'] + # We init the client + client3 = sandbox.register_client(3, rpc_port=node3.rpc_port) + expect_wrong_version(sandbox, node3) + # We now run the storage upgarde + sandbox.node(3).upgrade_storage() + # After upgrading, we restart the node + restart(sandbox, 3) + sandbox.init_client(client3) + + # Checkpoints + def test_rolling_consistency_1(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + check_expected_values(sandbox.client(3).get_head()) + savepoint = sandbox.client(3).get_savepoint() + assert savepoint == EXPECTED_CHECKPOINT + # In rolling, caboose = savepoint + caboose = sandbox.client(3).get_caboose() + assert caboose == EXPECTED_ROLLING_CABOOSE + # the metadata of genesis are available + utils.get_block_at_level(sandbox.client(3), 0) + + # All blocks in [1 ; ROLLING_CABOOSE] must not be known + def test_rolling_consistency_2(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + for i in range(1, EXPECTED_ROLLING_CABOOSE): + with utils.assert_run_failure(EXPECTED_SERVICE_ERROR): + utils.get_block_at_level(sandbox.client(3), i) + + # All blocks in [ROLLING_CABOOSE ; CHECKPOINT] must not be available + # (only headers are) + def test_rolling_consistency_3(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + for i in range(EXPECTED_ROLLING_CABOOSE, EXPECTED_CHECKPOINT): + with utils.assert_run_failure(EXPECTED_COMMAND_ERROR): + utils.get_block_metadata_at_level(sandbox.client(3), i) + + # All block headers in [SAVEPOINT ; CHECKPOINT] must be available + def test_rolling_consistency_4(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + for i in range(EXPECTED_SAVEPOINT, EXPECTED_CHECKPOINT): + utils.get_block_header_at_level(sandbox.client(3), i) + + # All blocks in [CHECKPOINT + 1; HEAD] must be available + def test_rolling_consistency_5(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + for i in range(EXPECTED_CHECKPOINT + 1, EXPECTED_LEVEL): + assert utils.get_block_at_level(sandbox.client(3), i) + + # Bake a few blocks to check if the Full and Rolling nodes catch up + def test_bake_to_catch_up(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + for _ in range(BATCH): + utils.bake(sandbox.client(1)) + + def test_archive_catch_up(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + head = sandbox.client(1).get_head() + expected_head = EXPECTED_LEVEL + BATCH + assert head['header']['level'] == expected_head + checkpoint = (sandbox.client(1).get_checkpoint())['block']['level'] + assert checkpoint == (expected_head - 2 * 8) + savepoint = sandbox.client(1).get_savepoint() + caboose = sandbox.client(1).get_caboose() + assert savepoint == caboose + assert caboose == 0 + + # We assume that "Full 0 mode" is now in "Full 5 mode" + def test_full_catch_up(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + head = sandbox.client(2).get_head() + expected_head = EXPECTED_LEVEL + BATCH + assert head['header']['level'] == expected_head + checkpoint = sandbox.client(2).get_checkpoint()['block']['level'] + assert checkpoint == (expected_head - 2 * 8) + savepoint = sandbox.client(2).get_savepoint() + assert savepoint == (checkpoint - MAX_OP_TTL) + caboose = sandbox.client(2).get_caboose() + assert caboose == 0 + + # We assume that "Rolling 0 mode" is now in "Rolling 5 mode" + def test_rolling_catch_up(self, sandbox, nodes_legacy_store): + # pylint: disable=unused-argument + head = sandbox.client(3).get_head() + expected_head = EXPECTED_LEVEL + BATCH + assert head['header']['level'] == expected_head + checkpoint = sandbox.client(3).get_checkpoint()['block']['level'] + assert checkpoint == (expected_head - 2 * 8) + savepoint = sandbox.client(3).get_savepoint() + assert savepoint == (checkpoint - MAX_OP_TTL) + caboose = sandbox.client(3).get_caboose() + assert caboose == savepoint diff --git a/tests_python/tests_011/test_liquidity_baking.py b/tests_python/tests_011/test_liquidity_baking.py new file mode 100644 index 000000000000..17aaafa06305 --- /dev/null +++ b/tests_python/tests_011/test_liquidity_baking.py @@ -0,0 +1,279 @@ +import pytest + +from tools import utils +from tools.constants import IDENTITIES + +DEX = "KT1TxqZ8QtKvLu3V3JH7Gx58n7Co8pgtpQU5" +TOK = "KT1VqarPDicMFn1ejmQqqshUkUXTCTXwmkCN" +LQT = "KT1AafHA1C1vk959wvHWBispY9Y2f3fxBUUo" +BOOTSTRAP1 = IDENTITIES['bootstrap1']['identity'] +TOK_ADMIN = BOOTSTRAP1 +BOOTSTRAP2 = IDENTITIES['bootstrap2']['identity'] +BOOTSTRAP3 = IDENTITIES['bootstrap3']['identity'] +FUTURE = "2050-01-01T00:00:00Z" + + +@pytest.mark.contract +@pytest.mark.regression +@pytest.mark.incremental +class SetupMintAndApprove: + """Test calling entrypoints of liquidity baking contracts""" + + def test_setup(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + assert DEX == client.rpc( + 'get', + "/chains/main/blocks/head/context/liquidity_baking/cpmm_address", + ) + dex_storage = client.get_storage(DEX).split() + assert dex_storage[4].strip('"') == TOK + assert dex_storage[5].strip('"') == LQT + + # mint some test TOK (1 tzBTC?) for ourselves + def test_call_mint_or_burn(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.call( + TOK_ADMIN, + TOK, + [ + '--entrypoint', + 'mintOrBurn', + '--arg', + f'(Pair 100000000 "{BOOTSTRAP1}")', + '--burn-cap', + '10', + ], + ) + utils.bake(client, 'bootstrap5') + + # pre-approve big allowances in TOK for DEX + def test_call_approve1(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.call( + 'bootstrap1', + TOK, + [ + '--entrypoint', + 'approve', + '--arg', + f'(Pair "{DEX}" 1000000000)', + '--burn-cap', + '10', + ], + ) + utils.bake(client, 'bootstrap5') + + def test_call_approve2(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.call( + 'bootstrap2', + TOK, + [ + '--entrypoint', + 'approve', + '--arg', + f'(Pair "{DEX}" 1000000000)', + '--burn-cap', + '10', + ], + ) + utils.bake(client, 'bootstrap5') + + def test_call_approve3(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.call( + 'bootstrap3', + TOK, + [ + '--entrypoint', + 'approve', + '--arg', + f'(Pair "{DEX}" 1000000000)', + '--burn-cap', + '10', + ], + ) + utils.bake(client, 'bootstrap5') + + +@pytest.mark.contract +@pytest.mark.regression +@pytest.mark.incremental +class TestAddApproveTransferRemove(SetupMintAndApprove): + """Test add/approve/transfer/remove liquidity""" + + # first add liquidity on DEX so that we have some LQT + def test_add_liquidity(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.transfer( + 9001, + 'bootstrap1', + DEX, + [ + '--entrypoint', + 'addLiquidity', + '--arg', + f'(Pair "{BOOTSTRAP1}" 0 1000000000 "{FUTURE}")', + '--burn-cap', + '10', + ], + ) + utils.bake(client, 'bootstrap5') + + # test LQT approval + def test_approval(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.call( + 'bootstrap1', + LQT, + [ + '--entrypoint', + 'approve', + '--arg', + f'(Pair "{BOOTSTRAP2}" 1000)', + '--burn-cap', + '10', + ], + ) + utils.bake(client, 'bootstrap5') + + # transfer LQT to bootstrap2 (using approval) + def test_approved_transfer(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.call( + 'bootstrap2', + LQT, + [ + '--entrypoint', + 'transfer', + '--arg', + f'(Pair "{BOOTSTRAP1}" "{BOOTSTRAP2}" 1000)', + '--burn-cap', + '10', + ], + ) + utils.bake(client, 'bootstrap5') + + # now remove LQT for bootstrap2 + def test_remove_liquidity(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.call( + 'bootstrap2', + DEX, + [ + '--entrypoint', + 'removeLiquidity', + '--arg', + f'(Pair "{BOOTSTRAP2}" 1000 0 0 "{FUTURE}")', + '--burn-cap', + '10', + ], + ) + utils.bake(client, 'bootstrap5') + + # check DEX storage + def test_dex_storage(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.get_storage(DEX) + + # check LQT storage + def test_lqt_storage(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.get_storage(LQT) + + # check TOK storage + def test_tok_storage(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.get_storage(TOK) + + +@pytest.mark.contract +@pytest.mark.regression +@pytest.mark.incremental +class TestTrades(SetupMintAndApprove): + """Test trades""" + + # add liquidity + def test_add_liquidity(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.transfer( + 9001, + 'bootstrap1', + DEX, + [ + '--entrypoint', + 'addLiquidity', + '--arg', + f'(Pair "{BOOTSTRAP1}" 0 1000000000 "{FUTURE}")', + '--burn-cap', + '10', + ], + ) + utils.bake(client, 'bootstrap5') + + # bootstrap2 buys some TOK + def test_buy_tok(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.transfer( + 9001, + 'bootstrap2', + DEX, + [ + '--entrypoint', + 'xtzToToken', + '--arg', + f'(Pair "{BOOTSTRAP2}" 0 "{FUTURE}")', + '--burn-cap', + '10', + ], + ) + utils.bake(client, 'bootstrap5') + + # bootstrap2 transfers TOK to bootstrap3 + def test_transfer(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.call( + 'bootstrap2', + TOK, + [ + '--entrypoint', + 'transfer', + '--arg', + f'(Pair "{BOOTSTRAP2}" "{BOOTSTRAP3}" 100)', + '--burn-cap', + '10', + ], + ) + utils.bake(client, 'bootstrap5') + + # bootstrap3 sells TOK + def test_sell_tok(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.call( + 'bootstrap3', + DEX, + [ + '--entrypoint', + 'tokenToXtz', + '--arg', + f'(Pair "{BOOTSTRAP3}" 100 0 "{FUTURE}")', + '--burn-cap', + '10', + ], + ) + utils.bake(client, 'bootstrap5') + + # check DEX storage + def test_dex_storage(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.get_storage(DEX) + + # check LQT storage + def test_lqt_storage(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.get_storage(LQT) + + # check TOK storage + def test_tok_storage(self, client_regtest_scrubbed): + client = client_regtest_scrubbed + client.get_storage(TOK) diff --git a/tests_python/tests_011/test_many_bakers.py b/tests_python/tests_011/test_many_bakers.py new file mode 100644 index 000000000000..8038c6cf8067 --- /dev/null +++ b/tests_python/tests_011/test_many_bakers.py @@ -0,0 +1,40 @@ +import time +import pytest +from tools import utils, constants +from launchers.sandbox import Sandbox +from . import protocol + + +# TODO parameterize test + + +@pytest.mark.baker +@pytest.mark.multinode +@pytest.mark.slow +@pytest.mark.incremental +class TestManyBakers: + """Run 5 bakers and num nodes, wait and check logs""" + + def test_init(self, sandbox: Sandbox): + for i in range(10): + sandbox.add_node(i, params=constants.NODE_PARAMS) + protocol.activate(sandbox.client(0)) + for i in range(5): + sandbox.add_baker(i, f'bootstrap{i + 1}', proto=protocol.DAEMON) + + def test_wait(self): + time.sleep(10) + + def test_progress(self, sandbox: Sandbox): + min_level = min( + [client.get_level() for client in sandbox.all_clients()] + ) + assert min_level >= 3 + + @pytest.mark.xfail + def test_check_logs(self, sandbox: Sandbox): + if not sandbox.log_dir: + pytest.skip() + assert sandbox.logs + error_pattern = r"canceled|crashed" + assert utils.check_logs(sandbox.logs, error_pattern) diff --git a/tests_python/tests_011/test_many_nodes.py b/tests_python/tests_011/test_many_nodes.py new file mode 100644 index 000000000000..816350aa1256 --- /dev/null +++ b/tests_python/tests_011/test_many_nodes.py @@ -0,0 +1,63 @@ +import random +import time +import pytest +from tools import utils, constants +from launchers.sandbox import Sandbox +from . import protocol + +NUM_NODES = 2 +NEW_NODES = 2 +REPLACE = False +ERROR_PATTERN = r"Uncaught|registered" + + +@pytest.mark.baker +@pytest.mark.multinode +@pytest.mark.slow +@pytest.mark.incremental +class TestManyNodesBootstrap: + """Run many nodes, wait a while, run more nodes, check logs""" + + def test_init(self, sandbox: Sandbox): + sandbox.add_node(0, params=constants.NODE_PARAMS) + parameters = dict(protocol.PARAMETERS) + parameters["time_between_blocks"] = ["1", "0"] + protocol.activate(sandbox.client(0), parameters) + sandbox.add_baker(0, 'bootstrap1', proto=protocol.DAEMON) + sandbox.add_node(1, params=constants.NODE_PARAMS) + sandbox.add_baker(1, 'bootstrap2', proto=protocol.DAEMON) + + def test_add_nodes(self, sandbox: Sandbox): + for i in range(2, NUM_NODES): + sandbox.add_node(i, params=constants.NODE_PARAMS) + + def test_sleep_10s(self): + time.sleep(10) + + def test_add_more_nodes(self, sandbox: Sandbox): + new_node = NUM_NODES + for i in range(NEW_NODES): + if REPLACE: + running_nodes = list(sandbox.nodes.keys()) + running_nodes.remove(0) + running_nodes.remove(1) + sandbox.rm_node(random.choice(running_nodes)) + sandbox.add_node(new_node + i, params=constants.NODE_PARAMS) + + def test_kill_baker(self, sandbox: Sandbox): + assert utils.check_logs(sandbox.logs, ERROR_PATTERN) + sandbox.rm_baker(0, proto=protocol.DAEMON) + sandbox.rm_baker(1, proto=protocol.DAEMON) + + def test_synchronize(self, sandbox: Sandbox): + utils.synchronize(sandbox.all_clients()) + + def test_progress(self, sandbox: Sandbox): + level = sandbox.client(0).get_level() + assert level >= 5 + + def test_check_logs(self, sandbox: Sandbox): + if not sandbox.log_dir: + pytest.skip() + assert sandbox.logs + assert utils.check_logs(sandbox.logs, ERROR_PATTERN) diff --git a/tests_python/tests_011/test_mempool.py b/tests_python/tests_011/test_mempool.py new file mode 100644 index 000000000000..11d9a459c2d7 --- /dev/null +++ b/tests_python/tests_011/test_mempool.py @@ -0,0 +1,66 @@ +import pytest +from tools import utils, constants +from launchers.sandbox import Sandbox + +from . import protocol + + +@pytest.mark.mempool +@pytest.mark.multinode +@pytest.mark.slow +@pytest.mark.incremental +class TestMempool: + " Tests mempool" + + def test_init(self, sandbox: Sandbox): + sandbox.add_node(1, params=constants.NODE_PARAMS) + sandbox.add_node(2, params=constants.NODE_PARAMS) + sandbox.add_node( + 3, params=constants.NODE_PARAMS + ['--disable-mempool'] + ) + protocol.activate(sandbox.client(1), activate_in_the_past=True) + + def test_level1(self, sandbox: Sandbox): + level = 1 + for client in sandbox.all_clients(): + assert utils.check_level(client, level) + + def test_running_prevalidators(self, sandbox: Sandbox): + assert sandbox.client(1).get_prevalidator() + assert sandbox.client(2).get_prevalidator() + assert not sandbox.client(3).get_prevalidator() + + def test_mempool_empty(self, sandbox: Sandbox): + for i in range(1, 4): + assert sandbox.client(i).mempool_is_empty() + + def test_transfer(self, sandbox: Sandbox, session: dict): + client = sandbox.client(1) + session['trsfr_hash'] = client.transfer( + 1.000, 'bootstrap1', 'bootstrap2' + ).operation_hash + + def test_mempool_include_transfer(self, sandbox: Sandbox, session: dict): + assert utils.check_mempool_contains_operations( + sandbox.client(1), [session['trsfr_hash']] + ) + assert utils.check_mempool_contains_operations( + sandbox.client(2), [session['trsfr_hash']] + ) + assert sandbox.client(3).mempool_is_empty() + + def test_bake_for1(self, sandbox: Sandbox): + utils.bake(sandbox.client(1)) + + def test_level2(self, sandbox: Sandbox): + level = 2 + for client in sandbox.all_clients(): + assert utils.check_level(client, level) + + def test_mempools_are_empty(self, sandbox: Sandbox): + for i in range(1, 4): + assert sandbox.client(i).mempool_is_empty() + + def test_injection_fails_on_mempool_disabled_node(self, sandbox: Sandbox): + with pytest.raises(Exception): + sandbox.client(3).transfer(2.000, 'bootstrap2', 'bootstrap3') diff --git a/tests_python/tests_011/test_migration.py b/tests_python/tests_011/test_migration.py new file mode 100644 index 000000000000..e40184958562 --- /dev/null +++ b/tests_python/tests_011/test_migration.py @@ -0,0 +1,204 @@ +from typing import Dict, List +import time + +import pytest + +from launchers.sandbox import Sandbox +from tools import constants, utils +from tools.constants import PROTO_GENESIS +from . import protocol + +MIGRATION_LEVEL = 8 +BAKER = 'bootstrap1' +BAKER_PKH = constants.IDENTITIES[BAKER]['identity'] +PREV_DEPOSIT = protocol.PREV_PARAMETERS["block_security_deposit"] +DEPOSIT = protocol.PARAMETERS["block_security_deposit"] + +PREV_DEPOSIT_RECEIPTS = [ + { + "kind": "contract", + "contract": BAKER_PKH, + "change": "-" + PREV_DEPOSIT, + "origin": "block", + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": BAKER_PKH, + "cycle": 0, + "change": PREV_DEPOSIT, + "origin": "block", + }, +] +DEPOSIT_RECEIPTS = [ + { + "kind": "contract", + "contract": BAKER_PKH, + "change": "-" + DEPOSIT, + "origin": "block", + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": BAKER_PKH, + "cycle": 1, + "change": DEPOSIT, + "origin": "block", + }, +] +MIGRATION_RECEIPTS: List[Dict[str, str]] = [] + + +# configure user-activate-upgrade at MIGRATION_LEVEL to test migration +NODE_CONFIG = { + 'network': { + 'genesis': { + 'timestamp': '2018-06-30T16:07:32Z', + 'block': 'BLockGenesisGenesisGenesisGenesisGenesisf79b5d1CoW2', + 'protocol': PROTO_GENESIS, + }, + 'genesis_parameters': { + 'values': {'genesis_pubkey': constants.GENESIS_PK} + }, + 'chain_name': 'TEZOS', + 'sandboxed_chain_name': 'SANDBOXED_TEZOS', + 'user_activated_upgrades': [ + {'level': MIGRATION_LEVEL, 'replacement_protocol': protocol.HASH} + ], + } +} + + +@pytest.fixture(scope="class") +def client(sandbox): + sandbox.add_node(0, node_config=NODE_CONFIG) + protocol.activate( + sandbox.client(0), + proto=protocol.PREV_HASH, + parameters=protocol.PREV_PARAMETERS, + activate_in_the_past=True, + ) + yield sandbox.client(0) + + +@pytest.mark.incremental +class TestMigration: + """Test migration from PROTO_A (the previous protocol) to PROTO_B (the + current protocol). + + After migration, test snapshots: + - node0: activate PROTO_A, migrate to PROTO_B, bake, export + a snapshot in full and rolling modes, and terminate + - node1: import full, bake + - node2: import rolling, sync, bake + - node3: reconstruct full, sync, bake + - all 4 are synced + """ + + def test_init(self, client): + # 1: genesis block + client.get_head() + client.rpc('get', '/config/network/user_activated_upgrades') + + def test_activate(self, client, sandbox): + # 2: activated PROTO_A + utils.bake(client, BAKER) + assert client.get_protocol() == protocol.PREV_HASH + assert sandbox.client(0).get_head()['header']['proto'] == 1 + metadata = client.get_metadata() + assert metadata['balance_updates'] == PREV_DEPOSIT_RECEIPTS + # PROTO_A is using env. V1+, metadata hashes should be present + _ops_metadata_hash = client.get_operations_metadata_hash() + _block_metadata_hash = client.get_block_metadata_hash() + + def test_migration(self, client, sandbox): + # 3: last block of PROTO_A, runs migration code (MIGRATION_LEVEL) + for _i in range(MIGRATION_LEVEL - 2): + utils.bake(client, BAKER) + metadata = client.get_metadata() + assert metadata['next_protocol'] == protocol.HASH + assert metadata['balance_updates'] == PREV_DEPOSIT_RECEIPTS + # PROTO_B is using env. V1+, metadata hashes should be present + _ops_metadata_hash = client.get_operations_metadata_hash() + _block_metadata_hash = client.get_block_metadata_hash() + assert sandbox.client(0).get_head()['header']['proto'] == 2 + + def test_new_proto(self, client, sandbox): + # 4: first block of PROTO_B + utils.bake(client, BAKER) + assert client.get_protocol() == protocol.HASH + assert sandbox.client(0).get_head()['header']['proto'] == 2 + + # check that migration balance update appears in receipts + metadata = client.get_metadata() + assert metadata['balance_updates'] == ( + MIGRATION_RECEIPTS + DEPOSIT_RECEIPTS + ) + _ops_metadata_hash = client.get_operations_metadata_hash() + _block_metadata_hash = client.get_block_metadata_hash() + + def test_new_proto_second(self, client): + # 5: second block of PROTO_B + utils.bake(client, BAKER) + metadata = client.get_metadata() + assert metadata['balance_updates'] == DEPOSIT_RECEIPTS + + def test_terminate_node0(self, client, sandbox: Sandbox, session: dict): + # to export rolling snapshot, we need to be at level > 60 + # (see `max_operations_ttl`) + level = client.get_head()['header']['level'] + for _ in range(60 - level + 1): + utils.bake(client, BAKER) + assert client.get_head()['header']['level'] == 61 + + # terminate node0 + session['head_hash'] = sandbox.client(0).get_head()['hash'] + sandbox.node(0).terminate() + time.sleep(1) + + def test_export_snapshots(self, sandbox, tmpdir, session: dict): + node_export = sandbox.node(0) + file_full = f'{tmpdir}/FILE.full' + file_rolling = f'{tmpdir}/FILE.rolling' + head_hash = session['head_hash'] + session['snapshot_full'] = file_full + session['snapshot_rolling'] = file_rolling + node_export.snapshot_export(file_full, params=['--block', head_hash]) + node_export.snapshot_export( + file_rolling, params=['--block', head_hash, '--rolling'] + ) + + def test_import_full_snapshot_node1(self, sandbox, session): + sandbox.add_node( + 1, snapshot=session['snapshot_full'], node_config=NODE_CONFIG + ) + client = sandbox.client(1) + utils.bake(client, BAKER) + + def test_import_rolling_snapshot_node2(self, sandbox, session): + sandbox.add_node( + 2, snapshot=session['snapshot_rolling'], node_config=NODE_CONFIG + ) + client = sandbox.client(2) + utils.synchronize([sandbox.client(1), client], max_diff=0) + utils.bake(client, BAKER) + + def test_reconstruct_full_node3(self, sandbox, session): + sandbox.add_node( + 3, snapshot=session['snapshot_full'], node_config=NODE_CONFIG + ) + sandbox.node(3).terminate() + time.sleep(3) + sandbox.node(3).reconstruct() + sandbox.node(3).run() + client = sandbox.client(3) + assert client.check_node_listening() + utils.synchronize( + [sandbox.client(1), sandbox.client(2), client], max_diff=0 + ) + utils.bake(client, BAKER) + + def test_rerun_node0(self, sandbox): + sandbox.node(0).run() + sandbox.client(0).check_node_listening() + utils.synchronize(sandbox.all_clients(), max_diff=0) diff --git a/tests_python/tests_011/test_migration_flattening.py b/tests_python/tests_011/test_migration_flattening.py new file mode 100644 index 000000000000..c0419914c007 --- /dev/null +++ b/tests_python/tests_011/test_migration_flattening.py @@ -0,0 +1,183 @@ +from typing import Dict, List +import copy + +import pytest + +from launchers.sandbox import Sandbox +from tools import constants, paths, utils +from tools.constants import PROTO_GENESIS +from . import protocol + +MIGRATION_LEVEL = 8 +BAKER = 'bootstrap1' +BAKER_PKH = constants.IDENTITIES[BAKER]['identity'] +PREV_DEPOSIT = protocol.PREV_PARAMETERS["block_security_deposit"] +DEPOSIT = protocol.PARAMETERS["block_security_deposit"] + +PREV_DEPOSIT_RECEIPTS = [ + { + "kind": "contract", + "contract": BAKER_PKH, + "change": "-" + PREV_DEPOSIT, + "origin": "block", + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": BAKER_PKH, + "cycle": 0, + "change": PREV_DEPOSIT, + "origin": "block", + }, +] +DEPOSIT_RECEIPTS = [ + { + "kind": "contract", + "contract": BAKER_PKH, + "change": "-" + DEPOSIT, + "origin": "block", + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": BAKER_PKH, + "cycle": 1, + "change": DEPOSIT, + "origin": "block", + }, +] +MIGRATION_RECEIPTS: List[Dict[str, str]] = [] + + +# configure user-activate-upgrade at MIGRATION_LEVEL to test migration +NODE_CONFIG = { + 'network': { + 'genesis': { + 'timestamp': '2018-06-30T16:07:32Z', + 'block': 'BLockGenesisGenesisGenesisGenesisGenesisf79b5d1CoW2', + 'protocol': PROTO_GENESIS, + }, + 'genesis_parameters': { + 'values': {'genesis_pubkey': constants.GENESIS_PK} + }, + 'chain_name': 'TEZOS', + 'sandboxed_chain_name': 'SANDBOXED_TEZOS', + 'user_activated_upgrades': [ + {'level': MIGRATION_LEVEL, 'replacement_protocol': protocol.HASH} + ], + } +} + +# the same configuration without user-activate-upgrade +NODE_CONFIG_NOUPGRADE = copy.deepcopy(NODE_CONFIG) +NODE_CONFIG_NOUPGRADE['network'].pop('user_activated_upgrades') + + +@pytest.fixture(scope="class") +def sandbox_noupgrade(singleprocess): + """Sandboxed network of nodes. + + Nodes, bakers and endorsers are added/removed dynamically.""" + with Sandbox( + paths.TEZOS_HOME, + constants.IDENTITIES, + rpc=20730, + p2p=21730, + singleprocess=singleprocess, + ) as sandbox: + yield sandbox + sandbox.are_daemons_alive() + + +@pytest.fixture(scope="class") +def client(sandbox): + sandbox.add_node(0, node_config=NODE_CONFIG) + protocol.activate( + sandbox.client(0), + proto=protocol.PREV_HASH, + parameters=protocol.PREV_PARAMETERS, + activate_in_the_past=True, + ) + yield sandbox.client(0) + + +@pytest.fixture(scope="class") +def client_noupgrade(sandbox_noupgrade): + sandbox_noupgrade.add_node(0, node_config=NODE_CONFIG_NOUPGRADE) + protocol.activate( + sandbox_noupgrade.client(0), + proto=protocol.PREV_HASH, + parameters=protocol.PREV_PARAMETERS, + activate_in_the_past=True, + ) + yield sandbox_noupgrade.client(0) + + +@pytest.mark.incremental +class TestMigration: + """Test migration from PROTO_A (the previous protocol) to PROTO_B (the + current protocol). + + After migration, test snapshots: + - node0: activate PROTO_A, migrate to PROTO_B, bake, export + a snapshot in full and rolling modes, and terminate + - node1: import full, bake + - node2: import rolling, sync, bake + - node3: reconstruct full, sync, bake + - all 4 are synced + """ + + def test_init(self, client, client_noupgrade): + # 1: genesis block + client.get_head() + client.rpc('get', '/config/network/user_activated_upgrades') + client_noupgrade.get_head() + client_noupgrade.rpc('get', '/config/network/user_activated_upgrades') + + def impl_activate(self, client, sandbox): + # 2: activated PROTO_A + utils.bake(client, BAKER) + assert client.get_protocol() == protocol.PREV_HASH + assert sandbox.client(0).get_head()['header']['proto'] == 1 + metadata = client.get_metadata() + assert metadata['balance_updates'] == PREV_DEPOSIT_RECEIPTS + + def test_activate( + self, client, sandbox, client_noupgrade, sandbox_noupgrade + ): + self.impl_activate(client, sandbox) + self.impl_activate(client_noupgrade, sandbox_noupgrade) + + def test_flattening(self, client, client_noupgrade): + # 3: last block of PROTO_A, runs migration code (MIGRATION_LEVEL) + for _i in range(MIGRATION_LEVEL - 2): + utils.bake(client, BAKER) + utils.bake(client_noupgrade, BAKER) + + # test path flattening migration + def check_rpc_equal(path, compare_on=None): + result_noupgrade = client_noupgrade.rpc('get', path) + result = client.rpc('get', path) + if compare_on is None: + assert result_noupgrade == result + else: + assert compare_on(result_noupgrade) == compare_on(result) + + block_root = '/chains/main/blocks/head/' + json_root = f'{block_root}/context/raw/json' + contracts = client_noupgrade.rpc( + 'get', f'{block_root}/context/contracts' + ) + assert contracts != [] + for contract in contracts: + check_rpc_equal(f'{block_root}/context/contracts/{contract}') + check_rpc_equal(f'{json_root}/rolls/index', sorted) + check_rpc_equal(f'{json_root}/rolls/index/1234') + check_rpc_equal(f'{json_root}/commitments') + check_rpc_equal(f'{block_root}/votes/listings') + check_rpc_equal(f'{block_root}/votes/ballots') + check_rpc_equal(f'{block_root}/context/delegates') + + metadata = client.get_metadata() + assert metadata['next_protocol'] == protocol.HASH + assert metadata['balance_updates'] == PREV_DEPOSIT_RECEIPTS diff --git a/tests_python/tests_011/test_mockup.py b/tests_python/tests_011/test_mockup.py new file mode 100644 index 000000000000..2ab9012a97a2 --- /dev/null +++ b/tests_python/tests_011/test_mockup.py @@ -0,0 +1,720 @@ +""" This file tests the mockup mode (tezos-client --mode mockup). + In this mode the client does not need a node running. + + Make sure to either use the fixture mockup_client or + to mimick it if you want a mockup with custom parameters. + + Care is taken not to leave any base_dir dangling after + tests are finished. Please continue doing this. +""" +import json +import os +import re +import shutil +import tempfile +from pathlib import Path +from typing import Any, List, Optional, Tuple +import pytest +from launchers.sandbox import Sandbox +from client.client import Client +from client.client_output import CreateMockupResult + +from . import protocol + +_BA_FLAG = "bootstrap-accounts" +_PC_FLAG = "protocol-constants" + + +@pytest.mark.client +def test_list_mockup_protocols(sandbox: Sandbox): + """Executes `tezos-client list mockup protocols` + The call must succeed and return a non empty list. + """ + try: + client = sandbox.create_client() + protocols = client.list_mockup_protocols().mockup_protocols + assert protocols + finally: + shutil.rmtree(client.base_dir) + + +@pytest.mark.client +def test_create_mockup_dir_exists_nonempty(sandbox: Sandbox): + """Executes `tezos-client --base-dir /tmp/mdir create mockup` + when /tmp/mdir is a non empty directory which is NOT a mockup + directory. The call must fail. + """ + with tempfile.TemporaryDirectory(prefix='tezos-client.') as base_dir: + # Make the directory not empty + with open(os.path.join(base_dir, "whatever"), "w") as handle: + handle.write("") + unmanaged_client = sandbox.create_client(base_dir=base_dir) + res = unmanaged_client.create_mockup( + protocol=protocol.HASH, check=False + ).create_mockup_result + assert res == CreateMockupResult.DIR_NOT_EMPTY + + +@pytest.mark.client +def test_retrieve_addresses(mockup_client: Client): + """Retrieves known addresses of a fresh mockup. + The call must succeed. + """ + addresses = mockup_client.get_known_addresses().wallet + assert addresses == { + 'bootstrap1': 'tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx', + 'bootstrap2': 'tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN', + 'bootstrap3': 'tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU', + 'bootstrap4': 'tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv', + 'bootstrap5': 'tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv', + } + + +@pytest.mark.client +def test_create_mockup_already_initialized(mockup_client: Client): + """Executes `tezos-client --base-dir /tmp/mdir create mockup` + when /tmp/mdir is not fresh. + The call must fail. + """ + # mockup was created already by fixture, try to create it second time: + res = mockup_client.create_mockup( + protocol=protocol.HASH, check=False + ).create_mockup_result + # it should fail: + assert res == CreateMockupResult.ALREADY_INITIALIZED + + +@pytest.mark.client +def test_transfer(mockup_client: Client): + """Executes `tezos-client --base-dir /tmp/mdir -M mockup + transfer 1 from bootstrap1 to bootstrap2` + in a valid mockup environment. + The call must succeed and the balances must be updated correctly. + """ + giver = "bootstrap1" + receiver = "bootstrap2" + transferred = 1.0 + + giver_balance_before = mockup_client.get_balance(giver) + receiver_balance_before = mockup_client.get_balance(receiver) + mockup_client.transfer(transferred, giver, receiver) + giver_balance_after = mockup_client.get_balance(giver) + receiver_balance_after = mockup_client.get_balance(receiver) + + assert giver_balance_after < giver_balance_before - transferred + assert receiver_balance_after == receiver_balance_before + transferred + + +# It's impossible to guess values of chain_id, these ones have been +# obtained by looking at the output of `compute chain id from seed` +@pytest.mark.parametrize( + 'chain_id', + [ + "NetXcqTGZX74DxG", + "NetXaFDF7xZQCpR", + "NetXkKbtqncJcAz", + "NetXjjE5cZUeWPy", + "NetXi7C1pyLhQNe", + ], +) +@pytest.mark.parametrize( + 'initial_timestamp', ["2020-07-21T17:11:10+02:00", "1970-01-01T00:00:00Z"] +) +@pytest.mark.client +def test_create_mockup_custom_constants( + sandbox: Sandbox, chain_id: str, initial_timestamp: str +): + """Tests `tezos-client create mockup` --protocols-constants argument + The call must succeed. + + Args: + mockup_client: the client to use + chain_id (str): the string to pass for field `chain_id` + initial_timestamp(str): an ISO-8601 formatted date string + """ + # Use another directory so that the constants change takes effect + with tempfile.TemporaryDirectory( + prefix='tezos-client.' + ) as base_dir, tempfile.NamedTemporaryFile( + prefix='tezos-custom-constants', mode='w+t' + ) as json_file: + json_data = { + "hard_gas_limit_per_operation": "400000", + "chain_id": chain_id, + "initial_timestamp": initial_timestamp, + } + json.dump(json_data, json_file) + json_file.flush() + unmanaged_client = sandbox.create_client(base_dir=base_dir) + res = unmanaged_client.create_mockup( + protocol=protocol.HASH, protocol_constants_file=json_file.name + ).create_mockup_result + assert res == CreateMockupResult.OK + + +def _create_accounts_list(): + """ + Returns a list of dictionary with 3 entries, that are + valid for being translated to json and passed + to `--bootstrap-accounts` + """ + accounts_list = [] + + def add_account(name: str, sk_uri: str, amount: str): + entry = { + "name": name, + "sk_uri": "unencrypted:" + sk_uri, + "amount": amount, + } + accounts_list.append(entry) + + # Took json structure from + # https://gitlab.com/tezos/tezos/-/merge_requests/1720 + add_account( + "bootstrap0", + "edsk2uqQB9AY4FvioK2YMdfmyMrer5R8mGFyuaLLFfSRo8EoyNdht3", + "2000000000000", + ) + add_account( + "bootstrap1", + "edsk3gUfUPyBSfrS9CCgmCiQsTCHGkviBDusMxDJstFtojtc1zcpsh", + "1000000000000", + ) + + return accounts_list + + +@pytest.mark.client +def test_create_mockup_custom_bootstrap_accounts(sandbox: Sandbox): + """Tests `tezos-client create mockup` --bootstrap-accounts argument + The call must succeed. + """ + accounts_list = _create_accounts_list() + + # Use another directory so that the constants change takes effect + with tempfile.TemporaryDirectory( + prefix='tezos-client.' + ) as base_dir, tempfile.NamedTemporaryFile( + prefix='tezos-bootstrap-accounts', mode='w+t' + ) as json_file: + json.dump(accounts_list, json_file) + json_file.flush() + # Follow pattern of mockup_client fixture: + unmanaged_client = sandbox.create_client(base_dir=base_dir) + res = unmanaged_client.create_mockup( + protocol=protocol.HASH, bootstrap_accounts_file=json_file.name + ).create_mockup_result + assert res == CreateMockupResult.OK + mock_client = sandbox.create_client(base_dir=base_dir, mode="mockup") + addresses_result = mock_client.get_known_addresses() + names_sent = sorted([account["name"] for account in accounts_list]) + names_witnessed = sorted(list(addresses_result.wallet.keys())) + assert names_sent == names_witnessed + + +@pytest.mark.client +def test_transfer_bad_base_dir(sandbox: Sandbox): + """Executes `tezos-client --base-dir /tmp/mdir create mockup` + when /tmp/mdir looks like a dubious base directory. + Checks that a warning is printed. + """ + try: + unmanaged_client = sandbox.create_client() + res = unmanaged_client.create_mockup( + protocol=protocol.HASH + ).create_mockup_result + assert res == CreateMockupResult.OK + base_dir = unmanaged_client.base_dir + mockup_dir = os.path.join(base_dir, "mockup") + + # A valid mockup has a directory named "mockup", in its directory: + assert os.path.isdir(mockup_dir) + mock_client = sandbox.create_client(base_dir=base_dir, mode="mockup") + # Delete this directory: + shutil.rmtree(mockup_dir) + # And put a file instead: + Path(os.path.join(mockup_dir)).touch() + + # Now execute a command + cmd = ["transfer", "1", "from", "bootstrap1", "to", "bootstrap2"] + (_, err_output, _) = mock_client.run_generic(cmd, check=False) + # See + # https://gitlab.com/tezos/tezos/-/merge_requests/1760#note_329071488 + # for the content being matched + searched = "Some commands .* might not work correctly." + # Witness that warning is printed: + assert re.search( + searched, err_output + ), f"'{searched}' not matched in error output" + finally: + shutil.rmtree(base_dir) + + +@pytest.mark.client +def test_config_show_mockup(mockup_client: Client): + """Executes `tezos-client --mode mockup config show` in + a state where it should succeed. + """ + mockup_client.run_generic(["--protocol", protocol.HASH, "config", "show"]) + + +@pytest.mark.client +def test_config_show_mockup_fail(mockup_client: Client): + """Executes `tezos-client --mode mockup config show` when + base dir is NOT a mockup. It should fail as this is dangerous + (the default base directory could contain sensitive data, + such as private keys) + """ + shutil.rmtree(mockup_client.base_dir) # See test_config_init_mockup_fail + # for a variant of how to make the base dir invalid for the mockup mode + _, _, return_code = mockup_client.run_generic( + ["config", "show"], check=False + ) + + # recreate directory: the cleanup later on expects its existence + os.mkdir(mockup_client.base_dir) + assert return_code != 0 + + +@pytest.mark.client +def test_config_init_mockup(mockup_client: Client): + """Executes `tezos-client config init mockup` in + a state where it should succeed. + """ + # We cannot use NamedTemporaryFile because `config init mockup` + # does not overwrite files. Because NamedTemporaryFile creates the file + # it would make the test fail. + ba_json_file = tempfile.mktemp(prefix='tezos-bootstrap-accounts') + pc_json_file = tempfile.mktemp(prefix='tezos-proto-consts') + # 1/ call `config init mockup` + mockup_client.run( + [ + "--protocol", + protocol.HASH, + "config", + "init", + f"--{_BA_FLAG}", + ba_json_file, + f"--{_PC_FLAG}", + pc_json_file, + ] + ) + + # 2/ Try loading the files, to check they are valid json + with open(ba_json_file) as handle: + json.load(handle) + with open(pc_json_file) as handle: + json.load(handle) + + # Cleanup + os.remove(ba_json_file) + os.remove(pc_json_file) + + +@pytest.mark.client +def test_config_init_mockup_fail(mockup_client: Client): + """Executes `tezos-client config init mockup` when + base dir is NOT a mockup. It should fail as this is dangerous + (the default base directory could contain sensitive data, + such as private keys) + """ + ba_json_file = tempfile.mktemp(prefix='tezos-bootstrap-accounts') + pc_json_file = tempfile.mktemp(prefix='tezos-proto-consts') + cmd = [ + "--protocol", + protocol.HASH, + "config", + "init", + f"--{_BA_FLAG}", + ba_json_file, + f"--{_PC_FLAG}", + pc_json_file, + ] + + # A valid mockup has a directory named "mockup" in its base_dir: + mockup_dir = os.path.join(mockup_client.base_dir, "mockup") + assert os.path.isdir(mockup_dir) + # Delete this directory, so that the base_dir is not a valid mockup + # base dir anymore: + shutil.rmtree(mockup_dir) # See test_config_show_mockup_fail above + # for a variant of how to make the base_dir invalid for the mockup mode + + _, _, return_code = mockup_client.run_generic(cmd, check=False) + assert return_code != 0 + # Check the test doesn't leak directories: + assert not os.path.exists(ba_json_file) + assert not os.path.exists(pc_json_file) + + +def _try_json_loads(flag: str, string: str) -> Any: + """ Converts the given string to a json object """ + try: + return json.loads(string) + except json.JSONDecodeError: + pytest.fail( + f"""Write back of {flag} value is not valid json: +{string}""" + ) + # Added to get rid of pylint warning inconsistent-return-statements. + # pytest.fail has no return value (NoReturn). + return None + + +def _get_state_using_config_init_mockup( + mock_client: Client, +) -> Tuple[str, str]: + """ + Calls `config init mockup` on a mockup client and returns + the strings of the bootstrap accounts and the protocol + constants + + Note that because this a mockup specific operation, the `mock_client` + parameter must be in mockup mode; do not give a vanilla client. + """ + ba_json_file = tempfile.mktemp(prefix='tezos-bootstrap-accounts') + pc_json_file = tempfile.mktemp(prefix='tezos-proto-consts') + + mock_client.run( + [ + "--protocol", + protocol.HASH, + "config", + "init", + f"--{_BA_FLAG}", + ba_json_file, + f"--{_PC_FLAG}", + pc_json_file, + ] + ) + + with open(ba_json_file) as handle: + ba_str = handle.read() + with open(pc_json_file) as handle: + pc_str = handle.read() + + # Cleanup of tempfile.mktemp + os.remove(ba_json_file) + os.remove(pc_json_file) + + return (ba_str, pc_str) + + +def _get_state_using_config_show_mockup( + mock_client: Client, +) -> Tuple[str, str]: + """ + Calls `--mode mockup config show` on a mockup client and returns + the strings of the bootstrap accounts and the protocol + constants, by parsing standard output. + + Note that because this a mockup specific operation, the `mock_client` + parameter must be in mockup mode; do not give a vanilla client. + """ + + def _find_line_starting_with(strings, searched) -> int: + i = 0 + for string in strings: + if string.startswith(searched): + return i + i += 1 + return -1 + + def _parse_config_init_output(string: str) -> Tuple[str, str]: + """Parses the output of `--mode mockup config init` + and return the json of the bootstrap accounts + and the protocol constants + """ + tagline1 = f"Default value of --{_BA_FLAG}:" + bootstrap_accounts_index = string.find(tagline1) + assert bootstrap_accounts_index >= 0, f"{_BA_FLAG} line not found" + + tagline2 = f"Default value of --{_PC_FLAG}:" + proto_constants_index = string.find(tagline2) + assert proto_constants_index > 0, f"{_PC_FLAG} line not found" + + bc_json = string[ + bootstrap_accounts_index + len(tagline1) : proto_constants_index - 1 + ] + + pc_json = string[proto_constants_index + len(tagline2) + 1 :] + return (bc_json, pc_json) + + stdout = mock_client.run(["--protocol", protocol.HASH, "config", "show"]) + return _parse_config_init_output(stdout) + + +def _test_create_mockup_init_show_roundtrip( + sandbox: Sandbox, + read_initial_state, + read_final_state, + bootstrap_json: Optional[str] = None, + protocol_constants_json: Optional[str] = None, +): + """1/ Creates a mockup, using possibly custom bootstrap_accounts + (as specified by `bootstrap_json`) + 2/ Then execute either `--mode mockup config show` or + `--mode mockup config init` to obtain the mockup's parameters + (parse stdout if `show` is called, + read the files generated by `init` otherwise) + + This is done by executing `read_initial_state` + 3/ Recreate a mockup using the output gathered in 2/ and call + `--mode mockup config show`/`--mode mockup config init` + (this is done by executing `read_final_state`) to check that output + received is similar to output seen in 2. + + This is a roundtrip test. + """ + + ba_file = None + pc_file = None + try: + if protocol_constants_json is not None: + pc_file = tempfile.mktemp(prefix='tezos-proto-consts') + with open(pc_file, 'w') as handle: + handle.write(protocol_constants_json) + + if bootstrap_json is not None: + ba_file = tempfile.mktemp(prefix='tezos-bootstrap-accounts') + with open(ba_file, 'w') as handle: + handle.write(bootstrap_json) + + with tempfile.TemporaryDirectory(prefix='tezos-client.') as base_dir: + # Follow pattern of mockup_client fixture: + unmanaged_client = sandbox.create_client(base_dir=base_dir) + res = unmanaged_client.create_mockup( + protocol=protocol.HASH, + bootstrap_accounts_file=ba_file, + protocol_constants_file=pc_file, + ).create_mockup_result + assert res == CreateMockupResult.OK + mock_client = sandbox.create_client( + base_dir=base_dir, mode="mockup" + ) + (ba_str, pc_str) = read_initial_state(mock_client) + finally: + if pc_file is not None: + os.remove(pc_file) + if ba_file is not None: + os.remove(ba_file) + + # 2/ Check the json obtained is valid by building json objects + ba_sent = _try_json_loads(_BA_FLAG, ba_str) + pc_sent = _try_json_loads(_PC_FLAG, pc_str) + + # Test that the initial mockup call honored the values it received. If + # it didn't, all calls would return the default values all along, and + # everything would seem fine; but it wouldn't be. This was witnessed in + # https://gitlab.com/tezos/tezos/-/issues/938 + if bootstrap_json: + ba_input = json.loads(bootstrap_json) + assert ba_sent == ba_input + if protocol_constants_json: + pc_input = json.loads(protocol_constants_json) + assert pc_sent == pc_input + + # 3/ Pass obtained json to a new mockup instance, to check json + # is valid w.r.t. ocaml encoding + + # Use another directory so that the constants change takes effect + with tempfile.TemporaryDirectory( + prefix='tezos-client.' + ) as base_dir, tempfile.NamedTemporaryFile( + prefix='tezos-bootstrap-accounts', mode='w+t' + ) as ba_json_file, tempfile.NamedTemporaryFile( + prefix='tezos-proto-consts', mode='w+t' + ) as pc_json_file, tempfile.TemporaryDirectory( + prefix='tezos-client.' + ) as base_dir: + + ba_json_file.write(ba_str) + ba_json_file.flush() + pc_json_file.write(pc_str) + pc_json_file.flush() + + with tempfile.TemporaryDirectory(prefix='tezos-client.') as base_dir: + # Follow pattern of mockup_client fixture: + unmanaged_client = sandbox.create_client(base_dir=base_dir) + res = unmanaged_client.create_mockup( + protocol=protocol.HASH, + protocol_constants_file=pc_json_file.name, + bootstrap_accounts_file=ba_json_file.name, + ).create_mockup_result + assert res == CreateMockupResult.OK + mock_client = sandbox.create_client( + base_dir=base_dir, mode="mockup" + ) + # 4/ Retrieve state again + (ba_received_str, pc_received_str) = read_final_state(mock_client) + + # Convert it to json objects (check that json is valid) + ba_received = _try_json_loads(_BA_FLAG, ba_received_str) + pc_received = _try_json_loads(_PC_FLAG, pc_received_str) + + def _gen_assert_msg(flag, sent, received): + result = f"Json sent with --{flag} differs from" + result += " json received" + result += f"\nJson sent is:\n{sent}" + result += f"\nwhile json received is:\n{received}" + + # and finally check that json objects received are the same + # as the ones that were given as input + assert ba_sent == ba_received, _gen_assert_msg( + _BA_FLAG, ba_sent, ba_received + ) + assert pc_sent == pc_received, _gen_assert_msg( + _PC_FLAG, pc_sent, pc_received + ) + + +@pytest.mark.client +@pytest.mark.parametrize( + 'initial_bootstrap_accounts', [None, json.dumps(_create_accounts_list())] +) +@pytest.mark.parametrize( + 'protocol_constants', + [ + None, + json.dumps( + { + "initial_timestamp": "2021-02-03T12:34:56Z", + "chain_id": "NetXaFDF7xZQCpR", + "delay_per_missing_endorsement": "2", + "initial_endorsers": 2, + "min_proposal_quorum": 501, + "quorum_max": 7001, + "quorum_min": 2001, + "hard_storage_limit_per_operation": "60001", + "cost_per_byte": "251", + "endorsement_reward": ["1250001", "833334"], + "baking_reward_per_endorsement": ["1250001", "187501"], + "endorsement_security_deposit": "64000001", + "block_security_deposit": "512000001", + "origination_size": 258, + "seed_nonce_revelation_tip": "125001", + "tokens_per_roll": "8000000001", + "proof_of_work_threshold": "-2", + "hard_gas_limit_per_block": "10400001", + "hard_gas_limit_per_operation": "1040001", + "endorsers_per_block": 33, + "time_between_blocks": ["2", "1"], + "blocks_per_voting_period": 65, + "blocks_per_roll_snapshot": 5, + "blocks_per_commitment": 5, + "blocks_per_cycle": 9, + "preserved_cycles": 3, + "minimal_block_delay": "1", + "liquidity_baking_escape_ema_threshold": 1000000, + "liquidity_baking_subsidy": "2500000", + "liquidity_baking_sunset_level": 1024, + } + ), + ], +) +@pytest.mark.parametrize( + 'read_initial_state', + [_get_state_using_config_show_mockup, _get_state_using_config_init_mockup], +) +@pytest.mark.parametrize( + 'read_final_state', + [_get_state_using_config_show_mockup, _get_state_using_config_init_mockup], +) +def test_create_mockup_config_show_init_roundtrip( + sandbox: Sandbox, + initial_bootstrap_accounts, + protocol_constants, + read_initial_state, + read_final_state, +): + """1/ Create a mockup, using possibly custom bootstrap_accounts + (as specified by `initial_bootstrap_json`). + 2/ Then execute either `--mode mockup config show` + or `--mode mockup config init` to obtain the mockup's parameters, + as specified by `read_initial_state`. + 3/ Recreate a mockup using the output gathered in 2/ and call + `read_final_state` to check that output + received is similar to output seen in 2. + + This is a roundtrip test using a matrix. + """ + _test_create_mockup_init_show_roundtrip( + sandbox, + read_initial_state, + read_final_state, + initial_bootstrap_accounts, + protocol_constants, + ) + + +def test_transfer_rpc(mockup_client: Client): + """Variant of test_transfer that uses RPCs to get the balances.""" + giver = "bootstrap1" + receiver = "bootstrap2" + transferred = 1.0 + transferred_mutz = transferred * 1000000 + + def get_balance(tz1): + res = mockup_client.rpc( + 'get', + f'chains/main/blocks/head/' f'context/contracts/{tz1}/balance', + ) + return float(res) + + addresses = mockup_client.get_known_addresses() + giver_tz1 = addresses.wallet[giver] + recvr_tz1 = addresses.wallet[receiver] + giver_balance_before = get_balance(giver_tz1) + receiver_balance_before = get_balance(recvr_tz1) + mockup_client.transfer(transferred, giver, receiver) + giver_balance_after = get_balance(giver_tz1) + receiver_balance_after = get_balance(recvr_tz1) + + assert giver_balance_after < giver_balance_before - transferred_mutz + assert receiver_balance_after == receiver_balance_before + transferred_mutz + + +@pytest.mark.parametrize( + 'protos', + [ + (proto1, proto2) + for proto1 in [protocol.HASH, protocol.PREV_HASH] + for proto2 in [protocol.HASH, protocol.PREV_HASH, ""] + ], +) +@pytest.mark.parametrize( + 'command', + [ + ["config", "show"], + ["config", "init"], + ["list", "known", "addresses"], + ["get", "balance", "for", "bootstrap1"], + ], +) +def test_proto_mix( + sandbox: Sandbox, protos: Tuple[str, str], command: List[str] +): + """ + This test covers 3 cases: + + 1/ When proto's second element equals the first member: + it tests that the command works. + 2/ When proto's second element is empty: + it tests that the correct mockup implementation is picked + (i.e. the one of the first element) and that the command works. + 3/ When protos' second element is not empty and differs from + the first member: it tests + that creating a mockup with a protocol and using it with another + protocol fails. + """ + proto1 = protos[0] + proto2 = protos[1] + with tempfile.TemporaryDirectory(prefix='tezos-client.') as base_dir: + # Follow pattern of mockup_client fixture: + unmanaged_client = sandbox.create_client(base_dir=base_dir) + res = unmanaged_client.create_mockup(protocol=proto1) + assert res.create_mockup_result == CreateMockupResult.OK + mock_client = sandbox.create_client(base_dir=base_dir, mode="mockup") + cmd = (["--protocol", proto2] if proto2 else []) + command + success = (proto2 == proto1) or (not proto2) + (_, _, return_code) = mock_client.run_generic(cmd, check=False) + assert (return_code == 0) == success diff --git a/tests_python/tests_011/test_multinode_snapshot.py b/tests_python/tests_011/test_multinode_snapshot.py new file mode 100644 index 000000000000..6501d1298462 --- /dev/null +++ b/tests_python/tests_011/test_multinode_snapshot.py @@ -0,0 +1,753 @@ +import tempfile +import shutil +import pytest +from tools import utils, constants +from launchers.sandbox import Sandbox +from . import protocol + +PARAMS = constants.NODE_PARAMS + +BATCH_1 = 48 +BATCH_2 = 48 # not enough bakes to drag the savepoint after snapshot import +BATCH_3 = 32 # enough bakes to drag the savepoint +GROUP1 = [0, 1, 2] +GROUP2 = [0, 1, 2, 3, 4, 5] +GROUP_FULL = [1, 3] +GROUP_ROLLING = [2, 4, 5] +SNAPSHOT_DIR = tempfile.mkdtemp(prefix='tezos-snapshots.') +BLOCKS_PER_CYCLE = 8 +PRESERVED_CYCLES = 2 +RETAINED_CYCLES = 8 + + +def clean(node): + shutil.rmtree(node.node_dir) + + +# Restart node. Side effect: clean store caches +def restart(sandbox, node_id): + sandbox.node(node_id).terminate_or_kill() + sandbox.node(node_id).run() + assert sandbox.client(node_id).check_node_listening() + + +@pytest.mark.multinode +@pytest.mark.incremental +@pytest.mark.snapshot +@pytest.mark.slow +class TestMultiNodeSnapshot: + # Tests both the snapshot mechanism and the store's behaviour + # TL;DR, how it works: + # - bake few blocks using all history modes + # - export all kinds of snapshots + # - import all kinds of snapshots + # - check consistency (the snapshot's window includes genesis) + # - bake a few blocks + # - check consistency (the checkpoints should not move yet) + # - bake a few blocks + # - check consistency (the checkpoints should have moved) + # - export all kinds of snapshots + # - import all kinds of snapshots + # - check consistency (checkpoints should be still valid) + # - bake a few blocks + # - check consistency (the checkpoints should have moved) + + def test_init(self, sandbox: Sandbox): + # Node 0: archive baker + sandbox.add_node(0, params=PARAMS + ['--history-mode', 'archive']) + # Node 1: full + sandbox.add_node(1, params=PARAMS + ['--history-mode', 'full']) + # Node 2: rolling + sandbox.add_node(2, params=PARAMS + ['--history-mode', 'rolling']) + protocol.activate(sandbox.client(GROUP1[0]), activate_in_the_past=True) + + def test_bake_batch_1(self, sandbox, session): + for _ in range(BATCH_1): + utils.bake(sandbox.client(0)) + sandbox.client(0).endorse('bootstrap2') + session['head_hash'] = sandbox.client(0).get_head()['hash'] + session['head_level'] = sandbox.client(0).get_head()['header']['level'] + session['snapshot_level'] = session['head_level'] + + def test_group1_batch_1(self, sandbox, session): + for i in GROUP1: + assert utils.check_level(sandbox.client(i), session['head_level']) + + ########################################################################### + # Export all kinds of snapshots + def test_archive_export_full_1(self, sandbox, session): + file = f'{SNAPSHOT_DIR}/node0_batch_1.full' + export_level = session['snapshot_level'] + sandbox.node(0).snapshot_export( + file, params=['--block', f'{export_level}'] + ) + + def test_archive_export_rolling_1(self, sandbox, session): + file = f'{SNAPSHOT_DIR}/node0_batch_1.rolling' + export_level = session['snapshot_level'] + sandbox.node(0).snapshot_export( + file, params=['--block', f'{export_level}', '--rolling'] + ) + + def test_full_export_full_1(self, sandbox, session): + file = f'{SNAPSHOT_DIR}/node1_batch_1.full' + export_level = session['snapshot_level'] + sandbox.node(1).snapshot_export( + file, params=['--block', f'{export_level}'] + ) + + def test_full_export_rolling_1(self, sandbox, session): + file = f'{SNAPSHOT_DIR}/node1_batch_1.rolling' + export_level = session['snapshot_level'] + sandbox.node(1).snapshot_export( + file, params=['--block', f'{export_level}', '--rolling'] + ) + + def test_rolling_export_rolling_1(self, sandbox, session): + file = f'{SNAPSHOT_DIR}/node2_batch_1.rolling' + export_level = session['snapshot_level'] + sandbox.node(2).snapshot_export( + file, params=['--block', f'{export_level}', '--rolling'] + ) + + ########################################################################### + # Import all kinds of snapshots + # New node: 3 + def test_run_full_node_from_archive_1(self, sandbox): + file = f'{SNAPSHOT_DIR}/node0_batch_1.full' + sandbox.add_node(3, snapshot=file, params=PARAMS) + + # New node: 4 + def test_run_rolling_node_from_archive_1(self, sandbox): + file = f'{SNAPSHOT_DIR}/node0_batch_1.rolling' + sandbox.add_node(4, snapshot=file, params=PARAMS) + + # Reset node 1 + def test_reset_full_node_from_full_1(self, sandbox): + file = f'{SNAPSHOT_DIR}/node1_batch_1.full' + sandbox.rm_node(1) + sandbox.add_node(1, snapshot=file, params=PARAMS) + + # New node: 5 + def test_run_rolling_node_from_full_1(self, sandbox): + file = f'{SNAPSHOT_DIR}/node1_batch_1.rolling' + sandbox.add_node(5, snapshot=file, params=PARAMS) + + # Reset node 2 + def test_reset_rolling_node_from_rolling_1(self, sandbox): + file = f'{SNAPSHOT_DIR}/node2_batch_1.rolling' + sandbox.rm_node(2) + sandbox.add_node(2, snapshot=file, params=PARAMS) + + ########################################################################### + # Check consistency of imported snapshots + # Do not factorize calls to ease debugging + # For the full nodes + def test_node_1_consistency_1(self, sandbox, session): + node_id = 1 + restart(sandbox, node_id) + expected_level = session['snapshot_level'] + expected_checkpoint = expected_level + expected_savepoint = expected_checkpoint + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.full_node_blocks_availability( + node_id, sandbox, expected_savepoint, expected_level + ) + + def test_node_3_consistency_1(self, sandbox, session): + node_id = 3 + restart(sandbox, node_id) + expected_level = session['snapshot_level'] + expected_checkpoint = expected_level + expected_savepoint = expected_checkpoint + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.full_node_blocks_availability( + node_id, sandbox, expected_savepoint, expected_level + ) + + # For the rolling nodes + def test_node_2_consistency_1(self, sandbox, session): + node_id = 2 + restart(sandbox, node_id) + expected_level = session['snapshot_level'] + expected_checkpoint = expected_level + expected_savepoint = expected_checkpoint + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + def test_node_4_consistency_1(self, sandbox, session): + node_id = 4 + restart(sandbox, node_id) + expected_level = session['snapshot_level'] + expected_checkpoint = expected_level + expected_savepoint = expected_checkpoint + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + def test_node_5_consistency_1(self, sandbox, session): + node_id = 5 + restart(sandbox, node_id) + expected_level = session['snapshot_level'] + expected_checkpoint = expected_level + expected_savepoint = expected_checkpoint + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + ########################################################################### + # Bake a few blocks + def test_bake_batch_2(self, sandbox, session): + for _ in range(BATCH_2): + utils.bake(sandbox.client(0)) + sandbox.client(0).endorse('bootstrap2') + session['head_hash'] = sandbox.client(0).get_head()['hash'] + session['head_level'] = sandbox.client(0).get_head()['header']['level'] + for i in GROUP2: + assert utils.check_level(sandbox.client(i), session['head_level']) + + ########################################################################### + # Check consistency of imported snapshots after > 5 baked cycles + # The savepoints of full and rolling nodes **have not** been dragged yet + + # For the full nodes + def test_node_1_consistency_2(self, sandbox, session): + node_id = 1 + restart(sandbox, node_id) + expected_level = session['head_level'] + # last allowed fork level of the head + expected_checkpoint = ( + expected_level - PRESERVED_CYCLES * BLOCKS_PER_CYCLE + ) + savepoint_when_imported = session['snapshot_level'] + expected_savepoint = savepoint_when_imported + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.full_node_blocks_availability( + node_id, sandbox, expected_savepoint, expected_level + ) + + def test_node_3_consistency_2(self, sandbox, session): + node_id = 3 + restart(sandbox, node_id) + expected_level = session['head_level'] + # last allowed fork level of the head + expected_checkpoint = ( + expected_level - PRESERVED_CYCLES * BLOCKS_PER_CYCLE + ) + savepoint_when_imported = session['snapshot_level'] + expected_savepoint = savepoint_when_imported + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.full_node_blocks_availability( + node_id, sandbox, expected_savepoint, expected_level + ) + + # For the rolling nodes + # The caboose of rolling mode were no dragged yet as + # (checkpoint - max_op_ttl(head)) < savepoint + def test_node_2_consistency_2(self, sandbox, session): + node_id = 2 + restart(sandbox, node_id) + expected_level = session['head_level'] + # last allowed fork level of the head + expected_checkpoint = ( + expected_level - PRESERVED_CYCLES * BLOCKS_PER_CYCLE + ) + savepoint_when_imported = session['snapshot_level'] + expected_savepoint = savepoint_when_imported + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_caboose = max(expected_checkpoint - max_op_ttl, 0) + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + def test_node_4_consistency_2(self, sandbox, session): + node_id = 4 + restart(sandbox, node_id) + expected_level = session['head_level'] + # last allowed fork level of the head + expected_checkpoint = ( + expected_level - PRESERVED_CYCLES * BLOCKS_PER_CYCLE + ) + savepoint_when_imported = session['snapshot_level'] + expected_savepoint = savepoint_when_imported + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_caboose = max(expected_checkpoint - max_op_ttl, 0) + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + def test_node_5_consistency_2(self, sandbox, session): + node_id = 5 + restart(sandbox, node_id) + expected_level = session['head_level'] + # last allowed fork level of the head + expected_checkpoint = ( + expected_level - PRESERVED_CYCLES * BLOCKS_PER_CYCLE + ) + savepoint_when_imported = session['snapshot_level'] + expected_savepoint = savepoint_when_imported + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_caboose = max(expected_checkpoint - max_op_ttl, 0) + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + ########################################################################### + # Bake a few blocks + def test_bake_batch_3(self, sandbox, session): + for _ in range(BATCH_3): + utils.bake(sandbox.client(0)) + sandbox.client(0).endorse('bootstrap2') + session['head_hash'] = sandbox.client(0).get_head()['hash'] + session['head_level'] = sandbox.client(0).get_head()['header']['level'] + session['snapshot_level'] = session['head_level'] + for i in GROUP2: + assert utils.check_level(sandbox.client(i), session['head_level']) + + ########################################################################### + # Check consistency of imported snapshots after > 5 baked cycles + # The savepoints of full and rolling nodes **have** been dragged yet + + # For the full nodes + def test_node_1_consistency_3(self, sandbox, session): + node_id = 1 + restart(sandbox, node_id) + expected_level = session['head_level'] + # last allowed fork level of the head + expected_checkpoint = ( + expected_level - PRESERVED_CYCLES * BLOCKS_PER_CYCLE + ) + expected_savepoint = expected_checkpoint - ( + RETAINED_CYCLES * BLOCKS_PER_CYCLE + ) + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.full_node_blocks_availability( + node_id, sandbox, expected_savepoint, expected_level + ) + + def test_node_3_consistency_3(self, sandbox, session): + node_id = 3 + restart(sandbox, node_id) + expected_level = session['head_level'] + # last allowed fork level of the head + expected_checkpoint = ( + expected_level - PRESERVED_CYCLES * BLOCKS_PER_CYCLE + ) + expected_savepoint = expected_checkpoint - ( + RETAINED_CYCLES * BLOCKS_PER_CYCLE + ) + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.full_node_blocks_availability( + node_id, sandbox, expected_savepoint, expected_level + ) + + # For the rolling nodes + def test_node_2_consistency_3(self, sandbox, session): + node_id = 2 + restart(sandbox, node_id) + expected_level = session['head_level'] + # last allowed fork level of the head + expected_checkpoint = ( + expected_level - PRESERVED_CYCLES * BLOCKS_PER_CYCLE + ) + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint - ( + RETAINED_CYCLES * BLOCKS_PER_CYCLE + ) + expected_caboose = max(expected_checkpoint - max_op_ttl, 0) + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + def test_node_4_consistency_3(self, sandbox, session): + node_id = 4 + restart(sandbox, node_id) + expected_level = session['head_level'] + # last allowed fork level of the head + expected_checkpoint = ( + expected_level - PRESERVED_CYCLES * BLOCKS_PER_CYCLE + ) + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint - ( + RETAINED_CYCLES * BLOCKS_PER_CYCLE + ) + expected_caboose = max(expected_checkpoint - max_op_ttl, 0) + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + def test_node_5_consistency_3(self, sandbox, session): + node_id = 5 + restart(sandbox, node_id) + expected_level = session['head_level'] + # last allowed fork level of the head + expected_checkpoint = ( + expected_level - PRESERVED_CYCLES * BLOCKS_PER_CYCLE + ) + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint - ( + RETAINED_CYCLES * BLOCKS_PER_CYCLE + ) + expected_caboose = max(expected_checkpoint - max_op_ttl, 0) + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + ########################################################################### + # Re-export all kinds of snapshots + def test_archive_export_full_2(self, sandbox, session): + file = f'{SNAPSHOT_DIR}/node0_batch_3.full' + export_level = session['snapshot_level'] + sandbox.node(0).snapshot_export( + file, params=['--block', f'{export_level}'] + ) + + def test_archive_export_rolling_2(self, sandbox, session): + file = f'{SNAPSHOT_DIR}/node0_batch_3.rolling' + export_level = session['snapshot_level'] + sandbox.node(0).snapshot_export( + file, params=['--block', f'{export_level}', '--rolling'] + ) + + def test_full_export_full_2(self, sandbox, session): + file = f'{SNAPSHOT_DIR}/node1_batch_3.full' + export_level = session['snapshot_level'] + sandbox.node(1).snapshot_export( + file, params=['--block', f'{export_level}'] + ) + + def test_full_export_rolling_2(self, sandbox, session): + file = f'{SNAPSHOT_DIR}/node1_batch_3.rolling' + export_level = session['snapshot_level'] + sandbox.node(1).snapshot_export( + file, params=['--block', f'{export_level}', '--rolling'] + ) + + def test_rolling_export_rolling_2(self, sandbox, session): + file = f'{SNAPSHOT_DIR}/node2_batch_3.rolling' + export_level = session['snapshot_level'] + sandbox.node(2).snapshot_export( + file, params=['--block', f'{export_level}', '--rolling'] + ) + + ########################################################################### + # Import all kinds of snapshots + # Reset node: 3 + def test_run_full_node_from_archive_2(self, sandbox): + file = f'{SNAPSHOT_DIR}/node0_batch_3.full' + sandbox.rm_node(3) + sandbox.add_node(3, snapshot=file, params=PARAMS) + + # Reset node: 4 + def test_run_rolling_node_from_archive_2(self, sandbox): + file = f'{SNAPSHOT_DIR}/node0_batch_3.rolling' + sandbox.rm_node(4) + sandbox.add_node(4, snapshot=file, params=PARAMS) + + # Reset node 1 + def test_reset_full_node_from_full_2(self, sandbox): + file = f'{SNAPSHOT_DIR}/node1_batch_3.full' + sandbox.rm_node(1) + sandbox.add_node(1, snapshot=file, params=PARAMS) + + # Reset node: 5 + def test_run_rolling_node_from_full_2(self, sandbox): + file = f'{SNAPSHOT_DIR}/node1_batch_3.rolling' + sandbox.rm_node(5) + sandbox.add_node(5, snapshot=file, params=PARAMS) + + # Reset node 2 + def test_reset_rolling_node_from_rolling_2(self, sandbox): + file = f'{SNAPSHOT_DIR}/node2_batch_3.rolling' + sandbox.rm_node(2) + sandbox.add_node(2, snapshot=file, params=PARAMS) + + ########################################################################### + # Check consistency of imported snapshots with > 5 cycles + + # For the full nodes + def test_node_1_consistency_4(self, sandbox, session): + node_id = 1 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level + expected_savepoint = expected_checkpoint + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.full_node_blocks_availability( + node_id, sandbox, expected_savepoint, expected_level + ) + + def test_node_3_consistency_4(self, sandbox, session): + node_id = 3 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level + expected_savepoint = expected_checkpoint + expected_caboose = 0 + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.full_node_blocks_availability( + node_id, sandbox, expected_savepoint, expected_level + ) + + # For the rolling nodes + def test_node_2_consistency_4(self, sandbox, session): + node_id = 2 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint + expected_caboose = expected_checkpoint - max_op_ttl + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + def test_node_4_consistency_4(self, sandbox, session): + node_id = 4 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint + expected_caboose = expected_checkpoint - max_op_ttl + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + def test_node_5_consistency_4(self, sandbox, session): + node_id = 5 + restart(sandbox, node_id) + expected_level = session['head_level'] + expected_checkpoint = expected_level + head = sandbox.client(node_id).get_head() + max_op_ttl = head['metadata']['max_operations_ttl'] + expected_savepoint = expected_checkpoint + expected_caboose = expected_checkpoint - max_op_ttl + utils.node_consistency_after_import( + node_id, + sandbox, + expected_level, + expected_checkpoint, + expected_savepoint, + expected_caboose, + ) + utils.rolling_node_blocks_availability( + node_id, + sandbox, + expected_savepoint, + expected_caboose, + expected_level, + ) + + ########################################################################### + # Clean exported snapshots + + def test_clean_files(self): + shutil.rmtree(SNAPSHOT_DIR) diff --git a/tests_python/tests_011/test_multinode_storage_reconstruction.py b/tests_python/tests_011/test_multinode_storage_reconstruction.py new file mode 100644 index 000000000000..c72cc50ca690 --- /dev/null +++ b/tests_python/tests_011/test_multinode_storage_reconstruction.py @@ -0,0 +1,177 @@ +import pytest +from tools import utils +from launchers.sandbox import Sandbox +from . import protocol + +PARAMS = ['--bootstrap-threshold', '0'] +# 2*cycle_size - (protocol_activation) +CEMENTED_LIMIT = 2 * 8 - 1 +# The whole store is cemented +BATCH_1 = 48 +# 2 cycles are pruned in full 5 mode +# This constant is above MAX_OP_TTL +BATCH_2 = 144 + +SNAPSHOT_1 = f'snapshot_block_{BATCH_1}.full' +SNAPSHOT_2 = f'snapshot_block_{BATCH_2}.full' + +EXPECTED_BLOCK_ERROR = 'Unable to find block' +EXPECTED_COMMAND_ERROR = 'Command failed: Unable to find block' + + +def clear_cache(sandbox, node_id): + # Restart node to clear the store's cache + sandbox.node(node_id).terminate_or_kill() + sandbox.node(node_id).run() + assert sandbox.client(node_id).check_node_listening() + + +@pytest.mark.multinode +@pytest.mark.incremental +@pytest.mark.snapshot +@pytest.mark.slow +class TestMultiNodeStorageReconstruction: + def test_init(self, sandbox: Sandbox): + sandbox.add_node(0, params=PARAMS) + protocol.activate(sandbox.client(0), activate_in_the_past=True) + # Keep node 3 in the dance + # History mode by default (full) + sandbox.add_node(3, params=PARAMS) + + # Node 0 bakes a few blocks + def test_bake_node0_level_a(self, sandbox: Sandbox, session: dict): + for _ in range(BATCH_1): + utils.bake(sandbox.client(0)) + session['head_hash'] = sandbox.client(0).get_head()['hash'] + session['head_level'] = sandbox.client(0).get_head()['header']['level'] + + # Node 3 tries to reconstruct its storage after the first batch. + # Reconstruct is expected to fail: nothing to reconstruct + def test_reconstruct_on_bootstrapped_node(self, sandbox: Sandbox): + # Stop, reconstruct the storage and restart the node + sandbox.node(3).terminate_or_kill() + pattern = 'nothing to reconstruct.' + with utils.assert_run_failure(pattern): + sandbox.node(3).reconstruct() + sandbox.node(3).run() + assert sandbox.client(3).check_node_listening() + + # Node 0 exports a snapshot + def test_export_snapshot_batch1(self, sandbox: Sandbox, session: dict): + node_export = sandbox.node(0) + session['snapshot_1_head_hash'] = session['head_hash'] + session['snapshot_1_head_level'] = session['head_level'] + file = f'{sandbox.node(0).node_dir}/{SNAPSHOT_1}' + export_level = session['head_level'] + assert export_level == (BATCH_1 + 1) + node_export.snapshot_export(file, params=['--block', f'{export_level}']) + + # Node 1 import and reconstruct (using the `--reconstruct` + # flag of the `snapshot import` command) + def test_node1_import_and_reconstruct( + self, sandbox: Sandbox, session: dict + ): + n0_tmpdir = sandbox.node(0).node_dir + file = f'{n0_tmpdir}/{SNAPSHOT_1}' + sandbox.add_node( + 1, + snapshot=file, + reconstruct=True, + params=PARAMS + ['--history-mode', 'archive'], + ) + assert utils.check_level(sandbox.client(1), session['head_level']) + clear_cache(sandbox, 1) + + # Test that all the reconstructed blocks can be requested + # with their metadata + def test_node1_request_all_blocks_with_metadata( + self, sandbox: Sandbox, session: dict + ): + for i in range(session['head_level']): + assert utils.get_block_at_level(sandbox.client(1), i) + + # Node 2 import and then reconstruct using the dedicated command. + def test_import_before_reconstruct(self, sandbox: Sandbox, session: dict): + n0_tmpdir = sandbox.node(0).node_dir + file = f'{n0_tmpdir}/{SNAPSHOT_1}' + sandbox.add_node(2, snapshot=file) + assert utils.check_level(sandbox.client(2), session['head_level']) + + # Checking node's 2 storage + def test_unavailable_blocks_node2(self, sandbox: Sandbox, session: dict): + # We must fail while requesting those pruned blocks + for i in range(1, session['snapshot_1_head_level'] - 1): + with utils.assert_run_failure(EXPECTED_COMMAND_ERROR): + utils.get_block_metadata_at_level(sandbox.client(2), i) + + # Call the reconstruct command on Node 2 + def test_reconstruct_after_snapshot_import(self, sandbox: Sandbox): + # Stop, reconstruct the storage and restart the node + sandbox.node(2).terminate_or_kill() + sandbox.node(2).reconstruct() + sandbox.node(2).run() + assert sandbox.client(2).check_node_listening() + + # Test that all the reconstructed blocks can be requested + # with their metadata + def test_available_blocks_node_2(self, sandbox: Sandbox, session: dict): + # We should now success requesting those reconstructed blocks + for i in range(session['head_level']): + assert utils.get_block_at_level(sandbox.client(2), i) + + # Second batch + + # Bake a few blocks + def test_bake_node0_level_b(self, sandbox: Sandbox, session: dict): + for _ in range(BATCH_2 - BATCH_1): + utils.bake(sandbox.client(0)) + session['head_hash'] = sandbox.client(0).get_head()['hash'] + session['head_level'] = sandbox.client(0).get_head()['header']['level'] + assert utils.check_level(sandbox.client(0), session['head_level']) + assert utils.check_level(sandbox.client(1), session['head_level']) + assert utils.check_level(sandbox.client(2), session['head_level']) + + # Node 0 exports a snapshot (with no floating to reconstruct) + def test_export_snapshot_batch2(self, sandbox: Sandbox, session: dict): + node_export = sandbox.node(0) + # to export on a cemented cycle + export_block_level = 64 + export_block = utils.get_block_at_level( + sandbox.client(0), export_block_level + ) + export_block_hash = export_block['hash'] + session['snapshot_2_head_hash'] = export_block_hash + session['snapshot_2_head_level'] = export_block_level + file = f'{sandbox.node(0).node_dir}/{SNAPSHOT_2}' + node_export.snapshot_export( + file, params=['--block', f'{export_block_level}'] + ) + + # Check that node 3 (full bootstrapped) can be reconstructed + def test_sync_node3(self, sandbox: Sandbox, session: dict): + assert utils.check_level(sandbox.client(3), session['head_level']) + clear_cache(sandbox, 3) + + # Checking node's 3 storage + def test_unavailable_blocks_node3(self, sandbox: Sandbox): + savepoint = int(sandbox.client(3).get_savepoint()) + assert utils.get_block_at_level(sandbox.client(3), savepoint) + # We must fail while requesting blocks before savepoint + for i in range(1, savepoint): + with utils.assert_run_failure(EXPECTED_COMMAND_ERROR): + utils.get_block_metadata_at_level(sandbox.client(3), i) + + def test_reconstruct_command_after_bootstrap(self, sandbox: Sandbox): + # Stop, reconstruct the storage and restart the node + sandbox.node(3).terminate_or_kill() + sandbox.node(3).reconstruct() + # History mode is now archive + sandbox.node(3).run() + assert sandbox.client(3).check_node_listening() + + def test_available_blocks_node3(self, sandbox: Sandbox, session: dict): + assert sandbox.client(3).get_savepoint() == 0 + assert sandbox.client(3).get_caboose() == 0 + # We should now success requesting those reconstructed blocks + for i in range(session['head_level']): + assert utils.get_block_at_level(sandbox.client(3), i) diff --git a/tests_python/tests_011/test_multiple_transfers.py b/tests_python/tests_011/test_multiple_transfers.py new file mode 100644 index 000000000000..0871c4010bea --- /dev/null +++ b/tests_python/tests_011/test_multiple_transfers.py @@ -0,0 +1,133 @@ +"""Test the multiple transfer feature of tezos-client""" +import os +import json +import pytest + +from client.client import Client +from tools import utils +from tools.constants import IDENTITIES +from .contract_paths import CONTRACT_PATH + + +def manager(client: Client) -> str: + """Originate and return the alias of a manager contract""" + alias = 'manager' + path = os.path.join(CONTRACT_PATH, 'entrypoints', alias + '.tz') + pubkey = IDENTITIES['bootstrap2']['identity'] + utils.init_with_transfer( + client, path, f'"{pubkey}"', 1000, sender='bootstrap1' + ) + return alias + + +@pytest.fixture(scope="class") +def big_map_entrypoints(client: Client) -> str: + """Originate and return the alias of a big_map_entrypoints contract""" + alias = 'big_map_entrypoints' + path = os.path.join(CONTRACT_PATH, 'entrypoints', alias + '.tz') + utils.init_with_transfer( + client, path, 'Pair {} {Elt "Hello" 42}', 1000, sender='bootstrap1' + ) + return alias + + +@pytest.fixture +def source(client: Client, request) -> str: + """A contract alias that will be used as source for a multiple transfers + command. + + This fixture is indirectly instantiated: the argument specifies + whether the alias of an originated manager contract should be + returned (if argument equals 'manager'). Otherwise, the alias is + assumed to already exist in the client's wallet and is returned + unmodified. + """ + alias = request.param + return manager(client) if alias == 'manager' else alias + + +@pytest.mark.contract +@pytest.mark.incremental +class TestMultipleTransfers: + def test_empty(self, client: Client): + with utils.assert_run_failure(r'Empty operation list'): + json_obj = '[]' + client.run(client.cmd_batch('bootstrap1', json_obj)) + + @pytest.mark.parametrize( + "payer, source", + [('bootstrap2', 'manager'), ('bootstrap4', 'bootstrap4')], + indirect=["source"], + ) + def test_transfer_json_to_entrypoint_with_args( + self, big_map_entrypoints: str, client: Client, payer: str, source: str + ): + """Test the multiple transfers command with a single transfer + to a contract's entrypoint, with implicit accounts or a manager + contract as source as per parametrization. + """ + balance_source = client.get_mutez_balance(source) + balance_payer = client.get_mutez_balance(payer) + fee = 0.0123 + fee_mutez = utils.mutez_of_tez(fee) + json_obj = [ + { + "destination": big_map_entrypoints, + "amount": "0", + "fee": str(fee), + "gas-limit": "65942", + "storage-limit": "1024", + "arg": '"Hello"', + "entrypoint": "mem_right", + } + ] + json_ops = json.dumps(json_obj, separators=(',', ':')) + client.run(client.cmd_batch(source, json_ops)) + utils.bake(client, 'bootstrap5') + new_balance_source = client.get_mutez_balance(source) + new_balance_payer = client.get_mutez_balance(payer) + + if payer != source: + assert balance_source == new_balance_source + + assert balance_payer - fee_mutez == new_balance_payer + + @pytest.mark.parametrize( + "payer, source", + [('bootstrap2', 'manager'), ('bootstrap4', 'bootstrap4')], + ) + def test_multiple_transfers(self, client: Client, payer: str, source: str): + """Test a multiple transfers to implicit accounts, with implicit + accounts or a manager contract as source as per parametrization. + """ + balance_source = client.get_mutez_balance(source) + balance_bootstrap1 = client.get_mutez_balance('bootstrap1') + balance_bootstrap3 = client.get_mutez_balance('bootstrap3') + amount_1 = 10.1 + amount_mutez_1 = utils.mutez_of_tez(amount_1) + amount_3 = 11.01 + amount_mutez_3 = utils.mutez_of_tez(amount_3) + json_obj = [ + {"destination": "bootstrap1", "amount": str(amount_1)}, + {"destination": "bootstrap3", "amount": str(amount_3)}, + ] + json_ops = json.dumps(json_obj, separators=(',', ':')) + client.run(client.cmd_batch(source, json_ops)) + utils.bake(client, 'bootstrap5') + new_balance_source = client.get_mutez_balance(source) + new_balance_bootstrap1 = client.get_mutez_balance('bootstrap1') + new_balance_bootstrap3 = client.get_mutez_balance('bootstrap3') + + if payer == source: + fee_first_transfer = 403 + fee_second_transfer = 307 + source_fee_mutez = fee_first_transfer + fee_second_transfer + else: + source_fee_mutez = 0 + + assert ( + balance_source - amount_mutez_1 - amount_mutez_3 - source_fee_mutez + == new_balance_source + ) + assert balance_bootstrap1 + amount_mutez_1 == new_balance_bootstrap1 + assert balance_bootstrap3 + amount_mutez_3 == new_balance_bootstrap3 diff --git a/tests_python/tests_011/test_multisig.py b/tests_python/tests_011/test_multisig.py new file mode 100644 index 000000000000..06108327a82c --- /dev/null +++ b/tests_python/tests_011/test_multisig.py @@ -0,0 +1,620 @@ +# tezos-client has builtin support for multisig smart contracts. See +# docs/user/multisig.rst for more details about it. + +# This file tests the client multisig support; more precisely it tests +# that both the generic and the legacy versions of the multisig smart +# contract behave as intended. For all commands, we check that we can +# interact with the multisig contract when invoking it by its address +# or by its alias. + +import os +import re +from typing import List +import pytest +from tools import utils, constants +from client.client import Client +from .contract_paths import MINI_SCENARIOS_CONTRACT_PATH, ATTIC_CONTRACT_PATH + + +def get_keys(client): + """Generate 3 pairs of keys using various schemes and return the list + of aliases.""" + keys = ['foo', 'bar', 'boo'] + sigs = [None, 'secp256k1', 'ed25519'] + for key, sig in zip(keys, sigs): + args = [] if sig is None else ['--sig', sig] + client.gen_key(key, args) + return keys + + +@pytest.fixture(scope="class") +def keys(client): + return get_keys(client) + + +def msig_path(msig_version: str) -> str: + return os.path.join( + MINI_SCENARIOS_CONTRACT_PATH, f'{msig_version}_multisig.tz' + ) + + +MSIG_PARAMS = [ + {'by_address': by_address, 'msig_version': msig_version} + for msig_version in ['generic', 'legacy'] + for by_address in [True, False] +] + + +def parse_msig_storage(storage: str): + """Parse the storage of a multisig contract to get its counter (as a + number), threshold (as a number), and the keys of the signers (as + Micheline sequence in a string).""" + # put everything on a single line + storage = ' '.join(storage.split('\n')) + storage_regexp = r'Pair\s+?([0-9]+)\s+?([0-9]+)\s+?(.*)\s*' + match = re.search(storage_regexp, storage) + assert match is not None + return { + 'counter': int(match[1]), + 'threshold': int(match[2]), + 'keys': match[3], + } + + +def resolve_key_alias(client: Client, alias: str) -> str: + """Convert a key alias into a public key that can be understood in + Michelson.""" + ret = client.show_address(alias).public_key + assert ret is not None + return ret + + +def build_michelson_key_list(client: Client, keys: List[str]): + """From a list of key aliases, build a Michelson list of public keys.""" + keys = [resolve_key_alias(client, k) for k in keys] + return '{"' + '"; "'.join(keys) + '"}' + + +def build_msig_storage( + client: Client, counter: int, threshold: int, keys: List[str] +): + """Build a multisig storage from its components: a counter, a + threshold and the list of signer public keys.""" + keys = build_michelson_key_list(client, keys) + return f'Pair {counter} {threshold} {keys}' + + +def assert_michelson_eq(client, data1, data2, typ): + """Check that two Michelson expressions of the same type are equal by + normalizing them.""" + normalized1 = client.normalize(data=data1, typ=typ) + normalized2 = client.normalize(data=data2, typ=typ) + assert normalized1 == normalized2 + + +def assert_msig_storage_eq(client, data1, data2): + """Check that two multisig storages are equal.""" + assert_michelson_eq(client, data1, data2, 'pair nat nat (list key)') + + +def assert_msig_counter_incr(current_storage, new_storage): + """Check that [new_storage] is the same multisig storage than + [current_storage] except that it uses the next counter.""" + current_storage = parse_msig_storage(current_storage) + new_storage = parse_msig_storage(new_storage) + assert new_storage['counter'] == 1 + current_storage['counter'] + assert new_storage['threshold'] == current_storage['threshold'] + assert new_storage['keys'] == current_storage['keys'] + + +@pytest.fixture(scope="class", params=MSIG_PARAMS) +def msig(client: Client, keys, request): + """This fixture originates a multisig contract with a threshold of 2 + and the keys given as parameter. The version of the script is given by + the msig_version parameter, it can be either 'generic' or + 'legacy'. This fixture returns a dictionary containing: + + - a [handle] that can be used to interact with the contract: + either the address of the script or an alias, depending on the + [by_address] parameter + + - the list of [keys] that are stored in the contract which is a + copy of the [keys] parameter + + - the [version], which is a copy of the [msig_version] parameter + + """ + + # We use the same alias for all multisig originations, this makes + # testing simpler but requires using the '--force' option. + msig_alias = 'msig' + msig_version = request.param['msig_version'] + by_address = request.param['by_address'] + initial_storage = build_msig_storage( + client=client, counter=0, threshold=2, keys=keys + ) + deployment = client.originate( + msig_alias, + 100, + 'bootstrap1', + msig_path(msig_version), + # Initialize with empty key list and null threshold + ['--init', initial_storage, '--burn-cap', '100', '--force'], + ) + utils.bake(client) + handle = deployment.contract if by_address else msig_alias + return {'handle': handle, 'keys': keys, 'version': msig_version} + + +@pytest.mark.incremental +class TestMultisig: + def test_deploy_multisig(self, msig, client: Client): + """Test that: + - the script originated by the "deploy multisig" command, + - the generic_multisig.tz script found in the mini_scenarios + directory, and + - the script printed by the "show multisig script" + are the same.""" + keys = msig['keys'] + + # The command cannot originate the legacy contract so there is + # nothing to test in the legacy case. + if msig['version'] == 'generic': + client.deploy_msig( + 'dummy_msig', + 100, + 'bootstrap1', + 2, + keys, + ['--burn-cap', '100', '--force'], + ) + utils.bake(client) + expected_hash = ( + 'exprub9UzpxmhedNQnsv1J1DazWGJnj1dLhtG1fxkUoWSdFLBGLqJ4' + ) + assert expected_hash in client.run( + ['show', 'supported', 'multisig', 'hashes'] + ) + assert client.get_script_hash(msig['handle']) == expected_hash + assert client.get_script_hash('dummy_msig') == expected_hash + assert client.hash_script( + [client.run(['show', 'multisig', 'script'])] + ) == [(expected_hash, None)] + assert client.get_balance('dummy_msig') == 100 + + def test_transfer(self, msig, client: Client, session: dict): + """Test the client command for signing a multisig transfer from key + number 0 and store the signature in the session.""" + keys = msig['keys'] + key = keys[0] + session['sig0'] = client.msig_sign_transfer( + msig['handle'], 10, 'bootstrap2', key + ) + + def test_prepare_msig_transfer(self, msig, client: Client): + """Test the client command for preparing a transfer. The result of the + command is ignored in this test, we only test that the command + succeeds.""" + client.msig_prepare_transfer(msig['handle'], 10, 'bootstrap2') + + def test_prepare_msig_sign(self, msig, client: Client, session: dict): + """Produce signatures for keys number 1 and 2 using the the + preparation command together with the sign_bytes client command. The + signatures are stored in the session.""" + to_sign = client.msig_prepare_transfer( + msig['handle'], 10, 'bootstrap2', ['--bytes-only'] + ) + session['sig1'] = client.sign_bytes_of_string(to_sign, msig['keys'][1]) + session['sig2'] = client.sign_bytes_of_string(to_sign, msig['keys'][2]) + + def test_transfer_failure(self, msig, client: Client, session: dict): + """Test transfer failure when there are too few signatures.""" + error_pattern = ( + r"Not enough signatures: " + + r"only 1 signatures were given " + + r"but the threshold is currently 2" + ) + + with utils.assert_run_failure(error_pattern): + client.msig_transfer( + msig['handle'], + 10, + 'bootstrap2', + 'bootstrap1', + [session['sig2']], + ) + + def test_transfer_success(self, msig, client: Client, session: dict): + """Test a successful transfer using signatures obtained by different + methods. The signatures are taken from the session.""" + current_storage = client.get_storage(msig['handle']) + current_balance = client.get_balance(msig['handle']) + + client.msig_transfer( + msig['handle'], + 10, + 'bootstrap2', + 'bootstrap1', + [session['sig0'], session['sig2']], + ) + utils.bake(client) + new_storage = client.get_storage(msig['handle']) + assert_msig_counter_incr(current_storage, new_storage) + new_balance = client.get_balance(msig['handle']) + assert new_balance == current_balance - 10 + + def test_default_entrypoint(self, msig, client): + """The generic multisig contract features an unauthorized default + entrypoint to receive donations but the legacy one does not.""" + + def cmd(): + client.transfer( + amount=100, giver='bootstrap1', receiver=msig['handle'] + ) + + if msig['version'] == 'legacy': + error_pattern = r'Invalid argument passed to contract' + with utils.assert_run_failure(error_pattern): + cmd() + else: + current_storage = client.get_storage(msig['handle']) + current_balance = client.get_balance(msig['handle']) + cmd() + utils.bake(client) + new_storage = client.get_storage(msig['handle']) + new_balance = client.get_balance(msig['handle']) + assert new_storage == current_storage + assert new_balance == current_balance + 100 + + def test_transfer_with_entrypoint(self, msig, client: Client): + """Both versions of the contract can call arbitrary entrypoints of + type unit. This test uses the two possible methods to produce the + signatures.""" + current_storage = client.get_storage(msig['handle']) + current_balance = client.get_balance(msig['handle']) + contract = ( + 'parameter (or (unit %a) (string %b)); ' + 'storage unit; ' + 'code {CDR; NIL operation; PAIR}' + ) + client.originate( + 'dest_entrypoint', + 0, + 'bootstrap1', + contract, + args=['--burn-cap', '10.0', '--force'], + ) + args = ['--entrypoint', 'a'] + utils.bake(client) + to_sign = client.msig_prepare_transfer( + msig_name=msig['handle'], + amount=10, + dest='dest_entrypoint', + args=args + ['--bytes-only'], + ) + sig0 = client.sign_bytes_of_string(to_sign, msig['keys'][0]) + sig2 = client.msig_sign_transfer( + msig_name=msig['handle'], + amount=10, + dest='dest_entrypoint', + secret_key=msig['keys'][2], + args=args, + ) + client.msig_transfer( + msig_name=msig['handle'], + amount=10, + dest='dest_entrypoint', + src='bootstrap1', + signatures=[sig0, sig2], + args=args, + ) + utils.bake(client) + new_storage = client.get_storage(msig['handle']) + new_balance = client.get_balance(msig['handle']) + assert_msig_counter_incr(current_storage, new_storage) + assert new_balance == current_balance - 10 + + def test_transfer_with_arg(self, msig, client: Client): + """The generic multisig contract can call other contracts with + arbitrary parameters but the legacy one can only send Unit.""" + contract = ( + 'parameter (or (int %a) (string %b)); ' + 'storage unit; ' + 'code {CDR; NIL operation; PAIR}' + ) + client.originate( + 'dest', + 0, + 'bootstrap1', + contract, + args=['--burn-cap', '10.0', '--force'], + ) + args = ['--entrypoint', 'a', '--arg', '42'] + utils.bake(client) + + def cmd(): + return client.msig_prepare_transfer( + msig_name=msig['handle'], + amount=10, + dest='dest', + args=args + ['--bytes-only'], + ) + + if msig['version'] == 'legacy': + error_pattern = ( + r'This multisig contract can only transfer tokens to' + ' contracts of type unit; calling a contract with argument 42' + ' is not supported.' + ) + with utils.assert_run_failure(error_pattern): + cmd() + else: + current_storage = client.get_storage(msig['handle']) + current_balance = client.get_balance(msig['handle']) + to_sign = cmd() + utils.bake(client) + sig0 = client.sign_bytes_of_string(to_sign, msig['keys'][0]) + sig2 = client.msig_sign_transfer( + msig_name=msig['handle'], + amount=10, + dest='dest', + secret_key=msig['keys'][2], + args=args, + ) + client.msig_transfer( + msig_name=msig['handle'], + amount=10, + dest='dest', + src='bootstrap1', + signatures=[sig0, sig2], + args=args, + ) + utils.bake(client) + new_storage = client.get_storage(msig['handle']) + new_balance = client.get_balance(msig['handle']) + assert_msig_counter_incr(current_storage, new_storage) + assert new_balance == current_balance - 10 + + def test_transfer_ill_typed(self, msig, client: Client): + """Test that the multisig transfer preparation command type checks the + parameter.""" + error_pattern = ( + ( + r'The entrypoint b of contract .* ' + 'called from a multisig contract is of type string; ' + 'the provided parameter 42 is ill-typed.' + ) + if msig['version'] == 'generic' + else ( + r'This multisig contract can only transfer tokens to' + ' contracts of type unit; calling a contract with argument 42' + ' is not supported.' + ) + ) + + args = ['--entrypoint', 'b', '--arg', '42'] + + def cmd(): + client.msig_prepare_transfer( + msig_name=msig['handle'], + amount=10, + dest='dest', + args=args + ['--bytes-only'], + ) + + with utils.assert_run_failure(error_pattern): + cmd() + + def test_transfer_too_high(self, msig, client: Client): + """Test that the multisig transfer preparation command checks the + balance.""" + expected_warning = ( + 'Transferred amount is bigger than current multisig balance' + ) + + client.msig_prepare_transfer( + msig_name=msig['handle'], + amount=1000, + dest='bootstrap1', + args=['--bytes-only'], + expected_warning=expected_warning, + ) + + def test_multiple_operations(self, msig, client: Client): + """The generic multisig client can run lambdas, this can be used to + atomically run several operations.""" + bootstrap1_address = constants.IDENTITIES['bootstrap1']['identity'] + bootstrap2_address = constants.IDENTITIES['bootstrap2']['identity'] + bootstrap3_address = constants.IDENTITIES['bootstrap3']['identity'] + lam = ( + '{ DROP; NIL operation; ' + f'PUSH key_hash "{bootstrap1_address}"; IMPLICIT_ACCOUNT; ' + 'PUSH mutez 1000000; UNIT; TRANSFER_TOKENS; CONS; ' + f'PUSH key_hash "{bootstrap2_address}"; IMPLICIT_ACCOUNT; ' + 'PUSH mutez 2000000; UNIT; TRANSFER_TOKENS; CONS; ' + f'PUSH key_hash "{bootstrap3_address}"; SOME; ' + 'SET_DELEGATE; CONS}' + ) + lam = client.normalize( + lam, typ='lambda unit (list operation)', mode='Optimized' + ) + + def cmd(): + return client.msig_prepare_lambda( + msig_name=msig['handle'], lam=lam, args=['--bytes-only'] + ) + + if msig['version'] == 'legacy': + error_pattern = 'This multisig contract has a fixed set of actions' + with utils.assert_run_failure(error_pattern): + cmd() + else: + current_storage = client.get_storage(msig['handle']) + current_balance = client.get_balance(msig['handle']) + to_sign = cmd() + sig0 = client.sign_bytes_of_string(to_sign, msig['keys'][0]) + sig2 = client.msig_sign_lambda( + msig_name=msig['handle'], lam=lam, secret_key=msig['keys'][2] + ) + client.msig_run_lambda( + msig_name=msig['handle'], + lam=lam, + src='bootstrap1', + signatures=[sig0, sig2], + ) + utils.bake(client) + new_storage = client.get_storage(msig['handle']) + new_balance = client.get_balance(msig['handle']) + assert_msig_counter_incr(current_storage, new_storage) + assert new_balance == current_balance - 3 + # TODO: check the delegate change + + def test_multiple_operations_failure(self, msig, client: Client): + """Test for the error message for ill-typed lambdas.""" + lam = '{ DROP }' + + def cmd(): + client.msig_prepare_lambda( + msig_name=msig['handle'], lam=lam, args=['--bytes-only'] + ) + + error_pattern = ( + ( + r'The provided lambda .* for multisig contract' + r' is ill-typed; .* is expected.' + ) + if msig['version'] == 'generic' + else 'This multisig contract has a fixed set of actions' + ) + + with utils.assert_run_failure(error_pattern): + cmd() + + def test_delegate_change(self, msig, client: Client): + """Test the multisig command for changing delegate.""" + current_storage = client.get_storage(msig['handle']) + current_balance = client.get_balance(msig['handle']) + sig0 = client.msig_sign_set_delegate( + msig['handle'], 'bootstrap5', msig['keys'][0] + ) + to_sign = client.msig_prepare_set_delegate( + msig['handle'], 'bootstrap5', ['--bytes-only'] + ) + sig2 = client.sign_bytes_of_string(to_sign, msig['keys'][2]) + client.msig_set_delegate( + msig['handle'], 'bootstrap5', 'bootstrap1', [sig0, sig2] + ) + utils.bake(client) + new_storage = client.get_storage(msig['handle']) + new_balance = client.get_balance(msig['handle']) + assert_msig_counter_incr(current_storage, new_storage) + assert new_balance == current_balance + + def test_delegate_withdraw(self, msig, client: Client): + """Test the multisig command for removing delegation.""" + current_storage = client.get_storage(msig['handle']) + current_balance = client.get_balance(msig['handle']) + sig0 = client.msig_sign_withdrawing_delegate( + msig['handle'], msig['keys'][0] + ) + to_sign = client.msig_prepare_withdrawing_delegate( + msig['handle'], ['--bytes-only'] + ) + + sig1 = client.sign_bytes_of_string(to_sign, msig['keys'][1]) + client.msig_withdrawing_delegate( + msig['handle'], 'bootstrap1', [sig0, sig1] + ) + utils.bake(client) + new_storage = client.get_storage(msig['handle']) + new_balance = client.get_balance(msig['handle']) + assert_msig_counter_incr(current_storage, new_storage) + assert new_balance == current_balance + + def test_run_transaction_change_keys_and_threshold( + self, msig, client: Client + ): + """Test changing the keys and threshold with the `run transaction` + command.""" + current_storage = client.get_storage(msig['handle']) + current_counter = parse_msig_storage(storage=current_storage)['counter'] + current_balance = client.get_balance(msig['handle']) + keys = msig['keys'] + sig0 = client.msig_sign_setting_threshold( + msig['handle'], keys[0], 2, [keys[0], keys[2]] + ) + to_sign = client.msig_prepare_setting_threshold( + msig['handle'], 2, [keys[0], keys[2]], ['--bytes-only'] + ) + sig2 = client.sign_bytes_of_string(to_sign, msig['keys'][2]) + client.msig_run_transaction( + msig['handle'], to_sign, 'bootstrap1', [sig0, sig2] + ) + utils.bake(client) + new_storage = client.get_storage(msig['handle']) + expected_counter = 1 + current_counter + expected_storage = build_msig_storage( + client=client, + counter=expected_counter, + threshold=2, + keys=[keys[0], keys[2]], + ) + assert_msig_storage_eq(client, new_storage, expected_storage) + new_balance = client.get_balance(msig['handle']) + assert new_balance == current_balance + + def test_change_keys_and_threshold(self, msig, client: Client): + """Test changing the keys and threshold with `set threshold of + multisig` command.""" + current_storage = client.get_storage(msig['handle']) + current_counter = parse_msig_storage(storage=current_storage)['counter'] + current_balance = client.get_balance(msig['handle']) + keys = msig['keys'] + new_keys = [keys[0], keys[2]] + sig0 = client.msig_sign_setting_threshold( + msig['handle'], keys[0], 2, new_keys + ) + to_sign = client.msig_prepare_setting_threshold( + msig['handle'], 2, new_keys, ['--bytes-only'] + ) + sig2 = client.sign_bytes_of_string(to_sign, msig['keys'][2]) + client.msig_set_threshold( + msig['handle'], 2, new_keys, 'bootstrap1', [sig0, sig2] + ) + utils.bake(client) + new_storage = client.get_storage(msig['handle']) + expected_counter = 1 + current_counter + expected_storage = build_msig_storage( + client=client, + counter=expected_counter, + threshold=2, + keys=[keys[0], keys[2]], + ) + assert_msig_storage_eq(client, new_storage, expected_storage) + new_balance = client.get_balance(msig['handle']) + assert new_balance == current_balance + + +class TestUnsupportedMultisig: + """Verify that non-multisig contracts are rejected""" + + def test_deploy_nonmultisig(self, client: Client): + contract = os.path.join(ATTIC_CONTRACT_PATH, 'id.tz') + client.originate( + 'id', + 0, + 'bootstrap1', + contract, + args=['--burn-cap', '10.0', '--force', '--init', '""'], + ) + utils.bake(client) + + error_pattern = ( + 'The hash of this script is ' + 'exprv8K6ceBpFH5SFjQm4BRYSLJCHQBFeQU6BFTdvQSRPaPkzdLyAL, ' + 'it was not found among in the list of known multisig ' + 'script hashes.' + ) + + with utils.assert_run_failure(error_pattern): + client.msig_transfer('id', 10, 'bootstrap2', 'bootstrap1', []) diff --git a/tests_python/tests_011/test_nonce_seed_revelation.py b/tests_python/tests_011/test_nonce_seed_revelation.py new file mode 100644 index 000000000000..b9c287a37883 --- /dev/null +++ b/tests_python/tests_011/test_nonce_seed_revelation.py @@ -0,0 +1,108 @@ +import time +import pytest +from tools import constants +from launchers.sandbox import Sandbox +from . import protocol + + +BLOCKS_PER_COMMITMENT = protocol.PARAMETERS['blocks_per_commitment'] +BLOCKS_PER_CYCLE = protocol.PARAMETERS['blocks_per_cycle'] +FIRST_PROTOCOL_BLOCK = 1 +TIMEOUT = 60 + + +@pytest.mark.incremental +@pytest.mark.slow +@pytest.mark.baker +class TestNonceSeedRevelation: + """Test baker injection of nonce revelations. + + See http://tezos.gitlab.io/011_hangzhou/proof_of_stake.html + + Runs a node and a baker. The baker bakes two full cycles. + We collect nonce hashes from the first cycle. And check + that they are revealed in the second cycle""" + + def test_init(self, sandbox: Sandbox): + """Run a node and a baker. + + The node runs in archive mode to get metadata in `client.get_block()`. + The protocol is activated in the past so the baker can submit blocks + immediately without waiting for current time.""" + + node_params = constants.NODE_PARAMS + ['--history-mode', 'archive'] + sandbox.add_node(0, params=node_params) + protocol.activate(sandbox.client(0), activate_in_the_past=True) + sandbox.add_baker(0, 'bootstrap1', proto=protocol.DAEMON) + + @pytest.mark.timeout(TIMEOUT) + def test_wait_for_two_cycles(self, sandbox: Sandbox): + """Poll the node until target level is reached """ + target = FIRST_PROTOCOL_BLOCK + 2 * BLOCKS_PER_CYCLE + while True: + time.sleep(3) # sleep first to avoid useless first query + if sandbox.client(0).get_level() >= target: + break + # No need to bake more + sandbox.rm_baker(0, proto=protocol.DAEMON) + + def test_get_all_blocks(self, sandbox: Sandbox, session: dict): + """Retrieve all blocks for two full cycles. """ + blocks = [ + sandbox.client(0).get_block(FIRST_PROTOCOL_BLOCK + i) + for i in range(2 * BLOCKS_PER_CYCLE) + ] + session['blocks'] = blocks + + def test_cycle_alignment(self, session): + """Test cycles start where they are supposed to start. + + Not really needed but helps clarifying cycles positions.""" + + blocks = session['blocks'] + # blocks[0] is considered cycle = 0, cycle_position = 0 for the new + # protocol, but because it is a protocol transition block, it + # doesn't have the "cycle" and "cycle_position" metadata (unlike + # the remaining blocks) + assert blocks[1]['metadata']['level_info']['cycle'] == 0 + assert blocks[1]['metadata']['level_info']['cycle_position'] == 1 + assert blocks[BLOCKS_PER_CYCLE]['metadata']['level_info']['cycle'] == 1 + assert ( + blocks[BLOCKS_PER_CYCLE]['metadata']['level_info']['cycle_position'] + == 0 + ) + + def test_collect_seed_nonce_hashes(self, session): + """Collect nonce hashes in the block headers in the first cycle """ + seed_nonce_hashes = {} + blocks = session['blocks'] + for i in range(BLOCKS_PER_CYCLE // BLOCKS_PER_COMMITMENT): + level = (i + 1) * BLOCKS_PER_COMMITMENT - 1 + seed_nonce_hash = blocks[level]['header']['seed_nonce_hash'] + seed_nonce_hashes[level] = seed_nonce_hash + session['seed_nonce_hashes'] = seed_nonce_hashes + + def test_check_revelations(self, session): + """Collect reveal ops in second cycle and check they match + the nonce hashes from first cycle.""" + blocks = session['blocks'] + seed_nonce_hashes = session['seed_nonce_hashes'] + ops = [] + # collect all operations + for i in range(BLOCKS_PER_CYCLE, 2 * BLOCKS_PER_CYCLE): + ops.extend(blocks[i]['operations'][2]) + reveal_ops = {} + for operation in ops: + content = operation['contents'][0] + # there should be only revelations there + assert content['kind'] == "seed_nonce_revelation" + level = content['level'] - FIRST_PROTOCOL_BLOCK + # Can't submit twice the same reveal op + assert level not in reveal_ops + # level should match a seed + assert level in seed_nonce_hashes + reveal_ops[level] = content['nonce'] + + # check all nonce hashes have been revealed + assert len(reveal_ops) == len(seed_nonce_hashes) + # we could go a step further and check that revelations are correct diff --git a/tests_python/tests_011/test_openapi.py b/tests_python/tests_011/test_openapi.py new file mode 100644 index 000000000000..9348d2302b31 --- /dev/null +++ b/tests_python/tests_011/test_openapi.py @@ -0,0 +1,73 @@ +""" Tests generating the implementation of openapi/swagger: + https://swagger.io/ + + This script launches a sandbox node, activates folder specific + protocol, gets the RPC descriptions as JSON, and converts this JSON + into an OpenAPI specification. + + This test mimicks src/openapi/generate.sh. +""" + +import json +import subprocess +from pathlib import Path +import requests +import openapi_spec_validator +import pytest + +from launchers.sandbox import Sandbox +from tools.constants import NODE_PARAMS +from . import protocol + + +def _get_tezos_node_version() -> str: + cmd = ["ocaml", "../scripts/print_version.ml"] + process_ret = subprocess.run( + cmd, check=True, capture_output=True, text=True + ) + version = process_ret.stdout.strip() + assert version, "version should not be empty" + return version + + +class TestOpenAPI: + @pytest.fixture(scope="class") + def sandbox(self, sandbox: Sandbox): + sandbox.add_node(0, params=NODE_PARAMS) + client = sandbox.client(0) + protocol.activate(client) + return sandbox + + @pytest.mark.parametrize( + "rpc_path", ["describe", "describe/chains/main/blocks/head/"] + ) + def test_validity(self, sandbox: Sandbox, rpc_path: str, tmp_path: Path): + """ + Mimicks the script src/openapi/generate.sh. Generates the API + and check it generates a valid OpenAPI specification. + """ + node = sandbox.node(0) + addr = f"http://localhost:{node.rpc_port}/{rpc_path}?recurse=yes" + json_path = tmp_path / "result.json" + with open(json_path, "w") as o_file: + json_res = requests.get(addr).json() + json.dump(json_res, o_file) + + # If you need to debug, insert time.sleep(15) in there, + # to give you time to inspect generated files before the + # enclosing 'with' block finishes or to execute the dune + # command manually while the temporary files are still there. + version = _get_tezos_node_version() + cmd = [ + "dune", + "exec", + "../src/bin_openapi/rpc_openapi.exe", + "--", + version, + str(json_path.absolute()), + ] + process_ret = subprocess.run( + cmd, check=True, capture_output=True, text=True + ) + res = json.loads(process_ret.stdout) + openapi_spec_validator.validate_spec(res) diff --git a/tests_python/tests_011/test_p2p.py b/tests_python/tests_011/test_p2p.py new file mode 100644 index 000000000000..d32da3e80374 --- /dev/null +++ b/tests_python/tests_011/test_p2p.py @@ -0,0 +1,147 @@ +import time +import pytest +from tools import constants +from launchers.sandbox import Sandbox + + +NUM_NODES = 5 +NUM_RETRIES = 20 # empirical values for testing a liveness property +POLLING_TIME = 10 # NUM_RETRY * POLLING_TIME = 200s, should be conservative + + +@pytest.mark.multinode +@pytest.mark.incremental +class TestTrustedRing: + """This test sets up a network of public peers (running the default + p2p protocol), with no initial bootstrap peers. It initializes a + trusted ring relationship, and checks that points are advertised + correctly to the whole network.""" + + def test_init(self, sandbox: Sandbox): + for i in range(NUM_NODES): + sandbox.add_node( + i, + private=False, + peers=[], + params=constants.NODE_PARAMS, + config_client=False, + ) + + def test_no_peers(self, sandbox: Sandbox): + """ Initially, nobody knows other peers. """ + for client in sandbox.all_clients(): + res = client.p2p_stat() + assert not res.peers + + def test_add_peers(self, sandbox: Sandbox): + """ Set up a trusted ring topology. """ + base_p2p = sandbox.p2p + for i in range(NUM_NODES): + client = sandbox.client(i) + client.trust_peer(base_p2p + ((i + 1) % NUM_NODES)) + + def test_check_clique(self, sandbox: Sandbox): + """Everyone should be connected to everyone else. This is a + liveness property. Its realization depends on the timing of the + p2p maintenance process. The check is repeated up to NUM_RETRIES + times with a POLLING_TIME seconds wait.""" + for i in range(NUM_NODES): + client = sandbox.client(i) + for _ in range(NUM_RETRIES): + points = client.p2p_stat().points.values() + num_connected = len( + [point for point in points if point.is_connected] + ) + if num_connected == NUM_NODES - 1: + break + time.sleep(POLLING_TIME) + assert num_connected == NUM_NODES - 1 + + def test_check_tables(self, sandbox: Sandbox): + """Test various assumptions on the point/peer tables. + Each peer has exactly one trusted neighbor. Tables don't + contain their own peer/point id and contain exactly NUM_NODES - 1 + values. + + The previous test should guarantee that maintenance has been + performed when this test is run.""" + base_p2p = sandbox.p2p + for i in range(NUM_NODES): + client = sandbox.client(i) + point_id = f'127.0.0.1:{base_p2p + i}' + peer_id = client.rpc('get', '/network/self') + res = client.p2p_stat() + assert peer_id not in res.peers + assert point_id not in res.points + num_trusted = 0 + for point_id, point in res.points.items(): + num_trusted += point.is_trusted + assert num_trusted == 1 + assert len(res.peers) == NUM_NODES - 1 + assert len(res.points) == NUM_NODES - 1 + + def test_set_expected_peers(self, sandbox: Sandbox): + """For all nodes, we add one expected peer_id + for the successor node.""" + peers_id = dict() + for i in range(NUM_NODES): + client = sandbox.client(i) + peers_id[i] = client.rpc('get', '/network/self') + + for i in range(NUM_NODES): + client = sandbox.client(i) + client.set_expected_peer_id( + sandbox.p2p + ((i + 1) % NUM_NODES), + peers_id[(i + 1) % NUM_NODES], + ) + + def test_expected_peers(self, sandbox: Sandbox): + """For all nodes, we check that expected peer_id was + set properly.""" + peers_id = dict() + for i in range(NUM_NODES): + client = sandbox.client(i) + peers_id[i] = client.rpc('get', '/network/self') + + for i in range(NUM_NODES): + client = sandbox.client(i) + expected_id = client.get_expected_peer_id( + sandbox.p2p + ((i + 1) % NUM_NODES) + ) + assert expected_id == peers_id[(i + 1) % NUM_NODES] + + def test_wrong_expected_peer(self, sandbox: Sandbox): + """We change the expected peer_id set previously to a wrong + expected peer_id.""" + peers_id = dict() + for i in range(NUM_NODES): + client = sandbox.client(i) + peers_id[i] = client.rpc('get', '/network/self') + + for i in range(NUM_NODES): + client = sandbox.client(i) + client.set_expected_peer_id( + sandbox.p2p + ((i + 2) % NUM_NODES), peers_id[i] + ) + + def test_check_stat_with_wrong_expected_peers(self, sandbox: Sandbox): + """All nodes are public, everyone should be connected. But + only one neighbor should be trusted.""" + base_p2p = sandbox.p2p + for i in range(NUM_NODES): + client = sandbox.client(i) + point_id = '127.0.0.1:' + str(base_p2p + i) + peer_id = client.rpc('get', '/network/self') + res = client.p2p_stat() + assert peer_id not in res.peers + assert point_id not in res.points + num_trusted = 0 + num_connected = 0 + for point_id, point in res.points.items(): + num_trusted += point.is_trusted + num_connected += point.is_connected + assert len(res.peers) == NUM_NODES - 1 + assert len(res.points) == NUM_NODES - 1 + assert num_trusted == 1 + # We lost two connections + assert num_connected == NUM_NODES - 1 - 2 diff --git a/tests_python/tests_011/test_per_block_votes.py b/tests_python/tests_011/test_per_block_votes.py new file mode 100644 index 000000000000..93dfe733faab --- /dev/null +++ b/tests_python/tests_011/test_per_block_votes.py @@ -0,0 +1,119 @@ +import time +from typing import Optional, Iterator + +import pytest + +from launchers.sandbox import Sandbox +from tools import utils, constants, paths + +from . import protocol + + +def run_vote_file_test(sandbox, filename): + sandbox.rm_baker(0, proto=protocol.DAEMON) + sandbox.add_baker( + 0, + 'bootstrap1', + proto=protocol.DAEMON, + run_params=["--votefile", filename], + ) + if not sandbox.log_dir: + pytest.skip() + time.sleep(1) + assert sandbox.logs + assert utils.check_logs(sandbox.logs, r'Error') + + +def run_vote_file_test_error(sandbox, filename, error_pattern): + sandbox.rm_baker(0, proto=protocol.DAEMON) + sandbox.add_baker( + 0, + 'bootstrap1', + proto=protocol.DAEMON, + run_params=["--votefile", filename], + ) + if not sandbox.log_dir: + pytest.skip() + time.sleep(1) + assert sandbox.logs + assert not utils.check_logs(sandbox.logs, error_pattern) + + +def run_nonexistent_file_test(sandbox, filename): + error_pattern = ( + r'The provided block vote file path ' + f'"{filename}" does not point to an existing file.' + ) + run_vote_file_test_error(sandbox, filename, error_pattern) + + +def run_invalid_file_test(sandbox, filename): + error_pattern = ( + r'The provided block vote file path ' + f'"{filename}" does not point to a valid JSON file.' + ) + run_vote_file_test_error(sandbox, filename, error_pattern) + + +def run_wrong_content_file_test(sandbox, filename): + error_pattern = ( + r'The provided block vote file ' + f'"{filename}" is a valid JSON file but its content is unexpected.' + ) + run_vote_file_test_error(sandbox, filename, error_pattern) + + +@pytest.fixture(scope="class") +def sandbox(log_dir: Optional[str], singleprocess: bool) -> Iterator[Sandbox]: + """Sandboxed network of nodes where daemons are allowed to fail. + + Nodes, bakers and endorsers are added/removed dynamically.""" + # log_dir is None if not provided on command-line + # singleprocess is false if not provided on command-line + with Sandbox( + paths.TEZOS_HOME, + constants.IDENTITIES, + log_dir=log_dir, + singleprocess=singleprocess, + ) as sandbox: + yield sandbox + + +class TestAllPerBlockVotes: + def test_setup_network(self, sandbox: Sandbox): + parameters = dict(protocol.PARAMETERS) + # each priority has a delay of 1 sec + parameters["time_between_blocks"] = ["1"] + sandbox.add_node(0, params=constants.NODE_PARAMS) + protocol.activate(sandbox.client(0), parameters) + sandbox.add_baker(0, 'bootstrap1', proto=protocol.DAEMON) + + def test_wait_for_protocol(self, sandbox: Sandbox): + clients = sandbox.all_clients() + for client in clients: + proto = protocol.HASH + assert utils.check_protocol(client, proto) + + def test_true_vote_file(self, sandbox: Sandbox): + filename = "tests_011/per_block_vote_files/true.json" + run_vote_file_test(sandbox, filename) + + def test_false_vote_file(self, sandbox: Sandbox): + filename = "tests_011/per_block_vote_files/false.json" + run_vote_file_test(sandbox, filename) + + def test_nonexistent_vote_file(self, sandbox: Sandbox): + filename = "tests_011/per_block_vote_files/nonexistant.json" + run_nonexistent_file_test(sandbox, filename) + + def test_invalid_json(self, sandbox: Sandbox): + filename = "tests_011/per_block_vote_files/invalid.json" + run_invalid_file_test(sandbox, filename) + + def test_nonboolean(self, sandbox: Sandbox): + filename = "tests_011/per_block_vote_files/non_boolean.json" + run_wrong_content_file_test(sandbox, filename) + + def test_wrong_key(self, sandbox: Sandbox): + filename = "tests_011/per_block_vote_files/wrong_key.json" + run_wrong_content_file_test(sandbox, filename) diff --git a/tests_python/tests_011/test_perf_endorsement.py b/tests_python/tests_011/test_perf_endorsement.py new file mode 100644 index 000000000000..ae748b398455 --- /dev/null +++ b/tests_python/tests_011/test_perf_endorsement.py @@ -0,0 +1,83 @@ +import re +import pytest +from client.client import Client +from tools import constants, utils +from . import protocol + +ENDORSING_SLOTS_PER_BLOCK = 2048 +NUM_ACCOUNTS = 256 +ACCOUNTS = [f'bootstrap{i}' for i in range(1, NUM_ACCOUNTS + 1)] +MAX_VALIDATION_TIME_MS = 1000 + + +@pytest.fixture(scope="session") +def required_log_dir( + log_dir: str, +) -> str: + """Skip test if CLI user-provided logging directory is not given""" + if log_dir is None: + pytest.skip('test must be run with "--log-dir LOG_DIR: option"') + return log_dir + + +@pytest.fixture(scope="class") +def client(sandbox): + + sandbox.add_node(0, config_client=False, params=constants.NODE_PARAMS) + client = sandbox.client(0) + client.import_secret_key( + 'activator', + 'unencrypted:edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6', + ) + bootstrap_accounts = [] + for account in ACCOUNTS: + client.gen_key(account) + address = sandbox.client(0).show_address(account, show_secret=True) + bootstrap_accounts.append([address.public_key, "4000000000000"]) + parameters = dict(protocol.PARAMETERS) + parameters["bootstrap_accounts"] = bootstrap_accounts + parameters["endorsers_per_block"] = ENDORSING_SLOTS_PER_BLOCK + protocol.activate(client, parameters, activate_in_the_past=True) + client.logs = sandbox.logs + yield client + + +@pytest.mark.slow +@pytest.mark.incremental +class TestManualBaking: + """This test bakes a block with NUM_ACCOUNTS endorsers and + check that it takes less than MAX_VALIDATION_TIME_MS to + bake this block. + + MAX_VALIDATION_TIME_MS is conservative to avoid + spurious fails due to slow CI.""" + + def test_endorse(self, client: Client): + utils.bake(client) + for account in ACCOUNTS: + client.endorse(account) + utils.bake(client) + + def test_check_baking_time_from_log(self, required_log_dir, client): + assert required_log_dir + file = client.logs[0] + # pattern = r"completed in ?(\w*)ms" + pattern = r"validator.block.*completed in ?(.*)s" + time = [] + with open(file, "r") as stream: + for line in stream: + match = re.search(pattern, line) + if match is not None: + time.append(match.groups()[0]) + # 3 blocks have been baked in this test + # . protocol injection + # . empty block + # . block with endorsers + assert len(time) == 3 + endorser_block_time = time[-1] + # log format may use s or ms unit + if endorser_block_time[-1] == 'm': + endorser_block_time_ms = float(endorser_block_time[:-2]) + else: + endorser_block_time_ms = float(endorser_block_time[:-1]) * 1000 + assert float(endorser_block_time_ms) < MAX_VALIDATION_TIME_MS diff --git a/tests_python/tests_011/test_programs.py b/tests_python/tests_011/test_programs.py new file mode 100644 index 000000000000..184f8a17c817 --- /dev/null +++ b/tests_python/tests_011/test_programs.py @@ -0,0 +1,97 @@ +import itertools +from client.client import Client + +CONVERT_INPUT_FORMATS = ["michelson", "json", "binary"] +CONVERT_OUTPUT_FORMATS = ["michelson", "json", "binary", "ocaml"] +CONVERT_SCRIPT = { + "michelson": """{ parameter unit ; + storage unit ; + code { CDR ; + NIL operation ; + SELF ; + PUSH mutez 0 ; + UNIT ; + TRANSFER_TOKENS ; + DUP ; + DIP { CONS } ; + CONS ; + PAIR } }""", + "json": """[ { "prim": "parameter", "args": [ { "prim": "unit" } ] }, + { "prim": "storage", "args": [ { "prim": "unit" } ] }, + { "prim": "code", + "args": + [ [ { "prim": "CDR" }, + { "prim": "NIL", "args": [ { "prim": "operation" } ] }, + { "prim": "SELF" }, + { "prim": "PUSH", "args": [ { "prim": "mutez" }, { "int": "0" } ] }, + { "prim": "UNIT" }, { "prim": "TRANSFER_TOKENS" }, + { "prim": "DUP" }, + { "prim": "DIP", "args": [ [ { "prim": "CONS" } ] ] }, + { "prim": "CONS" }, { "prim": "PAIR" } ] ] } ]""", + "binary": "0x02000000300500036c0501036c050202000000210317053d036d03490743036a0000034f034d0321051f0200000002031b031b0342", # pylint: disable=line-too-long # noqa: E501 + "ocaml": "Seq (0, [Prim (1, K_parameter, [Prim (2, T_unit, [], [])], []); Prim (3, K_storage, [Prim (4, T_unit, [], [])], []); Prim (5, K_code, [Seq (6, [Prim (7, I_CDR, [], []); Prim (8, I_NIL, [Prim (9, T_operation, [], [])], []); Prim (10, I_SELF, [], []); Prim (11, I_PUSH, [Prim (12, T_mutez, [], []); Int (13, Z.zero)], []); Prim (14, I_UNIT, [], []); Prim (15, I_TRANSFER_TOKENS, [], []); Prim (16, I_DUP, [], []); Prim (17, I_DIP, [Seq (18, [Prim (19, I_CONS, [], [])])], []); Prim (20, I_CONS, [], []); Prim (21, I_PAIR, [], [])])], [])])", # pylint: disable=line-too-long # noqa: E501 +} +CONVERT_DATA = { + "michelson": """{ DROP ; + PUSH address "tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU" ; + CONTRACT unit ; + { IF_NONE { { UNIT ; FAILWITH } } {} } ; + PUSH mutez 1 ; + UNIT ; + TRANSFER_TOKENS ; + DIP { NIL operation } ; + CONS }""", + "json": """[ { "prim": "DROP" }, + { "prim": "PUSH", + "args": + [ { "prim": "address" }, + { "string": "tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU" } ] }, + { "prim": "CONTRACT", "args": [ { "prim": "unit" } ] }, + [ { "prim": "IF_NONE", + "args": [ [ [ { "prim": "UNIT" }, { "prim": "FAILWITH" } ] ], [] ] } ], + { "prim": "PUSH", "args": [ { "prim": "mutez" }, { "int": "1" } ] }, + { "prim": "UNIT" }, { "prim": "TRANSFER_TOKENS" }, + { "prim": "DIP", + "args": [ [ { "prim": "NIL", "args": [ { "prim": "operation" } ] } ] ] }, + { "prim": "CONS" } ]""", + "binary": "0x020000006403200743036e0100000024747a31666173774354446369527a45346f4a396a6e32566d3264766a6579413966557a550555036c0200000015072f02000000090200000004034f032702000000000743036a0001034f034d051f0200000004053d036d031b", # pylint: disable=line-too-long # noqa: E501 + "ocaml": "Seq (0, [Prim (1, I_DROP, [], []); Prim (2, I_PUSH, [Prim (3, T_address, [], []); String (4, \"tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU\")], []); Prim (5, I_CONTRACT, [Prim (6, T_unit, [], [])], []); Seq (7, [Prim (8, I_IF_NONE, [Seq (9, [Seq (10, [Prim (11, I_UNIT, [], []); Prim (12, I_FAILWITH, [], [])])]); Seq (13, [])], [])]); Prim (14, I_PUSH, [Prim (15, T_mutez, [], []); Int (16, Z.one)], []); Prim (17, I_UNIT, [], []); Prim (18, I_TRANSFER_TOKENS, [], []); Prim (19, I_DIP, [Seq (20, [Prim (21, I_NIL, [Prim (22, T_operation, [], [])], [])])], []); Prim (23, I_CONS, [], [])])", # pylint: disable=line-too-long # noqa: E501 + "type": "lambda unit (list operation)", +} + + +class TestProgramsCommands: + def test_convert_script(self, client: Client): + for (input_, output) in itertools.product( + CONVERT_INPUT_FORMATS, CONVERT_OUTPUT_FORMATS + ): + result = client.run( + [ + "convert", + "script", + CONVERT_SCRIPT[input_], + "from", + input_, + "to", + output, + ] + ) + assert result.strip() == f"{CONVERT_SCRIPT[output]}" + + def test_convert_data(self, client: Client): + for (input_, output, typecheck) in itertools.product( + CONVERT_INPUT_FORMATS, CONVERT_OUTPUT_FORMATS, [True, False] + ): + args = [ + "convert", + "data", + CONVERT_DATA[input_], + "from", + input_, + "to", + output, + ] + if typecheck: + args += ["--type", CONVERT_DATA["type"]] + result = client.run(args) + assert result.strip() == f"{CONVERT_DATA[output]}" diff --git a/tests_python/tests_011/test_proto_demo_counter.py b/tests_python/tests_011/test_proto_demo_counter.py new file mode 100644 index 000000000000..12c2c7bb5e68 --- /dev/null +++ b/tests_python/tests_011/test_proto_demo_counter.py @@ -0,0 +1,88 @@ +import time +import pytest +from tools import constants +from tools.constants import PROTO_DEMO_COUNTER, PROTO_GENESIS +from client.client import Client + +PARAMS = ['-p', PROTO_GENESIS] + + +@pytest.fixture(scope="class") +def client(sandbox): + """One node with genesis.""" + sandbox.add_node(0, params=constants.NODE_PARAMS) + client = sandbox.client(0) + yield client + + +@pytest.mark.incremental +class TestProtoDemo: + """Activate protocol demo_counter, inject operations and bake block. + + This test relies on the fixture client which launches a single + sandboxed node. + """ + + def test_proto_known(self, client: Client): + res = client.list_protocols() + assert PROTO_DEMO_COUNTER in res + + def test_proto_client_known(self, client: Client): + res = client.list_understood_protocols() + assert PROTO_DEMO_COUNTER[:12] in res + + def test_first_protocol(self, client: Client): + proto = 'PrihK96nBAFSxVL1GLJTVhu9YnzkMFiBeuJRPA8NwuZVZCE1L6i' + assert client.get_protocol() == proto + + def test_activate_proto(self, client: Client): + parameters = {'init_a': 100, 'init_b': 100} + res = client.activate_protocol_json( + PROTO_DEMO_COUNTER, parameters, key='activator', fitness='1' + ) + assert res.block_hash + + def test_level1(self, client: Client): + assert client.get_level() == 1 + + def test_protocol_genesis(self, client: Client): + assert client.get_protocol() == PROTO_GENESIS + + def test_bake_command(self, client: Client): + time.sleep(1) + client.run(['bake', 'This is block 2']) + + def test_level2(self, client: Client): + head = client.rpc('get', '/chains/main/blocks/head/') + assert head['header']['level'] == 2 + + def test_inject_operations(self, client: Client): + client.run(['increment', 'a']) + client.run(['increment', 'b']) + client.run(['transfer', '10']) + + def test_mempool(self, client: Client): + ops = client.get_mempool() + assert len(ops['applied']) == 3 + + def test_bake_command_2(self, client: Client): + time.sleep(1) + client.run(['bake', 'This is block 3']) + + def test_level3(self, client: Client): + head = client.rpc('get', '/chains/main/blocks/head/') + assert head['header']['level'] == 3 + + def test_rpc_counter_a(self, client: Client): + head = client.rpc('get', '/chains/main/blocks/head/counter/a') + assert head == 91 + + def test_rpc_counter_b(self, client: Client): + head = client.rpc('get', '/chains/main/blocks/head/counter/b') + assert head == 111 + + def test_get_counter_commands(self, client: Client): + message_a = client.run(['get', 'a']) + assert message_a == "The counter value is 91\n" + message_b = client.run(['get', 'b']) + assert message_b == "The counter value is 111\n" diff --git a/tests_python/tests_011/test_proto_demo_noops_manual_bake.py b/tests_python/tests_011/test_proto_demo_noops_manual_bake.py new file mode 100644 index 000000000000..215f2ed99f1e --- /dev/null +++ b/tests_python/tests_011/test_proto_demo_noops_manual_bake.py @@ -0,0 +1,97 @@ +import time +import pytest +from tools.constants import PROTO_DEMO_NOOPS, PROTO_GENESIS +from client.client import Client + +PARAMS = ['-p', PROTO_GENESIS] + + +@pytest.fixture(scope="class") +def client(sandbox): + """One node with genesis.""" + sandbox.add_node(0) + client = sandbox.client(0) + yield client + + +def forge_block_header_data(protocol_data): + """ + Returns a binary encoding for a dict of the form + `{'block_header_data: string}`, as expected by the protocol. + + This corresponds to the encoding given by + `data_encoding.(obj1 (req "block_header_data" string))`. See + `lib_data_encoding/data_encoding.mli` for the spec. + """ + assert len(protocol_data) == 1 and 'block_header_data' in protocol_data + string = protocol_data['block_header_data'] + tag = '0000' + padded_hex_len = f'{len(string):#06x}'[2:] + return tag + padded_hex_len + bytes(string, 'utf-8').hex() + + +@pytest.mark.incremental +class TestProtoDemo: + """Activate protocol demo_noops, injection some operations and bake block. + + This test relies on the fixture client which launches a single + sandboxed node. + """ + + def test_proto_known(self, client: Client): + res = client.list_protocols() + assert PROTO_DEMO_NOOPS in res + + def test_first_protocol(self, client: Client): + proto = 'PrihK96nBAFSxVL1GLJTVhu9YnzkMFiBeuJRPA8NwuZVZCE1L6i' + assert client.get_protocol() == proto + + def test_activate_proto(self, client: Client): + parameters = {} # type: dict + res = client.activate_protocol_json( + PROTO_DEMO_NOOPS, parameters, key='activator', fitness='1' + ) + assert res.block_hash + + def test_level1(self, client: Client): + assert client.get_level(params=PARAMS) == 1 + + def test_protocol_genesis(self, client: Client): + assert client.get_protocol(params=PARAMS) == PROTO_GENESIS + + def test_manual_bake(self, client: Client): + time.sleep(1) + message = "hello world" + + data = { + "protocol_data": { + "protocol": PROTO_DEMO_NOOPS, + "block_header_data": message, + }, + "operations": [], + } + block = client.rpc( + 'post', + '/chains/main/blocks/head/helpers/preapply/block', + data=data, + params=PARAMS, + ) + + protocol_data = {'block_header_data': message} + encoded = forge_block_header_data(protocol_data) + + shell_header = block['shell_header'] + shell_header['protocol_data'] = encoded + encoded = client.rpc( + 'post', + '/chains/main/blocks/head/helpers/forge_block_header', + data=shell_header, + params=PARAMS, + ) + + inject = {'data': encoded['block'], 'operations': []} + client.rpc('post', '/injection/block', data=inject, params=PARAMS) + + def test_level2(self, client: Client): + head = client.rpc('get', '/chains/main/blocks/head/', params=PARAMS) + assert head['header']['level'] == 2 diff --git a/tests_python/tests_011/test_rpc.py b/tests_python/tests_011/test_rpc.py new file mode 100644 index 000000000000..07453f28e24f --- /dev/null +++ b/tests_python/tests_011/test_rpc.py @@ -0,0 +1,644 @@ +import os +import time +import pytest +from tools import utils, constants +from launchers.sandbox import Sandbox +from . import protocol +from . import contract_paths + +CHAIN_ID = "main" +BLOCK_ID = "head" +PKH = "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" +PROTOCOL_HASH = protocol.HASH +BLOCK_LEVEL = "3" +LIST_OFFSET = "0" +OPERATION_OFFSET = "0" + + +@pytest.fixture(scope="class") +def session(): + session = dict() + session["implicit_accounts"] = [ + "tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN", + "tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv", + "tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv", + "tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU", + "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx", + ] + return session + + +@pytest.fixture(scope="class") +def contract_name(): + return "contract_identity" + + +@pytest.fixture(scope="class", params=[None, "proxy"]) +def sandbox(request, sandbox: Sandbox, contract_name, session: dict): + """Adds two nodes to sandbox. Using the first node, originates the + identity contract `id.tz` with the name contract_name and makes it + address available under session['originated_accounts']. + """ + sandbox.add_node(1, params=constants.NODE_PARAMS, mode=request.param) + sandbox.add_node(2, params=constants.NODE_PARAMS, mode=request.param) + client = sandbox.client(1) + protocol.activate(sandbox.client(1), activate_in_the_past=True) + utils.bake(client) + time.sleep(2) + # Deploy a contract + contract = os.path.join(contract_paths.CONTRACT_PATH, 'attic', 'id.tz') + args = ['--init', "\"tezos\"", '--burn-cap', '10.0'] + origination = client.originate( + contract_name, 10.0, "bootstrap1", contract, args + ) + session['originated_accounts'] = [origination.contract] + utils.bake(client) + assert utils.check_block_contains_operations( + client, [origination.operation_hash] + ) + return sandbox + + +@pytest.mark.incremental +@pytest.mark.mempool +@pytest.mark.multinode +@pytest.mark.slow +class TestRPCsExistence: + """ + Tests the existence of RPCs. It does not check the output! + Existence relying on the storage are tested using bootstrap + accounts/originated contracts. + """ + + block_hash = "" + + def test_config_file(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/config') + + def test_network_self(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/network/self') + + def test_constants(self, sandbox: Sandbox): + sandbox.client(2).rpc('get', '/network/self') + utils.bake(sandbox.client(1)) + time.sleep(3) + + def test_chain_blocks(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', f'/chains/{CHAIN_ID}/blocks') + + def test_chain_chain_id(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', f'/chains/{CHAIN_ID}/chain_id') + + def test_chain_invalid_blocks(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', f'/chains/{CHAIN_ID}/invalid_blocks') + + def test_errors(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/errors') + + def test_fetch_protocol_protocol_hash(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', f'/fetch_protocol/{PROTOCOL_HASH}') + + def test_network_connections(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/network/connections') + + def test_network_connections_peer_id(self, sandbox: Sandbox): + peer_id = sandbox.client(2).rpc('get', '/network/self') + sandbox.client(1).rpc('get', f'/network/connections/{peer_id}') + + def test_network_greylist_clear(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/network/greylist/clear') + + def test_network_peers(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/network/peers') + + def test_network_peers_peer_id(self, sandbox: Sandbox): + peer_id = sandbox.client(2).rpc('get', '/network/self') + sandbox.client(1).rpc('get', f'/network/peers/{peer_id}') + + def test_network_peers_peer_id_ban(self, sandbox: Sandbox): + peer_id = sandbox.client(2).rpc('get', '/network/self') + sandbox.client(1).rpc('get', f'/network/peers/{peer_id}/ban') + + def test_network_peers_peer_id_banned(self, sandbox: Sandbox): + peer_id = sandbox.client(2).rpc('get', '/network/self') + sandbox.client(1).rpc('get', f'/network/peers/{peer_id}/banned') + + def test_network_peers_peer_id_unban(self, sandbox: Sandbox): + peer_id = sandbox.client(2).rpc('get', '/network/self') + sandbox.client(1).rpc('get', f'/network/peers/{peer_id}/unban') + + def test_network_peers_peer_id_untrust(self, sandbox: Sandbox): + peer_id = sandbox.client(2).rpc('get', '/network/self') + sandbox.client(1).rpc('get', f'/network/peers/{peer_id}/untrust') + + def test_network_peers_peer_id_trust(self, sandbox: Sandbox): + peer_id = sandbox.client(2).rpc('get', '/network/self') + sandbox.client(1).rpc('get', f'/network/peers/{peer_id}/trust') + + def test_network_points(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/network/points') + + def test_network_points_point(self, sandbox: Sandbox): + points = sandbox.client(1).rpc('get', '/network/points') + point = points[-1][0] + sandbox.client(1).rpc('get', f'/network/points/{point}') + + def test_network_points_point_ban(self, sandbox: Sandbox): + points = sandbox.client(1).rpc('get', '/network/points') + point = points[-1][0] + sandbox.client(1).rpc('get', f'/network/points/{point}/ban') + + def test_network_points_point_banned(self, sandbox: Sandbox): + points = sandbox.client(1).rpc('get', '/network/points') + point = points[-1][0] + sandbox.client(1).rpc('get', f'/network/points/{point}/banned') + + def test_network_points_point_trust(self, sandbox: Sandbox): + points = sandbox.client(1).rpc('get', '/network/points') + point = points[-1][0] + sandbox.client(1).rpc('get', f'/network/points/{point}/trust') + + def test_network_points_point_unban(self, sandbox: Sandbox): + points = sandbox.client(1).rpc('get', '/network/points') + point = points[-1][0] + sandbox.client(1).rpc('get', f'/network/points/{point}/unban') + + def test_network_points_point_untrust(self, sandbox: Sandbox): + points = sandbox.client(1).rpc('get', '/network/points') + point = points[-1][0] + sandbox.client(1).rpc('get', f'/network/points/{point}/untrust') + + def test_network_stat(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/network/stat') + + def test_network_version(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/network/version') + + def test_network_versions(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/network/versions') + + def test_protocols(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/protocols') + + def test_protocols_protocol_hash(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', f'/protocols/{PROTOCOL_HASH}') + + def test_workers_block_validator(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/workers/block_validator') + + def test_workers_chain_validators(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/workers/chain_validators') + + def test_workers_chain_validator(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', f'/workers/chain_validators/{CHAIN_ID}') + + def test_workers_chain_validator_ddb(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/workers/chain_validators/{CHAIN_ID}/ddb' + ) + + def test_workers_chain_validator_peers_validators(self, sandbox): + sandbox.client(1).rpc( + 'get', f'/workers/chain_validators/{CHAIN_ID}/' 'peers_validators' + ) + + def test_workers_prevalidators(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', '/workers/prevalidators') + + def test_workers_prevalidators_chain_id(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', f'/workers/prevalidators/{CHAIN_ID}') + + def test_chain_block(self, sandbox: Sandbox): + sandbox.client(1).rpc('get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}') + + def test_chain_block_context_constants(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'context/constants' + ) + + def test_chain_block_context_constants_errors(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'context/constants/errors', + ) + + def test_chain_block_context_contracts(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'context/contracts' + ) + + def test_chain_block_context_contract_id( + self, sandbox: Sandbox, session: dict + ): + accounts = session["originated_accounts"] + session["implicit_accounts"] + for contract_id in accounts: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/contracts/{contract_id}', + ) + + def test_chain_block_context_contract_balance( + self, sandbox: Sandbox, session: dict + ): + accounts = session["originated_accounts"] + session["implicit_accounts"] + for contract_id in accounts: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/contracts/{contract_id}/balance', + ) + + def test_chain_block_context_contract_counter( + self, sandbox: Sandbox, session: dict + ): + # only implicit contracts, see + # proto_011_PtHangzH/lib_protocol/contract_repr.ml + for contract_id in session["implicit_accounts"]: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/contracts/{contract_id}/counter', + ) + + def test_chain_block_context_contract_delegate( + self, sandbox: Sandbox, session: dict + ): + for contract_id in session["implicit_accounts"]: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/contracts/{contract_id}/delegate', + ) + + def test_chain_block_context_contract_script_originated( + self, sandbox: Sandbox, session: dict + ): + # only originated contracts + accounts = session["originated_accounts"] + for contract_id in accounts: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/contracts/{contract_id}/script', + ) + + def test_chain_block_context_contract_script_implicit( + self, sandbox: Sandbox, session: dict + ): + accounts = session["implicit_accounts"] + for contract_id in accounts: + with utils.assert_run_failure('No service found at this URL'): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/contracts/{contract_id}/' + 'script', + ) + + def test_chain_block_context_contract_storage_originated( + self, sandbox: Sandbox, session: dict + ): + # only originated contracts + accounts = session["originated_accounts"] + for contract_id in accounts: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/contracts/{contract_id}/storage', + ) + + def test_chain_block_context_contract_storage_implicit( + self, sandbox: Sandbox, session: dict + ): + # only implicit contracts + accounts = session["implicit_accounts"] + for contract_id in accounts: + with utils.assert_run_failure('No service found at this URL'): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/contracts/{contract_id}/' + 'storage', + ) + + def test_chain_block_context_delegates(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'context/delegates' + ) + + def test_chain_block_context_delegate_implicit( + self, sandbox: Sandbox, session: dict + ): + # only implicit accounts + accounts = session["implicit_accounts"] + for pkh in accounts: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/delegates/{pkh}', + ) + + def test_chain_block_context_delegate_deactivated_implicit( + self, sandbox: Sandbox, session: dict + ): + # only implicit accounts + accounts = session["implicit_accounts"] + for pkh in accounts: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/delegates/{pkh}/deactivated', + ) + + def test_chain_block_context_delegate_delegated_balance_implicit( + self, sandbox: Sandbox, session: dict + ): + # only implicit accounts + accounts = session["implicit_accounts"] + for pkh in accounts: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/delegates/{pkh}/delegated_balance', + ) + + def test_chain_block_context_delegate_delegated_contracts_implicit( + self, sandbox: Sandbox, session: dict + ): + # only implicit accounts + accounts = session["implicit_accounts"] + for pkh in accounts: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/delegates/{pkh}/' + 'delegated_contracts', + ) + + def test_chain_block_context_delegate_frozen_balance_implicit( + self, sandbox: Sandbox, session: dict + ): + # only implicit accounts + accounts = session["implicit_accounts"] + for pkh in accounts: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/delegates/{pkh}/frozen_balance', + ) + + def test_chain_block_context_delegate_frozen_balance_by_cycle_implicit( + self, sandbox: Sandbox, session: dict + ): + # only implicit accounts + accounts = session["implicit_accounts"] + for pkh in accounts: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/delegates/{pkh}/' + 'frozen_balance_by_cycle', + ) + + def test_chain_block_context_delegate_grace_period_implicit( + self, sandbox: Sandbox, session: dict + ): + # only implicit accounts + accounts = session["implicit_accounts"] + for pkh in accounts: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/delegates/{pkh}/grace_period', + ) + + def test_chain_block_context_delegate_staking_balance_implicit( + self, sandbox: Sandbox, session: dict + ): + # only implicit accounts + accounts = session["implicit_accounts"] + for pkh in accounts: + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/delegates/{pkh}/staking_balance', + ) + + def test_chain_block_context_nonces_block_level(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/nonces/{BLOCK_LEVEL}', + ) + + def test_chain_block_context_raw_bytes(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'context/raw/bytes' + ) + + def test_chain_block_hash(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/hash' + ) + + def test_chain_block_header(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'header' + ) + + def test_chain_block_header_protocol_data(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'header/protocol_data', + ) + + def test_chain_block_header_protocol_data_raw(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'header/protocol_data/raw', + ) + + def test_chain_block_header_raw(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'header/raw' + ) + + def test_chain_block_header_shell(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'header/shell' + ) + + def test_chain_block_helpers_baking_rights(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'helpers/baking_rights', + ) + + def test_chain_block_helpers_complete_prefix1(self, sandbox: Sandbox): + prefix = PKH[:10] + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'helpers/complete/{prefix}', + ) + + def test_chain_block_helpers_complete_prefix2(self, sandbox: Sandbox): + res = utils.bake(sandbox.client(1)) + prefix = res.block_hash[:5] + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'helpers/complete/{prefix}', + ) + + def test_chain_block_helpers_current_level(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'helpers/current_level', + ) + + def test_chain_block_helpers_endorsing_rights(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'helpers/endorsing_rights', + ) + + def test_chain_block_helpers_levels_in_current_cycle( + self, sandbox: Sandbox + ): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + 'helpers/levels_in_current_cycle', + ) + + def test_chain_block_live_blocks(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'live_blocks' + ) + + def test_chain_block_metadata(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'metadata' + ) + + def test_chain_block_operation_hashes(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'operation_hashes' + ) + + def test_add_transactions(self, sandbox: Sandbox): + sandbox.client(1).transfer(1.000, 'bootstrap1', 'bootstrap2') + sandbox.client(2).transfer(1.000, 'bootstrap3', 'bootstrap4') + sandbox.client(1).endorse('bootstrap1') + utils.bake(sandbox.client(1)) + time.sleep(3) + + def test_chain_block_operation_hashes_list_offset(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'operation_hashes/{LIST_OFFSET}', + ) + + def test_chain_block_operation_hashes_list_operation( + self, sandbox: Sandbox + ): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'operation_hashes/{LIST_OFFSET}/' + f'{OPERATION_OFFSET}', + ) + + def test_chain_block_operations(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'operations' + ) + + def test_chain_block_operations_list(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'operations/{LIST_OFFSET}', + ) + + def test_chain_block_operations_list_operation(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'operations/{LIST_OFFSET}/' + f'{OPERATION_OFFSET}', + ) + + def test_chain_block_votes_ballot_list(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' f'votes/ballot_list' + ) + + def test_chain_block_votes_ballots(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'votes/ballots' + ) + + def test_chain_block_votes_current_period(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'votes/current_period', + ) + + def test_chain_block_votes_current_proposal(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'votes/current_proposal', + ) + + def test_chain_block_votes_current_quorum(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'votes/current_quorum', + ) + + def test_chain_block_votes_listings(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'votes/listings' + ) + + def test_chain_block_votes_proposals(self, sandbox: Sandbox): + sandbox.client(1).rpc( + 'get', f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' 'votes/proposals' + ) + + def test_stat_gc(self, sandbox: Sandbox): + assert sandbox.client(1).rpc('get', "/stats/gc") + + def test_stat_memory(self, sandbox: Sandbox): + assert sandbox.client(1).rpc('get', "/stats/memory") + + +class TestDeprecatedRPCs: + def test_chain_block_context_contract_delegatable( + self, sandbox: Sandbox, session: dict + ): + for contract_id in session["implicit_accounts"]: + with utils.assert_run_failure(r"Did not find service"): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/' + f'{BLOCK_ID}/context/contracts/' + f'{contract_id}/delegatable', + ) + + def test_chain_block_context_contract_spendable( + self, sandbox: Sandbox, session: dict + ): + accounts = session["originated_accounts"] + session["implicit_accounts"] + for contract_id in accounts: + with utils.assert_run_failure(r"Did not find service"): + sandbox.client(1).rpc( + 'get', + f'/chains/{CHAIN_ID}/blocks/{BLOCK_ID}/' + f'context/contracts/{contract_id}/' + 'spendable', + ) diff --git a/tests_python/tests_011/test_sapling.py b/tests_python/tests_011/test_sapling.py new file mode 100644 index 000000000000..c0b0523c8140 --- /dev/null +++ b/tests_python/tests_011/test_sapling.py @@ -0,0 +1,946 @@ +import json +import re +from os import path +import pytest +from tools import utils, paths, constants +from tools.utils import assert_run_failure +from . import contract_paths +from . import protocol + +CONTRACT_PATH = path.join( + paths.TEZOS_HOME, 'src', protocol.FOLDER, 'lib_protocol', 'test' +) +TX_AMOUNT = 100.0 + + +# TODO: Use a random valid memo size for shielded-tez and others +@pytest.fixture +def contract_path(): + return CONTRACT_PATH + + +@pytest.fixture(scope="class") +def sandbox(sandbox): + sandbox.add_node(0, params=constants.NODE_PARAMS) + protocol.activate(sandbox.client(0), activate_in_the_past=True) + return sandbox + + +@pytest.fixture(scope="class") +def node(sandbox): + return sandbox.node(0) + + +@pytest.fixture(scope="class") +def client(sandbox, node): + client = sandbox.get_new_client(node) + return client + + +@pytest.fixture +def mnemonic(): + return [ + "morning", + "dinosaur", + "estate", + "youth", + "sausage", + "feature", + "apology", + "bullet", + "square", + "type", + "zoo", + "coyote", + "extra", + "fabric", + "grain", + "phone", + "pipe", + "despair", + "razor", + "ranch", + "blouse", + "debris", + "urge", + "evidence", + ] + + +@pytest.fixture +def non_originated_contract_address(): + return "KT1MXuZJJFg4EVpLQeLeuHvznTRiNefh3yCs" + + +@pytest.fixture +def non_originated_contract_name(): + return "fake-contract" + + +@pytest.fixture +def key_name(): + return "test_key_name" + + +# here baker 'account' has baked a block and has sent 'tx_amount' +def check_baker_balance(client, account, tx_amount): + parameters = dict(protocol.PARAMETERS) + initial_amount = float(parameters["bootstrap_accounts"][0][1]) + deposit = float(parameters["block_security_deposit"]) + # sender's balance without fees + expected_baker_balance = (initial_amount - deposit) / 1000000 - tx_amount + baker_balance = client.get_balance(account) + # the fees are assumed to be at most 1 tez + assert expected_baker_balance - 1 <= baker_balance <= expected_baker_balance + + +@pytest.mark.client +class TestSaplingWalletImportKey: + @pytest.fixture + def client( + self, + sandbox, + node, + non_originated_contract_name, + non_originated_contract_address, + ): + """ + A client with a pre-registered contract to link the wallet with. + """ + client = sandbox.get_new_client(node) + client.remember_contract( + non_originated_contract_name, non_originated_contract_address + ) + return client + + def test_import_key_no_force(self, client, mnemonic, key_name): + """ + Import key without forcing and without pre-existing alias + """ + client.sapling_import_key(key_name, mnemonic, force=False) + + def test_import_key_force_and_non_previously_saved( + self, + client, + mnemonic, + key_name, + ): + """ + Import key with forcing and without pre-existing alias + """ + client.sapling_import_key(key_name, mnemonic, force=True) + + def test_import_key_force_and_previously_saved( + self, + client, + mnemonic, + key_name, + ): + """ + Import key with forcing and with pre-existing alias + """ + client.sapling_import_key(key_name, mnemonic, force=False) + client.sapling_import_key(key_name, mnemonic, force=True) + + +class TestSaplingWalletAddressGeneration: + @pytest.fixture + def client(self, sandbox, node, key_name, mnemonic): + """ + A client with a sapling wallet + """ + client = sandbox.get_new_client(node) + client.sapling_import_key(key_name, mnemonic, force=False) + return client + + @pytest.mark.parametrize( + "expected_address,expected_index", + [ + ( + "zet13XtyU5Bkasoj1b19sy4DJc7U13XydbxLHqLUdf8Y5tarGb" + "HgFLgDrT6J6FYJoHGL3", + 0, + ) + ], + ) + def test_generate_first_address_of_key( + self, client, key_name, expected_address, expected_index + ): + result = client.sapling_gen_address(key_name) + assert result.index == expected_index + assert result.address == expected_address + + @pytest.mark.parametrize( + "requested_index,expected_address,expected_index", + [ + ( + 0, + "zet13XtyU5Bkasoj1b19sy4DJc7U13XydbxLHqLUdf8Y5tarGb" + "HgFLgDrT6J6FYJoHGL3", + 0, + ), + ( + 1, + "zet13mN26QV67FgPzMSzrigXjKZNMMtCubhi9L3kUePnFYdXqEj" + "c8pmjw1h2wC6NLZf5F", + 1, + ), + ( + 2, + "zet12hzbYRRKbWwKPY61FkjLg7CRWTcjooqeH7VH18fA6Vxnwy7" + "WyTrAEqBXmEdHp9woU", + 4, + ), + ( + 3, + "zet12hzbYRRKbWwKPY61FkjLg7CRWTcjooqeH7VH18fA6Vxnwy7" + "WyTrAEqBXmEdHp9woU", + 4, + ), + ( + 4, + "zet12hzbYRRKbWwKPY61FkjLg7CRWTcjooqeH7VH18fA6Vxnwy7" + "WyTrAEqBXmEdHp9woU", + 4, + ), + ( + 100, + "zet14LmgdAzVrTtQKpeuD3f2y7wFSjXTMEexNNuiEWhGimm25en" + "xkqmwmbdFsC4y6YmYx", + 100, + ), + ( + 143534, + "zet14EWNxZYoHJASHFpcCYSfTfQokWSMzdJeV5SfaGEPDtiYiDC" + "X5jz8QkMF5jZaK5F4k", + 143536, + ), + ( + 42, + "zet143WVQUmNodhSe4ytHL6gvtdXYhRp7bywDWASUFYUCMGAS71" + "juXT6AyWY89fjg3eZn", + 42, + ), + ( + 90870987456348, + "zet13CiUqFsVEr2LdMnyyUQNL3Nh74sa4LdU6V3oD3YfcizbwuF" + "tftPRYvRrB2zsVaEw1", + 90870987456348, + ), + ], + ) + def test_generate_address_with_address_index( + self, + client, + key_name, + expected_address, + expected_index, + requested_index, + ): + result = client.sapling_gen_address(key_name, index=requested_index) + assert result.index == expected_index + assert result.address == expected_address + + +@pytest.mark.client +@pytest.mark.contract +@pytest.mark.incremental +class TestSaplingShieldedTez: + """ + Tests involving sapling key management and shielded transactions using + the shielded tez example contract. + """ + + @pytest.fixture + def contract_path(self): + return path.join(CONTRACT_PATH, 'contracts', 'sapling_contract.tz') + + @pytest.fixture + def contract_name(self): + return "sapling" + + @pytest.fixture(scope="session") + def tmpdir(self, tmpdir_factory): + """ + Temporary directory. Forged transactions will be saved + in this directory. + FIXME/IMPROVEME: tmpdir_factory is a fixture provided by pytest. It is + session-scoped, then the fixture tmpdir must be session-scoped. + Would be nice to have a class-scoped fixture. + """ + tmpdir = tmpdir_factory.mktemp("sapling_transactions_shielded_tez") + return tmpdir + + def test_originate_sapling_contract( + self, contract_path, client, session, contract_name + ): + sender = "bootstrap1" + origination = client.originate( + contract_name=contract_name, + amount=0, + sender=sender, + contract=contract_path, + args=["--init", "{ }", "--burn-cap", "3.0"], + ) + session["contract_address"] = origination.contract + utils.bake(client, sender) + assert utils.check_block_contains_operations( + client, + [origination.operation_hash], + ) + + def test_generate_bob(self, client, session, contract_name): + key_name = "bob" + result = client.sapling_gen_key(key_name=key_name) + client.sapling_use_key_for_contract( + key_name, contract_name, memo_size=8 + ) + session['bob_mnemonic'] = result.mnemonic + + def test_list_keys_bob(self, client): + keys = client.sapling_list_keys() + assert keys == ["bob"] + + def test_list_keys_with_alice_and_bob(self, client, contract_name): + """ + NB: another key (ali) is generated in the test, but the mnemonic + is not saved. + We add this test to verify the list keys command orders alphabetically + """ + key_name = "ali" + client.sapling_gen_key(key_name=key_name) + client.sapling_use_key_for_contract( + key_name=key_name, contract_name=contract_name + ) + keys = client.sapling_list_keys() + assert keys == ["ali", "bob"] + + def test_generate_bob_address_0(self, client, session): + result = client.sapling_gen_address( + key_name="bob", + ) + session['last_address_index'] = result.index + session['bob_address_0'] = result.address + + def test_generate_bob_address_1(self, client, session): + result = client.sapling_gen_address( + key_name="bob", + ) + assert result.index > session['last_address_index'] + session['bob_address_1'] = result.address + + def test_check_bob_balance(self, client, contract_name): + result = client.sapling_get_balance( + key_name="bob", + contract_name=contract_name, + ) + assert result.balance == 0 + + def test_shield_bob_address_0(self, client, session, contract_name): + client.sapling_shield( + amount=TX_AMOUNT, + src="bootstrap2", + dest=session['bob_address_0'], + contract=contract_name, + args=["--burn-cap", "3.0"], + ) + utils.bake(client, "bootstrap2") + check_baker_balance(client, "bootstrap2", TX_AMOUNT) + bob_balance = client.sapling_get_balance( + key_name="bob", contract_name=contract_name + ).balance + assert bob_balance == TX_AMOUNT + + def test_check_contract_balance_after_shielding( + self, client, contract_name + ): + assert client.get_balance(contract_name) == TX_AMOUNT + + def test_regenerate_bob_from_mnemonic(self, client, session): + # Overwrite the old 'bob' key with one restored from the mnemonic. + key_name = "bob" + client.sapling_import_key( + key_name=key_name, + mnemonic=session['bob_mnemonic'], + force=True, + ) + + def test_derive_alice(self, client, contract_name): + result = client.sapling_derive_key( + source_key_name='bob', + target_key_name='alice', + contract_name=contract_name, + index='0', + ) + assert result.path == '0/0' + + def test_derive_yves(self, client, contract_name): + result = client.sapling_derive_key( + source_key_name='bob', + target_key_name='yves', + contract_name=contract_name, + index='1', + ) + assert result.path == '0/1' + + def test_generate_alice_address_0(self, client, session): + result = client.sapling_gen_address( + key_name="alice", + ) + session['alice_address_0'] = result.address + + def test_alice_shields_money_insufficient_funds( + self, client, session, contract_name + ): + with assert_run_failure(r'too low \(4000000\) to spend 2100000000'): + client.sapling_shield( + amount=2100000000.0, + src="bootstrap3", + dest=session['alice_address_0'], + contract=contract_name, + args=["--burn-cap", "3.0"], + ) + + def test_alice_shields_money(self, client, session, contract_name): + client.sapling_shield( + amount=TX_AMOUNT, + src="bootstrap3", + dest=session['alice_address_0'], + contract=contract_name, + args=[ + "--burn-cap", + "3.0", + ], + ) + utils.bake(client, "bootstrap3") + check_baker_balance(client, "bootstrap3", TX_AMOUNT) + alice_balance = client.sapling_get_balance( + key_name="alice", contract_name=contract_name + ).balance + assert alice_balance == TX_AMOUNT + + @pytest.mark.parametrize( + "transaction_file,use_json", + [ + ("sapling_transaction.bin", False), + ("sapling_transaction.json", True), + ], + ) + def test_forge_alice_to_bob_insufficient_funds( + self, + client, + tmpdir, + contract_name, + session, + transaction_file, + use_json, + ): + transaction_file = f'{tmpdir}/{transaction_file}' + amount = 2100000000.0 + account = 'alice' + additional_args = [] + if use_json: + additional_args += ["--json"] + + with assert_run_failure( + r"Balance too low \({}\) to spend {}".format(100, int(amount)) + ): + client.sapling_forge_transaction( + amount=amount, + src=account, + dest=session['bob_address_1'], + contract=contract_name, + file=transaction_file, + args=additional_args, + ) + + def test_forge_alice_to_bob_address_0( + self, tmpdir, session, client, contract_name + ): + transaction_file = f'{tmpdir}/sapling_transaction0.bin' + client.sapling_forge_transaction( + amount=TX_AMOUNT, + src='alice', + dest=session['bob_address_0'], + contract=contract_name, + file=transaction_file, + ) + + def test_forge_alice_to_bob_address_1_binary_format( + self, tmpdir, session, client, contract_name + ): + transaction_file = f'{tmpdir}/sapling_transaction1.bin' + client.sapling_forge_transaction( + amount=50.0, + src='alice', + dest=session['bob_address_1'], + contract=contract_name, + file=transaction_file, + ) + + @pytest.mark.parametrize( + "key_name,expected_balance", [("alice", TX_AMOUNT), ("bob", TX_AMOUNT)] + ) + def test_check_sapling_balances_post_forge_binary_format( + self, client, contract_name, key_name, expected_balance + ): + result = client.sapling_get_balance( + key_name=key_name, + contract_name=contract_name, + ) + assert result.balance == expected_balance + + def test_submit_alice_to_bob_address_1_binary_format( + self, client, tmpdir, contract_name + ): + transaction_file = f'{tmpdir}/sapling_transaction1.bin' + additional_args = ["--burn-cap", "3.0"] + client.sapling_submit( + file=transaction_file, + fee_payer='bootstrap2', + contract=contract_name, + args=additional_args, + ) + utils.bake(client, "bootstrap2") + + @pytest.mark.parametrize( + "key_name,expected_balance", [("alice", 50.0), ("bob", 150.0)] + ) + def test_check_sapling_balances_after_successfull_transaction_in_binary( + self, client, contract_name, key_name, expected_balance + ): + balance = client.sapling_get_balance( + key_name=key_name, contract_name=contract_name + ).balance + assert balance == expected_balance + + def test_forge_alice_to_bob_address_1_json_format( + self, tmpdir, session, client, contract_name + ): + transaction_file = f'{tmpdir}/sapling_transaction1.json' + client.sapling_forge_transaction( + amount=50.0, + src='alice', + dest=session['bob_address_1'], + contract=contract_name, + file=transaction_file, + args=['--json'], + ) + # Try to load the file as JSON. Must not fail. + with open(transaction_file, "r") as file_descriptor: + json.load(file_descriptor) + + @pytest.mark.parametrize( + "key_name,expected_balance", [("alice", 50.0), ("bob", 150.0)] + ) + def test_check_sapling_balances_post_forge_json_format( + self, client, contract_name, key_name, expected_balance + ): + result = client.sapling_get_balance( + key_name=key_name, + contract_name=contract_name, + ) + assert result.balance == expected_balance + + def test_submit_alice_to_bob_address_1_json_format( + self, client, tmpdir, contract_name + ): + transaction_file = f'{tmpdir}/sapling_transaction1.json' + additional_args = ["--burn-cap", "3.0", "--json"] + client.sapling_submit( + file=transaction_file, + fee_payer='bootstrap2', + contract=contract_name, + args=additional_args, + ) + utils.bake(client, "bootstrap2") + + @pytest.mark.parametrize( + "key_name,expected_balance", [("alice", 0.0), ("bob", 200.0)] + ) + def test_check_sapling_balances_after_successfull_transaction_in_json( + self, client, contract_name, key_name, expected_balance + ): + balance = client.sapling_get_balance( + key_name=key_name, contract_name=contract_name + ).balance + assert balance == expected_balance + + @pytest.mark.parametrize( + "transaction_file,use_json", + [ + ("sapling_transaction0.bin", False), + # ("sapling_transaction0.json", True), + ], + ) + def test_submit_alice_to_bob0( + self, client, transaction_file, use_json, tmpdir, contract_name + ): + transaction_file = f'{tmpdir}/{transaction_file}' + additional_args = ["--burn-cap", "3.0"] + if use_json: + additional_args.append("--json") + + with assert_run_failure(r'transfer simulation failed'): + client.sapling_submit( + file=transaction_file, + fee_payer='bootstrap2', + contract=contract_name, + args=additional_args, + ) + + @pytest.mark.parametrize( + "requested_token,real_balance,key_name", + [ + (2100000000, 200, "bob"), + (300, 200, "bob"), + (2100000000, 0, "alice"), + (100, 0, "alice"), + ], + ) + def test_unshields_money_insufficient_funds( + self, client, contract_name, requested_token, real_balance, key_name + ): + with assert_run_failure( + r'Balance too low \({}\) to spend {}'.format( + real_balance, requested_token + ) + ): + client.sapling_unshield( + amount=requested_token, + src=key_name, + dest="bootstrap4", + contract=contract_name, + args=["--burn-cap", "3.0"], + ) + + def test_bob_unshields_money(self, client, contract_name): + bootstrap4_prev_balance = client.get_balance('bootstrap4') + amount = 90.0 + client.sapling_unshield( + amount=amount, + src="bob", + dest="bootstrap4", + contract=contract_name, + args=["--burn-cap", "3.0"], + ) + utils.bake(client, "bootstrap2") + bob_balance = client.sapling_get_balance( + key_name="bob", contract_name=contract_name + ).balance + assert bob_balance == 200.0 - amount + bootstrap4_balance = client.get_balance("bootstrap4") + # The receiver pays fees by default so it will not get the full amount, + # but still, it should have more than before + assert bootstrap4_balance >= bootstrap4_prev_balance + assert bootstrap4_balance <= bootstrap4_prev_balance + amount + + def test_check_state_with_another_client( + self, sandbox, node, contract_name, session + ): + client = sandbox.get_new_client(node) + client.remember_contract(contract_name, session["contract_address"]) + key_name = "bob" + # Restore bob's key from mnemonic: + client.sapling_import_key( + key_name=key_name, + mnemonic=session['bob_mnemonic'], + ) + client.sapling_use_key_for_contract( + key_name, contract_name, memo_size=8 + ) + # Check Bob's balance again, it should be the same: + bob_balance = client.sapling_get_balance( + key_name=key_name, contract_name=contract_name + ).balance + assert bob_balance == 110.0 + + @pytest.mark.parametrize( + "transparent_signer,baker", [("bootstrap4", "bootstrap2")] + ) + def test_shielded_transfer_using_non_sapling_transfer_method( + self, client, contract_name, session, transparent_signer, baker, tmpdir + ): + transaction_filename = f'{tmpdir}/sapling_transaction_2.bin' + client.sapling_forge_transaction( + amount=10.0, + src='bob', + dest=session['bob_address_1'], + contract=contract_name, + file=transaction_filename, + args=[], + ) + with open(transaction_filename, "r") as file_descriptor: + content = re.sub(r'\s+', ' ', file_descriptor.read()) + client.transfer( + 0, + giver=transparent_signer, + receiver=contract_name, + args=[ + "--arg", + '{Pair %s None }' % content, + "--burn-cap", + "3.0", + ], + ) + utils.bake(client, baker) + + @pytest.mark.parametrize( + "key_name,expected_balance", [("alice", 0.0), ("bob", 110.0)] + ) + def test_check_sapling_balances_after_calling_smart_contract( + self, client, contract_name, key_name, expected_balance + ): + balance = client.sapling_get_balance( + key_name=key_name, contract_name=contract_name + ).balance + assert balance == expected_balance + + +class TestSaplingMemoSize: + @pytest.fixture(scope="class") + def contract_name(self): + return "sapling_memo_size" + + @pytest.fixture(scope="class") + def contract_generator(self): + def generator(memo_size): + return ''' +parameter unit; +storage (sapling_state %s); +code { + DROP; + SAPLING_EMPTY_STATE %s; + NIL operation; + PAIR; + } +''' % ( + memo_size, + memo_size, + ) + + return generator + + @pytest.mark.parametrize("memo_size", [0, 1, 10, 42, 100, 65535]) + def test_originate_with_valid_size_and_update_with_valid_size( + self, client, memo_size, contract_name, tmpdir, contract_generator + ): + contract_path = tmpdir.join("c.tz") + contract_path.write(contract_generator(memo_size)) + sender = "bootstrap1" + client.originate( + contract_name=contract_name, + amount=0, + sender=sender, + contract=str(contract_path), + args=["--init", '{ }', "--burn-cap", "3.0", "--force"], + ) + utils.bake(client) + client.transfer( + 0, + giver="bootstrap1", + receiver=contract_name, + args=["--arg", "Unit", "--burn-cap", "3.0"], + ) + utils.bake(client) + + @pytest.mark.parametrize("memo_size", [-1, 65536, 65598909, 908923434]) + def test_originate_with_invalid_size( + self, + client, + memo_size, + contract_path, + contract_name, + contract_generator, + tmpdir, + ): + contract_path = tmpdir.join("c.tz") + contract_path.write(contract_generator(memo_size)) + sender = "bootstrap1" + err = r"expected a positive 16-bit integer" + with assert_run_failure(err): + client.originate( + contract_name=contract_name, + amount=0, + sender=sender, + contract=str(contract_path), + args=["--init", "{ }", "--burn-cap", "3.0", "--force"], + ) + + +@pytest.mark.incremental +class TestSaplingStateCorruption: + @pytest.fixture(scope="session") + def tmpdir(self, tmpdir_factory): + """ + Temporary directory. Forged transactions will be saved + in this directory. + FIXME/IMPROVEME: tmpdir_factory is a fixture provided by pytest. It is + session-scoped, then the fixture tmpdir must be session-scoped. + Would be nice to have a class-scoped fixture. + """ + tmpdir = tmpdir_factory.mktemp("sapling_transactions_shielded_tez") + return tmpdir + + def test_push_sapling_state_with_id_is_forbidden( + self, client, contract_path + ): + contract_name = ( + f"{contract_path}/contracts/sapling_push_sapling_state.tz" + ) + sender = "bootstrap1" + msg = r"big_map or sapling_state type not expected here" + with assert_run_failure(msg): + client.originate( + contract_name="push_sapling_state", + amount=0, + sender=sender, + contract=contract_name, + args=["--init", "Unit", "--burn-cap", "3.0"], + ) + + def test_originate_with_empty(self, client): + """ + Makes sure sapling state with id 0 exists + """ + contract = path.join( + contract_paths.OPCODES_CONTRACT_PATH, "sapling_empty_state.tz" + ) + client.originate( + amount=0, + sender="bootstrap1", + contract=contract, + contract_name="sapling_empty_state", + args=["--init", "{}", "--burn-cap", "3.0"], + ) + client.bake("bootstrap1") + + def test_originate_with_id_is_forbidden(self, client): + contract = path.join( + contract_paths.OPCODES_CONTRACT_PATH, "sapling_empty_state.tz" + ) + with assert_run_failure(r'Unexpected forged value'): + client.originate( + amount=0, + sender="bootstrap1", + contract=contract, + contract_name="sapling_empty_state2", + args=["--init", "0", "--burn-cap", "3.0"], + ) + + +class TestSaplingDifferentMemosize: + """ + Deploy a sapling contract using a sapling state with a memo size N and + create transactions with a memo size of M + """ + + @pytest.fixture + def contract_path(self): + return f'{CONTRACT_PATH}/contracts/sapling_contract.tz' + + def test_shield_with_different_memo_size(self, contract_path, client): + contract_name = "sapling_memo_size_different" + implicit_account = "bootstrap1" + contract_address = client.originate( + contract_name=contract_name, + amount=0, + sender=implicit_account, + contract=contract_path, + args=["--init", "{ }", "--burn-cap", "3.0"], + ).contract + utils.bake(client, implicit_account) + client.sapling_gen_key(key_name='alice') + client.sapling_use_key_for_contract( + 'alice', contract_name, memo_size=16 + ) + address = client.sapling_gen_address(key_name='alice').address + # Key was registered with a memo_size of 16, it should fail + with assert_run_failure(r"Memo sizes of two sapling states"): + client.sapling_shield( + amount=TX_AMOUNT, + src=implicit_account, + dest=address, + contract=contract_address, + args=["--burn-cap", "3.0"], + ) + + +class TestSaplingRightMemosize: + """ + Deploy a sapling contract using a sapling state with a memo size N and + create transactions with a memo size of N and diverse messages + """ + + @pytest.fixture + def contract_path(self): + return f'{CONTRACT_PATH}/contracts/sapling_contract.tz' + + def test_shield_with_same_memo_size(self, contract_path, client): + contract_name = "sapling_memo_size_same" + implicit_account = "bootstrap1" + contract_address = client.originate( + contract_name=contract_name, + amount=0, + sender=implicit_account, + contract=contract_path, + args=["--init", "{ }", "--burn-cap", "3.0"], + ).contract + utils.bake(client, implicit_account) + client.sapling_gen_key(key_name='alice') + client.sapling_use_key_for_contract('alice', contract_name, memo_size=8) + address = client.sapling_gen_address(key_name='alice').address + # Should pass since memo-sizes are equal and message is + # filled with 0's + client.sapling_shield( + amount=TX_AMOUNT, + src=implicit_account, + dest=address, + contract=contract_address, + args=["--burn-cap", "3.0"], + ) + utils.bake(client, "bootstrap2") + # Deriving a new key should work as well since + # the memo-size is kept + client.sapling_derive_key( + source_key_name='alice', + target_key_name='bob', + contract_name=contract_name, + index=10, + ) + address_derived = client.sapling_gen_address(key_name='bob').address + client.sapling_shield( + amount=TX_AMOUNT, + src=implicit_account, + dest=address_derived, + contract=contract_address, + args=["--burn-cap", "3.0"], + ) + utils.bake(client, "bootstrap2") + # Now with a too short message + client.sapling_shield( + amount=TX_AMOUNT, + src=implicit_account, + dest=address, + contract=contract_address, + args=["--burn-cap", "3.0", "--message", "aB"], + ) + utils.bake(client, "bootstrap2") + # Now with a right length message + client.sapling_shield( + amount=TX_AMOUNT, + src=implicit_account, + dest=address, + contract=contract_address, + args=["--burn-cap", "3.0", "--message", "aBbf19F00a"], + ) + utils.bake(client, "bootstrap2") + # Now with a too long message + client.sapling_shield( + amount=TX_AMOUNT, + src=implicit_account, + dest=address, + contract=contract_address, + args=["--burn-cap", "3.0", "--message", "aBbf19F00aaBbf19F00aC"], + ) + utils.bake(client, "bootstrap2") diff --git a/tests_python/tests_011/test_slice_fails_params.txt b/tests_python/tests_011/test_slice_fails_params.txt new file mode 100644 index 000000000000..7241bd22aff3 --- /dev/null +++ b/tests_python/tests_011/test_slice_fails_params.txt @@ -0,0 +1,5 @@ +(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75ba63500a5694fb2ffe174acc2de22d01ccb7259342437f05e1987949f0ad82e9f32e9a0b79cb252d7f7b8236ad728893f4e7150742eefdbeda254970f9fcd92c6228c178e1a923e5600758eb83f2a05edd0be7625657901f2ba81eaf145d003dbef78e33f43a32a3788bdf0501000000085341554349535345 "p2sigsceCzcDw2AeYDzUonj4JT341WC9Px4wdhHBxbZcG1FhfqFVuG7f2fGCzrEHSAZgrsrQWpxduDPk9qZRgrpzwJnSHC3gZJ") +(Pair 0xeaa9ab79e8b84ef0e55c43a9a857214d8761e67b75ba63500a5694fb2ffe174acc2de22d01ccb7259342437f05e1987949f0ad82e9f32e9a0b79cb252d7f7b8236ad728893f4e7150742eefdbeda254970f9fcd92c6228c178e1a923e5600758eb83f2a05edd0be7625657901f2ba81eaf145d003dbef78e33f43a32a3788bdf0501000000085341554349535345 "spsig1PPUFZucuAQybs5wsqsNQ68QNgFaBnVKMFaoZZfi1BtNnuCAWnmL9wVy5HfHkR6AeodjVGxpBVVSYcJKyMURn6K1yknYLm") +(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75ba63500a5694fb2ffe174acc2deaad01ccb7259342437f05e1987949f0ad82e9f32e9a0b79cb252d7f7b8236ad728893f4e7150742eefdbeda254970f9fcd92c6228c178e1a923e5600758eb83f2a05edd0be7625657901f2ba81eaf145d003dbef78e33f43a32a3788bdf0501000000085341554349535345 "spsig1PPUFZucuAQybs5wsqsNQ68QNgFaBnVKMFaoZZfi1BtNnuCAWnmL9wVy5HfHkR6AeodjVGxpBVVSYcJKyMURn6K1yknYLm") +(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75ba63500a5694fb2ffe174acc2de22d01ccb7259342437f05e1987949f0ad82e9f32e9a0b79cb252d7f7b8236ad728893f4e7150733eefdbeda254970f9fcd92c6228c178e1a923e5600758eb83f2a05edd0be7625657901f2ba81eaf145d003dbef78e33f43a32a3788bdf0501000000085341554349535345 "spsig1PPUFZucuAQybs5wsqsNQ68QNgFaBnVKMFaoZZfi1BtNnuCAWnmL9wVy5HfHkR6AeodjVGxpBVVSYcJKyMURn6K1yknYLm") +(Pair 0xe009ab79e8b84ef0 "spsig1PPUFZucuAQybs5wsqsNQ68QNgFaBnVKMFaoZZfi1BtNnuCAWnmL9wVy5HfHkR6AeodjVGxpBVVSYcJKyMURn6K1yknYLm") diff --git a/tests_python/tests_011/test_slice_success_params.txt b/tests_python/tests_011/test_slice_success_params.txt new file mode 100644 index 000000000000..8c0d89bd8142 --- /dev/null +++ b/tests_python/tests_011/test_slice_success_params.txt @@ -0,0 +1 @@ +(Pair 0xe009ab79e8b84ef0e55c43a9a857214d8761e67b75ba63500a5694fb2ffe174acc2de22d01ccb7259342437f05e1987949f0ad82e9f32e9a0b79cb252d7f7b8236ad728893f4e7150742eefdbeda254970f9fcd92c6228c178e1a923e5600758eb83f2a05edd0be7625657901f2ba81eaf145d003dbef78e33f43a32a3788bdf0501000000085341554349535345 "spsig1PPUFZucuAQybs5wsqsNQ68QNgFaBnVKMFaoZZfi1BtNnuCAWnmL9wVy5HfHkR6AeodjVGxpBVVSYcJKyMURn6K1yknYLm") diff --git a/tests_python/tests_011/test_tls.py b/tests_python/tests_011/test_tls.py new file mode 100755 index 000000000000..475d786823bb --- /dev/null +++ b/tests_python/tests_011/test_tls.py @@ -0,0 +1,23 @@ +import pytest +from tools import constants +from client.client import Client + + +@pytest.fixture(scope="class") +def client(sandbox): + sandbox.add_node( + 0, + use_tls=(constants.TEZOS_CRT, constants.TEZOS_KEY), + params=constants.NODE_PARAMS, + ) + yield sandbox.client(0) + + +@pytest.mark.vote +@pytest.mark.incremental +@pytest.mark.skip(reason="requires to install a custom CA") +class TestTLS: + """Test voting protocol with manual baking, 4 blocks per voting period.""" + + def test_bootstrapped(self, client: Client): + assert client.bootstrapped() diff --git a/tests_python/tests_011/test_voting.py b/tests_python/tests_011/test_voting.py new file mode 100644 index 000000000000..523dbb3a26fc --- /dev/null +++ b/tests_python/tests_011/test_voting.py @@ -0,0 +1,249 @@ +import shutil + +import pytest + +from client.client import Client +from tools import constants, paths, utils + +from . import protocol + + +@pytest.fixture(scope="class") +def client(sandbox): + """One node, 4 blocks per voting period.""" + parameters = dict(protocol.PARAMETERS) + parameters["time_between_blocks"] = ["1", "0"] + parameters["blocks_per_voting_period"] = 4 + sandbox.add_node(0, params=constants.NODE_PARAMS) + protocol.activate(sandbox.client(0), parameters, activate_in_the_past=True) + yield sandbox.client(0) + + +@pytest.mark.vote +@pytest.mark.incremental +class TestManualBaking: + """Test voting protocol with manual baking, 4 blocks per voting period.""" + + def test_current_period(self, client: Client): + period_info = client.get_current_period() + level = client.get_current_level() + assert level["level_position"] == 0 + assert period_info["voting_period"]["index"] == 0 + assert period_info["voting_period"]["kind"] == "proposal" + assert period_info["voting_period"]["start_position"] == 0 + assert period_info["position"] == 0 + assert period_info["remaining"] == 3 + + def test_succ_period(self, client: Client): + period_info = client.get_succ_period() + assert period_info["voting_period"]["index"] == 0 + assert period_info["voting_period"]["kind"] == "proposal" + assert period_info["voting_period"]["start_position"] == 0 + assert period_info["position"] == 1 + assert period_info["remaining"] == 2 + + def test_level_info_offset(self, client: Client): + level = client.get_current_level(offset=1) + assert level["level_position"] == 1 + level = client.get_current_level(offset=4) + assert level["level_position"] == 4 + level = client.get_current_level(offset=10) + assert level["level_position"] == 10 + + def test_bake_two_blocks(self, client: Client): + utils.bake(client) + utils.bake(client) + period_info = client.get_current_period() + level = client.get_current_level() + assert level["level_position"] == 2 + assert period_info["voting_period"]["index"] == 0 + assert period_info["voting_period"]["kind"] == "proposal" + assert period_info["voting_period"]["start_position"] == 0 + assert period_info["position"] == 2 + assert period_info["remaining"] == 1 + + def test_last_block_of_proposal_period(self, client: Client): + # last block of voting period 0 + utils.bake(client) + period_info = client.get_current_period() + assert period_info["voting_period"]["index"] == 0 + assert period_info["voting_period"]["kind"] == "proposal" + assert period_info["voting_period"]["start_position"] == 0 + assert period_info["position"] == 3 + assert period_info["remaining"] == 0 + + def test_listing_is_not_empty(self, client: Client): + assert client.get_listings() != [] + + def test_inject_proto1(self, client: Client, tmpdir): + proto_fp = ( + f'{paths.TEZOS_HOME}/src/' f'bin_client/test/proto_test_injection' + ) + for i in range(1, 4): + proto = f'{tmpdir}/proto{i}' + shutil.copytree(proto_fp, proto) + main = f'{proto}/main.ml' + print(main) + with open(main, "a") as file: + file.write(f'(* {i} *)') + client.inject_protocol(proto) + + # this is maybe useless because the protocol already knows more than 4 + # protocol + def test_known_protocol(self, client: Client, session: dict): + protos = client.list_protocols() + assert len(protos) >= 4 + session['protos'] = protos[:4] + + def test_proposals_is_empty(self, client: Client): + assert client.get_proposals() == [] + + def test_show_voting_period2(self, client: Client): + client.show_voting_period() + + def test_bake_first_block_of_proposal_period(self, client: Client): + # using the client it's not possible to add voting operation on the + # first block of a voting period. This is to be fixed in a future + # protocol + utils.bake(client) + period_info = client.get_current_period() + assert period_info["voting_period"]["index"] == 1 + assert period_info["voting_period"]["kind"] == "proposal" + assert period_info["voting_period"]["start_position"] == 4 + assert period_info["position"] == 0 + assert period_info["remaining"] == 3 + + def test_submit_proposals(self, client: Client, session: dict): + protos = session['protos'] + client.submit_proposals('bootstrap1', [protos[0]]) + client.submit_proposals('bootstrap2', [protos[0], protos[1]]) + client.submit_proposals('bootstrap3', [protos[1]]) + client.submit_proposals('bootstrap4', [protos[2]]) + + def test_bake_one_block(self, client: Client): + utils.bake(client) + period_info = client.get_current_period() + assert period_info["voting_period"]["index"] == 1 + assert period_info["voting_period"]["kind"] == "proposal" + assert period_info["voting_period"]["start_position"] == 4 + assert period_info["position"] == 1 + assert period_info["remaining"] == 2 + + def test_proposals_is_not_empty(self, client: Client): + assert client.get_proposals() != [] + + def test_bake_until_prev_last_block_of_voting_period(self, client: Client): + utils.bake(client) + period_info = client.get_current_period() + assert period_info["position"] == 2 + assert period_info["remaining"] == 1 + + def test_break_proposal_tie(self, client: Client, session: dict): + protos = session['protos'] + client.submit_proposals('bootstrap4', [protos[1]]) + + def test_bake_last_block_of_proposal_period(self, client: Client): + utils.bake(client) + level = client.get_current_level() + period_info = client.get_current_period() + metadata = client.get_metadata() + level_info = metadata["level_info"] + meta_period_info = metadata["voting_period_info"] + expected_commitment = level["expected_commitment"] + assert level["level"] == level_info["level"] + assert level["level_position"] == level_info["level_position"] + assert level["cycle"] == level_info["cycle"] + assert level["cycle_position"] == level_info["cycle_position"] + assert expected_commitment == level_info["expected_commitment"] + assert level["level_position"] == 7 + assert period_info["voting_period"]["index"] == 1 + assert period_info["voting_period"]["kind"] == "proposal" + assert period_info["voting_period"]["start_position"] == 4 + assert period_info["position"] == 3 + assert period_info["remaining"] == 0 + assert meta_period_info == period_info + + def test_listing_is_not_empty2(self, client: Client): + assert client.get_listings() != [] + + def test_current_proposal(self, client: Client, session: dict): + expected = session['protos'][1] + assert expected == client.get_current_proposal() + + def test_bake_first_block_of_cooldown_vote_period(self, client: Client): + # using the client it's not possible to add voting operation on the + # first block of a voting period. This is to be fixed in a future + # protocol + utils.bake(client) + period_info = client.get_current_period() + assert period_info["voting_period"]["index"] == 2 + assert period_info["voting_period"]["kind"] == "exploration" + assert period_info["voting_period"]["start_position"] == 8 + assert period_info["position"] == 0 + assert period_info["remaining"] == 3 + + def test_submit_ballot(self, client: Client, session: dict): + # next block is going to be of 'exploration' kind + proto = session['protos'][1] + for i in range(1, 4): + client.submit_ballot(f'bootstrap{i}', proto, 'yay') + + def test_bake_until_prev_last_block_of_voting_period2(self, client: Client): + utils.bake(client) + utils.bake(client) + period_info = client.get_current_period() + level = client.get_current_level() + assert level["level_position"] == 10 + assert period_info["voting_period"]["index"] == 2 + assert period_info["voting_period"]["kind"] == "exploration" + assert period_info["voting_period"]["start_position"] == 8 + assert period_info["position"] == 2 + assert period_info["remaining"] == 1 + + def test_submit_failing_ballot(self, client: Client, session: dict): + proto = session['protos'][1] + client.submit_ballot(f'bootstrap{4}', proto, 'nay') + + def test_level_info_offset2(self, client: Client): + level = client.get_current_level(offset=-1) + assert level["level_position"] == 9 + level = client.get_current_level(offset=-4) + assert level["level_position"] == 6 + level = client.get_current_level(offset=-10) + assert level["level_position"] == 0 + + def test_bake_first_block_of_new_proposal_period(self, client: Client): + utils.bake(client) + # Because of the current hack in proposal here we make sure we get the + # correct value + level = client.get_current_level() + period_info = client.get_current_period() + metadata = client.get_metadata() + level_info = metadata["level_info"] + meta_period_info = metadata["voting_period_info"] + expected_commitment = level["expected_commitment"] + assert level["level"] == level_info["level"] + assert level["level_position"] == level_info["level_position"] + assert level["cycle"] == level_info["cycle"] + assert level["cycle_position"] == level_info["cycle_position"] + assert expected_commitment == level_info["expected_commitment"] + assert level["level_position"] == 11 + assert period_info["voting_period"]["index"] == 2 + assert period_info["voting_period"]["kind"] == "exploration" + assert period_info["voting_period"]["start_position"] == 8 + assert period_info["position"] == 3 + assert period_info["remaining"] == 0 + assert meta_period_info == period_info + utils.bake(client) + period_info = client.get_current_period() + level = client.get_current_level() + assert level["level_position"] == 12 + assert period_info["voting_period"]["index"] == 3 + assert period_info["voting_period"]["kind"] == "proposal" + assert period_info["voting_period"]["start_position"] == 12 + assert period_info["position"] == 0 + assert period_info["remaining"] == 3 + assert client.get_listings() != '[]' + # strange behavior here, RPC returns 'null' on stderr + assert client.get_current_proposal() is None + assert client.get_ballot_list() == [] diff --git a/tests_python/tests_011/test_voting_full.py b/tests_python/tests_011/test_voting_full.py new file mode 100644 index 000000000000..292c1a1bbd1c --- /dev/null +++ b/tests_python/tests_011/test_voting_full.py @@ -0,0 +1,175 @@ +import time + +import pytest + +from launchers.sandbox import Sandbox +from client.client import Client +from tools import utils, constants +from . import protocol + +BLOCKS_PER_VOTING_PERIOD = 8 +OFFSET = int(BLOCKS_PER_VOTING_PERIOD / 2) +POLLING_TIME = 5 +NUM_NODES = 3 +BAKER = "bootstrap1" +ERROR_PATTERN = r"Uncaught|registered|error" + +PROTO_A = protocol.PREV_HASH +PROTO_A_DAEMON = protocol.PREV_DAEMON +PROTO_A_PATH = f"proto_{PROTO_A_DAEMON.replace('-','_')}" +PROTO_B = protocol.HASH +PROTO_B_DAEMON = protocol.DAEMON + + +def client_get_current_period_kind(client) -> dict: + res = client.get_current_period() + return res['voting_period']['kind'] + + +def bake_n_blocks(client: Client, baker: str, n_blocks: int): + for _ in range(n_blocks): + utils.bake(client, baker) + + +def bake_until_next_voting_period(client: Client, baker: str, offset: int = 0): + period_info = client.get_current_period() + remaining_blocks = period_info["remaining"] + # if offset is the constant OFFSET, it will take us to + # the middle of the next voting period + bake_n_blocks(client, baker, 1 + remaining_blocks + offset) + + +@pytest.mark.timeout(10) +def wait_until_level(clients, level): + for client in clients: + while client.get_level() < level: + time.sleep(1) + + +def assert_all_clients_in_period(clients, period): + for client in clients: + assert client_get_current_period_kind(client) == period + + +@pytest.mark.vote +@pytest.mark.slow +@pytest.mark.baker +@pytest.mark.incremental +class TestVotingFull: + """This tests the migration from PROTO_A to PROTO_B using the voting + procedure. PROTO_A and PROTO_B are the previous and + respectively the current protocol as given by the 'protocol' + module. + + This test advances through all the periods of the voting procedure + until the last one (adoption), by manually baking the right number + of blocks. Once the adoption period is reached, a baker takes over + to bake the remaining blocks of the period. From there the baker + for the next protocol, which was started at the beginning of the + test, takes over. (Bakers are used to make the test more + realistic. However, to be sure that proposals and ballots are + injected at the right moment, manual baking is used instead.) + + This test differs in the following aspects from test_voting.py: + - it uses more nodes, not just one + - it goes through all voting periods, not just the first two + - it uses bakers + - it uses already registered protocols, instead of injecting a + new dummy protocol + """ + + def test_add_initial_nodes(self, sandbox: Sandbox): + for i in range(NUM_NODES): + sandbox.add_node(i, params=constants.NODE_PARAMS) + parameters = dict(protocol.PREV_PARAMETERS) + parameters["blocks_per_voting_period"] = BLOCKS_PER_VOTING_PERIOD + utils.activate_protocol( + sandbox.client(0), PROTO_A, parameters, activate_in_the_past=True + ) + + def test_add_baker(self, sandbox: Sandbox): + sandbox.add_baker(0, BAKER, proto=PROTO_B_DAEMON) + + def test_client_knows_proto_b(self, sandbox: Sandbox): + client = sandbox.client(0) + protos = client.list_protocols() + assert PROTO_B in protos + + def test_proposal_period(self, sandbox: Sandbox): + assert_all_clients_in_period(sandbox.all_clients(), 'proposal') + + def test_submit_proto_b_proposal(self, sandbox): + client = sandbox.client(0) + proposals = client.submit_proposals(BAKER, [PROTO_B]) + # bake a block for the submit proposal to be included + bake_n_blocks(client, BAKER, 1) + client.wait_for_inclusion(proposals.operation_hash, check_previous=1) + + def test_check_proto_b_proposed(self, sandbox: Sandbox): + clients = sandbox.all_clients() + wait_until_level(clients, sandbox.client(0).get_level()) + for client in clients: + proposals = client.get_proposals() + assert PROTO_B in [proto for (proto, _) in proposals] + + def test_wait_for_exploration_period(self, sandbox: Sandbox): + client = sandbox.client(0) + bake_until_next_voting_period(client, BAKER, OFFSET) + clients = sandbox.all_clients() + wait_until_level(clients, client.get_level()) + assert_all_clients_in_period(clients, 'exploration') + + def test_delegates_vote_proto_b(self, sandbox: Sandbox): + client = sandbox.client(0) + listings = client.get_listings() + # submit ballot for all bakers with listings + for listing in listings: + client.submit_ballot(listing["pkh"], PROTO_B, 'yay') + + def test_wait_for_cooldown(self, sandbox: Sandbox): + client = sandbox.client(0) + bake_until_next_voting_period(client, BAKER, OFFSET) + clients = sandbox.all_clients() + wait_until_level(clients, client.get_level()) + assert_all_clients_in_period(clients, 'cooldown') + + def test_wait_for_promotion_period(self, sandbox: Sandbox): + client = sandbox.client(0) + bake_until_next_voting_period(client, BAKER, OFFSET) + clients = sandbox.all_clients() + wait_until_level(clients, client.get_level()) + assert_all_clients_in_period(clients, 'promotion') + + def test_vote_in_promotion_phase(self, sandbox: Sandbox): + client = sandbox.client(0) + listings = client.get_listings() + for listing in listings: + client.submit_ballot(listing["pkh"], PROTO_B, 'yay') + + def test_wait_for_adoption(self, sandbox: Sandbox): + client = sandbox.client(0) + bake_until_next_voting_period(client, BAKER) + clients = sandbox.all_clients() + wait_until_level(clients, client.get_level()) + assert_all_clients_in_period(clients, 'adoption') + + @pytest.mark.timeout(60) + def test_all_nodes_run_proto_b(self, sandbox: Sandbox): + # we let a PROTO_A baker bake the last blocks of PROTO_A + sandbox.add_baker(0, BAKER, proto=PROTO_A_DAEMON) + clients = sandbox.all_clients() + all_have_proto = False + while not all_have_proto: + all_have_proto = all( + client.get_protocol() == PROTO_B for client in clients + ) + time.sleep(POLLING_TIME) + + def test_new_chain_progress(self, sandbox: Sandbox): + client = sandbox.client(0) + level_before = client.get_level() + assert utils.check_level_greater_than(client, level_before + 1) + + @pytest.mark.xfail + def test_check_logs(self, sandbox: Sandbox): + assert utils.check_logs(sandbox.logs, ERROR_PATTERN) diff --git a/tests_python/tests_alpha/protocol.py b/tests_python/tests_alpha/protocol.py index fa34775fb494..f5366b5d2566 100644 --- a/tests_python/tests_alpha/protocol.py +++ b/tests_python/tests_alpha/protocol.py @@ -5,9 +5,9 @@ DAEMON = constants.ALPHA_DAEMON PARAMETERS = constants.ALPHA_PARAMETERS FOLDER = constants.ALPHA_FOLDER -PREV_HASH = constants.GRANADA -PREV_DAEMON = constants.GRANADA_DAEMON -PREV_PARAMETERS = constants.GRANADA_PARAMETERS +PREV_HASH = constants.HANGZHOU +PREV_DAEMON = constants.HANGZHOU_DAEMON +PREV_PARAMETERS = constants.HANGZHOU_PARAMETERS def activate( diff --git a/tests_python/tools/constants.py b/tests_python/tools/constants.py index eeb7939eef82..238c7ebafbdf 100644 --- a/tests_python/tools/constants.py +++ b/tests_python/tools/constants.py @@ -106,6 +106,11 @@ GRANADA_DAEMON = "010-PtGRANAD" GRANADA_FOLDER = "proto_010_PtGRANAD" GRANADA_PARAMETERS = get_parameters(GRANADA_FOLDER) +HANGZHOU = "PtHangzHogokSuiMHemCuowEavgYTP8J5qQ9fQS793MHYFpCY3r" +HANGZHOU_DAEMON = "011-PtHangzH" +HANGZHOU_FOLDER = "proto_011_PtHangzH" +HANGZHOU_PARAMETERS = get_parameters(HANGZHOU_FOLDER) + TEZOS_CRT = """ Certificate: Data: -- GitLab From 86d648079746461bdc1bb4248dcd1e6f42b2aefc Mon Sep 17 00:00:00 2001 From: Pierre Boutillier Date: Fri, 17 Sep 2021 17:45:20 +0200 Subject: [PATCH 6/9] Tests : To be reverted when proto alpha stitching starts from H --- .gitlab/ci/integration.yml | 4 ++-- tests_python/tests_alpha/protocol.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab/ci/integration.yml b/.gitlab/ci/integration.yml index 640f698dad0c..5ada82787a66 100644 --- a/.gitlab/ci/integration.yml +++ b/.gitlab/ci/integration.yml @@ -82,7 +82,7 @@ integration:sandboxes:acc-endorsement: integration:sandboxes:u-a-u: extends: .integration_template script: - # - TMP=$PWD make -f sandbox.Makefile user_activated_upgrade_next + - TMP=$PWD make -f sandbox.Makefile user_activated_upgrade_next - TMP=$PWD make -f sandbox.Makefile user_activated_upgrade_alpha artifacts: paths: @@ -94,7 +94,7 @@ integration:sandboxes:u-a-u: integration:sandboxes:daemons-upgrade: extends: .integration_template script: - # - TMP=$PWD make -f sandbox.Makefile daemons_upgrade_next + - TMP=$PWD make -f sandbox.Makefile daemons_upgrade_next - TMP=$PWD make -f sandbox.Makefile daemons_upgrade_alpha artifacts: paths: diff --git a/tests_python/tests_alpha/protocol.py b/tests_python/tests_alpha/protocol.py index f5366b5d2566..fa34775fb494 100644 --- a/tests_python/tests_alpha/protocol.py +++ b/tests_python/tests_alpha/protocol.py @@ -5,9 +5,9 @@ DAEMON = constants.ALPHA_DAEMON PARAMETERS = constants.ALPHA_PARAMETERS FOLDER = constants.ALPHA_FOLDER -PREV_HASH = constants.HANGZHOU -PREV_DAEMON = constants.HANGZHOU_DAEMON -PREV_PARAMETERS = constants.HANGZHOU_PARAMETERS +PREV_HASH = constants.GRANADA +PREV_DAEMON = constants.GRANADA_DAEMON +PREV_PARAMETERS = constants.GRANADA_PARAMETERS def activate( -- GitLab From 0607f216db34956c9650350ab7533a3893fe22ec Mon Sep 17 00:00:00 2001 From: Pierre Boutillier Date: Fri, 17 Sep 2021 17:22:59 +0200 Subject: [PATCH 7/9] Revert "Hangzhou: vanity nonce" This reverts commit 00d33878ccf402d4680fc97a2f466a325f7ea1d3. --- src/proto_alpha/lib_protocol/main.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/proto_alpha/lib_protocol/main.ml b/src/proto_alpha/lib_protocol/main.ml index d134876737f2..0065f88ca92c 100644 --- a/src/proto_alpha/lib_protocol/main.ml +++ b/src/proto_alpha/lib_protocol/main.ml @@ -494,4 +494,4 @@ let value_of_key ~chain_id:_ ~predecessor_context:ctxt ~predecessor_timestamp Alpha_context.prepare ~level ~predecessor_timestamp ~timestamp ~fitness ctxt >>=? fun (ctxt, _, _) -> return (Apply.value_of_key ctxt) -(* Vanity nonce: 0105005008491999 *) +(* Vanity nonce: TBD *) -- GitLab From 237741cbcd7b32f14b9ab25adf763c56bdf7955e Mon Sep 17 00:00:00 2001 From: Romain Date: Mon, 20 Sep 2021 07:40:48 +0000 Subject: [PATCH 8/9] Doc: rename Alpha into Hangzhou --- docs/protocols/011_hangzhou.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/protocols/011_hangzhou.rst b/docs/protocols/011_hangzhou.rst index 6cbc0af5b3a9..5c5fc961dae0 100644 --- a/docs/protocols/011_hangzhou.rst +++ b/docs/protocols/011_hangzhou.rst @@ -1,13 +1,13 @@ -Protocol Alpha -============== +Protocol Hangzhou +================= -This page contains all the relevant information for protocol Alpha +This page contains all the relevant information for protocol Hangzhou (see :ref:`naming_convention`). The code can be found in the :src:`src/proto_011_PtHangzH` directory of the ``master`` branch of Tezos. -This page documents the changes brought by protocol Alpha with respect +This page documents the changes brought by protocol Hangzhou with respect to Granada. .. contents:: -- GitLab From 362a3290bfdd1f78beb828f2f8ffef97e5c8efda Mon Sep 17 00:00:00 2001 From: Pierre Boutillier Date: Mon, 20 Sep 2021 10:57:40 +0200 Subject: [PATCH 9/9] Doc: Generate Hangzhou RPC and commands doc --- docs/Makefile | 13 +++++++++++-- docs/doc_gen/dune | 1 + docs/doc_gen/rpc_doc.ml | 4 ++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index 5b041e1f8673..5bb8f45483ce 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -10,11 +10,13 @@ DOCERRORDIR = $(DOCGENDIR)/errors DOCRPCDIR = $(DOCGENDIR)/rpcs ALPHA_LONG = ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK +HANGZHOU_LONG = PtHangzHogokSuiMHemCuowEavgYTP8J5qQ9fQS793MHYFpCY3r GRANADA_LONG = PtGRANADsDU8R9daYKAgWnQYAJ64omN1o3KMGVCykShA97vQbvV ACTIVE_LONG = $(GRANADA_LONG) ALPHA_SHORT = alpha GRANADA_SHORT = 010-PtGRANAD +HANGZHOU_SHORT = 011-PtHangzH ACTIVE_SHORT = $(GRANADA_SHORT) SCRIPTSDIR = scripts @@ -31,6 +33,11 @@ manuals: main @../tezos-baker-$(ALPHA_SHORT) man -verbosity 3 -format html | sed "s#${HOME}#\$$HOME#g" > alpha/tezos-baker.html @../tezos-endorser-$(ALPHA_SHORT) man -verbosity 3 -format html | sed "s#${HOME}#\$$HOME#g" > alpha/tezos-endorser.html @../tezos-accuser-$(ALPHA_SHORT) man -verbosity 3 -format html | sed "s#${HOME}#\$$HOME#g" > alpha/tezos-accuser.html + # 011 (Hangzhou) protocol + @../tezos-client -protocol $(HANGZHOU_LONG) man -verbosity 3 -format html | sed "s#${HOME}#\$$HOME#g" > 011/tezos-client.html + @../tezos-baker-$(HANGZHOU_SHORT) man -verbosity 3 -format html | sed "s#${HOME}#\$$HOME#g" > 011/tezos-baker.html + @../tezos-endorser-$(HANGZHOU_SHORT) man -verbosity 3 -format html | sed "s#${HOME}#\$$HOME#g" > 011/tezos-endorser.html + @../tezos-accuser-$(HANGZHOU_SHORT) man -verbosity 3 -format html | sed "s#${HOME}#\$$HOME#g" > 011/tezos-accuser.html # 010 (Granada) protocol @../tezos-client -protocol $(GRANADA_LONG) man -verbosity 3 -format html | sed "s#${HOME}#\$$HOME#g" > 010/tezos-client.html @../tezos-baker-$(GRANADA_SHORT) man -verbosity 3 -format html | sed "s#${HOME}#\$$HOME#g" > 010/tezos-baker.html @@ -72,6 +79,7 @@ redirectcheck: # - on each other protocol including alpha, also checking label defs (option -l) xrefscheck: $(CHECKXREFS) 010 + $(CHECKXREFS) -l 011 $(CHECKXREFS) -l alpha scriptsindoccheck: @@ -101,6 +109,7 @@ $(DOCGENDIR)/rpc_doc.exe: rpc: $(DOCGENDIR)/rpc_doc.exe @dune exec $(DOCGENDIR)/rpc_doc.exe index "" > active/rpc.rst + @dune exec $(DOCGENDIR)/rpc_doc.exe index "011" > 011/rpc.rst @dune exec $(DOCGENDIR)/rpc_doc.exe index alpha > alpha/rpc.rst @dune exec $(DOCGENDIR)/rpc_doc.exe index shell > shell/rpc.rst @dune exec $(DOCGENDIR)/rpc_doc.exe acl > user/default-acl.json @@ -163,5 +172,5 @@ lint: pylint pycodestyle lint_black clean: @-rm -Rf "$(BUILDDIR)" - @-rm -Rf api/errors.rst active/rpc.rst 010/rpc.rst alpha/rpc.rst shell/rpc.rst shell/p2p_api.rst CHANGES.rst - @-rm -Rf api/tezos-*.html api/tezos-*.txt active/tezos-*.html 010/tezos-*.html alpha/tezos-*.html + @-rm -Rf api/errors.rst active/rpc.rst 010/rpc.rst 011/rpc.rst alpha/rpc.rst shell/rpc.rst shell/p2p_api.rst CHANGES.rst + @-rm -Rf api/tezos-*.html api/tezos-*.txt active/tezos-*.html 010/tezos-*.html 011/tezos-*.html alpha/tezos-*.html diff --git a/docs/doc_gen/dune b/docs/doc_gen/dune index 99a8f66e30e8..dbdd9ff8019d 100644 --- a/docs/doc_gen/dune +++ b/docs/doc_gen/dune @@ -8,6 +8,7 @@ tezos-protocol-updater ; TODO nomadic-labs/tezos#462: adapt next line(s) tezos-embedded-protocol-010-PtGRANAD + tezos-embedded-protocol-011-PtHangzH tezos-embedded-protocol-alpha data-encoding re) diff --git a/docs/doc_gen/rpc_doc.ml b/docs/doc_gen/rpc_doc.ml index 82e8e01d3ccf..42a1f6587bd7 100644 --- a/docs/doc_gen/rpc_doc.ml +++ b/docs/doc_gen/rpc_doc.ml @@ -33,6 +33,10 @@ let protocols = Some "/include/rpc_introduction.rst.inc", "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK" ); (* TODO nomadic-labs/tezos#462: adapt rest of this list *) + ( "011", + "011 Hangzhou", + Some "/include/rpc_introduction.rst.inc", + "PtHangzHogokSuiMHemCuowEavgYTP8J5qQ9fQS793MHYFpCY3r" ); ( "", "010 Granada", Some "/include/rpc_introduction.rst.inc", -- GitLab