From 2887ab32082b50bde7a6247ec3de9be2eb429a14 Mon Sep 17 00:00:00 2001 From: Ilya Peresadin Date: Fri, 9 Jun 2023 16:47:33 +0100 Subject: [PATCH] Sequencer, Tezt: Add sequencer tezt to check encoding matches --- .dockerignore | 3 +- .gitlab/ci/jobs/build/kernels.yml | 1 + .gitlab/ci/jobs/shared/templates.yml | 1 + kernels.mk | 4 +- src/kernel_sequencer/Cargo.lock | 9 + src/kernel_sequencer/Cargo.toml | 6 +- .../examples/sequenced_kernel.rs | 16 +- src/kernel_sequencer/src/delayed_inbox.rs | 22 +- src/kernel_sequencer/src/message.rs | 2 +- src/lib_scoru_sequencer/seq_batcher.ml | 26 +- tezt/lib_tezos/sc_rollup_client.ml | 11 - tezt/lib_tezos/sc_rollup_node.ml | 10 + tezt/lib_tezos/sc_rollup_node.mli | 16 ++ tezt/tests/main.ml | 1 + tezt/tests/sc_sequencer.ml | 222 ++++++++++++++++++ 15 files changed, 320 insertions(+), 30 deletions(-) create mode 100644 tezt/tests/sc_sequencer.ml diff --git a/.dockerignore b/.dockerignore index f84a78de1cd7..35093a909902 100644 --- a/.dockerignore +++ b/.dockerignore @@ -77,4 +77,5 @@ _coverage_report # Rust target -evm_kernel.wasm \ No newline at end of file +evm_kernel.wasm +sequenced_kernel.wasm \ No newline at end of file diff --git a/.gitlab/ci/jobs/build/kernels.yml b/.gitlab/ci/jobs/build/kernels.yml index 7495d0da7ec4..2c47422a6700 100644 --- a/.gitlab/ci/jobs/build/kernels.yml +++ b/.gitlab/ci/jobs/build/kernels.yml @@ -11,5 +11,6 @@ build_kernels: paths: - evm_kernel.wasm - smart-rollup-installer + - sequenced_kernel.wasm expire_in: 1 day when: on_success diff --git a/.gitlab/ci/jobs/shared/templates.yml b/.gitlab/ci/jobs/shared/templates.yml index 75e6d8a1a5e0..0dbf38f63ea0 100644 --- a/.gitlab/ci/jobs/shared/templates.yml +++ b/.gitlab/ci/jobs/shared/templates.yml @@ -54,6 +54,7 @@ name: "build-kernels-$CI_COMMIT_REF_SLUG" paths: - evm_kernel.wasm + - sequenced_kernel.wasm - smart-rollup-installer expire_in: 1 day when: on_success diff --git a/kernels.mk b/kernels.mk index b87bad1fdb69..b6e1c76fceed 100644 --- a/kernels.mk +++ b/kernels.mk @@ -1,4 +1,4 @@ -KERNELS = evm_kernel.wasm +KERNELS = evm_kernel.wasm sequenced_kernel.wasm SDK_DIR=src/kernel_sdk EVM_DIR=src/kernel_evm SEQUENCER_DIR=src/kernel_sequencer @@ -37,7 +37,7 @@ sequenced_kernel.wasm: @wasm-strip $@ .PHONY: build -build: ${KERNELS} kernel_sdk sequenced_kernel.wasm +build: ${KERNELS} kernel_sdk .PHONY: build-dev-deps build-dev-deps: build-deps diff --git a/src/kernel_sequencer/Cargo.lock b/src/kernel_sequencer/Cargo.lock index ec9b9d95b25b..04daf7ab571f 100644 --- a/src/kernel_sequencer/Cargo.lock +++ b/src/kernel_sequencer/Cargo.lock @@ -348,6 +348,7 @@ version = "0.1.0" dependencies = [ "nom", "tezos-smart-rollup-core", + "tezos-smart-rollup-debug", "tezos-smart-rollup-encoding", "tezos-smart-rollup-host", "tezos-smart-rollup-mock", @@ -766,6 +767,14 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" name = "tezos-smart-rollup-core" version = "0.2.0" +[[package]] +name = "tezos-smart-rollup-debug" +version = "0.2.0" +dependencies = [ + "tezos-smart-rollup-core", + "tezos-smart-rollup-host", +] + [[package]] name = "tezos-smart-rollup-encoding" version = "0.2.0" diff --git a/src/kernel_sequencer/Cargo.toml b/src/kernel_sequencer/Cargo.toml index 6a9a8784a239..5e8c913cd9a3 100644 --- a/src/kernel_sequencer/Cargo.toml +++ b/src/kernel_sequencer/Cargo.toml @@ -31,7 +31,7 @@ version = "0.5" [dependencies.tezos_data_encoding_derive] version = "0.5" -[dependencies.nom] +[dependencies.nom] version = "7.1" [dependencies.tezos_crypto_rs] @@ -42,6 +42,10 @@ default-features = false path = "../kernel_sdk/encoding" version = "0.2.0" +[dependencies.tezos-smart-rollup-debug] +path = "../kernel_sdk/debug" +version = "0.2.0" + [dev-dependencies.tezos_crypto_rs] version = "0.5.0" default-features = false diff --git a/src/kernel_sequencer/examples/sequenced_kernel.rs b/src/kernel_sequencer/examples/sequenced_kernel.rs index d7acb38371cb..4bb5c05a7d01 100644 --- a/src/kernel_sequencer/examples/sequenced_kernel.rs +++ b/src/kernel_sequencer/examples/sequenced_kernel.rs @@ -3,9 +3,23 @@ // SPDX-License-Identifier: MIT use kernel_sequencer::sequencer_kernel_entry; +use tezos_smart_rollup_debug::debug_msg; use tezos_smart_rollup_host::runtime::Runtime; -pub fn kernel_loop(_host: &mut Host) {} +pub fn kernel_loop(host: &mut Host) { + while let Ok(Some(message)) = host.read_input() { + debug_msg!( + host, + "Processing MessageData {} at level {}", + message.id, + message.level + ); + + if let Err(e) = host.mark_for_reboot() { + debug_msg!(host, "Could not mark host for reboot: {}", e); + } + } +} sequencer_kernel_entry!( kernel_loop, diff --git a/src/kernel_sequencer/src/delayed_inbox.rs b/src/kernel_sequencer/src/delayed_inbox.rs index 087a506b7f0d..0504b886b29d 100644 --- a/src/kernel_sequencer/src/delayed_inbox.rs +++ b/src/kernel_sequencer/src/delayed_inbox.rs @@ -5,6 +5,7 @@ use tezos_data_encoding::nom::NomReader; use tezos_data_encoding_derive::BinWriter; +use tezos_smart_rollup_debug::debug_msg; use tezos_smart_rollup_encoding::smart_rollup::SmartRollupAddress; use tezos_smart_rollup_host::{ input::Message, @@ -53,7 +54,12 @@ pub fn read_input( KernelMessage::Sequencer(Framed { destination, payload: SequencerMsg::Sequence(sequence), - }) => handle_sequence_message(sequence, destination, &raw_rollup_address), + }) => handle_sequence_message( + host, + sequence, + destination, + &raw_rollup_address, + ), KernelMessage::Sequencer(Framed { destination, payload: SequencerMsg::SetSequencer(set_sequence), @@ -82,11 +88,17 @@ pub fn read_input( /// Handle Sequence message fn handle_sequence_message( - _sequence: Sequence, + host: &impl Runtime, + sequence: Sequence, destination: SmartRollupAddress, rollup_address: &[u8; RAW_ROLLUP_ADDRESS_SIZE], ) { if destination.hash().as_ref() == rollup_address { + debug_msg!( + host, + "Received a sequence message {:?} targeting our rollup", + sequence + ); // process the sequence } } @@ -113,6 +125,12 @@ fn handle_message( ) -> Result<(), RuntimeError> { // Check if the message should be included in the delayed inbox if filter_behavior.predicate(user_message.as_ref(), rollup_address) { + debug_msg!( + host, + "Received user message {:?} targeting our rollup, hence, will be added to the delayed inbox", + user_message + ); + // add the message to the delayed inbox let user_message = UserMessage { timeout_level: level + timeout_window, diff --git a/src/kernel_sequencer/src/message.rs b/src/kernel_sequencer/src/message.rs index 8ecc5d5e80e1..8f5f85825d9d 100644 --- a/src/kernel_sequencer/src/message.rs +++ b/src/kernel_sequencer/src/message.rs @@ -40,7 +40,7 @@ pub struct Bytes { /// The sequence contains the number of messages /// that should be processed from the delayed inbox /// and the messages from the sequencer -/// +/// /// The number of messages that should be processed /// from the delayed inbox is divided into two parts /// delayed_messages_prefix and delayed_messages_suffix diff --git a/src/lib_scoru_sequencer/seq_batcher.ml b/src/lib_scoru_sequencer/seq_batcher.ml index bddb569f604d..c62e1de11282 100644 --- a/src/lib_scoru_sequencer/seq_batcher.ml +++ b/src/lib_scoru_sequencer/seq_batcher.ml @@ -91,7 +91,7 @@ let get_previous_delayed_inbox_size node_ctxt (head : Layer1.head) = | Some pointer_bytes -> return @@ Option.fold ~none:0 ~some:(fun x -> - Int32.(to_int @@ succ @@ sub x.Delayed_inbox_pointer.tail x.head)) + Int32.(to_int @@ sub x.Delayed_inbox_pointer.tail x.head)) @@ Data_encoding.Binary.of_bytes_opt Delayed_inbox_pointer.encoding pointer_bytes @@ -112,16 +112,20 @@ let get_batch_sequences state head = l2_messages |> Environment.wrap_tzresult in - return - ( [ - ( Kernel_message.encode_sequence_message - state.node_ctxt.rollup_address - ~prefix:(Int32.of_int (delayed_inbox_size - 1)) - ~suffix:1l - l2_messages_serialized, - l2_messages ); - ], - delayed_inbox_size ) + if delayed_inbox_size = 0 then + (* That might happen only for the genesis + 1 block level *) + return ([], 0) + else + return + ( [ + ( Kernel_message.encode_sequence_message + state.node_ctxt.rollup_address + ~prefix:(Int32.of_int (delayed_inbox_size - 1)) + ~suffix:1l + l2_messages_serialized, + l2_messages ); + ], + delayed_inbox_size ) let produce_batch_sequences state head = let open Lwt_result_syntax in diff --git a/tezt/lib_tezos/sc_rollup_client.ml b/tezt/lib_tezos/sc_rollup_client.ml index 4f585f5c63f8..aba8280f771b 100644 --- a/tezt/lib_tezos/sc_rollup_client.ml +++ b/tezt/lib_tezos/sc_rollup_client.ml @@ -285,17 +285,6 @@ let inspect_durable_state_value : rpc_req () |> Runnable.map (fun json -> List.map JSON.as_string (JSON.as_list json)) -(* match expected with - | Expected_success -> ( - let*! json = rpc_req () in - match operation with - | Value -> return (JSON.as_string json : a) - | Length -> return (JSON.as_int64 json : a) - | Subkeys -> return (List.map JSON.as_string (JSON.as_list json))) - | Expected_error msg -> - let*? process = rpc_req () in - Process.check_error ~msg process *) - let ticks ?hooks ?(block = "head") sc_client = let res = rpc_get ?hooks sc_client ["global"; "block"; block; "ticks"] in Runnable.map JSON.as_int res diff --git a/tezt/lib_tezos/sc_rollup_node.ml b/tezt/lib_tezos/sc_rollup_node.ml index fc4b262aed3f..9a8c16017cb2 100644 --- a/tezt/lib_tezos/sc_rollup_node.ml +++ b/tezt/lib_tezos/sc_rollup_node.ml @@ -394,6 +394,16 @@ let run ?legacy ?event_level ?event_sections_levels ?loser_mode let* () = if wait_ready then wait_for_ready node else unit in return () +let run_sequencer ?event_level ?event_sections_levels ?(wait_ready = true) node + rollup_address extra_arguments = + let cmd = + ["run"; "for"; rollup_address; "with"; "operator"] + @ operators_params node @ common_node_args node @ extra_arguments + in + let* () = do_runlike_command ?event_level ?event_sections_levels node cmd in + let* () = if wait_ready then wait_for_ready node else unit in + return () + let spawn_run node rollup_address extra_arguments = let mode, args = node_args node rollup_address in spawn_command node (["run"; mode] @ args @ extra_arguments) diff --git a/tezt/lib_tezos/sc_rollup_node.mli b/tezt/lib_tezos/sc_rollup_node.mli index 841eef6dd7b0..668ccf1f59da 100644 --- a/tezt/lib_tezos/sc_rollup_node.mli +++ b/tezt/lib_tezos/sc_rollup_node.mli @@ -147,6 +147,22 @@ val run : string list -> unit Lwt.t +(** [run_sequencer ?event_level ?event_sections_levels ?wait_ready node + rollup_address arguments] launches the sequencer node for + the rollup at [rollup_address] with the given extra arguments. + [event_level] and [event_sections_levels] allow to select which events we + want the node to emit (see {!Daemon}). + If [wait_ready] is [false], tezt does not wait for the node to be + ready. *) +val run_sequencer : + ?event_level:Daemon.Level.default_level -> + ?event_sections_levels:(string * Daemon.Level.level) list -> + ?wait_ready:bool -> + t -> + string -> + string list -> + unit Lwt.t + (** [spawn_run node rollup_address arguments] is a lightweight version of {!run} that spawns a process. *) val spawn_run : t -> string -> string list -> Process.t diff --git a/tezt/tests/main.ml b/tezt/tests/main.ml index 7257c1dde129..9e959dbf8e01 100644 --- a/tezt/tests/main.ml +++ b/tezt/tests/main.ml @@ -224,6 +224,7 @@ let register_protocol_specific_because_regression_tests () = (* TODO: https://gitlab.com/tezos/tezos/-/issues/4652 re-enable Mumbai when DAC is separated from Dal node. *) Tx_sc_rollup.register ~protocols:[Alpha] ; + Sc_sequencer.register ~protocols:[Alpha] ; Snoop_codegen.register ~protocols:[Alpha] ; Timelock.register ~protocols:[Alpha] ; Timelock_disabled.register ~protocols:[Mumbai] diff --git a/tezt/tests/sc_sequencer.ml b/tezt/tests/sc_sequencer.ml new file mode 100644 index 000000000000..e0aaab0f2b4e --- /dev/null +++ b/tezt/tests/sc_sequencer.ml @@ -0,0 +1,222 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs *) +(* Copyright (c) 2023 TriliTech *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION 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 Optimistic Rollups: Sequencer + Invocation: dune exec tezt/tests/main.exe -- --file sc_sequencer.ml +*) + +open Sc_rollup_helpers +open Tezos_protocol_alpha.Protocol + +let pvm_kind = "wasm_2_0_0" + +type full_sequencer_setup = { + node : Node.t; + client : Client.t; + sc_sequencer_node : Sc_rollup_node.t; + sc_rollup_client : Sc_rollup_client.t; + sc_rollup_address : string; + originator_key : string; + sequencer_key : string; +} + +let next_rollup_level {node; client; sc_sequencer_node; _} = + let* () = Client.bake_for_and_wait client in + Sc_rollup_node.wait_for_level + ~timeout:30. + sc_sequencer_node + (Node.get_level node) + +let setup_sequencer_kernel + ?(originator_key = Constant.bootstrap1.public_key_hash) + ?(sequencer_key = Constant.bootstrap1.public_key_hash) protocol = + let* node, client = setup_l1 protocol in + let sc_sequencer_node = + Sc_rollup_node.create + Custom + node + ~path:"./octez-smart-rollup-sequencer-node" + ~base_dir:(Client.base_dir client) + ~default_operator:sequencer_key + in + (* Prepare sequencer kernel & originate it *) + let* boot_sector = + prepare_installer_kernel + ~base_installee:"./" + ~preimages_dir: + (Filename.concat + (Sc_rollup_node.data_dir sc_sequencer_node) + "wasm_2_0_0") + "sequenced_kernel" + in + let* sc_rollup_address = + originate_sc_rollup + ~kind:pvm_kind + ~boot_sector + ~parameters_ty:"unit" + ~src:originator_key + client + in + (* Start a sequencer node *) + let* () = + Sc_rollup_node.run_sequencer + sc_sequencer_node + sc_rollup_address + ["--log-kernel-debug"] + in + let sc_rollup_client = Sc_rollup_client.create ~protocol sc_sequencer_node in + return + { + node; + client; + sc_sequencer_node; + sc_rollup_client; + sc_rollup_address; + originator_key; + sequencer_key; + } + +let wrap_with_framed rollup_address msg = + (* Byte from framing protocol, then smart rollup address, then message bytes *) + String.concat + "" + [ + "\000"; + Data_encoding.Binary.to_string_exn + Sc_rollup_repr.Address.encoding + rollup_address; + msg; + ] + +let send_message ~src client raw_msg = + Client.Sc_rollup.send_message + ~hooks + ~src + ~msg:(sf "hex:[%S]" @@ hex_encode raw_msg) + client + +let wait_for_sequence_debug_message sc_node = + Sc_rollup_node.wait_for sc_node "kernel_debug.v0" @@ fun json -> + let message = JSON.as_string json in + if String.starts_with ~prefix:"Received a sequence message" message then + Some message + else None + +let test_delayed_inbox_consumed = + Protocol.register_test + ~__FILE__ + ~tags:["sequencer"] + ~title:"Originate sequencer kernel & consume delayed inbox messages" + @@ fun protocol -> + let* ({client; sc_rollup_address; sc_sequencer_node; _} as setup) = + setup_sequencer_kernel protocol + in + let sc_rollup_address = + Sc_rollup_repr.Address.of_b58check_exn sc_rollup_address + in + let* () = + send_message ~src:Constant.bootstrap2.alias client + @@ wrap_with_framed sc_rollup_address "\000\000\000" + in + let* () = + send_message ~src:Constant.bootstrap3.alias client + @@ wrap_with_framed sc_rollup_address "\000\000\001" + in + + (* Start async collection of sequence debug messages from the kernel *) + let collected_sequences = ref [] in + let _ = + let rec collect_sequences () = + let* c = wait_for_sequence_debug_message sc_sequencer_node in + collected_sequences := c :: !collected_sequences ; + collect_sequences () + in + collect_sequences () + in + + (* Bake block with those user messages, which has level 3, origination level is 2 *) + let* _ = next_rollup_level setup in + + (* At this moment delayed inbox corresponding to the previous block is empty, + hence, no Sequences have been batched. *) + + (* Bake a block with level 4 *) + let* _ = next_rollup_level setup in + + (* At this moment delayed inbox corresponding to the previous block have 5 messages: + [SoL, IpL, "\000\000\000", "\000\000\001", EoL]. + Seq_batcher has batched a Sequence with + 5 delayed inbox messages and 0 L2 messages, which denoted S1. + *) + + (* Bake a block with level 5, no injected batches here *) + let* _ = next_rollup_level setup in + + (* At this moment delayed inbox corresponding to the previous block have 8 messages: + [SoL3, IpL3, "\000\000\000", "\000\000\001", EoL3, SoL4, IpL4, EoL4]. + For now no delayed inbox messages consumed, so we just expect delayed inbox messages being accumulated. + Seq_batcher has batched a Sequence with + 8 delayed inbox messages and 0 L2 messages, which denoted S2. + *) + + (* Inject S1 into an upcoming block with level 6 *) + + (* Bake a block with level 6, containing S1 *) + let* _ = next_rollup_level setup in + + (* Feed to the sequencer kernel S1 sequence *) + + (* Inject S2 into an upcoming block with level 7 *) + (* Following S3 is not going to be injected within this test, so we ingore consideration of it *) + + (* Bake a block with level 7, containing S2 *) + let* _ = next_rollup_level setup in + + (* Feed to the sequencer kernel S2 sequence *) + let expected_sequences = + List.map (fun (delayed_inbox_prefix, delayed_inbox_suffix) -> + Format.sprintf + "Received a sequence message Sequence { nonce: 0, \ + delayed_messages_prefix: %d, delayed_messages_suffix: %d, messages: \ + [], signature: \ + Signature(\"edsigtXomBKi5CTRf5cjATJWSyaRvhfYNHqSUGrn4SdbYRcGwQrUGjzEfQDTuqHhuA8b2d8NarZjz8TRf65WkpQmo423BtomS8Q\") \ + } targeting our rollup" + delayed_inbox_prefix + delayed_inbox_suffix) + @@ [(4, 1); (7, 1)] + in + Check.( + ( = ) + expected_sequences + (List.rev !collected_sequences) + ~__LOC__ + (list string) + ~error_msg:"Unexpected debug messages emitted") ; + Lwt.return_unit + +let register ~protocols = test_delayed_inbox_consumed protocols -- GitLab