From 74d56d1339c9d6098080611f38545ac114ef159e Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 6 Feb 2024 13:28:51 +0100 Subject: [PATCH 1/2] DAL/Tezt: add support for DAL payloads in attestations --- tezt/lib_tezos/operation_core.ml | 120 ++++++++++++++++------- tezt/lib_tezos/operation_core.mli | 30 +++--- tezt/tests/double_consensus.ml | 11 ++- tezt/tests/prevalidator.ml | 7 +- tezt/tests/rpc_versioning_attestation.ml | 55 +++++++---- 5 files changed, 153 insertions(+), 70 deletions(-) diff --git a/tezt/lib_tezos/operation_core.ml b/tezt/lib_tezos/operation_core.ml index 9f577c14dc5b..b1a446d3adfa 100644 --- a/tezt/lib_tezos/operation_core.ml +++ b/tezt/lib_tezos/operation_core.ml @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 Nomadic Labs *) +(* Copyright (c) 2022-2024 Nomadic Labs *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -25,7 +25,10 @@ open Runnable.Syntax -type consensus_kind = Attestation | Preattestation | Dal_attestation +type consensus_kind = + | Attestation of {with_dal : bool} + | Preattestation + | Dal_attestation type kind = | Consensus of {kind : consensus_kind; chain_id : string} @@ -103,7 +106,7 @@ let sign ?protocol ({kind; signer; _} as t) client = let prefix = match kind with | Preattestation -> "\x12" - | Attestation -> "\x13" + | Attestation _ -> "\x13" | Dal_attestation -> "\x14" in Tezos_crypto.Signature.Custom @@ -245,14 +248,21 @@ let make_preapply_operation_input ~protocol ~signature t = ] module Consensus = struct + type consensus_content = { + slot : int; + level : int; + round : int; + block_payload_hash : string; + } + + type dal_content = {attestation : bool array} + type t = - | Consensus of { - kind : consensus_kind; + | CPreattestation of {use_legacy_name : bool; consensus : consensus_content} + | CAttestation of { use_legacy_name : bool; - slot : int; - level : int; - round : int; - block_payload_hash : string; + consensus : consensus_content; + dal : dal_content option; } | Dal_attestation of { attestation : bool array; @@ -262,41 +272,78 @@ module Consensus = struct } let consensus ~use_legacy_name ~kind ~slot ~level ~round ~block_payload_hash = - Consensus {kind; use_legacy_name; slot; level; round; block_payload_hash} - - let attestation = consensus ~kind:Attestation + let consensus = {slot; level; round; block_payload_hash} in + match kind with + | Preattestation -> CPreattestation {use_legacy_name; consensus} + | Attestation {with_dal} -> + assert (with_dal = false) ; + CAttestation {use_legacy_name; consensus; dal = None} + | Dal_attestation -> assert false + + let attestation ~use_legacy_name ~slot ~level ~round ~block_payload_hash + ?dal_attestation () = + let consensus = {slot; level; round; block_payload_hash} in + CAttestation + { + use_legacy_name; + consensus; + dal = Option.map (fun attestation -> {attestation}) dal_attestation; + } - let preattestation = consensus ~kind:Preattestation + let preattestation ~use_legacy_name ~slot ~level ~round ~block_payload_hash = + let consensus = {slot; level; round; block_payload_hash} in + CPreattestation {use_legacy_name; consensus} let dal_attestation ~attestation ~level ~round ~slot = Dal_attestation {attestation; level; round; slot} - let kind_to_string kind use_legacy_name = + let string_of_bool_vector dal_attestation = + let aux (acc, n) b = + let bit = if b then 1 else 0 in + (acc lor (bit lsl n), n + 1) + in + Array.fold_left aux (0, 0) dal_attestation |> fst |> string_of_int + + let kind_to_string kind ~use_legacy_name = let name = function true -> "endorsement" | false -> "attestation" in match kind with - | Attestation -> name use_legacy_name + | Attestation {with_dal} -> + name use_legacy_name ^ if with_dal then "_with_dal" else "" | Preattestation -> Format.sprintf "pre%s" (name use_legacy_name) | Dal_attestation -> "dal_attestation" let json = function - | Consensus {kind; use_legacy_name; slot; level; round; block_payload_hash} - -> + | CAttestation {use_legacy_name; consensus; dal} -> + let with_dal = Option.is_some dal in + `O + ([ + ( "kind", + Ezjsonm.string + (kind_to_string (Attestation {with_dal}) ~use_legacy_name) ); + ("slot", Ezjsonm.int consensus.slot); + ("level", Ezjsonm.int consensus.level); + ("round", Ezjsonm.int consensus.round); + ("block_payload_hash", Ezjsonm.string consensus.block_payload_hash); + ] + @ + match dal with + | None -> [] + | Some {attestation} -> + [ + ( "dal_attestation", + Ezjsonm.string (string_of_bool_vector attestation) ); + ]) + | CPreattestation {use_legacy_name; consensus} -> `O [ - ("kind", Ezjsonm.string (kind_to_string kind use_legacy_name)); - ("slot", Ezjsonm.int slot); - ("level", Ezjsonm.int level); - ("round", Ezjsonm.int round); - ("block_payload_hash", Ezjsonm.string block_payload_hash); + ( "kind", + Ezjsonm.string (kind_to_string Preattestation ~use_legacy_name) ); + ("slot", Ezjsonm.int consensus.slot); + ("level", Ezjsonm.int consensus.level); + ("round", Ezjsonm.int consensus.round); + ("block_payload_hash", Ezjsonm.string consensus.block_payload_hash); ] | Dal_attestation {attestation; level; round; slot} -> - let string_of_bool_vector attestation = - let aux (acc, n) b = - let bit = if b then 1 else 0 in - (acc lor (bit lsl n), n + 1) - in - Array.fold_left aux (0, 0) attestation |> fst |> string_of_int - in `O [ ("kind", Ezjsonm.string "dal_attestation"); @@ -320,7 +367,8 @@ module Consensus = struct in let kind = match consensus_operation with - | Consensus {kind; _} -> kind + | CPreattestation _ -> Preattestation + | CAttestation _ -> Attestation {with_dal = false} | Dal_attestation _ -> Dal_attestation in return (make ~branch ~signer ~kind:(Consensus {kind; chain_id}) json) @@ -373,8 +421,8 @@ module Anonymous = struct (({kind = op1_kind; _}, _) as op1) (({kind = op2_kind; _}, _) as op2) = match (kind, op1_kind, op2_kind) with | ( Double_attestation_evidence, - Consensus {kind = Attestation; _}, - Consensus {kind = Attestation; _} ) -> + Consensus {kind = Attestation {with_dal = false}; _}, + Consensus {kind = Attestation {with_dal = false}; _} ) -> Double_consensus_evidence {kind; use_legacy_name; op1; op2} | ( Double_preattestation_evidence, Consensus {kind = Preattestation; _}, @@ -389,14 +437,14 @@ module Anonymous = struct let double_preattestation_evidence = double_consensus_evidence ~kind:Double_preattestation_evidence - let kind_to_string kind use_legacy_name = + let kind_to_string kind ~use_legacy_name = sf "double_%s_evidence" (Consensus.kind_to_string (match kind with - | Double_attestation_evidence -> Attestation + | Double_attestation_evidence -> Attestation {with_dal = false} | Double_preattestation_evidence -> Preattestation) - use_legacy_name) + ~use_legacy_name) let denunced_op_json (op, signature) = `O @@ -412,7 +460,7 @@ module Anonymous = struct let op2 = denunced_op_json op2 in `O [ - ("kind", Ezjsonm.string (kind_to_string kind use_legacy_name)); + ("kind", Ezjsonm.string (kind_to_string kind ~use_legacy_name)); ("op1", op1); ("op2", op2); ] diff --git a/tezt/lib_tezos/operation_core.mli b/tezt/lib_tezos/operation_core.mli index 54f71ef69920..31245ec311d6 100644 --- a/tezt/lib_tezos/operation_core.mli +++ b/tezt/lib_tezos/operation_core.mli @@ -61,7 +61,10 @@ type t type operation := t -type consensus_kind = Attestation | Preattestation | Dal_attestation +type consensus_kind = + | Attestation of {with_dal : bool} + | Preattestation + | Dal_attestation (** The kind is necessary because it determines the watermark of an operation which is necessary for signing an operation. This type @@ -265,22 +268,26 @@ module Consensus : sig block_payload_hash:string -> t - (** [attestation ?use_legacy_name ~level ~round ~slot ~block_payload_hash] - crafts an attestation operation at [level] on the [round] with the [slot] - and [block_payload_hash]. If [use_legacy_name] is set, the [kind] field in - the crafted JSON will be "endorsement" instead of "attestation". *) + (** [attestation ?use_legacy_name ~level ~round ~slot ~block_payload_hash + ?dal_attestation ()] crafts an attestation operation at the given [level] + on the given [round] with the given [slot] and [block_payload_hash] and + optionally the given [dal_attestation]. If [use_legacy_name] is set, the + [kind] field in the crafted JSON will be "endorsement" instead of + "attestation". *) val attestation : use_legacy_name:bool -> slot:int -> level:int -> round:int -> block_payload_hash:string -> + ?dal_attestation:bool array -> + unit -> t - (** [kind_to_string kind use_legacy_name] return the name of the [kind]. If - [use_legacy_name] is set, the name corresponding to the [kind] will be - "(pre)endorsement" instead of "(pre)attestation". *) - val kind_to_string : consensus_kind -> bool -> string + (** [kind_to_string kind ~use_legacy_name] returns the name of the + [kind]. If [use_legacy_name] is set, the name corresponding to the [kind] + will be "(pre)endorsement" instead of "(pre)attestation". *) + val kind_to_string : consensus_kind -> use_legacy_name:bool -> string (** [operation] constructs an operation from a consensus operation. the [client] is used to fetch the branch and the @@ -364,11 +371,12 @@ module Anonymous : sig operation * Tezos_crypto.Signature.t -> t - (** [kind_to_string kind use_legacy_name] return the name of the [kind]. If + (** [kind_to_string kind ~use_legacy_name] return the name of the [kind]. If [use_legacy_name] is set, the name corresponding to the [kind] will be "double_(pre)endorsement_evidence" instead of "double_(pre)attestation_evidence". *) - val kind_to_string : double_consensus_evidence_kind -> bool -> string + val kind_to_string : + double_consensus_evidence_kind -> use_legacy_name:bool -> string (** [operation] constructs an operation from an anonymous operation. the [client] is used to fetch the branch and the [chain_id]. *) diff --git a/tezt/tests/double_consensus.ml b/tezt/tests/double_consensus.ml index a0dbe28c6705..6a2db62512ea 100644 --- a/tezt/tests/double_consensus.ml +++ b/tezt/tests/double_consensus.ml @@ -149,7 +149,14 @@ let double_consensus_wrong_slot let attest_utils = ( Client.attest_for, - Operation.Consensus.attestation ~use_legacy_name:true, + (fun ~slot ~level ~round ~block_payload_hash -> + Operation.Consensus.attestation + ~use_legacy_name:true + ~slot + ~level + ~round + ~block_payload_hash + ()), double_attestation_waiter, get_consensus_operation_name ) @@ -377,6 +384,7 @@ let operation_too_old = ~level ~round:3 ~block_payload_hash + () in let waiter = consensus_operation_too_old_waiter accuser in let* _ = @@ -455,6 +463,7 @@ let operation_too_far_in_future = ~level ~round:0 ~block_payload_hash + () in let waiter = consensus_operation_too_far_in_future_waiter accuser in let* _ = diff --git a/tezt/tests/prevalidator.ml b/tezt/tests/prevalidator.ml index 095bb0c4b0fe..cbc966994e09 100644 --- a/tezt/tests/prevalidator.ml +++ b/tezt/tests/prevalidator.ml @@ -1880,7 +1880,8 @@ module Revamped = struct ~slot:(Operation.Consensus.first_slot ~slots_json delegate) ~level ~round:0 - ~block_payload_hash) + ~block_payload_hash + ()) ~signer:delegate client in @@ -2130,7 +2131,8 @@ module Revamped = struct ~slot:(Operation.Consensus.first_slot ~slots_json delegate) ~level ~round:0 - ~block_payload_hash) + ~block_payload_hash + ()) ~signer:delegate client in @@ -2514,6 +2516,7 @@ module Revamped = struct ~level ~round ~block_payload_hash + () in return (op, branch, oph) in diff --git a/tezt/tests/rpc_versioning_attestation.ml b/tezt/tests/rpc_versioning_attestation.ml index 4b49c2fd18a3..42490988448c 100644 --- a/tezt/tests/rpc_versioning_attestation.ml +++ b/tezt/tests/rpc_versioning_attestation.ml @@ -78,7 +78,7 @@ let check_kind json kind = let check_version ~version ~use_legacy_name ~check ~rpc ~get_name ~data client = let* t = Client.RPC.call client @@ rpc ~version data in - return (check ~use_legacy_name t (get_name use_legacy_name)) + return (check ~use_legacy_name t (get_name ~use_legacy_name)) let check_unknown_version ~version ~rpc ~data client = let*? p = Client.RPC.spawn client @@ rpc ~version data in @@ -119,7 +119,7 @@ let check_rpc_versions ?(old = "0") ?(new_ = "1") ?(unknown = "2") ~check ~rpc let create_consensus_op ?slot ?level ?round ?block_payload_hash ~use_legacy_name ~signer ~kind client = let consensus_name = - Operation.Consensus.kind_to_string kind use_legacy_name + Operation.Consensus.kind_to_string kind ~use_legacy_name in Log.info "Create an %s operation" consensus_name ; let consensus = @@ -148,12 +148,13 @@ let create_double_consensus_evidence ~use_legacy_name ~double_evidence_kind client = let consensus_kind = match double_evidence_kind with - | Operation.Anonymous.Double_attestation_evidence -> Operation.Attestation + | Operation.Anonymous.Double_attestation_evidence -> + Operation.Attestation {with_dal = false} | Operation.Anonymous.Double_preattestation_evidence -> Operation.Preattestation in let consensus_name = - Operation.Anonymous.kind_to_string double_evidence_kind use_legacy_name + Operation.Anonymous.kind_to_string double_evidence_kind ~use_legacy_name in Log.info "Create an %s operation" consensus_name ; @@ -230,7 +231,8 @@ module Forge = struct register_test ~title:"Forge consensus operations" ~additionnal_tags:["forge"; "operations"; "consensus"] - @@ fun protocol -> test_consensus Operation.Attestation protocol + @@ fun protocol -> + test_consensus (Operation.Attestation {with_dal = false}) protocol let test_forge_preconsensus = register_test @@ -287,12 +289,12 @@ module Forge = struct let consensus_kind = match double_evidence_kind with | Operation.Anonymous.Double_attestation_evidence -> - Operation.Attestation + Operation.Attestation {with_dal = false} | Operation.Anonymous.Double_preattestation_evidence -> Operation.Preattestation in let consensus_name = - Operation.Anonymous.kind_to_string double_evidence_kind use_legacy_name + Operation.Anonymous.kind_to_string double_evidence_kind ~use_legacy_name in Log.info "Create an %s operation" consensus_name ; @@ -415,7 +417,8 @@ module Parse = struct ~title:"Parse raw consensus operations" ~additionnal_tags:["parse"; "raw"; "operations"; "consensus"] ~uses:(fun _protocol -> [Constant.octez_codec]) - @@ fun protocol -> test_parse Operation.Attestation protocol + @@ fun protocol -> + test_parse (Operation.Attestation {with_dal = false}) protocol let test_parse_preconsensus = register_test @@ -508,7 +511,9 @@ module Mempool = struct ~title:"Pending consensus operations" ~additionnal_tags:["mempool"; "pending"; "operations"; "consensus"] @@ fun protocol -> - test_pending_operations_consensus Operation.Attestation protocol + test_pending_operations_consensus + (Operation.Attestation {with_dal = false}) + protocol let test_pending_preconsensus = register_test @@ -638,7 +643,7 @@ module Mempool = struct let* () = Client.bake_for_and_wait ~node client in let check_monitor_mempool p ~use_legacy_name = - let name = Operation.Consensus.kind_to_string kind use_legacy_name in + let name = Operation.Consensus.kind_to_string kind ~use_legacy_name in check_monitor_mempool p name in let* () = check_monitor_mempool p_legacy ~use_legacy_name:true in @@ -650,7 +655,9 @@ module Mempool = struct ~title:"Monitor consensus operations" ~additionnal_tags:["mempool"; "monitor"; "operations"; "consensus"] @@ fun protocol -> - test_monitor_operations_consensus Operation.Attestation protocol + test_monitor_operations_consensus + (Operation.Attestation {with_dal = false}) + protocol let test_monitor_preconsensus = register_test @@ -680,7 +687,7 @@ module Mempool = struct let check_monitor_mempool p ~use_legacy_name = let name = - Operation.Anonymous.kind_to_string double_evidence_kind use_legacy_name + Operation.Anonymous.kind_to_string double_evidence_kind ~use_legacy_name in check_monitor_mempool p name in @@ -763,7 +770,7 @@ module Run_Simulate = struct let call_and_check_error ~use_legacy_name = Log.info "Create a %s operation, call %s and check that the call fail" - (Operation.Consensus.kind_to_string kind use_legacy_name) + (Operation.Consensus.kind_to_string kind ~use_legacy_name) (get_rpc_name rpc) ; let* consensus_op = @@ -780,7 +787,10 @@ module Run_Simulate = struct ~title:"Run operation with consensus operations" ~additionnal_tags:["run"; "operations"; "consensus"] @@ fun protocol -> - test_rpc_operation_unsupported Run Operation.Attestation protocol + test_rpc_operation_unsupported + Run + (Operation.Attestation {with_dal = false}) + protocol let test_run_operation_preconsensus = register_test @@ -794,7 +804,10 @@ module Run_Simulate = struct ~title:"Simulate operation with consensus operations" ~additionnal_tags:["simulate"; "operations"; "consensus"] @@ fun protocol -> - test_rpc_operation_unsupported Simulate Operation.Attestation protocol + test_rpc_operation_unsupported + Simulate + (Operation.Attestation {with_dal = false}) + protocol let test_simulate_operation_preconsensus = register_test @@ -812,7 +825,7 @@ module Run_Simulate = struct "Create a %s operation and call %s " (Operation.Anonymous.kind_to_string double_evidence_kind - use_legacy_name_in_input) + ~use_legacy_name:use_legacy_name_in_input) (get_rpc_name rpc) ; let* consensus_op = @@ -931,7 +944,8 @@ module Preapply = struct register_test ~title:"Preapply operation with consensus operations" ~additionnal_tags:["preapply"; "operations"; "consensus"] - @@ fun protocol -> test_consensus Operation.Attestation protocol + @@ fun protocol -> + test_consensus (Operation.Attestation {with_dal = false}) protocol let test_preapply_preconsensus = register_test @@ -1082,7 +1096,8 @@ module Block = struct register_test ~title:"Block consensus operations" ~additionnal_tags:["block"; "operations"; "consensus"] - @@ fun protocol -> test_block_consensus Operation.Attestation protocol + @@ fun protocol -> + test_block_consensus (Operation.Attestation {with_dal = false}) protocol let test_block_double_consensus_evidence double_evidence_kind protocol = let* node, client = Client.init_with_protocol ~protocol `Client () in @@ -1137,8 +1152,8 @@ module Block = struct "Bake 7 blocks to reach the end of a cycle with the metadata containing \ consensus rewards" ; let* () = repeat 7 (fun () -> Client.bake_for_and_wait ~node client) in - let get_name use_legacy_attestation_name = - if use_legacy_attestation_name then "endorsing" else "attesting" + let get_name ~use_legacy_name = + if use_legacy_name then "endorsing" else "attesting" in Log.info "Check block info RPC" ; -- GitLab From 741762ac912c24c1feeb5111b0dcd2b9b8299560 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 6 Feb 2024 13:28:01 +0100 Subject: [PATCH 2/2] DAL/Tezt: use attestations with DAL payload in DAL tests instead of the legacy DAL attestations --- tezt/lib_tezos/RPC.ml | 3 +- tezt/lib_tezos/RPC.mli | 1 + tezt/lib_tezos/operation_core.ml | 4 +- tezt/lib_tezos/operation_core.mli | 2 +- tezt/tests/dal.ml | 278 ++++++++++++++++++------------ 5 files changed, 176 insertions(+), 112 deletions(-) diff --git a/tezt/lib_tezos/RPC.ml b/tezt/lib_tezos/RPC.ml index f609ae61a42d..c8d2919259e8 100644 --- a/tezt/lib_tezos/RPC.ml +++ b/tezt/lib_tezos/RPC.ml @@ -799,11 +799,12 @@ let get_chain_block_context_contract_unstaked_frozen_balance ?(chain = "main") JSON.as_int let get_chain_block_helper_baking_rights ?(chain = "main") ?(block = "head") - ?delegate ?level ?cycle () = + ?delegate ?level ?cycle ?max_round () = let query_string = Query_arg.opt "delegate" Fun.id delegate @ Query_arg.opt "level" Int.to_string level @ Query_arg.opt "cycle" string_of_int cycle + @ Query_arg.opt "max_round" Int.to_string max_round in make ~query_string diff --git a/tezt/lib_tezos/RPC.mli b/tezt/lib_tezos/RPC.mli index eac762e15dd1..299078846bae 100644 --- a/tezt/lib_tezos/RPC.mli +++ b/tezt/lib_tezos/RPC.mli @@ -757,6 +757,7 @@ val get_chain_block_helper_baking_rights : ?delegate:string -> ?level:int -> ?cycle:int -> + ?max_round:int -> unit -> JSON.t t diff --git a/tezt/lib_tezos/operation_core.ml b/tezt/lib_tezos/operation_core.ml index b1a446d3adfa..750a8cbf54bc 100644 --- a/tezt/lib_tezos/operation_core.ml +++ b/tezt/lib_tezos/operation_core.ml @@ -397,9 +397,9 @@ module Consensus = struct delegate.public_key_hash (JSON.encode slots_json) - let get_block_payload_hash client = + let get_block_payload_hash ?block client = let* block_header = - Client.RPC.call client @@ RPC.get_chain_block_header () + Client.RPC.call client @@ RPC.get_chain_block_header ?block () in return JSON.(block_header |-> "payload_hash" |> as_string) end diff --git a/tezt/lib_tezos/operation_core.mli b/tezt/lib_tezos/operation_core.mli index 31245ec311d6..ebc79907756d 100644 --- a/tezt/lib_tezos/operation_core.mli +++ b/tezt/lib_tezos/operation_core.mli @@ -328,7 +328,7 @@ module Consensus : sig (** Calls the [GET /chains//blocks//header] RPC and extracts the head block's payload hash from the result. *) - val get_block_payload_hash : Client.t -> string Lwt.t + val get_block_payload_hash : ?block:string -> Client.t -> string Lwt.t end module Anonymous : sig diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index fa6228619082..e52e39633395 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -429,10 +429,32 @@ let wait_for_layer1_final_block dal_node level = Dal_node.wait_for dal_node "dal_node_layer_1_new_final_block.v0" (fun e -> if JSON.(e |-> "level" |> as_int) = level then Some () else None) -let inject_dal_attestation ?level ?(round = 0) ?force ?error ?request ~signer - ~nb_slots availability client = - let attestation = Array.make nb_slots false in - List.iter (fun i -> attestation.(i) <- true) availability ; +(* Return the baker at round 0 at the given level. *) +let baker_for_round_zero node ~level = + let* rights = + Node.RPC.call node + @@ RPC.get_chain_block_helper_baking_rights ~level ~max_round:0 () + in + JSON.(List.hd JSON.(rights |> as_list) |-> "delegate" |> as_string) |> return + +(* Return a delegate from the list of bootstrap accounts that is different from + the given delegate. *) +let different_delegate pkh = + List.find + (fun del -> not @@ String.equal pkh del.Account.public_key_hash) + (Array.to_list Account.Bootstrap.keys) + +(* Return the delegates from the list of bootstrap accounts that are different + from the given delegate. *) +let different_delegates pkh = + List.filter + (fun del -> not @@ String.equal pkh del.Account.public_key_hash) + (Array.to_list Account.Bootstrap.keys) + +let inject_dal_attestation ?level ?(round = 0) ?payload_level ?force ?error + ?request ~signer ~nb_slots availability client = + let dal_attestation = Array.make nb_slots false in + List.iter (fun i -> dal_attestation.(i) <- true) availability ; let* level = match level with Some level -> return level | None -> Client.level client in @@ -447,20 +469,34 @@ let inject_dal_attestation ?level ?(round = 0) ?force ?error ?request ~signer JSON.(List.hd JSON.(slots |> as_list) |-> "slots" |> as_list) |> List.hd |> JSON.as_int in + let* block_payload_hash = + let block = + (match payload_level with None -> level | Some l -> l) |> string_of_int + in + Operation.Consensus.get_block_payload_hash ~block client + in Operation.Consensus.inject ?force ?error ?request ~signer - (Operation.Consensus.dal_attestation ~level ~round ~attestation ~slot) + (Operation.Consensus.attestation + ~use_legacy_name:false + ~level + ~round + ~dal_attestation + ~slot + ~block_payload_hash + ()) client -let inject_dal_attestations ?level ?round ?force +let inject_dal_attestations ?payload_level ?level ?round ?force ?(signers = Array.to_list Account.Bootstrap.keys) ~nb_slots availability client = Lwt_list.map_s (fun signer -> inject_dal_attestation + ?payload_level ?level ?round ?force @@ -470,6 +506,17 @@ let inject_dal_attestations ?level ?round ?force client) signers +let inject_dal_attestations_and_bake node client ~number_of_slots indexes = + let* baker = + let* level = Node.get_level node in + baker_for_round_zero node ~level:(level + 1) + in + let signers = different_delegates baker in + let* _op_hashes = + inject_dal_attestations ~signers ~nb_slots:number_of_slots indexes client + in + bake_for ~delegates:(`For [baker]) client + let get_validated_dal_attestations_in_mempool node for_level = let* mempool_json = Node.RPC.call node @@ -519,12 +566,12 @@ let test_feature_flag _protocol _parameters _cryptobox node client ~msg:(rex "Data-availability layer will be enabled in a future proposal") process in - let* level = next_level node in + (* bake the block at level 2 because we cannot inject an attestation for block 1 *) + let* () = bake_for client in let* (`OpHash oph1) = inject_dal_attestation ~force:true ~nb_slots:params.number_of_slots - ~level ~signer:Constant.bootstrap1 [] client @@ -788,7 +835,11 @@ let test_slot_management_logic _protocol parameters cryptobox node client [1] client in - let* () = bake_for client in + let* baker = + let* level = Node.get_level node in + baker_for_round_zero node ~level:(level + 1) + in + let* () = bake_for ~delegates:(`For [baker]) client in let* metadata = Node.RPC.(call node @@ get_chain_block_metadata ()) in let attestation = match metadata.dal_attestation with @@ -809,21 +860,22 @@ let test_slot_management_logic _protocol parameters cryptobox node client (attestation.(1) = true) bool ~error_msg:"Expected slot 1 to be attested") ; check_dal_raw_context node -(** This test tests various situations related to DAL slots attestation. It's - many made of two parts (A) and (B). See the step inside the test. +(** This test tests various situations related to DAL slots attestation. + See the steps inside the test. *) -let test_slots_attestation_operation_behavior _protocol parameters cryptobox +let test_slots_attestation_operation_behavior _protocol parameters _cryptobox node client _bootstrap_key = (* Some helpers *) let nb_slots = parameters.Dal.Parameters.number_of_slots in let lag = parameters.attestation_lag in assert (lag > 1) ; - let attest ~level = + let attest ?payload_level ?(signer = Constant.bootstrap2) ~level () = inject_dal_attestation + ?payload_level ~force:true ~nb_slots ~level - ~signer:Constant.bootstrap2 + ~signer [0] client in @@ -854,91 +906,73 @@ let test_slots_attestation_operation_behavior _protocol parameters cryptobox attested |> return in - (* Just bake some blocks before starting publishing. *) - let* () = repeat (2 * lag) (fun () -> bake_for client) in + (* Just bake some blocks before starting attesting. *) + let* () = bake_for ~count:4 client in - (* Part A. - - No header published yet, just play with attestations with various levels; + (* No header published, we just play with attestations with various levels; - Initially, only [h3] is applied, [h1; h2] are outdated, and [h4] is branch_delayed. After baking a block, [h3] is included in a block and - [h4] becomes applied; + [h4] becomes applied. - No slot is confirmed as no slot header is published. *) let* now = Node.get_level node in - let* (`OpHash h1) = attest ~level:1 in + let* (`OpHash h1) = attest ~level:2 () in let outdated = [h1] in Log.info "expected mempool: outdated: h1 = %s" h1 ; let* () = mempool_is ~__LOC__ Mempool.{empty with outdated} in - let* (`OpHash h2) = attest ~level:(now - 1) in - let outdated = [h1; h2] in - Log.info "expected mempool: outdated: h1, h2 = %s" h2 ; - let* () = mempool_is ~__LOC__ Mempool.{empty with outdated} in - let* (`OpHash h3) = attest ~level:now in - Log.info "expected mempool: outdated: h1, h2; validated: h3 = %s" h3 ; + let* (`OpHash h2) = attest ~level:(now - 1) () in + (* level [now-1] is allowed in the mempool for attestations *) + let* (`OpHash h2') = attest ~level:(now - 2) () in + let outdated = [h1; h2'] in + Log.info "expected mempool: outdated: h1, h2' = %s, validated: h2 = %s" h2' h2 ; let* () = - mempool_is ~__LOC__ Mempool.{empty with outdated; validated = [h3]} + mempool_is ~__LOC__ Mempool.{empty with outdated; validated = [h2]} in - let* (`OpHash h4) = attest ~level:(now + 1) in + let* (`OpHash h3) = attest ~level:now () in + Log.info "expected mempool: outdated: h1, h2', validated: h2, h3 = %s" h3 ; let* () = - mempool_is - ~__LOC__ - Mempool.{empty with outdated; validated = [h3]; branch_delayed = [h4]} + mempool_is ~__LOC__ Mempool.{empty with outdated; validated = [h2; h3]} + in + (* Level [now+1] is allowed in the mempool for attestations, so we inject for + level [now+2]. We also take care that the attester is not the same one as + the baker (who will also inject an attestation, and the two ops will + conflict). *) + let* baker1 = baker_for_round_zero node ~level:(now + 1) in + let* baker2 = baker_for_round_zero node ~level:(now + 2) in + let signer1 = different_delegate baker1 in + let signer2 = different_delegate baker1 in + let* (`OpHash h4) = + attest ~payload_level:now ~level:(now + 1) ~signer:signer1 () + in + let* (`OpHash h4') = + attest ~payload_level:now ~level:(now + 2) ~signer:signer2 () in - let* () = bake_for client in - Log.info "expected mempool: outdated: h1, h2, validated: h4 = %s" h4 ; + Log.info + "expected mempool: outdated: h1, h2', validated: h2, h3, h4 = %s, \ + branch_delayed: h4' = %s" + h4 + h4' ; let* () = - mempool_is ~__LOC__ Mempool.{empty with outdated; validated = [h4]} - in - let* () = check_slots_availability ~__LOC__ ~attested:[] in - (* Part B. - - Publish a slot header (index 10) and bake; - - All delegates attest the slot, but the operation is injected too early. - The operation is branch_delayed; - - We bake sufficiently many blocks to get the attestation applied and - included in a block; - - We check in the metadata that the slot with index 10 is attested. - *) - let* (`OpHash h5) = - publish_dummy_slot - ~source:Constant.bootstrap1 - ~fee:1_200 - ~index:10 - ~message:" TEST!!! " - cryptobox - client + mempool_is + ~__LOC__ + Mempool. + {empty with outdated; validated = [h2; h3; h4]; branch_delayed = [h4']} in - Log.info "expected mempool: outdated: h1, h2, validated: h4, h5 = %s" h5 ; + let* () = bake_for ~delegates:(`For [baker1]) client in + let outdated = [h1; h2; h2'] in + (* [h4] and [h4'] cannot be included because their payload hash is wrong. *) let* () = - mempool_is ~__LOC__ Mempool.{empty with outdated; validated = [h4; h5]} + mempool_is ~__LOC__ Mempool.{empty with outdated; validated = [h4; h4']} in - let* () = bake_for client in - let* now = Node.get_level node in - let level = now + lag - 1 in - let* attestation_ops = - let* hashes = - inject_dal_attestations ~force:true ~nb_slots ~level [10] client - in - return @@ List.map (fun (`OpHash h) -> h) hashes + let* () = bake_for ~delegates:(`For [baker2]) client in + let* _json = + Node.RPC.call node + @@ RPC.get_chain_block_operations_validation_pass ~validation_pass:0 () in - Log.info - "Injected %d ops at level %d (current_level = %d, lag = %d)" - (List.length attestation_ops) - level - now - lag ; - let branch_delayed = attestation_ops in - let* () = mempool_is ~__LOC__ Mempool.{empty with outdated; branch_delayed} in - let* () = repeat (lag - 1) (fun () -> bake_for client) in let* () = - mempool_is - ~__LOC__ - Mempool.{empty with outdated; validated = attestation_ops} + mempool_is ~__LOC__ Mempool.{empty with outdated; validated = [h4; h4']} in - let* () = check_slots_availability ~__LOC__ ~attested:[] in - let* () = bake_for client in - Log.info "expected mempool: outdated: h1, h2" ; - let* () = mempool_is ~__LOC__ Mempool.{empty with outdated} in - check_slots_availability ~__LOC__ ~attested:[10] + check_slots_availability ~__LOC__ ~attested:[] (* Tests that DAL attestations are only included in a block if the attestation is from a DAL-committee member. This test may be fail sometimes (with @@ -950,6 +984,7 @@ let test_slots_attestation_operation_dal_committee_membership_check protocol (* The attestation from the bootstrap account should succeed as the bootstrap node has sufficient stake to be in the DAL committee. *) let nb_slots = parameters.Dal.Parameters.number_of_slots in + let* () = bake_for client in let* level = Client.level client in let* (`OpHash _oph) = inject_dal_attestation @@ -1019,22 +1054,46 @@ let test_slots_attestation_operation_dal_committee_membership_check protocol Log.info "Bake another block to change the DAL committee" ; let* () = bake_for client in iter ()) - else + else ( + Log.info + "We first check that the new account is in the Tenderbake committee" ; + let* validators = + Client.RPC.call client + @@ RPC.get_chain_block_helper_validators ~level () + in + let is_validator = + List.exists + (fun validator -> + JSON.(validator |-> "delegate" |> as_string) + |> String.equal new_account.public_key_hash) + (JSON.as_list validators) + in + Check.( + (is_validator = true) + bool + ~error_msg: + "The new account is not a validator, the test needs to be adapted") ; let* (`OpHash _oph) = - inject_dal_attestation - ~error: - (rex - (sf - "%s is not part of the DAL committee for the level %d" - new_account.public_key_hash - level)) - ~nb_slots - ~level - ~signer:new_account - [] - client + inject_dal_attestation ~nb_slots ~level ~signer:new_account [] client in - unit + (* Bake with all the bootstrap accounts, but not with the new account. *) + let* () = + let bootstrap_accounts = + Array.to_list Account.Bootstrap.keys + |> List.map (fun a -> a.Account.public_key_hash) + in + bake_for ~delegates:(`For bootstrap_accounts) client + in + let* json = + Node.RPC.call node + @@ RPC.get_chain_block_operations_validation_pass ~validation_pass:0 () + in + let num_ops = JSON.as_list json |> List.length in + Check.( + (num_ops = Array.length Account.Bootstrap.keys) + int + ~error_msg:"Expected %R operations, found %L") ; + unit) in iter () @@ -1086,7 +1145,7 @@ let publish_and_store_slot ?with_proof ?counter ?force ?(fee = 1_200) client in return commitment -let publish_store_and_attest_slot ?with_proof ?counter ?force ?fee client +let publish_store_and_attest_slot ?with_proof ?counter ?force ?fee client node dal_node source ~index ~content ~attestation_lag ~number_of_slots = let* _commitment = publish_and_store_slot @@ -1101,10 +1160,7 @@ let publish_store_and_attest_slot ?with_proof ?counter ?force ?fee client content in let* () = repeat attestation_lag (fun () -> bake_for client) in - let* _op_hashes = - inject_dal_attestations ~nb_slots:number_of_slots [index] client - in - bake_for client + inject_dal_attestations_and_bake node client ~number_of_slots [index] let check_get_commitment dal_node ~slot_level check_result slots_info = Lwt_list.iter_s @@ -1343,18 +1399,21 @@ let test_dal_node_slots_headers_tracking _protocol parameters _cryptobox node "Attest slots slot0 and slot2_b, and wait for the attestations to be final" ; let attested = [slot0; slot2_b] in let unattested = [slot1] in - let nb_slots = parameters.Dal.Parameters.number_of_slots in + let number_of_slots = parameters.Dal.Parameters.number_of_slots in let* () = bake_for ~count:(lag - 3) client in - let* _op_hash = - inject_dal_attestations ~nb_slots (List.map fst attested) client - in let wait_block_processing3 = let attested_level = pub_level + lag in wait_for_layer1_final_block dal_node attested_level in - let* () = bake_for ~count:3 client in + let* () = + inject_dal_attestations_and_bake + node + client + ~number_of_slots + (List.map fst attested) + in + let* () = bake_for ~count:2 client in let* () = wait_block_processing3 in - let* () = (* The number of published slots has not changed *) check_published_level_headers ~__LOC__ ~pub_level ~number_of_headers:4 @@ -1744,7 +1803,7 @@ let send_messages ?(bake = true) ?(src = Constant.bootstrap2.alias) if bake then bake_for client else unit let rollup_node_stores_dal_slots ?expand_test protocol parameters dal_node - sc_rollup_node sc_rollup_address _node client _pvm_name = + sc_rollup_node sc_rollup_address node client _pvm_name = (* Check that the rollup node downloaded the confirmed slots to which it is subscribed: @@ -1869,10 +1928,9 @@ let rollup_node_stores_dal_slots ?expand_test protocol parameters dal_node Log.info "Step 6: attest only slots 1 and 2" ; let* () = repeat (attestation_lag - 1) (fun () -> bake_for client) in - let* _ops_hashes = - inject_dal_attestations ~nb_slots:number_of_slots [2; 1] client + let* () = + inject_dal_attestations_and_bake node client ~number_of_slots [2; 1] in - let* () = bake_for client in let* slot_confirmed_level = Sc_rollup_node.wait_for_level sc_rollup_node @@ -2076,6 +2134,7 @@ let test_reveal_dal_page_in_fast_exec_wasm_pvm _protocol parameters dal_node let* () = publish_store_and_attest_slot client + node dal_node Constant.bootstrap1 ~index:0 @@ -4100,6 +4159,7 @@ module Tx_kernel_e2e = struct let* () = publish_store_and_attest_slot client + node dal_node Constant.bootstrap1 ~index:slot_index @@ -4116,6 +4176,7 @@ module Tx_kernel_e2e = struct let* () = publish_store_and_attest_slot client + node dal_node Constant.bootstrap1 ~index:slot_index @@ -4184,6 +4245,7 @@ module Tx_kernel_e2e = struct let* () = publish_store_and_attest_slot client + node dal_node Constant.bootstrap1 ~index:0 -- GitLab