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,
/// Block reward in base units.
pub block_reward: U256,
/// Block reward contract transition block.
pub block_reward_contract_transition: u64,
/// Block reward contract.
pub block_reward_contract: Option<BlockRewardContract>,
/// Block reward contract addresses with their associated starting block numbers.
pub block_reward_contract_transitions: BTreeMap<u64, BlockRewardContract>,
/// Number of accepted uncles transition block.
pub maximum_uncle_count_transition: u64,
/// Number of accepted uncles.
@ -114,6 +112,30 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
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 {
step_duration: step_duration_usize as u16,
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),
immediate_transitions: p.immediate_transitions.unwrap_or(false),
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: 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,
},
block_reward_contract_transitions: br_transitions,
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),
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>,
immediate_transitions: bool,
block_reward: U256,
block_reward_contract_transition: u64,
block_reward_contract: Option<BlockRewardContract>,
block_reward_contract_transitions: BTreeMap<u64, BlockRewardContract>,
maximum_uncle_count_transition: u64,
maximum_uncle_count: usize,
empty_steps_transition: u64,
@ -724,8 +740,7 @@ impl AuthorityRound {
epoch_manager: Mutex::new(EpochManager::blank(our_params.two_thirds_majority_transition)),
immediate_transitions: our_params.immediate_transitions,
block_reward: our_params.block_reward,
block_reward_contract_transition: our_params.block_reward_contract_transition,
block_reward_contract: our_params.block_reward_contract,
block_reward_contract_transitions: our_params.block_reward_contract_transitions,
maximum_uncle_count_transition: our_params.maximum_uncle_count_transition,
maximum_uncle_count: our_params.maximum_uncle_count,
empty_steps_transition: our_params.empty_steps_transition,
@ -1295,16 +1310,16 @@ impl Engine for AuthorityRound {
let author = *block.header.author();
beneficiaries.push((author, RewardKind::Author));
let rewards: Vec<_> = match self.block_reward_contract {
Some(ref c) if block.header.number() >= self.block_reward_contract_transition => {
let block_reward_contract_transition = self
.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 rewards = c.reward(beneficiaries, &mut call)?;
let rewards = contract.reward(beneficiaries, &mut call)?;
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()
},
};
block_reward::apply_block_rewards(&rewards, block, &self.machine)
@ -1645,6 +1660,7 @@ impl Engine for AuthorityRound {
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use std::str::FromStr;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
use hash::keccak;
@ -1665,9 +1681,11 @@ mod tests {
};
use crate::spec::{Spec, self};
use engine::Engine;
use engines::block_reward::BlockRewardContract;
use engines::validator_set::{TestSet, SimpleList};
use super::{AuthorityRoundParams, AuthorityRound, EmptyStep, SealedEmptyStep, calculate_score};
use machine::Machine;
use ethjson;
fn build_aura<F>(f: F) -> Arc<AuthorityRound> where
F: FnOnce(&mut AuthorityRoundParams),
@ -1684,8 +1702,7 @@ mod tests {
empty_steps_transition: u64::max_value(),
maximum_empty_steps: 0,
block_reward: Default::default(),
block_reward_contract_transition: 0,
block_reward_contract: Default::default(),
block_reward_contract_transitions: Default::default(),
strict_empty_steps_transition: 0,
two_thirds_majority_transition: 0,
};
@ -2452,4 +2469,55 @@ mod tests {
set_empty_steps_seal(&mut header, step, &signature, &empty_steps);
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
// 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 uint::Uint;
use bytes::Bytes;
@ -41,11 +64,24 @@ pub struct AuthorityRoundParams {
pub immediate_transitions: Option<bool>,
/// Reward per block in wei.
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>,
/// Block reward contract address (setting the block reward contract
/// overrides the static block reward definition).
/// Block reward contract address which overrides the `block_reward` setting. This option allows
/// 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>,
/// 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.
pub block_reward_contract_code: Option<Bytes>,
/// Block at which maximum uncle count should be considered.