diff --git a/src/lib_layer2_store/irmin_context.ml b/src/lib_layer2_store/irmin_context.ml index 02545e022c64c71590c11434eea4c0f3d5aaf140..de8e476d125a2c31b844d16232dbab359746951a 100644 --- a/src/lib_layer2_store/irmin_context.ml +++ b/src/lib_layer2_store/irmin_context.ml @@ -3,6 +3,7 @@ (* Open Source License *) (* Copyright (c) 2021 Nomadic Labs, *) (* Copyright (c) 2023 Marigold *) +(* Copyright (c) 2024 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -49,6 +50,8 @@ type repo = IStore.Repo.t type tree = IStore.tree +type mut_state = tree ref + type 'a raw_index = ('a, repo) Context_sigs.raw_index type 'a index = ('a, repo) Context_sigs.index @@ -93,6 +96,10 @@ let impl_name = "Irmin" let equality_witness : (repo, tree) Context_sigs.equality_witness = (Context_sigs.Equality_witness.make (), Context_sigs.Equality_witness.make ()) +let from_imm imm_state = ref imm_state + +let to_imm mut_state = !mut_state + let context_hash_of_hash h = IStore.Hash.to_raw_string h |> Smart_rollup_context_hash.of_string_exn diff --git a/src/lib_layer2_store/irmin_context.mli b/src/lib_layer2_store/irmin_context.mli index f06adc938248b81b1bdf28f8bf265fe04c40d32d..5473f96cdbb821a15b023318fb5693f7923fcd92 100644 --- a/src/lib_layer2_store/irmin_context.mli +++ b/src/lib_layer2_store/irmin_context.mli @@ -3,6 +3,7 @@ (* Open Source License *) (* Copyright (c) 2021 Nomadic Labs, *) (* Copyright (c) 2023 Marigold *) +(* Copyright (c) 2024 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -31,6 +32,8 @@ type repo (** The type of trees stored in the context, i.e. the actual data. *) type tree +type mut_state = tree ref + type 'a raw_index = ('a, repo) Context_sigs.raw_index (** The type of indexed repository for contexts. The parameter indicates if the @@ -70,6 +73,10 @@ val impl_name : string val equality_witness : (repo, tree) Context_sigs.equality_witness +val from_imm : tree -> mut_state + +val to_imm : mut_state -> tree + (** [load cache_size path] initializes from disk a context from [path]. [cache_size] allows to change the LRU cache size of Irmin (100_000 by default at irmin-pack/config.ml *) diff --git a/src/lib_layer2_store/riscv_context.ml b/src/lib_layer2_store/riscv_context.ml index 4bb42eff65c3f091996e0f0d8cf0250b193796d8..a938bd252ff55b5e6f699d5cfad653d37573b3e6 100644 --- a/src/lib_layer2_store/riscv_context.ml +++ b/src/lib_layer2_store/riscv_context.ml @@ -2,6 +2,7 @@ (* *) (* SPDX-License-Identifier: MIT *) (* Copyright (c) 2024 Nomadic Labs *) +(* Copyright (c) 2024 TriliTech *) (* *) (*****************************************************************************) @@ -13,6 +14,8 @@ type repo = Storage.Repo.t type tree = Storage.State.t +type mut_state = tree ref + type 'a raw_index = ('a, repo) Context_sigs.raw_index type 'a index = ('a, repo) Context_sigs.index @@ -21,6 +24,10 @@ type rw_index = [`Read | `Write] index let impl_name = "RISC-V" +let from_imm imm_state = ref imm_state + +let to_imm mut_state = !mut_state + let equality_witness : (repo, tree) Context_sigs.equality_witness = (Context_sigs.Equality_witness.make (), Context_sigs.Equality_witness.make ()) diff --git a/src/proto_alpha/lib_sc_rollup_node/arith_pvm.ml b/src/proto_alpha/lib_sc_rollup_node/arith_pvm.ml index 8369e4cb4265b7a398a4c5d25cfc318e7029251a..b1d87a62deec115f890817ed28e2ea0782194a46 100644 --- a/src/proto_alpha/lib_sc_rollup_node/arith_pvm.ml +++ b/src/proto_alpha/lib_sc_rollup_node/arith_pvm.ml @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022-2023 TriliTech *) +(* Copyright (c) 2022-2024 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -108,6 +108,53 @@ module Impl : Pvm_sig.S = struct else Lwt.return (state, step) in go initial_state 0L + + (** Arith PVM Mutable API works by holding a reference to an immutable state + and wrapping all immutable functionality around the reference *) + module Mutable_state : + Pvm_sig.MUTABLE_STATE_S + with type hash = hash + and type t = Ctxt_wrapper.mut_state = struct + type t = tree ref + + type hash = Sc_rollup.State_hash.t + + let get_tick state = get_tick !state + + let state_hash state = state_hash !state + + let is_input_state ~is_reveal_enabled state = + is_input_state ~is_reveal_enabled !state + + let set_input input state = + let open Lwt_syntax in + let* imm_state = set_input input !state in + state := imm_state ; + return_unit + + let eval_many ~reveal_builtins ~write_debug ~is_reveal_enabled + ?stop_at_snapshot ~max_steps mut_state = + let open Lwt_syntax in + let* imm_state, steps = + eval_many + ~reveal_builtins + ~write_debug + ~is_reveal_enabled + ?stop_at_snapshot + ~max_steps + !mut_state + in + mut_state := imm_state ; + return steps + + module Internal_for_tests = struct + let insert_failure state = + let open Lwt_syntax in + let* imm_state = Internal_for_tests.insert_failure !state in + state := imm_state ; + return_unit + end + end end include Impl diff --git a/src/proto_alpha/lib_sc_rollup_node/context_wrapper.ml b/src/proto_alpha/lib_sc_rollup_node/context_wrapper.ml index 897908e8ebd43c76a383b9f7e04030a9ca01f82a..345c16a13582bfec2965e1c581e0828bb5c512db 100644 --- a/src/proto_alpha/lib_sc_rollup_node/context_wrapper.ml +++ b/src/proto_alpha/lib_sc_rollup_node/context_wrapper.ml @@ -2,6 +2,7 @@ (* *) (* SPDX-License-Identifier: MIT *) (* Copyright (c) 2023-2024 Nomadic Labs *) +(* Copyright (c) 2024 TriliTech *) (* *) (*****************************************************************************) @@ -16,6 +17,8 @@ module type S = sig type tree + type mut_state + val of_node_context : 'a Context.t -> ('a, repo, tree) Context_sigs.t val to_node_context : ('a, repo, tree) Context_sigs.t -> 'a Context.t @@ -23,6 +26,10 @@ module type S = sig val of_node_pvmstate : Context.pvmstate -> tree val to_node_pvmstate : tree -> Context.pvmstate + + val from_imm : tree -> mut_state + + val to_imm : mut_state -> tree end (* Context *) @@ -79,6 +86,8 @@ module Irmin = struct type tree = I.tree + type mut_state = I.mut_state + let of_node_context : 'a Context.t -> ('a, repo, tree) Context_sigs.t = fun ctxt -> of_node_context I.equality_witness ctxt @@ -89,6 +98,10 @@ module Irmin = struct fun c -> of_node_pvmstate I.equality_witness c let to_node_pvmstate : tree -> Context.pvmstate = to_node_pvmstate (module I) + + let from_imm : tree -> mut_state = I.from_imm + + let to_imm : mut_state -> tree = I.to_imm end module Riscv = struct @@ -98,6 +111,8 @@ module Riscv = struct type tree = R.tree + type mut_state = R.mut_state + let of_node_context : 'a Context.t -> ('a, repo, tree) Context_sigs.t = fun ctxt -> of_node_context R.equality_witness ctxt @@ -108,4 +123,8 @@ module Riscv = struct fun c -> of_node_pvmstate R.equality_witness c let to_node_pvmstate : tree -> Context.pvmstate = to_node_pvmstate (module R) + + let from_imm : tree -> mut_state = R.from_imm + + let to_imm : mut_state -> tree = R.to_imm end diff --git a/src/proto_alpha/lib_sc_rollup_node/context_wrapper.mli b/src/proto_alpha/lib_sc_rollup_node/context_wrapper.mli index 0958a7630b753057d7d5471d1ce3328dd1bb8d85..ab68b1c586b0157559f0d748a15d66f33b118a44 100644 --- a/src/proto_alpha/lib_sc_rollup_node/context_wrapper.mli +++ b/src/proto_alpha/lib_sc_rollup_node/context_wrapper.mli @@ -2,19 +2,24 @@ (* *) (* SPDX-License-Identifier: MIT *) (* Copyright (c) 2023-2024 Nomadic Labs *) +(* Copyright (c) 2024 TriliTech *) (* *) (*****************************************************************************) val err_implementation_mismatch : got:string -> 'a (** Context wrappers translate from/to node-context and node-pvmstate - PVMs internal representation to those used in the PVM. Each - different PVM context will imply a dedicated wrapper.*) + PVMs internal representation to those used in the PVM. + Also provides conversion functions from/to mutable and immutable PVM types. + Each different PVM context will imply a dedicated wrapper.*) module type S = sig type repo type tree + (** Type used by the mutable API for PVMs *) + type mut_state + val of_node_context : 'a Context.t -> ('a, repo, tree) Context_sigs.t val to_node_context : ('a, repo, tree) Context_sigs.t -> 'a Context.t @@ -22,12 +27,22 @@ module type S = sig val of_node_pvmstate : Context.pvmstate -> tree val to_node_pvmstate : tree -> Context.pvmstate + + val from_imm : tree -> mut_state + + val to_imm : mut_state -> tree end (** Specialized module to handle translation to/from Irmin_context. Directly used in Arith, Wasm_2_0_0 and RISC-V PVM *) module Irmin : - S with type repo = Irmin_context.repo and type tree = Irmin_context.tree + S + with type repo = Irmin_context.repo + and type tree = Irmin_context.tree + and type mut_state = Irmin_context.mut_state module Riscv : - S with type repo = Riscv_context.repo and type tree = Riscv_context.tree + S + with type repo = Riscv_context.repo + and type tree = Riscv_context.tree + and type mut_state = Riscv_context.mut_state diff --git a/src/proto_alpha/lib_sc_rollup_node/pvm_sig.ml b/src/proto_alpha/lib_sc_rollup_node/pvm_sig.ml index 7afc012df23ebd132f64eebafa54048e36ac3c6c..b7438784d2c8eb6feda688caa19d919d2bb2fa30 100644 --- a/src/proto_alpha/lib_sc_rollup_node/pvm_sig.ml +++ b/src/proto_alpha/lib_sc_rollup_node/pvm_sig.ml @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022-2023 TriliTech *) +(* Copyright (c) 2022-2024 TriliTech *) (* Copyright (c) 2022 Nomadic Labs, *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) @@ -27,6 +27,40 @@ open Protocol open Alpha_context +(** Mutable API for the PVM. + - PVM functions which update the state in-place instead of returning a new state. + + This API helps the RISC-V PVM avoid unnecessary state copying. *) +module type MUTABLE_STATE_S = sig + type t + + type hash + + val get_tick : t -> Sc_rollup.Tick.t Lwt.t + + val state_hash : t -> hash Lwt.t + + val is_input_state : + is_reveal_enabled:Sc_rollup.is_reveal_enabled -> + t -> + Sc_rollup.input_request Environment.Lwt.t + + val set_input : Sc_rollup.input -> t -> unit Lwt.t + + val eval_many : + reveal_builtins:Tezos_scoru_wasm.Builtins.reveals -> + write_debug:Tezos_scoru_wasm.Builtins.write_debug -> + is_reveal_enabled:Sc_rollup.is_reveal_enabled -> + ?stop_at_snapshot:bool -> + max_steps:int64 -> + t -> + int64 Lwt.t + + module Internal_for_tests : sig + val insert_failure : t -> unit Lwt.t + end +end + (** Desired module type of a PVM from the L2 node's perspective *) module type S = sig type repo @@ -102,6 +136,10 @@ module type S = sig ('a, repo, tree) Context_sigs.t Lwt.t end + (** Mutable state API which allows updating the PVM state in-place. *) + module Mutable_state : + MUTABLE_STATE_S with type hash = hash and type t = Ctxt_wrapper.mut_state + (** Inspect durable state using a more specialised way of reading the PVM state. For example in WASM, it decodes the durable storage in the state diff --git a/src/proto_alpha/lib_sc_rollup_node/riscv_pvm.ml b/src/proto_alpha/lib_sc_rollup_node/riscv_pvm.ml index 5c8d71f4b43a2016fa3b5aad7879a689806df786..dcaa1051c647db0a7ab824160b0cdd5b9c9cb2e2 100644 --- a/src/proto_alpha/lib_sc_rollup_node/riscv_pvm.ml +++ b/src/proto_alpha/lib_sc_rollup_node/riscv_pvm.ml @@ -221,3 +221,49 @@ module Unsafe_patches = struct let apply _state (x : t) = match x with _ -> . end + +(* TODO: RV-217 Change implementation of RISCV PVM to use the Rust implementation *) +module Mutable_state : + Pvm_sig.MUTABLE_STATE_S + with type hash = PVM.hash + and type t = Ctxt_wrapper.mut_state = struct + type t = tree ref + + type hash = PVM.hash + + let get_tick state = get_tick !state + + let state_hash state = state_hash !state + + let is_input_state ~is_reveal_enabled state = + is_input_state ~is_reveal_enabled !state + + let set_input input state = + let open Lwt_syntax in + let* imm_state = set_input input !state in + state := imm_state ; + return_unit + + let eval_many ~reveal_builtins ~write_debug ~is_reveal_enabled + ?stop_at_snapshot ~max_steps mut_state = + let open Lwt_syntax in + let* imm_state, steps = + eval_many + ~reveal_builtins + ~write_debug + ~is_reveal_enabled + ?stop_at_snapshot + ~max_steps + !mut_state + in + mut_state := imm_state ; + return steps + + module Internal_for_tests = struct + let insert_failure state = + let open Lwt_syntax in + let* imm_state = Internal_for_tests.insert_failure !state in + state := imm_state ; + return_unit + end +end diff --git a/src/proto_alpha/lib_sc_rollup_node/wasm_2_0_0_pvm.ml b/src/proto_alpha/lib_sc_rollup_node/wasm_2_0_0_pvm.ml index b2d5d76c669315142af73bcbe850933e77b556aa..0510ed5ac27f73983b02d408eaf1a2cafd09db8e 100644 --- a/src/proto_alpha/lib_sc_rollup_node/wasm_2_0_0_pvm.ml +++ b/src/proto_alpha/lib_sc_rollup_node/wasm_2_0_0_pvm.ml @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022-2023 TriliTech *) +(* Copyright (c) 2022-2024 TriliTech *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -208,6 +208,53 @@ module Impl : Pvm_sig.S with type Unsafe_patches.t = unsafe_patch = struct ~reveal_builtins ~write_debug ?hooks:None + + (** WASM PVM Mutable API works by holding a reference to an immutable state + and wrapping all immutable functionality around the reference *) + module Mutable_state : + Pvm_sig.MUTABLE_STATE_S + with type hash = hash + and type t = Ctxt_wrapper.mut_state = struct + type t = tree ref + + type hash = Sc_rollup.State_hash.t + + let get_tick state = get_tick !state + + let state_hash state = state_hash !state + + let is_input_state ~is_reveal_enabled state = + is_input_state ~is_reveal_enabled !state + + let set_input input state = + let open Lwt_syntax in + let* imm_state = set_input input !state in + state := imm_state ; + return_unit + + let eval_many ~reveal_builtins ~write_debug ~is_reveal_enabled + ?stop_at_snapshot ~max_steps mut_state = + let open Lwt_syntax in + let* imm_state, steps = + eval_many + ~reveal_builtins + ~write_debug + ~is_reveal_enabled + ?stop_at_snapshot + ~max_steps + !mut_state + in + mut_state := imm_state ; + return steps + + module Internal_for_tests = struct + let insert_failure state = + let open Lwt_syntax in + let* imm_state = Internal_for_tests.insert_failure !state in + state := imm_state ; + return_unit + end + end end include Impl