Block reward contract (#8419)

* engine: add block reward contract abi and helper client

* aura: add support for block reward contract

* engine: test block reward contract client

* aura: test block reward contract

* engine + aura: add missing docs

* engine: share SystemCall type alias

* aura: add transition for block reward contract

* engine: fix example block reward contract source link and bytecode
This commit is contained in:
André Silva 2018-04-20 11:32:00 +01:00 committed by Afri Schoedon
parent 9c5e35548d
commit 24f6d8296b
9 changed files with 412 additions and 22 deletions

18
Cargo.lock generated
View File

@ -462,7 +462,7 @@ dependencies = [
[[package]]
name = "ethabi-contract"
version = "5.0.3"
version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -514,7 +514,7 @@ dependencies = [
"crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethash 1.11.0",
"ethcore-bloom-journal 0.1.0",
@ -745,7 +745,7 @@ version = "1.0.0"
dependencies = [
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.11.0",
"ethcore-bytes 0.1.0",
@ -780,7 +780,7 @@ version = "1.0.0"
dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.11.0",
"ethcore-bytes 0.1.0",
@ -1786,7 +1786,7 @@ name = "node-filter"
version = "1.11.0"
dependencies = [
"ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.11.0",
"ethcore-io 1.11.0",
@ -2084,7 +2084,7 @@ name = "parity-hash-fetch"
version = "1.11.0"
dependencies = [
"ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-bytes 0.1.0",
"ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2305,7 +2305,7 @@ name = "parity-updater"
version = "1.11.0"
dependencies = [
"ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.11.0",
"ethcore-bytes 0.1.0",
@ -2708,7 +2708,7 @@ name = "registrar"
version = "0.0.1"
dependencies = [
"ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"keccak-hash 0.1.0",
@ -3815,7 +3815,7 @@ dependencies = [
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
"checksum eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)" = "<none>"
"checksum ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05e33a914b94b763f0a92333e4e5c95c095563f06ef7d6b295b3d3c2cf31e21f"
"checksum ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca2263c24359e827348ac99aa1f2e28ba5bab0d6c0b83941fa252de8a9e9c073"
"checksum ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "210c9e21d164c15b6ef64fe601e0e12a3c84a031d5ef558e38463e53edbd22ed"
"checksum ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d2bc7099baa147187aedaecd9fe04a6c0541c82bc43ff317cb6900fe2b983d74"
"checksum ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a93a43ce2e9f09071449da36bfa7a1b20b950ee344b6904ff23de493b03b386"
"checksum ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3ae691a36ce5d25b433e63128ce5579f4a18457b6a9c849832b2c9e0fec92a"

View File

@ -0,0 +1,61 @@
{
"name": "TestAuthorityRoundBlockRewardContract",
"engine": {
"authorityRound": {
"params": {
"stepDuration": 1,
"startStep": 2,
"validators": {
"list": [
"0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e",
"0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1"
]
},
"immediateTransitions": true,
"emptyStepsTransition": "1",
"maximumEmptySteps": "2",
"blockRewardContractAddress": "0x0000000000000000000000000000000000000042"
}
}
},
"params": {
"gasLimitBoundDivisor": "0x0400",
"accountStartNonce": "0x0",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x69",
"eip140Transition": "0x0",
"eip211Transition": "0x0",
"eip214Transition": "0x0",
"eip658Transition": "0x0"
},
"genesis": {
"seal": {
"authorityRound": {
"step": "0x0",
"signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x20000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x222222"
},
"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 } } } },
"0000000000000000000000000000000000000005": { "balance": "1", "builtin": { "name": "modexp", "activate_at": 0, "pricing": { "modexp": { "divisor": 20 } } } },
"0000000000000000000000000000000000000006": { "balance": "1", "builtin": { "name": "alt_bn128_add", "activate_at": 0, "pricing": { "linear": { "base": 500, "word": 0 } } } },
"0000000000000000000000000000000000000007": { "balance": "1", "builtin": { "name": "alt_bn128_mul", "activate_at": 0, "pricing": { "linear": { "base": 40000, "word": 0 } } } },
"0000000000000000000000000000000000000008": { "balance": "1", "builtin": { "name": "alt_bn128_pairing", "activate_at": 0, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } },
"9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" },
"0000000000000000000000000000000000000042": {
"balance": "1",
"constructor": "6060604052341561000f57600080fd5b6102b88061001e6000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063f91c289814610046575b600080fd5b341561005157600080fd5b610086600480803590602001908201803590602001919091929080359060200190820180359060200191909192905050610125565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156100cd5780820151818401526020810190506100b2565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561010f5780820151818401526020810190506100f4565b5050505090500194505050505060405180910390f35b61012d610264565b610135610278565b61013d610278565b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561018d57600080fd5b85859050888890501415156101a157600080fd5b878790506040518059106101b25750595b90808252806020026020018201604052509150600090505b815181101561021d5785858281811015156101e157fe5b9050602002013561ffff166103e80161ffff16828281518110151561020257fe5b906020019060200201818152505080806001019150506101ca565b878783828280806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050915090915093509350505094509492505050565b602060405190810160405280600081525090565b6020604051908101604052806000815250905600a165627a7a723058201da0f164e75517fb8baf51f030b904032cb748334938e7386f63025bfb23f3de0029"
}
}
}

View File

@ -0,0 +1,29 @@
[
{
"constant": false,
"inputs": [
{
"name": "benefactors",
"type": "address[]"
},
{
"name": "kind",
"type": "uint16[]"
}
],
"name": "reward",
"outputs": [
{
"name": "",
"type": "address[]"
},
{
"name": "",
"type": "uint256[]"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
]

View File

@ -27,6 +27,8 @@ use account_provider::AccountProvider;
use block::*;
use client::EngineClient;
use engines::{Engine, Seal, EngineError, ConstructedVerifier};
use engines::block_reward;
use engines::block_reward::{BlockRewardContract, RewardKind};
use error::{Error, BlockError};
use ethjson;
use machine::{AuxiliaryData, Call, EthereumMachine};
@ -68,6 +70,10 @@ 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>,
/// Number of accepted uncles transition block.
pub maximum_uncle_count_transition: u64,
/// Number of accepted uncles.
@ -95,6 +101,8 @@ 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: p.block_reward_contract_address.map(BlockRewardContract::new),
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)),
@ -388,6 +396,8 @@ pub struct AuthorityRound {
epoch_manager: Mutex<EpochManager>,
immediate_transitions: bool,
block_reward: U256,
block_reward_contract_transition: u64,
block_reward_contract: Option<BlockRewardContract>,
maximum_uncle_count_transition: u64,
maximum_uncle_count: usize,
empty_steps_transition: u64,
@ -620,6 +630,8 @@ impl AuthorityRound {
epoch_manager: Mutex::new(EpochManager::blank()),
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,
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,
@ -970,9 +982,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> {
use parity_machine::WithBalances;
let mut rewards = Vec::new();
let mut benefactors = 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
@ -998,17 +1008,33 @@ impl Engine<EthereumMachine> for AuthorityRound {
for empty_step in empty_steps {
let author = empty_step.author()?;
rewards.push((author, self.block_reward));
benefactors.push((author, RewardKind::EmptyStep));
}
}
let author = *block.header().author();
rewards.push((author, self.block_reward));
benefactors.push((author, RewardKind::Author));
for &(ref author, ref block_reward) in rewards.iter() {
self.machine.add_balance(block, author, block_reward)?;
}
self.machine.note_rewards(block, &rewards, &[])
let rewards = match self.block_reward_contract {
Some(ref c) if block.header().number() >= self.block_reward_contract_transition => {
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))
};
c.reward(&benefactors, &mut call)?
},
_ => {
benefactors.into_iter().map(|(author, _)| (author, self.block_reward)).collect()
},
};
block_reward::apply_block_rewards(&rewards, block, &self.machine)
}
/// Check the number of seal fields.
@ -1521,6 +1547,8 @@ 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(),
};
let aura = {
@ -1563,6 +1591,8 @@ 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(),
};
let aura = {
@ -1617,6 +1647,8 @@ 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(),
};
let mut c_params = ::spec::CommonParams::default();
@ -1894,4 +1926,71 @@ mod tests {
_ => false,
});
}
#[test]
fn block_reward_contract() {
let spec = Spec::new_test_round_block_reward_contract();
let tap = Arc::new(AccountProvider::transient_provider());
let addr1 = tap.insert_account(keccak("1").into(), "1").unwrap();
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let client = generate_dummy_client_with_spec_and_accounts(
Spec::new_test_round_block_reward_contract,
None,
);
engine.register_client(Arc::downgrade(&client) as _);
// step 2
let b1 = OpenBlock::new(
engine,
Default::default(),
false,
db1,
&genesis_header,
last_hashes.clone(),
addr1,
(3141562.into(), 31415620.into()),
vec![],
false,
).unwrap();
let b1 = b1.close_and_lock();
// since the block is empty it isn't sealed and we generate empty steps
engine.set_signer(tap.clone(), addr1, "1".into());
assert_eq!(engine.generate_seal(b1.block(), &genesis_header), Seal::None);
engine.step();
// step 3
// the signer of the accumulated empty step message should be rewarded
let b2 = OpenBlock::new(
engine,
Default::default(),
false,
db2,
&genesis_header,
last_hashes.clone(),
addr1,
(3141562.into(), 31415620.into()),
vec![],
false,
).unwrap();
let addr1_balance = b2.block().state().balance(&addr1).unwrap();
// after closing the block `addr1` should be reward twice, one for the included empty step
// message and another for block creation
let b2 = b2.close_and_lock();
// the contract rewards (1000 + kind) for each benefactor/reward kind
assert_eq!(
b2.block().state().balance(&addr1).unwrap(),
addr1_balance + (1000 + 0).into() + (1000 + 2).into(),
)
}
}

View File

@ -0,0 +1,184 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use ethabi;
use ethabi::ParamType;
use ethereum_types::{H160, Address, U256};
use block::ExecutedBlock;
use error::Error;
use machine::EthereumMachine;
use super::SystemCall;
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,
/// Reward attributed to the author(s) of empty step(s) included in the block (AuthorityRound engine).
EmptyStep = 2,
}
impl From<RewardKind> for u16 {
fn from(reward_kind: RewardKind) -> Self {
reward_kind as u16
}
}
/// A client for the block reward contract.
pub struct BlockRewardContract {
/// Address of the contract.
address: Address,
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 {
BlockRewardContract {
address,
block_reward_contract: block_reward_contract::BlockReward::default(),
}
}
/// Calls the block reward contract with the given benefactors 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,
) -> 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)),
);
let output = caller(self.address, input)
.map_err(Into::into)
.map_err(::engines::EngineError::FailedSystemCall)?;
// since this is a non-constant call we can't use ethabi's function output
// deserialization, sadness ensues.
let types = &[
ParamType::Array(Box::new(ParamType::Address)),
ParamType::Array(Box::new(ParamType::Uint(256))),
];
let tokens = ethabi::decode(types, &output)
.map_err(|err| err.to_string())
.map_err(::engines::EngineError::FailedSystemCall)?;
assert!(tokens.len() == 2);
let addresses = tokens[0].clone().to_array().expect("type checked by ethabi::decode; qed");
let rewards = tokens[1].clone().to_array().expect("type checked by ethabi::decode; qed");
if addresses.len() != rewards.len() {
return Err(::engines::EngineError::FailedSystemCall(
"invalid data returned by reward contract: both arrays must have the same size".into()
).into());
}
let addresses = addresses.into_iter().map(|t| t.to_address().expect("type checked by ethabi::decode; qed"));
let rewards = rewards.into_iter().map(|t| t.to_uint().expect("type checked by ethabi::decode; qed"));
Ok(addresses.zip(rewards).collect())
}
}
/// Applies the given block rewards, i.e. adds the given balance to each benefactors' address.
/// If tracing is enabled the operations are recorded.
pub fn apply_block_rewards(rewards: &[(Address, U256)], block: &mut ExecutedBlock, machine: &EthereumMachine) -> Result<(), Error> {
use parity_machine::WithBalances;
for &(ref author, ref block_reward) in rewards {
machine.add_balance(block, author, block_reward)?;
}
machine.note_rewards(block, &rewards, &[])
}
#[cfg(test)]
mod test {
use client::PrepareOpenBlock;
use ethereum_types::U256;
use spec::Spec;
use test_helpers::generate_dummy_client_with_spec_and_accounts;
use super::{BlockRewardContract, RewardKind};
#[test]
fn block_reward_contract() {
let client = generate_dummy_client_with_spec_and_accounts(
Spec::new_test_round_block_reward_contract,
None,
);
let machine = Spec::new_test_machine();
// the spec has a block reward contract defined at the given address
let block_reward_contract = BlockRewardContract::new(
"0000000000000000000000000000000000000042".into(),
);
let mut call = |to, data| {
let mut block = client.prepare_open_block(
"0000000000000000000000000000000000000001".into(),
(3141562.into(), 31415620.into()),
vec![],
);
let result = machine.execute_as_system(
block.block_mut(),
to,
U256::max_value(),
Some(data),
);
result.map_err(|e| format!("{}", e))
};
// if no benefactors 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![
("0000000000000000000000000000000000000033".into(), RewardKind::Author),
("0000000000000000000000000000000000000034".into(), RewardKind::Uncle),
("0000000000000000000000000000000000000035".into(), RewardKind::EmptyStep),
];
let rewards = block_reward_contract.reward(&benefactors, &mut call).unwrap();
let expected = vec![
("0000000000000000000000000000000000000033".into(), U256::from(1000)),
("0000000000000000000000000000000000000034".into(), U256::from(1000 + 1)),
("0000000000000000000000000000000000000035".into(), U256::from(1000 + 2)),
];
assert_eq!(expected, rewards);
}
}

View File

@ -18,6 +18,7 @@
mod authority_round;
mod basic_authority;
mod block_reward;
mod instant_seal;
mod null_engine;
mod signer;
@ -56,7 +57,7 @@ use ethereum_types::{H256, U256, Address};
use unexpected::{Mismatch, OutOfBounds};
use bytes::Bytes;
/// Default EIP-210 contrat code.
/// Default EIP-210 contract code.
/// As defined in https://github.com/ethereum/EIPs/pull/210
pub const DEFAULT_BLOCKHASH_CONTRACT: &'static str = "73fffffffffffffffffffffffffffffffffffffffe33141561006a5760014303600035610100820755610100810715156100455760003561010061010083050761010001555b6201000081071515610064576000356101006201000083050761020001555b5061013e565b4360003512151561008457600060405260206040f361013d565b61010060003543031315156100a857610100600035075460605260206060f361013c565b6101006000350715156100c55762010000600035430313156100c8565b60005b156100ea576101006101006000350507610100015460805260206080f361013b565b620100006000350715156101095763010000006000354303131561010c565b60005b1561012f57610100620100006000350507610200015460a052602060a0f361013a565b600060c052602060c0f35b5b5b5b5b";
@ -119,6 +120,9 @@ pub enum Seal {
None,
}
/// 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;
/// Type alias for a function we can get headers by hash through.
pub type Headers<'a, H> = Fn(H256) -> Option<H> + 'a;

View File

@ -38,9 +38,7 @@ pub use self::simple_list::SimpleList;
use self::contract::ValidatorContract;
use self::safe_contract::ValidatorSafeContract;
use self::multi::Multi;
/// A system-calling closure. Enacts calls on a block's state from the system address.
pub type SystemCall<'a> = FnMut(Address, Bytes) -> Result<Bytes, String> + 'a;
use super::SystemCall;
/// Creates a validator set from spec.
pub fn new_validator_set(spec: ValidatorSpec) -> Box<ValidatorSet> {

View File

@ -848,6 +848,13 @@ impl Spec {
load_bundled!("authority_round_empty_steps")
}
/// Create a new Spec with AuthorityRound consensus (with empty steps) using a block reward
/// contract. The contract source code can be found at:
/// https://github.com/parity-contracts/block-reward/blob/daf7d44383b6cdb11cb6b953b018648e2b027cfb/contracts/ExampleBlockReward.sol
pub fn new_test_round_block_reward_contract() -> Self {
load_bundled!("authority_round_block_reward_contract")
}
/// Create a new Spec with Tendermint consensus which does internal sealing (not requiring
/// work).
/// Account keccak("0") and keccak("1") are a authorities.

View File

@ -16,6 +16,7 @@
//! Authority params deserialization.
use ethereum_types::Address;
use uint::Uint;
use super::ValidatorSet;
@ -43,6 +44,13 @@ pub struct AuthorityRoundParams {
/// 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 the static block reward definition).
#[serde(rename="blockRewardContractAddress")]
pub block_reward_contract_address: Option<Address>,
/// Block at which maximum uncle count should be considered.
#[serde(rename="maximumUncleCountTransition")]
pub maximum_uncle_count_transition: Option<Uint>,