From 8cd43082348cbeb1d9a176ad8ca4466141d9d981 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 18 Feb 2025 06:05:59 +0100 Subject: [PATCH 1/8] DAL/Tests: be able to set blocks_per_commitment --- tezt/tests/dal.ml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index cddd2ed32577..6c755a24bba3 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -501,7 +501,7 @@ let with_layer1 ?custom_constants ?additional_bootstrap_accounts ?dal_rewards_weight ?traps_fraction ?event_sections_levels ?node_arguments ?activation_timestamp ?dal_bootstrap_peers ?(parameters = []) ?(prover = true) ?smart_rollup_timeout_period_in_blocks ?l1_history_mode - ?blocks_per_cycle f ~protocol = + ?blocks_per_cycle ?blocks_per_commitment f ~protocol = let parameter_overrides = make_int_parameter ["dal_parametric"; "attestation_lag"] attestation_lag @ make_int_parameter ["dal_parametric"; "number_of_shards"] number_of_shards @@ -547,6 +547,7 @@ let with_layer1 ?custom_constants ?additional_bootstrap_accounts make_bool_parameter ["adaptive_issuance_force_activation"] (Some true) else []) @ make_int_parameter ["blocks_per_cycle"] blocks_per_cycle + @ make_int_parameter ["blocks_per_commitment"] blocks_per_commitment @ parameters in @@ -628,7 +629,7 @@ let scenario_with_layer1_node ?attestation_threshold ?regression ?(tags = []) ?(dal_enable = true) ?incentives_enable ?traps_fraction ?dal_rewards_weight ?event_sections_levels ?node_arguments ?activation_timestamp ?consensus_committee_size ?minimal_block_delay ?delay_increment_per_round - ?blocks_per_cycle variant scenario = + ?blocks_per_cycle ?blocks_per_commitment variant scenario = let description = "Testing DAL L1 integration" in let tags = if List.mem team tags then tags else team :: tags in let tags = @@ -643,6 +644,7 @@ let scenario_with_layer1_node ?attestation_threshold ?regression ?(tags = []) (fun protocol -> with_layer1 ?blocks_per_cycle + ?blocks_per_commitment ?attestation_threshold ~custom_constants ?additional_bootstrap_accounts -- GitLab From bb3b4b006d74db80d11113b64c89fc6414dd01aa Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 18 Feb 2025 06:06:41 +0100 Subject: [PATCH 2/8] DAL/Tests: set blocks_per_commitment to blocks_per_cycle in participation test This ensures that there is no nonce to reveal, and thus a delegate does not lose its TB attesting rewards because of this. --- tezt/tests/dal.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 6c755a24bba3..b9946d12750e 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -10032,7 +10032,8 @@ let register ~protocols = who attest sufficiently. *) ~attestation_threshold:30 ~attestation_lag:2 - ~blocks_per_cycle:16 ; + ~blocks_per_cycle:16 + ~blocks_per_commitment:16 ; scenario_with_layer1_node ~attestation_lag:5 "slots attestation operation behavior" -- GitLab From 7e3a44817f3595696d0cd966fd88a9d879efc4b5 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 18 Feb 2025 06:10:11 +0100 Subject: [PATCH 3/8] DAL/Tests: when building an attestation, treat case when attester has no slots --- tezt/tests/dal.ml | 177 +++++++++++++++++++++++++++++++--------------- 1 file changed, 120 insertions(+), 57 deletions(-) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index b9946d12750e..f4a68d4acd0b 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -860,47 +860,81 @@ let craft_dal_attestation ?level ?round ?payload_level ~signer ~nb_slots let* level = match level with Some level -> return level | None -> Client.level client in - let* slots = + let* json = Client.RPC.call client @@ RPC.get_chain_block_helper_validators ~level ~delegate:signer.Account.public_key_hash () in - let slot = - JSON.(List.hd JSON.(slots |> as_list) |-> "slots" |> as_list) - |> List.hd |> JSON.as_int - in - let* block_payload_hash, round = - let block = - (match payload_level with None -> level | Some l -> l) |> string_of_int - in - let* block_payload_hash = - Operation.Consensus.get_block_payload_hash ~block client - in - let* round = - match round with - | None -> - Client.RPC.call client @@ RPC.get_chain_block_helper_round ~block () - | Some round -> return round - in - return (block_payload_hash, round) - in - Operation.Consensus.operation - ~with_dal:true - ~signer - (Operation.Consensus.attestation - ~level - ~round - ?dal_attestation - ~slot - ~block_payload_hash - ()) - client + match JSON.(json |> as_list) with + | [] -> + Log.info + "[craft_dal_attestation] %s not in TB committee at level %d" + signer.public_key_hash + level ; + none + | [validator] -> + let slots = JSON.(validator |-> "slots" |> as_list) in + let slot = List.hd slots |> JSON.as_int in + let* block_payload_hash, round = + let block = + Option.value payload_level ~default:level |> string_of_int + in + let* block_payload_hash = + Operation.Consensus.get_block_payload_hash ~block client + in + let* round = + match round with + | None -> + Client.RPC.call client + @@ RPC.get_chain_block_helper_round ~block () + | Some round -> return round + in + return (block_payload_hash, round) + in + let* op = + Operation.Consensus.operation + ~with_dal:true + ~signer + (Operation.Consensus.attestation + ~level + ~round + ?dal_attestation + ~slot + ~block_payload_hash + ()) + client + in + some op + | _ -> + Test.fail + ~__LOC__ + "Unexpected format for get_chain_block_helper_validators RPC" + +let craft_dal_attestation_exn ?level ?round ?payload_level ~signer ~nb_slots + availability client = + let* res = + craft_dal_attestation + ?level + ?round + ?payload_level + ~signer + ~nb_slots + availability + client + in + match res with + | None -> + Test.fail + ~__LOC__ + "Unexpected case: pkh %s has no TB slot" + signer.Account.public_key_hash + | Some v -> return v let inject_dal_attestation ?level ?round ?payload_level ?force ?error ?request ~signer ~nb_slots availability client = - let* op = + let* op_opt = craft_dal_attestation ?level ?round @@ -910,13 +944,39 @@ let inject_dal_attestation ?level ?round ?payload_level ?force ?error ?request availability client in - let* oph = Operation.inject ?force ?error ?request op client in - return (op, oph) + match op_opt with + | None -> none + | Some op -> + let* oph = Operation.inject ?force ?error ?request op client in + some (op, oph) + +let inject_dal_attestation_exn ?level ?round ?payload_level ?force ?error + ?request ~signer ~nb_slots availability client = + let* res = + inject_dal_attestation + ?level + ?round + ?payload_level + ?force + ?error + ?request + ~signer + ~nb_slots + availability + client + in + match res with + | None -> + Test.fail + ~__LOC__ + "Unexpected case: pkh %s has no TB slot" + signer.Account.public_key_hash + | Some v -> return v let inject_dal_attestations ?payload_level ?level ?round ?force ?request ?(signers = Array.to_list Account.Bootstrap.keys) ~nb_slots availability client = - Lwt_list.map_s + Lwt_list.filter_map_s (fun signer -> inject_dal_attestation ?payload_level @@ -1328,7 +1388,7 @@ let test_slots_attestation_operation_behavior _protocol parameters _cryptobox assert (lag > 1) ; let attest ?payload_level ?(signer = Constant.bootstrap2) ~level () = let* _op, op_hash = - inject_dal_attestation + inject_dal_attestation_exn ?payload_level ~force:true ~nb_slots @@ -1517,7 +1577,7 @@ let test_slots_attestation_operation_dal_committee_membership_check _protocol let* () = bake_for client in let* level = Client.level client in let* _op, `OpHash _oph = - inject_dal_attestation + inject_dal_attestation_exn ~nb_slots ~level ~signer:Constant.bootstrap1 @@ -1583,7 +1643,7 @@ let test_slots_attestation_operation_dal_committee_membership_check _protocol check_in_TB_committee ~__LOC__ node new_account.public_key_hash ~level in let* _op, `OpHash _oph = - inject_dal_attestation + inject_dal_attestation_exn ~error:Operation.dal_data_availibility_attester_not_in_committee ~nb_slots ~level @@ -8698,7 +8758,11 @@ let test_inject_accusation _protocol dal_parameters cryptobox node client let availability = Slots [slot_index] in let signer = Constant.bootstrap2 in let* attestation, _op_hash = - inject_dal_attestation ~signer ~nb_slots:number_of_slots availability client + inject_dal_attestation_exn + ~signer + ~nb_slots:number_of_slots + availability + client in let* signature = Operation.sign attestation client in let attestation = (attestation, signature) in @@ -8876,7 +8940,7 @@ let test_attester_did_not_attest (_protocol : Protocol.t) log_step "Crafting attestation for [bootstrap3] (with expected DAL attestation)." ; let* op1 = - craft_dal_attestation + craft_dal_attestation_exn ~nb_slots:dal_params.number_of_slots ~signer:Constant.bootstrap3 (Slots [index]) @@ -8886,7 +8950,7 @@ let test_attester_did_not_attest (_protocol : Protocol.t) let op1_promise = wait_for_classified oph1 node in log_step "Crafting attestation for [bootstrap2] (with empty DAL attestation)." ; let* op2 = - craft_dal_attestation + craft_dal_attestation_exn ~nb_slots:dal_params.number_of_slots ~signer:Constant.bootstrap2 (Slots []) @@ -9032,7 +9096,7 @@ let test_duplicate_denunciations _protocol dal_parameters cryptobox node client let availability = Slots [slot_index] in let signer = Constant.bootstrap2 in let* attestation, _op_hash = - inject_dal_attestation + inject_dal_attestation_exn ~signer ~nb_slots:dal_parameters.number_of_slots availability @@ -9181,7 +9245,7 @@ let test_denunciation_next_cycle _protocol dal_parameters cryptobox node client Log.info "Injecting a first attestation at level %d" current_level ; let availability = Slots [slot_index] in let* attestation, _op_hash = - inject_dal_attestation + inject_dal_attestation_exn ~signer:Constant.bootstrap2 ~nb_slots:dal_parameters.number_of_slots availability @@ -9230,7 +9294,7 @@ let test_denunciation_next_cycle _protocol dal_parameters cryptobox node client let availability = Slots [slot_index] in let signer = Constant.bootstrap2 in let* attestation, _op_hash = - inject_dal_attestation + inject_dal_attestation_exn ~signer ~nb_slots:dal_parameters.number_of_slots availability @@ -9679,7 +9743,7 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client let* level = Node.get_level node in let count_dal_attesting_bakers = ref 0 in (* 1. Baker always attests TB and all DAL slots *) - let* (_ : (Operation_core.t * [`OpHash of peer_id]) list) = + let* (_ : Operation_core.t * [`OpHash of peer_id]) = (* The baker delegate will miss 1/10 of its DAL attestations and will send [No_dal_attestation] in this case. *) let baker_attestation = @@ -9688,14 +9752,14 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client incr count_dal_attesting_bakers ; Slots all_slots) in - inject_dal_attestations - ~signers:[baker] + inject_dal_attestation_exn + ~signer:baker ~nb_slots baker_attestation client in (* 2. attesting_dal_slot_10 always attests TB and DAL slot 10 *) - let* (_ : (Operation_core.t * [`OpHash of peer_id]) list) = + let* (_ : Operation_core.t * [`OpHash of peer_id]) = (* The attesting_dal_slot_10 delegate misses 1/11th of its DAL attestations and will send Slots [], but it should be fine for its rewards. *) @@ -9705,36 +9769,35 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client incr count_dal_attesting_bakers ; Slots [10]) in - inject_dal_attestations - ~signers:[attesting_dal_slot_10] + inject_dal_attestation_exn + ~signer:attesting_dal_slot_10 ~nb_slots attestation client in (* 3. not_attesting_at_all is not attesting neither TB nor DAL slots *) (* 4. not_attesting_dal either sends no DAL content or sends bitset 0 *) - let* (_ : (Operation_core.t * [`OpHash of peer_id]) list) = + let* (_ : Operation_core.t * [`OpHash of peer_id]) = let dal_attestation = if level mod 2 = 0 then No_dal_attestation else Slots [] in - inject_dal_attestations - ~signers:[not_attesting_dal] + inject_dal_attestation_exn + ~signer:not_attesting_dal ~nb_slots dal_attestation client in (* 5. not_sufficiently_attesting_dal_slot_10: is attesting DAL slot 10, but only 25% of the time. *) - let* (_ : (Operation_core.t * [`OpHash of peer_id]) list) = - let* level = Node.get_level node in + let* (_ : Operation_core.t * [`OpHash of peer_id]) = let slots_to_attest = if level mod 4 = 0 then ( incr count_dal_attesting_bakers ; Slots [10]) else No_dal_attestation in - inject_dal_attestations - ~signers:[not_sufficiently_attesting_dal_slot_10] + inject_dal_attestation_exn + ~signer:not_sufficiently_attesting_dal_slot_10 ~nb_slots slots_to_attest client -- GitLab From c98a3c43605b023b44974ff5e007b76cb1c0b273 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Thu, 6 Mar 2025 09:30:02 +0100 Subject: [PATCH 4/8] DAL/Tests: call RPCs via the node when possible --- tezt/tests/dal.ml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index f4a68d4acd0b..a4c5704001af 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -333,7 +333,8 @@ let generate_protocol_parameters base protocol parameter_overrides = Protocol.write_parameter_file ~base parameter_overrides in let* client = Client.init_mockup ~parameter_file ~protocol () in - Client.RPC.call client @@ RPC.get_chain_block_context_constants () + Client.RPC.call_via_endpoint client + @@ RPC.get_chain_block_context_constants () (* Compute the L1 history mode. This function may update the protocol parameters and this is why it needs additional, a priori unrelated parameters. *) @@ -861,7 +862,7 @@ let craft_dal_attestation ?level ?round ?payload_level ~signer ~nb_slots match level with Some level -> return level | None -> Client.level client in let* json = - Client.RPC.call client + Client.RPC.call_via_endpoint client @@ RPC.get_chain_block_helper_validators ~level ~delegate:signer.Account.public_key_hash @@ -887,7 +888,7 @@ let craft_dal_attestation ?level ?round ?payload_level ~signer ~nb_slots let* round = match round with | None -> - Client.RPC.call client + Client.RPC.call_via_endpoint client @@ RPC.get_chain_block_helper_round ~block () | Some round -> return round in @@ -1295,13 +1296,11 @@ let test_slot_management_logic protocol parameters cryptobox node client Mempool.classified_typ ~error_msg:"Expected all the operations to be applied. Got %L") ; let* () = bake_for client in - let* bytes = - Client.RPC.call client @@ RPC.get_chain_block_context_raw_bytes () - in + let* bytes = Node.RPC.call node @@ RPC.get_chain_block_context_raw_bytes () in if JSON.(bytes |-> "dal" |> is_null) then Test.fail "Expected the context to contain some information about the DAL" ; let* operations_result = - Client.RPC.call client @@ RPC.get_chain_block_operations () + Node.RPC.call node @@ RPC.get_chain_block_operations () in let fees_error = Failed @@ -7603,7 +7602,7 @@ let scenario_tutorial_dal_baker = let* () = bake_for ~count:(num_cycles * blocks_per_cycle) client in let* attestation_rights = - Client.RPC.call client + Node.RPC.call node @@ RPC.get_chain_block_helper_attestation_rights ~delegate:my_baker.public_key_hash () @@ -7622,7 +7621,7 @@ let scenario_tutorial_dal_baker = (* Only test the request can be processed *) let* _ = - Client.RPC.call client @@ RPC.get_chain_block_context_dal_shards () + Node.RPC.call node @@ RPC.get_chain_block_context_dal_shards () in (* Launch dal node (Step 4) *) -- GitLab From 7c882ae0a32922a916a4e3f84e80217d5c497607 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 18 Feb 2025 06:12:46 +0100 Subject: [PATCH 5/8] Tezt/Tezos: add helper function to get TB participation --- tezt/lib_tezos/RPC.ml | 46 +++++++++++++++++++++++++++++++++++++++++- tezt/lib_tezos/RPC.mli | 18 ++++++++++++++++- tezt/tests/dal.ml | 16 +++++++++------ 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/tezt/lib_tezos/RPC.ml b/tezt/lib_tezos/RPC.ml index a23206215f4f..21f18807f815 100644 --- a/tezt/lib_tezos/RPC.ml +++ b/tezt/lib_tezos/RPC.ml @@ -1462,7 +1462,7 @@ let get_chain_block_context_delegate_min_delegated_in_current_cycle ] Fun.id -let get_chain_block_context_delegate_participation ?(chain = "main") +let get_chain_block_context_delegate_participation_raw ?(chain = "main") ?(block = "head") pkh = make GET @@ -1478,6 +1478,50 @@ let get_chain_block_context_delegate_participation ?(chain = "main") ] Fun.id +type participation = { + expected_cycle_activity : int; + minimal_cycle_activity : int; + missed_slots : int; + missed_levels : int; + remaining_allowed_missed_slots : int; + expected_attesting_rewards : Tez.t; +} + +let get_chain_block_context_delegate_participation ?(chain = "main") + ?(block = "head") pkh = + make + GET + [ + "chains"; + chain; + "blocks"; + block; + "context"; + "delegates"; + pkh; + "participation"; + ] + @@ fun json -> + let open JSON in + let expected_cycle_activity = json |-> "expected_cycle_activity" |> as_int in + let minimal_cycle_activity = json |-> "minimal_cycle_activity" |> as_int in + let missed_slots = json |-> "missed_slots" |> as_int in + let missed_levels = json |-> "missed_levels" |> as_int in + let remaining_allowed_missed_slots = + json |-> "remaining_allowed_missed_slots" |> as_int + in + let expected_attesting_rewards = + json |-> "expected_attesting_rewards" |> as_int64 |> Tez.of_mutez_int64 + in + { + expected_cycle_activity : int; + minimal_cycle_activity : int; + missed_slots : int; + missed_levels : int; + remaining_allowed_missed_slots : int; + expected_attesting_rewards : Tez.t; + } + let get_chain_block_context_delegate_dal_participation ?(chain = "main") ?(block = "head") pkh = make diff --git a/tezt/lib_tezos/RPC.mli b/tezt/lib_tezos/RPC.mli index d9742b3b2ce2..ea772e8823dd 100644 --- a/tezt/lib_tezos/RPC.mli +++ b/tezt/lib_tezos/RPC.mli @@ -1156,9 +1156,25 @@ val get_chain_block_context_delegate_min_delegated_in_current_cycle : [chain] defaults to ["main"]. [block] defaults to ["head"]. *) -val get_chain_block_context_delegate_participation : +val get_chain_block_context_delegate_participation_raw : ?chain:string -> ?block:string -> string -> JSON.t t +type participation = { + expected_cycle_activity : int; + minimal_cycle_activity : int; + missed_slots : int; + missed_levels : int; + remaining_allowed_missed_slots : int; + expected_attesting_rewards : Tez.t; +} + +(** RPC: [GET /chains//blocks//context/delegates//participation] + + [chain] defaults to ["main"]. + [block] defaults to ["head"]. *) +val get_chain_block_context_delegate_participation : + ?chain:string -> ?block:string -> string -> participation t + (** RPC: [GET /chains//blocks//context/delegates//dal_participation] [chain] defaults to ["main"]. diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index a4c5704001af..1ab78590307b 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -9608,13 +9608,12 @@ let get_dal_participation l1_node public_key_hash = } let get_tb_expected_attesting_rewards l1_node public_key_hash = - let open JSON in - let* json = + let* participation = Node.RPC.( call l1_node @@ get_chain_block_context_delegate_participation public_key_hash) in - return (json |-> "expected_attesting_rewards" |> as_int) + return participation.expected_attesting_rewards (** [test_dal_rewards_distribution _protocol dal_parameters cryptobox node client _dal_node] verifies the correct distribution of DAL rewards among @@ -10022,7 +10021,12 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client - the participation RPC's result is aligned with the first check. *) List.iter (fun (account, bal1, bal2) -> - check_bal_incr ~__LOC__ account bal1 bal2 ~delta:expected_full_tb_rewards ; + check_bal_incr + ~__LOC__ + account + bal1 + bal2 + ~delta:(Tez.to_mutez expected_full_tb_rewards) ; let dal_participation = List.assoc account bootstrap_accounts_participation in @@ -10031,7 +10035,7 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client ~__LOC__ ~error_msg: ("account " ^ account.Account.public_key_hash - ^ ", expected to have insufficnent DAL participation.")) + ^ ", expected to have sufficient DAL participation?")) [ (not_attesting_dal, not_attesting_dal_bal1, not_attesting_dal_bal2); ( not_sufficiently_attesting_dal_slot_10, @@ -10046,7 +10050,7 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client attesting_dal_slot_10 attesting_dal_slot_10_bal1 attesting_dal_slot_10_bal2 - ~delta:(expected_full_tb_rewards + expected_full_dal_rewards) ; + ~delta:(Tez.to_mutez expected_full_tb_rewards + expected_full_dal_rewards) ; let dal_participation = List.assoc attesting_dal_slot_10 bootstrap_accounts_participation in -- GitLab From 9d70ebd5fd3c7f18a4aac5ff9e123fa65464df38 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Mon, 10 Mar 2025 10:07:05 +0100 Subject: [PATCH 6/8] Tezt/Tezos: add helper function to get DAL participation --- tezt/lib_tezos/RPC.ml | 52 ++++++++++++++++++- tezt/lib_tezos/RPC.mli | 18 ++++++- tezt/tests/dal.ml | 115 ++++++++--------------------------------- 3 files changed, 89 insertions(+), 96 deletions(-) diff --git a/tezt/lib_tezos/RPC.ml b/tezt/lib_tezos/RPC.ml index 21f18807f815..e509189f69dc 100644 --- a/tezt/lib_tezos/RPC.ml +++ b/tezt/lib_tezos/RPC.ml @@ -1522,7 +1522,7 @@ let get_chain_block_context_delegate_participation ?(chain = "main") expected_attesting_rewards : Tez.t; } -let get_chain_block_context_delegate_dal_participation ?(chain = "main") +let get_chain_block_context_delegate_dal_participation_raw ?(chain = "main") ?(block = "head") pkh = make GET @@ -1538,6 +1538,56 @@ let get_chain_block_context_delegate_dal_participation ?(chain = "main") ] Fun.id +type dal_participation = { + expected_assigned_shards_per_slot : int; + delegate_attested_dal_slots : int; + delegate_attestable_dal_slots : int; + expected_dal_rewards : Tez.t; + sufficient_dal_participation : bool; + denounced : bool; +} + +let get_chain_block_context_delegate_dal_participation ?(chain = "main") + ?(block = "head") pkh = + make + GET + [ + "chains"; + chain; + "blocks"; + block; + "context"; + "delegates"; + pkh; + "dal_participation"; + ] + @@ fun json -> + let open JSON in + let expected_assigned_shards_per_slot = + json |-> "expected_assigned_shards_per_slot" |> as_int + in + let delegate_attested_dal_slots = + json |-> "delegate_attested_dal_slots" |> as_int + in + let delegate_attestable_dal_slots = + json |-> "delegate_attestable_dal_slots" |> as_int + in + let expected_dal_rewards = + json |-> "expected_dal_rewards" |> as_int64 |> Tez.of_mutez_int64 + in + let sufficient_dal_participation = + json |-> "sufficient_dal_participation" |> as_bool + in + let denounced = json |-> "denounced" |> as_bool in + { + expected_assigned_shards_per_slot; + delegate_attested_dal_slots; + delegate_attestable_dal_slots; + expected_dal_rewards; + sufficient_dal_participation; + denounced; + } + let get_chain_block_context_delegate_frozen_balance ?(chain = "main") ?(block = "head") pkh = make diff --git a/tezt/lib_tezos/RPC.mli b/tezt/lib_tezos/RPC.mli index ea772e8823dd..d63ac836a3f4 100644 --- a/tezt/lib_tezos/RPC.mli +++ b/tezt/lib_tezos/RPC.mli @@ -1179,9 +1179,25 @@ val get_chain_block_context_delegate_participation : [chain] defaults to ["main"]. [block] defaults to ["head"]. *) -val get_chain_block_context_delegate_dal_participation : +val get_chain_block_context_delegate_dal_participation_raw : ?chain:string -> ?block:string -> string -> JSON.t t +type dal_participation = { + expected_assigned_shards_per_slot : int; + delegate_attested_dal_slots : int; + delegate_attestable_dal_slots : int; + expected_dal_rewards : Tez.t; + sufficient_dal_participation : bool; + denounced : bool; +} + +(** RPC: [GET /chains//blocks//context/delegates//dal_participation] + + [chain] defaults to ["main"]. + [block] defaults to ["head"]. *) +val get_chain_block_context_delegate_dal_participation : + ?chain:string -> ?block:string -> string -> dal_participation t + (** RPC: [GET /chains//blocks//context/delegates//balance] [chain] defaults to ["main"]. diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 1ab78590307b..49d28db1000e 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -4718,11 +4718,8 @@ let test_migration_accuser_issue ~migrate_from ~migrate_to = ~block:(string_of_int (last_level - 1)) delegate.Account.public_key_hash in - let is_denounced = - JSON.(dal_participation |-> "denounced" |> as_bool) - in Check.is_false - is_denounced + dal_participation.denounced ~__LOC__ ~error_msg:"Expected the delegate to not be denounced" ; unit) @@ -8484,52 +8481,36 @@ let extract_dal_balance_updates balance_updates = let check_participation_and_rewards participation ~expected_assigned_shards ~expected_attestable_slots ~attesting_reward_per_shard dal_balance_updates delegate ~sufficient_participation = - let json = participation in - let denounced = JSON.(json |-> "denounced" |> as_bool) in - Check.( - (denounced = false) - ~__LOC__ - bool - ~error_msg:"The delegate was unexpectedly denounced") ; - let expected_assigned_shards_per_slot = - JSON.(json |-> "expected_assigned_shards_per_slot" |> as_int) - in + Check.is_false + participation.RPC.denounced + ~__LOC__ + ~error_msg:"The delegate was unexpectedly denounced" ; Check.( - (expected_assigned_shards_per_slot = expected_assigned_shards) + (participation.expected_assigned_shards_per_slot = expected_assigned_shards) ~__LOC__ int ~error_msg:"Unexpected number of assigned shards. Expected %R, got %L") ; - let delegate_attested_dal_slots = - JSON.(json |-> "delegate_attested_dal_slots" |> as_int) - in let expected_attested_slots = if sufficient_participation then expected_attestable_slots else 0 in Check.( - (delegate_attested_dal_slots = expected_attested_slots) + (participation.delegate_attested_dal_slots = expected_attested_slots) ~__LOC__ int ~error_msg:"Expected that the delegate has attested %L slots, got %R") ; - let delegate_attestable_dal_slots = - JSON.(json |-> "delegate_attestable_dal_slots" |> as_int) - in Check.( - (delegate_attestable_dal_slots = expected_attestable_slots) + (participation.delegate_attestable_dal_slots = expected_attestable_slots) ~__LOC__ int ~error_msg:"Expected that there are %L attestable slots, got %R") ; - let sufficient_dal_participation = - JSON.(json |-> "sufficient_dal_participation" |> as_bool) - in Check.( - (sufficient_dal_participation = sufficient_participation) + (participation.sufficient_dal_participation = sufficient_participation) ~__LOC__ bool ~error_msg:"Expected sufficient_dal_participation to be %R, got %L") ; - let expected_dal_rewards = JSON.(json |-> "expected_dal_rewards" |> as_int) in let dal_rewards = expected_assigned_shards * attesting_reward_per_shard in Check.( - (expected_dal_rewards = dal_rewards) + (Tez.to_mutez participation.expected_dal_rewards = dal_rewards) ~__LOC__ int ~error_msg: @@ -8575,7 +8556,7 @@ let check_participation_and_rewards participation ~expected_assigned_shards (get_json_list dal_rewards) in Check.( - (expected_dal_rewards = rewards) + (Tez.to_mutez participation.expected_dal_rewards = rewards) ~__LOC__ int ~error_msg: @@ -9473,11 +9454,8 @@ let test_e2e_trap_faulty_dal_node _protocol dal_parameters _cryptobox node ~block:"head~1" faulty_delegate in - let is_denounced = - JSON.(faulty_delegate_dal_participation |-> "denounced" |> as_bool) - in Check.is_false - is_denounced + faulty_delegate_dal_participation.denounced ~__LOC__ ~error_msg:"Expected the faulty delegate to not be denounced" ; let wait_for_trap_injection = @@ -9537,27 +9515,16 @@ let test_e2e_trap_faulty_dal_node _protocol dal_parameters _cryptobox node ~block:"head~1" faulty_delegate in - let is_denounced = - JSON.(faulty_delegate_dal_participation |-> "denounced" |> as_bool) - in Check.is_true - is_denounced + faulty_delegate_dal_participation.denounced ~__LOC__ ~error_msg:"Expected the faulty delegate to be denounced" ; - let sufficient_dal_participation = - JSON.( - faulty_delegate_dal_participation |-> "sufficient_dal_participation" - |> as_bool) - in Check.is_true - sufficient_dal_participation + faulty_delegate_dal_participation.sufficient_dal_participation ~__LOC__ ~error_msg:"Expected sufficiant participation for the faulty delegate" ; - let expected_dal_rewards = - JSON.( - faulty_delegate_dal_participation |-> "expected_dal_rewards" |> as_int) - in - Check.(expected_dal_rewards = 0) + Check.( + Tez.to_mutez faulty_delegate_dal_participation.expected_dal_rewards = 0) ~__LOC__ Check.int ~error_msg: @@ -9565,48 +9532,6 @@ let test_e2e_trap_faulty_dal_node _protocol dal_parameters _cryptobox node got %L" ; unit -type dal_participation = { - expected_assigned_shards_per_slot : int; - delegate_attested_dal_slots : int; - delegate_attestable_dal_slots : int; - expected_dal_rewards : Tez.t; - sufficient_dal_participation : bool; - denounced : bool; -} - -let get_dal_participation l1_node public_key_hash = - let open JSON in - let* json = - Node.RPC.( - call l1_node - @@ get_chain_block_context_delegate_dal_participation public_key_hash) - in - let expected_assigned_shards_per_slot = - json |-> "expected_assigned_shards_per_slot" |> as_int - in - let delegate_attested_dal_slots = - json |-> "delegate_attested_dal_slots" |> as_int - in - let delegate_attestable_dal_slots = - json |-> "delegate_attestable_dal_slots" |> as_int - in - let expected_dal_rewards = - json |-> "expected_dal_rewards" |> as_int64 |> Tez.of_mutez_int64 - in - let sufficient_dal_participation = - json |-> "sufficient_dal_participation" |> as_bool - in - let denounced = json |-> "denounced" |> as_bool in - return - { - expected_assigned_shards_per_slot; - delegate_attested_dal_slots; - delegate_attestable_dal_slots; - expected_dal_rewards; - sufficient_dal_participation; - denounced; - } - let get_tb_expected_attesting_rewards l1_node public_key_hash = let* participation = Node.RPC.( @@ -9895,7 +9820,9 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client Lwt_list.map_s (fun (account, _account_role) -> let* dal_participation = - get_dal_participation node account.Account.public_key_hash + Node.RPC.call node + @@ RPC.get_chain_block_context_delegate_dal_participation + account.Account.public_key_hash in return (account, dal_participation)) accounts_list @@ -9963,7 +9890,7 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client (fun (_account, dal_participation) -> Check.( dal_part.expected_assigned_shards_per_slot - = dal_participation.expected_assigned_shards_per_slot) + = dal_participation.RPC.expected_assigned_shards_per_slot) ~__LOC__ Check.int ~error_msg:"expected_assigned_shards_per_slot mismatch" ; @@ -10066,7 +9993,7 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client List.iter (fun (account, dal_participation) -> Check.is_false - dal_participation.denounced + dal_participation.RPC.denounced ~__LOC__ ~error_msg: ("account " ^ account.Account.public_key_hash -- GitLab From 08e0968e57fb629c88caddb60cc7fe159fa229da Mon Sep 17 00:00:00 2001 From: Mohamed Iguernlala Date: Tue, 18 Feb 2025 06:13:27 +0100 Subject: [PATCH 7/8] DAL/Tests: add helper functions to create a new account --- tezt/tests/dal.ml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 49d28db1000e..a0c09d2b94a3 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -9540,6 +9540,32 @@ let get_tb_expected_attesting_rewards l1_node public_key_hash = in return participation.expected_attesting_rewards +let create_account ?(source = Constant.bootstrap2) ~amount ~alias client = + Log.info + "Create a [%s] account: generate a key, inject a transaction that funds \ + it, and bake a block to apply the transaction." + alias ; + let* fresh_account = Client.gen_and_show_keys ~alias client in + let* _oph = + Operation.Manager.inject_single_transfer + client + ~source + ~dest:fresh_account + ~amount + in + let* () = bake_for client in + return fresh_account + +let create_account_and_reveal ?source ~amount ~alias client = + let* fresh_account = create_account ?source ~amount ~alias client in + Log.info "Reveal pkh of [%s] account." alias ; + let op_reveal = + Operation.Manager.(make ~source:fresh_account (reveal fresh_account)) + in + let* _oph = Operation.Manager.inject [op_reveal] client in + let* () = bake_for client in + return fresh_account + (** [test_dal_rewards_distribution _protocol dal_parameters cryptobox node client _dal_node] verifies the correct distribution of DAL rewards among delegates based on their participation in DAL attestations activity. -- GitLab From d3b80d5070eaa7b0a621fdfd5bb38169c01e835a Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 18 Feb 2025 07:25:08 +0100 Subject: [PATCH 8/8] DAL/Tests: extend participation test with a small baker --- tezt/tests/dal.ml | 359 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 264 insertions(+), 95 deletions(-) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index a0c09d2b94a3..16d246a1779d 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -9570,9 +9570,12 @@ let create_account_and_reveal ?source ~amount ~alias client = client _dal_node] verifies the correct distribution of DAL rewards among delegates based on their participation in DAL attestations activity. + The test uses the 5 bootstrap accounts and a new account with a small stake + that has on average one assigned shard per level. + The main steps of the test are: - 1. Initialize delegates: we assign five bootstrap accounts to specific roles: + 1. Initialize delegates: we assign six accounts to specific roles: - **Baker:** Always attests both TenderBake (TB) and all DAL slots. - **Attesting DAL Slot 10:** Always attests TB and specifically DAL slot 10. - **Not Attesting at All:** Does not attest either TB or DAL slots. @@ -9580,6 +9583,7 @@ let create_account_and_reveal ?source ~amount ~alias client = any DAL attestation or by sending an empty bitset. - **Not Sufficiently Attesting DAL Slot 10:** Attests DAL slot 10 only 25% of the time. + - **Small Baker:** It has very few assigned shards, but does the same as the Baker. 2. Initial balances snapshot: we capture the initial balances of all delegates to compare against post-test balances. @@ -9590,7 +9594,7 @@ let create_account_and_reveal ?source ~amount ~alias client = - we inject attestations from each delegate according to their assigned behavior. - 4. Blocks production until ~end of cycle: we bake blocks up to the last + 4. Blocks production until end of cycle: we bake blocks up to the last block of the current cycle, ensuring DAL slot publications and attestations are appropriately injected. Each time a new block is produced, we check the value of the "dal_attestation" bitset in the block's metadata and count the @@ -9626,21 +9630,117 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client in let blocks_per_cycle = JSON.(proto_params |-> "blocks_per_cycle" |> as_int) in assert (blocks_per_cycle >= dal_parameters.Dal.Parameters.attestation_lag) ; - let* () = bake_for client in + let consensus_rights_delay = + JSON.(proto_params |-> "consensus_rights_delay" |> as_int) + in + let minimal_stake = JSON.(proto_params |-> "minimal_stake" |> as_int) in + let nb_slots = dal_parameters.Dal.Parameters.number_of_slots in + let all_slots = List.init nb_slots Fun.id in + let number_of_shards = + dal_parameters.Dal.Parameters.cryptobox.number_of_shards + in + + (* Compute the stake of the small baker. *) + let* small_baker_stake = + let* bootstrap_info = + Node.RPC.call node + @@ RPC.get_chain_block_context_delegate + Constant.bootstrap1.public_key_hash + in + let bootstrap_baking_power = + JSON.(bootstrap_info |-> "baking_power" |> as_string) |> int_of_string + in + let total_baking_power = + bootstrap_baking_power * Array.length Account.Bootstrap.keys + in + (* The amount is such that this baker has only one assigned shard per cycles + (on average). Note that if the baker has no assigned shard, the test + should still pass, because we just check that it gets its DAL rewards. + + Let [t] be total_baking_power, [s] be [small_baker_stake], and [1/n] + desired shards fraction for the small baker. We want [s / (t + s) = 1 / + n], ie [t + s = n * s], ie [t = (n-1) * s] ie, [s = t / (n-1)] *) + let desired_stake = + total_baking_power / ((blocks_per_cycle * number_of_shards) - 1) + in + let small_baker_stake = max desired_stake minimal_stake in + Log.info + "total_baking_power = %d, small_baker_stake = %d" + total_baking_power + small_baker_stake ; + return small_baker_stake + in + + (* Each of the 5 bootstrap accounts contributes equally to the new baker's + account. We give it a bit more tez, for it to be able to pay the fees for + the pk reveal and stake operations. *) + let to_transfer = (small_baker_stake + 3_000) / 5 in + let* level = Node.get_level node in assert (level < blocks_per_cycle) ; let level = ref level in - let nb_slots = dal_parameters.Dal.Parameters.number_of_slots in - let all_slots = List.init nb_slots Fun.id in + let* small_baker = + create_account_and_reveal ~amount:to_transfer ~alias:"small_baker" client + in + incr level ; + + let* () = + Lwt_list.iter_s + (fun bootstrap -> + if bootstrap <> Constant.bootstrap2 then + let* _oph = + Operation.Manager.inject_single_transfer + client + ~source:bootstrap + ~dest:small_baker + ~amount:to_transfer + in + unit + else unit) + (Array.to_list Account.Bootstrap.keys) + in + let* () = bake_for client in + incr level ; - (* We get our available delegates (up to 5) and assign them different roles - they'll play during the test. *) + Log.info "Register small_baker as a delegate" ; + let* _small_baker = + Client.register_delegate ~delegate:small_baker.alias client + in + let* () = bake_for client in + incr level ; + + Log.info "Stake for small_baker" ; + let* () = + Client.stake + (Tez.of_mutez_int small_baker_stake) + ~staker:small_baker.public_key_hash + client + in + + Log.info + "Bake (almost) %d cycles to activate the delegate" + consensus_rights_delay ; + let* () = + bake_for + ~count:((blocks_per_cycle * (1 + consensus_rights_delay)) - !level - 1) + client + in + let* current_level = + Node.RPC.call node @@ RPC.get_chain_block_helper_current_level () + in + assert (current_level.cycle_position = blocks_per_cycle - 1) ; + level := blocks_per_cycle * (1 + consensus_rights_delay) ; + assert (!level = current_level.level) ; + + (* We get our available delegates and assign them different roles they'll play + during the test. *) let ( accounts_list, ( baker, attesting_dal_slot_10, not_attesting_at_all, not_attesting_dal, - not_sufficiently_attesting_dal_slot_10 ) ) = + not_sufficiently_attesting_dal_slot_10, + small_baker ) ) = match Account.Bootstrap.keys with | [|d1; d2; d3; d4; d5|] -> ( [ @@ -9649,8 +9749,9 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client (d3, "not_attesting_at_all"); (d4, "not_attesting_dal"); (d5, "not_sufficiently_attesting_dal_slot_10"); + (small_baker, "small_baker"); ], - (d1, d2, d3, d4, d5) ) + (d1, d2, d3, d4, d5, small_baker) ) | _ -> Test.fail "Expected exactly 5 bootstrap accounts." in @@ -9670,10 +9771,11 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client bal not_attesting_at_all; bal not_attesting_dal; bal not_sufficiently_attesting_dal_slot_10; + bal small_baker; ] in match l with - | [b1; b2; b3; b4; b5] -> return (b1, b2, b3, b4, b5) + | [b1; b2; b3; b4; b5; b6] -> return (b1, b2, b3, b4, b5, b6) | _ -> Test.fail "Not reachable." in @@ -9682,21 +9784,21 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client attesting_dal_slot_10_bal0, not_attesting_at_all_bal0, not_attesting_dal_bal0, - not_sufficiently_attesting_dal_slot_10_bal0 ) = + not_sufficiently_attesting_dal_slot_10_bal0, + small_baker_bal0 ) = snapshot_full_balances_helper () in (* This is the main helper function which injects (DAL) attestations for delegates depending on their profiles. *) let inject_attestations () = - let* level = Node.get_level node in let count_dal_attesting_bakers = ref 0 in (* 1. Baker always attests TB and all DAL slots *) let* (_ : Operation_core.t * [`OpHash of peer_id]) = (* The baker delegate will miss 1/10 of its DAL attestations and will send [No_dal_attestation] in this case. *) let baker_attestation = - if level mod 10 = 0 then No_dal_attestation + if !level mod 10 = 0 then No_dal_attestation else ( incr count_dal_attesting_bakers ; Slots all_slots) @@ -9713,7 +9815,7 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client attestations and will send Slots [], but it should be fine for its rewards. *) let attestation = - if level mod 11 = 0 then Slots [] + if !level mod 11 = 0 then Slots [] else ( incr count_dal_attesting_bakers ; Slots [10]) @@ -9728,7 +9830,7 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client (* 4. not_attesting_dal either sends no DAL content or sends bitset 0 *) let* (_ : Operation_core.t * [`OpHash of peer_id]) = let dal_attestation = - if level mod 2 = 0 then No_dal_attestation else Slots [] + if !level mod 2 = 0 then No_dal_attestation else Slots [] in inject_dal_attestation_exn ~signer:not_attesting_dal @@ -9740,7 +9842,7 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client of the time. *) let* (_ : Operation_core.t * [`OpHash of peer_id]) = let slots_to_attest = - if level mod 4 = 0 then ( + if !level mod 4 = 0 then ( incr count_dal_attesting_bakers ; Slots [10]) else No_dal_attestation @@ -9751,9 +9853,28 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client slots_to_attest client in + (* 6. small_baker: is always attesting DAL slot 10. *) + let* () = + let slots_to_attest = Slots [10] in + let* res = + inject_dal_attestation + ~signer:small_baker + ~nb_slots + slots_to_attest + client + in + (match res with + | None -> + Log.info + "At level %d, %s could not TB attest" + !level + small_baker.alias + | Some _ -> incr count_dal_attesting_bakers) ; + unit + in Log.info "At level %d, there are %d bakers that DAL attested" - level + !level !count_dal_attesting_bakers ; unit in @@ -9784,9 +9905,7 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client attestations. We stop before baking the last block of the current cycle, where DAL rewards are distributed. *) let* () = - repeat - (blocks_per_cycle - !level - 1) - (fun () -> + repeat (blocks_per_cycle - 1) (fun () -> let* () = count_slot_10_if_attested () in let* (`OpHash _oph1) = publish_dummy_slot @@ -9822,11 +9941,13 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client ~validation_pass:0 () in - Check.( - (List.length @@ JSON.as_list attestations = 4) - int - ~__LOC__ - ~error_msg:"expected 4 attestations in block, got %L") ; + let num_attestations = List.length @@ JSON.as_list attestations in + (* The small baker may not have rights to inject its attestation *) + let check_num = num_attestations = 4 || num_attestations = 5 in + Check.is_true + check_num + ~__LOC__ + ~error_msg:"expected 4 or 5 attestations in block" ; unit) in @@ -9836,7 +9957,8 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client attesting_dal_slot_10_bal1, not_attesting_at_all_bal1, not_attesting_dal_bal1, - not_sufficiently_attesting_dal_slot_10_bal1 ) = + not_sufficiently_attesting_dal_slot_10_bal1, + small_baker_bal1 ) = snapshot_full_balances_helper () in @@ -9854,17 +9976,55 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client accounts_list in + (* We use the 'participation' RPC to get the expected Tenderbake rewards of delegate + who TB-attested sufficiently. *) + let snapshot_tb_participation () = + let participation account = + Node.RPC.call node + @@ RPC.get_chain_block_context_delegate_participation + account.Account.public_key_hash + in + let* l = + Lwt.all + [ + participation baker; + participation attesting_dal_slot_10; + participation not_attesting_at_all; + participation not_attesting_dal; + participation not_sufficiently_attesting_dal_slot_10; + participation small_baker; + ] + in + match l with + | [p1; p2; p3; p4; p5; p6] -> return (p1, p2, p3, p4, p5, p6) + | _ -> Test.fail "Not reachable." + in + let* ( _baker_tb_participation, + attesting_dal_slot_10_tb_participation, + _not_attesting_at_all_tb_participation, + not_attesting_dal_tb_participation, + not_sufficiently_attesting_dal_slot_10_tb_participation, + small_baker_tb_participation ) = + snapshot_tb_participation () + in + (* We now bake the last block of the cycle, which should trigger TB and DAL rewards distribution. TB rewards are actually set to 0. *) let* () = bake_for ~delegates:(`For [baker.Account.public_key_hash]) client in + let* _json = Node.RPC.(call node @@ get_chain_block_metadata_raw ()) in incr level ; + let* current_level = + Node.RPC.call node @@ RPC.get_chain_block_helper_current_level () + in + assert (current_level.cycle_position = blocks_per_cycle - 1) ; (* We snapshot the balances of the delegates at the end of the cycle. *) let* ( _baker_bal2, attesting_dal_slot_10_bal2, not_attesting_at_all_bal2, not_attesting_dal_bal2, - not_sufficiently_attesting_dal_slot_10_bal2 ) = + not_sufficiently_attesting_dal_slot_10_bal2, + small_baker_bal2 ) = snapshot_full_balances_helper () in @@ -9903,17 +10063,20 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client ( not_sufficiently_attesting_dal_slot_10, not_sufficiently_attesting_dal_slot_10_bal0, not_sufficiently_attesting_dal_slot_10_bal1 ); + (small_baker, small_baker_bal0, small_baker_bal1); ] ; - (* As the delegates have the same stake distribution, they're expected to have - the same number of the assigned shards, to have shards at the same level, - to have the same rewards allocated, ... *) - let expected_full_dal_rewards = - match bootstrap_accounts_participation with - | [] -> Test.fail "Not reachable." - | (_account, dal_part) :: rest -> + (* As all delegates except [small_baker] have the same stake distribution, + they're expected to have the same number of the assigned shards, to have + shards at the same level, to have the same rewards allocated, ... *) + let () = + match List.rev bootstrap_accounts_participation with + | (_small_baker, _) :: (_account, dal_part) :: rest -> List.iter (fun (_account, dal_participation) -> + (* We transferred funds from [bootstrap2] to [small_baker], so + [bootstrap_2] has a smaller baking power than the other bootstrap + delegates. *) Check.( dal_part.expected_assigned_shards_per_slot = dal_participation.RPC.expected_assigned_shards_per_slot) @@ -9921,31 +10084,23 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client Check.int ~error_msg:"expected_assigned_shards_per_slot mismatch" ; Check.( - dal_part.delegate_attestable_dal_slots - = dal_participation.delegate_attestable_dal_slots) + Tez.to_mutez dal_part.expected_dal_rewards + = Tez.to_mutez dal_participation.expected_dal_rewards) ~__LOC__ Check.int - ~error_msg:"delegate_attestable_dal_slots mismatch" ; + ~error_msg:"expected_dal_rewards mismatch" ; Check.( - Tez.to_mutez dal_part.expected_dal_rewards - = Tez.to_mutez dal_participation.expected_dal_rewards) + dal_part.delegate_attestable_dal_slots + = dal_participation.delegate_attestable_dal_slots) ~__LOC__ Check.int - ~error_msg:"expected_dal_rewards mismatch") - rest ; - Tez.to_mutez dal_part.expected_dal_rewards - in - - (* We use /participation RPC to get the expect Tenderbake rewards of delegate - who TB-attested sufficiently. *) - let* expected_full_tb_rewards = - get_tb_expected_attesting_rewards node baker.public_key_hash + ~error_msg:"delegate_attestable_dal_slots mismatch") + rest + | _ -> Test.fail "Not reachable." in (* After baking the last block of the cycle, we check that: - - the balances of the delegates who didn't attest at all didn't change. - - the participation RPC's result is aligned with the first check. *) List.iter (fun (account, bal1, bal2) -> @@ -9966,54 +10121,64 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client ] ; (* After baking the last block of the cycle, we check that: - - the balances of the delegates who didn't attest DAL sufficiently or - didn't attest DAL at all only increased by a delta equal to the expected - Tenderbake attestation rewards. - + didn't attest DAL at all only increased by a delta equal to the expected + Tenderbake attestation rewards. - the participation RPC's result is aligned with the first check. *) List.iter - (fun (account, bal1, bal2) -> - check_bal_incr - ~__LOC__ - account - bal1 - bal2 - ~delta:(Tez.to_mutez expected_full_tb_rewards) ; + (fun (account, bal1, bal2, tb_participation, sufficient_dal_participation) -> let dal_participation = List.assoc account bootstrap_accounts_participation in - Check.is_false - dal_participation.sufficient_dal_participation - ~__LOC__ - ~error_msg: - ("account " ^ account.Account.public_key_hash - ^ ", expected to have sufficient DAL participation?")) + Check.( + (dal_participation.sufficient_dal_participation + = sufficient_dal_participation) + ~__LOC__ + bool + ~error_msg: + ("account " ^ account.Account.public_key_hash + ^ ", expected to have sufficient DAL participation? %R, but got %L")) ; + let expected_dal_rewards = + if sufficient_dal_participation then + Tez.to_mutez dal_participation.expected_dal_rewards + else 0 + in + let delta = + Tez.to_mutez tb_participation.RPC.expected_attesting_rewards + + expected_dal_rewards + in + Log.info + "[check] %s %s: %Ld = %Ld + %d + %d" + account.Account.alias + account.public_key_hash + bal1 + bal2 + (Tez.to_mutez tb_participation.expected_attesting_rewards) + expected_dal_rewards ; + check_bal_incr ~__LOC__ account bal1 bal2 ~delta) [ - (not_attesting_dal, not_attesting_dal_bal1, not_attesting_dal_bal2); + ( not_attesting_dal, + not_attesting_dal_bal1, + not_attesting_dal_bal2, + not_attesting_dal_tb_participation, + false ); ( not_sufficiently_attesting_dal_slot_10, not_sufficiently_attesting_dal_slot_10_bal1, - not_sufficiently_attesting_dal_slot_10_bal2 ); + not_sufficiently_attesting_dal_slot_10_bal2, + not_sufficiently_attesting_dal_slot_10_tb_participation, + false ); + ( attesting_dal_slot_10, + attesting_dal_slot_10_bal1, + attesting_dal_slot_10_bal2, + attesting_dal_slot_10_tb_participation, + true ); + ( small_baker, + small_baker_bal1, + small_baker_bal2, + small_baker_tb_participation, + true ); ] ; - (* Below, we check that the only delegate who attested slot 10 correctly got - its (Tenderbake and) DAL rewards. *) - check_bal_incr - ~__LOC__ - attesting_dal_slot_10 - attesting_dal_slot_10_bal1 - attesting_dal_slot_10_bal2 - ~delta:(Tez.to_mutez expected_full_tb_rewards + expected_full_dal_rewards) ; - let dal_participation = - List.assoc attesting_dal_slot_10 bootstrap_accounts_participation - in - Check.is_true - dal_participation.sufficient_dal_participation - ~__LOC__ - ~error_msg: - ("account " ^ attesting_dal_slot_10.Account.public_key_hash - ^ ", expected balance to have sufficient DAL participation.") ; - (* As a final check, we verify that no delegate is denounced and that we report the correct number of attested slots. *) List.iter @@ -10025,14 +10190,18 @@ let test_dal_rewards_distribution _protocol dal_parameters cryptobox node client ("account " ^ account.Account.public_key_hash ^ ", not expected to be denounced.") ; - Check.( - dal_participation.delegate_attestable_dal_slots - = !count_set_dal_attestation_bitset) - ~__LOC__ - Check.int - ~error_msg: - "Expecting %L attestable DAL slots, but %R were reported in blocks \ - metadata") + (* The number of attestable slots for the small stake baker is smaller + than for the other bakers and since we did not count them, we don't + check them. *) + if not @@ String.equal account.alias small_baker.alias then + Check.( + dal_participation.delegate_attestable_dal_slots + = !count_set_dal_attestation_bitset) + ~__LOC__ + Check.int + ~error_msg: + "Expecting %L attestable DAL slots, but %R were reported in blocks \ + metadata") bootstrap_accounts_participation ; unit -- GitLab