diff --git a/src/proto_alpha/lib_protocol/sc_rollup_arith.mli b/src/proto_alpha/lib_protocol/sc_rollup_arith.mli index 61bf9fa50e8624c5f65cc7f8dcf1d2c6db113cb8..780e8f98fb53db980ca67b2362f8751e08770ec1 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_arith.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_arith.mli @@ -29,7 +29,7 @@ This rollup is a stack machine equipped with addition. - It processed postfix arithmetic expressions written as sequence of + It processes postfix arithmetic expressions written as sequence of (space separated) [int] and [+] using the following rules: - a number [x] is interpreted as pushing [x] on the stack ; @@ -75,7 +75,7 @@ module type S = sig (** [get_tick state] returns the current tick of [state]. *) val get_tick : state -> Sc_rollup.Tick.t Lwt.t - (** The machine has three possible states: *) + (** The machine has three possible statuses: *) type status = Halted | WaitingForInputMessage | Parsing | Evaluating (** [get_status state] returns the machine status in [state]. *) diff --git a/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.ml b/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.ml index d54dfc5ac9ee52248b5f6404dd6882718e2435f4..5dbb4a844ce2e5616cae1579430deb0694d0b7df 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.ml @@ -68,7 +68,7 @@ let () = register_error_kind `Permanent ~id:"sc_rollup_inbox.invalid_level_add_messages" - ~title:"Internal error: Trying to add an message to an inbox from the past" + ~title:"Internal error: Trying to add a message to an inbox from the past" ~description: "An inbox can only accept messages for its current level or for the next \ levels." @@ -215,7 +215,7 @@ let pp fmt rollup = %a level = %a current messages hash = %a - nb_available_messages = %s + nb_available_messages = %Ld nb_messages_in_commitment_period = %s starting_level_of_current_commitment_period = %a message_counter = %a @@ -227,7 +227,7 @@ let pp fmt level Context_hash.pp (current_messages_hash ()) - (Int64.to_string nb_available_messages) + nb_available_messages (Int64.to_string nb_messages_in_commitment_period) Raw_level_repr.pp starting_level_of_current_commitment_period @@ -410,7 +410,7 @@ module MakeHashingScheme (Tree : TREE) : let add_message inbox payload messages = let open Lwt_syntax in let message_index = inbox.message_counter in - let message_counter = Z.succ inbox.message_counter in + let message_counter = Z.succ message_index in let key = key_of_message message_index in let nb_available_messages = Int64.succ inbox.nb_available_messages in let* messages = diff --git a/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.mli b/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.mli index 86f64dcfecce7a23662eecdac775ab0a3168867e..62af4dfb5016ffcf27c1df8fc558602c08c3570b 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.mli @@ -92,7 +92,7 @@ {1 Clients} This module is meant to be used both by the protocol and by the - rollup node in order to maintain consistent inboxes on both side. + rollup node in order to maintain consistent inboxes on both sides. These two clients slightly differ on the amount of information they store about the inbox. @@ -135,7 +135,7 @@ val encoding : t Data_encoding.t message at all. *) val empty : Sc_rollup_repr.t -> Raw_level_repr.t -> t -(** [level inbox] returns the maximum level of message insertion in +(** [inbox_level inbox] returns the maximum level of message insertion in [inbox] or its initial level. *) val inbox_level : t -> Raw_level_repr.t @@ -199,7 +199,7 @@ module type MerkelizedOperations = sig To archive a sequence of [messages] for a given [level], we push it at the end of the [history] and update the witness of this history in the [inbox]. The [inbox]'s messages for the current - level is also emptied to insert the [payloads] in a fresh sequence + level are also emptied to insert the [payloads] in a fresh sequence of [messages] for [level]. This function fails if [level] is older than [inbox]'s [level]. diff --git a/src/proto_alpha/lib_protocol/sc_rollup_repr.ml b/src/proto_alpha/lib_protocol/sc_rollup_repr.ml index c7bade5f42a2f1f8584093083556122926dd5ce5..ae0f644ff7c23ef1f15bba60765f42ef45897380 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_repr.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_repr.ml @@ -256,15 +256,15 @@ module Commitment = struct Format.fprintf fmt "@[SCORU Commitment:@ compressed_state: %a@ inbox_level: %a@ \ - predecessor: %a@ number_of_messages: %d@ number_of_ticks: %d@]" + predecessor: %a@ number_of_messages: %ld@ number_of_ticks: %ld@]" State_hash.pp compressed_state Raw_level_repr.pp inbox_level Commitment_hash.pp predecessor - (Int32.to_int (Number_of_messages.to_int32 number_of_messages)) - (Int32.to_int (Number_of_ticks.to_int32 number_of_ticks)) + (Number_of_messages.to_int32 number_of_messages) + (Number_of_ticks.to_int32 number_of_ticks) let encoding = let open Data_encoding in diff --git a/src/proto_alpha/lib_protocol/sc_rollup_storage.ml b/src/proto_alpha/lib_protocol/sc_rollup_storage.ml index a30cb3055d6b61e5187ec51fb8872d8666631801..e7f5797538a2c4766a1b4098ad6cf5d53c6b6445 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_storage.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_storage.ml @@ -235,7 +235,7 @@ let () = register_error_kind `Temporary ~id:"Sc_rollup_unknown_commitment" - ~title:"Rollup does not exist" + ~title:"Unknown commitment" ~description ~pp:(fun ppf x -> Format.fprintf @@ -251,7 +251,7 @@ let () = register_error_kind `Temporary ~id:"Sc_rollup_bad_inbox_level" - ~title:"Committed too soon" + ~title:"Committing to a bad inbox level" ~description ~pp:(fun ppf () -> Format.fprintf ppf "%s" description) Data_encoding.empty @@ -475,13 +475,15 @@ let get_commitment_stake_count ctxt rollup node = let set_commitment_added ctxt rollup node new_value = let open Lwt_tzresult_syntax in let* ctxt, res = Store.Commitment_added.find (ctxt, rollup) node in - let new_value = - match res with None -> new_value | Some old_value -> old_value - in - let* ctxt, size_diff, _was_bound = - Store.Commitment_added.add (ctxt, rollup) node new_value - in - return (size_diff, new_value, ctxt) + match res with + | Some old_value -> + (* No need to re-add the read value *) + return (0, old_value, ctxt) + | None -> + let* ctxt, size_diff, _was_bound = + Store.Commitment_added.add (ctxt, rollup) node new_value + in + return (size_diff, new_value, ctxt) let deallocate ctxt rollup node = let open Lwt_tzresult_syntax in @@ -578,32 +580,30 @@ let assert_commitment_not_too_far_ahead ctxt rollup lcc commitment = *) let assert_commitment_period ctxt rollup commitment = let open Lwt_tzresult_syntax in - let pred = Commitment.(commitment.predecessor) in + let pred_hash = Commitment.(commitment.predecessor) in let* ctxt, pred_level = - if Commitment_hash.(pred = zero) then + if Commitment_hash.(pred_hash = zero) then let* level = Store.Initial_level.get ctxt rollup in return (ctxt, level) else - let* pred, ctxt = - get_commitment_internal ctxt rollup commitment.predecessor - in + let* pred, ctxt = get_commitment_internal ctxt rollup pred_hash in return (ctxt, Commitment.(pred.inbox_level)) in (* We want to check the following inequalities on [commitment.inbox_level], [commitment.predecessor.inbox_level] and the constant [sc_rollup_commitment_period]. - Greater-than-or-equal (>=), to ensure inbox_levels are monotonically - increasing. along each branch of commitments. Together with + increasing along each branch of commitments. Together with [assert_commitment_not_too_far_ahead] this is sufficient to limit the - depth of the commitment tree, which is also the number commitments stored + depth of the commitment tree, which is also the number of commitments stored per staker. This constraint must be enforced at submission time. - - Equality (=), so that that L2 blocks are produced at a regular rate. This + - Equality (=), so that L2 blocks are produced at a regular rate. This ensures that there is only ever one branch of correct commitments, simplifying refutation logic. This could also be enforced at refutation time rather than submission time, but doing it here works too. - Because [a >= b && a = b] is equivalent to [a = b], we can the latter as + Because [a >= b && a = b] is equivalent to [a = b], we can just keep the latter as an optimization. *) let sc_rollup_commitment_period = @@ -616,10 +616,10 @@ let assert_commitment_period ctxt rollup commitment = else fail Sc_rollup_bad_inbox_level (** Check invariants on [inbox_level], enforcing overallocation of storage and - regularity of block prorudction. + regularity of block production. The constants used by [assert_refine_conditions_met] must be chosen such - that the maximum cost of storage allocated by each staker at most the size + that the maximum cost of storage allocated by each staker is at most the size of their deposit. *) let assert_refine_conditions_met ctxt rollup lcc commitment = @@ -686,11 +686,12 @@ let refine_stake ctxt rollup staker commitment = let publish_commitment ctxt rollup staker commitment = let open Lwt_tzresult_syntax in let* ctxt, res = Store.Stakers.find (ctxt, rollup) staker in - match res with - | None -> - let* ctxt = deposit_stake ctxt rollup staker in - refine_stake ctxt rollup staker commitment - | Some _ -> refine_stake ctxt rollup staker commitment + let* ctxt = + match res with + | None -> deposit_stake ctxt rollup staker + | Some _ -> return ctxt + in + refine_stake ctxt rollup staker commitment let cement_commitment ctxt rollup new_lcc = let open Lwt_tzresult_syntax in @@ -796,28 +797,34 @@ let get_conflict_point ctxt rollup staker1 staker2 = We use this fact in the following to efficiently traverse both commitment histories towards the conflict points. *) let rec traverse_in_parallel ctxt commit1 commit2 = - if Commitment_hash.(commit1 = commit2) then - (* This case will most dominantly happen when either commit is part of the other's history. - It occurs when the commit that is farther ahead gets dereferenced to its predecessor often - enough to land at the other commit. *) - fail Sc_rollup_no_conflict + (* We know that commit1 <> commit2 at the first call and during recursive calls + as well. *) + let* commit1_info, ctxt = get_commitment_internal ctxt rollup commit1 in + let* commit2_info, ctxt = get_commitment_internal ctxt rollup commit2 in + (* This assert should hold because: + - We call function [traverse_in_parallel] with two initial commitments + whose levels are equal to [target_inbox_level], + - In recursive calls, the commitments are replaced by their respective + predecessors, and we know that successive commitments in a branch are + spaced by [sc_rollup_commitment_period_in_blocks] *) + assert (Raw_level_repr.(commit1_info.inbox_level = commit2_info.inbox_level)) ; + if Commitment_hash.(commit1_info.predecessor = commit2_info.predecessor) + then + (* Same predecessor means we've found the conflict points. *) + return ((commit1, commit2), ctxt) else - let* commit1_info, ctxt = get_commitment_internal ctxt rollup commit1 in - let* commit2_info, ctxt = get_commitment_internal ctxt rollup commit2 in - assert ( - Raw_level_repr.(commit1_info.inbox_level = commit2_info.inbox_level)) ; - if Commitment_hash.(commit1_info.predecessor = commit2_info.predecessor) - then - (* Same predecessor means we've found the conflict points. *) - return ((commit1, commit2), ctxt) - else - (* Different predecessors means they run in parallel. *) - (traverse_in_parallel [@ocaml.tailcall]) - ctxt - commit1_info.predecessor - commit2_info.predecessor - in - traverse_in_parallel ctxt commit1 commit2 + (* Different predecessors means they run in parallel. *) + (traverse_in_parallel [@ocaml.tailcall]) + ctxt + commit1_info.predecessor + commit2_info.predecessor + in + if Commitment_hash.(commit1 = commit2) then + (* This case will most dominantly happen when either commit is part of the other's history. + It occurs when the commit that is farther ahead gets dereferenced to its predecessor often + enough to land at the other commit. *) + fail Sc_rollup_no_conflict + else traverse_in_parallel ctxt commit1 commit2 let remove_staker ctxt rollup staker = let open Lwt_tzresult_syntax in diff --git a/src/proto_alpha/lib_protocol/sc_rollup_storage.mli b/src/proto_alpha/lib_protocol/sc_rollup_storage.mli index 8577751d2fb7c8f708e86ae9329042b516e6d6a6..e3c43b819319ba3ddf8c9a3644b835aba4d8c773 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_storage.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_storage.mli @@ -57,7 +57,7 @@ Commitments accepted as true by the protocol are referred to as Cemented. {3 Stakers} - The Stakers table maps Stakers (implicit accounts) to commitments. + The Stakers table maps Stakers (implicit accounts) to commitments hashes. Let [Stakers(S)] mean "looking up the key S in [Stakers]". @@ -178,7 +178,7 @@ val kind : Sc_rollup_repr.t -> Sc_rollup_repr.Kind.t option tzresult Lwt.t -(** [add_message context rollup msg] adds [msg] to [rollup]'s inbox. +(** [add_messages context rollup msg] adds [msg] to [rollup]'s inbox. This function returns the updated context as well as the size diff. @@ -347,7 +347,8 @@ val last_cemented_commitment : } If successful, [last_cemented_commitment] is set to the given [commitment] and - the appropriate amount of inbox messages is consumed. + the appropriate amount of inbox messages is consumed. The old LCC is also + deallocated. May fail with: {ul @@ -417,10 +418,10 @@ val remove_staker : Sc_rollup_repr.Staker.t -> Raw_context.t tzresult Lwt.t -(* [list context] returns a list of all rollups that have been originated. *) +(** [list context] returns a list of all rollups that have been originated. *) val list : Raw_context.t -> Sc_rollup_repr.t list tzresult Lwt.t -(* [initial_level ctxt sc_rollup] returns the level at which a [sc_rollup] was +(** [initial_level ctxt sc_rollup] returns the level at which a [sc_rollup] was originated. *) val initial_level : Raw_context.t -> Sc_rollup_repr.t -> Raw_level_repr.t tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/skip_list_repr.ml b/src/proto_alpha/lib_protocol/skip_list_repr.ml index 6686e8f87bf8d7540463d71092990d035ac206ea..56f0d73cc4f452b0fcf46db9f18f331be2dc1276 100644 --- a/src/proto_alpha/lib_protocol/skip_list_repr.ml +++ b/src/proto_alpha/lib_protocol/skip_list_repr.ml @@ -122,8 +122,8 @@ end) : S = struct in let {content; back_pointers; index} = cell1 in equal_content content cell2.content - && equal_back_pointers back_pointers cell2.back_pointers && Compare.Int.equal index cell2.index + && equal_back_pointers back_pointers cell2.back_pointers let index cell = cell.index diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index e97d724f49b9f0b839d0896f37bc411e08ee02d6..62037ee84e9309259bf43225c52dca7a8e5d10c1 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -670,14 +670,14 @@ module Sc_rollup : sig - a merkelized inbox, of which only the root hash is stored - a tree of commitments, rooted at the last cemented commitment - a map from stakers to commitments - - a map from commitments to the time (level) of its first insertion + - a map from commitments to the time (level) of their first insertion For performance reasons we also store (per rollup): - the total number of active stakers; - the number of stakers per commitment. - See module comments for details. + See module {!Sc_rollup_repr.Commitment} for details. *) module PVM_kind : Indexed_data_storage