Add block reward contract config to ethash and allow off-chain contracts (#9312)
This adds block reward contract config to ethash. A new config `blockRewardContractCode` is also added to both Aura and ethash. When specified, it will execute the code directly and overrides any `blockRewardContractAddress` config. Having this `blockRewardContractCode` config allows chains to deploy hard fork by simply replacing the current config value, without the need from us to support any `multi` block reward scheme.
This commit is contained in:
parent
1073d56245
commit
74ce0f738e
@ -100,7 +100,11 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
||||
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: p.block_reward_contract_address.map(BlockRewardContract::new),
|
||||
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: 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)),
|
||||
@ -1043,7 +1047,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
|
||||
/// Apply the block reward on finalisation of the block.
|
||||
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
|
||||
let mut benefactors = Vec::new();
|
||||
let mut beneficiaries = Vec::new();
|
||||
if block.header().number() >= self.empty_steps_transition {
|
||||
let empty_steps = if block.header().seal().is_empty() {
|
||||
// this is a new block, calculate rewards based on the empty steps messages we have accumulated
|
||||
@ -1069,32 +1073,22 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
|
||||
for empty_step in empty_steps {
|
||||
let author = empty_step.author()?;
|
||||
benefactors.push((author, RewardKind::EmptyStep));
|
||||
beneficiaries.push((author, RewardKind::EmptyStep));
|
||||
}
|
||||
}
|
||||
|
||||
let author = *block.header().author();
|
||||
benefactors.push((author, RewardKind::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 => {
|
||||
// NOTE: this logic should be moved to a function when another
|
||||
// engine needs support for block reward contract.
|
||||
let mut call = |to, data| {
|
||||
let result = self.machine.execute_as_system(
|
||||
block,
|
||||
to,
|
||||
U256::max_value(), // unbounded gas? maybe make configurable.
|
||||
Some(data),
|
||||
);
|
||||
result.map_err(|e| format!("{}", e))
|
||||
};
|
||||
let mut call = super::default_system_or_code_call(&self.machine, block);
|
||||
|
||||
let rewards = c.reward(&benefactors, &mut call)?;
|
||||
let rewards = c.reward(&beneficiaries, &mut call)?;
|
||||
rewards.into_iter().map(|(author, amount)| (author, RewardKind::External, amount)).collect()
|
||||
},
|
||||
_ => {
|
||||
benefactors.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()
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -21,33 +21,48 @@ use ethabi;
|
||||
use ethabi::ParamType;
|
||||
use ethereum_types::{H160, Address, U256};
|
||||
|
||||
use std::sync::Arc;
|
||||
use hash::keccak;
|
||||
use error::Error;
|
||||
use machine::WithRewards;
|
||||
use parity_machine::{Machine, WithBalances};
|
||||
use trace;
|
||||
use super::SystemCall;
|
||||
use types::BlockNumber;
|
||||
use super::{SystemOrCodeCall, SystemOrCodeCallKind};
|
||||
|
||||
use_contract!(block_reward_contract, "BlockReward", "res/contracts/block_reward.json");
|
||||
|
||||
/// The kind of block reward.
|
||||
/// Depending on the consensus engine the allocated block reward might have
|
||||
/// different semantics which could lead e.g. to different reward values.
|
||||
#[repr(u8)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum RewardKind {
|
||||
/// Reward attributed to the block author.
|
||||
Author = 0,
|
||||
/// Reward attributed to the block uncle(s).
|
||||
Uncle = 1,
|
||||
Author,
|
||||
/// Reward attributed to the author(s) of empty step(s) included in the block (AuthorityRound engine).
|
||||
EmptyStep = 2,
|
||||
EmptyStep,
|
||||
/// Reward attributed by an external protocol (e.g. block reward contract).
|
||||
External = 3,
|
||||
External,
|
||||
/// Reward attributed to the block uncle(s) with given difference.
|
||||
Uncle(u8),
|
||||
}
|
||||
|
||||
impl RewardKind {
|
||||
/// Create `RewardKind::Uncle` from given current block number and uncle block number.
|
||||
pub fn uncle(number: BlockNumber, uncle: BlockNumber) -> Self {
|
||||
RewardKind::Uncle(if number > uncle && number - uncle <= u8::max_value().into() { (number - uncle) as u8 } else { 0 })
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RewardKind> for u16 {
|
||||
fn from(reward_kind: RewardKind) -> Self {
|
||||
reward_kind as u16
|
||||
match reward_kind {
|
||||
RewardKind::Author => 0,
|
||||
RewardKind::EmptyStep => 2,
|
||||
RewardKind::External => 3,
|
||||
|
||||
RewardKind::Uncle(depth) => 100 + depth as u16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +70,7 @@ impl Into<trace::RewardType> for RewardKind {
|
||||
fn into(self) -> trace::RewardType {
|
||||
match self {
|
||||
RewardKind::Author => trace::RewardType::Block,
|
||||
RewardKind::Uncle => trace::RewardType::Uncle,
|
||||
RewardKind::Uncle(_) => trace::RewardType::Uncle,
|
||||
RewardKind::EmptyStep => trace::RewardType::EmptyStep,
|
||||
RewardKind::External => trace::RewardType::External,
|
||||
}
|
||||
@ -63,38 +78,50 @@ impl Into<trace::RewardType> for RewardKind {
|
||||
}
|
||||
|
||||
/// A client for the block reward contract.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct BlockRewardContract {
|
||||
/// Address of the contract.
|
||||
address: Address,
|
||||
kind: SystemOrCodeCallKind,
|
||||
block_reward_contract: block_reward_contract::BlockReward,
|
||||
}
|
||||
|
||||
impl BlockRewardContract {
|
||||
/// Create a new block reward contract client targeting the given address.
|
||||
pub fn new(address: Address) -> BlockRewardContract {
|
||||
/// Create a new block reward contract client targeting the system call kind.
|
||||
pub fn new(kind: SystemOrCodeCallKind) -> BlockRewardContract {
|
||||
BlockRewardContract {
|
||||
address,
|
||||
kind,
|
||||
block_reward_contract: block_reward_contract::BlockReward::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls the block reward contract with the given benefactors list (and associated reward kind)
|
||||
/// Create a new block reward contract client targeting the contract address.
|
||||
pub fn new_from_address(address: Address) -> BlockRewardContract {
|
||||
Self::new(SystemOrCodeCallKind::Address(address))
|
||||
}
|
||||
|
||||
/// Create a new block reward contract client targeting the given code.
|
||||
pub fn new_from_code(code: Arc<Vec<u8>>) -> BlockRewardContract {
|
||||
let code_hash = keccak(&code[..]);
|
||||
|
||||
Self::new(SystemOrCodeCallKind::Code(code, code_hash))
|
||||
}
|
||||
|
||||
/// Calls the block reward contract with the given beneficiaries list (and associated reward kind)
|
||||
/// and returns the reward allocation (address - value). The block reward contract *must* be
|
||||
/// called by the system address so the `caller` must ensure that (e.g. using
|
||||
/// `machine.execute_as_system`).
|
||||
pub fn reward(
|
||||
&self,
|
||||
benefactors: &[(Address, RewardKind)],
|
||||
caller: &mut SystemCall,
|
||||
beneficiaries: &[(Address, RewardKind)],
|
||||
caller: &mut SystemOrCodeCall,
|
||||
) -> Result<Vec<(Address, U256)>, Error> {
|
||||
let reward = self.block_reward_contract.functions().reward();
|
||||
|
||||
let input = reward.input(
|
||||
benefactors.iter().map(|&(address, _)| H160::from(address)),
|
||||
benefactors.iter().map(|&(_, ref reward_kind)| u16::from(*reward_kind)),
|
||||
beneficiaries.iter().map(|&(address, _)| H160::from(address)),
|
||||
beneficiaries.iter().map(|&(_, ref reward_kind)| u16::from(*reward_kind)),
|
||||
);
|
||||
|
||||
let output = caller(self.address, input)
|
||||
let output = caller(self.kind.clone(), input)
|
||||
.map_err(Into::into)
|
||||
.map_err(::engines::EngineError::FailedSystemCall)?;
|
||||
|
||||
@ -127,7 +154,7 @@ impl BlockRewardContract {
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies the given block rewards, i.e. adds the given balance to each benefactors' address.
|
||||
/// Applies the given block rewards, i.e. adds the given balance to each beneficiary' address.
|
||||
/// If tracing is enabled the operations are recorded.
|
||||
pub fn apply_block_rewards<M: Machine + WithBalances + WithRewards>(
|
||||
rewards: &[(Address, RewardKind, U256)],
|
||||
@ -149,6 +176,7 @@ mod test {
|
||||
use spec::Spec;
|
||||
use test_helpers::generate_dummy_client_with_spec_and_accounts;
|
||||
|
||||
use engines::SystemOrCodeCallKind;
|
||||
use super::{BlockRewardContract, RewardKind};
|
||||
|
||||
#[test]
|
||||
@ -161,7 +189,7 @@ mod test {
|
||||
let machine = Spec::new_test_machine();
|
||||
|
||||
// the spec has a block reward contract defined at the given address
|
||||
let block_reward_contract = BlockRewardContract::new(
|
||||
let block_reward_contract = BlockRewardContract::new_from_address(
|
||||
"0000000000000000000000000000000000000042".into(),
|
||||
);
|
||||
|
||||
@ -172,30 +200,35 @@ mod test {
|
||||
vec![],
|
||||
).unwrap();
|
||||
|
||||
let result = machine.execute_as_system(
|
||||
let result = match to {
|
||||
SystemOrCodeCallKind::Address(to) => {
|
||||
machine.execute_as_system(
|
||||
block.block_mut(),
|
||||
to,
|
||||
U256::max_value(),
|
||||
Some(data),
|
||||
);
|
||||
)
|
||||
},
|
||||
_ => panic!("Test reward contract is created by an address, we never reach this branch."),
|
||||
};
|
||||
|
||||
result.map_err(|e| format!("{}", e))
|
||||
};
|
||||
|
||||
// if no benefactors are given no rewards are attributed
|
||||
// if no beneficiaries are given no rewards are attributed
|
||||
assert!(block_reward_contract.reward(&vec![], &mut call).unwrap().is_empty());
|
||||
|
||||
// the contract rewards (1000 + kind) for each benefactor
|
||||
let benefactors = vec![
|
||||
let beneficiaries = vec![
|
||||
("0000000000000000000000000000000000000033".into(), RewardKind::Author),
|
||||
("0000000000000000000000000000000000000034".into(), RewardKind::Uncle),
|
||||
("0000000000000000000000000000000000000034".into(), RewardKind::Uncle(1)),
|
||||
("0000000000000000000000000000000000000035".into(), RewardKind::EmptyStep),
|
||||
];
|
||||
|
||||
let rewards = block_reward_contract.reward(&benefactors, &mut call).unwrap();
|
||||
let rewards = block_reward_contract.reward(&beneficiaries, &mut call).unwrap();
|
||||
let expected = vec![
|
||||
("0000000000000000000000000000000000000033".into(), U256::from(1000)),
|
||||
("0000000000000000000000000000000000000034".into(), U256::from(1000 + 1)),
|
||||
("0000000000000000000000000000000000000034".into(), U256::from(1000 + 101)),
|
||||
("0000000000000000000000000000000000000035".into(), U256::from(1000 + 2)),
|
||||
];
|
||||
|
||||
|
@ -133,6 +133,46 @@ pub enum Seal {
|
||||
/// A system-calling closure. Enacts calls on a block's state from the system address.
|
||||
pub type SystemCall<'a> = FnMut(Address, Vec<u8>) -> Result<Vec<u8>, String> + 'a;
|
||||
|
||||
/// A system-calling closure. Enacts calls on a block's state with code either from an on-chain contract, or hard-coded EVM or WASM (if enabled on-chain) codes.
|
||||
pub type SystemOrCodeCall<'a> = FnMut(SystemOrCodeCallKind, Vec<u8>) -> Result<Vec<u8>, String> + 'a;
|
||||
|
||||
/// Kind of SystemOrCodeCall, this is either an on-chain address, or code.
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub enum SystemOrCodeCallKind {
|
||||
/// On-chain address.
|
||||
Address(Address),
|
||||
/// Hard-coded code.
|
||||
Code(Arc<Vec<u8>>, H256),
|
||||
}
|
||||
|
||||
/// Default SystemOrCodeCall implementation.
|
||||
pub fn default_system_or_code_call<'a>(machine: &'a ::machine::EthereumMachine, block: &'a mut ::block::ExecutedBlock) -> impl FnMut(SystemOrCodeCallKind, Vec<u8>) -> Result<Vec<u8>, String> + 'a {
|
||||
move |to, data| {
|
||||
let result = match to {
|
||||
SystemOrCodeCallKind::Address(address) => {
|
||||
machine.execute_as_system(
|
||||
block,
|
||||
address,
|
||||
U256::max_value(),
|
||||
Some(data),
|
||||
)
|
||||
},
|
||||
SystemOrCodeCallKind::Code(code, code_hash) => {
|
||||
machine.execute_code_as_system(
|
||||
block,
|
||||
None,
|
||||
Some(code),
|
||||
Some(code_hash),
|
||||
U256::max_value(),
|
||||
Some(data),
|
||||
)
|
||||
},
|
||||
};
|
||||
|
||||
result.map_err(|e| format!("{}", e))
|
||||
}
|
||||
}
|
||||
|
||||
/// Type alias for a function we can get headers by hash through.
|
||||
pub type Headers<'a, H> = Fn(H256) -> Option<H> + 'a;
|
||||
|
||||
|
@ -89,7 +89,7 @@ impl<M: WithBalances + WithRewards> Engine<M> for NullEngine<M>
|
||||
for u in LiveBlock::uncles(&*block) {
|
||||
let uncle_author = u.author();
|
||||
let result_uncle_reward = (reward * U256::from(8 + u.number() - number)).shr(3);
|
||||
rewards.push((*uncle_author, RewardKind::Uncle, result_uncle_reward));
|
||||
rewards.push((*uncle_author, RewardKind::uncle(number, u.number()), result_uncle_reward));
|
||||
}
|
||||
|
||||
block_reward::apply_block_rewards(&rewards, block, &self.machine)
|
||||
|
@ -19,7 +19,7 @@ use std::cmp;
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
use hash::{KECCAK_EMPTY_LIST_RLP};
|
||||
use engines::block_reward::{self, RewardKind};
|
||||
use engines::block_reward::{self, BlockRewardContract, RewardKind};
|
||||
use ethash::{self, quick_get_difficulty, slow_hash_block_number, EthashManager, OptimizeFor};
|
||||
use ethereum_types::{H256, H64, U256, Address};
|
||||
use unexpected::{OutOfBounds, Mismatch};
|
||||
@ -124,6 +124,10 @@ pub struct EthashParams {
|
||||
pub expip2_transition: u64,
|
||||
/// EXPIP-2 duration limit
|
||||
pub expip2_duration_limit: u64,
|
||||
/// Block reward contract transition block.
|
||||
pub block_reward_contract_transition: u64,
|
||||
/// Block reward contract.
|
||||
pub block_reward_contract: Option<BlockRewardContract>,
|
||||
}
|
||||
|
||||
impl From<ethjson::spec::EthashParams> for EthashParams {
|
||||
@ -154,6 +158,12 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
|
||||
eip649_reward: p.eip649_reward.map(Into::into),
|
||||
expip2_transition: p.expip2_transition.map_or(u64::max_value(), Into::into),
|
||||
expip2_duration_limit: p.expip2_duration_limit.map_or(30, 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,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -231,6 +241,22 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
|
||||
let author = *LiveBlock::header(&*block).author();
|
||||
let number = LiveBlock::header(&*block).number();
|
||||
|
||||
let rewards = match self.ethash_params.block_reward_contract {
|
||||
Some(ref c) if number >= self.ethash_params.block_reward_contract_transition => {
|
||||
let mut beneficiaries = Vec::new();
|
||||
|
||||
beneficiaries.push((author, RewardKind::Author));
|
||||
for u in LiveBlock::uncles(&*block) {
|
||||
let uncle_author = u.author();
|
||||
beneficiaries.push((*uncle_author, RewardKind::uncle(number, u.number())));
|
||||
}
|
||||
|
||||
let mut call = engines::default_system_or_code_call(&self.machine, block);
|
||||
|
||||
let rewards = c.reward(&beneficiaries, &mut call)?;
|
||||
rewards.into_iter().map(|(author, amount)| (author, RewardKind::External, amount)).collect()
|
||||
},
|
||||
_ => {
|
||||
let mut rewards = Vec::new();
|
||||
|
||||
// Applies EIP-649 reward.
|
||||
@ -274,9 +300,13 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
|
||||
reward.shr(5)
|
||||
};
|
||||
|
||||
rewards.push((*uncle_author, RewardKind::Uncle, result_uncle_reward));
|
||||
rewards.push((*uncle_author, RewardKind::uncle(number, u.number()), result_uncle_reward));
|
||||
}
|
||||
|
||||
rewards
|
||||
},
|
||||
};
|
||||
|
||||
block_reward::apply_block_rewards(&rewards, block, &self.machine)
|
||||
}
|
||||
|
||||
@ -512,6 +542,8 @@ mod tests {
|
||||
eip649_reward: None,
|
||||
expip2_transition: u64::max_value(),
|
||||
expip2_duration_limit: 30,
|
||||
block_reward_contract: None,
|
||||
block_reward_contract_transition: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,10 +29,10 @@ use header::{BlockNumber, Header, ExtendedHeader};
|
||||
use spec::CommonParams;
|
||||
use state::{CleanupMode, Substate};
|
||||
use trace::{NoopTracer, NoopVMTracer, Tracer, ExecutiveTracer, RewardType, Tracing};
|
||||
use transaction::{self, SYSTEM_ADDRESS, UnverifiedTransaction, SignedTransaction};
|
||||
use transaction::{self, SYSTEM_ADDRESS, UNSIGNED_SENDER, UnverifiedTransaction, SignedTransaction};
|
||||
use tx_filter::TransactionFilter;
|
||||
|
||||
use ethereum_types::{U256, Address};
|
||||
use ethereum_types::{U256, H256, Address};
|
||||
use rlp::Rlp;
|
||||
use vm::{CallType, ActionParams, ActionValue, ParamsType};
|
||||
use vm::{EnvInfo, Schedule, CreateContractAddress};
|
||||
@ -122,6 +122,35 @@ impl EthereumMachine {
|
||||
contract_address: Address,
|
||||
gas: U256,
|
||||
data: Option<Vec<u8>>,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let (code, code_hash) = {
|
||||
let state = block.state();
|
||||
|
||||
(state.code(&contract_address)?,
|
||||
state.code_hash(&contract_address)?)
|
||||
};
|
||||
|
||||
self.execute_code_as_system(
|
||||
block,
|
||||
Some(contract_address),
|
||||
code,
|
||||
code_hash,
|
||||
gas,
|
||||
data
|
||||
)
|
||||
}
|
||||
|
||||
/// Same as execute_as_system, but execute code directly. If contract address is None, use the null sender
|
||||
/// address. If code is None, then this function has no effect. The call is executed without finalization, and does
|
||||
/// not form a transaction.
|
||||
pub fn execute_code_as_system(
|
||||
&self,
|
||||
block: &mut ExecutedBlock,
|
||||
contract_address: Option<Address>,
|
||||
code: Option<Arc<Vec<u8>>>,
|
||||
code_hash: Option<H256>,
|
||||
gas: U256,
|
||||
data: Option<Vec<u8>>
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let env_info = {
|
||||
let mut env_info = block.env_info();
|
||||
@ -130,31 +159,27 @@ impl EthereumMachine {
|
||||
};
|
||||
|
||||
let mut state = block.state_mut();
|
||||
|
||||
let params = ActionParams {
|
||||
code_address: contract_address.clone(),
|
||||
address: contract_address.clone(),
|
||||
sender: SYSTEM_ADDRESS.clone(),
|
||||
origin: SYSTEM_ADDRESS.clone(),
|
||||
gas: gas,
|
||||
code_address: contract_address.unwrap_or(UNSIGNED_SENDER),
|
||||
address: contract_address.unwrap_or(UNSIGNED_SENDER),
|
||||
sender: SYSTEM_ADDRESS,
|
||||
origin: SYSTEM_ADDRESS,
|
||||
gas,
|
||||
gas_price: 0.into(),
|
||||
value: ActionValue::Transfer(0.into()),
|
||||
code: state.code(&contract_address)?,
|
||||
code_hash: state.code_hash(&contract_address)?,
|
||||
data: data,
|
||||
code,
|
||||
code_hash,
|
||||
data,
|
||||
call_type: CallType::Call,
|
||||
params_type: ParamsType::Separate,
|
||||
};
|
||||
let schedule = self.schedule(env_info.number);
|
||||
let mut ex = Executive::new(&mut state, &env_info, self, &schedule);
|
||||
let mut substate = Substate::new();
|
||||
let res = ex.call(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer);
|
||||
let output = match res {
|
||||
Ok(res) => res.return_data.to_vec(),
|
||||
Err(e) => {
|
||||
warn!("Encountered error on making system call: {}", e);
|
||||
Vec::new()
|
||||
}
|
||||
};
|
||||
|
||||
let res = ex.call(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).map_err(|e| ::engines::EngineError::FailedSystemCall(format!("{}", e)))?;
|
||||
let output = res.return_data.to_vec();
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
@ -16,8 +16,9 @@
|
||||
|
||||
//! Authority params deserialization.
|
||||
|
||||
use ethereum_types::Address;
|
||||
use hash::Address;
|
||||
use uint::Uint;
|
||||
use bytes::Bytes;
|
||||
use super::ValidatorSet;
|
||||
|
||||
/// Authority params deserialization.
|
||||
@ -51,6 +52,9 @@ pub struct AuthorityRoundParams {
|
||||
/// overrides the static block reward definition).
|
||||
#[serde(rename="blockRewardContractAddress")]
|
||||
pub block_reward_contract_address: Option<Address>,
|
||||
/// Block reward code. This overrides the block reward contract address.
|
||||
#[serde(rename="blockRewardContractCode")]
|
||||
pub block_reward_contract_code: Option<Bytes>,
|
||||
/// Block at which maximum uncle count should be considered.
|
||||
#[serde(rename="maximumUncleCountTransition")]
|
||||
pub maximum_uncle_count_transition: Option<Uint>,
|
||||
|
@ -17,6 +17,7 @@
|
||||
//! Ethash params deserialization.
|
||||
|
||||
use uint::{self, Uint};
|
||||
use bytes::Bytes;
|
||||
use hash::Address;
|
||||
|
||||
/// Deserializable doppelganger of EthashParams.
|
||||
@ -48,6 +49,16 @@ pub struct EthashParams {
|
||||
/// Reward per block in wei.
|
||||
#[serde(rename="blockReward")]
|
||||
pub block_reward: Option<Uint>,
|
||||
/// Block at which the block reward contract should start being used.
|
||||
#[serde(rename="blockRewardContractTransition")]
|
||||
pub block_reward_contract_transition: Option<Uint>,
|
||||
/// Block reward contract address (setting the block reward contract
|
||||
/// overrides all other block reward parameters).
|
||||
#[serde(rename="blockRewardContractAddress")]
|
||||
pub block_reward_contract_address: Option<Address>,
|
||||
/// Block reward code. This overrides the block reward contract address.
|
||||
#[serde(rename="blockRewardContractCode")]
|
||||
pub block_reward_contract_code: Option<Bytes>,
|
||||
|
||||
/// See main EthashParams docs.
|
||||
#[serde(rename="daoHardforkTransition")]
|
||||
@ -183,7 +194,7 @@ mod tests {
|
||||
let deserialized: Ethash = serde_json::from_str(s).unwrap();
|
||||
|
||||
assert_eq!(deserialized, Ethash {
|
||||
params: EthashParams{
|
||||
params: EthashParams {
|
||||
minimum_difficulty: Uint(U256::from(0x020000)),
|
||||
difficulty_bound_divisor: Uint(U256::from(0x0800)),
|
||||
difficulty_increment_divisor: None,
|
||||
@ -191,6 +202,9 @@ mod tests {
|
||||
duration_limit: Some(Uint(U256::from(0x0d))),
|
||||
homestead_transition: Some(Uint(U256::from(0x42))),
|
||||
block_reward: Some(Uint(U256::from(0x100))),
|
||||
block_reward_contract_address: None,
|
||||
block_reward_contract_code: None,
|
||||
block_reward_contract_transition: None,
|
||||
dao_hardfork_transition: Some(Uint(U256::from(0x08))),
|
||||
dao_hardfork_beneficiary: Some(Address(H160::from("0xabcabcabcabcabcabcabcabcabcabcabcabcabca"))),
|
||||
dao_hardfork_accounts: Some(vec![
|
||||
@ -256,6 +270,9 @@ mod tests {
|
||||
duration_limit: None,
|
||||
homestead_transition: None,
|
||||
block_reward: None,
|
||||
block_reward_contract_address: None,
|
||||
block_reward_contract_code: None,
|
||||
block_reward_contract_transition: None,
|
||||
dao_hardfork_transition: None,
|
||||
dao_hardfork_beneficiary: None,
|
||||
dao_hardfork_accounts: None,
|
||||
|
Loading…
Reference in New Issue
Block a user