Skip to content

Commit a6dd871

Browse files
authored
Merge pull request #4666 from anoma/tomas/optimize-claim-rewards
optimize claim rewards tx
2 parents 179de15 + 237c45e commit a6dd871

File tree

5 files changed

+712
-64
lines changed

5 files changed

+712
-64
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- Optinmized the PoS claim rewards tx to use less gas.
2+
([\#4666](https://github.com/anoma/namada/pull/4666))

crates/proof_of_stake/src/lib.rs

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -929,28 +929,42 @@ struct FoldRedelegatedBondsResult {
929929
/// Iterates over a `redelegated_unbonds` and computes the both the sum of all
930930
/// redelegated tokens and how much is left after applying all relevant slashes.
931931
// `def foldAndSlashRedelegatedBondsMap`
932-
fn fold_and_slash_redelegated_bonds<S>(
932+
fn fold_and_slash_redelegated_bonds<'a, S>(
933933
storage: &S,
934934
params: &OwnedPosParams,
935935
redelegated_unbonds: &EagerRedelegatedBondsMap,
936936
start_epoch: Epoch,
937-
list_slashes: &[Slash],
937+
list_slashes: impl Iterator<Item = &'a Slash> + Clone,
938938
slash_epoch_filter: impl Fn(Epoch) -> bool,
939939
) -> Result<FoldRedelegatedBondsResult>
940940
where
941941
S: StorageRead,
942942
{
943+
use std::collections::hash_map;
944+
943945
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+
944950
for (src_validator, bonds_map) in redelegated_unbonds {
945951
for (bond_start, &change) in bonds_map {
946952
// 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+
952966
let mut merged: Vec<Slash> = validator_slashes
953-
.into_iter()
967+
.iter()
954968
.filter(|slash| {
955969
params.in_redelegation_slashing_window(
956970
slash.epoch,
@@ -959,16 +973,18 @@ where
959973
) && *bond_start <= slash.epoch
960974
&& slash_epoch_filter(slash.epoch)
961975
})
976+
.cloned()
962977
// ... and add `list_slashes`
963-
.chain(list_slashes.iter().cloned())
978+
.chain(list_slashes.clone().cloned())
964979
.collect();
965980

966981
// Sort slashes by epoch
967982
merged.sort_by(|s1, s2| s1.epoch.partial_cmp(&s2.epoch).unwrap());
968983

969984
result.total_redelegated =
970985
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)?;
972988
result.total_after_slashing =
973989
checked!(result.total_after_slashing + list_slashes)?;
974990
}
@@ -1915,7 +1931,7 @@ where
19151931
&params,
19161932
&redelegated_bonds,
19171933
start,
1918-
&list_slashes,
1934+
list_slashes.iter(),
19191935
slash_epoch_filter,
19201936
)?;
19211937

@@ -1924,7 +1940,7 @@ where
19241940

19251941
let after_not_redelegated = apply_list_slashes(
19261942
&params,
1927-
&list_slashes,
1943+
list_slashes.iter(),
19281944
total_not_redelegated,
19291945
)?;
19301946

@@ -1959,6 +1975,8 @@ where
19591975
S: StorageRead,
19601976
Gov: governance::Read<S>,
19611977
{
1978+
use std::collections::hash_map;
1979+
19621980
let params = read_pos_params::<S, Gov>(storage)?;
19631981
// Outer key is every epoch in which the a bond amount contributed to stake
19641982
// and the inner key is the start epoch used to calculate slashes. The inner
@@ -1973,10 +1991,12 @@ where
19731991
for next in bonds.iter(storage)? {
19741992
let (start, delta) = next?;
19751993

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+
) {
19802000
let amount =
19812001
amounts.entry(ep).or_default().entry(start).or_default();
19822002
*amount = checked!(amount + delta)?;
@@ -1985,42 +2005,50 @@ where
19852005
}
19862006

19872007
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)?;
19892009
let redelegated_bonded =
19902010
delegator_redelegated_bonds_handle(&bond_id.source)
19912011
.at(&bond_id.validator);
19922012

2013+
#[allow(clippy::disallowed_types)] // The cache ordering doesn't matter
2014+
let mut redelegated_bonds_cache = hash_map::HashMap::new();
2015+
19932016
// Apply slashes
19942017
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+
19952022
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+
});
20142032

20152033
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+
};
20172045

20182046
let result_fold = fold_and_slash_redelegated_bonds(
20192047
storage,
20202048
&params,
2021-
&redelegated_bonds,
2049+
redelegated_bonds,
20222050
start,
2023-
&list_slashes,
2051+
slashes.clone(),
20242052
slash_epoch_filter,
20252053
)?;
20262054

@@ -2029,7 +2057,7 @@ where
20292057

20302058
let after_not_redelegated = apply_list_slashes(
20312059
&params,
2032-
&list_slashes,
2060+
slashes,
20332061
total_not_redelegated,
20342062
)?;
20352063

0 commit comments

Comments
 (0)