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),
|
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_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_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)),
|
||||||
@ -1043,7 +1047,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
|||||||
|
|
||||||
/// Apply the block reward on finalisation of the block.
|
/// Apply the block reward on finalisation of the block.
|
||||||
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
|
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 {
|
if block.header().number() >= self.empty_steps_transition {
|
||||||
let empty_steps = if block.header().seal().is_empty() {
|
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
|
// 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 {
|
for empty_step in empty_steps {
|
||||||
let author = empty_step.author()?;
|
let author = empty_step.author()?;
|
||||||
benefactors.push((author, RewardKind::EmptyStep));
|
beneficiaries.push((author, RewardKind::EmptyStep));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let author = *block.header().author();
|
let author = *block.header().author();
|
||||||
benefactors.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 block.header().number() >= self.block_reward_contract_transition => {
|
||||||
// NOTE: this logic should be moved to a function when another
|
let mut call = super::default_system_or_code_call(&self.machine, block);
|
||||||
// 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 rewards = c.reward(&benefactors, &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()
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
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 ethabi::ParamType;
|
||||||
use ethereum_types::{H160, Address, U256};
|
use ethereum_types::{H160, Address, U256};
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use hash::keccak;
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use machine::WithRewards;
|
use machine::WithRewards;
|
||||||
use parity_machine::{Machine, WithBalances};
|
use parity_machine::{Machine, WithBalances};
|
||||||
use trace;
|
use trace;
|
||||||
use super::SystemCall;
|
use types::BlockNumber;
|
||||||
|
use super::{SystemOrCodeCall, SystemOrCodeCallKind};
|
||||||
|
|
||||||
use_contract!(block_reward_contract, "BlockReward", "res/contracts/block_reward.json");
|
use_contract!(block_reward_contract, "BlockReward", "res/contracts/block_reward.json");
|
||||||
|
|
||||||
/// The kind of block reward.
|
/// The kind of block reward.
|
||||||
/// Depending on the consensus engine the allocated block reward might have
|
/// Depending on the consensus engine the allocated block reward might have
|
||||||
/// different semantics which could lead e.g. to different reward values.
|
/// different semantics which could lead e.g. to different reward values.
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||||
pub enum RewardKind {
|
pub enum RewardKind {
|
||||||
/// Reward attributed to the block author.
|
/// Reward attributed to the block author.
|
||||||
Author = 0,
|
Author,
|
||||||
/// Reward attributed to the block uncle(s).
|
|
||||||
Uncle = 1,
|
|
||||||
/// Reward attributed to the author(s) of empty step(s) included in the block (AuthorityRound engine).
|
/// 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).
|
/// 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 {
|
impl From<RewardKind> for u16 {
|
||||||
fn from(reward_kind: RewardKind) -> Self {
|
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 {
|
fn into(self) -> trace::RewardType {
|
||||||
match self {
|
match self {
|
||||||
RewardKind::Author => trace::RewardType::Block,
|
RewardKind::Author => trace::RewardType::Block,
|
||||||
RewardKind::Uncle => trace::RewardType::Uncle,
|
RewardKind::Uncle(_) => trace::RewardType::Uncle,
|
||||||
RewardKind::EmptyStep => trace::RewardType::EmptyStep,
|
RewardKind::EmptyStep => trace::RewardType::EmptyStep,
|
||||||
RewardKind::External => trace::RewardType::External,
|
RewardKind::External => trace::RewardType::External,
|
||||||
}
|
}
|
||||||
@ -63,38 +78,50 @@ impl Into<trace::RewardType> for RewardKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A client for the block reward contract.
|
/// A client for the block reward contract.
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct BlockRewardContract {
|
pub struct BlockRewardContract {
|
||||||
/// Address of the contract.
|
kind: SystemOrCodeCallKind,
|
||||||
address: Address,
|
|
||||||
block_reward_contract: block_reward_contract::BlockReward,
|
block_reward_contract: block_reward_contract::BlockReward,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockRewardContract {
|
impl BlockRewardContract {
|
||||||
/// Create a new block reward contract client targeting the given address.
|
/// Create a new block reward contract client targeting the system call kind.
|
||||||
pub fn new(address: Address) -> BlockRewardContract {
|
pub fn new(kind: SystemOrCodeCallKind) -> BlockRewardContract {
|
||||||
BlockRewardContract {
|
BlockRewardContract {
|
||||||
address,
|
kind,
|
||||||
block_reward_contract: block_reward_contract::BlockReward::default(),
|
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
|
/// 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
|
/// called by the system address so the `caller` must ensure that (e.g. using
|
||||||
/// `machine.execute_as_system`).
|
/// `machine.execute_as_system`).
|
||||||
pub fn reward(
|
pub fn reward(
|
||||||
&self,
|
&self,
|
||||||
benefactors: &[(Address, RewardKind)],
|
beneficiaries: &[(Address, RewardKind)],
|
||||||
caller: &mut SystemCall,
|
caller: &mut SystemOrCodeCall,
|
||||||
) -> Result<Vec<(Address, U256)>, Error> {
|
) -> Result<Vec<(Address, U256)>, Error> {
|
||||||
let reward = self.block_reward_contract.functions().reward();
|
let reward = self.block_reward_contract.functions().reward();
|
||||||
|
|
||||||
let input = reward.input(
|
let input = reward.input(
|
||||||
benefactors.iter().map(|&(address, _)| H160::from(address)),
|
beneficiaries.iter().map(|&(address, _)| H160::from(address)),
|
||||||
benefactors.iter().map(|&(_, ref reward_kind)| u16::from(*reward_kind)),
|
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(Into::into)
|
||||||
.map_err(::engines::EngineError::FailedSystemCall)?;
|
.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.
|
/// If tracing is enabled the operations are recorded.
|
||||||
pub fn apply_block_rewards<M: Machine + WithBalances + WithRewards>(
|
pub fn apply_block_rewards<M: Machine + WithBalances + WithRewards>(
|
||||||
rewards: &[(Address, RewardKind, U256)],
|
rewards: &[(Address, RewardKind, U256)],
|
||||||
@ -149,6 +176,7 @@ mod test {
|
|||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use test_helpers::generate_dummy_client_with_spec_and_accounts;
|
use test_helpers::generate_dummy_client_with_spec_and_accounts;
|
||||||
|
|
||||||
|
use engines::SystemOrCodeCallKind;
|
||||||
use super::{BlockRewardContract, RewardKind};
|
use super::{BlockRewardContract, RewardKind};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -161,7 +189,7 @@ mod test {
|
|||||||
let machine = Spec::new_test_machine();
|
let machine = Spec::new_test_machine();
|
||||||
|
|
||||||
// the spec has a block reward contract defined at the given address
|
// 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(),
|
"0000000000000000000000000000000000000042".into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -172,30 +200,35 @@ mod test {
|
|||||||
vec![],
|
vec![],
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let result = machine.execute_as_system(
|
let result = match to {
|
||||||
|
SystemOrCodeCallKind::Address(to) => {
|
||||||
|
machine.execute_as_system(
|
||||||
block.block_mut(),
|
block.block_mut(),
|
||||||
to,
|
to,
|
||||||
U256::max_value(),
|
U256::max_value(),
|
||||||
Some(data),
|
Some(data),
|
||||||
);
|
)
|
||||||
|
},
|
||||||
|
_ => panic!("Test reward contract is created by an address, we never reach this branch."),
|
||||||
|
};
|
||||||
|
|
||||||
result.map_err(|e| format!("{}", e))
|
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());
|
assert!(block_reward_contract.reward(&vec![], &mut call).unwrap().is_empty());
|
||||||
|
|
||||||
// the contract rewards (1000 + kind) for each benefactor
|
// the contract rewards (1000 + kind) for each benefactor
|
||||||
let benefactors = vec![
|
let beneficiaries = vec![
|
||||||
("0000000000000000000000000000000000000033".into(), RewardKind::Author),
|
("0000000000000000000000000000000000000033".into(), RewardKind::Author),
|
||||||
("0000000000000000000000000000000000000034".into(), RewardKind::Uncle),
|
("0000000000000000000000000000000000000034".into(), RewardKind::Uncle(1)),
|
||||||
("0000000000000000000000000000000000000035".into(), RewardKind::EmptyStep),
|
("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![
|
let expected = vec![
|
||||||
("0000000000000000000000000000000000000033".into(), U256::from(1000)),
|
("0000000000000000000000000000000000000033".into(), U256::from(1000)),
|
||||||
("0000000000000000000000000000000000000034".into(), U256::from(1000 + 1)),
|
("0000000000000000000000000000000000000034".into(), U256::from(1000 + 101)),
|
||||||
("0000000000000000000000000000000000000035".into(), U256::from(1000 + 2)),
|
("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.
|
/// 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;
|
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.
|
/// Type alias for a function we can get headers by hash through.
|
||||||
pub type Headers<'a, H> = Fn(H256) -> Option<H> + 'a;
|
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) {
|
for u in LiveBlock::uncles(&*block) {
|
||||||
let uncle_author = u.author();
|
let uncle_author = u.author();
|
||||||
let result_uncle_reward = (reward * U256::from(8 + u.number() - number)).shr(3);
|
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)
|
block_reward::apply_block_rewards(&rewards, block, &self.machine)
|
||||||
|
@ -19,7 +19,7 @@ use std::cmp;
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use hash::{KECCAK_EMPTY_LIST_RLP};
|
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 ethash::{self, quick_get_difficulty, slow_hash_block_number, EthashManager, OptimizeFor};
|
||||||
use ethereum_types::{H256, H64, U256, Address};
|
use ethereum_types::{H256, H64, U256, Address};
|
||||||
use unexpected::{OutOfBounds, Mismatch};
|
use unexpected::{OutOfBounds, Mismatch};
|
||||||
@ -124,6 +124,10 @@ pub struct EthashParams {
|
|||||||
pub expip2_transition: u64,
|
pub expip2_transition: u64,
|
||||||
/// EXPIP-2 duration limit
|
/// EXPIP-2 duration limit
|
||||||
pub expip2_duration_limit: u64,
|
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 {
|
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),
|
eip649_reward: p.eip649_reward.map(Into::into),
|
||||||
expip2_transition: p.expip2_transition.map_or(u64::max_value(), 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),
|
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 author = *LiveBlock::header(&*block).author();
|
||||||
let number = LiveBlock::header(&*block).number();
|
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();
|
let mut rewards = Vec::new();
|
||||||
|
|
||||||
// Applies EIP-649 reward.
|
// Applies EIP-649 reward.
|
||||||
@ -274,9 +300,13 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
|
|||||||
reward.shr(5)
|
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)
|
block_reward::apply_block_rewards(&rewards, block, &self.machine)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,6 +542,8 @@ mod tests {
|
|||||||
eip649_reward: None,
|
eip649_reward: None,
|
||||||
expip2_transition: u64::max_value(),
|
expip2_transition: u64::max_value(),
|
||||||
expip2_duration_limit: 30,
|
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 spec::CommonParams;
|
||||||
use state::{CleanupMode, Substate};
|
use state::{CleanupMode, Substate};
|
||||||
use trace::{NoopTracer, NoopVMTracer, Tracer, ExecutiveTracer, RewardType, Tracing};
|
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 tx_filter::TransactionFilter;
|
||||||
|
|
||||||
use ethereum_types::{U256, Address};
|
use ethereum_types::{U256, H256, Address};
|
||||||
use rlp::Rlp;
|
use rlp::Rlp;
|
||||||
use vm::{CallType, ActionParams, ActionValue, ParamsType};
|
use vm::{CallType, ActionParams, ActionValue, ParamsType};
|
||||||
use vm::{EnvInfo, Schedule, CreateContractAddress};
|
use vm::{EnvInfo, Schedule, CreateContractAddress};
|
||||||
@ -122,6 +122,35 @@ impl EthereumMachine {
|
|||||||
contract_address: Address,
|
contract_address: Address,
|
||||||
gas: U256,
|
gas: U256,
|
||||||
data: Option<Vec<u8>>,
|
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> {
|
) -> Result<Vec<u8>, Error> {
|
||||||
let env_info = {
|
let env_info = {
|
||||||
let mut env_info = block.env_info();
|
let mut env_info = block.env_info();
|
||||||
@ -130,31 +159,27 @@ impl EthereumMachine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut state = block.state_mut();
|
let mut state = block.state_mut();
|
||||||
|
|
||||||
let params = ActionParams {
|
let params = ActionParams {
|
||||||
code_address: contract_address.clone(),
|
code_address: contract_address.unwrap_or(UNSIGNED_SENDER),
|
||||||
address: contract_address.clone(),
|
address: contract_address.unwrap_or(UNSIGNED_SENDER),
|
||||||
sender: SYSTEM_ADDRESS.clone(),
|
sender: SYSTEM_ADDRESS,
|
||||||
origin: SYSTEM_ADDRESS.clone(),
|
origin: SYSTEM_ADDRESS,
|
||||||
gas: gas,
|
gas,
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
value: ActionValue::Transfer(0.into()),
|
value: ActionValue::Transfer(0.into()),
|
||||||
code: state.code(&contract_address)?,
|
code,
|
||||||
code_hash: state.code_hash(&contract_address)?,
|
code_hash,
|
||||||
data: data,
|
data,
|
||||||
call_type: CallType::Call,
|
call_type: CallType::Call,
|
||||||
params_type: ParamsType::Separate,
|
params_type: ParamsType::Separate,
|
||||||
};
|
};
|
||||||
let schedule = self.schedule(env_info.number);
|
let schedule = self.schedule(env_info.number);
|
||||||
let mut ex = Executive::new(&mut state, &env_info, self, &schedule);
|
let mut ex = Executive::new(&mut state, &env_info, self, &schedule);
|
||||||
let mut substate = Substate::new();
|
let mut substate = Substate::new();
|
||||||
let res = ex.call(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer);
|
|
||||||
let output = match res {
|
let res = ex.call(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).map_err(|e| ::engines::EngineError::FailedSystemCall(format!("{}", e)))?;
|
||||||
Ok(res) => res.return_data.to_vec(),
|
let output = res.return_data.to_vec();
|
||||||
Err(e) => {
|
|
||||||
warn!("Encountered error on making system call: {}", e);
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,9 @@
|
|||||||
|
|
||||||
//! Authority params deserialization.
|
//! Authority params deserialization.
|
||||||
|
|
||||||
use ethereum_types::Address;
|
use hash::Address;
|
||||||
use uint::Uint;
|
use uint::Uint;
|
||||||
|
use bytes::Bytes;
|
||||||
use super::ValidatorSet;
|
use super::ValidatorSet;
|
||||||
|
|
||||||
/// Authority params deserialization.
|
/// Authority params deserialization.
|
||||||
@ -51,6 +52,9 @@ pub struct AuthorityRoundParams {
|
|||||||
/// overrides the static block reward definition).
|
/// overrides the static block reward definition).
|
||||||
#[serde(rename="blockRewardContractAddress")]
|
#[serde(rename="blockRewardContractAddress")]
|
||||||
pub block_reward_contract_address: Option<Address>,
|
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.
|
/// Block at which maximum uncle count should be considered.
|
||||||
#[serde(rename="maximumUncleCountTransition")]
|
#[serde(rename="maximumUncleCountTransition")]
|
||||||
pub maximum_uncle_count_transition: Option<Uint>,
|
pub maximum_uncle_count_transition: Option<Uint>,
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
//! Ethash params deserialization.
|
//! Ethash params deserialization.
|
||||||
|
|
||||||
use uint::{self, Uint};
|
use uint::{self, Uint};
|
||||||
|
use bytes::Bytes;
|
||||||
use hash::Address;
|
use hash::Address;
|
||||||
|
|
||||||
/// Deserializable doppelganger of EthashParams.
|
/// Deserializable doppelganger of EthashParams.
|
||||||
@ -48,6 +49,16 @@ pub struct EthashParams {
|
|||||||
/// Reward per block in wei.
|
/// Reward per block in wei.
|
||||||
#[serde(rename="blockReward")]
|
#[serde(rename="blockReward")]
|
||||||
pub block_reward: Option<Uint>,
|
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.
|
/// See main EthashParams docs.
|
||||||
#[serde(rename="daoHardforkTransition")]
|
#[serde(rename="daoHardforkTransition")]
|
||||||
@ -183,7 +194,7 @@ mod tests {
|
|||||||
let deserialized: Ethash = serde_json::from_str(s).unwrap();
|
let deserialized: Ethash = serde_json::from_str(s).unwrap();
|
||||||
|
|
||||||
assert_eq!(deserialized, Ethash {
|
assert_eq!(deserialized, Ethash {
|
||||||
params: EthashParams{
|
params: EthashParams {
|
||||||
minimum_difficulty: Uint(U256::from(0x020000)),
|
minimum_difficulty: Uint(U256::from(0x020000)),
|
||||||
difficulty_bound_divisor: Uint(U256::from(0x0800)),
|
difficulty_bound_divisor: Uint(U256::from(0x0800)),
|
||||||
difficulty_increment_divisor: None,
|
difficulty_increment_divisor: None,
|
||||||
@ -191,6 +202,9 @@ mod tests {
|
|||||||
duration_limit: Some(Uint(U256::from(0x0d))),
|
duration_limit: Some(Uint(U256::from(0x0d))),
|
||||||
homestead_transition: Some(Uint(U256::from(0x42))),
|
homestead_transition: Some(Uint(U256::from(0x42))),
|
||||||
block_reward: Some(Uint(U256::from(0x100))),
|
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_transition: Some(Uint(U256::from(0x08))),
|
||||||
dao_hardfork_beneficiary: Some(Address(H160::from("0xabcabcabcabcabcabcabcabcabcabcabcabcabca"))),
|
dao_hardfork_beneficiary: Some(Address(H160::from("0xabcabcabcabcabcabcabcabcabcabcabcabcabca"))),
|
||||||
dao_hardfork_accounts: Some(vec![
|
dao_hardfork_accounts: Some(vec![
|
||||||
@ -256,6 +270,9 @@ mod tests {
|
|||||||
duration_limit: None,
|
duration_limit: None,
|
||||||
homestead_transition: None,
|
homestead_transition: None,
|
||||||
block_reward: 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_transition: None,
|
||||||
dao_hardfork_beneficiary: None,
|
dao_hardfork_beneficiary: None,
|
||||||
dao_hardfork_accounts: None,
|
dao_hardfork_accounts: None,
|
||||||
|
Loading…
Reference in New Issue
Block a user