Skip to content

Commit af1e5c6

Browse files
authored
Pass all London tests (#377)
* New TransactGasPrice struct and implement pre-EIP1559 * Implement EIP-1559 * Pass all London tests * Run cargo fmt
1 parent 02c402a commit af1e5c6

File tree

9 files changed

+177
-58
lines changed

9 files changed

+177
-58
lines changed

fuzz/src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ fn main() {
8787
caller: H160::from_low_u64_be(1),
8888
value: U256::zero(),
8989
gas_limit,
90-
gas_price,
90+
gas_price: gas_price.into(),
9191
access_list: vec![],
9292
config: &config,
9393
};
@@ -119,7 +119,7 @@ fn main() {
119119
caller: H160::from_low_u64_be(1),
120120
value: U256::zero(),
121121
gas_limit,
122-
gas_price,
122+
gas_price: gas_price.into(),
123123
access_list: vec![],
124124
config: &config,
125125
};
@@ -143,7 +143,7 @@ fn main() {
143143
caller: user_address,
144144
value: U256::zero(),
145145
gas_limit,
146-
gas_price,
146+
gas_price: gas_price.into(),
147147
access_list: vec![],
148148
config: &config,
149149
};

jsontests/src/run.rs

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::{
77
use evm::{
88
backend::{InMemoryAccount, InMemoryBackend, InMemoryEnvironment, OverlayedBackend},
99
interpreter::{Capture, runtime::GasState},
10-
standard::{Config, TransactArgs, TransactArgsCallCreate},
10+
standard::{Config, TransactArgs, TransactArgsCallCreate, TransactGasPrice},
1111
};
1212
use evm_mainnet::with_mainnet_invoker;
1313
use primitive_types::{H256, U256};
@@ -187,20 +187,27 @@ pub fn run_test(
187187
Fork::ConstantinopleFix => Config::petersburg(),
188188
Fork::Istanbul => Config::istanbul(),
189189
Fork::Berlin => Config::berlin(),
190+
Fork::London => Config::london(),
190191
_ => return Err(Error::UnsupportedFork),
191192
};
192193
config_change(&mut config);
193194

194-
if test.post.expect_exception == Some(TestExpectException::TR_TypeNotSupported) {
195+
match test.post.expect_exception {
195196
// The `evm` crate does not understand transaction format, only the `ethereum` crate. So
196197
// there's nothing for us to test here for `TR_TypeNotSupported`.
197-
return Ok(());
198-
}
198+
Some(TestExpectException::TR_TypeNotSupported) => return Ok(()),
199+
200+
Some(TestExpectException::TR_RLP_WRONGVALUE) if test.transaction.value.0.is_err() => {
201+
return Ok(());
202+
}
203+
204+
// The responsibility to check gas limit / gas cap is on the block executor.
205+
Some(TestExpectException::TR_FeeCapLessThanBlocks) => return Ok(()),
206+
Some(TestExpectException::TR_NoFunds) => return Ok(()),
207+
Some(TestExpectException::TR_GasLimitReached) => return Ok(()),
208+
Some(TestExpectException::TR_TipGtFeeCap) => return Ok(()),
199209

200-
if test.post.expect_exception == Some(TestExpectException::TR_RLP_WRONGVALUE)
201-
&& test.transaction.value.0.is_err()
202-
{
203-
return Ok(());
210+
_ => (),
204211
}
205212

206213
let env = InMemoryEnvironment {
@@ -221,7 +228,7 @@ pub fn run_test(
221228
block_difficulty: test.env.current_difficulty,
222229
block_randomness: test.env.current_random,
223230
block_gas_limit: test.env.current_gas_limit,
224-
block_base_fee_per_gas: test.transaction.gas_price,
231+
block_base_fee_per_gas: test.env.current_base_fee.unwrap_or_default(),
225232
chain_id: U256::one(),
226233
};
227234

@@ -249,6 +256,18 @@ pub fn run_test(
249256
})
250257
.collect::<BTreeMap<_, _>>();
251258

259+
let gas_price = if let Some(gas_price) = test.transaction.gas_price {
260+
TransactGasPrice::Legacy(gas_price)
261+
} else {
262+
TransactGasPrice::FeeMarket {
263+
max_priority: test
264+
.transaction
265+
.max_priority_fee_per_gas
266+
.unwrap_or_default(),
267+
max: test.transaction.max_fee_per_gas.unwrap_or_default(),
268+
}
269+
};
270+
252271
let args = if let Some(to) = test.transaction.to {
253272
TransactArgs {
254273
call_create: TransactArgsCallCreate::Call {
@@ -262,7 +281,7 @@ pub fn run_test(
262281
.0
263282
.map_err(|()| TestError::UnexpectedDecoding)?,
264283
gas_limit: test.transaction.gas_limit,
265-
gas_price: test.transaction.gas_price,
284+
gas_price,
266285
access_list: test
267286
.transaction
268287
.access_list
@@ -285,7 +304,7 @@ pub fn run_test(
285304
.0
286305
.map_err(|()| TestError::UnexpectedDecoding)?,
287306
gas_limit: test.transaction.gas_limit,
288-
gas_price: test.transaction.gas_price,
307+
gas_price,
289308
access_list: test
290309
.transaction
291310
.access_list
@@ -393,9 +412,9 @@ pub fn run_test(
393412
transaction: TestMultiTransaction {
394413
data: vec![HexBytes(test.transaction.data)],
395414
gas_limit: vec![test.transaction.gas_limit],
396-
gas_price: Some(test.transaction.gas_price),
397-
max_fee_per_gas: None,
398-
max_priority_fee_per_gas: test.transaction.gas_priority_fee,
415+
gas_price: test.transaction.gas_price,
416+
max_fee_per_gas: test.transaction.max_fee_per_gas,
417+
max_priority_fee_per_gas: test.transaction.max_priority_fee_per_gas,
399418
nonce: test.transaction.nonce,
400419
secret_key: test.transaction.secret_key,
401420
sender: test.transaction.sender,

jsontests/src/types.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,9 @@ impl TestMulti {
9292
transaction: TestTransaction {
9393
data: self.transaction.data[post_state.indexes.data].0.clone(),
9494
gas_limit: self.transaction.gas_limit[post_state.indexes.gas],
95-
gas_price: self
96-
.transaction
97-
.gas_price
98-
.unwrap_or(self.env.current_base_fee.unwrap_or_default()),
99-
gas_priority_fee: self.transaction.max_priority_fee_per_gas,
95+
gas_price: self.transaction.gas_price,
96+
max_priority_fee_per_gas: self.transaction.max_priority_fee_per_gas,
97+
max_fee_per_gas: self.transaction.max_fee_per_gas,
10098
nonce: self.transaction.nonce,
10199
secret_key: self.transaction.secret_key,
102100
sender: self.transaction.sender,
@@ -315,8 +313,9 @@ pub struct TestAccessListItem {
315313
pub struct TestTransaction {
316314
pub data: Vec<u8>,
317315
pub gas_limit: U256,
318-
pub gas_price: U256,
319-
pub gas_priority_fee: Option<U256>,
316+
pub gas_price: Option<U256>,
317+
pub max_priority_fee_per_gas: Option<U256>,
318+
pub max_fee_per_gas: Option<U256>,
320319
pub nonce: U256,
321320
pub secret_key: H256,
322321
pub sender: H160,

precompile/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Standard EVM precompiles.
22
33
#![deny(warnings)]
4-
// #![forbid(unsafe_code, unused_variables)]
4+
#![forbid(unsafe_code, unused_variables)]
55
#![warn(missing_docs)]
66
#![cfg_attr(not(feature = "std"), no_std)]
77

src/backend/overlayed.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ impl<B: RuntimeBaseBackend> RuntimeBackend for OverlayedBackend<'_, B> {
268268
self.substate.touched.insert(address);
269269
}
270270
TouchKind::Coinbase => {
271+
self.substate.touched.insert(address);
271272
if self.config.eip3651_warm_coinbase_address {
272273
self.substate.accessed.insert((address, None));
273274
}

src/standard/config.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,20 @@ impl Config {
260260

261261
/// Gas paid for sstore refund.
262262
pub fn refund_sstore_clears(&self) -> i64 {
263-
15000
263+
if self.eip3529_decrease_clears_refund {
264+
4800
265+
} else {
266+
15000
267+
}
264268
}
265269

266270
/// EIP-3529
267271
pub fn max_refund_quotient(&self) -> u64 {
268-
2
272+
if self.eip3529_decrease_clears_refund {
273+
5
274+
} else {
275+
2
276+
}
269277
}
270278

271279
/// Gas paid for BALANCE opcode.

src/standard/invoker/mod.rs

Lines changed: 116 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,104 @@ pub enum TransactValueCallCreate {
7171
pub struct TransactValue {
7272
/// Call/Create status.
7373
pub call_create: TransactValueCallCreate,
74-
/// Used gas minus the refund.
75-
pub effective_gas: U256,
74+
/// Used gas.
75+
pub used_gas: U256,
76+
}
77+
78+
/// Transact gas price.
79+
#[derive(Clone, Debug, Copy, Eq, PartialEq)]
80+
pub enum TransactGasPrice {
81+
/// Legacy gas price.
82+
Legacy(U256),
83+
/// EIP-1559 fee market.
84+
FeeMarket {
85+
/// `max_priority_fee_per_gas` according to EIP-1559.
86+
max_priority: U256,
87+
/// `max_fee_per_gas` according to EIP-1559.
88+
max: U256,
89+
},
90+
}
91+
92+
impl TransactGasPrice {
93+
/// Caller fee.
94+
pub fn fee<H: RuntimeEnvironment>(
95+
&self,
96+
gas_limit: U256,
97+
config: &Config,
98+
handler: &H,
99+
) -> U256 {
100+
let effective_gas_price = self.effective_gas_price(config, handler);
101+
gas_limit.saturating_mul(effective_gas_price)
102+
}
103+
104+
/// Refunded caller fee after call.
105+
pub fn refunded_fee<H: RuntimeEnvironment>(
106+
&self,
107+
refunded_gas: U256,
108+
config: &Config,
109+
handler: &H,
110+
) -> U256 {
111+
let effective_gas_price = self.effective_gas_price(config, handler);
112+
refunded_gas.saturating_mul(effective_gas_price)
113+
}
114+
115+
/// Coinbase reward.
116+
pub fn coinbase_reward<H: RuntimeEnvironment>(
117+
&self,
118+
used_gas: U256,
119+
config: &Config,
120+
handler: &H,
121+
) -> U256 {
122+
if config.eip1559_fee_market {
123+
let max_priority = match self {
124+
Self::Legacy(gas_price) => *gas_price,
125+
Self::FeeMarket { max_priority, .. } => *max_priority,
126+
};
127+
let max = match self {
128+
Self::Legacy(gas_price) => *gas_price,
129+
Self::FeeMarket { max, .. } => *max,
130+
};
131+
let priority = min(
132+
max_priority,
133+
max.saturating_sub(handler.block_base_fee_per_gas()),
134+
);
135+
used_gas.saturating_mul(priority)
136+
} else {
137+
let effective_gas_price = self.effective_gas_price(config, handler);
138+
used_gas.saturating_mul(effective_gas_price)
139+
}
140+
}
141+
142+
/// Effective gas price as returned by `GASPRICE` opcode.
143+
pub fn effective_gas_price<H: RuntimeEnvironment>(&self, config: &Config, handler: &H) -> U256 {
144+
if config.eip1559_fee_market {
145+
let max_priority = match self {
146+
Self::Legacy(gas_price) => *gas_price,
147+
Self::FeeMarket { max_priority, .. } => *max_priority,
148+
};
149+
let max = match self {
150+
Self::Legacy(gas_price) => *gas_price,
151+
Self::FeeMarket { max, .. } => *max,
152+
};
153+
154+
let priority = min(
155+
max_priority,
156+
max.saturating_sub(handler.block_base_fee_per_gas()),
157+
);
158+
priority.saturating_add(handler.block_base_fee_per_gas())
159+
} else {
160+
match self {
161+
Self::Legacy(gas_price) => *gas_price,
162+
Self::FeeMarket { max_priority, .. } => *max_priority,
163+
}
164+
}
165+
}
166+
}
167+
168+
impl From<U256> for TransactGasPrice {
169+
fn from(gas_price: U256) -> Self {
170+
Self::Legacy(gas_price)
171+
}
76172
}
77173

78174
/// The invoke used in a top-layer transaction stack.
@@ -82,7 +178,7 @@ pub struct TransactInvoke<'config> {
82178
/// Gas limit.
83179
pub gas_limit: U256,
84180
/// Gas price.
85-
pub gas_price: U256,
181+
pub gas_price: TransactGasPrice,
86182
/// Caller.
87183
pub caller: H160,
88184
/// Config used for the transaction.
@@ -120,7 +216,7 @@ pub struct TransactArgs<'config> {
120216
/// Transaction gas limit.
121217
pub gas_limit: U256,
122218
/// Transaction gas price.
123-
pub gas_price: U256,
219+
pub gas_price: TransactGasPrice,
124220
/// Access list information, in the format of (address, storage keys).
125221
pub access_list: Vec<(H160, Vec<H256>)>,
126222
/// Config of this arg.
@@ -187,9 +283,11 @@ where
187283
> {
188284
let caller = AsRef::<TransactArgs>::as_ref(&args).caller;
189285
let gas_price = AsRef::<TransactArgs>::as_ref(&args).gas_price;
190-
let gas_fee = AsRef::<TransactArgs>::as_ref(&args)
191-
.gas_limit
192-
.saturating_mul(gas_price);
286+
let gas_fee = gas_price.fee(
287+
AsRef::<TransactArgs>::as_ref(&args).gas_limit,
288+
AsRef::<TransactArgs>::as_ref(&args).config,
289+
handler,
290+
);
193291
let coinbase = handler.block_coinbase();
194292

195293
let address = match &AsRef::<TransactArgs>::as_ref(&args).call_create {
@@ -225,6 +323,8 @@ where
225323
config: AsRef::<TransactArgs>::as_ref(&args).config,
226324
};
227325

326+
handler.mark_hot(coinbase, TouchKind::Coinbase);
327+
228328
if handler.code_size(caller) != U256::zero() {
229329
handler.push_substate();
230330
return Ok((
@@ -276,7 +376,8 @@ where
276376
};
277377
let transaction_context = TransactionContext {
278378
origin: caller,
279-
gas_price,
379+
gas_price: gas_price
380+
.effective_gas_price(AsRef::<TransactArgs>::as_ref(&args).config, handler),
280381
};
281382
let transfer = Transfer {
282383
source: caller,
@@ -297,7 +398,6 @@ where
297398
}
298399
}
299400

300-
handler.mark_hot(coinbase, TouchKind::Coinbase);
301401
handler.mark_hot(caller, TouchKind::Access);
302402
handler.mark_hot(caller, TouchKind::StateChange);
303403
handler.mark_hot(address, TouchKind::Access);
@@ -423,27 +523,19 @@ where
423523
}
424524
}
425525

426-
let refunded_fee = effective_gas.saturating_mul(invoke.gas_price);
526+
let used_gas = invoke.gas_limit.saturating_sub(effective_gas);
527+
let refunded_fee = invoke
528+
.gas_price
529+
.refunded_fee(effective_gas, invoke.config, handler);
427530
handler.deposit(invoke.caller, refunded_fee);
428-
// Reward coinbase address
429-
// EIP-1559 updated the fee system so that miners only get to keep the priority fee.
430-
// The base fee is always burned.
431-
let coinbase_gas_price = if invoke.config.eip1559_fee_market {
432-
invoke
433-
.gas_price
434-
.saturating_sub(handler.block_base_fee_per_gas())
435-
} else {
436-
invoke.gas_price
437-
};
438531
let coinbase_reward = invoke
439-
.gas_limit
440-
.saturating_mul(coinbase_gas_price)
441-
.saturating_sub(refunded_fee);
532+
.gas_price
533+
.coinbase_reward(used_gas, invoke.config, handler);
442534
handler.deposit(handler.block_coinbase(), coinbase_reward);
443535

444536
result.map(|call_create| TransactValue {
445537
call_create,
446-
effective_gas,
538+
used_gas,
447539
})
448540
}
449541

0 commit comments

Comments
 (0)