diff --git a/docs/protocols/alpha.rst b/docs/protocols/alpha.rst index 211c0519b6944628494473b1bd9323a3b3a9c312..25d39409025e0cf10d77d48e311b9d38ff51f98a 100644 --- a/docs/protocols/alpha.rst +++ b/docs/protocols/alpha.rst @@ -35,6 +35,9 @@ Increase_paid_storage Bug Fixes --------- +- Fix a discrepancy in gas consumption of contract origination between + dry run and actual application (MR :gl:`!5659`) + Minor Changes ------------- diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index 365be4acd51b50be2bcc0758b9500d126b069145..960a36bdd39107ca13569354c2207e5783b3be6f 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -1455,17 +1455,17 @@ let apply_external_manager_operation_content : ctxt script.Script.storage >>?= fun (_unparsed_storage, ctxt) -> + Script.force_decode_in_context + ~consume_deserialization_gas + ctxt + script.Script.code + >>?= fun (unparsed_code, ctxt) -> Script_ir_translator.parse_script ctxt ~legacy:false ~allow_forged_in_storage:false script >>=? fun (Ex_script parsed_script, ctxt) -> - Script.force_decode_in_context - ~consume_deserialization_gas - ctxt - script.Script.code - >>?= fun (unparsed_code, ctxt) -> let (Script {storage_type; views; storage; _}) = parsed_script in let views_result = Script_ir_translator.parse_views ctxt ~legacy:false storage_type views diff --git a/tezt/lib_tezos/client.ml b/tezt/lib_tezos/client.ml index f0bafba517f8691de50721800aab8afc83ce9feb..7ea5520f9b84528ad0969ae59e37cd7c038eda0a 100644 --- a/tezt/lib_tezos/client.ml +++ b/tezt/lib_tezos/client.ml @@ -920,7 +920,7 @@ let unset_deposits_limit ?hooks ?endpoint ?(wait = "none") ~src client = |> Process.check_and_read_stdout let spawn_originate_contract ?hooks ?log_output ?endpoint ?(wait = "none") ?init - ?burn_cap ~alias ~amount ~src ~prg client = + ?burn_cap ?gas_limit ?(dry_run = false) ~alias ~amount ~src ~prg client = spawn_command ?hooks ?log_output @@ -939,7 +939,9 @@ let spawn_originate_contract ?hooks ?log_output ?endpoint ?(wait = "none") ?init prg; ] @ optional_arg "init" Fun.id init - @ optional_arg "burn-cap" Tez.to_string burn_cap) + @ optional_arg "burn-cap" Tez.to_string burn_cap + @ optional_arg "gas-limit" string_of_int gas_limit + @ optional_switch "dry-run" dry_run) let convert_michelson_to_json ~kind ?endpoint ~input client = let* client_output = @@ -957,8 +959,8 @@ let convert_script_to_json ?endpoint ~script client = let convert_data_to_json ?endpoint ~data client = convert_michelson_to_json ~kind:"data" ?endpoint ~input:data client -let originate_contract ?hooks ?log_output ?endpoint ?wait ?init ?burn_cap ~alias - ~amount ~src ~prg client = +let originate_contract ?hooks ?log_output ?endpoint ?wait ?init ?burn_cap + ?gas_limit ?dry_run ~alias ~amount ~src ~prg client = let* client_output = spawn_originate_contract ?endpoint @@ -967,6 +969,8 @@ let originate_contract ?hooks ?log_output ?endpoint ?wait ?init ?burn_cap ~alias ?wait ?init ?burn_cap + ?gas_limit + ?dry_run ~alias ~amount ~src diff --git a/tezt/lib_tezos/client.mli b/tezt/lib_tezos/client.mli index 66eb459330173f6f9f1215efe9c6e346b438b21c..b360f6c6b9a76121243d32ebc6ae3817ae145fcb 100644 --- a/tezt/lib_tezos/client.mli +++ b/tezt/lib_tezos/client.mli @@ -753,6 +753,8 @@ val originate_contract : ?wait:string -> ?init:string -> ?burn_cap:Tez.t -> + ?gas_limit:int -> + ?dry_run:bool -> alias:string -> amount:Tez.t -> src:string -> @@ -768,6 +770,8 @@ val spawn_originate_contract : ?wait:string -> ?init:string -> ?burn_cap:Tez.t -> + ?gas_limit:int -> + ?dry_run:bool -> alias:string -> amount:Tez.t -> src:string -> diff --git a/tezt/tests/client_commands.ml b/tezt/tests/client_commands.ml index a873806b7684f269033bf36d0e8849243e328762..0dcffae68f2c1a4f79f9cee3ce68efd78e09f30d 100644 --- a/tezt/tests/client_commands.ml +++ b/tezt/tests/client_commands.ml @@ -203,6 +203,112 @@ module Transfer = struct alias_pkh_source protocol end +module Dry_run = struct + let test_gas_consumed = + Protocol.register_test + ~__FILE__ + ~title:"Check consumed gas of origination dry run" + ~tags:["client"; "gas"; "estimation"; "dryrun"] + @@ fun protocol -> + Log.info + "This test checks that the consumed gas returned by the dry run of a \ + contract origination is sufficient to successfully inject the \ + origination." ; + + Log.info "Initialize a client with protocol %s." (Protocol.name protocol) ; + let* node, client = Client.init_with_protocol `Client ~protocol () in + + let alias = "originated_contract" in + let src = Constant.bootstrap1.alias in + let amount = Tez.zero in + let burn_cap = Tez.of_int 10 in + let prg = + "file:./tezt/tests/contracts/proto_alpha/large_flat_contract.tz" + in + + Log.info + "Call the origination command of the client with dry-run argument to \ + recover gas_consumption estimation." ; + let dry_run_res = + Client.spawn_originate_contract + ~alias + ~amount + ~src + ~prg + ~burn_cap + ~dry_run:true + client + in + let* res = Process.check_and_read_stdout dry_run_res in + let gas_consumed = + let re = + Re.Str.regexp "\\(.\\|[ \\\n]\\)*Consumed gas: \\([0-9.]+\\).*" + in + if Re.Str.string_match re res 0 then + float_of_string (Re.Str.matched_group 2 res) + else + Test.fail + "Failed to parse the consumed gas in the following output of the dry \ + run:\n\ + %s" + res + in + let gas_limit = Float.(to_int (ceil gas_consumed)) in + Log.info + "Estimated gas consumption is: %f. The gas_limit must be at least of %d \ + gas unit for the origination to succeed." + gas_consumed + gas_limit ; + + Log.info + "Try to originate the contract with a gas_limit of %d and check that the \ + origination fails." + (pred gas_limit) ; + let originate_res_ko = + Client.spawn_originate_contract + ~alias + ~amount + ~src + ~prg + ~burn_cap + ~gas_limit:(pred gas_limit) + ~dry_run:false + client + in + let* () = Process.check_error originate_res_ko in + + Log.info + "Originate the contract with a gas_limit of %d (ceil gas_consumed + 1) \ + and check that the origination succeeds." + (succ gas_limit) ; + let originate_res_ok = + Client.spawn_originate_contract + ~alias + ~amount + ~wait:"0" + (* We wait for a new block to force the application of the + operation not only its prechecking. *) + ~src + ~prg + ~burn_cap + ~gas_limit:(succ gas_limit) + ~dry_run:false + client + in + let* () = Node.wait_for_request ~request:`Inject node in + let* _ = Client.bake_for client in + Process.check originate_res_ok + + let register protocols = test_gas_consumed protocols +end + let register ~protocols = Simulation.register [Jakarta; Alpha] ; - Transfer.register protocols + Transfer.register protocols ; + Dry_run.register + (* TODO: https://gitlab.com/tezos/tezos/-/issues/3336 + + use `protocols` when the fixes added in + https://gitlab.com/tezos/tezos/-/merge_requests/5659 will be + backported to `K` *) + [Alpha; Jakarta; Ithaca]