@@ -56,13 +56,16 @@ int64_t compute_tx_intrinsic_cost(evmc_revision rev, const Transaction& tx) noex
56
56
{
57
57
static constexpr auto call_tx_cost = 21000 ;
58
58
static constexpr auto create_tx_cost = 53000 ;
59
+ static constexpr auto per_auth_base_cost = 2500 ;
59
60
static constexpr auto initcode_word_cost = 2 ;
60
61
const auto is_create = !tx.to .has_value (); // Covers also EOF creation txs.
62
+ const auto auth_list_cost =
63
+ static_cast <int64_t >(per_auth_base_cost * tx.authorization_list .size ());
61
64
const auto initcode_cost =
62
65
is_create && rev >= EVMC_SHANGHAI ? initcode_word_cost * num_words (tx.data .size ()) : 0 ;
63
66
const auto tx_cost = is_create && rev >= EVMC_HOMESTEAD ? create_tx_cost : call_tx_cost;
64
67
return tx_cost + compute_tx_data_cost (rev, tx.data ) + compute_access_list_cost (tx.access_list ) +
65
- compute_initcode_list_cost (rev, tx.initcodes ) + initcode_cost;
68
+ compute_initcode_list_cost (rev, tx.initcodes ) + auth_list_cost + initcode_cost;
66
69
}
67
70
68
71
evmc_message build_message (
@@ -283,6 +286,17 @@ std::variant<int64_t, std::error_code> validate_transaction(const Account& sende
283
286
return make_error_code (BLOB_GAS_LIMIT_EXCEEDED);
284
287
break ;
285
288
289
+ case Transaction::Type::set_code:
290
+ if (rev < EVMC_PRAGUE)
291
+ return make_error_code (TX_TYPE_NOT_SUPPORTED);
292
+
293
+ // TODO is empty auth list valid?
294
+ // if (tx.authorization_list.empty())
295
+ // return make_error_code(EMPTY_BLOB_AUTHORIZATION_LIST);
296
+
297
+ // TODO is empty destination valid?
298
+ break ;
299
+
286
300
case Transaction::Type::initcodes:
287
301
if (rev < EVMC_OSAKA)
288
302
return make_error_code (TX_TYPE_NOT_SUPPORTED);
@@ -305,6 +319,7 @@ std::variant<int64_t, std::error_code> validate_transaction(const Account& sende
305
319
{
306
320
case Transaction::Type::blob:
307
321
case Transaction::Type::initcodes:
322
+ case Transaction::Type::set_code:
308
323
case Transaction::Type::eip1559:
309
324
if (rev < EVMC_LONDON)
310
325
return make_error_code (TX_TYPE_NOT_SUPPORTED);
@@ -329,6 +344,7 @@ std::variant<int64_t, std::error_code> validate_transaction(const Account& sende
329
344
if (tx.max_gas_price < block.base_fee )
330
345
return make_error_code (FEE_CAP_LESS_THEN_BLOCKS);
331
346
347
+ // TODO this is relaxed for 7702
332
348
if (!sender_acc.code .empty ())
333
349
return make_error_code (SENDER_NOT_EOA); // Origin must not be a contract (EIP-3607).
334
350
@@ -442,6 +458,11 @@ void finalize(State& state, evmc_revision rev, const address& coinbase,
442
458
delete_empty_accounts (state);
443
459
}
444
460
461
+ constexpr bool is_code_delegated (bytes_view code) noexcept
462
+ {
463
+ return code.starts_with (DELEGATION_MAGIC);
464
+ }
465
+
445
466
std::variant<TransactionReceipt, std::error_code> transition (State& state, const BlockInfo& block,
446
467
const Transaction& tx, evmc_revision rev, evmc::VM& vm, int64_t block_gas_left,
447
468
int64_t blob_gas_left)
@@ -458,6 +479,26 @@ std::variant<TransactionReceipt, std::error_code> transition(State& state, const
458
479
if (holds_alternative<std::error_code>(validation_result))
459
480
return get<std::error_code>(validation_result);
460
481
482
+ for (const auto & auth : tx.authorization_list )
483
+ {
484
+ // TODO check chain_id
485
+
486
+ auto & acc = state.get_or_insert (auth.signer );
487
+ if (!acc.code .empty () && !is_code_delegated (acc.code ))
488
+ continue ;
489
+
490
+ if (acc.nonce != auth.nonce )
491
+ continue ;
492
+
493
+ acc.code .reserve (std::size (DELEGATION_MAGIC) + std::size (auth.addr .bytes ));
494
+ acc.code = DELEGATION_MAGIC;
495
+ acc.code += auth.addr ;
496
+
497
+ ++acc.nonce ;
498
+
499
+ acc.access_status = EVMC_ACCESS_WARM;
500
+ }
501
+
461
502
// Once the transaction is valid, create new sender account.
462
503
// The account won't be empty because its nonce will be bumped.
463
504
auto & sender_acc = (sender_ptr != nullptr ) ? *sender_ptr : state.insert (tx.sender );
0 commit comments