Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suspicious gas calculation at pallet_ethereum::Pallet::store_block #1558

Open
MOZGIII opened this issue Dec 13, 2024 · 8 comments
Open

Suspicious gas calculation at pallet_ethereum::Pallet::store_block #1558

MOZGIII opened this issue Dec 13, 2024 · 8 comments
Labels
bug Something isn't working

Comments

@MOZGIII
Copy link
Contributor

MOZGIII commented Dec 13, 2024

Found this code while doing the code review on frontier.

let mut cumulative_gas_used = U256::zero();
for (transaction, status, receipt) in Pending::<T>::get() {
transactions.push(transaction);
statuses.push(status);
receipts.push(receipt.clone());
let (logs, used_gas) = match receipt {
Receipt::Legacy(d) | Receipt::EIP2930(d) | Receipt::EIP1559(d) => {
(d.logs.clone(), d.used_gas)
}
};
cumulative_gas_used = used_gas;
Self::logs_bloom(logs, &mut logs_bloom);
}

Why cumulative_gas_used = used_gas?

I'd think it should be something like cumulative_gas_used += used_gas?

Unless used_gas already includes the gas of all previous txs (which doesn't seem to be the case) - this is a bug?

@MOZGIII MOZGIII added the bug Something isn't working label Dec 13, 2024
@conr2d
Copy link
Contributor

conr2d commented Dec 17, 2024

This clearly looks like a bug. Looking at this commit 278be3e, it seems there was a mistake while modifying the calculation of the gas_used amount, which was previously obtained by addition.

@@ -412,11 +412,18 @@ impl<T: Config> Pallet<T> {
                let mut statuses = Vec::new();
                let mut receipts = Vec::new();
                let mut logs_bloom = Bloom::default();
+               let mut cumulative_gas_used = U256::zero();
                for (transaction, status, receipt) in Pending::<T>::get() {
                        transactions.push(transaction);
                        statuses.push(status);
                        receipts.push(receipt.clone());
-                       Self::logs_bloom(receipt.logs.clone(), &mut logs_bloom);
+                       let (logs, used_gas) = match receipt {
+                               Receipt::Legacy(d) | Receipt::EIP2930(d) | Receipt::EIP1559(d) => {
+                                       (d.logs.clone(), d.used_gas)
+                               }
+                       };
+                       cumulative_gas_used = used_gas;
+                       Self::logs_bloom(logs, &mut logs_bloom);
                }

                let ommers = Vec::<ethereum::Header>::new();
@@ -431,10 +438,7 @@ impl<T: Config> Pallet<T> {
                        difficulty: U256::zero(),
                        number: block_number,
                        gas_limit: T::BlockGasLimit::get(),
-                       gas_used: receipts
-                               .clone()
-                               .into_iter()
-                               .fold(U256::zero(), |acc, r| acc + r.used_gas),
+                       gas_used: cumulative_gas_used,
                        timestamp: UniqueSaturatedInto::<u64>::unique_saturated_into(
                                pallet_timestamp::Pallet::<T>::get(),
                        ),

@MOZGIII
Copy link
Contributor Author

MOZGIII commented Dec 17, 2024

Let's fix it then!

@conr2d
Copy link
Contributor

conr2d commented Dec 17, 2024

Sorry for providing incorrect information earlier. The Ethereum Yellow Paper only specifies that the transaction receipt contains the cumulative gas used value.

In Geth:

type Receipt struct {
	// Consensus fields: These fields are defined by the Yellow Paper
	Type              uint8  `json:"type,omitempty"`
	PostState         []byte `json:"root"`
	Status            uint64 `json:"status"`
	CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"`
	Bloom             Bloom  `json:"logsBloom"         gencodec:"required"`
	Logs              []*Log `json:"logs"              gencodec:"required"`

	// Implementation fields: These fields are added by geth when processing a transaction.
	/* ... */
	GasUsed           uint64         `json:"gasUsed" gencodec:"required"`
	/* ... */
}

In Reth:

pub struct Receipt {
    pub tx_type: TxType,
    pub success: bool,
    pub cumulative_gas_used: u64,
    pub logs: Vec<Log>,
}

The receipt includes only the cumulative gas used value. When making an RPC call, the gasUsed value is calculated as the difference between the cumulative gas used of the current transaction and that of the previous transaction.

@MOZGIII
Copy link
Contributor Author

MOZGIII commented Dec 17, 2024

I see! This sure looks suspicious, so, how about we change the naming of the variables?

@boundless-forest
Copy link
Collaborator

Any renaming ideas? I think we should rename used_gas to cumulative_gas_used at this link: https://github.com/rust-ethereum/ethereum/blob/master/src/receipt.rs#L21C6-L21C14. The current field name is misleading.

@MOZGIII
Copy link
Contributor Author

MOZGIII commented Dec 18, 2024

Yes, my thinking as well...

@boundless-forest
Copy link
Collaborator

Yes, my thinking as well...

Are you willing to raise a pr for this?

@MOZGIII
Copy link
Contributor Author

MOZGIII commented Dec 18, 2024

Not at this time. I'm busy trying to figure out why our chain exhibits some odd behavior around CREATE opcode... Maybe once I'm done with that...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants