@@ -3,16 +3,21 @@ const primitives = @import("primitives");
33const context = @import ("context" );
44const state = @import ("state" );
55const main = @import ("main.zig" );
6+ const interpreter_mod = @import ("interpreter" );
67
78// Gas constants for intrinsic gas calculation
89const TX_BASE_COST : u64 = 21000 ;
910const TX_CREATE_COST : u64 = 32000 ;
11+ // EIP-8037 (Amsterdam+): reduced regular CREATE cost
12+ const TX_CREATE_COST_AMSTERDAM : u64 = 9000 ;
1013const CALLDATA_ZERO_BYTE_COST : u64 = 4 ;
1114const CALLDATA_NONZERO_BYTE_COST : u64 = 16 ;
1215const ACCESS_LIST_ADDRESS_COST : u64 = 2400 ;
1316const ACCESS_LIST_STORAGE_KEY_COST : u64 = 1900 ;
1417// EIP-7702: per-authorization intrinsic gas (PER_EMPTY_ACCOUNT_COST per EIP-7702 spec)
1518const TX_EIP7702_AUTH_COST : u64 = 25000 ;
19+ // EIP-8037 (Amsterdam+): reduced regular per-auth cost
20+ const TX_EIP7702_AUTH_COST_AMSTERDAM : u64 = 7500 ;
1621// EIP-7623: token costs (different from calldata gas costs)
1722const FLOOR_ZERO_TOKEN_COST : u64 = 1 ;
1823const FLOOR_NONZERO_TOKEN_COST : u64 = 4 ;
@@ -92,20 +97,20 @@ pub const Validation = struct {
9297 const tx = & ctx .tx ;
9398 const spec = ctx .cfg .spec ;
9499
95- // EIP-3860 (Shanghai+): initcode size limit for CREATE transactions
96- // EIP-7954 (Amsterdam+): limit doubled to 65536
100+ // EIP-3860 (Shanghai+): initcode size limit for CREATE transactions.
101+ // EIP-7954 (Amsterdam+): max code size doubles to 32768, so max initcode = 65536.
97102 if (primitives .isEnabledIn (spec , .shanghai )) {
98103 if (tx .kind == .Create ) {
99- const calldata_len = if (tx .data ) | d | d .items .len else 0 ;
100104 const max_initcode : usize = if (primitives .isEnabledIn (spec , .amsterdam )) primitives .AMSTERDAM_MAX_INITCODE_SIZE else primitives .MAX_INITCODE_SIZE ;
105+ const calldata_len = if (tx .data ) | d | d .items .len else 0 ;
101106 if (calldata_len > max_initcode ) {
102107 return ValidationError .CreateInitcodeOverLimit ;
103108 }
104109 }
105110 }
106111
107112 // Calculate initial gas cost
108- const initial_gas = calculateInitialGas (tx , spec );
113+ const initial_gas = calculateInitialGas (tx , spec , ctx . block . gas_limit );
109114
110115 // Calculate floor gas exec-portion (EIP-7623: tokens * 10, only calldata tokens).
111116 // Returns 0 if EIP-7623 is disabled via cfg flag.
@@ -125,9 +130,26 @@ pub const Validation = struct {
125130 }
126131 }
127132
133+ // EIP-8037 (Amsterdam+): compute the state gas portion of the intrinsic cost.
134+ // This is needed to compute gasUsed = max(regular_gas, state_gas) for receipts.
135+ var initial_state_gas : u64 = 0 ;
136+ if (primitives .isEnabledIn (spec , .amsterdam )) {
137+ const gas_costs = interpreter_mod .gas_costs ;
138+ const cpsb = gas_costs .costPerStateByte (ctx .block .gas_limit );
139+ if (tx .kind == .Create ) {
140+ initial_state_gas += gas_costs .STATE_BYTES_PER_NEW_ACCOUNT * cpsb ;
141+ }
142+ // EIP-7702: auth list state gas — 135*cpsb per auth (base 23 + new-account 112)
143+ if (tx .authorization_list ) | auth_list | {
144+ const num_auths : u64 = @intCast (auth_list .items .len );
145+ initial_state_gas += num_auths * ((gas_costs .STATE_BYTES_PER_AUTH_BASE + gas_costs .STATE_BYTES_PER_NEW_ACCOUNT ) * cpsb );
146+ }
147+ }
148+
128149 return InitialAndFloorGas {
129150 .initial_gas = initial_gas ,
130151 .floor_gas = floor_gas ,
152+ .initial_state_gas = initial_state_gas ,
131153 };
132154 }
133155
@@ -258,18 +280,28 @@ pub const Validation = struct {
258280 ///
259281 /// Breakdown:
260282 /// 21,000 base (always)
261- /// + 32,000 for CREATE transactions
283+ /// + 32,000 for CREATE transactions (pre-Amsterdam) or 9,000 + 112*cpsb (Amsterdam+)
262284 /// + 4 per zero calldata byte, 16 per non-zero calldata byte
263285 /// + 2,400 per access-list address, 1,900 per access-list storage slot
264- /// + 25,000 per EIP-7702 authorization list entry (PER_EMPTY_ACCOUNT_COST, Prague +)
286+ /// + 25,000 per EIP-7702 authorization list entry (pre-Amsterdam) or 7,500 + 135*cpsb (Amsterdam +)
265287 /// + GAS_PER_BLOB per EIP-4844 blob hash
266- pub fn calculateInitialGas (tx : * const context.TxEnv , spec : primitives.SpecId ) u64 {
288+ pub fn calculateInitialGas (tx : * const context.TxEnv , spec : primitives.SpecId , block_gas_limit : u64 ) u64 {
289+ const gas_costs = interpreter_mod .gas_costs ;
290+ const cpsb : u64 = if (primitives .isEnabledIn (spec , .amsterdam ))
291+ gas_costs .costPerStateByte (block_gas_limit )
292+ else
293+ 0 ;
267294 var gas : u64 = TX_BASE_COST ;
268295
269296 // CREATE adds extra base cost (EIP-2, Homestead+).
270- // Frontier does NOT charge G_TXCREATE (32000) for CREATE transactions.
297+ // Frontier does NOT charge G_TXCREATE for CREATE transactions.
298+ // EIP-8037 (Amsterdam+): regular CREATE cost drops to 9000; state gas (112*cpsb) added.
271299 if (tx .kind == .Create and primitives .isEnabledIn (spec , .homestead )) {
272- gas += TX_CREATE_COST ;
300+ if (primitives .isEnabledIn (spec , .amsterdam )) {
301+ gas += TX_CREATE_COST_AMSTERDAM + gas_costs .STATE_BYTES_PER_NEW_ACCOUNT * cpsb ;
302+ } else {
303+ gas += TX_CREATE_COST ;
304+ }
273305 }
274306
275307 // Calldata costs:
@@ -310,9 +342,16 @@ pub const Validation = struct {
310342 // Blob fees are deducted in validateAgainstStateAndDeductCaller.
311343
312344 // EIP-7702: authorization list intrinsic gas (Prague+)
345+ // EIP-8037 (Amsterdam+): per-auth cost = 7500 regular + 135*cpsb state (= 23+112 state bytes)
313346 if (primitives .isEnabledIn (spec , .prague )) {
314347 if (tx .authorization_list ) | auth_list | {
315- gas += @as (u64 , auth_list .items .len ) * TX_EIP7702_AUTH_COST ;
348+ const num_auths : u64 = @intCast (auth_list .items .len );
349+ if (primitives .isEnabledIn (spec , .amsterdam )) {
350+ const per_auth = TX_EIP7702_AUTH_COST_AMSTERDAM + (gas_costs .STATE_BYTES_PER_AUTH_BASE + gas_costs .STATE_BYTES_PER_NEW_ACCOUNT ) * cpsb ;
351+ gas += num_auths * per_auth ;
352+ } else {
353+ gas += num_auths * TX_EIP7702_AUTH_COST ;
354+ }
316355 }
317356 }
318357
@@ -425,6 +464,13 @@ pub const InitialAndFloorGas = struct {
425464 /// 25,000 (PER_EMPTY_ACCOUNT_COST) added for each valid authorization that sets code.
426465 /// Applied in postExecution with the standard 1/5 cap against total gas used.
427466 auth_refund : i64 = 0 ,
467+ /// EIP-8037 (Amsterdam+): state gas portion of the intrinsic cost.
468+ /// For CREATE: STATE_BYTES_PER_NEW_ACCOUNT * CPSB.
469+ /// For EIP-7702 auth entries: (STATE_BYTES_PER_AUTH_BASE + STATE_BYTES_PER_NEW_ACCOUNT) * CPSB per auth.
470+ initial_state_gas : u64 = 0 ,
471+ /// EIP-8037 (Amsterdam+): state gas refunded for valid auths to existing accounts.
472+ /// 112*cpsb per valid auth applied to an existing (non-empty) account. Bypasses 1/5 cap.
473+ auth_state_refund : u64 = 0 ,
428474};
429475
430476/// Validation errors
0 commit comments