Configuration map of block reward contract addresses (#10875)

* configuration map of block reward contract addresses

* Revert test module updates.

* re-added block reward transition map tests and docs

* review comment
This commit is contained in:
Vladimir Komendantskiy 2019-08-22 09:45:24 +01:00 committed by David
parent 175051bac7
commit efb390eb60
2 changed files with 134 additions and 30 deletions

View File

@ -87,10 +87,8 @@ pub struct AuthorityRoundParams {
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: U256,
/// Block reward contract transition block. /// Block reward contract addresses with their associated starting block numbers.
pub block_reward_contract_transition: u64, pub block_reward_contract_transitions: BTreeMap<u64, BlockRewardContract>,
/// Block reward contract.
pub block_reward_contract: Option<BlockRewardContract>,
/// Number of accepted uncles transition block. /// Number of accepted uncles transition block.
pub maximum_uncle_count_transition: u64, pub maximum_uncle_count_transition: u64,
/// Number of accepted uncles. /// Number of accepted uncles.
@ -114,6 +112,30 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
step_duration_usize = U16_MAX; step_duration_usize = U16_MAX;
warn!(target: "engine", "step_duration is too high ({}), setting it to {}", step_duration_usize, U16_MAX); warn!(target: "engine", "step_duration is too high ({}), setting it to {}", step_duration_usize, U16_MAX);
} }
let transition_block_num = p.block_reward_contract_transition.map_or(0, Into::into);
let mut br_transitions: BTreeMap<_, _> = p.block_reward_contract_transitions
.unwrap_or_default()
.into_iter()
.map(|(block_num, address)|
(block_num.into(), BlockRewardContract::new_from_address(address.into())))
.collect();
if (p.block_reward_contract_code.is_some() || p.block_reward_contract_address.is_some()) &&
br_transitions.keys().next().map_or(false, |&block_num| block_num <= transition_block_num)
{
let s = "blockRewardContractTransition";
panic!("{} should be less than any of the keys in {}s", s, s);
}
if let Some(code) = p.block_reward_contract_code {
br_transitions.insert(
transition_block_num,
BlockRewardContract::new_from_code(Arc::new(code.into()))
);
} else if let Some(address) = p.block_reward_contract_address {
br_transitions.insert(
transition_block_num,
BlockRewardContract::new_from_address(address.into())
);
}
AuthorityRoundParams { AuthorityRoundParams {
step_duration: step_duration_usize as u16, step_duration: step_duration_usize as u16,
validators: new_validator_set(p.validators), validators: new_validator_set(p.validators),
@ -122,12 +144,7 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
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(Default::default, Into::into),
block_reward_contract_transition: p.block_reward_contract_transition.map_or(0, Into::into), block_reward_contract_transitions: br_transitions,
block_reward_contract: match (p.block_reward_contract_code, p.block_reward_contract_address) {
(Some(code), _) => Some(BlockRewardContract::new_from_code(Arc::new(code.into()))),
(_, Some(address)) => Some(BlockRewardContract::new_from_address(address.into())),
(None, None) => None,
},
maximum_uncle_count_transition: p.maximum_uncle_count_transition.map_or(0, Into::into), maximum_uncle_count_transition: p.maximum_uncle_count_transition.map_or(0, Into::into),
maximum_uncle_count: p.maximum_uncle_count.map_or(0, Into::into), maximum_uncle_count: p.maximum_uncle_count.map_or(0, Into::into),
empty_steps_transition: p.empty_steps_transition.map_or(u64::max_value(), |n| ::std::cmp::max(n.into(), 1)), empty_steps_transition: p.empty_steps_transition.map_or(u64::max_value(), |n| ::std::cmp::max(n.into(), 1)),
@ -454,8 +471,7 @@ pub struct AuthorityRound {
epoch_manager: Mutex<EpochManager>, epoch_manager: Mutex<EpochManager>,
immediate_transitions: bool, immediate_transitions: bool,
block_reward: U256, block_reward: U256,
block_reward_contract_transition: u64, block_reward_contract_transitions: BTreeMap<u64, BlockRewardContract>,
block_reward_contract: Option<BlockRewardContract>,
maximum_uncle_count_transition: u64, maximum_uncle_count_transition: u64,
maximum_uncle_count: usize, maximum_uncle_count: usize,
empty_steps_transition: u64, empty_steps_transition: u64,
@ -724,8 +740,7 @@ impl AuthorityRound {
epoch_manager: Mutex::new(EpochManager::blank(our_params.two_thirds_majority_transition)), epoch_manager: Mutex::new(EpochManager::blank(our_params.two_thirds_majority_transition)),
immediate_transitions: our_params.immediate_transitions, immediate_transitions: our_params.immediate_transitions,
block_reward: our_params.block_reward, block_reward: our_params.block_reward,
block_reward_contract_transition: our_params.block_reward_contract_transition, block_reward_contract_transitions: our_params.block_reward_contract_transitions,
block_reward_contract: our_params.block_reward_contract,
maximum_uncle_count_transition: our_params.maximum_uncle_count_transition, maximum_uncle_count_transition: our_params.maximum_uncle_count_transition,
maximum_uncle_count: our_params.maximum_uncle_count, maximum_uncle_count: our_params.maximum_uncle_count,
empty_steps_transition: our_params.empty_steps_transition, empty_steps_transition: our_params.empty_steps_transition,
@ -1295,16 +1310,16 @@ impl Engine for AuthorityRound {
let author = *block.header.author(); let author = *block.header.author();
beneficiaries.push((author, RewardKind::Author)); beneficiaries.push((author, RewardKind::Author));
let rewards: Vec<_> = match self.block_reward_contract { let block_reward_contract_transition = self
Some(ref c) if block.header.number() >= self.block_reward_contract_transition => { .block_reward_contract_transitions
.range(..=block.header.number())
.last();
let rewards: Vec<_> = if let Some((_, contract)) = block_reward_contract_transition {
let mut call = engine::default_system_or_code_call(&self.machine, block); let mut call = engine::default_system_or_code_call(&self.machine, block);
let rewards = contract.reward(beneficiaries, &mut call)?;
let rewards = c.reward(beneficiaries, &mut call)?;
rewards.into_iter().map(|(author, amount)| (author, RewardKind::External, amount)).collect() rewards.into_iter().map(|(author, amount)| (author, RewardKind::External, amount)).collect()
}, } else {
_ => {
beneficiaries.into_iter().map(|(author, reward_kind)| (author, reward_kind, self.block_reward)).collect() beneficiaries.into_iter().map(|(author, reward_kind)| (author, reward_kind, self.block_reward)).collect()
},
}; };
block_reward::apply_block_rewards(&rewards, block, &self.machine) block_reward::apply_block_rewards(&rewards, block, &self.machine)
@ -1645,6 +1660,7 @@ impl Engine for AuthorityRound {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
use hash::keccak; use hash::keccak;
@ -1665,9 +1681,11 @@ mod tests {
}; };
use crate::spec::{Spec, self}; use crate::spec::{Spec, self};
use engine::Engine; use engine::Engine;
use engines::block_reward::BlockRewardContract;
use engines::validator_set::{TestSet, SimpleList}; use engines::validator_set::{TestSet, SimpleList};
use super::{AuthorityRoundParams, AuthorityRound, EmptyStep, SealedEmptyStep, calculate_score}; use super::{AuthorityRoundParams, AuthorityRound, EmptyStep, SealedEmptyStep, calculate_score};
use machine::Machine; use machine::Machine;
use ethjson;
fn build_aura<F>(f: F) -> Arc<AuthorityRound> where fn build_aura<F>(f: F) -> Arc<AuthorityRound> where
F: FnOnce(&mut AuthorityRoundParams), F: FnOnce(&mut AuthorityRoundParams),
@ -1684,8 +1702,7 @@ mod tests {
empty_steps_transition: u64::max_value(), empty_steps_transition: u64::max_value(),
maximum_empty_steps: 0, maximum_empty_steps: 0,
block_reward: Default::default(), block_reward: Default::default(),
block_reward_contract_transition: 0, block_reward_contract_transitions: Default::default(),
block_reward_contract: Default::default(),
strict_empty_steps_transition: 0, strict_empty_steps_transition: 0,
two_thirds_majority_transition: 0, two_thirds_majority_transition: 0,
}; };
@ -2452,4 +2469,55 @@ mod tests {
set_empty_steps_seal(&mut header, step, &signature, &empty_steps); set_empty_steps_seal(&mut header, step, &signature, &empty_steps);
assert_eq!(engine.verify_block_family(&header, &parent).unwrap(), ()); assert_eq!(engine.verify_block_family(&header, &parent).unwrap(), ());
} }
#[test]
fn should_collect_block_reward_transitions() {
let config = r#"{
"params": {
"stepDuration": "5",
"validators": {
"list" : ["0x1000000000000000000000000000000000000001"]
},
"blockRewardContractTransition": "0",
"blockRewardContractAddress": "0x2000000000000000000000000000000000000002",
"blockRewardContractTransitions": {
"7": "0x3000000000000000000000000000000000000003",
"42": "0x4000000000000000000000000000000000000004"
}
}
}"#;
let deserialized: ethjson::spec::AuthorityRound = serde_json::from_str(config).unwrap();
let params = AuthorityRoundParams::from(deserialized.params);
for ((block_num1, address1), (block_num2, address2)) in
params.block_reward_contract_transitions.iter().zip(
[(0u64, BlockRewardContract::new_from_address(Address::from_str("2000000000000000000000000000000000000002").unwrap())),
(7u64, BlockRewardContract::new_from_address(Address::from_str("3000000000000000000000000000000000000003").unwrap())),
(42u64, BlockRewardContract::new_from_address(Address::from_str("4000000000000000000000000000000000000004").unwrap())),
].iter())
{
assert_eq!(block_num1, block_num2);
assert_eq!(address1, address2);
}
}
#[test]
#[should_panic(expected="blockRewardContractTransition should be less than any of the keys in blockRewardContractTransitions")]
fn should_reject_out_of_order_block_reward_transition() {
let config = r#"{
"params": {
"stepDuration": "5",
"validators": {
"list" : ["0x1000000000000000000000000000000000000001"]
},
"blockRewardContractTransition": "7",
"blockRewardContractAddress": "0x2000000000000000000000000000000000000002",
"blockRewardContractTransitions": {
"0": "0x3000000000000000000000000000000000000003",
"42": "0x4000000000000000000000000000000000000004"
}
}
}"#;
let deserialized: ethjson::spec::AuthorityRound = serde_json::from_str(config).unwrap();
AuthorityRoundParams::from(deserialized.params);
}
} }

View File

@ -14,8 +14,31 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>. // along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
//! Authority params deserialization. //! Authority Round parameter deserialization.
//!
//! Here is an example of input parameters where the step duration is constant at 5 seconds, the set
//! of validators is decided by the contract at address `0x10..01` starting from block 0, and where
//! the address of the contract that computes block rewards is set to `0x20..02` for blocks 0
//! through 41 and to `0x30.03` for all blocks starting from block 42.
//!
//! ```ignore
//! "params": {
//! "stepDuration": "5",
//! "validators": {
//! "multi": {
//! "0": {
//! "contract": "0x1000000000000000000000000000000000000001"
//! }
//! }
//! },
//! "blockRewardContractTransitions": {
//! "0": "0x2000000000000000000000000000000000000002",
//! "42": "0x3000000000000000000000000000000000000003"
//! }
//! }
//! ```
use std::collections::BTreeMap;
use hash::Address; use hash::Address;
use uint::Uint; use uint::Uint;
use bytes::Bytes; use bytes::Bytes;
@ -41,11 +64,24 @@ pub struct AuthorityRoundParams {
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<Uint>,
/// Block at which the block reward contract should start being used. /// Block at which the block reward contract should start being used. This option allows one to
/// add a single block reward contract transition and is compatible with the multiple address
/// option `block_reward_contract_transitions` below.
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 which overrides the `block_reward` setting. This option allows
/// overrides the static block reward definition). /// one to add a single block reward contract address and is compatible with the multiple
/// address option `block_reward_contract_transitions` below.
pub block_reward_contract_address: Option<Address>, pub block_reward_contract_address: Option<Address>,
/// Block reward contract addresses with their associated starting block numbers.
///
/// Setting the block reward contract overrides `block_reward`. If the single block reward
/// contract address is also present then it is added into the map at the block number stored in
/// `block_reward_contract_transition` or 0 if that block number is not provided. Therefore both
/// a single block reward contract transition and a map of reward contract transitions can be
/// used simulataneously in the same configuration. In such a case the code requires that the
/// block number of the single transition is strictly less than any of the block numbers in the
/// map.
pub block_reward_contract_transitions: Option<BTreeMap<Uint, Address>>,
/// Block reward code. This overrides the block reward contract address. /// Block reward code. This overrides the block reward contract address.
pub block_reward_contract_code: Option<Bytes>, pub block_reward_contract_code: Option<Bytes>,
/// Block at which maximum uncle count should be considered. /// Block at which maximum uncle count should be considered.