Revision faf83b3a79b050cb8eecf865a9377c34ebd1cf47 authored by Marge Bot on 02 February 2024, 16:08:48 UTC, committed by Marge Bot on 02 February 2024, 16:08:48 UTC
Co-authored-by: Killian Delarue <killian.delarue@nomadic-labs.com> Approved-by: Arvid Jakobsson <arvid.jakobsson@nomadic-labs.com> Approved-by: Nic Volanschi <nic.volanschi@nomadic-labs.com> See merge request https://gitlab.com/tezos/tezos/-/merge_requests/11768
node_context.mli
(*****************************************************************************)
(* *)
(* Open Source License *)
(* Copyright (c) 2023 TriliTech <contact@trili.tech> *)
(* Copyright (c) 2023 Functori, <contact@functori.com> *)
(* Copyright (c) 2023 Marigold <contact@marigold.dev> *)
(* *)
(* 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 describes the execution context of the node. *)
type lcc = {commitment : Commitment.Hash.t; level : int32}
type genesis_info = Metadata.genesis_info = {
level : int32;
commitment_hash : Commitment.Hash.t;
}
(** Abstract type for store to force access through this module. *)
type 'a store constraint 'a = [< `Read | `Write > `Read]
(** Exposed functions to manipulate Node_context store outside of this module *)
module Node_store : sig
(** [load mode ~index_buffer_size ~l2_blocks_cache_size directory]
loads a store form the data persisted [directory] as described in
{!Store_sigs.load} *)
val load :
'a Store_sigs.mode ->
index_buffer_size:int ->
l2_blocks_cache_size:int ->
string ->
'a store tzresult Lwt.t
(** [close_store store] closes the store *)
val close : 'a store -> unit tzresult Lwt.t
(** [check_and_set_history_mode store history_mode] checks the
compatibility between given history mode and that of the store.
History mode can be converted from Archive to Full. Trying to
convert from Full to Archive will trigger an error.*)
val check_and_set_history_mode :
'a Store_sigs.mode ->
'a store ->
Configuration.history_mode option ->
unit tzresult Lwt.t
end
type debug_logger = string -> unit Lwt.t
type current_protocol = {
hash : Protocol_hash.t; (** Hash of the current protocol. *)
proto_level : int;
(** Protocol supported by this rollup node (represented as a protocol
level). *)
constants : Rollup_constants.protocol_constants;
(** Protocol constants retrieved from the Tezos node. *)
}
type last_whitelist_update = {message_index : int; outbox_level : Int32.t}
type private_info = {
last_whitelist_update : last_whitelist_update;
last_outbox_level_searched : int32;
(** If the rollup is private then the last search outbox level
when looking at whitelist update to execute. This is to
reduce the folding call at each cementation. If the rollup
is public then it's None. *)
}
type 'a t = {
config : Configuration.t; (** Inlined configuration for the rollup node. *)
cctxt : Client_context.full; (** Client context used by the rollup node. *)
dal_cctxt : Dal_node_client.cctxt option;
(** DAL client context to query the dal node, if the rollup node supports
the DAL. *)
dac_client : Dac_observer_client.t option;
(** DAC observer client to optionally pull in preimages *)
data_dir : string; (** Node data dir. *)
l1_ctxt : Layer1.t;
(** Layer 1 context to fetch blocks and monitor heads, etc.*)
genesis_info : genesis_info;
(** Origination information of the smart rollup. *)
injector_retention_period : int;
(** Number of blocks the injector will keep information about included
operations. *)
block_finality_time : int;
(** Deterministic block finality time for the layer 1 protocol. *)
kind : Kind.t; (** Kind of the smart rollup. *)
lockfile : Lwt_unix.file_descr;
(** A lock file acquired when the node starts. *)
store : 'a store; (** The store for the persistent storage. *)
context : 'a Context.t; (** The persistent context for the rollup node. *)
lcc : ('a, lcc) Reference.t;
(** Last cemented commitment on L1 (independently of synchronized status
of rollup node) and its level. *)
lpc : ('a, Commitment.t option) Reference.t;
(** The last published commitment on L1, i.e. commitment that the operator
is staked on (even if the rollup node is not synchronized). *)
private_info : ('a, private_info option) Reference.t;
(** contains information for the rollup when it's private.*)
kernel_debug_logger : debug_logger;
(** Logger used for writing [kernel_debug] messages *)
finaliser : unit -> unit Lwt.t;
(** Aggregation of finalisers to run when the node context closes *)
mutable current_protocol : current_protocol;
(** Information about the current protocol. This value is changed in place
on protocol upgrades. *)
global_block_watcher : Sc_rollup_block.t Lwt_watcher.input;
(** Watcher for the L2 chain, which enables RPC services to access
a stream of L2 blocks. *)
}
(** Read/write node context {!t}. *)
type rw = [`Read | `Write] t
(** Read only node context {!t}. *)
type ro = [`Read] t
(** [get_operator cctxt purpose] returns the public key hash for the operator
who has purpose [purpose], if any.
*)
val get_operator : _ t -> 'a Purpose.t -> 'a Purpose.operator option
(** [is_operator cctxt pkh] returns [true] if the public key hash [pkh] is an
operator for the node (for any purpose). *)
val is_operator : _ t -> Signature.Public_key_hash.t -> bool
(** [is_accuser node_ctxt] returns [true] if the rollup node runs in accuser
mode. *)
val is_accuser : _ t -> bool
(** [is_bailout node_ctxt] returns [true] if the rollup node runs in bailout
mode. *)
val is_bailout : _ t -> bool
(** [is_loser node_ctxt] returns [true] if the rollup node runs has some
failures planned. *)
val is_loser : _ t -> bool
(** [can_inject config op_kind] determines if a given operation kind can
be injected based on the configuration settings. *)
val can_inject : _ t -> Operation_kind.t -> bool
(** [check_op_in_whitelist_or_bailout_mode node_ctxt whitelist] Checks
when the rollup node is operating to determine if the operator is in the
whitelist or if the rollup node is in bailout mode. Bailout mode
does not publish any commitments but still defends previously
committed one. *)
val check_op_in_whitelist_or_bailout_mode :
_ t -> Signature.Public_key_hash.t list -> unit tzresult
(** [get_fee_parameter cctxt purpose] returns the fee parameter to inject an
operation for a given [purpose]. If no specific fee parameters were
configured for this purpose, returns the default fee parameter for this
purpose.
*)
val get_fee_parameter : _ t -> Operation_kind.t -> Injector_common.fee_parameter
(** The path for the lockfile used when starting and running the node. *)
val global_lockfile_path : data_dir:string -> string
(** The path for the lockfile used in block processing. *)
val processing_lockfile_path : data_dir:string -> string
(** The path for the lockfile used in garbage collection. *)
val gc_lockfile_path : data_dir:string -> string
(** [checkout_context node_ctxt block_hash] returns the context at block
[block_hash]. *)
val checkout_context : 'a t -> Block_hash.t -> 'a Context.t tzresult Lwt.t
(** Returns [true] if the rollup node supports the DAL and if DAL is enabled for
the current protocol. *)
val dal_supported : _ t -> bool
(** [readonly node_ctxt] returns a read only version of the node context
[node_ctxt]. *)
val readonly : _ t -> ro
(** Monad for values with delayed write effects in the node context. *)
type 'a delayed_write = ('a, rw) Delayed_write_monad.t
(** {2 Abstraction over store} *)
(** [get_history_mode t] returns the current history mode for the rollup
node. *)
val get_history_mode : _ t -> Configuration.history_mode tzresult Lwt.t
(** {3 Layer 2 blocks} *)
(** [is_processed store hash] returns [true] if the block with [hash] has
already been processed by the daemon. *)
val is_processed : _ t -> Block_hash.t -> bool tzresult Lwt.t
(** [get_l2_block t hash] returns the Layer 2 block known by the rollup node for
Layer 1 block [hash]. *)
val get_l2_block : _ t -> Block_hash.t -> Sc_rollup_block.t tzresult Lwt.t
(** Same as {!get_l2_block} but returns [None] when the Layer 2 block is not
available. *)
val find_l2_block :
_ t -> Block_hash.t -> Sc_rollup_block.t option tzresult Lwt.t
(** Same as {!get_l2_block} but retrieves the Layer 2 block by its level. *)
val get_l2_block_by_level : _ t -> int32 -> Sc_rollup_block.t tzresult Lwt.t
(** Same as {!get_l2_block_by_level} but returns [None] when the Layer 2 block
is not available. *)
val find_l2_block_by_level :
_ t -> int32 -> Sc_rollup_block.t option tzresult Lwt.t
(** [get_full_l2_block node_ctxt hash] returns the full L2 block for L1 block
hash [hash]. The result contains the L2 block and its content (inbox,
messages, commitment). *)
val get_full_l2_block :
_ t -> Block_hash.t -> Sc_rollup_block.full tzresult Lwt.t
(** [save_level t head] registers the correspondences [head.level |->
head.hash] in the store. *)
val save_level : rw -> Layer1.head -> unit tzresult Lwt.t
(** [save_l2_block t l2_block] remembers that the [l2_block] is processed. The
system should not have to come back to it. *)
val save_l2_block : rw -> Sc_rollup_block.t -> unit tzresult Lwt.t
(** [set_l2_head t l2_block] sets [l2_block] as the new head of the L2 chain. *)
val set_l2_head : rw -> Sc_rollup_block.t -> unit tzresult Lwt.t
(** [last_processed_head_opt store] returns the last processed head if it
exists. *)
val last_processed_head_opt : _ t -> Sc_rollup_block.t option tzresult Lwt.t
(** [mark_finalized_head store head] remembers that the [head] is finalized. By
construction, every block whose level is smaller than [head]'s is also
finalized. *)
val mark_finalized_level : rw -> int32 -> unit tzresult Lwt.t
(** [get_finalized_level t] returns the last finalized level. *)
val get_finalized_level : _ t -> int32 tzresult Lwt.t
(** [get_finalized_head_opt store] returns the last finalized head if it exists. *)
val get_finalized_head_opt : _ t -> Sc_rollup_block.t option tzresult Lwt.t
(** [hash_of_level node_ctxt level] returns the current block hash for a given
[level]. *)
val hash_of_level : _ t -> int32 -> Block_hash.t tzresult Lwt.t
(** [hash_of_level_opt] is like {!hash_of_level} but returns [None] if the
[level] is not known. *)
val hash_of_level_opt : _ t -> int32 -> Block_hash.t option tzresult Lwt.t
(** [level_of_hash node_ctxt hash] returns the level for Tezos block hash [hash]
if it is known by the Tezos Layer 1 node. *)
val level_of_hash : _ t -> Block_hash.t -> int32 tzresult Lwt.t
(** Returns the block header for a given hash using the L1 node. *)
val header_of_hash : _ t -> Block_hash.t -> Layer1.header tzresult Lwt.t
(** [get_predecessor_opt state head] returns the predecessor of block [head],
when [head] is not the genesis block. *)
val get_predecessor_opt :
_ t -> Layer1.head -> Layer1.head option tzresult Lwt.t
(** [get_predecessor state head] returns the predecessor block of [head]. *)
val get_predecessor : _ t -> Layer1.head -> Layer1.head tzresult Lwt.t
(** Same as {!get_predecessor_opt} with headers. *)
val get_predecessor_header_opt :
_ t -> Layer1.header -> Layer1.header option tzresult Lwt.t
(** Same as {!get_predecessor} with headers. *)
val get_predecessor_header :
_ t -> Layer1.header -> Layer1.header tzresult Lwt.t
(** [get_tezos_reorg_for_new_head node_ctxt old_head new_head] returns the L1
reorganization between [old_head] and [new_head]. *)
val get_tezos_reorg_for_new_head :
_ t ->
[`Head of Layer1.head | `Level of int32] ->
Layer1.head ->
Layer1.head Reorg.t tzresult Lwt.t
(** [block_with_tick store ~max_level tick] returns [Some b] where [b] is the
last layer 2 block which contains the [tick] before [max_level]. If no such
block exists (the tick happened after [max_level], or we are too late), the
function returns [None]. *)
val block_with_tick :
_ t -> max_level:int32 -> Z.t -> Sc_rollup_block.t option tzresult Lwt.t
(** {3 Commitments} *)
(** [get_commitment t hash] returns the commitment with [hash] stored by the
rollup node. *)
val get_commitment : _ t -> Commitment.Hash.t -> Commitment.t tzresult Lwt.t
(** Same as {!get_commitment} but returns [None] if this commitment hash is not
known by the rollup node. *)
val find_commitment :
_ t -> Commitment.Hash.t -> Commitment.t option tzresult Lwt.t
(** [commitment_exists t hash] returns [true] if the commitment with [hash] is
known (i.e. stored) by the rollup node. *)
val commitment_exists : _ t -> Commitment.Hash.t -> bool tzresult Lwt.t
(** [save_commitment t commitment] saves a commitment in the store an returns is
hash. *)
val save_commitment : rw -> Commitment.t -> Commitment.Hash.t tzresult Lwt.t
(** [commitment_published_at_level t hash] returns the levels at which the
commitment was first published and the one at which it was included by in a
Layer 1 block. It returns [None] if the commitment is not known by the
rollup node or if it was never published by the rollup node (and included on
L1). *)
val commitment_published_at_level :
_ t ->
Commitment.Hash.t ->
Store.Commitments_published_at_level.element option tzresult Lwt.t
(** [save_commitment_published_at_level t hash levels] saves the
publication/inclusion information for a commitment with [hash]. *)
val set_commitment_published_at_level :
rw ->
Commitment.Hash.t ->
Store.Commitments_published_at_level.element ->
unit tzresult Lwt.t
type commitment_source = Anyone | Us
(** [commitment_was_published t hash] returns [true] if the commitment is known
as being already published on L1. The [source] indicates if we want to know
the publication status for commitments we published ourselves [`Us] or that
[`Anyone] published. *)
val commitment_was_published :
_ t -> source:commitment_source -> Commitment.Hash.t -> bool tzresult Lwt.t
(** [set_lcc t lcc] saves the LCC both on disk and in the node context. It's written in the context iff [lcc] is is younger than its current value. *)
val set_lcc : rw -> lcc -> unit tzresult Lwt.t
(** [register_published_commitment t c ~first_published_at_level ~level
~published_by_us] saves the publishing information for commitment [c] both
on disk and in the node context. We remember the first publication level
and the level the commitment was published by us. *)
val register_published_commitment :
rw ->
Commitment.t ->
first_published_at_level:int32 ->
level:int32 ->
published_by_us:bool ->
unit tzresult Lwt.t
(** {3 Inboxes} *)
(** [get_inbox t inbox_hash] retrieves the inbox whose hash is [inbox_hash] from
the rollup node's storage. *)
val get_inbox :
_ t ->
Octez_smart_rollup.Inbox.Hash.t ->
Octez_smart_rollup.Inbox.t tzresult Lwt.t
(** Same as {!get_inbox} but returns [None] if this inbox is not known. *)
val find_inbox :
_ t ->
Octez_smart_rollup.Inbox.Hash.t ->
Octez_smart_rollup.Inbox.t option tzresult Lwt.t
(** [save_inbox t inbox] remembers the [inbox] in the storage. It is associated
to its hash which is returned. *)
val save_inbox :
rw ->
Octez_smart_rollup.Inbox.t ->
Octez_smart_rollup.Inbox.Hash.t tzresult Lwt.t
(** [inbox_of_head node_ctxt block] returns the latest inbox at the given
[block]. This function always returns [inbox] for all levels at and
after the rollup genesis. NOTE: It requires the L2 block for [block.hash] to
have been saved. *)
val inbox_of_head :
_ t -> Layer1.head -> Octez_smart_rollup.Inbox.t tzresult Lwt.t
(** Same as {!get_inbox} but uses the Layer 1 block hash for this inbox instead. *)
val get_inbox_by_block_hash :
_ t -> Block_hash.t -> Octez_smart_rollup.Inbox.t tzresult Lwt.t
(** Returns messages as they are stored in the store, unsafe to use because all
messages may not be present. Use {!Messages.get} instead. *)
val unsafe_find_stored_messages :
_ t ->
Merkelized_payload_hashes_hash.t ->
(string list * Block_hash.t) option tzresult Lwt.t
(** [get_num_messages t witness_hash] retrieves the number of messages for the
inbox witness [witness_hash] stored by the rollup node. *)
val get_num_messages :
_ t -> Merkelized_payload_hashes_hash.t -> int tzresult Lwt.t
(** [save_messages t payloads_hash ~predecessor messages] associates the list of
[messages] to the [payloads_hash]. The payload hash must be computed by
calling, e.g. {!Sc_rollup.Inbox.add_all_messages}. *)
val save_messages :
rw ->
Merkelized_payload_hashes_hash.t ->
predecessor:Block_hash.t ->
string list ->
unit tzresult Lwt.t
(** Return values for {!protocol_of_level}. *)
type proto_info = {
proto_level : int;
(** Protocol level for operations of block (can be different from L1
header value in the case of a migration block). *)
first_level_of_protocol : bool;
(** [true] if the level is the first of the protocol. *)
protocol : Protocol_hash.t;
(** Hash of the {e current} protocol for this level. *)
}
(** [protocol_of_level_with_store store level] returns the protocol of block level [level]. *)
val protocol_of_level_with_store :
_ Store.t -> int32 -> proto_info tzresult Lwt.t
(** [protocol_of_level t level] returns the protocol of block level [level]. *)
val protocol_of_level : _ t -> int32 -> proto_info tzresult Lwt.t
(** Returns the last protocol seen by the rollup node. *)
val last_seen_protocol : _ t -> Protocol_hash.t option tzresult Lwt.t
(** Returns the activation level of a protocol or fails if the protocol was
never seen by the rollup node. *)
val protocol_activation_level :
_ t -> Protocol_hash.t -> Store.Protocols.level tzresult Lwt.t
(** [save_protocol_info t block ~predecessor] saves to disk the protocol
information associated to the [block], if there is a protocol change
between [block] and [predecessor]. *)
val save_protocol_info :
rw -> Layer1.header -> predecessor:Layer1.header -> unit tzresult Lwt.t
(** {3 DAL} *)
(** [get_slot_header t ~published_in_block_hash slot_index] returns the slot
header for the [slot_index] that was published in the provided block hash on
Layer 1. *)
val get_slot_header :
_ t ->
published_in_block_hash:Block_hash.t ->
Dal.Slot_index.t ->
Dal.Slot_header.t tzresult Lwt.t
(** [get_all_slot_headers t ~published_in_block_hash] returns the slot headers
for all the slots that were published in the provided block hash on Layer
1. *)
val get_all_slot_headers :
_ t ->
published_in_block_hash:Block_hash.t ->
Dal.Slot_header.t list tzresult Lwt.t
(** [get_slot_indexes t ~published_in_block_hash] returns the slot indexes whose
headers were published in the provided block hash on Layer 1. *)
val get_slot_indexes :
_ t ->
published_in_block_hash:Block_hash.t ->
Dal.Slot_index.t list tzresult Lwt.t
(** [save_slot_header t ~published_in_block_hash header] saves the [header] as
being published for its index in the provided block hash on Layer 1. *)
val save_slot_header :
rw ->
published_in_block_hash:Block_hash.t ->
Dal.Slot_header.t ->
unit tzresult Lwt.t
(** [find_slot_status t ~confirmed_in_block_hash index] returns [None] if the
slot's block is not processed yet, [Some `Unconfirmed] if the slot was not
confirmed and [Some `Confirmed] if the slot is confirmed and the associated
pages are available. *)
val find_slot_status :
_ t ->
confirmed_in_block_hash:Block_hash.t ->
Dal.Slot_index.t ->
[`Unconfirmed | `Confirmed] option tzresult Lwt.t
(** [list_slots_statuses t ~confirmed_in_block_hash] lists the list of
slots indices with their respective statuses that are saved for the given
[confirmed_in_block_hash] *)
val list_slots_statuses :
_ t ->
confirmed_in_block_hash:Block_hash.t ->
(Dal.Slot_index.t * [`Confirmed | `Unconfirmed]) list tzresult Lwt.t
(** [save_slot_status node_ctxt hash slot_index status] saves in
[node_ctxt.store] that [slot_index] has status [status] in the
block with hash in [node_ctxt.store].
*)
val save_slot_status :
rw ->
Block_hash.t ->
Dal.Slot_index.t ->
[`Confirmed | `Unconfirmed] ->
unit tzresult Lwt.t
(* TODO: https://gitlab.com/tezos/tezos/-/issues/4636
Missing docstrings. *)
val find_confirmed_slots_history :
_ t -> Block_hash.t -> Dal.Slot_history.t option tzresult Lwt.t
val save_confirmed_slots_history :
rw -> Block_hash.t -> Dal.Slot_history.t -> unit tzresult Lwt.t
val find_confirmed_slots_histories :
_ t -> Block_hash.t -> Dal.Slot_history_cache.t option tzresult Lwt.t
val save_confirmed_slots_histories :
rw -> Block_hash.t -> Dal.Slot_history_cache.t -> unit tzresult Lwt.t
(** [gc node_ctxt level] triggers garbage collection for the node in accordance
with [node_ctxt.config.gc_parameters]. Upon completion, all data for L2
levels lower than [level] will be removed. *)
val gc : [> `Write] t -> level:int32 -> unit tzresult Lwt.t
(** [get_gc_levels node_ctxt] returns information about the garbage collected
levels. *)
val get_gc_levels : _ t -> Store.Gc_levels.levels tzresult Lwt.t
(** [check_level_available node_ctxt level] resolves with an error if the
[level] is before the first non garbage collected level. *)
val check_level_available : _ t -> int32 -> unit tzresult Lwt.t
val get_last_context_split_level : _ t -> int32 option tzresult Lwt.t
val save_context_split_level : rw -> int32 -> unit tzresult Lwt.t
(** {2 Helpers} *)
(** [make_kernel_logger event ?log_kernel_debug_file logs_dir] returns two
functions [kernel_debug_logger] and [finaliser], to be used in the node
context. [kernel_debug_logger] writes kernel logs to
[logs_dir/log_kernel_debug_file] and emits them with the [event]. *)
val make_kernel_logger :
(string -> unit Lwt.t) ->
?log_kernel_debug_file:string ->
string ->
((string -> unit Lwt.t) * (unit -> unit Lwt.t)) Lwt.t
module Internal_for_tests : sig
val write_protocols_in_store :
[> `Write] store -> Store.Protocols.value -> unit tzresult Lwt.t
(** Extract the underlying store from the node context. This function is
unsafe to use outside of tests as it breaks the abstraction barrier
provided by the [Node_context]. *)
val unsafe_get_store : 'a t -> 'a Store.t
end
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...