Skip to content

Commit 51630c5

Browse files
committed
Precalculate the fee in era=1
1 parent 56977cf commit 51630c5

File tree

3 files changed

+198
-23
lines changed

3 files changed

+198
-23
lines changed

core/src/consensus/stake/action_data.rs

Lines changed: 103 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -409,12 +409,12 @@ impl IntoIterator for Validators {
409409
}
410410

411411
#[derive(Default, Debug, PartialEq)]
412-
pub struct IntermediateRewards {
412+
pub struct IntermediateRewardsV0 {
413413
previous: BTreeMap<Address, u64>,
414414
current: BTreeMap<Address, u64>,
415415
}
416416

417-
impl IntermediateRewards {
417+
impl IntermediateRewardsV0 {
418418
pub fn load_from_state(state: &TopLevelState) -> StateResult<Self> {
419419
let key = get_intermediate_rewards_key();
420420
let action_data = state.action_data(&key)?;
@@ -456,6 +456,59 @@ impl IntermediateRewards {
456456
}
457457
}
458458

459+
#[derive(Default, Debug, PartialEq)]
460+
pub struct IntermediateRewardsV1 {
461+
current: BTreeMap<Address, u64>,
462+
calculated: BTreeMap<Address, u64>,
463+
}
464+
465+
impl IntermediateRewardsV1 {
466+
pub fn load_from_state(state: &TopLevelState) -> StateResult<Self> {
467+
let key = get_intermediate_rewards_key();
468+
let action_data = state.action_data(&key)?;
469+
let (current, calculated) = decode_map_tuple(action_data.as_ref());
470+
471+
Ok(Self {
472+
current,
473+
calculated,
474+
})
475+
}
476+
477+
pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> {
478+
let key = get_intermediate_rewards_key();
479+
if self.current.is_empty() && self.calculated.is_empty() {
480+
state.remove_action_data(&key);
481+
} else {
482+
let encoded = encode_map_tuple(&self.current, &self.calculated);
483+
state.update_action_data(&key, encoded)?;
484+
}
485+
Ok(())
486+
}
487+
488+
pub fn add_quantity(&mut self, address: Address, quantity: StakeQuantity) {
489+
if quantity == 0 {
490+
return
491+
}
492+
*self.current.entry(address).or_insert(0) += quantity;
493+
}
494+
495+
pub fn update_calculated(&mut self, rewards: BTreeMap<Address, u64>) {
496+
self.calculated = rewards;
497+
}
498+
499+
pub fn drain_current(&mut self) -> BTreeMap<Address, u64> {
500+
let mut new = BTreeMap::new();
501+
mem::swap(&mut new, &mut self.current);
502+
new
503+
}
504+
505+
pub fn drain_calculated(&mut self) -> BTreeMap<Address, u64> {
506+
let mut new = BTreeMap::new();
507+
mem::swap(&mut new, &mut self.calculated);
508+
new
509+
}
510+
}
511+
459512
pub struct Candidates(Vec<Candidate>);
460513
#[derive(Clone, Debug, Eq, PartialEq, RlpEncodable, RlpDecodable)]
461514
pub struct Candidate {
@@ -1129,46 +1182,85 @@ mod tests {
11291182
}
11301183

11311184
#[test]
1132-
fn load_and_save_intermediate_rewards() {
1185+
fn load_and_save_intermediate_rewards_v0() {
11331186
let mut state = helpers::get_temp_state();
1134-
let rewards = IntermediateRewards::load_from_state(&state).unwrap();
1187+
let rewards = IntermediateRewardsV0::load_from_state(&state).unwrap();
11351188
rewards.save_to_state(&mut state).unwrap();
11361189
}
11371190

11381191
#[test]
1139-
fn add_quantity() {
1192+
fn add_quantity_v0() {
11401193
let address1 = Address::random();
11411194
let address2 = Address::random();
11421195
let mut state = helpers::get_temp_state();
1143-
let mut origin_rewards = IntermediateRewards::load_from_state(&state).unwrap();
1196+
let mut origin_rewards = IntermediateRewardsV0::load_from_state(&state).unwrap();
11441197
origin_rewards.add_quantity(address1, 1);
11451198
origin_rewards.add_quantity(address2, 2);
11461199
origin_rewards.save_to_state(&mut state).unwrap();
1147-
let recovered_rewards = IntermediateRewards::load_from_state(&state).unwrap();
1200+
let recovered_rewards = IntermediateRewardsV0::load_from_state(&state).unwrap();
11481201
assert_eq!(origin_rewards, recovered_rewards);
11491202
}
11501203

11511204
#[test]
1152-
fn drain() {
1205+
fn drain_v0() {
11531206
let address1 = Address::random();
11541207
let address2 = Address::random();
11551208
let mut state = helpers::get_temp_state();
1156-
let mut origin_rewards = IntermediateRewards::load_from_state(&state).unwrap();
1209+
let mut origin_rewards = IntermediateRewardsV0::load_from_state(&state).unwrap();
11571210
origin_rewards.add_quantity(address1, 1);
11581211
origin_rewards.add_quantity(address2, 2);
11591212
origin_rewards.save_to_state(&mut state).unwrap();
1160-
let mut recovered_rewards = IntermediateRewards::load_from_state(&state).unwrap();
1213+
let mut recovered_rewards = IntermediateRewardsV0::load_from_state(&state).unwrap();
11611214
assert_eq!(origin_rewards, recovered_rewards);
11621215
let _drained = recovered_rewards.drain_previous();
11631216
recovered_rewards.save_to_state(&mut state).unwrap();
1164-
let mut final_rewards = IntermediateRewards::load_from_state(&state).unwrap();
1217+
let mut final_rewards = IntermediateRewardsV0::load_from_state(&state).unwrap();
11651218
assert_eq!(BTreeMap::new(), final_rewards.previous);
11661219
let current = final_rewards.current.clone();
11671220
final_rewards.move_current_to_previous();
11681221
assert_eq!(BTreeMap::new(), final_rewards.current);
11691222
assert_eq!(current, final_rewards.previous);
11701223
}
11711224

1225+
#[test]
1226+
fn load_and_save_intermediate_rewards_v1() {
1227+
let mut state = helpers::get_temp_state();
1228+
let rewards = IntermediateRewardsV1::load_from_state(&state).unwrap();
1229+
rewards.save_to_state(&mut state).unwrap();
1230+
}
1231+
1232+
#[test]
1233+
fn add_quantity_v1() {
1234+
let address1 = Address::random();
1235+
let address2 = Address::random();
1236+
let mut state = helpers::get_temp_state();
1237+
let mut origin_rewards = IntermediateRewardsV1::load_from_state(&state).unwrap();
1238+
origin_rewards.add_quantity(address1, 1);
1239+
origin_rewards.add_quantity(address2, 2);
1240+
origin_rewards.save_to_state(&mut state).unwrap();
1241+
let recovered_rewards = IntermediateRewardsV1::load_from_state(&state).unwrap();
1242+
assert_eq!(origin_rewards, recovered_rewards);
1243+
}
1244+
1245+
#[test]
1246+
fn drain_v1() {
1247+
let address1 = Address::random();
1248+
let address2 = Address::random();
1249+
let mut state = helpers::get_temp_state();
1250+
let mut origin_rewards = IntermediateRewardsV1::load_from_state(&state).unwrap();
1251+
origin_rewards.add_quantity(address1, 1);
1252+
origin_rewards.add_quantity(address2, 2);
1253+
origin_rewards.save_to_state(&mut state).unwrap();
1254+
let mut recovered_rewards = IntermediateRewardsV1::load_from_state(&state).unwrap();
1255+
assert_eq!(origin_rewards, recovered_rewards);
1256+
recovered_rewards.drain_current();
1257+
recovered_rewards.save_to_state(&mut state).unwrap();
1258+
let mut final_rewards = IntermediateRewardsV1::load_from_state(&state).unwrap();
1259+
assert_eq!(BTreeMap::new(), final_rewards.current);
1260+
final_rewards.drain_calculated();
1261+
assert_eq!(BTreeMap::new(), final_rewards.calculated);
1262+
}
1263+
11721264
#[test]
11731265
fn candidates_deposit_add() {
11741266
let mut state = helpers::get_temp_state();

core/src/consensus/stake/mod.rs

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ use primitives::{Bytes, H256};
3434
use rlp::{Decodable, Rlp};
3535

3636
pub use self::action_data::{Banned, Validator, Validators};
37-
use self::action_data::{Candidates, Delegation, IntermediateRewards, Jail, ReleaseResult, StakeAccount, Stakeholders};
37+
use self::action_data::{
38+
Candidates, Delegation, IntermediateRewardsV0, IntermediateRewardsV1, Jail, ReleaseResult, StakeAccount,
39+
Stakeholders,
40+
};
3841
pub use self::actions::Action;
3942
pub use self::distribute::fee_distribute;
4043
use super::ValidatorSet;
@@ -322,25 +325,57 @@ pub fn get_validators(state: &TopLevelState) -> StateResult<Validators> {
322325
}
323326

324327
pub fn add_intermediate_rewards(state: &mut TopLevelState, address: Address, reward: u64) -> StateResult<()> {
325-
let mut rewards = IntermediateRewards::load_from_state(state)?;
326-
rewards.add_quantity(address, reward);
327-
rewards.save_to_state(state)?;
328+
let metadata = state.metadata()?.expect("The metadata must exist");
329+
let era = metadata.term_params().map_or(0, |p| p.era());
330+
match era {
331+
0 => {
332+
let mut rewards = IntermediateRewardsV0::load_from_state(state)?;
333+
rewards.add_quantity(address, reward);
334+
rewards.save_to_state(state)?;
335+
}
336+
1 => {
337+
let mut rewards = IntermediateRewardsV1::load_from_state(state)?;
338+
rewards.add_quantity(address, reward);
339+
rewards.save_to_state(state)?;
340+
}
341+
_ => unimplemented!(),
342+
}
328343
Ok(())
329344
}
330345

331346
pub fn drain_previous_rewards(state: &mut TopLevelState) -> StateResult<BTreeMap<Address, u64>> {
332-
let mut rewards = IntermediateRewards::load_from_state(state)?;
347+
let mut rewards = IntermediateRewardsV0::load_from_state(state)?;
333348
let drained = rewards.drain_previous();
334349
rewards.save_to_state(state)?;
335350
Ok(drained)
336351
}
337352

338353
pub fn move_current_to_previous_intermediate_rewards(state: &mut TopLevelState) -> StateResult<()> {
339-
let mut rewards = IntermediateRewards::load_from_state(state)?;
354+
let mut rewards = IntermediateRewardsV0::load_from_state(state)?;
340355
rewards.move_current_to_previous();
341356
rewards.save_to_state(state)
342357
}
343358

359+
pub fn drain_current_rewards(state: &mut TopLevelState) -> StateResult<BTreeMap<Address, u64>> {
360+
let mut rewards = IntermediateRewardsV1::load_from_state(state)?;
361+
let drained = rewards.drain_current();
362+
rewards.save_to_state(state)?;
363+
Ok(drained)
364+
}
365+
366+
pub fn update_calculated_rewards(state: &mut TopLevelState, values: HashMap<Address, u64>) -> StateResult<()> {
367+
let mut rewards = IntermediateRewardsV1::load_from_state(state)?;
368+
rewards.update_calculated(values.into_iter().collect());
369+
rewards.save_to_state(state)
370+
}
371+
372+
pub fn drain_calculated_rewards(state: &mut TopLevelState) -> StateResult<BTreeMap<Address, u64>> {
373+
let mut rewards = IntermediateRewardsV1::load_from_state(state)?;
374+
let drained = rewards.drain_calculated();
375+
rewards.save_to_state(state)?;
376+
Ok(drained)
377+
}
378+
344379
pub fn update_validator_weights(state: &mut TopLevelState, block_author: &Address) -> StateResult<()> {
345380
let mut validators = Validators::load_from_state(state)?;
346381
validators.update_weight(block_author);

core/src/consensus/tendermint/engine.rs

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,43 @@ impl ConsensusEngine for Tendermint {
136136

137137
/// Block transformation functions, before the transactions.
138138
fn on_open_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
139+
let client = self.client().ok_or(EngineError::CannotOpenBlock)?;
140+
141+
let block_number = block.header().number();
142+
let era = client.term_common_params(block_number.into()).map_or(0, |p| p.era());
139143
let metadata = block.state().metadata()?.expect("Metadata must exist");
140-
if block.header().number() == metadata.last_term_finished_block_num() + 1 {
141-
// FIXME: on_term_open
144+
if block_number == metadata.last_term_finished_block_num() + 1 {
145+
match era {
146+
0 => {}
147+
1 => {
148+
let rewards = stake::drain_current_rewards(block.state_mut())?;
149+
let start_of_the_current_term = block_number;
150+
let start_of_the_previous_term = {
151+
let end_of_the_two_level_previous_term = client
152+
.last_term_finished_block_num((metadata.last_term_finished_block_num() - 1).into())
153+
.unwrap();
154+
155+
end_of_the_two_level_previous_term + 1
156+
};
157+
158+
let banned = stake::Banned::load_from_state(block.state())?;
159+
let start_of_the_current_term_header =
160+
encoded::Header::new(block.header().clone().rlp_bytes().to_vec());
161+
162+
let pending_rewards = calculate_pending_rewards_of_the_previous_term(
163+
&*client,
164+
&*self.validators,
165+
rewards,
166+
start_of_the_current_term,
167+
start_of_the_current_term_header,
168+
start_of_the_previous_term,
169+
&banned,
170+
)?;
171+
172+
stake::update_calculated_rewards(block.state_mut(), pending_rewards)?;
173+
}
174+
_ => unimplemented!(),
175+
}
142176
}
143177
Ok(())
144178
}
@@ -174,6 +208,7 @@ impl ConsensusEngine for Tendermint {
174208

175209
let block_author_reward = total_reward - total_min_fee + distributor.remaining_fee();
176210

211+
let era = term_common_params.map_or(0, |p| p.era());
177212
let metadata = block.state().metadata()?.expect("Metadata must exist");
178213
let term = metadata.current_term_id();
179214
let term_seconds = match term {
@@ -195,9 +230,9 @@ impl ConsensusEngine for Tendermint {
195230
return Ok(())
196231
}
197232

198-
let inactive_validators = match term {
199-
0 => Vec::new(),
200-
_ => {
233+
let inactive_validators = match (era, term) {
234+
(0, 0) => Vec::new(),
235+
(0, _) => {
201236
let rewards = stake::drain_previous_rewards(block.state_mut())?;
202237
let start_of_the_current_term = metadata.last_term_finished_block_num() + 1;
203238

@@ -240,13 +275,26 @@ impl ConsensusEngine for Tendermint {
240275
.collect();
241276
inactive_validators(&*client, start_of_the_current_term, block.header(), validators)
242277
}
278+
(1, _) => {
279+
for (address, reward) in stake::drain_calculated_rewards(block.state_mut())? {
280+
self.machine.add_balance(block, &address, reward)?;
281+
}
282+
283+
let start_of_the_current_term = metadata.last_term_finished_block_num() + 1;
284+
let validators = stake::Validators::load_from_state(block.state())?
285+
.into_iter()
286+
.map(|val| public_to_address(val.pubkey()))
287+
.collect();
288+
inactive_validators(&*client, start_of_the_current_term, block.header(), validators)
289+
}
290+
_ => unimplemented!(),
243291
};
244292

245293
stake::on_term_close(block.state_mut(), block_number, &inactive_validators)?;
246294

247295
match term {
248296
0 => {}
249-
_ => match term_common_params.expect("Term common params should exist").era() {
297+
_ => match era {
250298
0 => {}
251299
1 => block.state_mut().snapshot_term_params()?,
252300
_ => unimplemented!("It is not decided how we handle this"),

0 commit comments

Comments
 (0)