Skip to content

Commit 9651de1

Browse files
foriequal0mergify[bot]
authored andcommitted
Remove empty stake entries from state
1 parent d2d29a4 commit 9651de1

File tree

6 files changed

+216
-27
lines changed

6 files changed

+216
-27
lines changed

core/src/consensus/tendermint/stake/action_data.rs

Lines changed: 84 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rlp::{Decodable, Encodable, Rlp, RlpStream};
2626

2727
use super::CUSTOM_ACTION_HANDLER_ID;
2828

29-
fn get_account_key(address: &Address) -> H256 {
29+
pub fn get_account_key(address: &Address) -> H256 {
3030
ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 2).append(&"Account").append(address).into_key()
3131
}
3232

@@ -35,7 +35,7 @@ lazy_static! {
3535
ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 1).append(&"StakeholderAddresses").into_key();
3636
}
3737

38-
fn get_delegation_key(address: &Address) -> H256 {
38+
pub fn get_delegation_key(address: &Address) -> H256 {
3939
ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 2).append(&"Delegation").append(address).into_key()
4040
}
4141

@@ -64,8 +64,12 @@ impl<'a> StakeAccount<'a> {
6464

6565
pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> {
6666
let account_key = get_account_key(self.address);
67-
let rlp = rlp::encode(&self.balance);
68-
state.update_action_data(&account_key, rlp.into_vec())?;
67+
if self.balance != 0 {
68+
let rlp = rlp::encode(&self.balance);
69+
state.update_action_data(&account_key, rlp.into_vec())?;
70+
} else {
71+
state.remove_action_data(&account_key);
72+
}
6973
Ok(())
7074
}
7175

@@ -97,7 +101,12 @@ impl Stakeholders {
97101
}
98102

99103
pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> {
100-
state.update_action_data(&*STAKEHOLDER_ADDRESSES_KEY, encode_set(&self.0))?;
104+
let key = *STAKEHOLDER_ADDRESSES_KEY;
105+
if !self.0.is_empty() {
106+
state.update_action_data(&key, encode_set(&self.0))?;
107+
} else {
108+
state.remove_action_data(&key);
109+
}
101110
Ok(())
102111
}
103112

@@ -106,10 +115,15 @@ impl Stakeholders {
106115
self.0.contains(address)
107116
}
108117

109-
pub fn update(&mut self, account: &StakeAccount) {
118+
pub fn update_by_increased_balance(&mut self, account: &StakeAccount) {
110119
if account.balance > 0 {
111120
self.0.insert(*account.address);
112-
} else {
121+
}
122+
}
123+
124+
pub fn update_by_decreased_balance(&mut self, account: &StakeAccount, delegation: &Delegation) {
125+
assert!(account.address == delegation.delegator);
126+
if account.balance == 0 && delegation.sum() == 0 {
113127
self.0.remove(account.address);
114128
}
115129
}
@@ -138,8 +152,12 @@ impl<'a> Delegation<'a> {
138152

139153
pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> {
140154
let key = get_delegation_key(self.delegator);
141-
let encoded = encode_map(&self.delegatees);
142-
state.update_action_data(&key, encoded)?;
155+
if !self.delegatees.is_empty() {
156+
let encoded = encode_map(&self.delegatees);
157+
state.update_action_data(&key, encoded)?;
158+
} else {
159+
state.remove_action_data(&key);
160+
}
143161
Ok(())
144162
}
145163

@@ -296,6 +314,24 @@ mod tests {
296314
assert_eq!(account.balance, 10);
297315
}
298316

317+
#[test]
318+
fn balance_subtract_all_should_remove_entry_from_db() {
319+
let mut state = helpers::get_temp_state();
320+
let address = Address::random();
321+
322+
let mut account = StakeAccount::load_from_state(&state, &address).unwrap();
323+
account.add_balance(100).unwrap();
324+
account.save_to_state(&mut state).unwrap();
325+
326+
let mut account = StakeAccount::load_from_state(&state, &address).unwrap();
327+
let result = account.subtract_balance(100);
328+
assert!(result.is_ok());
329+
account.save_to_state(&mut state).unwrap();
330+
331+
let data = state.action_data(&get_account_key(&address)).unwrap();
332+
assert_eq!(data, None);
333+
}
334+
299335
#[test]
300336
fn stakeholders_track() {
301337
let mut rng = rng();
@@ -311,7 +347,7 @@ mod tests {
311347

312348
let mut stakeholders = Stakeholders::load_from_state(&state).unwrap();
313349
for account in &accounts {
314-
stakeholders.update(account);
350+
stakeholders.update_by_increased_balance(account);
315351
}
316352
stakeholders.save_to_state(&mut state).unwrap();
317353

@@ -334,18 +370,17 @@ mod tests {
334370

335371
let mut stakeholders = Stakeholders::load_from_state(&state).unwrap();
336372
for account in &accounts {
337-
stakeholders.update(account);
373+
stakeholders.update_by_increased_balance(account);
338374
}
339375
stakeholders.save_to_state(&mut state).unwrap();
340376

377+
let mut stakeholders = Stakeholders::load_from_state(&state).unwrap();
341378
for account in &mut accounts {
342379
if rand::random() {
343380
account.balance = 0;
344381
}
345-
}
346-
let mut stakeholders = Stakeholders::load_from_state(&state).unwrap();
347-
for account in &accounts {
348-
stakeholders.update(account);
382+
let delegation = Delegation::load_from_state(&state, account.address).unwrap();
383+
stakeholders.update_by_decreased_balance(account, &delegation);
349384
}
350385
stakeholders.save_to_state(&mut state).unwrap();
351386

@@ -357,6 +392,40 @@ mod tests {
357392
}
358393
}
359394

395+
#[test]
396+
fn stakeholders_doesnt_untrack_if_delegation_exists() {
397+
let mut state = helpers::get_temp_state();
398+
let addresses: Vec<_> = (1..100).map(|_| Address::random()).collect();
399+
let mut accounts: Vec<_> = addresses
400+
.iter()
401+
.map(|address| StakeAccount {
402+
address,
403+
balance: 100,
404+
})
405+
.collect();
406+
407+
let mut stakeholders = Stakeholders::load_from_state(&state).unwrap();
408+
for account in &accounts {
409+
stakeholders.update_by_increased_balance(account);
410+
}
411+
stakeholders.save_to_state(&mut state).unwrap();
412+
413+
let mut stakeholders = Stakeholders::load_from_state(&state).unwrap();
414+
for account in &mut accounts {
415+
// like self-delegate
416+
let mut delegation = Delegation::load_from_state(&state, account.address).unwrap();
417+
delegation.add_quantity(*account.address, account.balance).unwrap();
418+
account.balance = 0;
419+
stakeholders.update_by_decreased_balance(account, &delegation);
420+
}
421+
stakeholders.save_to_state(&mut state).unwrap();
422+
423+
let stakeholders = Stakeholders::load_from_state(&state).unwrap();
424+
for account in &accounts {
425+
assert!(stakeholders.contains(account.address));
426+
}
427+
}
428+
360429
#[test]
361430
fn initial_delegation_is_empty() {
362431
let state = helpers::get_temp_state();

core/src/consensus/tendermint/stake/mod.rs

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,14 @@ impl ActionHandler for Stake {
5757
fn init(&self, state: &mut TopLevelState) -> StateResult<()> {
5858
let mut stakeholders = Stakeholders::load_from_state(state)?;
5959
for (address, amount) in self.genesis_stakes.iter() {
60-
if *amount > 0 {
61-
let account = StakeAccount {
62-
address,
63-
balance: *amount,
64-
};
65-
stakeholders.update(&account);
66-
account.save_to_state(state)?;
67-
}
68-
stakeholders.save_to_state(state)?;
60+
let account = StakeAccount {
61+
address,
62+
balance: *amount,
63+
};
64+
account.save_to_state(state)?;
65+
stakeholders.update_by_increased_balance(&account);
6966
}
67+
stakeholders.save_to_state(state)?;
7068
Ok(())
7169
}
7270

@@ -90,12 +88,13 @@ fn transfer_ccs(state: &mut TopLevelState, sender: &Address, receiver: &Address,
9088
let mut stakeholders = Stakeholders::load_from_state(state)?;
9189
let mut sender_account = StakeAccount::load_from_state(state, sender)?;
9290
let mut receiver_account = StakeAccount::load_from_state(state, receiver)?;
91+
let sender_delegations = Delegation::load_from_state(state, sender)?;
9392

9493
sender_account.subtract_balance(quantity)?;
9594
receiver_account.add_balance(quantity)?;
9695

97-
stakeholders.update(&sender_account);
98-
stakeholders.update(&receiver_account);
96+
stakeholders.update_by_decreased_balance(&sender_account, &sender_delegations);
97+
stakeholders.update_by_increased_balance(&receiver_account);
9998

10099
stakeholders.save_to_state(state)?;
101100
sender_account.save_to_state(state)?;
@@ -120,6 +119,7 @@ fn delegate_ccs(
120119

121120
delegator.subtract_balance(quantity)?;
122121
delegation.add_quantity(*delegatee, quantity)?;
122+
// delegation does not touch stakeholders
123123

124124
delegation.save_to_state(state)?;
125125
delegator.save_to_state(state)?;
@@ -139,10 +139,13 @@ pub fn get_stakes(state: &TopLevelState) -> StateResult<HashMap<Address, u64>> {
139139

140140
#[cfg(test)]
141141
mod tests {
142+
use super::action_data::get_account_key;
142143
use super::*;
144+
143145
use ckey::{public_to_address, Public};
144146
use consensus::validator_set::new_validator_set;
145147
use cstate::tests::helpers;
148+
use cstate::TopStateView;
146149
use rlp::Encodable;
147150

148151
#[test]
@@ -210,6 +213,7 @@ mod tests {
210213
let account1 = StakeAccount::load_from_state(&state, &address1).unwrap();
211214
let account2 = StakeAccount::load_from_state(&state, &address2).unwrap();
212215
assert_eq!(account1.balance, 0);
216+
assert_eq!(state.action_data(&get_account_key(&address1)).unwrap(), None);
213217
assert_eq!(account2.balance, 100);
214218
let stakeholders = Stakeholders::load_from_state(&state).unwrap();
215219
assert!(!stakeholders.contains(&address1));
@@ -251,6 +255,42 @@ mod tests {
251255
assert_eq!(delegation_untouched.iter().count(), 0);
252256
}
253257

258+
#[test]
259+
fn delegate_all() {
260+
let delegatee_public = Public::random();
261+
let delegatee = public_to_address(&delegatee_public);
262+
let delegator = Address::random();
263+
264+
let mut state = helpers::get_temp_state();
265+
let stake = {
266+
let mut genesis_stakes = HashMap::new();
267+
genesis_stakes.insert(delegatee, 100);
268+
genesis_stakes.insert(delegator, 100);
269+
Stake::new(genesis_stakes, new_validator_set(vec![delegatee_public]))
270+
};
271+
assert_eq!(Ok(()), stake.init(&mut state));
272+
273+
let action = Action::DelegateCCS {
274+
address: delegatee,
275+
quantity: 100,
276+
};
277+
let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator);
278+
assert_eq!(result, Ok(()));
279+
280+
let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap();
281+
let delegation = Delegation::load_from_state(&state, &delegator).unwrap();
282+
assert_eq!(delegator_account.balance, 0);
283+
assert_eq!(state.action_data(&get_account_key(&delegator)).unwrap(), None);
284+
assert_eq!(delegation.iter().count(), 1);
285+
assert_eq!(delegation.get_quantity(&delegatee), 100);
286+
287+
// Should not be touched
288+
let delegatee_account = StakeAccount::load_from_state(&state, &delegatee).unwrap();
289+
let delegation_untouched = Delegation::load_from_state(&state, &delegatee).unwrap();
290+
assert_eq!(delegatee_account.balance, 100);
291+
assert_eq!(delegation_untouched.iter().count(), 0);
292+
}
293+
254294
#[test]
255295
fn delegate_only_to_validator() {
256296
let delegatee_public = Public::random();

state/src/cache/top_cache.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ impl TopCache {
155155
self.action_data.get_mut(a, db)
156156
}
157157

158-
#[allow(dead_code)]
159158
pub fn remove_action_data(&self, address: &H256) {
160159
self.action_data.remove(address)
161160
}

state/src/impls/top_level.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,10 @@ impl TopState for TopLevelState {
967967
*action_data = data.into();
968968
Ok(())
969969
}
970+
971+
fn remove_action_data(&mut self, key: &H256) {
972+
self.top_cache.remove_action_data(key)
973+
}
970974
}
971975

972976
fn is_active_account(state: &TopStateView, address: &Address) -> TrieResult<bool> {

state/src/traits.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ pub trait TopState {
178178
fn remove_text(&mut self, key: &H256, sig: &Signature) -> StateResult<()>;
179179

180180
fn update_action_data(&mut self, key: &H256, data: Bytes) -> StateResult<()>;
181+
fn remove_action_data(&mut self, key: &H256);
181182
}
182183

183184
pub trait StateWithCache {

0 commit comments

Comments
 (0)