diff --git a/CHANGES.rst b/CHANGES.rst index b874566e6f41f006eea0a89a21dd63270c2aa505..406692137e56e1f42c6b1583b60281a074e4b48a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -30,6 +30,10 @@ Node Client ------ +- A new ``--force`` option was added to the ``transfer`` command. It + makes the client inject the transaction in a node even if the + simulation of the transaction fails. + Baker / Endorser / Accuser -------------------------- diff --git a/src/lib_clic/clic.ml b/src/lib_clic/clic.ml index 3513194c7fcb54027d060f7ccd954f15a4f01229..693b6bdc15b608aa5594ce88f75475b04094e029 100644 --- a/src/lib_clic/clic.ml +++ b/src/lib_clic/clic.ml @@ -1366,6 +1366,68 @@ let args17 spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 spec10 spec11 spec17 )); } +let args18 spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 spec10 spec11 + spec12 spec13 spec14 spec15 spec16 spec17 spec18 = + Argument + { + spec = + spec1 + >> (spec2 + >> (spec3 + >> (spec4 + >> (spec5 + >> (spec6 + >> (spec7 + >> (spec8 + >> (spec9 + >> (spec10 + >> (spec11 + >> (spec12 + >> (spec13 + >> (spec14 + >> (spec15 + >> (spec16 + >> (spec17 + >> (spec18 >> NoArgs)))) + ))))))))))))); + converter = + (fun ( arg1, + ( arg2, + ( arg3, + ( arg4, + ( arg5, + ( spec6, + ( spec7, + ( spec8, + ( spec9, + ( spec10, + ( spec11, + ( spec12, + ( spec13, + ( spec14, + ( spec15, + (spec16, (spec17, (spec18, ()))) ) ) + ) ) ) ) ) ) ) ) ) ) ) ) ) -> + ( arg1, + arg2, + arg3, + arg4, + arg5, + spec6, + spec7, + spec8, + spec9, + spec10, + spec11, + spec12, + spec13, + spec14, + spec15, + spec16, + spec17, + spec18 )); + } + (* Some combinators for writing commands concisely. *) let param ~name ~desc kind next = Param (name, desc, kind, next) diff --git a/src/lib_clic/clic.mli b/src/lib_clic/clic.mli index 677f1795b587d0b92fc585a5c26db9a16f4fe7f6..c15840d82b002eb71de2595970200290509adb87 100644 --- a/src/lib_clic/clic.mli +++ b/src/lib_clic/clic.mli @@ -359,6 +359,47 @@ val args17 : 'ctx ) options +(** Include 18 optional parameters *) +val args18 : + ('a, 'ctx) arg -> + ('b, 'ctx) arg -> + ('c, 'ctx) arg -> + ('d, 'ctx) arg -> + ('e, 'ctx) arg -> + ('f, 'ctx) arg -> + ('g, 'ctx) arg -> + ('h, 'ctx) arg -> + ('i, 'ctx) arg -> + ('j, 'ctx) arg -> + ('k, 'ctx) arg -> + ('l, 'ctx) arg -> + ('m, 'ctx) arg -> + ('n, 'ctx) arg -> + ('o, 'ctx) arg -> + ('p, 'ctx) arg -> + ('q, 'ctx) arg -> + ('r, 'ctx) arg -> + ( 'a + * 'b + * 'c + * 'd + * 'e + * 'f + * 'g + * 'h + * 'i + * 'j + * 'k + * 'l + * 'm + * 'n + * 'o + * 'p + * 'q + * 'r, + 'ctx ) + options + (** {2 Parameter based command lines} *) (** Type of parameters for a command *) diff --git a/src/proto_011_PtHangz2/lib_client/client_proto_context.ml b/src/proto_011_PtHangz2/lib_client/client_proto_context.ml index 459fcc41da91b9af03f61536b6fc9012a3b98fb1..e53f8948ecb97831a8f85193b4ed947818bbf5db 100644 --- a/src/proto_011_PtHangz2/lib_client/client_proto_context.ml +++ b/src/proto_011_PtHangz2/lib_client/client_proto_context.ml @@ -101,9 +101,9 @@ let build_transaction_operation ~amount ~parameters ?(entrypoint = "default") 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 () = + ?verbose_signing ?simulation ?(force = false) ?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 @@ -124,6 +124,7 @@ let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run ?dry_run ?verbose_signing ?simulation + ~force ?branch ~source ~fee:(Limit.of_option fee) @@ -135,7 +136,8 @@ let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run ~fee_parameter contents >>=? fun (oph, op, result) -> - Lwt.return (Injection.originated_contracts result) >>=? fun contracts -> + Lwt.return (Injection.originated_contracts ~force 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) @@ -338,7 +340,7 @@ let originate_contract (cctxt : #full) ~chain ~block ?confirmations ?dry_run | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> return (oph, op, result)) >>=? fun res -> - Lwt.return (Injection.originated_contracts result) >>=? function + Lwt.return (Injection.originated_contracts ~force:false result) >>=? function | [contract] -> return (res, contract) | contracts -> failwith diff --git a/src/proto_011_PtHangz2/lib_client/client_proto_context.mli b/src/proto_011_PtHangz2/lib_client/client_proto_context.mli index c5dc30b57e243804d8af442c62f6afe1eb656d1d..ba5306132ed88c9319d1904bf51e0771d1e0b118 100644 --- a/src/proto_011_PtHangz2/lib_client/client_proto_context.mli +++ b/src/proto_011_PtHangz2/lib_client/client_proto_context.mli @@ -185,6 +185,7 @@ val transfer : ?dry_run:bool -> ?verbose_signing:bool -> ?simulation:bool -> + ?force:bool -> ?branch:int -> source:public_key_hash -> src_pk:public_key -> diff --git a/src/proto_011_PtHangz2/lib_client/injection.ml b/src/proto_011_PtHangz2/lib_client/injection.ml index 9d68cdd144250c689b7dd21606f995426ffb84fc..d9712d786715c02fab1d3e40b487ba3504182cf2 100644 --- a/src/proto_011_PtHangz2/lib_client/injection.ml +++ b/src/proto_011_PtHangz2/lib_client/injection.ml @@ -407,6 +407,11 @@ let rec originated_contracts : type kind. kind contents_result_list -> _ = originated_contracts rest >>? fun contracts2 -> Ok (List.rev_append contracts1 contracts2) +(* When --force is used, we don't want [originated_contracts] to fail as + it would stop the client before the injection of the operation. *) +let originated_contracts ~force results = + match originated_contracts results with Error _ when force -> Ok [] | e -> e + 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) @@ -780,8 +785,8 @@ let may_patch_limits (type kind) (cctxt : #Protocol_client_context.full) 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) = + ?(dry_run = false) ?(simulation = false) ?(force = false) ?branch ?src_sk + ?verbose_signing ~fee_parameter (contents : kind contents_list) = (if simulation then simulate cctxt ~chain ~block ?branch contents else preapply @@ -801,7 +806,7 @@ let inject_operation_internal (type kind) cctxt ~chain ~block ?confirmations "@[This simulation failed:@,%a@]" Operation_result.pp_operation_result (op.protocol_data.contents, result.contents) - >>= fun () -> Lwt.return res) + >>= fun () -> if force then return_unit else Lwt.return res) >>=? fun () -> let bytes = Data_encoding.Binary.to_bytes_exn Operation.encoding (Operation.pack op) @@ -871,7 +876,8 @@ let inject_operation_internal (type kind) cctxt ~chain ~block ?confirmations Operation_result.pp_operation_result (op.protocol_data.contents, result.contents) >>= fun () -> - Lwt.return (originated_contracts result.contents) >>=? fun contracts -> + Lwt.return (originated_contracts result.contents ~force) + >>=? fun contracts -> List.iter_s (fun c -> cctxt#message "New contract %a originated." Contract.pp c) contracts @@ -937,7 +943,7 @@ 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 + ?verbose_signing ?simulation ?force ~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 @@ -1010,6 +1016,7 @@ let inject_manager_operation cctxt ~chain ~block ?branch ?confirmations ?dry_run ?confirmations ?dry_run ?simulation + ?force ~fee_parameter ?verbose_signing ?branch @@ -1035,6 +1042,7 @@ let inject_manager_operation cctxt ~chain ~block ?branch ?confirmations ?dry_run ?dry_run ?verbose_signing ?simulation + ?force ~fee_parameter ?branch ~src_sk diff --git a/src/proto_011_PtHangz2/lib_client/injection.mli b/src/proto_011_PtHangz2/lib_client/injection.mli index d8f99d62051005e5a5af957a060b8161a58a1f75..50da92f06c55782f54afbba010f8ed4dc2d338d5 100644 --- a/src/proto_011_PtHangz2/lib_client/injection.mli +++ b/src/proto_011_PtHangz2/lib_client/injection.mli @@ -90,6 +90,7 @@ val inject_manager_operation : ?dry_run:bool -> ?verbose_signing:bool -> ?simulation:bool -> + ?force:bool -> source:Signature.Public_key_hash.t -> src_pk:Signature.public_key -> src_sk:Client_keys.sk_uri -> @@ -101,5 +102,8 @@ val inject_manager_operation : 'kind Annotated_manager_operation.annotated_list -> 'kind Kind.manager result_list tzresult Lwt.t +(** Collects the addresses of all contracts originated by a batch of operations + by looking at the operation results. Fails if an operation in the batch is + failed unless [force] is given. *) val originated_contracts : - 'kind contents_result_list -> Contract.t list tzresult + force:bool -> 'kind contents_result_list -> Contract.t list tzresult diff --git a/src/proto_011_PtHangz2/lib_client/managed_contract.ml b/src/proto_011_PtHangz2/lib_client/managed_contract.ml index 29bb3d976b631f4606eec0a36d85cfae94b22306..cbc1db16a4eb3d32149df8ada2a5fc44853adaff 100644 --- a/src/proto_011_PtHangz2/lib_client/managed_contract.ml +++ b/src/proto_011_PtHangz2/lib_client/managed_contract.ml @@ -277,9 +277,9 @@ let build_transaction_operation (cctxt : #full) ~chain ~block ~contract 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 () : + ?verbose_signing ?simulation ?(force = false) ?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 @@ -305,6 +305,7 @@ let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run ?dry_run ?verbose_signing ?simulation + ~force ?branch ~source ~fee:(Limit.of_option fee) @@ -316,6 +317,7 @@ let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run ~fee_parameter operation >>=? fun (oph, op, result) -> - Lwt.return (Injection.originated_contracts result) >>=? fun contracts -> + Lwt.return (Injection.originated_contracts ~force result) + >>=? fun contracts -> return_single_manager_result (oph, op, result) >>=? fun res -> return (res, contracts) diff --git a/src/proto_011_PtHangz2/lib_client/managed_contract.mli b/src/proto_011_PtHangz2/lib_client/managed_contract.mli index ae532c986987df213f6d52e2c90e45c69dbf1f81..bb467b5482e8315151cb9602112cf8b66b09cb99 100644 --- a/src/proto_011_PtHangz2/lib_client/managed_contract.mli +++ b/src/proto_011_PtHangz2/lib_client/managed_contract.mli @@ -93,6 +93,7 @@ val transfer : ?dry_run:bool -> ?verbose_signing:bool -> ?simulation:bool -> + ?force:bool -> ?branch:int -> source:public_key_hash -> src_pk:public_key -> diff --git a/src/proto_011_PtHangz2/lib_client_commands/client_proto_context_commands.ml b/src/proto_011_PtHangz2/lib_client_commands/client_proto_context_commands.ml index bad29a4fde77021f6151289d8a63a8c881cbf588..9885bc0090bd720382cdc48135f00a7e71e4756d 100644 --- a/src/proto_011_PtHangz2/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_011_PtHangz2/lib_client_commands/client_proto_context_commands.ml @@ -56,6 +56,14 @@ let simulate_switch = "Simulate the execution of the command, without needing any signatures." () +let force_switch = + Clic.switch + ~long:"force" + ~doc: + "Inject the operation even if the simulation results in a failure. This \ + switch requires --gas-limit, --storage-limit, and --fee." + () + let report_michelson_errors ?(no_print_source = false) ~msg (cctxt : #Client_context.printer) = function | Error errs -> @@ -104,11 +112,12 @@ 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 +let transfer_command amount source destination (cctxt : #Client_context.printer) ( fee, dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, @@ -131,6 +140,22 @@ let transfer_command amount source destination cctxt burn_cap; } in + (* When --force is used we want to inject the transfer even if it fails. + In that case we cannot rely on simulation to compute limits and fees + so we require the corresponding options to be set. *) + let check_force_dependency name = function + | None -> + cctxt#error + "When the --force switch is used, the %s option is required." + name + | _ -> Lwt.return_unit + in + (if force then + check_force_dependency "--gas-limit" gas_limit >>= fun () -> + check_force_dependency "--storage-limit" storage_limit >>= fun () -> + check_force_dependency "--fee" fee + else Lwt.return_unit) + >>= fun () -> (match Contract.is_implicit source with | None -> let contract = source in @@ -144,6 +169,7 @@ let transfer_command amount source destination cctxt ~dry_run ~verbose_signing ~simulation + ~force ~fee_parameter ?fee ~contract @@ -167,6 +193,7 @@ let transfer_command amount source destination cctxt ?confirmations:cctxt#confirmations ~dry_run ~simulation + ~force ~verbose_signing ~fee_parameter ~source @@ -948,11 +975,12 @@ let commands network () = command ~group ~desc:"Transfer tokens / call a smart contract." - (args16 + (args17 fee_arg dry_run_switch verbose_signing_switch simulate_switch + force_switch gas_limit_arg storage_limit_arg counter_arg @@ -980,6 +1008,7 @@ let commands network () = dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, @@ -1005,6 +1034,7 @@ let commands network () = dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, @@ -1101,11 +1131,12 @@ let commands network () = command ~group ~desc:"Call a smart contract (same as 'transfer 0')." - (args16 + (args17 fee_arg dry_run_switch verbose_signing_switch simulate_switch + force_switch gas_limit_arg storage_limit_arg counter_arg @@ -1131,6 +1162,7 @@ let commands network () = dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, @@ -1156,6 +1188,7 @@ let commands network () = dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, diff --git a/src/proto_012_PsiThaCa/lib_client/client_proto_context.ml b/src/proto_012_PsiThaCa/lib_client/client_proto_context.ml index d55e8eb9f3219984d4010660e0c51206d9e44ce0..718ca408e4cac9b76d5a72ceca7097218bb4f9b3 100644 --- a/src/proto_012_PsiThaCa/lib_client/client_proto_context.ml +++ b/src/proto_012_PsiThaCa/lib_client/client_proto_context.ml @@ -104,9 +104,9 @@ let build_transaction_operation ~amount ~parameters ?(entrypoint = "default") 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 () = + ?verbose_signing ?simulation ?(force = false) ?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 @@ -127,6 +127,7 @@ let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run ?dry_run ?verbose_signing ?simulation + ~force ?branch ~source ~fee:(Limit.of_option fee) @@ -138,7 +139,8 @@ let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run ~fee_parameter contents >>=? fun (oph, op, result) -> - Lwt.return (Injection.originated_contracts result) >>=? fun contracts -> + Lwt.return (Injection.originated_contracts ~force 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) @@ -374,7 +376,7 @@ let originate_contract (cctxt : #full) ~chain ~block ?confirmations ?dry_run | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> return (oph, op, result)) >>=? fun res -> - Lwt.return (Injection.originated_contracts result) >>=? function + Lwt.return (Injection.originated_contracts ~force:false result) >>=? function | [contract] -> return (res, contract) | contracts -> failwith diff --git a/src/proto_012_PsiThaCa/lib_client/client_proto_context.mli b/src/proto_012_PsiThaCa/lib_client/client_proto_context.mli index 05d01ac753ef1ce36a71ecfd029003491c1b7939..5cf83c93f133c7a4aa3eb22b1ee7efa498ff2e88 100644 --- a/src/proto_012_PsiThaCa/lib_client/client_proto_context.mli +++ b/src/proto_012_PsiThaCa/lib_client/client_proto_context.mli @@ -208,6 +208,7 @@ val transfer : ?dry_run:bool -> ?verbose_signing:bool -> ?simulation:bool -> + ?force:bool -> ?branch:int -> source:public_key_hash -> src_pk:public_key -> diff --git a/src/proto_012_PsiThaCa/lib_client/injection.ml b/src/proto_012_PsiThaCa/lib_client/injection.ml index a60dddcb4fd98d1088372ca63093c4fa2040bd15..862e9f78396adf5cfdc7377554298acf25c87972 100644 --- a/src/proto_012_PsiThaCa/lib_client/injection.ml +++ b/src/proto_012_PsiThaCa/lib_client/injection.ml @@ -414,6 +414,11 @@ let rec originated_contracts : type kind. kind contents_result_list -> _ = originated_contracts rest >>? fun contracts2 -> Ok (List.rev_append contracts1 contracts2) +(* When --force is used, we don't want [originated_contracts] to fail as + it would stop the client before the injection of the operation. *) +let originated_contracts ~force results = + match originated_contracts results with Error _ when force -> Ok [] | e -> e + 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) @@ -808,8 +813,8 @@ let tenderbake_adjust_confirmations (cctxt : #Client_context.full) = function were tenderbake_finality_confirmations. *) 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) = + ?(dry_run = false) ?(simulation = false) ?(force = false) ?branch ?src_sk + ?verbose_signing ~fee_parameter (contents : kind contents_list) = (if simulation then simulate cctxt ~chain ~block ?branch contents else preapply @@ -829,7 +834,7 @@ let inject_operation_internal (type kind) cctxt ~chain ~block ?confirmations "@[This simulation failed:@,%a@]" Operation_result.pp_operation_result (op.protocol_data.contents, result.contents) - >>= fun () -> Lwt.return res) + >>= fun () -> if force then return_unit else Lwt.return res) >>=? fun () -> let bytes = Data_encoding.Binary.to_bytes_exn Operation.encoding (Operation.pack op) @@ -901,7 +906,8 @@ let inject_operation_internal (type kind) cctxt ~chain ~block ?confirmations Operation_result.pp_operation_result (op.protocol_data.contents, result.contents) >>= fun () -> - Lwt.return (originated_contracts result.contents) >>=? fun contracts -> + Lwt.return (originated_contracts result.contents ~force) + >>=? fun contracts -> List.iter_s (fun c -> cctxt#message "New contract %a originated." Contract.pp c) contracts @@ -967,7 +973,7 @@ 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 + ?verbose_signing ?simulation ?force ~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 @@ -1040,6 +1046,7 @@ let inject_manager_operation cctxt ~chain ~block ?branch ?confirmations ?dry_run ?confirmations ?dry_run ?simulation + ?force ~fee_parameter ?verbose_signing ?branch @@ -1065,6 +1072,7 @@ let inject_manager_operation cctxt ~chain ~block ?branch ?confirmations ?dry_run ?dry_run ?verbose_signing ?simulation + ?force ~fee_parameter ?branch ~src_sk diff --git a/src/proto_012_PsiThaCa/lib_client/injection.mli b/src/proto_012_PsiThaCa/lib_client/injection.mli index d8f99d62051005e5a5af957a060b8161a58a1f75..50da92f06c55782f54afbba010f8ed4dc2d338d5 100644 --- a/src/proto_012_PsiThaCa/lib_client/injection.mli +++ b/src/proto_012_PsiThaCa/lib_client/injection.mli @@ -90,6 +90,7 @@ val inject_manager_operation : ?dry_run:bool -> ?verbose_signing:bool -> ?simulation:bool -> + ?force:bool -> source:Signature.Public_key_hash.t -> src_pk:Signature.public_key -> src_sk:Client_keys.sk_uri -> @@ -101,5 +102,8 @@ val inject_manager_operation : 'kind Annotated_manager_operation.annotated_list -> 'kind Kind.manager result_list tzresult Lwt.t +(** Collects the addresses of all contracts originated by a batch of operations + by looking at the operation results. Fails if an operation in the batch is + failed unless [force] is given. *) val originated_contracts : - 'kind contents_result_list -> Contract.t list tzresult + force:bool -> 'kind contents_result_list -> Contract.t list tzresult diff --git a/src/proto_012_PsiThaCa/lib_client/managed_contract.ml b/src/proto_012_PsiThaCa/lib_client/managed_contract.ml index 29bb3d976b631f4606eec0a36d85cfae94b22306..cbc1db16a4eb3d32149df8ada2a5fc44853adaff 100644 --- a/src/proto_012_PsiThaCa/lib_client/managed_contract.ml +++ b/src/proto_012_PsiThaCa/lib_client/managed_contract.ml @@ -277,9 +277,9 @@ let build_transaction_operation (cctxt : #full) ~chain ~block ~contract 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 () : + ?verbose_signing ?simulation ?(force = false) ?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 @@ -305,6 +305,7 @@ let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run ?dry_run ?verbose_signing ?simulation + ~force ?branch ~source ~fee:(Limit.of_option fee) @@ -316,6 +317,7 @@ let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run ~fee_parameter operation >>=? fun (oph, op, result) -> - Lwt.return (Injection.originated_contracts result) >>=? fun contracts -> + Lwt.return (Injection.originated_contracts ~force result) + >>=? fun contracts -> return_single_manager_result (oph, op, result) >>=? fun res -> return (res, contracts) diff --git a/src/proto_012_PsiThaCa/lib_client/managed_contract.mli b/src/proto_012_PsiThaCa/lib_client/managed_contract.mli index ae532c986987df213f6d52e2c90e45c69dbf1f81..bb467b5482e8315151cb9602112cf8b66b09cb99 100644 --- a/src/proto_012_PsiThaCa/lib_client/managed_contract.mli +++ b/src/proto_012_PsiThaCa/lib_client/managed_contract.mli @@ -93,6 +93,7 @@ val transfer : ?dry_run:bool -> ?verbose_signing:bool -> ?simulation:bool -> + ?force:bool -> ?branch:int -> source:public_key_hash -> src_pk:public_key -> diff --git a/src/proto_012_PsiThaCa/lib_client_commands/client_proto_context_commands.ml b/src/proto_012_PsiThaCa/lib_client_commands/client_proto_context_commands.ml index 077fadc50d629a51fb74dba9cb78b8a070b30826..65729e330f1c1fc6d9b78626ebda25866021ff5b 100644 --- a/src/proto_012_PsiThaCa/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_012_PsiThaCa/lib_client_commands/client_proto_context_commands.ml @@ -584,11 +584,20 @@ let simulate_switch = "Simulate the execution of the command, without needing any signatures." () -let transfer_command amount source destination cctxt +let force_switch = + Clic.switch + ~long:"force" + ~doc: + "Inject the operation even if the simulation results in a failure. This \ + switch requires --gas-limit, --storage-limit, and --fee." + () + +let transfer_command amount source destination (cctxt : #Client_context.printer) ( fee, dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, @@ -611,6 +620,22 @@ let transfer_command amount source destination cctxt burn_cap; } in + (* When --force is used we want to inject the transfer even if it fails. + In that case we cannot rely on simulation to compute limits and fees + so we require the corresponding options to be set. *) + let check_force_dependency name = function + | None -> + cctxt#error + "When the --force switch is used, the %s option is required." + name + | _ -> Lwt.return_unit + in + (if force then + check_force_dependency "--gas-limit" gas_limit >>= fun () -> + check_force_dependency "--storage-limit" storage_limit >>= fun () -> + check_force_dependency "--fee" fee + else Lwt.return_unit) + >>= fun () -> (match Contract.is_implicit source with | None -> let contract = source in @@ -624,6 +649,7 @@ let transfer_command amount source destination cctxt ~dry_run ~verbose_signing ~simulation + ~force ~fee_parameter ?fee ~contract @@ -647,6 +673,7 @@ let transfer_command amount source destination cctxt ?confirmations:cctxt#confirmations ~dry_run ~simulation + ~force ~verbose_signing ~fee_parameter ~source @@ -1216,11 +1243,12 @@ let commands_rw () = command ~group ~desc:"Transfer tokens / call a smart contract." - (args16 + (args17 fee_arg dry_run_switch verbose_signing_switch simulate_switch + force_switch gas_limit_arg storage_limit_arg counter_arg @@ -1248,6 +1276,7 @@ let commands_rw () = dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, @@ -1273,6 +1302,7 @@ let commands_rw () = dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, @@ -1369,11 +1399,12 @@ let commands_rw () = command ~group ~desc:"Call a smart contract (same as 'transfer 0')." - (args16 + (args17 fee_arg dry_run_switch verbose_signing_switch simulate_switch + force_switch gas_limit_arg storage_limit_arg counter_arg @@ -1399,6 +1430,7 @@ let commands_rw () = dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, @@ -1424,6 +1456,7 @@ let commands_rw () = dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, diff --git a/src/proto_alpha/lib_client/client_proto_context.ml b/src/proto_alpha/lib_client/client_proto_context.ml index ae75c1f8e330a16b2dc51c3191ad08cd37058cb9..5b65d975b954056450941893f8fc8e411574e73c 100644 --- a/src/proto_alpha/lib_client/client_proto_context.ml +++ b/src/proto_alpha/lib_client/client_proto_context.ml @@ -105,9 +105,9 @@ let build_transaction_operation ~amount ~parameters operation let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run - ?verbose_signing ?simulation ?branch ~source ~src_pk ~src_sk ~destination - ?(entrypoint = Entrypoint.default) ?arg ~amount ?fee ?gas_limit - ?storage_limit ?counter ~fee_parameter ?replace_by_fees () = + ?verbose_signing ?simulation ?(force = false) ?branch ~source ~src_pk + ~src_sk ~destination ?(entrypoint = Entrypoint.default) ?arg ~amount ?fee + ?gas_limit ?storage_limit ?counter ~fee_parameter ?replace_by_fees () = parse_arg_transfer arg >>=? fun parameters -> let contents = build_transaction_operation @@ -128,6 +128,7 @@ let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run ?dry_run ?verbose_signing ?simulation + ~force ?branch ~source ~fee:(Limit.of_option fee) @@ -140,7 +141,8 @@ let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run ~fee_parameter contents >>=? fun (oph, op, result) -> - Lwt.return (Injection.originated_contracts result) >>=? fun contracts -> + Lwt.return (Injection.originated_contracts ~force 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) @@ -376,7 +378,7 @@ let originate_contract (cctxt : #full) ~chain ~block ?confirmations ?dry_run | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> return (oph, op, result)) >>=? fun res -> - Lwt.return (Injection.originated_contracts result) >>=? function + Lwt.return (Injection.originated_contracts ~force:false result) >>=? function | [contract] -> return (res, contract) | contracts -> failwith diff --git a/src/proto_alpha/lib_client/client_proto_context.mli b/src/proto_alpha/lib_client/client_proto_context.mli index 6fdbc4e62128e4fe24685a77d96832989aad5dd4..f3fef840578318176279b571b4a66497605af1ff 100644 --- a/src/proto_alpha/lib_client/client_proto_context.mli +++ b/src/proto_alpha/lib_client/client_proto_context.mli @@ -208,6 +208,7 @@ val transfer : ?dry_run:bool -> ?verbose_signing:bool -> ?simulation:bool -> + ?force:bool -> ?branch:int -> source:public_key_hash -> src_pk:public_key -> diff --git a/src/proto_alpha/lib_client/injection.ml b/src/proto_alpha/lib_client/injection.ml index 1aa906a326db65f244e878f469d1ccb0ecdd6e48..942ef9d0e6b72671aa67d594ef6993e8c62c9525 100644 --- a/src/proto_alpha/lib_client/injection.ml +++ b/src/proto_alpha/lib_client/injection.ml @@ -432,6 +432,11 @@ let rec originated_contracts : type kind. kind contents_result_list -> _ = originated_contracts rest >>? fun contracts2 -> Ok (List.rev_append contracts1 contracts2) +(* When --force is used, we don't want [originated_contracts] to fail as + it would stop the client before the injection of the operation. *) +let originated_contracts ~force results = + match originated_contracts results with Error _ when force -> Ok [] | e -> e + 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) @@ -833,8 +838,8 @@ let tenderbake_adjust_confirmations (cctxt : #Client_context.full) = function were tenderbake_finality_confirmations. *) 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) = + ?(dry_run = false) ?(simulation = false) ?(force = false) ?branch ?src_sk + ?verbose_signing ~fee_parameter (contents : kind contents_list) = (if simulation then simulate cctxt ~chain ~block ?branch contents else preapply @@ -854,7 +859,7 @@ let inject_operation_internal (type kind) cctxt ~chain ~block ?confirmations "@[This simulation failed:@,%a@]" Operation_result.pp_operation_result (op.protocol_data.contents, result.contents) - >>= fun () -> Lwt.return res) + >>= fun () -> if force then return_unit else Lwt.return res) >>=? fun () -> let bytes = Data_encoding.Binary.to_bytes_exn Operation.encoding (Operation.pack op) @@ -926,7 +931,8 @@ let inject_operation_internal (type kind) cctxt ~chain ~block ?confirmations Operation_result.pp_operation_result (op.protocol_data.contents, result.contents) >>= fun () -> - Lwt.return (originated_contracts result.contents) >>=? fun contracts -> + Lwt.return (originated_contracts result.contents ~force) + >>=? fun contracts -> List.iter_s (fun c -> cctxt#message "New contract %a originated." Contract.pp c) contracts @@ -1165,7 +1171,7 @@ let may_replace_operation (type kind) (cctxt : #full) chain from Lwt.return_ok contents let inject_manager_operation cctxt ~chain ~block ?branch ?confirmations ?dry_run - ?verbose_signing ?simulation ~source ~src_pk ~src_sk ~fee ~gas_limit + ?verbose_signing ?simulation ?force ~source ~src_pk ~src_sk ~fee ~gas_limit ~storage_limit ?counter ?(replace_by_fees = false) ~fee_parameter (type kind) (operations : kind Annotated_manager_operation.annotated_list) : (Operation_hash.t @@ -1244,6 +1250,7 @@ let inject_manager_operation cctxt ~chain ~block ?branch ?confirmations ?dry_run ?confirmations ?dry_run ?simulation + ?force ~fee_parameter ?verbose_signing ?branch @@ -1275,6 +1282,7 @@ let inject_manager_operation cctxt ~chain ~block ?branch ?confirmations ?dry_run ?dry_run ?verbose_signing ?simulation + ?force ~fee_parameter ?branch ~src_sk diff --git a/src/proto_alpha/lib_client/injection.mli b/src/proto_alpha/lib_client/injection.mli index 1fba94f4a0e207baa1993853e09f7e2c825f3c6a..21b1301e09e4c92cd8e9546cd7826e4d2392fa20 100644 --- a/src/proto_alpha/lib_client/injection.mli +++ b/src/proto_alpha/lib_client/injection.mli @@ -90,6 +90,7 @@ val inject_manager_operation : ?dry_run:bool -> ?verbose_signing:bool -> ?simulation:bool -> + ?force:bool -> source:Signature.Public_key_hash.t -> src_pk:Signature.public_key -> src_sk:Client_keys.sk_uri -> @@ -102,5 +103,8 @@ val inject_manager_operation : 'kind Annotated_manager_operation.annotated_list -> 'kind Kind.manager result_list tzresult Lwt.t +(** Collects the addresses of all contracts originated by a batch of operations + by looking at the operation results. Fails if an operation in the batch is + failed unless [force] is given. *) val originated_contracts : - 'kind contents_result_list -> Contract.t list tzresult + force:bool -> 'kind contents_result_list -> Contract.t list tzresult diff --git a/src/proto_alpha/lib_client/managed_contract.ml b/src/proto_alpha/lib_client/managed_contract.ml index 676a7d95b03b109847ebddcc847162c809399e0d..3fb10456085169fa092ed2b82890005a0e6cb3eb 100644 --- a/src/proto_alpha/lib_client/managed_contract.ml +++ b/src/proto_alpha/lib_client/managed_contract.ml @@ -285,9 +285,9 @@ let build_transaction_operation (cctxt : #full) ~chain ~block ~contract contract) let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run - ?verbose_signing ?simulation ?branch ~source ~src_pk ~src_sk ~contract - ~destination ?(entrypoint = Entrypoint.default) ?arg ~amount ?fee ?gas_limit - ?storage_limit ?counter ~fee_parameter () : + ?verbose_signing ?simulation ?(force = false) ?branch ~source ~src_pk + ~src_sk ~contract ~destination ?(entrypoint = 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 @@ -313,6 +313,7 @@ let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run ?dry_run ?verbose_signing ?simulation + ~force ?branch ~source ~fee:(Limit.of_option fee) @@ -324,6 +325,7 @@ let transfer (cctxt : #full) ~chain ~block ?confirmations ?dry_run ~fee_parameter operation >>=? fun (oph, op, result) -> - Lwt.return (Injection.originated_contracts result) >>=? fun contracts -> + Lwt.return (Injection.originated_contracts ~force result) + >>=? fun contracts -> return_single_manager_result (oph, op, result) >>=? fun res -> return (res, contracts) diff --git a/src/proto_alpha/lib_client/managed_contract.mli b/src/proto_alpha/lib_client/managed_contract.mli index e272420913a993d4e4a5f31de4090c0eda8fb3f1..cc40c9caa8ff51cc5d88f9a6da31fa6854e6cdb2 100644 --- a/src/proto_alpha/lib_client/managed_contract.mli +++ b/src/proto_alpha/lib_client/managed_contract.mli @@ -93,6 +93,7 @@ val transfer : ?dry_run:bool -> ?verbose_signing:bool -> ?simulation:bool -> + ?force:bool -> ?branch:int -> source:public_key_hash -> src_pk:public_key -> diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index 591df1d6eac99dd3edd2f36db2ebf9c094ccaeb0..72b4f1df59719d84f3c3f7f0ade4961684b2b07d 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -640,11 +640,20 @@ let simulate_switch = "Simulate the execution of the command, without needing any signatures." () -let transfer_command amount source destination cctxt +let force_switch = + Clic.switch + ~long:"force" + ~doc: + "Inject the operation even if the simulation results in a failure. This \ + switch requires --gas-limit, --storage-limit, and --fee." + () + +let transfer_command amount source destination (cctxt : #Client_context.printer) ( fee, dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, @@ -668,6 +677,22 @@ let transfer_command amount source destination cctxt burn_cap; } in + (* When --force is used we want to inject the transfer even if it fails. + In that case we cannot rely on simulation to compute limits and fees + so we require the corresponding options to be set. *) + let check_force_dependency name = function + | None -> + cctxt#error + "When the --force switch is used, the %s option is required." + name + | _ -> Lwt.return_unit + in + (if force then + check_force_dependency "--gas-limit" gas_limit >>= fun () -> + check_force_dependency "--storage-limit" storage_limit >>= fun () -> + check_force_dependency "--fee" fee + else Lwt.return_unit) + >>= fun () -> (match Contract.is_implicit source with | None -> let contract = source in @@ -681,6 +706,7 @@ let transfer_command amount source destination cctxt ~dry_run ~verbose_signing ~simulation + ~force ~fee_parameter ?fee ~contract @@ -704,6 +730,7 @@ let transfer_command amount source destination cctxt ?confirmations:cctxt#confirmations ~dry_run ~simulation + ~force ~verbose_signing ~fee_parameter ~source @@ -1277,11 +1304,12 @@ let commands_rw () = command ~group ~desc:"Transfer tokens / call a smart contract." - (args17 + (args18 fee_arg dry_run_switch verbose_signing_switch simulate_switch + force_switch gas_limit_arg storage_limit_arg counter_arg @@ -1310,6 +1338,7 @@ let commands_rw () = dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, @@ -1336,6 +1365,7 @@ let commands_rw () = dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, @@ -1433,11 +1463,12 @@ let commands_rw () = command ~group ~desc:"Call a smart contract (same as 'transfer 0')." - (args17 + (args18 fee_arg dry_run_switch verbose_signing_switch simulate_switch + force_switch gas_limit_arg storage_limit_arg counter_arg @@ -1464,6 +1495,7 @@ let commands_rw () = dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, @@ -1490,6 +1522,7 @@ let commands_rw () = dry_run, verbose_signing, simulation, + force, gas_limit, storage_limit, counter, diff --git a/tezt/lib_tezos/client.ml b/tezt/lib_tezos/client.ml index ad7ca13760ce9268d45822a3f9e0d696be4d043c..46f02e10e110153c53ea788e9f8a7eb069ebb5c0 100644 --- a/tezt/lib_tezos/client.ml +++ b/tezt/lib_tezos/client.ml @@ -566,7 +566,8 @@ let gen_and_show_keys ?alias client = show_address ~alias client let spawn_transfer ?hooks ?endpoint ?(wait = "none") ?burn_cap ?fee ?gas_limit - ?storage_limit ?counter ?arg ~amount ~giver ~receiver client = + ?storage_limit ?counter ?arg ?(force = false) ~amount ~giver ~receiver + client = spawn_command ?endpoint ?hooks @@ -593,10 +594,11 @@ let spawn_transfer ?hooks ?endpoint ?(wait = "none") ?burn_cap ?fee ?gas_limit ~none:[] ~some:(fun s -> ["--counter"; string_of_int s]) counter - @ Option.fold ~none:[] ~some:(fun p -> ["--arg"; p]) arg) + @ Option.fold ~none:[] ~some:(fun p -> ["--arg"; p]) arg + @ if force then ["--force"] else []) let transfer ?hooks ?endpoint ?wait ?burn_cap ?fee ?gas_limit ?storage_limit - ?counter ?arg ~amount ~giver ~receiver client = + ?counter ?arg ?force ~amount ~giver ~receiver client = spawn_transfer ?endpoint ?hooks @@ -607,6 +609,7 @@ let transfer ?hooks ?endpoint ?wait ?burn_cap ?fee ?gas_limit ?storage_limit ?storage_limit ?counter ?arg + ?force ~amount ~giver ~receiver diff --git a/tezt/lib_tezos/client.mli b/tezt/lib_tezos/client.mli index a2ac462dc584fd43f7b561293f26bba7e9d239c5..0664566483ee501b8d79fa8a6acb82f454df8124 100644 --- a/tezt/lib_tezos/client.mli +++ b/tezt/lib_tezos/client.mli @@ -422,6 +422,7 @@ val transfer : ?storage_limit:int -> ?counter:int -> ?arg:string -> + ?force:bool -> amount:Tez.t -> giver:string -> receiver:string -> @@ -439,6 +440,7 @@ val spawn_transfer : ?storage_limit:int -> ?counter:int -> ?arg:string -> + ?force:bool -> amount:Tez.t -> giver:string -> receiver:string -> diff --git a/tezt/tests/contracts/proto_alpha/always_fails.tz b/tezt/tests/contracts/proto_alpha/always_fails.tz new file mode 100644 index 0000000000000000000000000000000000000000..54014f82672d10a7d1c87c6b9c602d661bfc2b2f --- /dev/null +++ b/tezt/tests/contracts/proto_alpha/always_fails.tz @@ -0,0 +1,3 @@ +parameter string; +storage unit; +code FAILWITH diff --git a/tezt/tests/main.ml b/tezt/tests/main.ml index 792fd66ccb455fec24ca2b2a65668e003ebf3997..f29f347d270ebb472d76234b4f985b357e314aa7 100644 --- a/tezt/tests/main.ml +++ b/tezt/tests/main.ml @@ -109,5 +109,6 @@ let () = Replace_by_fees.register ~protocols:[Alpha] ; Sc_rollup.register ~protocols:[Alpha] ; Views.register ~protocols:[Alpha] () ; + Runtime_script_failure.register ~protocols ; (* Test.run () should be the last statement, don't register afterwards! *) Test.run () diff --git a/tezt/tests/runtime_script_failure.ml b/tezt/tests/runtime_script_failure.ml new file mode 100644 index 0000000000000000000000000000000000000000..815df7e297b595dc13ad50e025237eea1a75b1c7 --- /dev/null +++ b/tezt/tests/runtime_script_failure.ml @@ -0,0 +1,83 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 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 + ------- + Components: Client + Invocation: dune exec tezt/tests/main.exe -- runtime_script_failure + Subject: Test that the --force option of the transfer command can be used + to include an invalid operation in a block +*) + +let check_client_force = + Protocol.register_test + ~__FILE__ + ~title:"Runtime Script Failure: client force" + ~tags:["runtime_script_failure"] + @@ fun protocol -> + let* node = Node.init [Synchronisation_threshold 0; Connections 0] in + let* client = Client.init ~endpoint:(Node node) () in + let* () = Client.activate_protocol ~protocol client in + let* _ = Node.wait_for_level node 1 in + let* contract_id = + Client.originate_contract + ~alias:"always_fails" + ~amount:Tez.zero + ~src:"bootstrap1" + ~prg:"file:./tezt/tests/contracts/proto_alpha/always_fails.tz" + ~init:"Unit" + ~burn_cap:Tez.(of_int 1) + client + in + let* () = Client.bake_for client in + let* () = + Client.transfer + ~gas_limit:100_000 + ~fee:Tez.one + ~amount:Tez.zero + ~burn_cap:Tez.zero + ~storage_limit:10000 + ~giver:"bootstrap1" + ~receiver:contract_id + ~arg:"20" + ~force:true + client + in + let* () = Client.bake_for client in + let* first_manager_operation = + Client.rpc + Client.GET + ["chains"; "main"; "blocks"; "head"; "operations"; "3"; "0"] + client + in + let first_result = + JSON.( + first_manager_operation |-> "contents" |=> 0 |-> "metadata" + |-> "operation_result" |-> "status" |> as_string) + in + assert (first_result = "failed") ; + return () + +let register ~protocols = check_client_force ~protocols