From 86f68303dfee562432167fc92d3956bb398f834d Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Thu, 9 Oct 2025 16:49:53 +0200 Subject: [PATCH 1/7] Tezt: add thousand separators --- tezt/lib_tezos/operation_receipt.ml | 2 +- tezt/tests/adaptive_issuance.ml | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tezt/lib_tezos/operation_receipt.ml b/tezt/lib_tezos/operation_receipt.ml index 234f9ed441fa..fcc216c981be 100644 --- a/tezt/lib_tezos/operation_receipt.ml +++ b/tezt/lib_tezos/operation_receipt.ml @@ -141,7 +141,7 @@ module Balance_updates = struct Format.sprintf "{kind: %s\n\ contract: %s\n\ - change: %d\n\ + change: %#d\n\ staker: %s\n\ category: %s\n\ delayed_operation_hash: %s\n\ diff --git a/tezt/tests/adaptive_issuance.ml b/tezt/tests/adaptive_issuance.ml index ec6379af342b..41a12b826184 100644 --- a/tezt/tests/adaptive_issuance.ml +++ b/tezt/tests/adaptive_issuance.ml @@ -238,8 +238,8 @@ let check_with_roundings ?(margin = 1) got expected = let assert_with_roundings ~__LOC__ ?margin got expected = if not (check_with_roundings ?margin got expected) then Test.fail - "@[%s: Asserted equality (up to rounding) failed. got %d, expected \ - %d.@]@." + "@[%s: Asserted equality (up to rounding) failed. got %#d, expected \ + %#d.@]@." __LOC__ got expected @@ -260,7 +260,7 @@ let check_balance_updates balance_updates (predicates : bu_check list) = then Test.fail "@[Inconsistent balance update, could it be a regression.@. \ - Expected:@ @[%s, change amount: %d@]@.Got:@ @[%s@]@]" + Expected:@ @[%s, change amount: %#d@]@.Got:@ @[%s@]@]" msg change (List.fold_left @@ -586,7 +586,7 @@ let test_staking = @@ RPC.get_chain_block_context_contract_staking_numerator Constant.bootstrap2.public_key_hash in - Log.info "Numerator/denominator before: %d/%d " numerator denominator ; + Log.info "Numerator/denominator before: %#d/%#d " numerator denominator ; let bake = Helpers.bake ~ai_vote:Pass ~endpoint ~protocol in let* () = Helpers.bake_n_cycles bake 1 client_1 in @@ -614,7 +614,7 @@ let test_staking = staker0.public_key_hash in Log.info - "Numerator/denominator after for %s: %d/%d " + "Numerator/denominator after for %s: %#d/%#d " staker0.alias numerator0 (JSON.as_int denominator) ; @@ -628,7 +628,7 @@ let test_staking = assert (numerator0 + numerator1 = JSON.as_int denominator) ; Log.info - "Numerator/denominator after for %s: %d/%d " + "Numerator/denominator after for %s: %#d/%#d " staker1.alias numerator1 (JSON.as_int denominator) ; @@ -658,7 +658,7 @@ let test_staking = contract.public_key_hash in Log.info - "Balance of %s: spendable : %s, staked_balance : %d" + "Balance of %s: spendable : %s, staked_balance : %#d" contract.alias (Tez.to_string balance) staked_balance ; @@ -1132,14 +1132,14 @@ let test_staking = assert (List.length finalizable == 1) ; assert (List.length unfinalizable == 1) ; - Log.info "Unstaked frozen balance: %d" unstaked_frozen_balance ; + Log.info "Unstaked frozen balance: %#d" unstaked_frozen_balance ; let* unstaked_finalizable_balance = Client.RPC.call client_1 @@ RPC.get_chain_block_context_contract_unstaked_finalizable_balance staker0.public_key_hash in - Log.info "Unstaked finalizable balance: %d" unstaked_finalizable_balance ; - assert (check_with_roundings unstaked_finalizable_balance 1000000000) ; + Log.info "Unstaked finalizable balance: %#d" unstaked_finalizable_balance ; + assert (check_with_roundings unstaked_finalizable_balance 1_000_000_000) ; let finalize_unstake = Client.spawn_finalize_unstake ~staker:staker0.public_key_hash client_1 @@ -1220,7 +1220,7 @@ let test_staking = @@ RPC.get_chain_block_context_contract_unstaked_finalizable_balance staker0.public_key_hash in - Log.info "Unstaked finalizable balance: %d" unstaked_finalizable_balance ; + Log.info "Unstaked finalizable balance: %#d" unstaked_finalizable_balance ; assert (unstaked_finalizable_balance = 0) ; let* () = repeat 2 (fun () -> -- GitLab From 62864f40d7884494f7dccd5d35e71bbd36b94a79 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Fri, 10 Oct 2025 16:24:27 +0200 Subject: [PATCH 2/7] Tezt/AI: add consensus_rights_delay variable back --- tezt/tests/adaptive_issuance.ml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tezt/tests/adaptive_issuance.ml b/tezt/tests/adaptive_issuance.ml index 41a12b826184..997d94af319b 100644 --- a/tezt/tests/adaptive_issuance.ml +++ b/tezt/tests/adaptive_issuance.ml @@ -312,6 +312,12 @@ let test_staking = in let* _proto_hash, endpoint, client_1, node_1 = init ~overrides protocol in + let* constants = + Client.RPC.call client_1 @@ RPC.get_chain_block_context_constants () + in + let consensus_rights_delay = + JSON.(constants |-> "consensus_rights_delay" |> as_int) + in log_step 1 "Prepare second node for double baking" ; Log.info "Starting second node" ; @@ -791,7 +797,7 @@ let test_staking = Client.spawn_unstake (Tez.of_int 500000) ~staker:staker0.alias client_1 in - let* _ = Helpers.bake_n_cycles bake 2 client_1 in + let* _ = Helpers.bake_n_cycles bake consensus_rights_delay client_1 in let* () = Process.check ~expect_failure:false unstake0 in -- GitLab From 09025e4c997b2675cb7e1e570af7e38f9f073cc8 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Fri, 10 Oct 2025 16:44:52 +0200 Subject: [PATCH 3/7] Tezt: add Node.current_cycle --- tezt/lib_tezos/node.ml | 4 ++++ tezt/lib_tezos/node.mli | 4 ++++ tezt/tests/adaptive_issuance.ml | 9 ++------- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/tezt/lib_tezos/node.ml b/tezt/lib_tezos/node.ml index fab76486aedd..f48e9200d7cc 100644 --- a/tezt/lib_tezos/node.ml +++ b/tezt/lib_tezos/node.ml @@ -1276,3 +1276,7 @@ module RPC = struct include RPC_callers include RPC end + +let current_cycle node = + let* level = RPC.call node @@ RPC.get_chain_block_helper_current_level () in + return level.cycle diff --git a/tezt/lib_tezos/node.mli b/tezt/lib_tezos/node.mli index 35a3731dcdcb..fb0e69e5f742 100644 --- a/tezt/lib_tezos/node.mli +++ b/tezt/lib_tezos/node.mli @@ -747,6 +747,10 @@ val get_version : t -> string Lwt.t See [rpc_endpoint] for a description of the [local] argument. *) val as_rpc_endpoint : ?local:bool -> t -> Endpoint.t +(** Returns the cycle of the current head, as observed via the RPC + {!RPC.get_chain_block_helper_current_level}. *) +val current_cycle : t -> int Lwt.t + module RPC : sig include RPC_core.CALLERS with type uri_provider := t diff --git a/tezt/tests/adaptive_issuance.ml b/tezt/tests/adaptive_issuance.ml index 997d94af319b..8dc4843e9c08 100644 --- a/tezt/tests/adaptive_issuance.ml +++ b/tezt/tests/adaptive_issuance.ml @@ -1354,14 +1354,9 @@ let test_delegate_parameter_UX = "Staking - test set_delegate_parameters and update_delegate_parameters UX" ~tags:["staking"; "node"; "client"] @@ fun protocol -> - let* _proto_hash, endpoint, client, _node_1 = init protocol in + let* _proto_hash, endpoint, client, node = init protocol in let bake = Helpers.bake ~ai_vote:Pass ~endpoint ~protocol in - let current_cycle () = - let* level = - Client.RPC.call client @@ RPC.get_chain_block_helper_current_level () - in - return level.cycle - in + let current_cycle () = Node.current_cycle node in let* delegate_parameters_activation_delay = let* json = -- GitLab From 97174d87133f67fd11f4ad8e7cdc18bb3375f271 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Fri, 10 Oct 2025 16:35:49 +0200 Subject: [PATCH 4/7] Tezt/AI: rename and move some variables, and update some comments Do not change the computations yet. This will make the next commits easier to review. --- tezt/tests/adaptive_issuance.ml | 100 ++++++++++++++++---------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/tezt/tests/adaptive_issuance.ml b/tezt/tests/adaptive_issuance.ml index 8dc4843e9c08..bffcc810862e 100644 --- a/tezt/tests/adaptive_issuance.ml +++ b/tezt/tests/adaptive_issuance.ml @@ -920,7 +920,9 @@ let test_staking = and* _ = Node.wait_for_level node_2 node_3_final_level and* _ = Node.wait_for_level node_3 node_3_final_level in - log_step 20 "Check denunciation is in the last block." ; + log_step + 20 + "Check denunciation is in the last block, and culprit is now forbidden." ; (* Getting the operations of the current head. *) let* ops = Client.RPC.call client_1 @@ RPC.get_chain_block_operations () in let* () = Accuser.terminate accuser_3 in @@ -929,7 +931,7 @@ let test_staking = else Test.fail "Double baking evidence was not found" in - (* Bootstrap2 has been denounced, check it is not forbidden *) + (* Bootstrap2 has been denounced, check it is forbidden. *) let* is_forbidden = Client.RPC.call client_1 @@ RPC.get_chain_block_context_delegate_is_forbidden @@ -937,6 +939,12 @@ let test_staking = in assert is_forbidden ; + log_step + 21 + "Bake until the slashing is applied at the end of the next cycle, and \ + check that the block receipt contains the expected slashed and rewarded \ + amounts." ; + (* Bake a cycle to wait for the slashing *) let* () = Helpers.bake_n_cycles @@ -949,18 +957,8 @@ let test_staking = let* bu = Operation_receipt.get_block_metadata client_1 in let* bu = Operation_receipt.Balance_updates.from_result [bu] in - (* check slashed and rewarded amounts *) - let global_limit_of_staking_over_baking = 9 in - (* It's critical that the rewarded amount cannot exceed the amount - slashed from the baker's own deposits; otherwise, the baker may - actually gain tez by purposefully double signing and denuncing - itself. Therefore, the rewarded part is set to 1 / - (global_limit_of_staking_over_baking + 2) of the slashed - amount. *) - let reward_denominator = global_limit_of_staking_over_baking + 2 in - (* slashed stakers (including baker) unstake deposit *) - let amount_slashed_from_unstake_stakers_deposits = + let amount_slashed_from_unstake_requests = if Protocol.(number protocol > number S023) then (* From T on, when activating the protocol from Genesis, the initialization of consensus rights for the first cycles is @@ -970,47 +968,50 @@ let test_staking = 50_000_004 else 50_000_003 in - let amount_rewarded_from_unstake_stakers_deposits = - amount_slashed_from_unstake_stakers_deposits / reward_denominator - in - let amount_burned_from_unstake_stakers_deposits = - amount_slashed_from_unstake_stakers_deposits - - amount_rewarded_from_unstake_stakers_deposits - in (* slashed stake *) - let amount_slashed_from_stakers_deposits = + let amount_slashed_from_own_staked = + if Protocol.(number protocol > number S023) then 10_049_785_808 + else 10_049_764_732 + in + let amount_slashed_from_external_staked = if Protocol.(number protocol > number S023) then 50_248_756 else 50_248_756 in - let amount_rewarded_from_stakers_deposits = - amount_slashed_from_stakers_deposits / reward_denominator + + (* Compute rewarded vs burned amounts. *) + let global_limit_of_staking_over_baking = 9 in + (* It's critical that the rewarded amount cannot exceed the amount + slashed from the baker's own deposits; otherwise, the baker may + actually gain tez by purposefully double signing and denuncing + itself. Therefore, the rewarded part is set to 1 / + (global_limit_of_staking_over_baking + 2) of the slashed + amount. *) + let reward_denominator = global_limit_of_staking_over_baking + 2 in + let amount_rewarded_from_unstake_requests = + amount_slashed_from_unstake_requests / reward_denominator in - let amount_burned_from_stakers_deposits = - amount_slashed_from_stakers_deposits - amount_rewarded_from_stakers_deposits + let amount_burned_from_unstake_requests = + amount_slashed_from_unstake_requests - amount_rewarded_from_unstake_requests in - - (* slashing baker (bootstrap2) stake*) - let amount_slashed_from_baker_deposits = - if Protocol.(number protocol > number S023) then 10_049_785_808 - else 10_049_764_732 + let amount_rewarded_from_own_staked = + amount_slashed_from_own_staked / reward_denominator in - - let amount_rewarded_from_baker_deposits = - amount_slashed_from_baker_deposits / reward_denominator + let amount_burned_from_own_staked = + amount_slashed_from_own_staked - amount_rewarded_from_own_staked in - let amount_burned_from_baker_deposits = - amount_slashed_from_baker_deposits - amount_rewarded_from_baker_deposits + let amount_rewarded_from_external_staked = + amount_slashed_from_external_staked / reward_denominator + in + let amount_burned_from_external_staked = + amount_slashed_from_external_staked - amount_rewarded_from_external_staked in - - (* total amounts *) let total_amount_rewarded = - amount_rewarded_from_unstake_stakers_deposits - + amount_rewarded_from_stakers_deposits - + amount_rewarded_from_baker_deposits + amount_rewarded_from_unstake_requests + amount_rewarded_from_external_staked + + amount_rewarded_from_own_staked in let total_amount_burned = - amount_burned_from_unstake_stakers_deposits - + amount_burned_from_stakers_deposits + amount_burned_from_baker_deposits + amount_burned_from_unstake_requests + amount_burned_from_external_staked + + amount_burned_from_own_staked in let check_opr ~kind ~category ~change ~staker ~msg ~delayed_operation_hash = @@ -1027,14 +1028,13 @@ let test_staking = msg; } in - check_balance_updates bu [ check_opr ~kind:"freezer" ~category:(Some "unstaked_deposits") - ~change:(-amount_burned_from_unstake_stakers_deposits) + ~change:(-amount_burned_from_unstake_requests) ~staker: (Some (Delegate @@ -1047,7 +1047,7 @@ let test_staking = check_opr ~kind:"freezer" ~category:(Some "deposits") - ~change:(-amount_burned_from_baker_deposits) + ~change:(-amount_burned_from_own_staked) ~staker: (Some (Baker_own_stake {baker = Constant.bootstrap2.public_key_hash})) ~msg:"Slashed from baker deposits" @@ -1055,7 +1055,7 @@ let test_staking = check_opr ~kind:"freezer" ~category:(Some "deposits") - ~change:(-amount_burned_from_stakers_deposits) + ~change:(-amount_burned_from_external_staked) ~staker: (Some (Delegate @@ -1075,7 +1075,7 @@ let test_staking = check_opr ~kind:"freezer" ~category:(Some "unstaked_deposits") - ~change:(-amount_rewarded_from_unstake_stakers_deposits) + ~change:(-amount_rewarded_from_unstake_requests) ~staker: (Some (Delegate @@ -1088,7 +1088,7 @@ let test_staking = check_opr ~kind:"freezer" ~category:(Some "deposits") - ~change:(-amount_rewarded_from_baker_deposits) + ~change:(-amount_rewarded_from_own_staked) ~staker: (Some (Baker_own_stake {baker = Constant.bootstrap2.public_key_hash})) ~delayed_operation_hash:(Some denunciation_oph) @@ -1096,7 +1096,7 @@ let test_staking = check_opr ~kind:"freezer" ~category:(Some "deposits") - ~change:(-amount_rewarded_from_stakers_deposits) + ~change:(-amount_rewarded_from_external_staked) ~staker: (Some (Delegate @@ -1118,7 +1118,7 @@ let test_staking = }; ] ; - log_step 21 "Test finalize_unstake" ; + log_step 22 "Test finalize_unstake" ; let* balance = Client.get_balance_for ~account:staker0.alias client_1 in Log.info "Balance of %s before unstake: spendable : %s" -- GitLab From d01d9129568b20afb19da2df173df8330cf0a889 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Fri, 10 Oct 2025 11:09:39 +0200 Subject: [PATCH 5/7] Tezt/AI: compute expected amount slashed from unstake requests --- tezt/tests/adaptive_issuance.ml | 68 ++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/tezt/tests/adaptive_issuance.ml b/tezt/tests/adaptive_issuance.ml index bffcc810862e..331deca8c8e0 100644 --- a/tezt/tests/adaptive_issuance.ml +++ b/tezt/tests/adaptive_issuance.ml @@ -874,6 +874,7 @@ let test_staking = ~keys:[Constant.bootstrap2.public_key_hash] client_2 in + let* misbehaviour_cycle = Node.current_cycle node_2 in let* _ = Node.wait_for_level node_2 (common_ancestor + node_2_branch_size) in @@ -945,28 +946,65 @@ let test_staking = check that the block receipt contains the expected slashed and rewarded \ amounts." ; - (* Bake a cycle to wait for the slashing *) + (* Bake until the block right before the slashing (second-to-last + block of cycle [misbehaviour_cycle + 1]), so that we can retrieve + data that will be needed to compute expected slashed amounts. *) let* () = - Helpers.bake_n_cycles - bake + Client.bake_until_cycle_end + ~target_cycle:(misbehaviour_cycle + 1) ~keys:[Constant.bootstrap1.public_key_hash] - 1 client_1 in + let* bootstrap2_info_right_before_slashing = + Node.RPC.call node_2 + @@ RPC.get_chain_block_context_delegate Constant.bootstrap2.public_key_hash + in + (* Bake the block that applies the slashing (last block of cycle + [misbehaviour_cycle + 1]). We will now check the slashed and + rewarded amounts in this block's receipts. *) + let* () = bake ~keys:[Constant.bootstrap1.public_key_hash] client_1 in let* bu = Operation_receipt.get_block_metadata client_1 in let* bu = Operation_receipt.Balance_updates.from_result [bu] in - (* slashed stakers (including baker) unstake deposit *) + (* Compute the expected amount slashed from unstaked requests + (baker's and external stakers' are counted together) *) + let unstake_requests_earliest_slashable_cycle = + (* Rights for the misbehaviour cycle were determined at the end of + cycle [misbehaviour_cycle - consensus_rights_delay - 1], so any + funds unstaked in cycle [misbehaviour_cycle - + consensus_rights_delay] and up have contributed to those + rights. *) + misbehaviour_cycle - consensus_rights_delay + in + let total_amount_in_slashable_unstake_requests = + let open JSON in + let unstake_requests = + bootstrap2_info_right_before_slashing |-> "total_unstaked_per_cycle" + |> as_list + in + List.fold_left + (fun total_amount unstake_request -> + if + unstake_request |-> "cycle" |> as_int + >= unstake_requests_earliest_slashable_cycle + then total_amount + (unstake_request |-> "deposit" |> as_int) + else total_amount) + 0 + unstake_requests + in + let percentage_of_frozen_deposits_slashed_per_double_baking = + JSON.( + constants |-> "percentage_of_frozen_deposits_slashed_per_double_baking" + |> as_int) + in + let double_baking_penalty = + Q.(percentage_of_frozen_deposits_slashed_per_double_baking // 10_000) + in let amount_slashed_from_unstake_requests = - if Protocol.(number protocol > number S023) then - (* From T on, when activating the protocol from Genesis, the - initialization of consensus rights for the first cycles is - done with AI already in effect, so delegation already counts - less than staking. This slightly skews the balances in the - whole test. *) - 50_000_004 - else 50_000_003 + Q.( + of_int total_amount_in_slashable_unstake_requests * double_baking_penalty + |> to_int) in (* slashed stake *) @@ -979,7 +1017,9 @@ let test_staking = in (* Compute rewarded vs burned amounts. *) - let global_limit_of_staking_over_baking = 9 in + let global_limit_of_staking_over_baking = + JSON.(constants |-> "global_limit_of_staking_over_baking" |> as_int) + in (* It's critical that the rewarded amount cannot exceed the amount slashed from the baker's own deposits; otherwise, the baker may actually gain tez by purposefully double signing and denuncing -- GitLab From 6e9476b1ca4a8969e6edbc09e6c7819aee188702 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Thu, 9 Oct 2025 16:22:02 +0200 Subject: [PATCH 6/7] Tezt: keep breakdown of baking power when calling stake_distribution RPC --- tezt/lib_tezos/RPC.ml | 11 +++++++---- tezt/lib_tezos/RPC.mli | 13 ++++++++++++- tezt/tests/cloud/monitoring_app.ml | 6 ++++-- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/tezt/lib_tezos/RPC.ml b/tezt/lib_tezos/RPC.ml index 7ada6f51c6b1..db9e72eabbcc 100644 --- a/tezt/lib_tezos/RPC.ml +++ b/tezt/lib_tezos/RPC.ml @@ -2001,7 +2001,11 @@ let get_chain_block_context_denunciations ?(chain = "main") ?(block = "head") () = make GET ["chains"; chain; "blocks"; block; "context"; "denunciations"] Fun.id -type baker_with_power = {delegate : string; baking_power : int} +type baker_with_power = { + delegate : string; + staked : int; + weighted_delegated : int; +} let get_stake_distribution ?(chain = "main") ?(block = "head") ~cycle () = make @@ -2024,11 +2028,10 @@ let get_stake_distribution ?(chain = "main") ?(block = "head") ~cycle () = JSON.( fun baker_with_pow -> let active_stake = baker_with_pow |-> "active_stake" in - let frozen_stake = active_stake |-> "frozen" |> as_int in - let delegated_stake = active_stake |-> "delegated" |> as_int in { delegate = baker_with_pow |-> "baker" |> as_string; - baking_power = frozen_stake + delegated_stake; + staked = active_stake |-> "frozen" |> as_int; + weighted_delegated = active_stake |-> "delegated" |> as_int; }) bakers_with_pow diff --git a/tezt/lib_tezos/RPC.mli b/tezt/lib_tezos/RPC.mli index 30f870b5143d..cb05ea642603 100644 --- a/tezt/lib_tezos/RPC.mli +++ b/tezt/lib_tezos/RPC.mli @@ -1470,7 +1470,18 @@ val nonexistent_path : JSON.t t val get_chain_block_context_denunciations : ?chain:string -> ?block:string -> unit -> JSON.t t -type baker_with_power = {delegate : string; baking_power : int} +(** Delegate's pkh and staked/delegated portions of its baking power. + + [weighted_delegated] is the part that comes from delegated tez, + already divided by the [edge_of_staking_over_delegation] constant. + + The total baking power of the delegate is [staked + + weighted_delegated]. *) +type baker_with_power = { + delegate : string; + staked : int; + weighted_delegated : int; +} val get_stake_distribution : ?chain:string -> ?block:string -> cycle:int -> unit -> baker_with_power list t diff --git a/tezt/tests/cloud/monitoring_app.ml b/tezt/tests/cloud/monitoring_app.ml index d72c451f9b29..ea42001a8d27 100644 --- a/tezt/tests/cloud/monitoring_app.ml +++ b/tezt/tests/cloud/monitoring_app.ml @@ -297,18 +297,20 @@ module Baker_helpers = struct let* bakers = get_bakers_with_staking_power endpoint cycle in let total_baking_power = List.fold_left - (fun acc RPC.{baking_power; _} -> acc + baking_power) + (fun acc RPC.{delegate = _; staked; weighted_delegated} -> + acc + staked + weighted_delegated) 0 bakers in let* bakers_info = Lwt_list.filter_map_p - (fun RPC.{delegate; baking_power} -> + (fun RPC.{delegate; staked; weighted_delegated} -> let* attest_infos = fetch_baker_info ~origin:(Format.sprintf "fetch_baker_info.%s" delegate) ~tz1:delegate in + let baking_power = staked + weighted_delegated in let stake_fraction = float_of_int baking_power /. float_of_int total_baking_power in -- GitLab From 3f4fc66f87a9eb3c4c14375c7385ed527fa71215 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Fri, 10 Oct 2025 12:09:40 +0200 Subject: [PATCH 7/7] Tezt/AI: compute expected amounts slashed from own/external staked --- tezt/tests/adaptive_issuance.ml | 47 ++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/tezt/tests/adaptive_issuance.ml b/tezt/tests/adaptive_issuance.ml index 331deca8c8e0..9f2f7d7e106c 100644 --- a/tezt/tests/adaptive_issuance.ml +++ b/tezt/tests/adaptive_issuance.ml @@ -76,6 +76,10 @@ module Helpers = struct current_level (current_level + nb_blocks_to_bake) ; repeat nb_blocks_to_bake (fun () -> bake ?keys client) + + let ceil_q q = + let floor = Q.to_int q in + if Q.equal q (Q.of_int floor) then floor else floor + 1 end let log_step counter msg = @@ -959,6 +963,12 @@ let test_staking = Node.RPC.call node_2 @@ RPC.get_chain_block_context_delegate Constant.bootstrap2.public_key_hash in + let* misbehaviour_stake_distribution = + (* Last chance to retrieve this, because it gets cleared from the + context at the end of cycle [misbehaviour_cycle + 1]. *) + Node.RPC.call node_2 + @@ RPC.get_stake_distribution ~cycle:misbehaviour_cycle () + in (* Bake the block that applies the slashing (last block of cycle [misbehaviour_cycle + 1]). We will now check the slashed and @@ -1007,13 +1017,42 @@ let test_staking = |> to_int) in - (* slashed stake *) + (* Compute the expected amounts slashed from the baker's and the + external stakers' staked tez respectively. + + Note: we're skipping over some steps of slashing computation, + e.g. applying the delegate's and global + limit_of_staking_over_baking (we're very far from reaching it + here), and bounding the amount to slash from the baker by its + currently staked amount (which is more than high enough). *) + let own_staked = + JSON.(bootstrap2_info_right_before_slashing |-> "own_staked" |> as_int) + in + let external_staked = + JSON.(bootstrap2_info_right_before_slashing |-> "external_staked" |> as_int) + in + let total_staked = own_staked + external_staked in + let baker_share = Q.(own_staked // total_staked) in + let total_staked_recorded_for_misbehaviour_rights = + List.find_map + (fun RPC.{delegate; staked; weighted_delegated = _} -> + if String.equal delegate Constant.bootstrap2.public_key_hash then + Some staked + else None) + misbehaviour_stake_distribution + |> Option.get + in + let amount_slashed_from_total_staked = + Q.( + of_int total_staked_recorded_for_misbehaviour_rights + * double_baking_penalty + |> to_int) + in let amount_slashed_from_own_staked = - if Protocol.(number protocol > number S023) then 10_049_785_808 - else 10_049_764_732 + Q.(baker_share * of_int amount_slashed_from_total_staked) |> Helpers.ceil_q in let amount_slashed_from_external_staked = - if Protocol.(number protocol > number S023) then 50_248_756 else 50_248_756 + amount_slashed_from_total_staked - amount_slashed_from_own_staked in (* Compute rewarded vs burned amounts. *) -- GitLab