Skip to content

Commit 88748ec

Browse files
authored
Work around receipts root calculation for Stable network (#428)
Work around receipts root calculation for Stable network. It uses gasUsed instead of cumulativeGasUsed in receipts root
1 parent 80fdedd commit 88748ec

File tree

2 files changed

+24
-5
lines changed

2 files changed

+24
-5
lines changed

evm/evm-rpc/src/chain-utils.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ export class ChainUtils {
1616
public isPolygonMainnet: boolean
1717
public isHyperliquidMainnet: boolean
1818
public isHyperliquidTestnet: boolean
19+
public isStable: boolean
1920

2021
constructor(chainId: Qty) {
2122
this.isPolygonMainnet = chainId == '0x89'
2223
this.isHyperliquidMainnet = chainId == '0x3e7'
2324
this.isHyperliquidTestnet = chainId == '0x3e6'
25+
this.isStable = chainId == '0x3dc' || chainId == '0x899' // Chain ID 988 (mainnet) or 2201 (testnet)
2426
}
2527

2628
calculateBlockHash(block: GetBlock) {
@@ -86,6 +88,11 @@ export class ChainUtils {
8688
receipts = receipts.filter(receipt => !isHyperliquidSystemReceipt(receipt))
8789
}
8890

91+
// Stable chain uses gasUsed instead of cumulativeGasUsed in receipts root
92+
if (this.isStable) {
93+
return receiptsRoot(receipts, {useGasUsed: true})
94+
}
95+
8996
return receiptsRoot(receipts)
9097
}
9198

evm/evm-rpc/src/verification.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,26 @@ function decodeLogs(logs: Log[]) {
281281
}
282282

283283

284-
function encodeReceipt(receipt: Receipt): Buffer {
284+
export interface ReceiptEncodingOptions {
285+
/**
286+
* Use gasUsed instead of cumulativeGasUsed when encoding receipts.
287+
* This is needed for chains like Stable (chain ID 988) that deviate from
288+
* the Ethereum standard by using per-transaction gas instead of cumulative.
289+
*/
290+
useGasUsed?: boolean
291+
}
292+
293+
294+
function encodeReceipt(receipt: Receipt, options?: ReceiptEncodingOptions): Buffer {
285295
let type = receipt.type == '0x0' ? Buffer.alloc(0) : RLP.encode(qty2Int(receipt.type))
286296
let payload: Uint8Array
297+
// Use gasUsed instead of cumulativeGasUsed for certain chains (e.g., Stable)
298+
let gasField = options?.useGasUsed ? receipt.gasUsed : receipt.cumulativeGasUsed
287299
if (receipt.type == '0x7e') {
288300
// https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/deposits.md#deposit-receipt
289301
payload = RLP.encode([
290302
qty2Int(receipt.status),
291-
BigInt(receipt.cumulativeGasUsed),
303+
BigInt(gasField),
292304
decodeHex(receipt.logsBloom),
293305
decodeLogs(receipt.logs),
294306
BigInt(assertNotNull(receipt.depositNonce, 'receipt.depositNonce is missing')),
@@ -297,7 +309,7 @@ function encodeReceipt(receipt: Receipt): Buffer {
297309
} else {
298310
payload = RLP.encode([
299311
qty2Int(receipt.status),
300-
BigInt(receipt.cumulativeGasUsed),
312+
BigInt(gasField),
301313
decodeHex(receipt.logsBloom),
302314
decodeLogs(receipt.logs),
303315
])
@@ -306,15 +318,15 @@ function encodeReceipt(receipt: Receipt): Buffer {
306318
}
307319

308320

309-
export async function receiptsRoot(receipts: Receipt[]) {
321+
export async function receiptsRoot(receipts: Receipt[], options?: ReceiptEncodingOptions) {
310322
let trie = await createMPT()
311323

312324
for (let idx = 0; idx < receipts.length; idx++) {
313325
let receipt = receipts[idx]
314326
let key = RLP.encode(idx)
315327
let value: Buffer
316328
try {
317-
value = encodeReceipt(receipt)
329+
value = encodeReceipt(receipt, options)
318330
} catch (err: any) {
319331
throw addErrorContext(err, {
320332
transactionIndex: qty2Int(receipt.transactionIndex),

0 commit comments

Comments
 (0)