-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Rewards on closing blocks #6194
Changes from 26 commits
ab61538
16f3948
7312803
53c3b77
af1fbb3
b193534
1f3f911
94efa3a
bb043ba
06862c7
204a63a
5086dc3
3fdb912
f2d12ae
45043c3
1a3f3ff
9374e31
e809582
8826fdb
141c2fd
2e840bc
01ea968
01a02a8
3043432
655ed93
dd91121
bfd238e
50495c6
e366645
88200a1
8a420d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
{ | ||
"name": "Morden", | ||
"engine": { | ||
"null": null | ||
}, | ||
"params": { | ||
"gasLimitBoundDivisor": "0x0400", | ||
"accountStartNonce": "0x0", | ||
"maximumExtraDataSize": "0x20", | ||
"minGasLimit": "0x1388", | ||
"networkID" : "0x2", | ||
"blockReward": "0x4563918244F40000" | ||
}, | ||
"genesis": { | ||
"seal": { | ||
"ethereum": { | ||
"nonce": "0x00006d6f7264656e", | ||
"mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578" | ||
} | ||
}, | ||
"difficulty": "0x20000", | ||
"author": "0x0000000000000000000000000000000000000000", | ||
"timestamp": "0x00", | ||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", | ||
"extraData": "0x", | ||
"gasLimit": "0x2fefd8" | ||
}, | ||
"accounts": { | ||
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, | ||
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, | ||
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, | ||
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, | ||
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,7 @@ use std::sync::Arc; | |
use std::collections::HashSet; | ||
|
||
use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError}; | ||
use util::{Bytes, Address, Hashable, U256, H256, ordered_trie_root, SHA3_NULL_RLP}; | ||
use util::{Bytes, Address, Hashable, U256, H256, ordered_trie_root, SHA3_NULL_RLP, SHA3_EMPTY_LIST_RLP}; | ||
use util::error::{Mismatch, OutOfBounds}; | ||
|
||
use basic_types::{LogBloom, Seal}; | ||
|
@@ -91,7 +91,7 @@ pub struct ExecutedBlock { | |
receipts: Vec<Receipt>, | ||
transactions_set: HashSet<H256>, | ||
state: State<StateDB>, | ||
traces: Option<Vec<Vec<FlatTrace>>>, | ||
traces: Option<Vec<Vec<FlatTrace>>> | ||
} | ||
|
||
/// A set of references to `ExecutedBlock` fields that are publicly accessible. | ||
|
@@ -107,7 +107,7 @@ pub struct BlockRefMut<'a> { | |
/// State. | ||
pub state: &'a mut State<StateDB>, | ||
/// Traces. | ||
pub traces: &'a Option<Vec<Vec<FlatTrace>>>, | ||
pub traces: &'a mut Option<Vec<Vec<FlatTrace>>>, | ||
} | ||
|
||
/// A set of immutable references to `ExecutedBlock` fields that are publicly accessible. | ||
|
@@ -148,7 +148,7 @@ impl ExecutedBlock { | |
uncles: &self.uncles, | ||
state: &mut self.state, | ||
receipts: &self.receipts, | ||
traces: &self.traces, | ||
traces: &mut self.traces, | ||
} | ||
} | ||
|
||
|
@@ -196,6 +196,9 @@ pub trait IsBlock { | |
|
||
/// Get all uncles in this block. | ||
fn uncles(&self) -> &[Header] { &self.block().uncles } | ||
|
||
/// Get tracing enabled flag for this block. | ||
fn tracing_enabled(&self) -> bool { self.block().traces.is_some() } | ||
} | ||
|
||
/// Trait for a object that has a state database. | ||
|
@@ -393,8 +396,9 @@ impl<'x> OpenBlock<'x> { | |
let unclosed_state = s.block.state.clone(); | ||
|
||
if let Err(e) = s.engine.on_close_block(&mut s.block) { | ||
warn!("Encountered error on closing the block: {}", e); | ||
warn!("Encountered error on closing the block: {}", e); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dodgy space added |
||
} | ||
|
||
if let Err(e) = s.block.state.commit() { | ||
warn!("Encountered error on state commit: {}", e); | ||
} | ||
|
@@ -419,7 +423,7 @@ impl<'x> OpenBlock<'x> { | |
let mut s = self; | ||
|
||
if let Err(e) = s.engine.on_close_block(&mut s.block) { | ||
warn!("Encountered error on closing the block: {}", e); | ||
warn!("Encountered error on closing the block: {}", e); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dodgy space added (beginning of line) |
||
} | ||
|
||
if let Err(e) = s.block.state.commit() { | ||
|
@@ -429,7 +433,7 @@ impl<'x> OpenBlock<'x> { | |
s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes().into_vec()))); | ||
} | ||
let uncle_bytes = s.block.uncles.iter().fold(RlpStream::new_list(s.block.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out(); | ||
if s.block.header.uncles_hash().is_zero() { | ||
if s.block.header.uncles_hash().is_zero() || s.block.header.uncles_hash() == &SHA3_EMPTY_LIST_RLP { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any particular reason for this change? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. From my point of view it's a logical flaw. If block is initialized using default construction, uncle_hash won't be zero and won't be set in this method. I assume, that original intent was to set it in this case. You can see the same pattern (checking default values and zero) in this function for other fields. As a result simple integration test with close_and_seal for block failed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok that's fair enough. |
||
s.block.header.set_uncles_hash(uncle_bytes.sha3()); | ||
} | ||
if s.block.header.receipts_root().is_zero() || s.block.header.receipts_root() == &SHA3_NULL_RLP { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -229,7 +229,7 @@ pub trait Engine : Sync + Send { | |
|
||
/// Block transformation functions, after the transactions. | ||
fn on_close_block(&self, _block: &mut ExecutedBlock) -> Result<(), Error> { | ||
Ok(()) | ||
Ok(()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dodgy space added |
||
} | ||
|
||
/// None means that it requires external input (e.g. PoW) to seal a block. | ||
|
@@ -399,8 +399,9 @@ pub mod common { | |
use transaction::SYSTEM_ADDRESS; | ||
use executive::Executive; | ||
use vm::{CallType, ActionParams, ActionValue, EnvInfo, LastHashes}; | ||
use trace::{NoopTracer, NoopVMTracer}; | ||
use trace::{NoopTracer, NoopVMTracer, Tracer, ExecutiveTracer, RewardType}; | ||
use state::Substate; | ||
use state::CleanupMode; | ||
|
||
use util::*; | ||
use super::Engine; | ||
|
@@ -469,4 +470,27 @@ pub mod common { | |
} | ||
Ok(()) | ||
} | ||
|
||
/// Trace rewards on closing block | ||
pub fn bestow_block_reward<E: Engine + ?Sized>(block: &mut ExecutedBlock, engine: &E) -> Result<(), Error> { | ||
let fields = block.fields_mut(); | ||
// Bestow block reward | ||
let reward = engine.params().block_reward; | ||
let res = fields.state.add_balance(fields.header.author(), &reward, CleanupMode::NoEmpty) | ||
.map_err(::error::Error::from) | ||
.and_then(|_| fields.state.commit()); | ||
|
||
let block_author = fields.header.author().clone(); | ||
fields.traces.as_mut().map(|mut traces| { | ||
let mut tracer = ExecutiveTracer::default(); | ||
tracer.trace_reward(block_author, engine.params().block_reward, RewardType::Block); | ||
traces.push(tracer.traces()) | ||
}); | ||
|
||
// Commit state so that we can actually figure out the state root. | ||
if let Err(ref e) = res { | ||
warn!("Encountered error on bestowing reward: {}", e); | ||
} | ||
res | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ use block::*; | |
use builtin::Builtin; | ||
use vm::EnvInfo; | ||
use error::{BlockError, Error, TransactionError}; | ||
use trace::{Tracer, ExecutiveTracer,RewardType}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inconsistent spaces. |
||
use header::{Header, BlockNumber}; | ||
use state::CleanupMode; | ||
use spec::CommonParams; | ||
|
@@ -275,38 +276,60 @@ impl Engine for Arc<Ethash> { | |
/// Apply the block reward on finalisation of the block. | ||
/// 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> { | ||
use std::ops::Shr; | ||
let reward = self.params().block_reward; | ||
let tracing_enabled = block.tracing_enabled(); | ||
let fields = block.fields_mut(); | ||
let eras_rounds = self.ethash_params.ecip1017_era_rounds; | ||
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, fields.header.number()); | ||
let mut tracer = ExecutiveTracer::default(); | ||
|
||
// Bestow block reward | ||
let result_block_reward = reward + reward.shr(5) * U256::from(fields.uncles.len()); | ||
fields.state.add_balance( | ||
fields.header.author(), | ||
&(reward + reward / U256::from(32) * U256::from(fields.uncles.len())), | ||
&result_block_reward, | ||
CleanupMode::NoEmpty | ||
)?; | ||
|
||
if tracing_enabled { | ||
let block_author = fields.header.author().clone(); | ||
tracer.trace_reward(block_author, result_block_reward, RewardType::Block); | ||
} | ||
|
||
// Bestow uncle rewards | ||
let current_number = fields.header.number(); | ||
for u in fields.uncles.iter() { | ||
let uncle_author = u.author().clone(); | ||
let result_uncle_reward: U256; | ||
|
||
if eras == 0 { | ||
result_uncle_reward = (reward * U256::from(8 + u.number() - current_number)).shr(3); | ||
fields.state.add_balance( | ||
u.author(), | ||
&(reward * U256::from(8 + u.number() - current_number) / U256::from(8)), | ||
&result_uncle_reward, | ||
CleanupMode::NoEmpty | ||
) | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. trailing whitespace |
||
} else { | ||
result_uncle_reward = reward.shr(5); | ||
fields.state.add_balance( | ||
u.author(), | ||
&(reward / U256::from(32)), | ||
&result_uncle_reward, | ||
CleanupMode::NoEmpty | ||
) | ||
}?; | ||
|
||
// Trace uncle rewards | ||
if tracing_enabled { | ||
tracer.trace_reward(uncle_author, result_uncle_reward, RewardType::Uncle); | ||
} | ||
} | ||
|
||
// Commit state so that we can actually figure out the state root. | ||
fields.state.commit()?; | ||
if tracing_enabled { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here (avoid to produce traces when tracing is disabled) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you sure? In this case it seems to be covered with if. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, you're right sorry! |
||
fields.traces.as_mut().map(|mut traces| traces.push(tracer.traces())); | ||
} | ||
Ok(()) | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -170,7 +170,7 @@ impl From<ethjson::spec::Params> for CommonParams { | |
wasm: p.wasm.unwrap_or(false), | ||
gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(), | ||
block_reward: p.block_reward.map_or_else(U256::zero, Into::into), | ||
registrar: p.registrar.map_or_else(Address::new, Into::into), | ||
registrar: p.registrar.map_or_else(Address::new, Into::into) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't kill the trailing |
||
} | ||
} | ||
} | ||
|
@@ -478,6 +478,9 @@ impl Spec { | |
/// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus. | ||
pub fn new_test() -> Spec { load_bundled!("null_morden") } | ||
|
||
/// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus with applying reward on block close. | ||
pub fn new_test_with_reward() -> Spec { load_bundled!("null_morden_with_reward") } | ||
|
||
/// Create a new Spec which is a NullEngine consensus with a premine of address whose secret is sha3(''). | ||
pub fn new_null() -> Spec { load_bundled!("null") } | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
pub mod helpers; | ||
mod client; | ||
mod evm; | ||
mod trace; | ||
|
||
#[cfg(feature="ipc")] | ||
mod rpc; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: don't kill the trailing
,