AuRa multi block reward (#290)

* Multi block reward for AuRa
* Added test
* Better error on wrong config
This commit is contained in:
rakita 2021-03-08 11:59:04 +01:00 committed by GitHub
parent dbc5f94241
commit 6f50061f0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 99 additions and 16 deletions

View File

@ -43,7 +43,7 @@ use engines::{
}; };
use error::{BlockError, Error, ErrorKind}; use error::{BlockError, Error, ErrorKind};
use ethereum_types::{Address, H256, H520, U128, U256}; use ethereum_types::{Address, H256, H520, U128, U256};
use ethjson; use ethjson::{self, uint::Uint};
use ethkey::{self, Signature}; use ethkey::{self, Signature};
use hash::keccak; use hash::keccak;
use io::{IoContext, IoHandler, IoService, TimerToken}; use io::{IoContext, IoHandler, IoService, TimerToken};
@ -80,7 +80,7 @@ pub struct AuthorityRoundParams {
/// Immediate transitions. /// Immediate transitions.
pub immediate_transitions: bool, pub immediate_transitions: bool,
/// Block reward in base units. /// Block reward in base units.
pub block_reward: U256, pub block_reward: BTreeMap<BlockNumber, U256>,
/// Block reward contract transition block. /// Block reward contract transition block.
pub block_reward_contract_transition: u64, pub block_reward_contract_transition: u64,
/// Block reward contract. /// Block reward contract.
@ -113,7 +113,33 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
validate_score_transition: p.validate_score_transition.map_or(0, Into::into), validate_score_transition: p.validate_score_transition.map_or(0, Into::into),
validate_step_transition: p.validate_step_transition.map_or(0, Into::into), validate_step_transition: p.validate_step_transition.map_or(0, Into::into),
immediate_transitions: p.immediate_transitions.unwrap_or(false), immediate_transitions: p.immediate_transitions.unwrap_or(false),
block_reward: p.block_reward.map_or_else(Default::default, Into::into), block_reward: p.block_reward.map_or_else(
|| {
let mut ret = BTreeMap::new();
ret.insert(0, U256::zero());
ret
},
|reward| match reward {
ethjson::spec::BlockReward::Single(reward) => {
let mut ret = BTreeMap::new();
ret.insert(0, reward.into());
ret
}
ethjson::spec::BlockReward::Multi(mut multi) => {
if multi.is_empty() {
panic!("No block rewards are found in config");
}
// add block reward from genesis and put reward to zero.
multi
.entry(Uint(U256::from(0)))
.or_insert(Uint(U256::from(0)));
multi
.into_iter()
.map(|(block, reward)| (block.into(), reward.into()))
.collect()
}
},
),
block_reward_contract_transition: p block_reward_contract_transition: p
.block_reward_contract_transition .block_reward_contract_transition
.map_or(0, Into::into), .map_or(0, Into::into),
@ -457,7 +483,7 @@ pub struct AuthorityRound {
empty_steps: Mutex<BTreeSet<EmptyStep>>, empty_steps: Mutex<BTreeSet<EmptyStep>>,
epoch_manager: Mutex<EpochManager>, epoch_manager: Mutex<EpochManager>,
immediate_transitions: bool, immediate_transitions: bool,
block_reward: U256, block_reward: BTreeMap<BlockNumber, U256>,
block_reward_contract_transition: u64, block_reward_contract_transition: u64,
block_reward_contract: Option<BlockRewardContract>, block_reward_contract: Option<BlockRewardContract>,
maximum_uncle_count_transition: u64, maximum_uncle_count_transition: u64,
@ -1374,10 +1400,11 @@ impl Engine<EthereumMachine> for AuthorityRound {
} }
let author = *block.header.author(); let author = *block.header.author();
let number = block.header.number();
beneficiaries.push((author, RewardKind::Author)); beneficiaries.push((author, RewardKind::Author));
let rewards: Vec<_> = match self.block_reward_contract { let rewards: Vec<_> = match self.block_reward_contract {
Some(ref c) if block.header.number() >= self.block_reward_contract_transition => { Some(ref c) if number >= self.block_reward_contract_transition => {
let mut call = super::default_system_or_code_call(&self.machine, block); let mut call = super::default_system_or_code_call(&self.machine, block);
let rewards = c.reward(&beneficiaries, &mut call)?; let rewards = c.reward(&beneficiaries, &mut call)?;
@ -1386,10 +1413,18 @@ impl Engine<EthereumMachine> for AuthorityRound {
.map(|(author, amount)| (author, RewardKind::External, amount)) .map(|(author, amount)| (author, RewardKind::External, amount))
.collect() .collect()
} }
_ => beneficiaries _ => {
.into_iter() let (_, reward) = self.block_reward.iter()
.map(|(author, reward_kind)| (author, reward_kind, self.block_reward)) .rev()
.collect(), .find(|&(block, _)| *block <= number)
.expect("Current block's reward is not found; this indicates a chain config error; qed");
let reward = *reward;
beneficiaries
.into_iter()
.map(|(author, reward_kind)| (author, reward_kind, reward))
.collect()
}
}; };
block_reward::apply_block_rewards(&rewards, block, &self.machine) block_reward::apply_block_rewards(&rewards, block, &self.machine)

View File

@ -17,7 +17,7 @@
use std::{cmp, collections::BTreeMap, path::Path, sync::Arc}; use std::{cmp, collections::BTreeMap, path::Path, sync::Arc};
use ethereum_types::{H256, H64, U256}; use ethereum_types::{H256, H64, U256};
use ethjson; use ethjson::{self, uint::Uint};
use hash::KECCAK_EMPTY_LIST_RLP; use hash::KECCAK_EMPTY_LIST_RLP;
use rlp::Rlp; use rlp::Rlp;
use types::{ use types::{
@ -145,10 +145,19 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
ret.insert(0, reward.into()); ret.insert(0, reward.into());
ret ret
} }
ethjson::spec::BlockReward::Multi(multi) => multi ethjson::spec::BlockReward::Multi(mut multi) => {
.into_iter() if multi.is_empty() {
.map(|(block, reward)| (block.into(), reward.into())) panic!("No block rewards are found in config");
.collect(), }
// add block reward from genesis and put reward to zero.
multi
.entry(Uint(U256::from(0)))
.or_insert(Uint(U256::from(0)));
multi
.into_iter()
.map(|(block, reward)| (block.into(), reward.into()))
.collect()
}
}, },
), ),
expip2_transition: p.expip2_transition.map_or(u64::max_value(), Into::into), expip2_transition: p.expip2_transition.map_or(u64::max_value(), Into::into),

View File

@ -16,7 +16,7 @@
//! Authority params deserialization. //! Authority params deserialization.
use super::ValidatorSet; use super::{BlockReward, ValidatorSet};
use bytes::Bytes; use bytes::Bytes;
use hash::Address; use hash::Address;
use uint::Uint; use uint::Uint;
@ -40,7 +40,7 @@ pub struct AuthorityRoundParams {
/// Whether transitions should be immediate. /// Whether transitions should be immediate.
pub immediate_transitions: Option<bool>, pub immediate_transitions: Option<bool>,
/// Reward per block in wei. /// Reward per block in wei.
pub block_reward: Option<Uint>, pub block_reward: Option<BlockReward>,
/// Block at which the block reward contract should start being used. /// Block at which the block reward contract should start being used.
pub block_reward_contract_transition: Option<Uint>, pub block_reward_contract_transition: Option<Uint>,
/// Block reward contract address (setting the block reward contract /// Block reward contract address (setting the block reward contract
@ -70,6 +70,9 @@ pub struct AuthorityRound {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::collections::BTreeMap;
use super::BlockReward;
use ethereum_types::{H160, U256}; use ethereum_types::{H160, U256};
use hash::Address; use hash::Address;
use serde_json; use serde_json;
@ -110,5 +113,41 @@ mod tests {
deserialized.params.maximum_uncle_count, deserialized.params.maximum_uncle_count,
Some(Uint(5.into())) Some(Uint(5.into()))
); );
assert_eq!(
deserialized.params.block_reward,
Some(BlockReward::Single(Uint(5000000.into())))
)
}
#[test]
fn authority_round_deserialization_multi_block() {
let s = r#"{
"params": {
"stepDuration": "0x02",
"validators": {
"contract" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b"
},
"blockReward": {
"0": 5000000,
"100": 150
}
}
}"#;
let deserialized: AuthorityRound = serde_json::from_str(s).unwrap();
assert_eq!(deserialized.params.step_duration, Uint(U256::from(0x02)));
assert_eq!(
deserialized.params.validators,
ValidatorSet::Contract(Address(H160::from(
"0xc6d9d2cd449a754c494264e1809c50e34d64562b"
)))
);
let mut rewards: BTreeMap<Uint, Uint> = BTreeMap::new();
rewards.insert(Uint(U256::from(0)), Uint(U256::from(5000000)));
rewards.insert(Uint(U256::from(100)), Uint(U256::from(150)));
assert_eq!(
deserialized.params.block_reward,
Some(BlockReward::Multi(rewards))
);
} }
} }