@@ -929,28 +929,42 @@ struct FoldRedelegatedBondsResult {
929
929
/// Iterates over a `redelegated_unbonds` and computes the both the sum of all
930
930
/// redelegated tokens and how much is left after applying all relevant slashes.
931
931
// `def foldAndSlashRedelegatedBondsMap`
932
- fn fold_and_slash_redelegated_bonds < S > (
932
+ fn fold_and_slash_redelegated_bonds < ' a , S > (
933
933
storage : & S ,
934
934
params : & OwnedPosParams ,
935
935
redelegated_unbonds : & EagerRedelegatedBondsMap ,
936
936
start_epoch : Epoch ,
937
- list_slashes : & [ Slash ] ,
937
+ list_slashes : impl Iterator < Item = & ' a Slash > + Clone ,
938
938
slash_epoch_filter : impl Fn ( Epoch ) -> bool ,
939
939
) -> Result < FoldRedelegatedBondsResult >
940
940
where
941
941
S : StorageRead ,
942
942
{
943
+ use std:: collections:: hash_map;
944
+
943
945
let mut result = FoldRedelegatedBondsResult :: default ( ) ;
946
+
947
+ #[ allow( clippy:: disallowed_types) ] // The cache ordering doesn't matter
948
+ let mut src_slash_cache = hash_map:: HashMap :: < Address , Vec < Slash > > :: new ( ) ;
949
+
944
950
for ( src_validator, bonds_map) in redelegated_unbonds {
945
951
for ( bond_start, & change) in bonds_map {
946
952
// Look-up slashes for this validator ...
947
- let validator_slashes: Vec < Slash > =
948
- validator_slashes_handle ( src_validator)
949
- . iter ( storage) ?
950
- . collect :: < Result < Vec < Slash > > > ( ) ?;
951
- // Merge the two lists of slashes
953
+ let validator_slashes = match src_slash_cache
954
+ . entry ( src_validator. clone ( ) )
955
+ {
956
+ hash_map:: Entry :: Vacant ( vacant_entry) => vacant_entry. insert (
957
+ validator_slashes_handle ( src_validator)
958
+ . iter ( storage) ?
959
+ . collect :: < Result < Vec < Slash > > > ( ) ?,
960
+ ) ,
961
+ hash_map:: Entry :: Occupied ( occupied_entry) => {
962
+ occupied_entry. into_mut ( )
963
+ }
964
+ } ;
965
+
952
966
let mut merged: Vec < Slash > = validator_slashes
953
- . into_iter ( )
967
+ . iter ( )
954
968
. filter ( |slash| {
955
969
params. in_redelegation_slashing_window (
956
970
slash. epoch ,
@@ -959,16 +973,18 @@ where
959
973
) && * bond_start <= slash. epoch
960
974
&& slash_epoch_filter ( slash. epoch )
961
975
} )
976
+ . cloned ( )
962
977
// ... and add `list_slashes`
963
- . chain ( list_slashes. iter ( ) . cloned ( ) )
978
+ . chain ( list_slashes. clone ( ) . cloned ( ) )
964
979
. collect ( ) ;
965
980
966
981
// Sort slashes by epoch
967
982
merged. sort_by ( |s1, s2| s1. epoch . partial_cmp ( & s2. epoch ) . unwrap ( ) ) ;
968
983
969
984
result. total_redelegated =
970
985
checked ! ( result. total_redelegated + change) ?;
971
- let list_slashes = apply_list_slashes ( params, & merged, change) ?;
986
+ let list_slashes =
987
+ apply_list_slashes ( params, merged. iter ( ) , change) ?;
972
988
result. total_after_slashing =
973
989
checked ! ( result. total_after_slashing + list_slashes) ?;
974
990
}
@@ -1915,7 +1931,7 @@ where
1915
1931
& params,
1916
1932
& redelegated_bonds,
1917
1933
start,
1918
- & list_slashes,
1934
+ list_slashes. iter ( ) ,
1919
1935
slash_epoch_filter,
1920
1936
) ?;
1921
1937
@@ -1924,7 +1940,7 @@ where
1924
1940
1925
1941
let after_not_redelegated = apply_list_slashes (
1926
1942
& params,
1927
- & list_slashes,
1943
+ list_slashes. iter ( ) ,
1928
1944
total_not_redelegated,
1929
1945
) ?;
1930
1946
@@ -1959,6 +1975,8 @@ where
1959
1975
S : StorageRead ,
1960
1976
Gov : governance:: Read < S > ,
1961
1977
{
1978
+ use std:: collections:: hash_map;
1979
+
1962
1980
let params = read_pos_params :: < S , Gov > ( storage) ?;
1963
1981
// Outer key is every epoch in which the a bond amount contributed to stake
1964
1982
// and the inner key is the start epoch used to calculate slashes. The inner
@@ -1973,10 +1991,12 @@ where
1973
1991
for next in bonds. iter ( storage) ? {
1974
1992
let ( start, delta) = next?;
1975
1993
1976
- for ep in Epoch :: iter_bounds_inclusive ( claim_start, claim_end) {
1977
- // A bond that wasn't unbonded is added to all epochs up to
1978
- // `claim_end`
1979
- if start <= ep {
1994
+ // A bond that wasn't unbonded is added to all epochs up to `claim_end`
1995
+ if claim_end >= start {
1996
+ for ep in Epoch :: iter_bounds_inclusive (
1997
+ cmp:: max ( claim_start, start) ,
1998
+ claim_end,
1999
+ ) {
1980
2000
let amount =
1981
2001
amounts. entry ( ep) . or_default ( ) . entry ( start) . or_default ( ) ;
1982
2002
* amount = checked ! ( amount + delta) ?;
@@ -1985,42 +2005,50 @@ where
1985
2005
}
1986
2006
1987
2007
if !amounts. is_empty ( ) {
1988
- let slashes = find_validator_slashes ( storage, & bond_id. validator ) ?;
2008
+ let list_slashes = find_validator_slashes ( storage, & bond_id. validator ) ?;
1989
2009
let redelegated_bonded =
1990
2010
delegator_redelegated_bonds_handle ( & bond_id. source )
1991
2011
. at ( & bond_id. validator ) ;
1992
2012
2013
+ #[ allow( clippy:: disallowed_types) ] // The cache ordering doesn't matter
2014
+ let mut redelegated_bonds_cache = hash_map:: HashMap :: new ( ) ;
2015
+
1993
2016
// Apply slashes
1994
2017
for ( & ep, amounts) in amounts. iter_mut ( ) {
2018
+ let slash_epoch_filter = |e : Epoch | {
2019
+ e. unchecked_add ( params. slash_processing_epoch_offset ( ) ) <= ep
2020
+ } ;
2021
+
1995
2022
for ( & start, amount) in amounts. iter_mut ( ) {
1996
- let list_slashes = slashes
1997
- . iter ( )
1998
- . filter ( |slash| {
1999
- let processing_epoch = slash. epoch . unchecked_add (
2000
- params. slash_processing_epoch_offset ( ) ,
2001
- ) ;
2002
- // Only use slashes that were processed before or at the
2003
- // epoch associated with the bond amount. This assumes
2004
- // that slashes are applied before inflation.
2005
- processing_epoch <= ep && start <= slash. epoch
2006
- } )
2007
- . cloned ( )
2008
- . collect :: < Vec < _ > > ( ) ;
2009
-
2010
- let slash_epoch_filter = |e : Epoch | {
2011
- e. unchecked_add ( params. slash_processing_epoch_offset ( ) )
2012
- <= ep
2013
- } ;
2023
+ let slashes = list_slashes. iter ( ) . filter ( |slash| {
2024
+ let processing_epoch = slash
2025
+ . epoch
2026
+ . unchecked_add ( params. slash_processing_epoch_offset ( ) ) ;
2027
+ // Only use slashes that were processed before or at the
2028
+ // epoch associated with the bond amount. This assumes
2029
+ // that slashes are applied before inflation.
2030
+ processing_epoch <= ep && start <= slash. epoch
2031
+ } ) ;
2014
2032
2015
2033
let redelegated_bonds =
2016
- redelegated_bonded. at ( & start) . collect_map ( storage) ?;
2034
+ match redelegated_bonds_cache. entry ( start) {
2035
+ hash_map:: Entry :: Vacant ( vacant_entry) => vacant_entry
2036
+ . insert (
2037
+ redelegated_bonded
2038
+ . at ( & start)
2039
+ . collect_map ( storage) ?,
2040
+ ) ,
2041
+ hash_map:: Entry :: Occupied ( occupied_entry) => {
2042
+ occupied_entry. into_mut ( )
2043
+ }
2044
+ } ;
2017
2045
2018
2046
let result_fold = fold_and_slash_redelegated_bonds (
2019
2047
storage,
2020
2048
& params,
2021
- & redelegated_bonds,
2049
+ redelegated_bonds,
2022
2050
start,
2023
- & list_slashes ,
2051
+ slashes . clone ( ) ,
2024
2052
slash_epoch_filter,
2025
2053
) ?;
2026
2054
@@ -2029,7 +2057,7 @@ where
2029
2057
2030
2058
let after_not_redelegated = apply_list_slashes (
2031
2059
& params,
2032
- & list_slashes ,
2060
+ slashes ,
2033
2061
total_not_redelegated,
2034
2062
) ?;
2035
2063
0 commit comments