diff --git a/.gitlab/ci/jobs/packaging/opam_package.yml b/.gitlab/ci/jobs/packaging/opam_package.yml index f50455001ddef42030c1f262708dbac17bc8c309..5db45cf6494c1985dc200696b9e59ea15c937e28 100644 --- a/.gitlab/ci/jobs/packaging/opam_package.yml +++ b/.gitlab/ci/jobs/packaging/opam_package.yml @@ -1367,6 +1367,8 @@ opam:tezos-sapling: variables: package: tezos-sapling +# Ignoring unreleased package tezos-sc-rollup-node-test. + opam:tezos-scoru-wasm: extends: - .opam_template diff --git a/dune-project b/dune-project index e696ed8ee53fa9d20cbfcaf6d94482f421638e9a..900301f7f2932efec79a70ac10534d5c53245abb 100644 --- a/dune-project +++ b/dune-project @@ -202,6 +202,7 @@ (package (name tezos-rpc-http-client-unix)) (package (name tezos-rpc-http-server)) (package (name tezos-sapling)) +(package (name tezos-sc-rollup-node-test)(allow_empty)) (package (name tezos-scoru-wasm)) (package (name tezos-scoru-wasm-durable-snapshot)(allow_empty)) (package (name tezos-scoru-wasm-fast)) diff --git a/manifest/main.ml b/manifest/main.ml index 50ec70a795e683c090562e7509fcc8ee5fd8eefc..ab8288be45db97b5200bc2d848988e670b72313e 100644 --- a/manifest/main.ml +++ b/manifest/main.ml @@ -5287,6 +5287,47 @@ module Protocol = Protocol octez_node_config |> if_ N.(number >= 016); ] in + let _octez_sc_rollup_node_test = + only_if N.(number >= 016) @@ fun () -> + let helpers = + private_lib + (sf "octez_smart_rollup_node_%s_test_helpers" short_hash) + ~path:(path // "lib_sc_rollup_node/test/helpers") + ~opam:"tezos-sc-rollup-node-test" + ~deps: + [ + octez_base |> open_ ~m:"TzPervasives" + |> open_ ~m:"TzPervasives.Error_monad.Legacy_monad_globals"; + main |> open_; + parameters |> if_some |> open_; + client |> if_some |> open_; + octez_test_helpers |> open_; + qcheck_alcotest; + qcheck_core; + logs_lwt; + octez_sc_rollup_layer2 |> if_some |> open_; + octez_sc_rollup_node |> if_some |> open_; + alcotezt; + ] + in + tezt + ["canary"] + ~path:(path // "lib_sc_rollup_node/test") + ~opam:"tezos-sc-rollup-node-test" + ~synopsis:"Tests for the smart rollup node library" + ~with_macos_security_framework:true + ~deps: + [ + octez_base |> open_ ~m:"TzPervasives" + |> open_ ~m:"TzPervasives.Error_monad.Legacy_monad_globals"; + main |> open_; + octez_test_helpers |> open_; + octez_sc_rollup_layer2 |> if_some |> open_; + octez_sc_rollup_node |> if_some |> open_; + alcotezt; + helpers |> open_; + ] + in let octez_sc_rollup_client = only_if (active && N.(number >= 016)) @@ fun () -> private_lib diff --git a/opam/tezos-sc-rollup-node-test.opam b/opam/tezos-sc-rollup-node-test.opam new file mode 100644 index 0000000000000000000000000000000000000000..e94634bce32043b5e40b6da5796bf72375b02029 --- /dev/null +++ b/opam/tezos-sc-rollup-node-test.opam @@ -0,0 +1,35 @@ +# This file was automatically generated, do not edit. +# Edit file manifest/main.ml instead. +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" { >= "3.0" } + "ocaml" { >= "4.14" } + "tezos-base" + "tezos-protocol-016-PtMumbai" + "tezos-client-016-PtMumbai" + "tezos-test-helpers" + "qcheck-alcotest" { >= "0.20" } + "qcheck-core" + "logs" + "tezos-smart-rollup-layer2-016-PtMumbai" + "octez-smart-rollup-node-PtMumbai" + "octez-alcotezt" + "tezos-protocol-alpha" + "tezos-client-alpha" + "tezos-smart-rollup-layer2-alpha" + "octez-smart-rollup-node-alpha" + "tezt" { with-test & >= "3.0.0" } +] +build: [ + ["rm" "-r" "vendors"] + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} + ["dune" "build" "@runtezt" "-p" name "-j" jobs] {with-test} +] +synopsis: "Tests for the smart rollup node library" diff --git a/src/lib_crawler/layer_1.ml b/src/lib_crawler/layer_1.ml index 70a128dec8325bca4d085d1151b4f6440337568e..2431fc7d5eb08a2057457f78925e74bdd7e93af9 100644 --- a/src/lib_crawler/layer_1.ml +++ b/src/lib_crawler/layer_1.ml @@ -308,3 +308,16 @@ let get_tezos_reorg_for_new_head l1_state ?get_old_predecessor old_head new_head ?get_old_predecessor old_head new_head + +module Internal_for_tests = struct + let dummy cctxt = + let heads, _push = Lwt_stream.create () in + { + name = "dummy_layer_1_for_tests"; + reconnection_delay = 5.0; + heads; + cctxt = (cctxt :> Client_context.full); + stopper = Fun.id; + running = false; + } +end diff --git a/src/lib_crawler/layer_1.mli b/src/lib_crawler/layer_1.mli index e03581a8734d54af6c86ab7ed45882b6dc373491..8477675383406f966c36cb0d8219d9889a64e967 100644 --- a/src/lib_crawler/layer_1.mli +++ b/src/lib_crawler/layer_1.mli @@ -93,3 +93,12 @@ val get_tezos_reorg_for_new_head : [`Head of Block_hash.t * int32 | `Level of int32] -> Block_hash.t * int32 -> (Block_hash.t * int32) Reorg.t tzresult Lwt.t + +(**/**) + +module Internal_for_tests : sig + (** Create a dummy Layer 1 object that does not follow any L1 chain. This + function is only to be used as a placeholder for unit tests (that do not + exercise the Layer 1 connection). *) + val dummy : #Client_context.full -> t +end diff --git a/src/lib_injector/injector_events.ml b/src/lib_injector/injector_events.ml index ff6ff1062819155ff3fc2a4850fbbb7eeb7b6098..a9ab5a36ea124c3883f1dbe9076f60a8ea36cb84 100644 --- a/src/lib_injector/injector_events.ml +++ b/src/lib_injector/injector_events.ml @@ -35,7 +35,7 @@ module Make struct include Internal_event.Simple - let section = Parameters.events_section + let section = Parameters.events_section @ ["injector"] let monitoring_error = declare_1 diff --git a/src/lib_injector/injector_functor.ml b/src/lib_injector/injector_functor.ml index 729265213423d7d5ca85cae14edb2a8548178c5b..0c7b4492b4ef49e10d6c67cf5de6560a9bf43a5f 100644 --- a/src/lib_injector/injector_functor.ml +++ b/src/lib_injector/injector_functor.ml @@ -989,6 +989,18 @@ struct } end + module Name = struct + type t = Signature.public_key_hash + + let encoding = Signature.Public_key_hash.encoding + + let base = Parameters.events_section @ ["injector"] + + let pp = Signature.Public_key_hash.pp_short + + let equal = Signature.Public_key_hash.equal + end + (* The worker for the injector. *) module Worker = Worker.MakeSingle (Name) (Request) (Types) diff --git a/src/lib_injector/injector_worker_types.ml b/src/lib_injector/injector_worker_types.ml index bd4c61d94b9233f7d4cdf77cd3481c8bd59fb8a7..89aea4f0692624c56991d1becf11d90296212e1c 100644 --- a/src/lib_injector/injector_worker_types.ml +++ b/src/lib_injector/injector_worker_types.ml @@ -80,15 +80,3 @@ module Request (L1_operation : INJECTOR_OPERATION) = struct level | Inject -> Format.fprintf ppf "injection" end - -module Name = struct - type t = Signature.public_key_hash - - let encoding = Signature.Public_key_hash.encoding - - let base = ["injector"] - - let pp = Signature.Public_key_hash.pp_short - - let equal = Signature.Public_key_hash.equal -end diff --git a/src/lib_injector/injector_worker_types.mli b/src/lib_injector/injector_worker_types.mli index 829bf80376139f814f5f2b2e9591423d6df0208d..98f748fa813affa02f376b8f3607c57fbbd9f40e 100644 --- a/src/lib_injector/injector_worker_types.mli +++ b/src/lib_injector/injector_worker_types.mli @@ -39,5 +39,3 @@ module Request (Inj_operation : INJECTOR_OPERATION) : sig with type ('a, 'request_error) t := ('a, 'request_error) t and type view := view end - -module Name : Worker_intf.NAME with type t = Signature.public_key_hash diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/RPC_server.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/RPC_server.ml index 5912cfecb54afee61d6b3690093bc38844c55244..a72a534334a1aad6dfde09e2ec062bc8eca875a3 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/RPC_server.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/RPC_server.ml @@ -95,109 +95,111 @@ let get_dal_slot_page node_ctxt block slot_index slot_page = | None -> assert false | Some _contents -> return ("Slot page is available", contents_opt)) -module Global_directory = Make_directory (struct - include Sc_rollup_services.Global - - type context = Node_context.ro - - let context_of_prefix node_ctxt () = return (Node_context.readonly node_ctxt) -end) - -module Proof_helpers_directory = Make_directory (struct - include Sc_rollup_services.Global.Helpers - - (* The context needs to be accessed with write permissions because we need to - commit on disk to generate the proofs. *) - type context = Node_context.rw - - let context_of_prefix node_ctxt () = return node_ctxt -end) - -module Local_directory = Make_directory (struct - include Sc_rollup_services.Local - - type context = Node_context.ro +module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct + module PVM = Simulation.PVM + module Interpreter = Simulation.Interpreter + module Outbox = Outbox.Make (PVM) + module Free_pvm = Interpreter.Free_pvm - let context_of_prefix node_ctxt () = return (Node_context.readonly node_ctxt) -end) + module Global_directory = Make_directory (struct + include Sc_rollup_services.Global -module Block_directory = Make_directory (struct - include Sc_rollup_services.Global.Block + type context = Node_context.ro - type context = Node_context.ro * Block_hash.t + let context_of_prefix node_ctxt () = + return (Node_context.readonly node_ctxt) + end) - let context_of_prefix node_ctxt (((), block) : prefix) = - let open Lwt_result_syntax in - let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in - (Node_context.readonly node_ctxt, block) -end) + module Proof_helpers_directory = Make_directory (struct + include Sc_rollup_services.Global.Helpers -module Outbox_directory = Make_directory (struct - include Sc_rollup_services.Global.Block.Outbox + (* The context needs to be accessed with write permissions because we need to + commit on disk to generate the proofs. *) + type context = Node_context.rw - type context = Node_context.ro * Block_hash.t * Alpha_context.Raw_level.t + let context_of_prefix node_ctxt () = return node_ctxt + end) - let context_of_prefix node_ctxt (((), block), level) = - let open Lwt_result_syntax in - let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in - (Node_context.readonly node_ctxt, block, level) -end) + module Local_directory = Make_directory (struct + include Sc_rollup_services.Local -module Common = struct - let () = - Block_directory.register0 Sc_rollup_services.Global.Block.block - @@ fun (node_ctxt, block) () () -> - Node_context.get_full_l2_block node_ctxt block + type context = Node_context.ro - let () = - Block_directory.register0 Sc_rollup_services.Global.Block.num_messages - @@ fun (node_ctxt, block) () () -> - let open Lwt_result_syntax in - let* l2_block = Node_context.get_l2_block node_ctxt block in - let+ num_messages = - Node_context.get_num_messages node_ctxt l2_block.header.inbox_witness - in - Z.of_int num_messages + let context_of_prefix node_ctxt () = + return (Node_context.readonly node_ctxt) + end) - let () = - Global_directory.register0 Sc_rollup_services.Global.sc_rollup_address - @@ fun node_ctxt () () -> return @@ node_ctxt.rollup_address + module Block_directory = Make_directory (struct + include Sc_rollup_services.Global.Block - let () = - Global_directory.register0 Sc_rollup_services.Global.current_tezos_head - @@ fun node_ctxt () () -> get_head_hash_opt node_ctxt + type context = Node_context.ro * Block_hash.t - let () = - Global_directory.register0 Sc_rollup_services.Global.current_tezos_level - @@ fun node_ctxt () () -> get_head_level_opt node_ctxt + let context_of_prefix node_ctxt (((), block) : prefix) = + let open Lwt_result_syntax in + let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in + (Node_context.readonly node_ctxt, block) + end) - let () = - Block_directory.register0 Sc_rollup_services.Global.Block.hash - @@ fun (_node_ctxt, block) () () -> return block + module Outbox_directory = Make_directory (struct + include Sc_rollup_services.Global.Block.Outbox - let () = - Block_directory.register0 Sc_rollup_services.Global.Block.level - @@ fun (node_ctxt, block) () () -> - Node_context.level_of_hash node_ctxt block + type context = Node_context.ro * Block_hash.t * Alpha_context.Raw_level.t - let () = - Block_directory.register0 Sc_rollup_services.Global.Block.inbox - @@ fun (node_ctxt, block) () () -> - Node_context.get_inbox_by_block_hash node_ctxt block + let context_of_prefix node_ctxt (((), block), level) = + let open Lwt_result_syntax in + let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in + (Node_context.readonly node_ctxt, block, level) + end) - let () = - Block_directory.register0 Sc_rollup_services.Global.Block.ticks - @@ fun (node_ctxt, block) () () -> - let open Lwt_result_syntax in - let+ l2_block = Node_context.get_l2_block node_ctxt block in - Z.of_int64 l2_block.num_ticks -end + module Common = struct + let () = + Block_directory.register0 Sc_rollup_services.Global.Block.block + @@ fun (node_ctxt, block) () () -> + Node_context.get_full_l2_block node_ctxt block -module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct - module PVM = Simulation.PVM - module Interpreter = Simulation.Interpreter - module Outbox = Outbox.Make (PVM) - module Free_pvm = Interpreter.Free_pvm + let () = + Block_directory.register0 Sc_rollup_services.Global.Block.num_messages + @@ fun (node_ctxt, block) () () -> + let open Lwt_result_syntax in + let* l2_block = Node_context.get_l2_block node_ctxt block in + let+ num_messages = + Node_context.get_num_messages node_ctxt l2_block.header.inbox_witness + in + Z.of_int num_messages + + let () = + Global_directory.register0 Sc_rollup_services.Global.sc_rollup_address + @@ fun node_ctxt () () -> return @@ node_ctxt.rollup_address + + let () = + Global_directory.register0 Sc_rollup_services.Global.current_tezos_head + @@ fun node_ctxt () () -> get_head_hash_opt node_ctxt + + let () = + Global_directory.register0 Sc_rollup_services.Global.current_tezos_level + @@ fun node_ctxt () () -> get_head_level_opt node_ctxt + + let () = + Block_directory.register0 Sc_rollup_services.Global.Block.hash + @@ fun (_node_ctxt, block) () () -> return block + + let () = + Block_directory.register0 Sc_rollup_services.Global.Block.level + @@ fun (node_ctxt, block) () () -> + Node_context.level_of_hash node_ctxt block + + let () = + Block_directory.register0 Sc_rollup_services.Global.Block.inbox + @@ fun (node_ctxt, block) () () -> + Node_context.get_inbox_by_block_hash node_ctxt block + + let () = + Block_directory.register0 Sc_rollup_services.Global.Block.ticks + @@ fun (node_ctxt, block) () () -> + let open Lwt_result_syntax in + let+ l2_block = Node_context.get_l2_block node_ctxt block in + Z.of_int64 l2_block.num_ticks + end let get_state (node_ctxt : _ Node_context.t) block_hash = let open Lwt_result_syntax in diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher.ml index 84be3b4fa94e1fcfe18f22841737814ec79471ba..d45abd021e60d7f6535037faf5c57409626ed0dc 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher.ml @@ -34,6 +34,10 @@ end module Batched_messages = Hash_queue.Make (L2_message.Hash) (L2_batched_message) +(* Count instances of the batcher functor to allow for multiple worker events + without conflicts. *) +let instances_count = ref 0 + module type S = sig type status = Pending_batch | Batched of Injector.Inj_operation.hash @@ -61,6 +65,8 @@ module type S = sig end module Make (Simulation : Simulation.S) : S = struct + let () = incr instances_count + module PVM = Simulation.PVM type status = Pending_batch | Batched of Injector.Inj_operation.hash @@ -265,6 +271,27 @@ module Make (Simulation : Simulation.S) : S = struct } end + module Name = struct + (* We only have a single batcher in the node *) + type t = unit + + let encoding = Data_encoding.unit + + let base = + (* But we can have multiple instances in the unit tests. This is just to + avoid conflicts in the events declarations. *) + Batcher_events.Worker.section + @ [ + ("worker" + ^ if !instances_count = 1 then "" else string_of_int !instances_count + ); + ] + + let pp _ _ = () + + let equal () () = true + end + module Worker = Worker.MakeSingle (Name) (Request) (Types) type worker = Worker.infinite Worker.queue Worker.t diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher_events.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher_events.ml index 5d0ad969a3c0da23d93734f372cf308640a24fba..da9ad33fa984124015ca8c1663e77cd5c9bedee5 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher_events.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher_events.ml @@ -25,7 +25,7 @@ include Internal_event.Simple -let section = ["sc_rollup_node"; "batcher"] +let section = [Protocol.name; "sc_rollup_node"; "batcher"] let queue = declare_1 diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher_worker_types.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher_worker_types.ml index 63afd1221a6d1ae3d50f9817e382cab7229aeafa..c0fe7350814c9ede1c17f9c55265cdb6e075447f 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher_worker_types.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher_worker_types.ml @@ -75,16 +75,3 @@ module Request = struct level | Batch -> Format.pp_print_string ppf "batch" end - -module Name = struct - (* We only have a single batcher right now *) - type t = unit - - let encoding = Data_encoding.unit - - let base = ["sc_rollup_batcher"] - - let pp _ _ = () - - let equal () () = true -end diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher_worker_types.mli b/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher_worker_types.mli index 681291fbd22f7c2aa45d1dc703f7f198f4b4d4d2..d3a3fd2c09e963cb9b9655a92c2d411893aa8343 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher_worker_types.mli +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher_worker_types.mli @@ -42,5 +42,3 @@ module Request : sig with type ('a, 'request_error) t := ('a, 'request_error) t and type view := view end - -module Name : Worker_intf.NAME with type t = unit diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment.ml index f1c09fefe9d21c0a5f589dccaa1fd709cacded25..237c288a0ba95874f9b40146bd79f885cdf0c329 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment.ml @@ -81,7 +81,13 @@ let sc_rollup_challenge_window node_ctxt = let next_commitment_level node_ctxt last_commitment_level = add_level last_commitment_level (sc_rollup_commitment_period node_ctxt) +(* Count instances of the commitment functor to allow for multiple worker events + without conflicts. *) +let instances_count = ref 0 + module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct + let () = incr instances_count + module PVM = PVM type state = Node_context.ro @@ -406,6 +412,28 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct type parameters = {node_ctxt : Node_context.ro} end + module Name = struct + (* We only have a single committer in the node *) + type t = unit + + let encoding = Data_encoding.unit + + let base = + (* But we can have multiple instances in the unit tests. This is just to + avoid conflicts in the events declarations. *) + Commitment_event.section + @ [ + ("publisher" + ^ + if !instances_count = 1 then "" else string_of_int !instances_count + ); + ] + + let pp _ _ = () + + let equal () () = true + end + module Worker = Worker.MakeSingle (Name) (Request) (Types) type worker = Worker.infinite Worker.queue Worker.t diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment_event.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment_event.ml index 7f9135d2792a16f0a870196cad9942a9f5fc33e8..e5d62ef4337c738934ab3f3975eb9d582a244452 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment_event.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment_event.ml @@ -30,7 +30,7 @@ open Publisher_worker_types module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "commitment"] + let section = [Protocol.name; "sc_rollup_node"; "commitment"] let starting = declare_0 @@ -157,6 +157,8 @@ let stopping = Simple.(emit stopping) open Sc_rollup.Commitment +let section = Simple.section + let emit_commitment_event f commitment_hash {predecessor; inbox_level; compressed_state; number_of_ticks} = Simple.( diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment_event.mli b/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment_event.mli index 8f4baf9b0e14b40ddcdbd621c2aa831741bd4f9f..6f583d61cc72d497a7671cda2dccb1f0055215d6 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment_event.mli +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment_event.mli @@ -33,6 +33,9 @@ val starting : unit -> unit Lwt.t val stopping : unit -> unit Lwt.t +(** Section for commitment events. *) +val section : string list + (** [commitment_stored commitment_hash commitment] emits the event that the [commitment] was stored. *) val commitment_stored : diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/daemon.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/daemon.ml index 9f067c83c4a4154f1d852c84713af9471e53b2a7..e52d3e6bed119a88262e46ed4f61e9e6dc7c585e 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/daemon.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/daemon.ml @@ -572,6 +572,67 @@ module Make (PVM : Pvm.S) = struct Format.eprintf "%!%a@.Exiting.@." pp_print_trace e ; let*! _ = Lwt_exit.exit_and_wait 1 in return_unit) + + module Internal_for_tests = struct + (** Same as {!process_head} but only builds and stores the L2 block + corresponding to [messages]. It is used by the unit tests to build an L2 + chain. *) + let process_messages (node_ctxt : _ Node_context.t) ~predecessor + ~predecessor_timestamp head messages = + let open Lwt_result_syntax in + let* () = Node_context.save_level node_ctxt head in + let* inbox_hash, inbox, inbox_witness, messages, ctxt = + Inbox.Internal_for_tests.process_messages + node_ctxt + ~predecessor + ~predecessor_timestamp + ~level:head.level + messages + in + let* ctxt, _num_messages, num_ticks, initial_tick = + Components.Interpreter.process_head + node_ctxt + ctxt + ~predecessor + head + (inbox, messages) + in + let*! context_hash = Context.commit ctxt in + let* commitment_hash = + Components.Commitment.process_head + node_ctxt + ~predecessor:predecessor.Layer1.hash + head + ctxt + in + let level = Raw_level.of_int32_exn head.level in + let* previous_commitment_hash = + if level = node_ctxt.genesis_info.Sc_rollup.Commitment.level then + (* Previous commitment for rollup genesis is itself. *) + return node_ctxt.genesis_info.Sc_rollup.Commitment.commitment_hash + else + let+ pred = Node_context.get_l2_block node_ctxt predecessor.hash in + Sc_rollup_block.most_recent_commitment pred.header + in + let header = + Sc_rollup_block. + { + block_hash = head.hash; + level; + predecessor = predecessor.hash; + commitment_hash; + previous_commitment_hash; + context = context_hash; + inbox_witness; + inbox_hash; + } + in + let l2_block = + Sc_rollup_block.{header; content = (); num_ticks; initial_tick} + in + let* () = Node_context.save_l2_head node_ctxt l2_block in + return l2_block + end end let run ~data_dir (configuration : Configuration.t) diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/daemon_event.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/daemon_event.ml index cf8b076f59f2a5dde499bb2c03707fc101fc700f..73d701430da0bff4474dd2ebc6b41cac8de8d3de 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/daemon_event.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/daemon_event.ml @@ -26,7 +26,7 @@ module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "daemon"] + let section = [Protocol.name; "sc_rollup_node"; "daemon"] let head_processing = declare_3 diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/dal_pages_request.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/dal_pages_request.ml index 03d79c17ef343397ad38bfd89bd56dae78e783ce..0e0e11aae1ecd0d78a5a36fc15a732d4bab6d1fc 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/dal_pages_request.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/dal_pages_request.ml @@ -38,7 +38,7 @@ type error += | Dal_invalid_page_for_slot of Dal.Page.t let () = - register_error_kind + Sc_rollup_node_errors.register_error_kind `Permanent ~id:"dal_pages_request.dal_slot_not_found_in_store" ~title:"Dal slot not found in store" @@ -48,7 +48,7 @@ let () = Data_encoding.(obj1 (req "slot_id" Dal.Slot.Header.id_encoding)) (function Dal_slot_not_found_in_store slot_id -> Some slot_id | _ -> None) (fun slot_id -> Dal_slot_not_found_in_store slot_id) ; - register_error_kind + Sc_rollup_node_errors.register_error_kind `Permanent ~id:"dal_pages_request.dal_invalid_page_for_slot" ~title:"Invalid Dal page requested for slot" diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/dal_slots_tracker_event.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/dal_slots_tracker_event.ml index 84ed4506c47f31ccd7ce935589470a5057a2ff8c..05620638edb998237635252ebe5799f9fb3e1013 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/dal_slots_tracker_event.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/dal_slots_tracker_event.ml @@ -29,7 +29,7 @@ open Alpha_context module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "dal_slots_tracker"] + let section = [Protocol.name; "sc_rollup_node"; "dal_slots_tracker"] let slot_has_been_confirmed = declare_3 diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/event.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/event.ml index ce5d693db33d04a45d73ec101bebe0051a28bde2..ea2fa9aaa35ec021ba3f29b197e53dca08917f47 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/event.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/event.ml @@ -26,7 +26,7 @@ module Simple = struct include Internal_event.Simple - let section = ["smart_rollup_node"] + let section = [Protocol.name; "smart_rollup_node"] let starting_node = declare_0 diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/inbox.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/inbox.ml index e788af5f0d550f289876f366d56bac152667540a..be94f89f5e69353a4805ff484e59b4a5998a4adf 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/inbox.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/inbox.ml @@ -120,6 +120,46 @@ let add_messages ~predecessor_timestamp ~predecessor inbox messages = inbox, messages_with_protocol_internal_messages ) +let process_messages (node_ctxt : _ Node_context.t) ~predecessor + ~predecessor_timestamp ~level messages = + let open Lwt_result_syntax in + let* inbox = Node_context.inbox_of_head node_ctxt predecessor in + let inbox_metrics = Metrics.Inbox.metrics in + Prometheus.Gauge.set inbox_metrics.head_inbox_level @@ Int32.to_float level ; + let*? level = Environment.wrap_tzresult @@ Raw_level.of_int32 level in + let* ctxt = + if Raw_level.(level <= node_ctxt.Node_context.genesis_info.level) then + (* This is before we have interpreted the boot sector, so we start + with an empty context in genesis *) + return (Context.empty node_ctxt.context) + else Node_context.checkout_context node_ctxt predecessor.hash + in + let* ( _messages_history, + witness_hash, + inbox, + messages_with_protocol_internal_messages ) = + add_messages + ~predecessor_timestamp + ~predecessor:predecessor.hash + inbox + messages + in + Metrics.Inbox.Stats.head_messages_list := + messages_with_protocol_internal_messages ; + let* () = + Node_context.save_messages + node_ctxt + witness_hash + {predecessor = predecessor.hash; predecessor_timestamp; messages} + in + let* inbox_hash = Node_context.save_inbox node_ctxt inbox in + return + ( inbox_hash, + inbox, + witness_hash, + messages_with_protocol_internal_messages, + ctxt ) + let process_head (node_ctxt : _ Node_context.t) ~predecessor Layer1.{level; hash = head_hash} = let open Lwt_result_syntax in @@ -127,63 +167,30 @@ let process_head (node_ctxt : _ Node_context.t) ~predecessor Raw_level.to_int32 node_ctxt.genesis_info.level |> Int32.succ in if level >= first_inbox_level then ( - (* - - We compute the inbox of this block using the inbox of its - predecessor. That way, the computation of inboxes is robust - to chain reorganization. - - *) - let* inbox = Node_context.inbox_of_head node_ctxt predecessor in - let inbox_metrics = Metrics.Inbox.metrics in - Prometheus.Gauge.set inbox_metrics.head_inbox_level @@ Int32.to_float level ; - let*? level = Environment.wrap_tzresult @@ Raw_level.of_int32 level in - let* ctxt = - if Raw_level.(level <= node_ctxt.Node_context.genesis_info.level) then - (* This is before we have interpreted the boot sector, so we start - with an empty context in genesis *) - return (Context.empty node_ctxt.context) - else Node_context.checkout_context node_ctxt predecessor.hash - in + (* We compute the inbox of this block using the inbox of its + predecessor. That way, the computation of inboxes is robust to chain + reorganization. *) let* collected_messages, predecessor_timestamp, predecessor_hash = get_messages node_ctxt head_hash in + assert (Block_hash.(predecessor.Layer1.hash = predecessor_hash)) ; let*! () = - Inbox_event.get_messages - head_hash - (Raw_level.to_int32 level) - (List.length collected_messages) + Inbox_event.get_messages head_hash level (List.length collected_messages) in - let* ( _messages_history, - witness_hash, - inbox, - messages_with_protocol_internal_messages ) = - add_messages + let* (( _inbox_hash, + inbox, + _witness_hash, + _messages_with_protocol_internal_messages, + _ctxt ) as res) = + process_messages + node_ctxt + ~predecessor ~predecessor_timestamp - ~predecessor:predecessor_hash - inbox + ~level collected_messages in - Metrics.Inbox.Stats.head_messages_list := - messages_with_protocol_internal_messages ; - let* () = - Node_context.save_messages - node_ctxt - witness_hash - { - predecessor = predecessor_hash; - predecessor_timestamp; - messages = collected_messages; - } - in let* () = same_inbox_as_layer_1 node_ctxt head_hash inbox in - let* inbox_hash = Node_context.save_inbox node_ctxt inbox in - return - ( inbox_hash, - inbox, - witness_hash, - messages_with_protocol_internal_messages, - ctxt )) + return res) else let* inbox = Node_context.genesis_inbox node_ctxt in return @@ -218,3 +225,7 @@ let payloads_history_of_messages ~predecessor ~predecessor_timestamp messages = messages in payloads_history + +module Internal_for_tests = struct + let process_messages = process_messages +end diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/inbox.mli b/src/proto_016_PtMumbai/lib_sc_rollup_node/inbox.mli index b078741d65da8da37bb05efa8aa77558e9586255..3fd50275e5d76c8db5bc2165637b4d0c03f32a00 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/inbox.mli +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/inbox.mli @@ -78,3 +78,21 @@ val payloads_history_of_messages : predecessor_timestamp:Timestamp.time -> Sc_rollup.Inbox_message.t list -> Sc_rollup.Inbox_merkelized_payload_hashes.History.t tzresult + +(**/**) + +module Internal_for_tests : sig + val process_messages : + Node_context.rw -> + predecessor:Layer1.head -> + predecessor_timestamp:Timestamp.time -> + level:int32 -> + Sc_rollup.Inbox_message.t list -> + (Sc_rollup.Inbox.Hash.t + * Sc_rollup.Inbox.t + * Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t + * Sc_rollup.Inbox_message.t list + * Context.rw) + tzresult + Lwt.t +end diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/inbox_event.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/inbox_event.ml index 18d83fc56dcdd5113fdf528aa536bbcb4fe3aef7..ed732319c4dc66f38a24f3053bc5e2f3dc32bb8f 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/inbox_event.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/inbox_event.ml @@ -26,7 +26,7 @@ module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "inbox"] + let section = [Protocol.name; "sc_rollup_node"; "inbox"] let starting = declare_0 diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/injector.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/injector.ml index 3f4a3648e8fd7730254f0cd56d7b28ba99c542a6..1431139541d59059b31365f35d005ba0e69758ac 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/injector.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/injector.ml @@ -37,7 +37,7 @@ module Parameters : and type Operation.t = L1_operation.t = struct type state = Node_context.ro - let events_section = ["sc_rollup.injector"] + let events_section = [Protocol.name; "sc_rollup_node"] module Tag : TAG with type t = Configuration.purpose = struct type t = Configuration.purpose diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/interpreter.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/interpreter.ml index 41301dd9a88da1e2f46889afe42a37ab57240788..47833d8e42572c9eaa847d9034991471360e46d5 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/interpreter.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/interpreter.ml @@ -119,15 +119,15 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct let state_of_head node_ctxt ctxt Layer1.{hash; level} = let open Lwt_result_syntax in - let genesis_level = - Raw_level.to_int32 node_ctxt.Node_context.genesis_info.level - in - if level = genesis_level then genesis_state hash node_ctxt ctxt - else - let*! state = PVM.State.find ctxt in - match state with - | None -> tzfail (Sc_rollup_node_errors.Missing_PVM_state (hash, level)) - | Some state -> return (ctxt, state) + let*! state = PVM.State.find ctxt in + match state with + | None -> + let genesis_level = + Raw_level.to_int32 node_ctxt.Node_context.genesis_info.level + in + if level = genesis_level then genesis_state hash node_ctxt ctxt + else tzfail (Sc_rollup_node_errors.Missing_PVM_state (hash, level)) + | Some state -> return (ctxt, state) (** [transition_pvm node_ctxt predecessor head] runs a PVM at the previous state from block [predecessor] by consuming as many messages diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/interpreter_event.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/interpreter_event.ml index ffc016b9123b695c0084c840b202617a92dede29..80fab8ac3274387359c9aad5045bc31948f183af 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/interpreter_event.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/interpreter_event.ml @@ -28,7 +28,7 @@ open Protocol.Alpha_context.Sc_rollup module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "interpreter"] + let section = [Protocol.name; "sc_rollup_node"; "interpreter"] let transitioned_pvm = declare_4 diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/layer1.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/layer1.ml index 0c515602b8c258546bf1c156b0b6b6d2ae7bb263..fe5776cb19d136698ca62c3ce2adf3d88db1e895 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/layer1.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/layer1.ml @@ -36,7 +36,7 @@ open Protocol_client_context type error += Cannot_find_block of Block_hash.t let () = - register_error_kind + Sc_rollup_node_errors.register_error_kind ~id:"sc_rollup.node.cannot_find_block" ~title:"Cannot find block from L1" ~description:"A block couldn't be found from the L1 node" diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/layer1_event.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/layer1_event.ml index 6e9773d48ec283c97c84cddab6fbdbe083b59434..6a0987632b05f33897697fb843de8c909db21eb6 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/layer1_event.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/layer1_event.ml @@ -26,7 +26,7 @@ module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "layer_1"] + let section = [Protocol.name; "sc_rollup_node"; "layer_1"] let starting = declare_0 diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/node_context.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/node_context.ml index d2692f61778ae6db33b139893d143bba167a3d4d..857ea7d48258abacc1542dc983f644f5195b55aa 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/node_context.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/node_context.ml @@ -732,3 +732,57 @@ let find_confirmed_slots_histories {store; _} = let save_confirmed_slots_histories {store; _} = Store.Dal_confirmed_slots_histories.add store.irmin_store + +module Internal_for_tests = struct + let create_node_context cctxt + ?(constants = Default_parameters.constants_mainnet) ~data_dir kind = + let open Lwt_result_syntax in + let l2_blocks_cache_size = Configuration.default_l2_blocks_cache_size in + let protocol_constants = + constants + |> Data_encoding.Binary.to_bytes_exn Constants.Parametric.encoding + |> Data_encoding.Binary.of_bytes_exn Constants_parametric_repr.encoding + |> Constants_repr.all_of_parametric + |> Data_encoding.Binary.to_bytes_exn Constants_repr.encoding + |> Data_encoding.Binary.of_bytes_exn Constants.encoding + in + let* store = + Store.load + Read_write + ~l2_blocks_cache_size + Configuration.(default_storage_dir data_dir) + in + let*! context = + Context.load Read_write (Configuration.default_context_dir data_dir) + in + let genesis_info = + Sc_rollup.Commitment.{level = Raw_level.root; commitment_hash = Hash.zero} + in + let l1_ctxt = Layer1.Internal_for_tests.dummy cctxt in + let lcc = + Reference.new_ + {commitment = Sc_rollup.Commitment.Hash.zero; level = Raw_level.root} + in + let lpc = Reference.new_ None in + return + { + cctxt; + dal_cctxt = None; + data_dir; + l1_ctxt; + rollup_address = Sc_rollup.Address.zero; + mode = Observer; + operators = Configuration.Operator_purpose_map.empty; + genesis_info; + lcc; + lpc; + kind; + injector_retention_period = 0; + block_finality_time = 2; + fee_parameters = Configuration.default_fee_parameters; + protocol_constants; + loser_mode = Loser_mode.no_failures; + store; + context; + } +end diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/node_context.mli b/src/proto_016_PtMumbai/lib_sc_rollup_node/node_context.mli index 4016ced93b150e36099eaea93d2c8c792d73dc9b..03fb62b860c40eda2747ca3d982327df7a5a6add 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/node_context.mli +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/node_context.mli @@ -439,3 +439,17 @@ val find_confirmed_slots_histories : val save_confirmed_slots_histories : rw -> Block_hash.t -> Dal.Slots_history.History_cache.t -> unit tzresult Lwt.t + +(**/**) + +module Internal_for_tests : sig + (** Create a node context which really stores data on disk but does not + connect to any layer 1 node. It is meant to be used in unit tests for the + rollup node functions. *) + val create_node_context : + Protocol_client_context.full -> + ?constants:Constants.Parametric.t -> + data_dir:string -> + Sc_rollup.Kind.t -> + Store_sigs.rw t tzresult Lwt.t +end diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/publisher_worker_types.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/publisher_worker_types.ml index 2ae31036e3105f7f5d6362c9eabedfd48b18bc7c..c10e697273e3a27772ce298eb43d33c53dde9db5 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/publisher_worker_types.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/publisher_worker_types.ml @@ -55,16 +55,3 @@ module Request = struct | Publish -> Format.pp_print_string ppf "publish" | Cement -> Format.pp_print_string ppf "cement" end - -module Name = struct - (* We only have a single commitment publisher right now *) - type t = unit - - let encoding = Data_encoding.unit - - let base = ["sc_rollup_commitment_publisher"] - - let pp _ _ = () - - let equal () () = true -end diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/publisher_worker_types.mli b/src/proto_016_PtMumbai/lib_sc_rollup_node/publisher_worker_types.mli index ab244e31a486323c889645a1a1a44aa815eeb797..eed1fdcad468e10c17c8bb15d651c24ab699ee0c 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/publisher_worker_types.mli +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/publisher_worker_types.mli @@ -38,5 +38,3 @@ module Request : sig with type ('a, 'request_error) t := ('a, 'request_error) t and type view := view end - -module Name : Worker_intf.NAME with type t = unit diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game_event.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game_event.ml index dc873b95d4671d1fa2f73b35291697bed20a761b..f894e7e199ddad909e5859293002147c26775123 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game_event.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game_event.ml @@ -31,7 +31,7 @@ open Protocol.Alpha_context module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "refutation_game"] + let section = [Protocol.name; "sc_rollup_node"; "refutation_game"] let timeout = declare_1 @@ -86,6 +86,7 @@ module Simple = struct let timeout_detected = declare_1 + ~section ~name:"sc_rollup_node_timeout_detected" ~msg: "The rollup node has detected that opponent {other} can be timed out." diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/reveals.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/reveals.ml index a414b71145109b9401f5d1b6bb767637aed5814e..696f4de9d06eaa57c8d1ddd6c9000a6c6bb6af77 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/reveals.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/reveals.ml @@ -32,7 +32,7 @@ type error += | Could_not_encode_raw_data let () = - register_error_kind + Sc_rollup_node_errors.register_error_kind ~id:"sc_rollup.node.wrong_hash_of_reveal_preimage" ~title:"Hash of reveal preimage is not correct" ~description:"Hash of reveal preimage is not correct." @@ -52,7 +52,7 @@ let () = (function | Wrong_hash {found; expected} -> Some (found, expected) | _ -> None) (fun (found, expected) -> Wrong_hash {found; expected}) ; - register_error_kind + Sc_rollup_node_errors.register_error_kind ~id:"sc_rollup.node.could_not_open_reveal_preimage_file" ~title:"Could not open reveal preimage file" ~description:"Could not open reveal preimage file." @@ -66,7 +66,7 @@ let () = (function | Could_not_open_preimage_file filename -> Some filename | _ -> None) (fun filename -> Could_not_open_preimage_file filename) ; - register_error_kind + Sc_rollup_node_errors.register_error_kind ~id:"sc_rollup.node.could_not_encode_raw_data" ~title:"Could not encode raw data to reveal" ~description:"Could not encode raw data to reveal." diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/sc_rollup_node_errors.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/sc_rollup_node_errors.ml index c2b5d2a399469978bc5d8c776637d9e909043b3a..fb10fab765cfe60fb64a3d387e32e85bd94c4021 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/sc_rollup_node_errors.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/sc_rollup_node_errors.ml @@ -25,6 +25,10 @@ open Protocol.Alpha_context +let make_id id = String.concat "." [Protocol.name; id] + +let register_error_kind ~id = register_error_kind ~id:(make_id id) + type error += | Cannot_produce_proof of Sc_rollup.Inbox.t * Raw_level.t | Missing_mode_operators of {mode : string; missing_operators : string list} diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/test/canary.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/test/canary.ml new file mode 100644 index 0000000000000000000000000000000000000000..ccbf80edb15fe806370103ed6c67152fc87b07c6 --- /dev/null +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/test/canary.ml @@ -0,0 +1,102 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 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: Smart rollup node library + Invocation: dune exec src/proto_016_PtMumbai/lib_sc_rollup_node/test/main.exe \ + -- -f canary + Subject: Canary unit tests to make sure the test helpers work as intended +*) + +open Protocol.Alpha_context + +let build_chain node_ctxt ~genesis ~length = + let open Lwt_result_syntax in + let* blocks = Helpers.append_dummy_l2_chain node_ctxt ~length in + return (genesis :: blocks) + +let canary_test node_ctxt ~genesis = + let open Lwt_result_syntax in + let length = 100 in + let* chain = build_chain node_ctxt ~genesis ~length in + Assert.Int.equal + ~loc:__LOC__ + ~msg:"chain_length_ok" + (List.length chain) + (length + 1) ; + (* Checking that the chain matches what is stored *) + let* () = + List.iter_es + (fun (block : Sc_rollup_block.t) -> + let* store_block_by_hash = + Node_context.get_l2_block node_ctxt block.header.block_hash + in + let* store_block_by_level = + Node_context.get_l2_block_by_level + node_ctxt + (Raw_level.to_int32 block.header.level) + in + Helpers.Assert.L2_block.equal + ~loc:__LOC__ + ~msg:"stored_block_by_hash_ok" + store_block_by_hash + block ; + Helpers.Assert.L2_block.equal + ~loc:__LOC__ + ~msg:"stored_block_by_level_ok" + store_block_by_level + block ; + return_unit) + chain + in + let* head = Node_context.last_processed_head_opt node_ctxt in + let last = List.last_opt chain in + Helpers.Assert.L2_block.Option.equal + ~loc:__LOC__ + ~msg:"head_is_last_block" + head + last ; + return_unit + +let tests = + [ + Helpers.alcotest + "canary arith" + `Quick + Sc_rollup.Kind.Example_arith + ~boot_sector:"" + canary_test; + Helpers.alcotest + "canary wasm" + `Quick + Sc_rollup.Kind.Wasm_2_0_0 + ~boot_sector:"" + canary_test; + ] + +let () = + Alcotest_lwt.run "canary" [(Protocol.name ^ ": canary", tests)] + |> Lwt_main.run diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/test/dune b/src/proto_016_PtMumbai/lib_sc_rollup_node/test/dune new file mode 100644 index 0000000000000000000000000000000000000000..a8cd5803af889e2a62c6e7accae131c7936df1b2 --- /dev/null +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/test/dune @@ -0,0 +1,49 @@ +; This file was automatically generated, do not edit. +; Edit file manifest/main.ml instead. + +(library + (name src_proto_016_PtMumbai_lib_sc_rollup_node_test_tezt_lib) + (instrumentation (backend bisect_ppx)) + (libraries + tezt.core + tezos-base + tezos-protocol-016-PtMumbai + tezos-test-helpers + tezos-smart-rollup-layer2-016-PtMumbai + octez_smart_rollup_node_PtMumbai + octez-alcotezt + octez_smart_rollup_node_PtMumbai_test_helpers) + (library_flags (:standard -linkall)) + (flags + (:standard) + -open Tezt_core + -open Tezt_core.Base + -open Tezos_base.TzPervasives + -open Tezos_base.TzPervasives.Error_monad.Legacy_monad_globals + -open Tezos_protocol_016_PtMumbai + -open Tezos_test_helpers + -open Tezos_smart_rollup_layer2_016_PtMumbai + -open Octez_smart_rollup_node_PtMumbai + -open Octez_alcotezt + -open Octez_smart_rollup_node_PtMumbai_test_helpers) + (modules canary)) + +(executable + (name main) + (instrumentation (backend bisect_ppx --bisect-sigterm)) + (libraries + src_proto_016_PtMumbai_lib_sc_rollup_node_test_tezt_lib + tezt) + (link_flags + (:standard) + (:include %{workspace_root}/macos-link-flags.sexp)) + (modules main)) + +(rule + (alias runtezt) + (package tezos-sc-rollup-node-test) + (action (run %{dep:./main.exe}))) + +(rule + (targets main.ml) + (action (with-stdout-to %{targets} (echo "let () = Tezt.Test.run ()")))) diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/test/helpers/dune b/src/proto_016_PtMumbai/lib_sc_rollup_node/test/helpers/dune new file mode 100644 index 0000000000000000000000000000000000000000..66a1eb2e0087dd1bbfcf8813a9ac16167ed31bfa --- /dev/null +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/test/helpers/dune @@ -0,0 +1,30 @@ +; This file was automatically generated, do not edit. +; Edit file manifest/main.ml instead. + +(library + (name octez_smart_rollup_node_PtMumbai_test_helpers) + (package tezos-sc-rollup-node-test) + (instrumentation (backend bisect_ppx)) + (libraries + tezos-base + tezos-protocol-016-PtMumbai + tezos-protocol-016-PtMumbai.parameters + tezos-client-016-PtMumbai + tezos-test-helpers + qcheck-alcotest + qcheck-core + logs.lwt + tezos-smart-rollup-layer2-016-PtMumbai + octez_smart_rollup_node_PtMumbai + octez-alcotezt) + (flags + (:standard) + -open Tezos_base.TzPervasives + -open Tezos_base.TzPervasives.Error_monad.Legacy_monad_globals + -open Tezos_protocol_016_PtMumbai + -open Tezos_protocol_016_PtMumbai_parameters + -open Tezos_client_016_PtMumbai + -open Tezos_test_helpers + -open Tezos_smart_rollup_layer2_016_PtMumbai + -open Octez_smart_rollup_node_PtMumbai + -open Octez_alcotezt)) diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/test/helpers/faked_client_context.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/test/helpers/faked_client_context.ml new file mode 100644 index 0000000000000000000000000000000000000000..fdf0855af82755d2ec3d8b943116c4a4a3f0a531 --- /dev/null +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/test/helpers/faked_client_context.ml @@ -0,0 +1,172 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 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 client contexts that stores information (such as the + wallet, etc.) in memory and that cannot do RPCs but which can be used in + unit tests. + + It is largely taken from the mockup simulator of the baker. + *) + +open Tezos_client_base + +class dummy_prompter : Client_context.prompter = + object + method prompt : type a. (a, string tzresult) Client_context.lwt_format -> a + = + fun _msg -> assert false + + method prompt_password : type a. + (a, Bytes.t tzresult) Client_context.lwt_format -> a = + fun _msg -> assert false + + method multiple_password_retries = false + end + +class faked_ctxt : Tezos_rpc.Context.generic = + let local_ctxt = + Tezos_mockup_proxy.RPC_client.local_ctxt Tezos_rpc.Directory.empty + in + object + method base = local_ctxt#base + + method generic_media_type_call meth ?body uri = + local_ctxt#generic_media_type_call meth ?body uri + + method call_service + : 'm 'p 'q 'i 'o. + (([< Resto.meth] as 'm), unit, 'p, 'q, 'i, 'o) Tezos_rpc.Service.t -> + 'p -> + 'q -> + 'i -> + 'o tzresult Lwt.t = + fun service params query body -> + local_ctxt#call_service service params query body + + method call_streamed_service + : 'm 'p 'q 'i 'o. + (([< Resto.meth] as 'm), unit, 'p, 'q, 'i, 'o) Tezos_rpc.Service.t -> + on_chunk:('o -> unit) -> + on_close:(unit -> unit) -> + 'p -> + 'q -> + 'i -> + (unit -> unit) tzresult Lwt.t = + fun service ~on_chunk ~on_close params query body -> + local_ctxt#call_streamed_service + service + ~on_chunk + ~on_close + params + query + body + end + +class faked_wallet ~base_dir ~filesystem : Client_context.wallet = + object (self) + method load_passwords = None + + method read_file fname = + match String.Hashtbl.find filesystem fname with + | None -> failwith "faked_wallet: cannot read file (%s)" fname + | Some (content, _mtime) -> return content + + method private filename alias_name = + Filename.concat + base_dir + (String.map (function ' ' -> '_' | c -> c) alias_name ^ "s") + + val lock_mutex = Lwt_mutex.create () + + method with_lock : type a. (unit -> a Lwt.t) -> a Lwt.t = + fun f -> Lwt_mutex.with_lock lock_mutex f + + method get_base_dir = base_dir + + method load : type a. + string -> default:a -> a Data_encoding.encoding -> a tzresult Lwt.t = + fun alias_name ~default encoding -> + let filename = self#filename alias_name in + if not (String.Hashtbl.mem filesystem filename) then return default + else + self#read_file filename >>=? fun content -> + let json = (Ezjsonm.from_string content :> Data_encoding.json) in + match Data_encoding.Json.destruct encoding json with + | exception e -> + failwith + "did not understand the %s alias file %s : %s" + alias_name + filename + (Printexc.to_string e) + | data -> return data + + method write : type a. + string -> a -> a Data_encoding.encoding -> unit tzresult Lwt.t = + fun alias_name list encoding -> + let filename = self#filename alias_name in + let json = Data_encoding.Json.construct encoding list in + let str = Ezjsonm.value_to_string (json :> Ezjsonm.value) in + String.Hashtbl.replace + filesystem + filename + (str, Some (Ptime.to_float_s (Ptime_clock.now ()))) ; + return_unit + + method last_modification_time : string -> float option tzresult Lwt.t = + let open Lwt_result_syntax in + fun alias_name -> + let filename = self#filename alias_name in + let file = String.Hashtbl.find_opt filesystem filename in + match file with + | None -> return_none + | Some (_content, mtime) -> return mtime + end + +class faked_io_wallet ~base_dir ~filesystem : Client_context.io_wallet = + let log _channel msg = Logs_lwt.info (fun m -> m "%s" msg) in + object + inherit Client_context.simple_printer log + + inherit dummy_prompter + + inherit faked_wallet ~base_dir ~filesystem + end + +class unix_faked ~base_dir ~filesystem : Client_context.full = + object + inherit faked_io_wallet ~base_dir ~filesystem + + inherit faked_ctxt + + inherit Tezos_client_base_unix.Client_context_unix.unix_ui + + method chain = `Main + + method block = `Head 0 + + method confirmations = None + + method verbose_rpc_error_diagnostics = false + end diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/test/helpers/helpers.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/test/helpers/helpers.ml new file mode 100644 index 0000000000000000000000000000000000000000..9fb935f54691d00a4805ffaa9542a0c4f4edc34d --- /dev/null +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/test/helpers/helpers.ml @@ -0,0 +1,283 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 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 + +let uid = ref 0 + +let block_hash_of_level level = + let s = Z.of_int32 level |> Z.to_bits in + let len = String.length s in + let s = + String.init Block_hash.size (fun i -> if i >= len then '\000' else s.[i]) + in + Block_hash.of_string_exn s + +module type S = sig + val with_node_context : + ?constants:Constants.Parametric.t -> + Sc_rollup.Kind.t -> + boot_sector:string -> + ([`Read | `Write] Node_context.t -> + genesis:Sc_rollup_block.t -> + 'a tzresult Lwt.t) -> + 'a tzresult Lwt.t + + val add_l2_genesis_block : + [`Read | `Write] Node_context.t -> + boot_sector:string -> + ((Sc_rollup_block.header, unit) Sc_rollup_block.block, tztrace) result Lwt.t + + val append_l2_block : + [`Read | `Write] Node_context.t -> + Sc_rollup.Inbox_message.t trace -> + ((Sc_rollup_block.header, unit) Sc_rollup_block.block, tztrace) result Lwt.t +end + +module Make (PVM : Pvm.S) = struct + module Daemon = Daemon.Make (PVM) + module Components = Daemon.Components + + let default_constants = + let constants = Default_parameters.constants_test in + let sc_rollup = + { + constants.sc_rollup with + arith_pvm_enable = true; + challenge_window_in_blocks = 4032; + commitment_period_in_blocks = 3; + } + in + {constants with sc_rollup} + + let add_l2_genesis_block (node_ctxt : _ Node_context.t) ~boot_sector = + let open Lwt_result_syntax in + let head = + Layer1. + { + hash = Block_hash.zero; + level = Raw_level.to_int32 node_ctxt.genesis_info.level; + } + in + let* () = Node_context.save_level node_ctxt head in + let predecessor = head in + let predecessor_timestamp = Time.Protocol.epoch in + let*? inbox = + Environment.wrap_tzresult + @@ Sc_rollup.Inbox.genesis + ~predecessor_timestamp + ~predecessor:predecessor.hash + node_ctxt.genesis_info.level + in + let* inbox_hash = Node_context.save_inbox node_ctxt inbox in + let inbox_witness = Sc_rollup.Inbox.current_witness inbox in + let ctxt = Context.empty node_ctxt.context in + let num_ticks = 0L in + let initial_tick = Sc_rollup.Tick.initial in + let*! initial_state = PVM.initial_state ~empty:(PVM.State.empty ()) in + let*! state = PVM.install_boot_sector initial_state boot_sector in + let*! genesis_state_hash = PVM.state_hash state in + let*! ctxt = PVM.State.set ctxt state in + let*! context_hash = Context.commit ctxt in + let commitment = + Sc_rollup.Commitment.genesis_commitment + ~origination_level:node_ctxt.genesis_info.level + ~genesis_state_hash + in + let* commitment_hash = Node_context.save_commitment node_ctxt commitment in + let previous_commitment_hash = node_ctxt.genesis_info.commitment_hash in + let header = + Sc_rollup_block. + { + block_hash = head.hash; + level = node_ctxt.genesis_info.level; + predecessor = predecessor.hash; + commitment_hash = Some commitment_hash; + previous_commitment_hash; + context = context_hash; + inbox_witness; + inbox_hash; + } + in + let l2_block = + Sc_rollup_block.{header; content = (); num_ticks; initial_tick} + in + let* () = Node_context.save_l2_head node_ctxt l2_block in + return l2_block + + let initialize_node_context ?(constants = default_constants) kind ~boot_sector + = + let open Lwt_result_syntax in + incr uid ; + (* To avoid any conflict with previous runs of this test. *) + let pid = Unix.getpid () in + let data_dir = + Filename.(concat @@ get_temp_dir_name ()) + (Format.sprintf "sc-rollup-node-test-%d-%d" pid !uid) + in + let base_dir = + Filename.(concat @@ get_temp_dir_name ()) + (Format.sprintf "sc-rollup-node-test-base-%d-%d" pid !uid) + in + let filesystem = String.Hashtbl.create 10 in + let cctxt = + new Protocol_client_context.wrap_full + (new Faked_client_context.unix_faked ~base_dir ~filesystem) + in + let* ctxt = + Node_context.Internal_for_tests.create_node_context + cctxt + ~constants + ~data_dir + kind + in + let* genesis = add_l2_genesis_block ctxt ~boot_sector in + let commitment_hash = + WithExceptions.Option.get ~loc:__LOC__ genesis.header.commitment_hash + in + let ctxt = + {ctxt with genesis_info = {ctxt.genesis_info with commitment_hash}} + in + return (ctxt, genesis) + + let with_node_context ?constants kind ~boot_sector f = + let open Lwt_result_syntax in + let* node_ctxt, genesis = + initialize_node_context ?constants kind ~boot_sector + in + Lwt.finalize (fun () -> f node_ctxt ~genesis) @@ fun () -> + let open Lwt_syntax in + let* _ = Node_context.close node_ctxt in + return_unit + + let append_l2_block (node_ctxt : _ Node_context.t) messages = + let open Lwt_result_syntax in + let* predecessor_l2_block = + Node_context.last_processed_head_opt node_ctxt + in + let* predecessor_l2_block = + match predecessor_l2_block with + | Some b -> return b + | None -> + failwith "No genesis block, please add one with add_l2_genesis_block" + in + let level = + Raw_level.(to_int32 @@ succ predecessor_l2_block.header.level) + in + let hash = block_hash_of_level level in + let predecessor = + Layer1. + { + hash = predecessor_l2_block.header.block_hash; + level = Raw_level.to_int32 predecessor_l2_block.header.level; + } + in + let head = Layer1.{hash; level} in + let predecessor_timestamp = + Time.Protocol.of_seconds (Int64.of_int32 level) + in + Daemon.Internal_for_tests.process_messages + node_ctxt + ~predecessor + ~predecessor_timestamp + head + messages +end + +let l2_chain_builders = + List.map + (fun kind -> + let module PVM = (val Components.pvm_of_kind kind) in + (kind, (module Make (PVM) : S))) + Sc_rollup.Kind.all + +let l2_chain_builder kind = Stdlib.List.assoc kind l2_chain_builders + +let with_node_context ?constants kind ~boot_sector = + let module L = (val l2_chain_builder kind) in + L.with_node_context ?constants kind ~boot_sector + +let add_l2_genesis_block (node_ctxt : _ Node_context.t) = + let module L = (val l2_chain_builder node_ctxt.kind) in + L.add_l2_genesis_block node_ctxt + +let append_l2_block (node_ctxt : _ Node_context.t) = + let module L = (val l2_chain_builder node_ctxt.kind) in + L.append_l2_block node_ctxt + +let append_l2_blocks node_ctxt message_batches = + List.map_es (append_l2_block node_ctxt) message_batches + +let append_dummy_l2_chain node_ctxt ~length = + let open Lwt_result_syntax in + let* head = Node_context.last_processed_head_opt node_ctxt in + let head_level = + match head with + | None -> 0 + | Some h -> h.header.level |> Raw_level.to_int32 |> Int32.to_int + in + let batches = + Stdlib.List.init length (fun i -> + [ + Sc_rollup.Inbox_message.External + (Z.to_bits (Z.of_int (i + head_level + 1))); + ]) + in + append_l2_blocks node_ctxt batches + +module Assert = struct + module Make_with_encoding (X : sig + type t + + val encoding : t Data_encoding.t + end) = + Assert.Make_equalities (struct + type t = X.t + + let eq (b1 : X.t) (b2 : X.t) = + Bytes.equal + (Data_encoding.Binary.to_bytes_exn X.encoding b1) + (Data_encoding.Binary.to_bytes_exn X.encoding b2) + + let pp ppf (b : X.t) = + Data_encoding.Json.pp ppf (Data_encoding.Json.construct X.encoding b) + end) + + module L2_block = Make_with_encoding (Sc_rollup_block) + module Commitment = Make_with_encoding (Sc_rollup.Commitment) + module Commitment_hash = Make_with_encoding (Sc_rollup.Commitment.Hash) + module State_hash = Make_with_encoding (Sc_rollup.State_hash) +end + +let alcotest name speed ?constants kind ~boot_sector f = + Alcotest_lwt.test_case name speed @@ fun _lwt_switch () -> + let open Lwt_result_syntax in + let*! r = with_node_context ?constants kind ~boot_sector f in + match r with + | Ok () -> Lwt.return_unit + | Error err -> + Format.printf "@\n%a@." pp_print_trace err ; + Lwt.fail Alcotest.Test_error diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/test/helpers/helpers.mli b/src/proto_016_PtMumbai/lib_sc_rollup_node/test/helpers/helpers.mli new file mode 100644 index 0000000000000000000000000000000000000000..04b986c0394cfeee62f8c01e74ad83457863ecc5 --- /dev/null +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/test/helpers/helpers.mli @@ -0,0 +1,115 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 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 + +(** {1 Helper functions to build and run unit tests for the rollup node} *) + +(** {2 Creating Node Contexts} *) + +(** [with_node_context ?constants kind ~boot_sector f] creates a node context + and (with a store, a context, etc.) where protocol [constants] can be + specified, and runs [f] with this node context. The L2 chain is initialized + with a genesis block and the PVM with the [boot_sector]. When [f] terminates + or fails, the created node context is closed properly. Test that need a node + context need to use this function in order to avoid file descriptor + leaks. *) +val with_node_context : + ?constants:Constants.Parametric.t -> + Sc_rollup.Kind.t -> + boot_sector:string -> + ([`Read | `Write] Node_context.t -> + genesis:Sc_rollup_block.t -> + 'a tzresult Lwt.t) -> + 'a tzresult Lwt.t + +(** {2 Building L2 Chains} *) + +(** Create and add a genesis block for the L2 chain. The [boot_sector] for the + rollup/kernel needs to be provided. The newly created L2 block is + returned. *) +val add_l2_genesis_block : + [`Read | `Write] Node_context.t -> + boot_sector:string -> + Sc_rollup_block.t tzresult Lwt.t + +(** [append_l2_block node_ctxt messages] creates and append + an L2 block containing the [messages] given in argument. The block is added + on top of the last L2 block in the chain (i.e. the head known by the node), + and is returned. *) +val append_l2_block : + [`Read | `Write] Node_context.t -> + Sc_rollup.Inbox_message.t list -> + Sc_rollup_block.t tzresult Lwt.t + +(** [append_l2_block node_ctxt message_batches] appends as many blocks as there + are batches in [message_batches]. Each block contain a batch of + messages. The portion of the chain that was added is returned. *) +val append_l2_blocks : + [`Read | `Write] Node_context.t -> + Sc_rollup.Inbox_message.t list list -> + Sc_rollup_block.t list tzresult Lwt.t + +(** [append_dummy_l2_chain node_ctxt ~length] append [length] L2 blocks with an + arbitrary content to the chain. The portion of the chain that was added is + returned. This function is useful for quickly building long(er) L2 chains + for the tests. *) +val append_dummy_l2_chain : + [`Read | `Write] Node_context.t -> + length:int -> + Sc_rollup_block.t list tzresult Lwt.t + +(** {2 Assertions} *) + +module Assert : sig + (** Assertions on L2 blocks *) + module L2_block : Assert.EQUALITIES with type t = Sc_rollup_block.t + + (** Assertions on commitments *) + module Commitment : Assert.EQUALITIES with type t = Sc_rollup.Commitment.t + + (** Assertions on commitment hashes *) + module Commitment_hash : + Assert.EQUALITIES with type t = Sc_rollup.Commitment.Hash.t + + (** Assertions on PVM state hashes *) + module State_hash : Assert.EQUALITIES with type t = Sc_rollup.State_hash.t +end + +(** {2 Building and Running tests} *) + +(** Build an alcotest test case that executes with node context initialized with + a genesis block with the provided [boot_sector]. *) +val alcotest : + string -> + Alcotest.speed_level -> + ?constants:Constants.Parametric.t -> + Sc_rollup.Kind.t -> + boot_sector:string -> + ([`Read | `Write] Node_context.t -> + genesis:Sc_rollup_block.t -> + unit tzresult Lwt.t) -> + unit Alcotest_lwt.test_case diff --git a/src/proto_alpha/lib_sc_rollup_node/RPC_server.ml b/src/proto_alpha/lib_sc_rollup_node/RPC_server.ml index ea3457213c2a7c8807046f9bf4fbd6d722359dcc..bc9bcbf82b63cda0acc4abf7d12dbc9ea163de1f 100644 --- a/src/proto_alpha/lib_sc_rollup_node/RPC_server.ml +++ b/src/proto_alpha/lib_sc_rollup_node/RPC_server.ml @@ -53,110 +53,112 @@ end let get_dal_processed_slots node_ctxt block = Node_context.list_slots_statuses node_ctxt ~confirmed_in_block_hash:block -module Global_directory = Make_directory (struct - include Sc_rollup_services.Global - - type context = Node_context.ro - - let context_of_prefix node_ctxt () = return (Node_context.readonly node_ctxt) -end) - -module Proof_helpers_directory = Make_directory (struct - include Sc_rollup_services.Global.Helpers - - (* The context needs to be accessed with write permissions because we need to - commit on disk to generate the proofs. *) - type context = Node_context.rw - - let context_of_prefix node_ctxt () = return node_ctxt -end) - -module Local_directory = Make_directory (struct - include Sc_rollup_services.Local - - type context = Node_context.ro - - let context_of_prefix node_ctxt () = return (Node_context.readonly node_ctxt) -end) - -module Block_directory = Make_directory (struct - include Sc_rollup_services.Global.Block - - type context = Node_context.ro * Block_hash.t - - let context_of_prefix node_ctxt (((), block) : prefix) = - let open Lwt_result_syntax in - let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in - (Node_context.readonly node_ctxt, block) -end) - -module Outbox_directory = Make_directory (struct - include Sc_rollup_services.Global.Block.Outbox - - type context = Node_context.ro * Block_hash.t * Alpha_context.Raw_level.t - - let context_of_prefix node_ctxt (((), block), level) = - let open Lwt_result_syntax in - let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in - (Node_context.readonly node_ctxt, block, level) -end) - -module Common = struct - let () = - Block_directory.register0 Sc_rollup_services.Global.Block.block - @@ fun (node_ctxt, block) () () -> - Node_context.get_full_l2_block node_ctxt block - - let () = - Block_directory.register0 Sc_rollup_services.Global.Block.num_messages - @@ fun (node_ctxt, block) () () -> - let open Lwt_result_syntax in - let* l2_block = Node_context.get_l2_block node_ctxt block in - let+ num_messages = - Node_context.get_num_messages node_ctxt l2_block.header.inbox_witness - in - Z.of_int num_messages - - let () = - Global_directory.register0 Sc_rollup_services.Global.sc_rollup_address - @@ fun node_ctxt () () -> return @@ node_ctxt.rollup_address - - let () = - Global_directory.register0 Sc_rollup_services.Global.current_tezos_head - @@ fun node_ctxt () () -> get_head_hash_opt node_ctxt - - let () = - Global_directory.register0 Sc_rollup_services.Global.current_tezos_level - @@ fun node_ctxt () () -> get_head_level_opt node_ctxt - - let () = - Block_directory.register0 Sc_rollup_services.Global.Block.hash - @@ fun (_node_ctxt, block) () () -> return block - - let () = - Block_directory.register0 Sc_rollup_services.Global.Block.level - @@ fun (node_ctxt, block) () () -> - Node_context.level_of_hash node_ctxt block - - let () = - Block_directory.register0 Sc_rollup_services.Global.Block.inbox - @@ fun (node_ctxt, block) () () -> - Node_context.get_inbox_by_block_hash node_ctxt block - - let () = - Block_directory.register0 Sc_rollup_services.Global.Block.ticks - @@ fun (node_ctxt, block) () () -> - let open Lwt_result_syntax in - let+ l2_block = Node_context.get_l2_block node_ctxt block in - Z.of_int64 l2_block.num_ticks -end - module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct module PVM = Simulation.PVM module Interpreter = Simulation.Interpreter module Outbox = Outbox.Make (PVM) module Free_pvm = Interpreter.Free_pvm + module Global_directory = Make_directory (struct + include Sc_rollup_services.Global + + type context = Node_context.ro + + let context_of_prefix node_ctxt () = + return (Node_context.readonly node_ctxt) + end) + + module Proof_helpers_directory = Make_directory (struct + include Sc_rollup_services.Global.Helpers + + (* The context needs to be accessed with write permissions because we need to + commit on disk to generate the proofs. *) + type context = Node_context.rw + + let context_of_prefix node_ctxt () = return node_ctxt + end) + + module Local_directory = Make_directory (struct + include Sc_rollup_services.Local + + type context = Node_context.ro + + let context_of_prefix node_ctxt () = + return (Node_context.readonly node_ctxt) + end) + + module Block_directory = Make_directory (struct + include Sc_rollup_services.Global.Block + + type context = Node_context.ro * Block_hash.t + + let context_of_prefix node_ctxt (((), block) : prefix) = + let open Lwt_result_syntax in + let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in + (Node_context.readonly node_ctxt, block) + end) + + module Outbox_directory = Make_directory (struct + include Sc_rollup_services.Global.Block.Outbox + + type context = Node_context.ro * Block_hash.t * Alpha_context.Raw_level.t + + let context_of_prefix node_ctxt (((), block), level) = + let open Lwt_result_syntax in + let+ block = Block_directory_helpers.block_of_prefix node_ctxt block in + (Node_context.readonly node_ctxt, block, level) + end) + + module Common = struct + let () = + Block_directory.register0 Sc_rollup_services.Global.Block.block + @@ fun (node_ctxt, block) () () -> + Node_context.get_full_l2_block node_ctxt block + + let () = + Block_directory.register0 Sc_rollup_services.Global.Block.num_messages + @@ fun (node_ctxt, block) () () -> + let open Lwt_result_syntax in + let* l2_block = Node_context.get_l2_block node_ctxt block in + let+ num_messages = + Node_context.get_num_messages node_ctxt l2_block.header.inbox_witness + in + Z.of_int num_messages + + let () = + Global_directory.register0 Sc_rollup_services.Global.sc_rollup_address + @@ fun node_ctxt () () -> return @@ node_ctxt.rollup_address + + let () = + Global_directory.register0 Sc_rollup_services.Global.current_tezos_head + @@ fun node_ctxt () () -> get_head_hash_opt node_ctxt + + let () = + Global_directory.register0 Sc_rollup_services.Global.current_tezos_level + @@ fun node_ctxt () () -> get_head_level_opt node_ctxt + + let () = + Block_directory.register0 Sc_rollup_services.Global.Block.hash + @@ fun (_node_ctxt, block) () () -> return block + + let () = + Block_directory.register0 Sc_rollup_services.Global.Block.level + @@ fun (node_ctxt, block) () () -> + Node_context.level_of_hash node_ctxt block + + let () = + Block_directory.register0 Sc_rollup_services.Global.Block.inbox + @@ fun (node_ctxt, block) () () -> + Node_context.get_inbox_by_block_hash node_ctxt block + + let () = + Block_directory.register0 Sc_rollup_services.Global.Block.ticks + @@ fun (node_ctxt, block) () () -> + let open Lwt_result_syntax in + let+ l2_block = Node_context.get_l2_block node_ctxt block in + Z.of_int64 l2_block.num_ticks + end + let get_state (node_ctxt : _ Node_context.t) block_hash = let open Lwt_result_syntax in let* ctxt = Node_context.checkout_context node_ctxt block_hash in diff --git a/src/proto_alpha/lib_sc_rollup_node/batcher.ml b/src/proto_alpha/lib_sc_rollup_node/batcher.ml index 27aa3059d536afc37b006a0ed46dd7810f504ccb..f2090acd06976860d79c7b7cca7279a2017fb4be 100644 --- a/src/proto_alpha/lib_sc_rollup_node/batcher.ml +++ b/src/proto_alpha/lib_sc_rollup_node/batcher.ml @@ -34,6 +34,10 @@ end module Batched_messages = Hash_queue.Make (L2_message.Hash) (L2_batched_message) +(* Count instances of the batcher functor to allow for multiple worker events + without conflicts. *) +let instances_count = ref 0 + module type S = sig type status = Pending_batch | Batched of Injector.Inj_operation.hash @@ -61,6 +65,8 @@ module type S = sig end module Make (Simulation : Simulation.S) : S = struct + let () = incr instances_count + module PVM = Simulation.PVM type status = Pending_batch | Batched of Injector.Inj_operation.hash @@ -265,6 +271,27 @@ module Make (Simulation : Simulation.S) : S = struct } end + module Name = struct + (* We only have a single batcher in the node *) + type t = unit + + let encoding = Data_encoding.unit + + let base = + (* But we can have multiple instances in the unit tests. This is just to + avoid conflicts in the events declarations. *) + Batcher_events.Worker.section + @ [ + ("worker" + ^ if !instances_count = 1 then "" else string_of_int !instances_count + ); + ] + + let pp _ _ = () + + let equal () () = true + end + module Worker = Worker.MakeSingle (Name) (Request) (Types) type worker = Worker.infinite Worker.queue Worker.t diff --git a/src/proto_alpha/lib_sc_rollup_node/batcher_events.ml b/src/proto_alpha/lib_sc_rollup_node/batcher_events.ml index 5d0ad969a3c0da23d93734f372cf308640a24fba..da9ad33fa984124015ca8c1663e77cd5c9bedee5 100644 --- a/src/proto_alpha/lib_sc_rollup_node/batcher_events.ml +++ b/src/proto_alpha/lib_sc_rollup_node/batcher_events.ml @@ -25,7 +25,7 @@ include Internal_event.Simple -let section = ["sc_rollup_node"; "batcher"] +let section = [Protocol.name; "sc_rollup_node"; "batcher"] let queue = declare_1 diff --git a/src/proto_alpha/lib_sc_rollup_node/batcher_worker_types.ml b/src/proto_alpha/lib_sc_rollup_node/batcher_worker_types.ml index 63afd1221a6d1ae3d50f9817e382cab7229aeafa..c0fe7350814c9ede1c17f9c55265cdb6e075447f 100644 --- a/src/proto_alpha/lib_sc_rollup_node/batcher_worker_types.ml +++ b/src/proto_alpha/lib_sc_rollup_node/batcher_worker_types.ml @@ -75,16 +75,3 @@ module Request = struct level | Batch -> Format.pp_print_string ppf "batch" end - -module Name = struct - (* We only have a single batcher right now *) - type t = unit - - let encoding = Data_encoding.unit - - let base = ["sc_rollup_batcher"] - - let pp _ _ = () - - let equal () () = true -end diff --git a/src/proto_alpha/lib_sc_rollup_node/batcher_worker_types.mli b/src/proto_alpha/lib_sc_rollup_node/batcher_worker_types.mli index 681291fbd22f7c2aa45d1dc703f7f198f4b4d4d2..d3a3fd2c09e963cb9b9655a92c2d411893aa8343 100644 --- a/src/proto_alpha/lib_sc_rollup_node/batcher_worker_types.mli +++ b/src/proto_alpha/lib_sc_rollup_node/batcher_worker_types.mli @@ -42,5 +42,3 @@ module Request : sig with type ('a, 'request_error) t := ('a, 'request_error) t and type view := view end - -module Name : Worker_intf.NAME with type t = unit diff --git a/src/proto_alpha/lib_sc_rollup_node/commitment.ml b/src/proto_alpha/lib_sc_rollup_node/commitment.ml index f1c09fefe9d21c0a5f589dccaa1fd709cacded25..237c288a0ba95874f9b40146bd79f885cdf0c329 100644 --- a/src/proto_alpha/lib_sc_rollup_node/commitment.ml +++ b/src/proto_alpha/lib_sc_rollup_node/commitment.ml @@ -81,7 +81,13 @@ let sc_rollup_challenge_window node_ctxt = let next_commitment_level node_ctxt last_commitment_level = add_level last_commitment_level (sc_rollup_commitment_period node_ctxt) +(* Count instances of the commitment functor to allow for multiple worker events + without conflicts. *) +let instances_count = ref 0 + module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct + let () = incr instances_count + module PVM = PVM type state = Node_context.ro @@ -406,6 +412,28 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct type parameters = {node_ctxt : Node_context.ro} end + module Name = struct + (* We only have a single committer in the node *) + type t = unit + + let encoding = Data_encoding.unit + + let base = + (* But we can have multiple instances in the unit tests. This is just to + avoid conflicts in the events declarations. *) + Commitment_event.section + @ [ + ("publisher" + ^ + if !instances_count = 1 then "" else string_of_int !instances_count + ); + ] + + let pp _ _ = () + + let equal () () = true + end + module Worker = Worker.MakeSingle (Name) (Request) (Types) type worker = Worker.infinite Worker.queue Worker.t diff --git a/src/proto_alpha/lib_sc_rollup_node/commitment_event.ml b/src/proto_alpha/lib_sc_rollup_node/commitment_event.ml index 7f9135d2792a16f0a870196cad9942a9f5fc33e8..e5d62ef4337c738934ab3f3975eb9d582a244452 100644 --- a/src/proto_alpha/lib_sc_rollup_node/commitment_event.ml +++ b/src/proto_alpha/lib_sc_rollup_node/commitment_event.ml @@ -30,7 +30,7 @@ open Publisher_worker_types module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "commitment"] + let section = [Protocol.name; "sc_rollup_node"; "commitment"] let starting = declare_0 @@ -157,6 +157,8 @@ let stopping = Simple.(emit stopping) open Sc_rollup.Commitment +let section = Simple.section + let emit_commitment_event f commitment_hash {predecessor; inbox_level; compressed_state; number_of_ticks} = Simple.( diff --git a/src/proto_alpha/lib_sc_rollup_node/commitment_event.mli b/src/proto_alpha/lib_sc_rollup_node/commitment_event.mli index 8f4baf9b0e14b40ddcdbd621c2aa831741bd4f9f..6f583d61cc72d497a7671cda2dccb1f0055215d6 100644 --- a/src/proto_alpha/lib_sc_rollup_node/commitment_event.mli +++ b/src/proto_alpha/lib_sc_rollup_node/commitment_event.mli @@ -33,6 +33,9 @@ val starting : unit -> unit Lwt.t val stopping : unit -> unit Lwt.t +(** Section for commitment events. *) +val section : string list + (** [commitment_stored commitment_hash commitment] emits the event that the [commitment] was stored. *) val commitment_stored : diff --git a/src/proto_alpha/lib_sc_rollup_node/daemon.ml b/src/proto_alpha/lib_sc_rollup_node/daemon.ml index 6c40166adcd20200092a7010db52470b3eb9b679..b824df25ac95174917bfcc5d402835e1cda34fa1 100644 --- a/src/proto_alpha/lib_sc_rollup_node/daemon.ml +++ b/src/proto_alpha/lib_sc_rollup_node/daemon.ml @@ -564,6 +564,68 @@ module Make (PVM : Pvm.S) = struct Format.eprintf "%!%a@.Exiting.@." pp_print_trace e ; let*! _ = Lwt_exit.exit_and_wait 1 in return_unit) + + module Internal_for_tests = struct + (** Same as {!process_head} but only builds and stores the L2 block + corresponding to [messages]. It is used by the unit tests to build an L2 + chain. *) + let process_messages (node_ctxt : _ Node_context.t) ~is_migration_block + ~predecessor ~predecessor_timestamp head messages = + let open Lwt_result_syntax in + let* () = Node_context.save_level node_ctxt head in + let* inbox_hash, inbox, inbox_witness, messages, ctxt = + Inbox.Internal_for_tests.process_messages + node_ctxt + ~is_migration_block + ~predecessor + ~predecessor_timestamp + ~level:head.level + messages + in + let* ctxt, _num_messages, num_ticks, initial_tick = + Components.Interpreter.process_head + node_ctxt + ctxt + ~predecessor + head + (inbox, messages) + in + let*! context_hash = Context.commit ctxt in + let* commitment_hash = + Components.Commitment.process_head + node_ctxt + ~predecessor:predecessor.Layer1.hash + head + ctxt + in + let level = Raw_level.of_int32_exn head.level in + let* previous_commitment_hash = + if level = node_ctxt.genesis_info.Sc_rollup.Commitment.level then + (* Previous commitment for rollup genesis is itself. *) + return node_ctxt.genesis_info.Sc_rollup.Commitment.commitment_hash + else + let+ pred = Node_context.get_l2_block node_ctxt predecessor.hash in + Sc_rollup_block.most_recent_commitment pred.header + in + let header = + Sc_rollup_block. + { + block_hash = head.hash; + level; + predecessor = predecessor.hash; + commitment_hash; + previous_commitment_hash; + context = context_hash; + inbox_witness; + inbox_hash; + } + in + let l2_block = + Sc_rollup_block.{header; content = (); num_ticks; initial_tick} + in + let* () = Node_context.save_l2_head node_ctxt l2_block in + return l2_block + end end let run ~data_dir (configuration : Configuration.t) diff --git a/src/proto_alpha/lib_sc_rollup_node/daemon_event.ml b/src/proto_alpha/lib_sc_rollup_node/daemon_event.ml index cf8b076f59f2a5dde499bb2c03707fc101fc700f..73d701430da0bff4474dd2ebc6b41cac8de8d3de 100644 --- a/src/proto_alpha/lib_sc_rollup_node/daemon_event.ml +++ b/src/proto_alpha/lib_sc_rollup_node/daemon_event.ml @@ -26,7 +26,7 @@ module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "daemon"] + let section = [Protocol.name; "sc_rollup_node"; "daemon"] let head_processing = declare_3 diff --git a/src/proto_alpha/lib_sc_rollup_node/dal_pages_request.ml b/src/proto_alpha/lib_sc_rollup_node/dal_pages_request.ml index 0f1ed5f27595ed77b4edbe2672372d17e5816606..5744e9f67728e3593ce0c9b163be93ea558fdd4c 100644 --- a/src/proto_alpha/lib_sc_rollup_node/dal_pages_request.ml +++ b/src/proto_alpha/lib_sc_rollup_node/dal_pages_request.ml @@ -38,7 +38,7 @@ type error += | Dal_invalid_page_for_slot of Dal.Page.t let () = - register_error_kind + Sc_rollup_node_errors.register_error_kind `Permanent ~id:"dal_pages_request.dal_slot_not_found_in_store" ~title:"Dal slot not found in store" @@ -48,7 +48,7 @@ let () = Data_encoding.(obj1 (req "slot_id" Dal.Slot.Header.id_encoding)) (function Dal_slot_not_found_in_store slot_id -> Some slot_id | _ -> None) (fun slot_id -> Dal_slot_not_found_in_store slot_id) ; - register_error_kind + Sc_rollup_node_errors.register_error_kind `Permanent ~id:"dal_pages_request.dal_invalid_page_for_slot" ~title:"Invalid Dal page requested for slot" diff --git a/src/proto_alpha/lib_sc_rollup_node/dal_slots_tracker_event.ml b/src/proto_alpha/lib_sc_rollup_node/dal_slots_tracker_event.ml index 84ed4506c47f31ccd7ce935589470a5057a2ff8c..05620638edb998237635252ebe5799f9fb3e1013 100644 --- a/src/proto_alpha/lib_sc_rollup_node/dal_slots_tracker_event.ml +++ b/src/proto_alpha/lib_sc_rollup_node/dal_slots_tracker_event.ml @@ -29,7 +29,7 @@ open Alpha_context module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "dal_slots_tracker"] + let section = [Protocol.name; "sc_rollup_node"; "dal_slots_tracker"] let slot_has_been_confirmed = declare_3 diff --git a/src/proto_alpha/lib_sc_rollup_node/event.ml b/src/proto_alpha/lib_sc_rollup_node/event.ml index ce5d693db33d04a45d73ec101bebe0051a28bde2..ea2fa9aaa35ec021ba3f29b197e53dca08917f47 100644 --- a/src/proto_alpha/lib_sc_rollup_node/event.ml +++ b/src/proto_alpha/lib_sc_rollup_node/event.ml @@ -26,7 +26,7 @@ module Simple = struct include Internal_event.Simple - let section = ["smart_rollup_node"] + let section = [Protocol.name; "smart_rollup_node"] let starting_node = declare_0 diff --git a/src/proto_alpha/lib_sc_rollup_node/inbox.ml b/src/proto_alpha/lib_sc_rollup_node/inbox.ml index ae42c820870e13b706e0b1a5db2aa2f553fcc3c9..61a8e4b3226a6ae909356b7d47d6df2e47e44551 100644 --- a/src/proto_alpha/lib_sc_rollup_node/inbox.ml +++ b/src/proto_alpha/lib_sc_rollup_node/inbox.ml @@ -133,6 +133,52 @@ let add_messages ~is_migration_block ~predecessor_timestamp ~predecessor inbox inbox, messages_with_protocol_internal_messages ) +let process_messages (node_ctxt : _ Node_context.t) ~is_migration_block + ~predecessor ~predecessor_timestamp ~level messages = + let open Lwt_result_syntax in + let* inbox = Node_context.inbox_of_head node_ctxt predecessor in + let inbox_metrics = Metrics.Inbox.metrics in + Prometheus.Gauge.set inbox_metrics.head_inbox_level @@ Int32.to_float level ; + let*? level = Environment.wrap_tzresult @@ Raw_level.of_int32 level in + let* ctxt = + if Raw_level.(level <= node_ctxt.Node_context.genesis_info.level) then + (* This is before we have interpreted the boot sector, so we start + with an empty context in genesis *) + return (Context.empty node_ctxt.context) + else Node_context.checkout_context node_ctxt predecessor.hash + in + let* ( _messages_history, + witness_hash, + inbox, + messages_with_protocol_internal_messages ) = + add_messages + ~is_migration_block + ~predecessor_timestamp + ~predecessor:predecessor.hash + inbox + messages + in + Metrics.Inbox.Stats.head_messages_list := + messages_with_protocol_internal_messages ; + let* () = + Node_context.save_messages + node_ctxt + witness_hash + { + is_migration_block; + predecessor = predecessor.hash; + predecessor_timestamp; + messages; + } + in + let* inbox_hash = Node_context.save_inbox node_ctxt inbox in + return + ( inbox_hash, + inbox, + witness_hash, + messages_with_protocol_internal_messages, + ctxt ) + let process_head (node_ctxt : _ Node_context.t) ~predecessor Layer1.{level; hash = head_hash} = let open Lwt_result_syntax in @@ -140,68 +186,34 @@ let process_head (node_ctxt : _ Node_context.t) ~predecessor Raw_level.to_int32 node_ctxt.genesis_info.level |> Int32.succ in if level >= first_inbox_level then ( - (* - - We compute the inbox of this block using the inbox of its - predecessor. That way, the computation of inboxes is robust - to chain reorganization. - - *) - let* inbox = Node_context.inbox_of_head node_ctxt predecessor in - let inbox_metrics = Metrics.Inbox.metrics in - Prometheus.Gauge.set inbox_metrics.head_inbox_level @@ Int32.to_float level ; - let*? level = Environment.wrap_tzresult @@ Raw_level.of_int32 level in - let* ctxt = - if Raw_level.(level <= node_ctxt.Node_context.genesis_info.level) then - (* This is before we have interpreted the boot sector, so we start - with an empty context in genesis *) - return (Context.empty node_ctxt.context) - else Node_context.checkout_context node_ctxt predecessor.hash - in + (* We compute the inbox of this block using the inbox of its + predecessor. That way, the computation of inboxes is robust to chain + reorganization. *) let* ( is_migration_block, collected_messages, predecessor_timestamp, predecessor_hash ) = get_messages node_ctxt head_hash in + assert (Block_hash.(predecessor.Layer1.hash = predecessor_hash)) ; let*! () = - Inbox_event.get_messages - head_hash - (Raw_level.to_int32 level) - (List.length collected_messages) + Inbox_event.get_messages head_hash level (List.length collected_messages) in - let* ( _messages_history, - witness_hash, - inbox, - messages_with_protocol_internal_messages ) = - add_messages + let* (( _inbox_hash, + inbox, + _witness_hash, + _messages_with_protocol_internal_messages, + _ctxt ) as res) = + process_messages + node_ctxt ~is_migration_block + ~predecessor ~predecessor_timestamp - ~predecessor:predecessor_hash - inbox + ~level collected_messages in - Metrics.Inbox.Stats.head_messages_list := - messages_with_protocol_internal_messages ; - let* () = - Node_context.save_messages - node_ctxt - witness_hash - { - is_migration_block; - predecessor = predecessor_hash; - predecessor_timestamp; - messages = collected_messages; - } - in let* () = same_inbox_as_layer_1 node_ctxt head_hash inbox in - let* inbox_hash = Node_context.save_inbox node_ctxt inbox in - return - ( inbox_hash, - inbox, - witness_hash, - messages_with_protocol_internal_messages, - ctxt )) + return res) else let* inbox = Node_context.genesis_inbox node_ctxt in return @@ -238,3 +250,7 @@ let payloads_history_of_messages ~is_migration_block ~predecessor messages in payloads_history + +module Internal_for_tests = struct + let process_messages = process_messages +end diff --git a/src/proto_alpha/lib_sc_rollup_node/inbox.mli b/src/proto_alpha/lib_sc_rollup_node/inbox.mli index 23c035774f3a6a6824d7a16f456b1ed4d7b4ee8c..58023fccfe4e2effd314545a6583e652f23f43e7 100644 --- a/src/proto_alpha/lib_sc_rollup_node/inbox.mli +++ b/src/proto_alpha/lib_sc_rollup_node/inbox.mli @@ -82,3 +82,22 @@ val payloads_history_of_messages : predecessor_timestamp:Timestamp.time -> Sc_rollup.Inbox_message.t list -> Sc_rollup.Inbox_merkelized_payload_hashes.History.t tzresult + +(**/**) + +module Internal_for_tests : sig + val process_messages : + Node_context.rw -> + is_migration_block:bool -> + predecessor:Layer1.head -> + predecessor_timestamp:Timestamp.time -> + level:int32 -> + Sc_rollup.Inbox_message.t list -> + (Sc_rollup.Inbox.Hash.t + * Sc_rollup.Inbox.t + * Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t + * Sc_rollup.Inbox_message.t list + * Context.rw) + tzresult + Lwt.t +end diff --git a/src/proto_alpha/lib_sc_rollup_node/inbox_event.ml b/src/proto_alpha/lib_sc_rollup_node/inbox_event.ml index 18d83fc56dcdd5113fdf528aa536bbcb4fe3aef7..ed732319c4dc66f38a24f3053bc5e2f3dc32bb8f 100644 --- a/src/proto_alpha/lib_sc_rollup_node/inbox_event.ml +++ b/src/proto_alpha/lib_sc_rollup_node/inbox_event.ml @@ -26,7 +26,7 @@ module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "inbox"] + let section = [Protocol.name; "sc_rollup_node"; "inbox"] let starting = declare_0 diff --git a/src/proto_alpha/lib_sc_rollup_node/injector.ml b/src/proto_alpha/lib_sc_rollup_node/injector.ml index 3f4a3648e8fd7730254f0cd56d7b28ba99c542a6..1431139541d59059b31365f35d005ba0e69758ac 100644 --- a/src/proto_alpha/lib_sc_rollup_node/injector.ml +++ b/src/proto_alpha/lib_sc_rollup_node/injector.ml @@ -37,7 +37,7 @@ module Parameters : and type Operation.t = L1_operation.t = struct type state = Node_context.ro - let events_section = ["sc_rollup.injector"] + let events_section = [Protocol.name; "sc_rollup_node"] module Tag : TAG with type t = Configuration.purpose = struct type t = Configuration.purpose diff --git a/src/proto_alpha/lib_sc_rollup_node/interpreter.ml b/src/proto_alpha/lib_sc_rollup_node/interpreter.ml index 5276c655db4c073485a0da6f3848c68756bf6052..99abd3eb93a0ad16173738da30722005f47be527 100644 --- a/src/proto_alpha/lib_sc_rollup_node/interpreter.ml +++ b/src/proto_alpha/lib_sc_rollup_node/interpreter.ml @@ -119,15 +119,15 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct let state_of_head node_ctxt ctxt Layer1.{hash; level} = let open Lwt_result_syntax in - let genesis_level = - Raw_level.to_int32 node_ctxt.Node_context.genesis_info.level - in - if level = genesis_level then genesis_state hash node_ctxt ctxt - else - let*! state = PVM.State.find ctxt in - match state with - | None -> tzfail (Sc_rollup_node_errors.Missing_PVM_state (hash, level)) - | Some state -> return (ctxt, state) + let*! state = PVM.State.find ctxt in + match state with + | None -> + let genesis_level = + Raw_level.to_int32 node_ctxt.Node_context.genesis_info.level + in + if level = genesis_level then genesis_state hash node_ctxt ctxt + else tzfail (Sc_rollup_node_errors.Missing_PVM_state (hash, level)) + | Some state -> return (ctxt, state) (** [transition_pvm node_ctxt predecessor head] runs a PVM at the previous state from block [predecessor] by consuming as many messages diff --git a/src/proto_alpha/lib_sc_rollup_node/interpreter_event.ml b/src/proto_alpha/lib_sc_rollup_node/interpreter_event.ml index ffc016b9123b695c0084c840b202617a92dede29..80fab8ac3274387359c9aad5045bc31948f183af 100644 --- a/src/proto_alpha/lib_sc_rollup_node/interpreter_event.ml +++ b/src/proto_alpha/lib_sc_rollup_node/interpreter_event.ml @@ -28,7 +28,7 @@ open Protocol.Alpha_context.Sc_rollup module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "interpreter"] + let section = [Protocol.name; "sc_rollup_node"; "interpreter"] let transitioned_pvm = declare_4 diff --git a/src/proto_alpha/lib_sc_rollup_node/layer1.ml b/src/proto_alpha/lib_sc_rollup_node/layer1.ml index d32f5b6d5c3f3d25c5170f6d11526c279a9d6239..70c02794a585657767ae121156473b616af4b19c 100644 --- a/src/proto_alpha/lib_sc_rollup_node/layer1.ml +++ b/src/proto_alpha/lib_sc_rollup_node/layer1.ml @@ -36,7 +36,7 @@ open Protocol_client_context type error += Cannot_find_block of Block_hash.t let () = - register_error_kind + Sc_rollup_node_errors.register_error_kind ~id:"sc_rollup.node.cannot_find_block" ~title:"Cannot find block from L1" ~description:"A block couldn't be found from the L1 node" diff --git a/src/proto_alpha/lib_sc_rollup_node/layer1_event.ml b/src/proto_alpha/lib_sc_rollup_node/layer1_event.ml index 6e9773d48ec283c97c84cddab6fbdbe083b59434..6a0987632b05f33897697fb843de8c909db21eb6 100644 --- a/src/proto_alpha/lib_sc_rollup_node/layer1_event.ml +++ b/src/proto_alpha/lib_sc_rollup_node/layer1_event.ml @@ -26,7 +26,7 @@ module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "layer_1"] + let section = [Protocol.name; "sc_rollup_node"; "layer_1"] let starting = declare_0 diff --git a/src/proto_alpha/lib_sc_rollup_node/node_context.ml b/src/proto_alpha/lib_sc_rollup_node/node_context.ml index f722a271d21143f55baf52628b919636ab221da2..ed848a8f4de1c2aa535e874501b40d6b64106b5e 100644 --- a/src/proto_alpha/lib_sc_rollup_node/node_context.ml +++ b/src/proto_alpha/lib_sc_rollup_node/node_context.ml @@ -717,3 +717,57 @@ let find_confirmed_slots_histories {store; _} = let save_confirmed_slots_histories {store; _} = Store.Dal_confirmed_slots_histories.add store.irmin_store + +module Internal_for_tests = struct + let create_node_context cctxt + ?(constants = Default_parameters.constants_mainnet) ~data_dir kind = + let open Lwt_result_syntax in + let l2_blocks_cache_size = Configuration.default_l2_blocks_cache_size in + let protocol_constants = + constants + |> Data_encoding.Binary.to_bytes_exn Constants.Parametric.encoding + |> Data_encoding.Binary.of_bytes_exn Constants_parametric_repr.encoding + |> Constants_repr.all_of_parametric + |> Data_encoding.Binary.to_bytes_exn Constants_repr.encoding + |> Data_encoding.Binary.of_bytes_exn Constants.encoding + in + let* store = + Store.load + Read_write + ~l2_blocks_cache_size + Configuration.(default_storage_dir data_dir) + in + let*! context = + Context.load Read_write (Configuration.default_context_dir data_dir) + in + let genesis_info = + Sc_rollup.Commitment.{level = Raw_level.root; commitment_hash = Hash.zero} + in + let l1_ctxt = Layer1.Internal_for_tests.dummy cctxt in + let lcc = + Reference.new_ + {commitment = Sc_rollup.Commitment.Hash.zero; level = Raw_level.root} + in + let lpc = Reference.new_ None in + return + { + cctxt; + dal_cctxt = None; + data_dir; + l1_ctxt; + rollup_address = Sc_rollup.Address.zero; + mode = Observer; + operators = Configuration.Operator_purpose_map.empty; + genesis_info; + lcc; + lpc; + kind; + injector_retention_period = 0; + block_finality_time = 2; + fee_parameters = Configuration.default_fee_parameters; + protocol_constants; + loser_mode = Loser_mode.no_failures; + store; + context; + } +end diff --git a/src/proto_alpha/lib_sc_rollup_node/node_context.mli b/src/proto_alpha/lib_sc_rollup_node/node_context.mli index c2bbebd6f04dd31159d55d3c9d06e41318103d59..7583b4377195ca3f958505544349d9f68fd34e0f 100644 --- a/src/proto_alpha/lib_sc_rollup_node/node_context.mli +++ b/src/proto_alpha/lib_sc_rollup_node/node_context.mli @@ -426,3 +426,17 @@ val find_confirmed_slots_histories : val save_confirmed_slots_histories : rw -> Block_hash.t -> Dal.Slots_history.History_cache.t -> unit tzresult Lwt.t + +(**/**) + +module Internal_for_tests : sig + (** Create a node context which really stores data on disk but does not + connect to any layer 1 node. It is meant to be used in unit tests for the + rollup node functions. *) + val create_node_context : + Protocol_client_context.full -> + ?constants:Constants.Parametric.t -> + data_dir:string -> + Sc_rollup.Kind.t -> + Store_sigs.rw t tzresult Lwt.t +end diff --git a/src/proto_alpha/lib_sc_rollup_node/publisher_worker_types.ml b/src/proto_alpha/lib_sc_rollup_node/publisher_worker_types.ml index 2ae31036e3105f7f5d6362c9eabedfd48b18bc7c..c10e697273e3a27772ce298eb43d33c53dde9db5 100644 --- a/src/proto_alpha/lib_sc_rollup_node/publisher_worker_types.ml +++ b/src/proto_alpha/lib_sc_rollup_node/publisher_worker_types.ml @@ -55,16 +55,3 @@ module Request = struct | Publish -> Format.pp_print_string ppf "publish" | Cement -> Format.pp_print_string ppf "cement" end - -module Name = struct - (* We only have a single commitment publisher right now *) - type t = unit - - let encoding = Data_encoding.unit - - let base = ["sc_rollup_commitment_publisher"] - - let pp _ _ = () - - let equal () () = true -end diff --git a/src/proto_alpha/lib_sc_rollup_node/publisher_worker_types.mli b/src/proto_alpha/lib_sc_rollup_node/publisher_worker_types.mli index ab244e31a486323c889645a1a1a44aa815eeb797..eed1fdcad468e10c17c8bb15d651c24ab699ee0c 100644 --- a/src/proto_alpha/lib_sc_rollup_node/publisher_worker_types.mli +++ b/src/proto_alpha/lib_sc_rollup_node/publisher_worker_types.mli @@ -38,5 +38,3 @@ module Request : sig with type ('a, 'request_error) t := ('a, 'request_error) t and type view := view end - -module Name : Worker_intf.NAME with type t = unit diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_game_event.ml b/src/proto_alpha/lib_sc_rollup_node/refutation_game_event.ml index 83857af8579a54c6a39058abfdd007454b99ea57..45530c687e35d706bbe507eca905c584858fe115 100644 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_game_event.ml +++ b/src/proto_alpha/lib_sc_rollup_node/refutation_game_event.ml @@ -31,7 +31,7 @@ open Protocol.Alpha_context module Simple = struct include Internal_event.Simple - let section = ["sc_rollup_node"; "refutation_game"] + let section = [Protocol.name; "sc_rollup_node"; "refutation_game"] let timeout = declare_1 @@ -86,6 +86,7 @@ module Simple = struct let timeout_detected = declare_1 + ~section ~name:"sc_rollup_node_timeout_detected" ~msg: "The rollup node has detected that opponent {other} can be timed out." diff --git a/src/proto_alpha/lib_sc_rollup_node/reveals.ml b/src/proto_alpha/lib_sc_rollup_node/reveals.ml index e61edb2d4003aec99f3b1d2e6abd311bc210fceb..59fb19e4a7d0f668d7a72c8aaf3473aede285771 100644 --- a/src/proto_alpha/lib_sc_rollup_node/reveals.ml +++ b/src/proto_alpha/lib_sc_rollup_node/reveals.ml @@ -32,7 +32,7 @@ type error += | Could_not_encode_raw_data let () = - register_error_kind + Sc_rollup_node_errors.register_error_kind ~id:"sc_rollup.node.wrong_hash_of_reveal_preimage" ~title:"Hash of reveal preimage is not correct" ~description:"Hash of reveal preimage is not correct." @@ -52,7 +52,7 @@ let () = (function | Wrong_hash {found; expected} -> Some (found, expected) | _ -> None) (fun (found, expected) -> Wrong_hash {found; expected}) ; - register_error_kind + Sc_rollup_node_errors.register_error_kind ~id:"sc_rollup.node.could_not_open_reveal_preimage_file" ~title:"Could not open reveal preimage file" ~description:"Could not open reveal preimage file." @@ -66,7 +66,7 @@ let () = (function | Could_not_open_preimage_file filename -> Some filename | _ -> None) (fun filename -> Could_not_open_preimage_file filename) ; - register_error_kind + Sc_rollup_node_errors.register_error_kind ~id:"sc_rollup.node.could_not_encode_raw_data" ~title:"Could not encode raw data to reveal" ~description:"Could not encode raw data to reveal." diff --git a/src/proto_alpha/lib_sc_rollup_node/sc_rollup_node_errors.ml b/src/proto_alpha/lib_sc_rollup_node/sc_rollup_node_errors.ml index c2b5d2a399469978bc5d8c776637d9e909043b3a..fb10fab765cfe60fb64a3d387e32e85bd94c4021 100644 --- a/src/proto_alpha/lib_sc_rollup_node/sc_rollup_node_errors.ml +++ b/src/proto_alpha/lib_sc_rollup_node/sc_rollup_node_errors.ml @@ -25,6 +25,10 @@ open Protocol.Alpha_context +let make_id id = String.concat "." [Protocol.name; id] + +let register_error_kind ~id = register_error_kind ~id:(make_id id) + type error += | Cannot_produce_proof of Sc_rollup.Inbox.t * Raw_level.t | Missing_mode_operators of {mode : string; missing_operators : string list} diff --git a/src/proto_alpha/lib_sc_rollup_node/test/canary.ml b/src/proto_alpha/lib_sc_rollup_node/test/canary.ml new file mode 100644 index 0000000000000000000000000000000000000000..168ce5c8e701b1a1df7c133547bde316c488345c --- /dev/null +++ b/src/proto_alpha/lib_sc_rollup_node/test/canary.ml @@ -0,0 +1,102 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 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: Smart rollup node library + Invocation: dune exec src/proto_alpha/lib_sc_rollup_node/test/main.exe \ + -- -f canary + Subject: Canary unit tests to make sure the test helpers work as intended +*) + +open Protocol.Alpha_context + +let build_chain node_ctxt ~genesis ~length = + let open Lwt_result_syntax in + let* blocks = Helpers.append_dummy_l2_chain node_ctxt ~length in + return (genesis :: blocks) + +let canary_test node_ctxt ~genesis = + let open Lwt_result_syntax in + let length = 100 in + let* chain = build_chain node_ctxt ~genesis ~length in + Assert.Int.equal + ~loc:__LOC__ + ~msg:"chain_length_ok" + (List.length chain) + (length + 1) ; + (* Checking that the chain matches what is stored *) + let* () = + List.iter_es + (fun (block : Sc_rollup_block.t) -> + let* store_block_by_hash = + Node_context.get_l2_block node_ctxt block.header.block_hash + in + let* store_block_by_level = + Node_context.get_l2_block_by_level + node_ctxt + (Raw_level.to_int32 block.header.level) + in + Helpers.Assert.L2_block.equal + ~loc:__LOC__ + ~msg:"stored_block_by_hash_ok" + store_block_by_hash + block ; + Helpers.Assert.L2_block.equal + ~loc:__LOC__ + ~msg:"stored_block_by_level_ok" + store_block_by_level + block ; + return_unit) + chain + in + let* head = Node_context.last_processed_head_opt node_ctxt in + let last = List.last_opt chain in + Helpers.Assert.L2_block.Option.equal + ~loc:__LOC__ + ~msg:"head_is_last_block" + head + last ; + return_unit + +let tests = + [ + Helpers.alcotest + "canary arith" + `Quick + Sc_rollup.Kind.Example_arith + ~boot_sector:"" + canary_test; + Helpers.alcotest + "canary wasm" + `Quick + Sc_rollup.Kind.Wasm_2_0_0 + ~boot_sector:"" + canary_test; + ] + +let () = + Alcotest_lwt.run "canary" [(Protocol.name ^ ": canary", tests)] + |> Lwt_main.run diff --git a/src/proto_alpha/lib_sc_rollup_node/test/dune b/src/proto_alpha/lib_sc_rollup_node/test/dune new file mode 100644 index 0000000000000000000000000000000000000000..c1ab36f7bf655fcebe55a05633335f127d0dc87f --- /dev/null +++ b/src/proto_alpha/lib_sc_rollup_node/test/dune @@ -0,0 +1,49 @@ +; This file was automatically generated, do not edit. +; Edit file manifest/main.ml instead. + +(library + (name src_proto_alpha_lib_sc_rollup_node_test_tezt_lib) + (instrumentation (backend bisect_ppx)) + (libraries + tezt.core + tezos-base + tezos-protocol-alpha + tezos-test-helpers + tezos-smart-rollup-layer2-alpha + octez_smart_rollup_node_alpha + octez-alcotezt + octez_smart_rollup_node_alpha_test_helpers) + (library_flags (:standard -linkall)) + (flags + (:standard) + -open Tezt_core + -open Tezt_core.Base + -open Tezos_base.TzPervasives + -open Tezos_base.TzPervasives.Error_monad.Legacy_monad_globals + -open Tezos_protocol_alpha + -open Tezos_test_helpers + -open Tezos_smart_rollup_layer2_alpha + -open Octez_smart_rollup_node_alpha + -open Octez_alcotezt + -open Octez_smart_rollup_node_alpha_test_helpers) + (modules canary)) + +(executable + (name main) + (instrumentation (backend bisect_ppx --bisect-sigterm)) + (libraries + src_proto_alpha_lib_sc_rollup_node_test_tezt_lib + tezt) + (link_flags + (:standard) + (:include %{workspace_root}/macos-link-flags.sexp)) + (modules main)) + +(rule + (alias runtezt) + (package tezos-sc-rollup-node-test) + (action (run %{dep:./main.exe}))) + +(rule + (targets main.ml) + (action (with-stdout-to %{targets} (echo "let () = Tezt.Test.run ()")))) diff --git a/src/proto_alpha/lib_sc_rollup_node/test/helpers/dune b/src/proto_alpha/lib_sc_rollup_node/test/helpers/dune new file mode 100644 index 0000000000000000000000000000000000000000..d8b04b2883ef680d248e3ed2b45771858a568498 --- /dev/null +++ b/src/proto_alpha/lib_sc_rollup_node/test/helpers/dune @@ -0,0 +1,30 @@ +; This file was automatically generated, do not edit. +; Edit file manifest/main.ml instead. + +(library + (name octez_smart_rollup_node_alpha_test_helpers) + (package tezos-sc-rollup-node-test) + (instrumentation (backend bisect_ppx)) + (libraries + tezos-base + tezos-protocol-alpha + tezos-protocol-alpha.parameters + tezos-client-alpha + tezos-test-helpers + qcheck-alcotest + qcheck-core + logs.lwt + tezos-smart-rollup-layer2-alpha + octez_smart_rollup_node_alpha + octez-alcotezt) + (flags + (:standard) + -open Tezos_base.TzPervasives + -open Tezos_base.TzPervasives.Error_monad.Legacy_monad_globals + -open Tezos_protocol_alpha + -open Tezos_protocol_alpha_parameters + -open Tezos_client_alpha + -open Tezos_test_helpers + -open Tezos_smart_rollup_layer2_alpha + -open Octez_smart_rollup_node_alpha + -open Octez_alcotezt)) diff --git a/src/proto_alpha/lib_sc_rollup_node/test/helpers/faked_client_context.ml b/src/proto_alpha/lib_sc_rollup_node/test/helpers/faked_client_context.ml new file mode 100644 index 0000000000000000000000000000000000000000..fdf0855af82755d2ec3d8b943116c4a4a3f0a531 --- /dev/null +++ b/src/proto_alpha/lib_sc_rollup_node/test/helpers/faked_client_context.ml @@ -0,0 +1,172 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 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 client contexts that stores information (such as the + wallet, etc.) in memory and that cannot do RPCs but which can be used in + unit tests. + + It is largely taken from the mockup simulator of the baker. + *) + +open Tezos_client_base + +class dummy_prompter : Client_context.prompter = + object + method prompt : type a. (a, string tzresult) Client_context.lwt_format -> a + = + fun _msg -> assert false + + method prompt_password : type a. + (a, Bytes.t tzresult) Client_context.lwt_format -> a = + fun _msg -> assert false + + method multiple_password_retries = false + end + +class faked_ctxt : Tezos_rpc.Context.generic = + let local_ctxt = + Tezos_mockup_proxy.RPC_client.local_ctxt Tezos_rpc.Directory.empty + in + object + method base = local_ctxt#base + + method generic_media_type_call meth ?body uri = + local_ctxt#generic_media_type_call meth ?body uri + + method call_service + : 'm 'p 'q 'i 'o. + (([< Resto.meth] as 'm), unit, 'p, 'q, 'i, 'o) Tezos_rpc.Service.t -> + 'p -> + 'q -> + 'i -> + 'o tzresult Lwt.t = + fun service params query body -> + local_ctxt#call_service service params query body + + method call_streamed_service + : 'm 'p 'q 'i 'o. + (([< Resto.meth] as 'm), unit, 'p, 'q, 'i, 'o) Tezos_rpc.Service.t -> + on_chunk:('o -> unit) -> + on_close:(unit -> unit) -> + 'p -> + 'q -> + 'i -> + (unit -> unit) tzresult Lwt.t = + fun service ~on_chunk ~on_close params query body -> + local_ctxt#call_streamed_service + service + ~on_chunk + ~on_close + params + query + body + end + +class faked_wallet ~base_dir ~filesystem : Client_context.wallet = + object (self) + method load_passwords = None + + method read_file fname = + match String.Hashtbl.find filesystem fname with + | None -> failwith "faked_wallet: cannot read file (%s)" fname + | Some (content, _mtime) -> return content + + method private filename alias_name = + Filename.concat + base_dir + (String.map (function ' ' -> '_' | c -> c) alias_name ^ "s") + + val lock_mutex = Lwt_mutex.create () + + method with_lock : type a. (unit -> a Lwt.t) -> a Lwt.t = + fun f -> Lwt_mutex.with_lock lock_mutex f + + method get_base_dir = base_dir + + method load : type a. + string -> default:a -> a Data_encoding.encoding -> a tzresult Lwt.t = + fun alias_name ~default encoding -> + let filename = self#filename alias_name in + if not (String.Hashtbl.mem filesystem filename) then return default + else + self#read_file filename >>=? fun content -> + let json = (Ezjsonm.from_string content :> Data_encoding.json) in + match Data_encoding.Json.destruct encoding json with + | exception e -> + failwith + "did not understand the %s alias file %s : %s" + alias_name + filename + (Printexc.to_string e) + | data -> return data + + method write : type a. + string -> a -> a Data_encoding.encoding -> unit tzresult Lwt.t = + fun alias_name list encoding -> + let filename = self#filename alias_name in + let json = Data_encoding.Json.construct encoding list in + let str = Ezjsonm.value_to_string (json :> Ezjsonm.value) in + String.Hashtbl.replace + filesystem + filename + (str, Some (Ptime.to_float_s (Ptime_clock.now ()))) ; + return_unit + + method last_modification_time : string -> float option tzresult Lwt.t = + let open Lwt_result_syntax in + fun alias_name -> + let filename = self#filename alias_name in + let file = String.Hashtbl.find_opt filesystem filename in + match file with + | None -> return_none + | Some (_content, mtime) -> return mtime + end + +class faked_io_wallet ~base_dir ~filesystem : Client_context.io_wallet = + let log _channel msg = Logs_lwt.info (fun m -> m "%s" msg) in + object + inherit Client_context.simple_printer log + + inherit dummy_prompter + + inherit faked_wallet ~base_dir ~filesystem + end + +class unix_faked ~base_dir ~filesystem : Client_context.full = + object + inherit faked_io_wallet ~base_dir ~filesystem + + inherit faked_ctxt + + inherit Tezos_client_base_unix.Client_context_unix.unix_ui + + method chain = `Main + + method block = `Head 0 + + method confirmations = None + + method verbose_rpc_error_diagnostics = false + end diff --git a/src/proto_alpha/lib_sc_rollup_node/test/helpers/helpers.ml b/src/proto_alpha/lib_sc_rollup_node/test/helpers/helpers.ml new file mode 100644 index 0000000000000000000000000000000000000000..9b71207218a7fae68970552d11d0936c2fb2ab84 --- /dev/null +++ b/src/proto_alpha/lib_sc_rollup_node/test/helpers/helpers.ml @@ -0,0 +1,285 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 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 + +let uid = ref 0 + +let block_hash_of_level level = + let s = Z.of_int32 level |> Z.to_bits in + let len = String.length s in + let s = + String.init Block_hash.size (fun i -> if i >= len then '\000' else s.[i]) + in + Block_hash.of_string_exn s + +module type S = sig + val with_node_context : + ?constants:Constants.Parametric.t -> + Sc_rollup.Kind.t -> + boot_sector:string -> + ([`Read | `Write] Node_context.t -> + genesis:Sc_rollup_block.t -> + 'a tzresult Lwt.t) -> + 'a tzresult Lwt.t + + val add_l2_genesis_block : + [`Read | `Write] Node_context.t -> + boot_sector:string -> + ((Sc_rollup_block.header, unit) Sc_rollup_block.block, tztrace) result Lwt.t + + val append_l2_block : + [`Read | `Write] Node_context.t -> + ?is_migration_block:bool -> + Sc_rollup.Inbox_message.t trace -> + ((Sc_rollup_block.header, unit) Sc_rollup_block.block, tztrace) result Lwt.t +end + +module Make (PVM : Pvm.S) = struct + module Daemon = Daemon.Make (PVM) + module Components = Daemon.Components + + let default_constants = + let constants = Default_parameters.constants_test in + let sc_rollup = + { + constants.sc_rollup with + arith_pvm_enable = true; + challenge_window_in_blocks = 4032; + commitment_period_in_blocks = 3; + } + in + {constants with sc_rollup} + + let add_l2_genesis_block (node_ctxt : _ Node_context.t) ~boot_sector = + let open Lwt_result_syntax in + let head = + Layer1. + { + hash = Block_hash.zero; + level = Raw_level.to_int32 node_ctxt.genesis_info.level; + } + in + let* () = Node_context.save_level node_ctxt head in + let predecessor = head in + let predecessor_timestamp = Time.Protocol.epoch in + let inbox = + Sc_rollup.Inbox.genesis + ~predecessor_timestamp + ~predecessor:predecessor.hash + node_ctxt.genesis_info.level + in + let* inbox_hash = Node_context.save_inbox node_ctxt inbox in + let inbox_witness = Sc_rollup.Inbox.current_witness inbox in + let ctxt = Context.empty node_ctxt.context in + let num_ticks = 0L in + let initial_tick = Sc_rollup.Tick.initial in + let*! initial_state = PVM.initial_state ~empty:(PVM.State.empty ()) in + let*! state = PVM.install_boot_sector initial_state boot_sector in + let*! genesis_state_hash = PVM.state_hash state in + let*! ctxt = PVM.State.set ctxt state in + let*! context_hash = Context.commit ctxt in + let commitment = + Sc_rollup.Commitment.genesis_commitment + ~origination_level:node_ctxt.genesis_info.level + ~genesis_state_hash + in + let* commitment_hash = Node_context.save_commitment node_ctxt commitment in + let previous_commitment_hash = node_ctxt.genesis_info.commitment_hash in + let header = + Sc_rollup_block. + { + block_hash = head.hash; + level = node_ctxt.genesis_info.level; + predecessor = predecessor.hash; + commitment_hash = Some commitment_hash; + previous_commitment_hash; + context = context_hash; + inbox_witness; + inbox_hash; + } + in + let l2_block = + Sc_rollup_block.{header; content = (); num_ticks; initial_tick} + in + let* () = Node_context.save_l2_head node_ctxt l2_block in + return l2_block + + let initialize_node_context ?(constants = default_constants) kind ~boot_sector + = + let open Lwt_result_syntax in + incr uid ; + (* To avoid any conflict with previous runs of this test. *) + let pid = Unix.getpid () in + let data_dir = + Filename.(concat @@ get_temp_dir_name ()) + (Format.sprintf "sc-rollup-node-test-%d-%d" pid !uid) + in + let base_dir = + Filename.(concat @@ get_temp_dir_name ()) + (Format.sprintf "sc-rollup-node-test-base-%d-%d" pid !uid) + in + let filesystem = String.Hashtbl.create 10 in + let cctxt = + new Protocol_client_context.wrap_full + (new Faked_client_context.unix_faked ~base_dir ~filesystem) + in + let* ctxt = + Node_context.Internal_for_tests.create_node_context + cctxt + ~constants + ~data_dir + kind + in + let* genesis = add_l2_genesis_block ctxt ~boot_sector in + let commitment_hash = + WithExceptions.Option.get ~loc:__LOC__ genesis.header.commitment_hash + in + let ctxt = + {ctxt with genesis_info = {ctxt.genesis_info with commitment_hash}} + in + return (ctxt, genesis) + + let with_node_context ?constants kind ~boot_sector f = + let open Lwt_result_syntax in + let* node_ctxt, genesis = + initialize_node_context ?constants kind ~boot_sector + in + Lwt.finalize (fun () -> f node_ctxt ~genesis) @@ fun () -> + let open Lwt_syntax in + let* _ = Node_context.close node_ctxt in + return_unit + + let append_l2_block (node_ctxt : _ Node_context.t) + ?(is_migration_block = false) messages = + let open Lwt_result_syntax in + let* predecessor_l2_block = + Node_context.last_processed_head_opt node_ctxt + in + let* predecessor_l2_block = + match predecessor_l2_block with + | Some b -> return b + | None -> + failwith "No genesis block, please add one with add_l2_genesis_block" + in + let level = + Raw_level.(to_int32 @@ succ predecessor_l2_block.header.level) + in + let hash = block_hash_of_level level in + let predecessor = + Layer1. + { + hash = predecessor_l2_block.header.block_hash; + level = Raw_level.to_int32 predecessor_l2_block.header.level; + } + in + let head = Layer1.{hash; level} in + let predecessor_timestamp = + Time.Protocol.of_seconds (Int64.of_int32 level) + in + Daemon.Internal_for_tests.process_messages + node_ctxt + ~is_migration_block + ~predecessor + ~predecessor_timestamp + head + messages +end + +let l2_chain_builders = + List.map + (fun kind -> + let module PVM = (val Components.pvm_of_kind kind) in + (kind, (module Make (PVM) : S))) + Sc_rollup.Kind.all + +let l2_chain_builder kind = Stdlib.List.assoc kind l2_chain_builders + +let with_node_context ?constants kind ~boot_sector = + let module L = (val l2_chain_builder kind) in + L.with_node_context ?constants kind ~boot_sector + +let add_l2_genesis_block (node_ctxt : _ Node_context.t) = + let module L = (val l2_chain_builder node_ctxt.kind) in + L.add_l2_genesis_block node_ctxt + +let append_l2_block (node_ctxt : _ Node_context.t) = + let module L = (val l2_chain_builder node_ctxt.kind) in + L.append_l2_block node_ctxt + +let append_l2_blocks node_ctxt message_batches = + List.map_es (append_l2_block node_ctxt) message_batches + +let append_dummy_l2_chain node_ctxt ~length = + let open Lwt_result_syntax in + let* head = Node_context.last_processed_head_opt node_ctxt in + let head_level = + match head with + | None -> 0 + | Some h -> h.header.level |> Raw_level.to_int32 |> Int32.to_int + in + let batches = + Stdlib.List.init length (fun i -> + [ + Sc_rollup.Inbox_message.External + (Z.to_bits (Z.of_int (i + head_level + 1))); + ]) + in + append_l2_blocks node_ctxt batches + +module Assert = struct + module Make_with_encoding (X : sig + type t + + val encoding : t Data_encoding.t + end) = + Assert.Make_equalities (struct + type t = X.t + + let eq (b1 : X.t) (b2 : X.t) = + Bytes.equal + (Data_encoding.Binary.to_bytes_exn X.encoding b1) + (Data_encoding.Binary.to_bytes_exn X.encoding b2) + + let pp ppf (b : X.t) = + Data_encoding.Json.pp ppf (Data_encoding.Json.construct X.encoding b) + end) + + module L2_block = Make_with_encoding (Sc_rollup_block) + module Commitment = Make_with_encoding (Sc_rollup.Commitment) + module Commitment_hash = Make_with_encoding (Sc_rollup.Commitment.Hash) + module State_hash = Make_with_encoding (Sc_rollup.State_hash) +end + +let alcotest name speed ?constants kind ~boot_sector f = + Alcotest_lwt.test_case name speed @@ fun _lwt_switch () -> + let open Lwt_result_syntax in + let*! r = with_node_context ?constants kind ~boot_sector f in + match r with + | Ok () -> Lwt.return_unit + | Error err -> + Format.printf "@\n%a@." pp_print_trace err ; + Lwt.fail Alcotest.Test_error diff --git a/src/proto_alpha/lib_sc_rollup_node/test/helpers/helpers.mli b/src/proto_alpha/lib_sc_rollup_node/test/helpers/helpers.mli new file mode 100644 index 0000000000000000000000000000000000000000..252b6b9eaf91cdca59a66a553ebc2fad9314a88d --- /dev/null +++ b/src/proto_alpha/lib_sc_rollup_node/test/helpers/helpers.mli @@ -0,0 +1,116 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 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 + +(** {1 Helper functions to build and run unit tests for the rollup node} *) + +(** {2 Creating Node Contexts} *) + +(** [with_node_context ?constants kind ~boot_sector f] creates a node context + and (with a store, a context, etc.) where protocol [constants] can be + specified, and runs [f] with this node context. The L2 chain is initialized + with a genesis block and the PVM with the [boot_sector]. When [f] terminates + or fails, the created node context is closed properly. Test that need a node + context need to use this function in order to avoid file descriptor + leaks. *) +val with_node_context : + ?constants:Constants.Parametric.t -> + Sc_rollup.Kind.t -> + boot_sector:string -> + ([`Read | `Write] Node_context.t -> + genesis:Sc_rollup_block.t -> + 'a tzresult Lwt.t) -> + 'a tzresult Lwt.t + +(** {2 Building L2 Chains} *) + +(** Create and add a genesis block for the L2 chain. The [boot_sector] for the + rollup/kernel needs to be provided. The newly created L2 block is + returned. *) +val add_l2_genesis_block : + [`Read | `Write] Node_context.t -> + boot_sector:string -> + Sc_rollup_block.t tzresult Lwt.t + +(** [append_l2_block node_ctxt ?is_migration_block messages] creates and append + an L2 block containing the [messages] given in argument. The block is added + on top of the last L2 block in the chain (i.e. the head known by the node), + and is returned. *) +val append_l2_block : + [`Read | `Write] Node_context.t -> + ?is_migration_block:bool -> + Sc_rollup.Inbox_message.t list -> + Sc_rollup_block.t tzresult Lwt.t + +(** [append_l2_block node_ctxt message_batches] appends as many blocks as there + are batches in [message_batches]. Each block contain a batch of + messages. The portion of the chain that was added is returned. *) +val append_l2_blocks : + [`Read | `Write] Node_context.t -> + Sc_rollup.Inbox_message.t list list -> + Sc_rollup_block.t list tzresult Lwt.t + +(** [append_dummy_l2_chain node_ctxt ~length] append [length] L2 blocks with an + arbitrary content to the chain. The portion of the chain that was added is + returned. This function is useful for quickly building long(er) L2 chains + for the tests. *) +val append_dummy_l2_chain : + [`Read | `Write] Node_context.t -> + length:int -> + Sc_rollup_block.t list tzresult Lwt.t + +(** {2 Assertions} *) + +module Assert : sig + (** Assertions on L2 blocks *) + module L2_block : Assert.EQUALITIES with type t = Sc_rollup_block.t + + (** Assertions on commitments *) + module Commitment : Assert.EQUALITIES with type t = Sc_rollup.Commitment.t + + (** Assertions on commitment hashes *) + module Commitment_hash : + Assert.EQUALITIES with type t = Sc_rollup.Commitment.Hash.t + + (** Assertions on PVM state hashes *) + module State_hash : Assert.EQUALITIES with type t = Sc_rollup.State_hash.t +end + +(** {2 Building and Running tests} *) + +(** Build an alcotest test case that executes with node context initialized with + a genesis block with the provided [boot_sector]. *) +val alcotest : + string -> + Alcotest.speed_level -> + ?constants:Constants.Parametric.t -> + Sc_rollup.Kind.t -> + boot_sector:string -> + ([`Read | `Write] Node_context.t -> + genesis:Sc_rollup_block.t -> + unit tzresult Lwt.t) -> + unit Alcotest_lwt.test_case diff --git a/tezt/tests/dune b/tezt/tests/dune index f1d8e60280c97de2f37eada22a22c653f912032a..e503505f98397639577a1ecfb4a1ae4c8c605c7f 100644 --- a/tezt/tests/dune +++ b/tezt/tests/dune @@ -16,6 +16,7 @@ tezos-stdlib-unix tezos-protocol-alpha tezt_self_tests_tezt_lib + src_proto_alpha_lib_sc_rollup_node_test_tezt_lib src_proto_alpha_lib_protocol_test_unit_tezt_lib src_proto_alpha_lib_protocol_test_regression_tezt_lib src_proto_alpha_lib_protocol_test_pbt_tezt_lib @@ -30,6 +31,7 @@ src_proto_alpha_lib_dal_test_tezt_lib src_proto_alpha_lib_dac_plugin_test_tezt_lib src_proto_alpha_lib_client_test_tezt_lib + src_proto_016_PtMumbai_lib_sc_rollup_node_test_tezt_lib src_proto_016_PtMumbai_lib_protocol_test_unit_tezt_lib src_proto_016_PtMumbai_lib_protocol_test_regression_tezt_lib src_proto_016_PtMumbai_lib_protocol_test_pbt_tezt_lib diff --git a/tezt/tests/sc_rollup.ml b/tezt/tests/sc_rollup.ml index 32bc33d8db6715194aabd963e51aa7aa929f1749..63665a0dce4148d8cea7ad0fc46b1fbf31f106db 100644 --- a/tezt/tests/sc_rollup.ml +++ b/tezt/tests/sc_rollup.ml @@ -2747,12 +2747,7 @@ let test_refutation_scenario ?commitment_period ?challenge_window ~variant ~mode in gather_dissections () in - let* () = - Sc_rollup_node.run - ~event_sections_levels:[("sc_rollup_node.refutation_game", `Debug)] - sc_rollup_node - [] - in + let* () = Sc_rollup_node.run ~event_level:`Debug sc_rollup_node [] in return [ gather_conflicts_promise;