Skip to content

Commit 9bf06ac

Browse files
foriequal0mergify[bot]
authored andcommitted
Implement revoke
1 parent e59bfbb commit 9bf06ac

File tree

4 files changed

+538
-1
lines changed

4 files changed

+538
-1
lines changed

core/src/consensus/stake/actions.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp};
2020

2121
const ACTION_TAG_TRANSFER_CCS: u8 = 1;
2222
const ACTION_TAG_DELEGATE_CCS: u8 = 2;
23+
const ACTION_TAG_REVOKE: u8 = 3;
2324
const ACTION_TAG_CHANGE_PARAMS: u8 = 0xFF;
2425

2526
#[derive(Debug, PartialEq)]
@@ -32,6 +33,10 @@ pub enum Action {
3233
address: Address,
3334
quantity: u64,
3435
},
36+
Revoke {
37+
address: Address,
38+
quantity: u64,
39+
},
3540
ChangeParams {
3641
metadata_seq: u64,
3742
params: Box<CommonParams>,
@@ -54,6 +59,12 @@ impl Encodable for Action {
5459
} => {
5560
s.begin_list(3).append(&ACTION_TAG_DELEGATE_CCS).append(address).append(quantity);
5661
}
62+
Action::Revoke {
63+
address,
64+
quantity,
65+
} => {
66+
s.begin_list(3).append(&ACTION_TAG_REVOKE).append(address).append(quantity);
67+
}
5768
Action::ChangeParams {
5869
metadata_seq,
5970
params,
@@ -101,6 +112,19 @@ impl Decodable for Action {
101112
quantity: rlp.val_at(2)?,
102113
})
103114
}
115+
ACTION_TAG_REVOKE => {
116+
let item_count = rlp.item_count()?;
117+
if item_count != 3 {
118+
return Err(DecoderError::RlpInvalidLength {
119+
expected: 3,
120+
got: item_count,
121+
})
122+
}
123+
Ok(Action::Revoke {
124+
address: rlp.val_at(1)?,
125+
quantity: rlp.val_at(2)?,
126+
})
127+
}
104128
ACTION_TAG_CHANGE_PARAMS => {
105129
let item_count = rlp.item_count()?;
106130
if item_count < 4 {

core/src/consensus/stake/mod.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,16 @@ impl ActionHandler for Stake {
115115
Err(RuntimeError::FailedToHandleCustomAction("DelegateCCS is disabled".to_string()).into())
116116
}
117117
}
118+
Action::Revoke {
119+
address,
120+
quantity,
121+
} => {
122+
if self.enable_delegations {
123+
revoke(state, sender, &address, quantity)
124+
} else {
125+
Err(RuntimeError::FailedToHandleCustomAction("DelegateCCS is disabled".to_string()).into())
126+
}
127+
}
118128
Action::ChangeParams {
119129
metadata_seq,
120130
params,
@@ -133,6 +143,9 @@ impl ActionHandler for Stake {
133143
Action::DelegateCCS {
134144
..
135145
} => Ok(()),
146+
Action::Revoke {
147+
..
148+
} => Ok(()),
136149
Action::ChangeParams {
137150
metadata_seq,
138151
params,
@@ -208,6 +221,19 @@ fn delegate_ccs(
208221
Ok(())
209222
}
210223

224+
fn revoke(state: &mut TopLevelState, sender: &Address, delegatee: &Address, quantity: u64) -> StateResult<()> {
225+
let mut delegator = StakeAccount::load_from_state(state, sender)?;
226+
let mut delegation = Delegation::load_from_state(state, &sender)?;
227+
228+
delegator.add_balance(quantity)?;
229+
delegation.subtract_quantity(*delegatee, quantity)?;
230+
// delegation does not touch stakeholders
231+
232+
delegation.save_to_state(state)?;
233+
delegator.save_to_state(state)?;
234+
Ok(())
235+
}
236+
211237
pub fn get_stakes(state: &TopLevelState) -> StateResult<HashMap<Address, u64>> {
212238
let stakeholders = Stakeholders::load_from_state(state)?;
213239
let mut result = HashMap::new();
@@ -279,6 +305,7 @@ mod tests {
279305
use super::*;
280306

281307
use ckey::{public_to_address, Public};
308+
use consensus::stake::action_data::get_delegation_key;
282309
use consensus::validator_set::new_validator_set;
283310
use cstate::tests::helpers;
284311
use cstate::TopStateView;
@@ -552,4 +579,110 @@ mod tests {
552579
let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator);
553580
assert!(result.is_err());
554581
}
582+
583+
#[test]
584+
fn can_revoke_delegated_tokens() {
585+
let delegatee_public = Public::random();
586+
let delegatee = public_to_address(&delegatee_public);
587+
let delegator = Address::random();
588+
589+
let mut state = helpers::get_temp_state();
590+
let stake = {
591+
let mut genesis_stakes = HashMap::new();
592+
genesis_stakes.insert(delegatee, 100);
593+
genesis_stakes.insert(delegator, 100);
594+
Stake::new(genesis_stakes, new_validator_set(vec![delegatee_public]))
595+
};
596+
stake.init(&mut state).unwrap();
597+
598+
let action = Action::DelegateCCS {
599+
address: delegatee,
600+
quantity: 50,
601+
};
602+
let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator);
603+
assert!(result.is_ok());
604+
605+
let action = Action::Revoke {
606+
address: delegatee,
607+
quantity: 20,
608+
};
609+
let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator);
610+
assert_eq!(Ok(()), result);
611+
612+
let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap();
613+
let delegation = Delegation::load_from_state(&state, &delegator).unwrap();
614+
assert_eq!(delegator_account.balance, 100 - 50 + 20);
615+
assert_eq!(delegation.iter().count(), 1);
616+
assert_eq!(delegation.get_quantity(&delegatee), 50 - 20);
617+
}
618+
619+
#[test]
620+
fn cannot_revoke_more_than_delegated_tokens() {
621+
let delegatee_public = Public::random();
622+
let delegatee = public_to_address(&delegatee_public);
623+
let delegator = Address::random();
624+
625+
let mut state = helpers::get_temp_state();
626+
let stake = {
627+
let mut genesis_stakes = HashMap::new();
628+
genesis_stakes.insert(delegatee, 100);
629+
genesis_stakes.insert(delegator, 100);
630+
Stake::new(genesis_stakes, new_validator_set(vec![delegatee_public]))
631+
};
632+
stake.init(&mut state).unwrap();
633+
634+
let action = Action::DelegateCCS {
635+
address: delegatee,
636+
quantity: 50,
637+
};
638+
let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator);
639+
assert!(result.is_ok());
640+
641+
let action = Action::Revoke {
642+
address: delegatee,
643+
quantity: 70,
644+
};
645+
let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator);
646+
assert!(result.is_err());
647+
648+
let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap();
649+
let delegation = Delegation::load_from_state(&state, &delegator).unwrap();
650+
assert_eq!(delegator_account.balance, 100 - 50);
651+
assert_eq!(delegation.iter().count(), 1);
652+
assert_eq!(delegation.get_quantity(&delegatee), 50);
653+
}
654+
655+
#[test]
656+
fn revoke_all_should_clear_state() {
657+
let delegatee_public = Public::random();
658+
let delegatee = public_to_address(&delegatee_public);
659+
let delegator = Address::random();
660+
661+
let mut state = helpers::get_temp_state();
662+
let stake = {
663+
let mut genesis_stakes = HashMap::new();
664+
genesis_stakes.insert(delegatee, 100);
665+
genesis_stakes.insert(delegator, 100);
666+
Stake::new(genesis_stakes, new_validator_set(vec![delegatee_public]))
667+
};
668+
stake.init(&mut state).unwrap();
669+
670+
let action = Action::DelegateCCS {
671+
address: delegatee,
672+
quantity: 50,
673+
};
674+
let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator);
675+
assert!(result.is_ok());
676+
677+
let action = Action::Revoke {
678+
address: delegatee,
679+
quantity: 50,
680+
};
681+
let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator);
682+
assert_eq!(Ok(()), result);
683+
684+
let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap();
685+
assert_eq!(delegator_account.balance, 100);
686+
assert_eq!(state.action_data(&get_delegation_key(&delegator)).unwrap(), None);
687+
}
555688
}

0 commit comments

Comments
 (0)