Skip to content

Commit

Permalink
Split tx fee to author and governance
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewAR2 committed Nov 28, 2024
1 parent 7bd7085 commit 73c1ea5
Show file tree
Hide file tree
Showing 15 changed files with 513 additions and 59 deletions.
33 changes: 33 additions & 0 deletions crates/ethcore/res/contracts/fees.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[
{
"inputs": [],
"name": "getFeesParams",
"outputs": [
{
"internalType": "address",
"name": "addr",
"type": "address"
},
{
"internalType": "uint256",
"name": "percent",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getGasPrice",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]
36 changes: 36 additions & 0 deletions crates/ethcore/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,17 @@ use types::{
transaction::{Error as TransactionError, SignedTransaction},
};

use crate::{executive::FeesParams};

/// Block that is ready for transactions to be added.
///
/// It's a bit like a Vec<Transaction>, except that whenever a transaction is pushed, we execute it and
/// maintain the system `state()`. We also archive execution receipts in preparation for later block creation.
pub struct OpenBlock<'x> {
block: ExecutedBlock,
engine: &'x dyn EthEngine,
gas_price: Option<U256>,
fees_params: Option<FeesParams>,
}

/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
Expand Down Expand Up @@ -188,6 +192,8 @@ impl<'x> OpenBlock<'x> {
let mut r = OpenBlock {
block: ExecutedBlock::new(state, last_hashes, tracing),
engine: engine,
gas_price: None,
fees_params: None,
};

r.block.header.set_parent_hash(parent.hash());
Expand Down Expand Up @@ -218,6 +224,9 @@ impl<'x> OpenBlock<'x> {
engine.machine().on_new_block(&mut r.block)?;
engine.on_new_block(&mut r.block, is_epoch_begin, &mut ancestry.into_iter())?;

r.update_gas_price();
r.update_fees_params();

Ok(r)
}

Expand Down Expand Up @@ -282,6 +291,7 @@ impl<'x> OpenBlock<'x> {
let outcome = self.block.state.apply(
&env_info,
self.engine.machine(),
self.fees_params,
&t,
self.block.traces.is_enabled(),
)?;
Expand All @@ -301,6 +311,30 @@ impl<'x> OpenBlock<'x> {
.expect("receipt just pushed; qed"))
}

/// Returns gas price getted from from contract during block creation
pub fn get_current_gas_price(&self) -> Option<U256> {
self.gas_price
}

/// Gets the current gas price from the fees contract.
fn update_gas_price(&mut self) {
if let Some(price) = self.engine.get_gas_price(&self.block.header) {
self.gas_price = Some(price);
}
}

/// Get the current fees params from the fees contract.
pub fn get_fees_params(&self) -> Option<FeesParams> {
self.fees_params
}

/// Get the current fees params from the fees contract.
fn update_fees_params(&mut self) {
if let Some(params) = self.engine.get_fee_params(&self.block.header) {
self.fees_params = Some(params);
}
}

/// Push transactions onto the block.
#[cfg(not(feature = "slow-blocks"))]
fn push_transactions(&mut self, transactions: Vec<SignedTransaction>) -> Result<(), Error> {
Expand Down Expand Up @@ -456,6 +490,8 @@ impl ClosedBlock {
OpenBlock {
block: block,
engine: engine,
gas_price: None,
fees_params: None,
}
}
}
Expand Down
19 changes: 17 additions & 2 deletions crates/ethcore/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,10 @@ impl Importer {
receipts: Some(&receipts),
};

match self.engine.signals_epoch_end(header, auxiliary, self.engine.machine()) {
match self
.engine
.signals_epoch_end(header, auxiliary, self.engine.machine())
{
EpochChange::Yes(proof) => {
use engines::Proof;
let proof = match proof {
Expand Down Expand Up @@ -841,7 +844,7 @@ impl Importer {
let machine = self.engine.machine();
let schedule = machine.schedule(env_info.number);
let res = Executive::new(&mut state, &env_info, &machine, &schedule)
.transact(&transaction, options);
.transact(&transaction, options, None);

let res = match res {
Err(e) => {
Expand Down Expand Up @@ -2086,6 +2089,7 @@ impl Call for Client {
let mut clone = state.clone();
let machine = self.engine.machine();
let schedule = machine.schedule(env_info.number);
// fees_params is None because they have no influence on gas
Executive::new(&mut clone, &env_info, &machine, &schedule)
.transact_virtual(&tx, options())
};
Expand Down Expand Up @@ -2825,6 +2829,10 @@ impl BlockChainClient for Client {
fn state_data(&self, hash: &H256) -> Option<Bytes> {
self.state_db.read().journal_db().state(hash)
}

fn latest_state_and_header_external(&self) -> (State<StateDB>, Header) {
self.latest_state_and_header()
}
}

impl IoClient for Client {
Expand Down Expand Up @@ -3154,6 +3162,13 @@ impl super::traits::EngineClient for Client {
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
<dyn BlockChainClient>::block_header(self, id)
}

fn proxy_call(&self, transaction: &SignedTransaction, analytics: CallAnalytics, state: &mut State<StateDB>, header: &Header) -> Option<Bytes> {
match self.call(transaction, analytics, state, header) {
Ok(executed) => Some(executed.output),
Err(_) => None,
}
}
}

impl ProvingBlockChainClient for Client {
Expand Down
10 changes: 9 additions & 1 deletion crates/ethcore/src/client/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ use engines::EthEngine;
use error::{Error, EthcoreResult};
use executed::CallError;
use executive::Executed;
use state::StateInfo;
use state::{StateInfo, State};
use trace::LocalizedTrace;
use verification::queue::{kind::blocks::Unverified, QueueInfo as BlockQueueInfo};

use crate::state_db::StateDB;

/// State information to be used during client query
pub enum StateOrBlock {
/// State to be used, may be pending
Expand Down Expand Up @@ -490,6 +492,9 @@ pub trait BlockChainClient:

/// Returns true, if underlying import queue is processing possible fork at the moment
fn is_processing_fork(&self) -> bool;

/// Returns latest known state and header. Created only to get gas price on the verification stage.
fn latest_state_and_header_external(&self) -> (State<StateDB>, Header);
}

/// The data required for a `Client` to create a transaction.
Expand Down Expand Up @@ -617,6 +622,9 @@ pub trait EngineClient: Sync + Send + ChainInfo {

/// Get raw block header data by block id.
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;

/// Proxy to the Client::call to use in engine. Added to get gas_price.
fn proxy_call(&self, transaction: &SignedTransaction, analytics: CallAnalytics, state: &mut State<StateDB>, header: &Header) -> Option<Bytes>;
}

/// Extended client interface for providing proofs of the state.
Expand Down
39 changes: 39 additions & 0 deletions crates/ethcore/src/engines/authority_round/block_gas_price.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity Ethereum.

// Parity Ethereum 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 Ethereum 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 Ethereum. If not, see <http://www.gnu.org/licenses/>.

//! A client interface for interacting with the block gas limit contract.
use client::{BlockChainClient, BlockId};
use types::header::Header;
use ethabi::FunctionOutputDecoder;
use ethabi_contract::use_contract;
use ethereum_types::{Address, U256};
use log::{debug, error};

use_contract!(contract, "res/contracts/fees.json");

pub fn block_gas_price(full_client: &dyn BlockChainClient, header: &Header, address: Address) -> Option<U256> {
let (data, decoder) = contract::functions::get_gas_price::call();
let value = full_client.call_contract(BlockId::Hash(*header.parent_hash()), address, data).map_err(|err| {
error!(target: "fees", "Contract call failed. Not changing the block gas price. {:?}", err);
}).ok()?;
if value.is_empty() {
debug!(target: "fees", "Contract call returned nothing. Not changing the block gas price.");
None
} else {
decoder.decode(&value).ok()
}
}
53 changes: 53 additions & 0 deletions crates/ethcore/src/engines/authority_round/block_tx_fee.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity Ethereum.

// Parity Ethereum 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 Ethereum 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 Ethereum. If not, see <http://www.gnu.org/licenses/>.

//! A client interface for interacting with the block gas limit contract.
use client::{BlockChainClient, BlockId};
use types::header::Header;
use ethabi::{self, ParamType};
use ethabi_contract::use_contract;
use ethereum_types::{Address};
use log::{debug, error};
use crate::executive::FeesParams;

use_contract!(contract, "res/contracts/fees.json");

pub fn block_tx_fee(full_client: &dyn BlockChainClient, header: &Header, address: Address) -> Option<FeesParams> {
let (data, _decoder) = contract::functions::get_fees_params::call();
let output = full_client.call_contract(BlockId::Hash(*header.parent_hash()), address, data).map_err(|err| {
error!(target: "fees", "Contract call failed. Not changing the tx fee params. {:?}", err);
}).ok()?;
if output.is_empty() {
debug!(target: "fees", "Contract call returned nothing. Not changing the tx fee params.");
None
} else {
let types = &[
ParamType::Address,
ParamType::Uint(256),
];

let tokens = ethabi::decode(types, &output).ok()?;

assert!(tokens.len() == 2);

let params = FeesParams {
address: tokens[0].clone().to_address().unwrap(),
governance_part: tokens[1].clone().to_uint().unwrap(),
};
Some(params)
}
}
Loading

0 comments on commit 73c1ea5

Please sign in to comment.