ethcore, rpc, machine: refactor block reward application and tracing (#8490)

This commit is contained in:
André Silva 2018-05-07 11:57:03 +01:00 committed by Afri Schoedon
parent e30839e85f
commit 32c32ecfda
10 changed files with 93 additions and 55 deletions

View File

@ -1015,8 +1015,10 @@ impl Engine<EthereumMachine> for AuthorityRound {
let author = *block.header().author(); let author = *block.header().author();
benefactors.push((author, RewardKind::Author)); benefactors.push((author, RewardKind::Author));
let rewards = 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
// engine needs support for block reward contract.
let mut call = |to, data| { let mut call = |to, data| {
let result = self.machine.execute_as_system( let result = self.machine.execute_as_system(
block, block,
@ -1027,10 +1029,11 @@ impl Engine<EthereumMachine> for AuthorityRound {
result.map_err(|e| format!("{}", e)) result.map_err(|e| format!("{}", e))
}; };
c.reward(&benefactors, &mut call)? let rewards = c.reward(&benefactors, &mut call)?;
rewards.into_iter().map(|(author, amount)| (author, RewardKind::External, amount)).collect()
}, },
_ => { _ => {
benefactors.into_iter().map(|(author, _)| (author, self.block_reward)).collect() benefactors.into_iter().map(|(author, reward_kind)| (author, reward_kind, self.block_reward)).collect()
}, },
}; };

View File

@ -14,13 +14,17 @@
// 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. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! A module with types for declaring block rewards and a client interface for interacting with a
//! block reward contract.
use ethabi; use ethabi;
use ethabi::ParamType; use ethabi::ParamType;
use ethereum_types::{H160, Address, U256}; use ethereum_types::{H160, Address, U256};
use block::ExecutedBlock;
use error::Error; use error::Error;
use machine::EthereumMachine; use machine::WithRewards;
use parity_machine::{Machine, WithBalances};
use trace;
use super::SystemCall; use super::SystemCall;
use_contract!(block_reward_contract, "BlockReward", "res/contracts/block_reward.json"); use_contract!(block_reward_contract, "BlockReward", "res/contracts/block_reward.json");
@ -37,6 +41,8 @@ pub enum RewardKind {
Uncle = 1, 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 = 2,
/// Reward attributed by an external protocol (e.g. block reward contract).
External = 3,
} }
impl From<RewardKind> for u16 { impl From<RewardKind> for u16 {
@ -45,6 +51,17 @@ impl From<RewardKind> for u16 {
} }
} }
impl Into<trace::RewardType> for RewardKind {
fn into(self) -> trace::RewardType {
match self {
RewardKind::Author => trace::RewardType::Block,
RewardKind::Uncle => trace::RewardType::Uncle,
RewardKind::EmptyStep => trace::RewardType::EmptyStep,
RewardKind::External => trace::RewardType::External,
}
}
}
/// A client for the block reward contract. /// A client for the block reward contract.
pub struct BlockRewardContract { pub struct BlockRewardContract {
/// Address of the contract. /// Address of the contract.
@ -112,14 +129,17 @@ 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 benefactors' address.
/// If tracing is enabled the operations are recorded. /// If tracing is enabled the operations are recorded.
pub fn apply_block_rewards(rewards: &[(Address, U256)], block: &mut ExecutedBlock, machine: &EthereumMachine) -> Result<(), Error> { pub fn apply_block_rewards<M: Machine + WithBalances + WithRewards>(
use parity_machine::WithBalances; rewards: &[(Address, RewardKind, U256)],
block: &mut M::LiveBlock,
for &(ref author, ref block_reward) in rewards { machine: &M,
) -> Result<(), M::Error> {
for &(ref author, _, ref block_reward) in rewards {
machine.add_balance(block, author, block_reward)?; machine.add_balance(block, author, block_reward)?;
} }
machine.note_rewards(block, &rewards, &[]) let rewards: Vec<_> = rewards.into_iter().map(|&(a, k, r)| (a, k.into(), r)).collect();
machine.note_rewards(block, &rewards)
} }
#[cfg(test)] #[cfg(test)]

View File

@ -18,7 +18,6 @@
mod authority_round; mod authority_round;
mod basic_authority; mod basic_authority;
mod block_reward;
mod instant_seal; mod instant_seal;
mod null_engine; mod null_engine;
mod signer; mod signer;
@ -27,6 +26,7 @@ mod transition;
mod validator_set; mod validator_set;
mod vote_collector; mod vote_collector;
pub mod block_reward;
pub mod epoch; pub mod epoch;
pub use self::authority_round::AuthorityRound; pub use self::authority_round::AuthorityRound;

View File

@ -16,7 +16,9 @@
use ethereum_types::U256; use ethereum_types::U256;
use engines::Engine; use engines::Engine;
use engines::block_reward::{self, RewardKind};
use header::BlockNumber; use header::BlockNumber;
use machine::WithRewards;
use parity_machine::{Header, LiveBlock, WithBalances}; use parity_machine::{Header, LiveBlock, WithBalances};
/// Params for a null engine. /// Params for a null engine.
@ -56,7 +58,7 @@ impl<M: Default> Default for NullEngine<M> {
} }
} }
impl<M: WithBalances> Engine<M> for NullEngine<M> { impl<M: WithBalances + WithRewards> Engine<M> for NullEngine<M> {
fn name(&self) -> &str { fn name(&self) -> &str {
"NullEngine" "NullEngine"
} }
@ -74,26 +76,20 @@ impl<M: WithBalances> Engine<M> for NullEngine<M> {
let n_uncles = LiveBlock::uncles(&*block).len(); let n_uncles = LiveBlock::uncles(&*block).len();
let mut rewards = Vec::new();
// Bestow block reward // Bestow block reward
let result_block_reward = reward + reward.shr(5) * U256::from(n_uncles); let result_block_reward = reward + reward.shr(5) * U256::from(n_uncles);
let mut uncle_rewards = Vec::with_capacity(n_uncles); rewards.push((author, RewardKind::Author, result_block_reward));
self.machine.add_balance(block, &author, &result_block_reward)?;
// bestow uncle rewards. // bestow uncle rewards.
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));
uncle_rewards.push((*uncle_author, result_uncle_reward));
} }
for &(ref a, ref reward) in &uncle_rewards { block_reward::apply_block_rewards(&rewards, block, &self.machine)
self.machine.add_balance(block, a, reward)?;
}
// note and trace.
self.machine.note_rewards(block, &[(author, result_block_reward)], &uncle_rewards)
} }
fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 2 } fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 2 }

View File

@ -41,6 +41,7 @@ use ethkey::{self, Message, Signature};
use account_provider::AccountProvider; use account_provider::AccountProvider;
use block::*; use block::*;
use engines::{Engine, Seal, EngineError, ConstructedVerifier}; use engines::{Engine, Seal, EngineError, ConstructedVerifier};
use engines::block_reward::{self, RewardKind};
use io::IoService; use io::IoService;
use super::signer::EngineSigner; use super::signer::EngineSigner;
use super::validator_set::{ValidatorSet, SimpleList}; use super::validator_set::{ValidatorSet, SimpleList};
@ -550,10 +551,13 @@ impl Engine<EthereumMachine> for Tendermint {
/// 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>{
use parity_machine::WithBalances;
let author = *block.header().author(); let author = *block.header().author();
self.machine.add_balance(block, &author, &self.block_reward)?;
self.machine.note_rewards(block, &[(author, self.block_reward)], &[]) block_reward::apply_block_rewards(
&[(author, RewardKind::Author, self.block_reward)],
block,
&self.machine,
)
} }
fn verify_local_seal(&self, _header: &Header) -> Result<(), Error> { fn verify_local_seal(&self, _header: &Header) -> Result<(), Error> {

View File

@ -19,6 +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 ethash::{quick_get_difficulty, slow_hash_block_number, EthashManager, OptimizeFor}; use ethash::{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};
@ -233,11 +234,13 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
/// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current). /// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current).
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> { fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
use std::ops::Shr; use std::ops::Shr;
use parity_machine::{LiveBlock, WithBalances}; use parity_machine::LiveBlock;
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 mut rewards = Vec::new();
// Applies EIP-649 reward. // Applies EIP-649 reward.
let reward = if number >= self.ethash_params.eip649_transition { let reward = if number >= self.ethash_params.eip649_transition {
self.ethash_params.eip649_reward.unwrap_or(self.ethash_params.block_reward) self.ethash_params.eip649_reward.unwrap_or(self.ethash_params.block_reward)
@ -253,20 +256,21 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
// Bestow block rewards. // Bestow block rewards.
let mut result_block_reward = reward + reward.shr(5) * U256::from(n_uncles); let mut result_block_reward = reward + reward.shr(5) * U256::from(n_uncles);
let mut uncle_rewards = Vec::with_capacity(n_uncles);
if number >= self.ethash_params.mcip3_transition { if number >= self.ethash_params.mcip3_transition {
result_block_reward = self.ethash_params.mcip3_miner_reward; result_block_reward = self.ethash_params.mcip3_miner_reward;
let ubi_contract = self.ethash_params.mcip3_ubi_contract; let ubi_contract = self.ethash_params.mcip3_ubi_contract;
let ubi_reward = self.ethash_params.mcip3_ubi_reward; let ubi_reward = self.ethash_params.mcip3_ubi_reward;
let dev_contract = self.ethash_params.mcip3_dev_contract; let dev_contract = self.ethash_params.mcip3_dev_contract;
let dev_reward = self.ethash_params.mcip3_dev_reward; let dev_reward = self.ethash_params.mcip3_dev_reward;
self.machine.add_balance(block, &author, &result_block_reward)?; rewards.push((author, RewardKind::Author, result_block_reward));
self.machine.add_balance(block, &ubi_contract, &ubi_reward)?; rewards.push((ubi_contract, RewardKind::External, ubi_reward));
self.machine.add_balance(block, &dev_contract, &dev_reward)?; rewards.push((dev_contract, RewardKind::External, dev_reward));
} else { } else {
self.machine.add_balance(block, &author, &result_block_reward)?; rewards.push((author, RewardKind::Author, result_block_reward));
} }
// Bestow uncle rewards. // Bestow uncle rewards.
@ -278,15 +282,10 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
reward.shr(5) reward.shr(5)
}; };
uncle_rewards.push((*uncle_author, result_uncle_reward)); rewards.push((*uncle_author, RewardKind::Uncle, result_uncle_reward));
} }
for &(ref a, ref reward) in &uncle_rewards { block_reward::apply_block_rewards(&rewards, block, &self.machine)
self.machine.add_balance(block, a, reward)?;
}
// Note and trace.
self.machine.note_rewards(block, &[(author, result_block_reward)], &uncle_rewards)
} }
fn verify_local_seal(&self, header: &Header) -> Result<(), Error> { fn verify_local_seal(&self, header: &Header) -> Result<(), Error> {

View File

@ -437,22 +437,30 @@ impl ::parity_machine::WithBalances for EthereumMachine {
fn add_balance(&self, live: &mut ExecutedBlock, address: &Address, amount: &U256) -> Result<(), Error> { fn add_balance(&self, live: &mut ExecutedBlock, address: &Address, amount: &U256) -> Result<(), Error> {
live.state_mut().add_balance(address, amount, CleanupMode::NoEmpty).map_err(Into::into) live.state_mut().add_balance(address, amount, CleanupMode::NoEmpty).map_err(Into::into)
} }
}
/// A state machine that uses block rewards.
pub trait WithRewards: ::parity_machine::Machine {
/// Note block rewards, traces each reward storing information about benefactor, amount and type
/// of reward.
fn note_rewards( fn note_rewards(
&self, &self,
live: &mut Self::LiveBlock, live: &mut Self::LiveBlock,
direct: &[(Address, U256)], rewards: &[(Address, RewardType, U256)],
indirect: &[(Address, U256)], ) -> Result<(), Self::Error>;
}
impl WithRewards for EthereumMachine {
fn note_rewards(
&self,
live: &mut Self::LiveBlock,
rewards: &[(Address, RewardType, U256)],
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
if let Tracing::Enabled(ref mut traces) = *live.traces_mut() { if let Tracing::Enabled(ref mut traces) = *live.traces_mut() {
let mut tracer = ExecutiveTracer::default(); let mut tracer = ExecutiveTracer::default();
for &(address, amount) in direct { for &(address, ref reward_type, amount) in rewards {
tracer.trace_reward(address, amount, RewardType::Block); tracer.trace_reward(address, amount, reward_type.clone());
}
for &(address, amount) in indirect {
tracer.trace_reward(address, amount, RewardType::Uncle);
} }
traces.push(tracer.drain().into()); traces.push(tracer.drain().into());

View File

@ -141,6 +141,10 @@ pub enum RewardType {
Block, Block,
/// Uncle /// Uncle
Uncle, Uncle,
/// Empty step (AuthorityRound)
EmptyStep,
/// A reward directly attributed by an external protocol (e.g. block reward contract)
External,
} }
impl Encodable for RewardType { impl Encodable for RewardType {
@ -148,6 +152,8 @@ impl Encodable for RewardType {
let v = match *self { let v = match *self {
RewardType::Block => 0u32, RewardType::Block => 0u32,
RewardType::Uncle => 1, RewardType::Uncle => 1,
RewardType::EmptyStep => 2,
RewardType::External => 3,
}; };
Encodable::rlp_append(&v, s); Encodable::rlp_append(&v, s);
} }
@ -158,6 +164,8 @@ impl Decodable for RewardType {
rlp.as_val().and_then(|v| Ok(match v { rlp.as_val().and_then(|v| Ok(match v {
0u32 => RewardType::Block, 0u32 => RewardType::Block,
1 => RewardType::Uncle, 1 => RewardType::Uncle,
2 => RewardType::EmptyStep,
3 => RewardType::External,
_ => return Err(DecoderError::Custom("Invalid value of RewardType item")), _ => return Err(DecoderError::Custom("Invalid value of RewardType item")),
})) }))
} }

View File

@ -106,12 +106,4 @@ pub trait WithBalances: Machine {
/// Increment the balance of an account in the state of the live block. /// Increment the balance of an account in the state of the live block.
fn add_balance(&self, live: &mut Self::LiveBlock, address: &Address, amount: &U256) -> Result<(), Self::Error>; fn add_balance(&self, live: &mut Self::LiveBlock, address: &Address, amount: &U256) -> Result<(), Self::Error>;
/// Note block rewards. "direct" rewards are for authors, "indirect" are for e.g. uncles.
fn note_rewards(
&self,
_live: &mut Self::LiveBlock,
_direct: &[(Address, U256)],
_indirect: &[(Address, U256)],
) -> Result<(), Self::Error> { Ok(()) }
} }

View File

@ -308,6 +308,12 @@ pub enum RewardType {
/// Uncle /// Uncle
#[serde(rename="uncle")] #[serde(rename="uncle")]
Uncle, Uncle,
/// EmptyStep (AuthorityRound)
#[serde(rename="emptyStep")]
EmptyStep,
/// External (attributed as part of an external protocol)
#[serde(rename="external")]
External,
} }
impl From<trace::RewardType> for RewardType { impl From<trace::RewardType> for RewardType {
@ -315,6 +321,8 @@ impl From<trace::RewardType> for RewardType {
match c { match c {
trace::RewardType::Block => RewardType::Block, trace::RewardType::Block => RewardType::Block,
trace::RewardType::Uncle => RewardType::Uncle, trace::RewardType::Uncle => RewardType::Uncle,
trace::RewardType::EmptyStep => RewardType::EmptyStep,
trace::RewardType::External => RewardType::External,
} }
} }
} }