Skip to content

Commit

Permalink
EIP-1559 support (#429)
Browse files Browse the repository at this point in the history
* Add `pallet-base-fee`

* WIP pallet-ethereum changes

* Rpc wips: send_raw_transaction

* Rpc wips: send_transaction

* More

* Rework for ethereum 0.9.0

* Rollback package-lock.json..

* Fix typed transaction encoding and hashing

* Add ethers dep and init provider

* Typed transaction basic test

* editorconfig

* Reintroduce `pallet-base-fee`

* Update `pallet-ethereum` tests

* `pallet-base-fee` work + integration tests

* Use `pallet_evm::FeeCalculator` trait

* Add runtime api call/create version

* Update runner (breaks api)

* Update CallRequest + eth_call/estimate_gas

* Update ts-tests

* rpc: post-eip1559 blocks include `baseFeePerGas`

* rpc: calculate `gasPrice` for post-eip1559 txns

* Do not serialize 1559 fields in pre-1559 txns

* Add eip helper to `StorageOverride` trait

* rpc: add `effectiveGasPrice` to receipt

* Fix package.json

* fmt

* Customize `ethereum_schema_cache_task` version from service

* Fix integration tests

* `EthDevSigner` fix `odd_y_parity`

* Replicate integration tests for each txn type

* Default gas_price/fee_per_gas in `sign_transaction`

* Remove todo comments

* Oops

* Introduce `OnChargeEVMTransaction::pay_priority_fee`

* Fix warnings

* Add test for priority tip

* fmt

* Fix fees / priority + test

* Comment fee handling in pallet-evm runner

* Set defaults for `pallet-base-fee` storage

* Rename `Modifier` to `Elasticity` + move it to storage + dispatchable

* fmt

* `pallet-base-fee` dispatchables integration tests

* WIP Bump ethereum + evm version

* Handle `access_list`

* Oops

* fmt

* Fix test-balance test

* Bump evm version to 0.32.0

* fmt

* Warning cleanup

* Oops rollback package.json

* Fix test

* Fix `gas_limit` on `eth_sendTransaction`

* Implement `is_cold` / `is_storage_cold`

* Err when no chain id for eth_sendTransaction

* Move fee details logic to own function

* Safer match `base_fee`

* Just evaluate and return

* Cleaner map into

* Fix priority for legacy transactions

* Safer check over gas_price

* fmt

* Fix priority in tests

* Bump evm 0.33.0

* Update pallet-evm test

* Remove std feature gate on rpc-core
  • Loading branch information
tgmichel authored Nov 10, 2021
1 parent 7be5145 commit bcae569
Show file tree
Hide file tree
Showing 78 changed files with 3,753 additions and 1,108 deletions.
649 changes: 305 additions & 344 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client/consensus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fc-db = { version = "2.0.0-dev", path = "../db" }
sp-consensus = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate" }
sc-consensus = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate" }
log = "0.4.8"
futures = { version = "0.3.1", features = ["compat"] }
futures = { version = "0.3.17", features = ["compat"] }
sp-timestamp = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate" }
derive_more = "0.99.2"
prometheus-endpoint = { version = "0.9.0", package = "substrate-prometheus-endpoint", git = "https://github.com/paritytech/substrate" }
Expand Down
5 changes: 4 additions & 1 deletion client/rpc-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ jsonrpc-core-client = "18.0"
jsonrpc-derive = "18.0"
jsonrpc-pubsub = "18.0"
rustc-hex = "2.1.0"
ethereum-types = "0.12.0"
ethereum = { version = "0.10.0", features = ["with-codec"] }
sha3 = "0.8"
ethereum-types = "0.12"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
rlp = "0.5"
3 changes: 3 additions & 0 deletions client/rpc-core/src/types/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ pub struct Block {
pub transactions: BlockTransactions,
/// Size in bytes
pub size: Option<U256>,
/// Base Fee for post-EIP1559 blocks.
#[serde(skip_serializing_if = "Option::is_none")]
pub base_fee_per_gas: Option<U256>,
}

/// Block header representation.
Expand Down
4 changes: 4 additions & 0 deletions client/rpc-core/src/types/call_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ pub struct CallRequest {
pub to: Option<H160>,
/// Gas Price
pub gas_price: Option<U256>,
/// EIP-1559 Max base fee the caller is willing to pay
pub max_fee_per_gas: Option<U256>,
/// EIP-1559 Priority fee the caller is paying to the block author
pub max_priority_fee_per_gas: Option<U256>,
/// Gas
pub gas: Option<U256>,
/// Value
Expand Down
2 changes: 1 addition & 1 deletion client/rpc-core/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,6 @@ pub use self::{
Peers, PipProtocolInfo, SyncInfo, SyncStatus, TransactionStats,
},
transaction::{LocalTransactionStatus, RichRawTransaction, Transaction},
transaction_request::TransactionRequest,
transaction_request::{TransactionMessage, TransactionRequest},
work::Work,
};
2 changes: 2 additions & 0 deletions client/rpc-core/src/types/receipt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,6 @@ pub struct Receipt {
// NOTE(niklasad1): Unknown after EIP98 rules, if it's missing then skip serializing it
#[serde(skip_serializing_if = "Option::is_none", rename = "status")]
pub status_code: Option<U64>,
/// Effective gas price. Pre-eip1559 this is just the gasprice. Post-eip1559 this is base fee + priority fee.
pub effective_gas_price: U256,
}
95 changes: 94 additions & 1 deletion client/rpc-core/src/types/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use crate::types::Bytes;
use ethereum::{AccessListItem, TransactionV2};
use ethereum_types::{H160, H256, H512, U256, U64};
use serde::{ser::SerializeStruct, Serialize, Serializer};

Expand All @@ -41,7 +42,14 @@ pub struct Transaction {
/// Transfered value
pub value: U256,
/// Gas Price
pub gas_price: U256,
#[serde(skip_serializing_if = "Option::is_none")]
pub gas_price: Option<U256>,
/// Max BaseFeePerGas the user is willing to pay.
#[serde(skip_serializing_if = "Option::is_none")]
pub max_fee_per_gas: Option<U256>,
/// The miner's tip.
#[serde(skip_serializing_if = "Option::is_none")]
pub max_priority_fee_per_gas: Option<U256>,
/// Gas
pub gas: U256,
/// Data
Expand All @@ -62,6 +70,91 @@ pub struct Transaction {
pub r: U256,
/// The S field of the signature.
pub s: U256,
/// Pre-pay to warm storage access.
#[cfg_attr(feature = "std", serde(skip_serializing_if = "Option::is_none"))]
pub access_list: Option<Vec<AccessListItem>>,
}

impl From<TransactionV2> for Transaction {
fn from(transaction: TransactionV2) -> Self {
let serialized = rlp::encode(&transaction);
let hash = transaction.hash();
let raw = Bytes(serialized.to_vec());
match transaction {
TransactionV2::Legacy(t) => Transaction {
hash,
nonce: t.nonce,
block_hash: None,
block_number: None,
transaction_index: None,
from: H160::default(),
to: None,
value: t.value,
gas_price: Some(t.gas_price),
max_fee_per_gas: Some(t.gas_price),
max_priority_fee_per_gas: Some(t.gas_price),
gas: t.gas_limit,
input: Bytes(t.clone().input),
creates: None,
raw,
public_key: None,
chain_id: t.signature.chain_id().map(U64::from),
standard_v: U256::from(t.signature.standard_v()),
v: U256::from(t.signature.v()),
r: U256::from(t.signature.r().as_bytes()),
s: U256::from(t.signature.s().as_bytes()),
access_list: None,
},
TransactionV2::EIP2930(t) => Transaction {
hash,
nonce: t.nonce,
block_hash: None,
block_number: None,
transaction_index: None,
from: H160::default(),
to: None,
value: t.value,
gas_price: Some(t.gas_price),
max_fee_per_gas: Some(t.gas_price),
max_priority_fee_per_gas: Some(t.gas_price),
gas: t.gas_limit,
input: Bytes(t.clone().input),
creates: None,
raw,
public_key: None,
chain_id: Some(U64::from(t.chain_id)),
standard_v: U256::from(t.odd_y_parity as u8),
v: U256::from(t.odd_y_parity as u8),
r: U256::from(t.r.as_bytes()),
s: U256::from(t.s.as_bytes()),
access_list: Some(t.access_list),
},
TransactionV2::EIP1559(t) => Transaction {
hash,
nonce: t.nonce,
block_hash: None,
block_number: None,
transaction_index: None,
from: H160::default(),
to: None,
value: t.value,
gas_price: None,
max_fee_per_gas: Some(t.max_fee_per_gas),
max_priority_fee_per_gas: Some(t.max_priority_fee_per_gas),
gas: t.gas_limit,
input: Bytes(t.clone().input),
creates: None,
raw,
public_key: None,
chain_id: Some(U64::from(t.chain_id)),
standard_v: U256::from(t.odd_y_parity as u8),
v: U256::from(t.odd_y_parity as u8),
r: U256::from(t.r.as_bytes()),
s: U256::from(t.s.as_bytes()),
access_list: Some(t.access_list),
},
}
}
}

/// Local Transaction Status
Expand Down
92 changes: 90 additions & 2 deletions client/rpc-core/src/types/transaction_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,18 @@
//! `TransactionRequest` type
use crate::types::Bytes;
use ethereum_types::{H160, U256};
use ethereum::{
AccessListItem, EIP1559TransactionMessage, EIP2930TransactionMessage, LegacyTransactionMessage,
};
use ethereum_types::{H160, H256, U256};
use serde::{Deserialize, Serialize};

pub enum TransactionMessage {
Legacy(LegacyTransactionMessage),
EIP2930(EIP2930TransactionMessage),
EIP1559(EIP1559TransactionMessage),
}

/// Transaction request coming from RPC
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
Expand All @@ -31,8 +40,15 @@ pub struct TransactionRequest {
pub from: Option<H160>,
/// Recipient
pub to: Option<H160>,
/// Gas Price
/// Gas Price, legacy.
#[serde(default)]
pub gas_price: Option<U256>,
/// Max BaseFeePerGas the user is willing to pay.
#[serde(default)]
pub max_fee_per_gas: Option<U256>,
/// The miner's tip.
#[serde(default)]
pub max_priority_fee_per_gas: Option<U256>,
/// Gas
pub gas: Option<U256>,
/// Value of transaction in wei
Expand All @@ -41,4 +57,76 @@ pub struct TransactionRequest {
pub data: Option<Bytes>,
/// Transaction's nonce
pub nonce: Option<U256>,
/// TODO! Pre-pay to warm storage access.
#[serde(default)]
pub access_list: Option<Vec<(H160, Vec<H256>)>>,
}

impl Into<Option<TransactionMessage>> for TransactionRequest {
fn into(self) -> Option<TransactionMessage> {
match (
self.gas_price,
self.max_fee_per_gas,
self.access_list.clone(),
) {
// Legacy
(Some(_), None, None) => Some(TransactionMessage::Legacy(LegacyTransactionMessage {
nonce: U256::zero(),
gas_price: self.gas_price.unwrap_or_default(),
gas_limit: self.gas.unwrap_or_default(),
value: self.value.unwrap_or(U256::zero()),
input: self.data.map(|s| s.into_vec()).unwrap_or_default(),
action: match self.to {
Some(to) => ethereum::TransactionAction::Call(to),
None => ethereum::TransactionAction::Create,
},
chain_id: None,
})),
// EIP2930
(_, None, Some(_)) => Some(TransactionMessage::EIP2930(EIP2930TransactionMessage {
nonce: U256::zero(),
gas_price: self.gas_price.unwrap_or_default(),
gas_limit: self.gas.unwrap_or_default(),
value: self.value.unwrap_or(U256::zero()),
input: self.data.map(|s| s.into_vec()).unwrap_or_default(),
action: match self.to {
Some(to) => ethereum::TransactionAction::Call(to),
None => ethereum::TransactionAction::Create,
},
chain_id: 0,
access_list: self
.access_list
.unwrap()
.into_iter()
.map(|(address, slots)| AccessListItem { address, slots })
.collect(),
})),
// EIP1559
(None, Some(_), _) | (None, None, None) => {
// Empty fields fall back to the canonical transaction schema.
Some(TransactionMessage::EIP1559(EIP1559TransactionMessage {
nonce: U256::zero(),
max_fee_per_gas: self.max_fee_per_gas.unwrap_or_default(),
max_priority_fee_per_gas: self
.max_priority_fee_per_gas
.unwrap_or(U256::from(0)),
gas_limit: self.gas.unwrap_or_default(),
value: self.value.unwrap_or(U256::zero()),
input: self.data.map(|s| s.into_vec()).unwrap_or_default(),
action: match self.to {
Some(to) => ethereum::TransactionAction::Call(to),
None => ethereum::TransactionAction::Create,
},
chain_id: 0,
access_list: self
.access_list
.unwrap_or(Vec::new())
.into_iter()
.map(|(address, slots)| AccessListItem { address, slots })
.collect(),
}))
}
_ => None,
}
}
}
6 changes: 3 additions & 3 deletions client/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ jsonrpc-derive = "18.0"
jsonrpc-core-client = "18.0"
jsonrpc-pubsub = "18.0"
log = "0.4.8"
ethereum-types = "0.12.0"
evm = "0.30.1"
ethereum-types = "0.12"
evm = "0.33.0"
fc-consensus = { version = "2.0.0-dev", path = "../consensus" }
fc-db = { version = "2.0.0-dev", path = "../db" }
fc-rpc-core = { version = "1.1.0-dev", path = "../rpc-core" }
Expand All @@ -35,7 +35,7 @@ sc-network = { version = "0.10.0-dev", git = "https://github.com/paritytech/subs
pallet-evm = { version = "6.0.0-dev", path = "../../frame/evm" }
fp-evm = { version = "3.0.0-dev", path = "../../primitives/evm" }
pallet-ethereum = { version = "4.0.0-dev", path = "../../frame/ethereum" }
ethereum = { version = "0.9.0", features = ["with-codec"] }
ethereum = { version = "0.10.0", features = ["with-codec"] }
codec = { package = "parity-scale-codec", version = "2.0.0" }
rlp = "0.5"
futures = { version = "0.3.1", features = ["compat"] }
Expand Down
Loading

0 comments on commit bcae569

Please sign in to comment.