diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.mli b/src/proto_alpha/lib_protocol/test/helpers/context.mli index 243f5a1544469187fee0a1bcd58c22aa9442fb22..06496419bad3f9e665a320584d4736a93bfcd721 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/context.mli @@ -187,7 +187,10 @@ module Tx_rollup : sig transaction rollup at [level]. If the inbox does not exist, the function returns an error. *) val inbox : - t -> Tx_rollup.t -> Tx_rollup_level.t -> Tx_rollup_inbox.t tzresult Lwt.t + t -> + Tx_rollup.t -> + Tx_rollup_level.t -> + Tx_rollup_inbox.t option tzresult Lwt.t (** [commitment ctxt tx_rollup] returns the commitment of this transaction rollup at [level]. If the commitment does not exist, diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index ff6387b20c7a160fd5b7ff78140d0998763c14a0..03f6ad3eb52ed148f83d40fa482907273616482e 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -347,6 +347,7 @@ let raw_level level = assert_ok @@ Raw_level.of_int32 level expensive *) let make_incomplete_commitment_for_batch context level tx_rollup withdraw_list = Context.Tx_rollup.inbox context tx_rollup level >>=? fun metadata -> + let metadata = assert_some metadata in let str_for_context_hash = Data_encoding.Binary.to_string_exn Tx_rollup_inbox.encoding metadata in @@ -702,11 +703,12 @@ let test_add_batch () = Tx_rollup_inbox. {inbox_length = 1; cumulated_size = contents_size; merkle_root} in - Alcotest.check - inbox_testable - "Expected inbox is not the computed one" - expected_inbox - inbox ; + Alcotest.( + check + (option inbox_testable) + "Expected inbox is not the computed one" + (Some expected_inbox) + inbox) ; inbox_burn state contents_size >>?= fun cost -> Assert.balance_was_debited ~loc:__LOC__ (B b) contract balance cost @@ -795,10 +797,10 @@ let test_add_two_batches () = in Alcotest.( check - inbox_testable + (option inbox_testable) "The expected inbox is not the computed one" inbox - expected_inbox) ; + (Some expected_inbox)) ; inbox_burn state expected_inbox.cumulated_size >>?= fun cost -> Assert.balance_was_debited ~loc:__LOC__ (B b) contract balance cost @@ -996,10 +998,10 @@ let test_valid_deposit () = in Alcotest.( check - inbox_testable + (option inbox_testable) "Expected inbox different from the computed one" inbox - expected_inbox) ; + (Some expected_inbox)) ; return_unit (** [test_additional_space_allocation_for_valid_deposit] originates a tx rollup with small [tx_rollup_origination_size], make a valid deposit and check additional space allocation *) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_services.ml b/src/proto_alpha/lib_protocol/tx_rollup_services.ml index 2d150b1de3212e1314bec13571f7f7e468d7eb20..49d7589d484f83e6c20e1eff2ac31b18f559581b 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_services.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_services.ml @@ -41,7 +41,7 @@ module S = struct RPC_service.get_service ~description:"Get the inbox of a transaction rollup" ~query:RPC_query.empty - ~output:Tx_rollup_inbox.encoding + ~output:Data_encoding.(option Tx_rollup_inbox.encoding) RPC_path.( custom_root /: Tx_rollup.rpc_arg / "inbox" /: Tx_rollup_level.rpc_arg) @@ -71,7 +71,7 @@ let register () = let open Services_registration in opt_register1 ~chunked:false S.state (fun ctxt tx_rollup () () -> Tx_rollup_state.find ctxt tx_rollup >|=? snd) ; - opt_register2 ~chunked:false S.inbox (fun ctxt tx_rollup level () () -> + register2 ~chunked:false S.inbox (fun ctxt tx_rollup level () () -> Tx_rollup_inbox.find ctxt level tx_rollup >|=? snd) ; register2 ~chunked:false S.commitment (fun ctxt tx_rollup level () () -> Tx_rollup_state.get ctxt tx_rollup >>=? fun (ctxt, state) -> diff --git a/src/proto_alpha/lib_protocol/tx_rollup_services.mli b/src/proto_alpha/lib_protocol/tx_rollup_services.mli index f9f4dea9bca5296f9534385c877377af005baf69..74ba514a1fa6dcd0dd9dd0a4de38af7833c76bcd 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_services.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_services.mli @@ -43,7 +43,7 @@ val inbox : 'a -> Tx_rollup.t -> Tx_rollup_level.t -> - Tx_rollup_inbox.t shell_tzresult Lwt.t + Tx_rollup_inbox.t option shell_tzresult Lwt.t val commitment : 'a #RPC_context.simple -> diff --git a/tezt/lib_tezos/rollup.ml b/tezt/lib_tezos/rollup.ml index e630fe228c67ac2d03b302ffc85e5ff209f49fa9..80ae424c4f2261be0bfca276371281716285f025 100644 --- a/tezt/lib_tezos/rollup.ml +++ b/tezt/lib_tezos/rollup.ml @@ -50,6 +50,27 @@ module Tx_rollup = struct type inbox = {inbox_length : int; cumulated_size : int; merkle_root : string} + type messages = { + count : int; + root : string; + last_message_result_hash : string; + } + + type commitment = { + level : int; + messages : messages; + predecessor : string option; + inbox_merkle_root : string; + } + + type submitted_commitment = { + commitment : commitment; + commitment_hash : string; + committer : string; + submitted_at : int; + finalized_at : int option; + } + type message = [`Batch of Hex.t] let make_batch batch = `Batch (Hex.of_string batch) @@ -85,15 +106,44 @@ module Tx_rollup = struct let get_inbox ?hooks ~rollup ~level client = let parse json = - let inbox_length = JSON.(json |-> "inbox_length" |> as_int) in - let cumulated_size = JSON.(json |-> "cumulated_size" |> as_int) in - let merkle_root = JSON.(json |-> "merkle_root" |> as_string) in - {inbox_length; cumulated_size; merkle_root} + if JSON.is_null json then None + else + let inbox_length = JSON.(json |-> "inbox_length" |> as_int) in + let cumulated_size = JSON.(json |-> "cumulated_size" |> as_int) in + let merkle_root = JSON.(json |-> "merkle_root" |> as_string) in + Some {inbox_length; cumulated_size; merkle_root} in RPC.Tx_rollup.get_inbox ?hooks ~rollup ~level client |> map_runnable parse let get_commitment ?hooks ?block ~rollup ~level client = + let parse json = + if JSON.is_null json then None + else + let commitment_json = JSON.(json |-> "commitment") in + let level = JSON.(commitment_json |-> "level" |> as_int) in + let messages_json = JSON.(commitment_json |-> "messages") in + let count = JSON.(messages_json |-> "count" |> as_int) in + let root = JSON.(messages_json |-> "root" |> as_string) in + let last_message_result_hash = + JSON.(messages_json |-> "last_message_result_hash" |> as_string) + in + let messages = {count; root; last_message_result_hash} in + let predecessor = + JSON.(commitment_json |-> "predecessor" |> as_string_opt) + in + let inbox_merkle_root = + JSON.(commitment_json |-> "inbox_merkle_root" |> as_string) + in + let commitment = {level; messages; predecessor; inbox_merkle_root} in + let commitment_hash = JSON.(json |-> "commitment_hash" |> as_string) in + let committer = JSON.(json |-> "committer" |> as_string) in + let submitted_at = JSON.(json |-> "submitted_at" |> as_int) in + let finalized_at = JSON.(json |-> "finalized_at" |> as_int_opt) in + Some + {commitment; commitment_hash; committer; submitted_at; finalized_at} + in RPC.Tx_rollup.get_commitment ?hooks ?block ~rollup ~level client + |> map_runnable parse let get_pending_bonded_commitments ?hooks ?block ~rollup ~pkh client = RPC.Tx_rollup.get_pending_bonded_commitments @@ -216,6 +266,37 @@ module Tx_rollup = struct (fun {inbox_length; cumulated_size; merkle_root} -> (inbox_length, cumulated_size, merkle_root)) (tuple3 int int string) + + let commitment : submitted_commitment Check.typ = + let open Check in + convert + (fun { + commitment = + { + level; + messages = {count; root; last_message_result_hash}; + predecessor; + inbox_merkle_root; + }; + commitment_hash; + committer; + submitted_at; + finalized_at; + } -> + ( ( level, + (count, root, last_message_result_hash), + predecessor, + inbox_merkle_root ), + commitment_hash, + committer, + submitted_at, + finalized_at )) + (tuple5 + (tuple4 int (tuple3 int string string) (option string) string) + string + string + int + (option int)) end module Parameters = struct diff --git a/tezt/lib_tezos/rollup.mli b/tezt/lib_tezos/rollup.mli index 60814434c12aa1937449f529cbd256962865fac7..84fe1f915f381efa01f34983327d5fae57065a81 100644 --- a/tezt/lib_tezos/rollup.mli +++ b/tezt/lib_tezos/rollup.mli @@ -38,6 +38,27 @@ module Tx_rollup : sig type inbox = {inbox_length : int; cumulated_size : int; merkle_root : string} + type messages = { + count : int; + root : string; + last_message_result_hash : string; + } + + type commitment = { + level : int; + messages : messages; + predecessor : string option; + inbox_merkle_root : string; + } + + type submitted_commitment = { + commitment : commitment; + commitment_hash : string; + committer : string; + submitted_at : int; + finalized_at : int option; + } + type message = [`Batch of Hex.t] val make_batch : string -> message @@ -50,7 +71,7 @@ module Tx_rollup : sig rollup:string -> level:int -> Client.t -> - inbox Process.runnable + inbox option Process.runnable val get_commitment : ?hooks:Process.hooks -> @@ -58,7 +79,7 @@ module Tx_rollup : sig rollup:string -> level:int -> Client.t -> - JSON.t Process.runnable + submitted_commitment option Process.runnable val get_pending_bonded_commitments : ?hooks:Process.hooks -> @@ -107,6 +128,8 @@ module Tx_rollup : sig val state : state Check.typ val inbox : inbox Check.typ + + val commitment : submitted_commitment Check.typ end module Parameters : sig diff --git a/tezt/tests/tx_rollup.ml b/tezt/tests/tx_rollup.ml index 76477786979be896f248c5779f261bf3f61f6f34..de443f0ae8c9b5a61aa63db428be859464224c8d 100644 --- a/tezt/tests/tx_rollup.ml +++ b/tezt/tests/tx_rollup.ml @@ -41,6 +41,8 @@ module Parameters = Rollup.Parameters type t = {node : Node.t; client : Client.t; rollup : string} +let assert_some res = match res with Some r -> r | None -> assert false + let init_with_tx_rollup ?additional_bootstrap_account_count ?(parameters = Parameters.default) ~protocol () = let* parameter_file = Parameters.parameter_file ~parameters protocol in @@ -163,7 +165,10 @@ module Regressions = struct (* The content of the batch does not matter for the regression test. *) let batch = Rollup.make_batch "blob" in let* () = submit_batch ~batch state in - let*! _inbox = Rollup.get_inbox ~hooks ~rollup ~level:0 client in + let*! inbox = Rollup.get_inbox ~hooks ~rollup ~level:0 client in + Check.(inbox <> None) + (Check.option Rollup.Check.inbox) + ~error_msg:"Expected some inbox" ; unit let rpc_inbox_message_hash = @@ -256,9 +261,13 @@ module Regressions = struct let*! commitment = Rollup.get_commitment ~hooks ~block:"head" ~level:0 ~rollup client in - let hash = JSON.(commitment |-> "commitment_hash" |> as_string) in + let hash = + Option.map + (fun (c : Rollup.submitted_commitment) -> c.commitment_hash) + commitment + in let*! state = Rollup.get_state ~hooks ~rollup client in - Check.(state.Rollup.commitment_newest_hash = Some hash) + Check.(state.Rollup.commitment_newest_hash = hash) (Check.option Check.string) ~error_msg:"Commitment hash mismatch: %L vs %R" ; unit @@ -333,6 +342,24 @@ module Regressions = struct "Batch content in JSON should be a string: %s." batch_content_str ; unit + + let rpc_inbox_future = + Protocol.register_test + ~__FILE__ + ~title:"RPC (tx_rollups, regression) - inbox from the future" + ~tags:["tx_rollup"; "rpc"; "inbox"] + @@ fun protocol -> + let* ({rollup; client; node = _} as state) = + init_with_tx_rollup ~protocol () + in + (* The content of the batch does not matter for the regression test. *) + let batch = Rollup.make_batch "blob" in + let* () = submit_batch ~batch state in + let*! inbox = Rollup.get_inbox ~hooks ~rollup ~level:1 client in + Check.(inbox = None) + (Check.option Rollup.Check.inbox) + ~error_msg:"Expected no inbox" ; + unit end module Limits = struct @@ -405,10 +432,9 @@ module Regressions = struct let current_level = Node.get_level node in let* () = Client.bake_for client in let* _ = Node.wait_for_level node (current_level + 1) in - let*! {inbox_length = _; cumulated_size; merkle_root = _} = - Rollup.get_inbox ~hooks ~rollup ~level:0 client - in - Check.(cumulated_size = inbox_limit) + let*! inbox = Rollup.get_inbox ~hooks ~rollup ~level:0 client in + let inbox = assert_some inbox in + Check.(inbox.cumulated_size = inbox_limit) Check.int ~error_msg:"Unexpected inbox size. Expected %R. Got %L" ; unit @@ -548,6 +574,7 @@ module Regressions = struct RPC.rpc_commitment protocols ; RPC.rpc_pending_bonded_commitment protocols ; RPC.batch_encoding protocols ; + RPC.rpc_inbox_future protocols ; Limits.submit_empty_batch protocols ; Limits.submit_maximum_size_batch protocols ; Limits.inbox_maximum_size protocols ; @@ -584,9 +611,9 @@ let submit_three_batches_and_check_size ~rollup ~tezos_level ~tx_level node in let*! inbox = Rollup.get_inbox ~hooks ~rollup ~level:tx_level client in Check.( - ((inbox = expected_inbox) + ((inbox = Some expected_inbox) ~error_msg:"Unexpected inbox. Got: %L. Expected: %R.") - Rollup.Check.inbox) ; + (Check.option Rollup.Check.inbox)) ; return () let test_submit_batches_in_several_blocks = @@ -752,7 +779,16 @@ let test_rollup_with_two_commitments = let* () = repeat parameters.finality_period (fun () -> Client.bake_for client) in - let* _ = RPC.raw_bytes ~path:[] client in + let*! commitment = Rollup.get_commitment ~hooks ~rollup ~level:0 client in + let first_commitment_level = (assert_some commitment).commitment.level in + Check.(first_commitment_level = 0) + Check.int + ~error_msg:"First commitment level must be 0" ; + (* There is only one commitment, so trying to get level 1 will fail *) + let*! commitment = Rollup.get_commitment ~hooks ~rollup ~level:1 client in + Check.(commitment = None) + (Check.option Rollup.Check.commitment) + ~error_msg:"Expected no commitment" ; let*! () = submit_finalize_commitment state in (* A second submission just to ensure it can be included into a block even if it fails. *) @@ -760,10 +796,10 @@ let test_rollup_with_two_commitments = submit_finalize_commitment ~src:Constant.bootstrap2.public_key_hash state in let* _ = Client.bake_for client in - let*? process = Rollup.get_inbox ~hooks ~rollup ~level:0 client in - let* () = - Process.check_error ~msg:(rex " No service found at this URL") process - in + let*! inbox = Rollup.get_inbox ~hooks ~rollup ~level:0 client in + Check.(inbox = None) + (Check.option Rollup.Check.inbox) + ~error_msg:"Expected no inbox" ; let* json = RPC.get_operations client in let manager_operations = JSON.(json |=> 3 |> as_list) in Check.(List.length manager_operations = 2) @@ -801,7 +837,11 @@ let test_rollup_with_two_commitments = submit_remove_commitment ~src:Constant.bootstrap2.public_key_hash state in let* () = Client.bake_for client in - let predecessor = Some JSON.(commitment |-> "commitment_hash" |> as_string) in + let predecessor = + Option.map + (fun (c : Rollup.submitted_commitment) -> c.commitment_hash) + commitment + in let inbox_content = `Content [batch] in let* () = submit_commitment @@ -817,20 +857,30 @@ let test_rollup_with_two_commitments = let*! () = submit_finalize_commitment ~src:Constant.bootstrap2.public_key_hash state in - let*! _inbox = Rollup.get_inbox ~hooks ~rollup ~level:1 client in + let*! inbox = Rollup.get_inbox ~hooks ~rollup ~level:1 client in + Check.(inbox <> None) + (Check.option Rollup.Check.inbox) + ~error_msg:"Expected some inbox" ; let* () = Client.bake_for client in - let*? process = Rollup.get_inbox ~hooks ~rollup ~level:0 client in - let* () = - Process.check_error ~msg:(rex " No service found at this URL") process - in - let*! _commitment = Rollup.get_commitment ~hooks ~rollup ~level:0 client in + let*! inbox = Rollup.get_inbox ~hooks ~rollup ~level:0 client in + Check.(inbox = None) + (Check.option Rollup.Check.inbox) + ~error_msg:"Expected no inbox" ; + let*! _commitment = Rollup.get_commitment ~hooks ~rollup ~level:1 client in + let*! commitment = Rollup.get_commitment ~hooks ~rollup ~level:0 client in + Check.(commitment = None) + (Check.option Rollup.Check.commitment) + ~error_msg:"Expected no commitment" ; let* () = Client.bake_for client in let*! () = submit_remove_commitment ~src:Constant.bootstrap2.public_key_hash state in let* () = Client.bake_for client in let*! _commitment = Rollup.get_commitment ~hooks ~rollup ~level:0 client in - let*! _commitment = Rollup.get_commitment ~hooks ~rollup ~level:1 client in + let*! commitment = Rollup.get_commitment ~hooks ~rollup ~level:1 client in + Check.(commitment = None) + (Check.option Rollup.Check.commitment) + ~error_msg:"Expected no commitment" ; let* () = submit_return_bond ~src:Constant.bootstrap1.public_key_hash state in let* json = RPC.raw_bytes ~path:["tx_rollup"] client in let json_object = JSON.as_object json in @@ -1075,7 +1125,7 @@ let test_rollup_wrong_path_for_rejection = let test_rollup_wrong_rejection_long_path = Protocol.register_test ~__FILE__ - ~title:"wrong rejection wtih long path" + ~title:"wrong rejection with long path" ~tags:["tx_rollup"; "rejection"; "batch"] @@ fun protocol -> let parameters = Parameters.{finality_period = 1; withdraw_period = 1} in diff --git a/tezt/tests/tx_rollup_node.ml b/tezt/tests/tx_rollup_node.ml index 6478d3e939389aba9c3d7a5cffb0c576de0eb9d0..7a3e7ac127cb42dd7b2a02219c75cd89cfd0de2d 100644 --- a/tezt/tests/tx_rollup_node.ml +++ b/tezt/tests/tx_rollup_node.ml @@ -189,8 +189,8 @@ let test_tx_node_store_inbox = let*! expected_inbox_1 = Rollup.get_inbox ~rollup ~level:0 client in (* Ensure that stored inboxes on daemon's side are equivalent of inboxes returned by the rpc call. *) - Check.(node_inbox_1 = expected_inbox_1) - Rollup.Check.inbox + Check.(Some node_inbox_1 = expected_inbox_1) + (Check.option Rollup.Check.inbox) ~error_msg: "Unexpected inbox computed from the rollup node. Expected %R. \ Computed %L" ; @@ -205,8 +205,8 @@ let test_tx_node_store_inbox = let*! expected_inbox_2 = Rollup.get_inbox ~rollup ~level:1 client in (* Ensure that stored inboxes on daemon side are equivalent of inboxes returned by the rpc call. *) - Check.(node_inbox_2 = expected_inbox_2) - Rollup.Check.inbox + Check.(Some node_inbox_2 = expected_inbox_2) + (Check.option Rollup.Check.inbox) ~error_msg: "Unexpected inbox computed from the rollup node. Expected %R. \ Computed %L" ; @@ -215,8 +215,8 @@ let test_tx_node_store_inbox = let* () = Rollup_node.run tx_node in let* () = Rollup_node.wait_for_ready tx_node in let*! inbox_after_restart = Rollup.get_inbox ~rollup ~level:1 client in - Check.(node_inbox_2 = inbox_after_restart) - Rollup.Check.inbox + Check.(Some node_inbox_2 = inbox_after_restart) + (Check.option Rollup.Check.inbox) ~error_msg: "Unexpected inbox computed from the rollup node. Expected %R. \ Computed %L" ;