|
1 | 1 | use crate::{
|
2 | 2 | alloc::vec::Vec, calc_blob_fee, Account, EVMError, InvalidTransaction, Spec, SpecId, B160,
|
3 |
| - B256, GAS_PER_BLOB, KECCAK_EMPTY, MAX_INITCODE_SIZE, U256, |
| 3 | + B256, GAS_PER_BLOB, KECCAK_EMPTY, MAX_BLOB_NUMBER_PER_BLOCK, MAX_INITCODE_SIZE, U256, |
| 4 | + VERSIONED_HASH_VERSION_KZG, |
4 | 5 | };
|
5 | 6 | use bytes::Bytes;
|
6 | 7 | use core::cmp::{min, Ordering};
|
@@ -107,7 +108,8 @@ pub struct TxEnv {
|
107 | 108 | /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559
|
108 | 109 | pub gas_priority_fee: Option<U256>,
|
109 | 110 |
|
110 |
| - /// The list of blob versioned hashes. |
| 111 | + /// The list of blob versioned hashes. Per EIP there should be at least |
| 112 | + /// one blob present if [`Self::max_fee_per_blob_gas`] is `Some`. |
111 | 113 | ///
|
112 | 114 | /// Incorporated as part of the Cancun upgrade via [EIP-4844].
|
113 | 115 | ///
|
@@ -458,11 +460,40 @@ impl Env {
|
458 | 460 | // - For CANCUN and later, check that the gas price is not more than the tx max
|
459 | 461 | // - For before CANCUN, check that `blob_hashes` and `max_fee_per_blob_gas` are empty / not set
|
460 | 462 | if SPEC::enabled(SpecId::CANCUN) {
|
| 463 | + // Presence of max_fee_per_blob_gas means that this is blob transaction. |
461 | 464 | if let Some(max) = self.tx.max_fee_per_blob_gas {
|
| 465 | + // ensure that the user was willing to at least pay the current blob gasprice |
462 | 466 | let price = self.block.get_blob_gasprice().expect("already checked");
|
463 | 467 | if U256::from(price) > max {
|
464 | 468 | return Err(InvalidTransaction::BlobGasPriceGreaterThanMax);
|
465 | 469 | }
|
| 470 | + |
| 471 | + // there must be at least one blob |
| 472 | + // assert len(tx.blob_versioned_hashes) > 0 |
| 473 | + if self.tx.blob_hashes.is_empty() { |
| 474 | + return Err(InvalidTransaction::EmptyBlobs); |
| 475 | + } |
| 476 | + |
| 477 | + // The field `to` deviates slightly from the semantics with the exception |
| 478 | + // that it MUST NOT be nil and therefore must always represent |
| 479 | + // a 20-byte address. This means that blob transactions cannot |
| 480 | + // have the form of a create transaction. |
| 481 | + if self.tx.transact_to.is_create() { |
| 482 | + return Err(InvalidTransaction::BlobCreateTransaction); |
| 483 | + } |
| 484 | + |
| 485 | + // all versioned blob hashes must start with VERSIONED_HASH_VERSION_KZG |
| 486 | + for blob in self.tx.blob_hashes.iter() { |
| 487 | + if blob[0] != VERSIONED_HASH_VERSION_KZG { |
| 488 | + return Err(InvalidTransaction::BlobVersionNotSupported); |
| 489 | + } |
| 490 | + } |
| 491 | + |
| 492 | + // ensure the total blob gas spent is at most equal to the limit |
| 493 | + // assert blob_gas_used <= MAX_BLOB_GAS_PER_BLOCK |
| 494 | + if self.tx.blob_hashes.len() > MAX_BLOB_NUMBER_PER_BLOCK as usize { |
| 495 | + return Err(InvalidTransaction::TooManyBlobs); |
| 496 | + } |
466 | 497 | }
|
467 | 498 | } else {
|
468 | 499 | if !self.tx.blob_hashes.is_empty() {
|
|
0 commit comments