Skip to content

Commit

Permalink
Block reward contract (openethereum#8419)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
andresilva authored and VladLupashevskyi committed May 23, 2018
1 parent 7e9466a commit 47103c4
Show file tree
Hide file tree
Showing 9 changed files with 412 additions and 22 deletions.
18 changes: 9 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 61 additions & 0 deletions ethcore/res/authority_round_block_reward_contract.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
29 changes: 29 additions & 0 deletions ethcore/res/contracts/block_reward.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
117 changes: 108 additions & 9 deletions ethcore/src/engines/authority_round/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)),
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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));

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))
};

for &(ref author, ref block_reward) in rewards.iter() {
self.machine.add_balance(block, author, block_reward)?;
}
self.machine.note_rewards(block, &rewards, &[])
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.
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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(),
)
}
}
Loading

0 comments on commit 47103c4

Please sign in to comment.