Skip to content

Commit 1053926

Browse files
committed
core/types: Populate Jovian receipt fields
1 parent c853f0e commit 1053926

File tree

6 files changed

+128
-38
lines changed

6 files changed

+128
-38
lines changed

core/types/gen_receipt_json.go

Lines changed: 8 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/types/receipt.go

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,16 @@ type Receipt struct {
8686
TransactionIndex uint `json:"transactionIndex"`
8787

8888
// Optimism: extend receipts with L1 and operator fee info
89-
L1GasPrice *big.Int `json:"l1GasPrice,omitempty"` // Present from pre-bedrock. L1 Basefee after Bedrock
90-
L1BlobBaseFee *big.Int `json:"l1BlobBaseFee,omitempty"` // Always nil prior to the Ecotone hardfork
91-
L1GasUsed *big.Int `json:"l1GasUsed,omitempty"` // Present from pre-bedrock, deprecated as of Fjord
92-
L1Fee *big.Int `json:"l1Fee,omitempty"` // Present from pre-bedrock
93-
FeeScalar *big.Float `json:"l1FeeScalar,omitempty"` // Present from pre-bedrock to Ecotone. Nil after Ecotone
94-
L1BaseFeeScalar *uint64 `json:"l1BaseFeeScalar,omitempty"` // Always nil prior to the Ecotone hardfork
95-
L1BlobBaseFeeScalar *uint64 `json:"l1BlobBaseFeeScalar,omitempty"` // Always nil prior to the Ecotone hardfork
96-
OperatorFeeScalar *uint64 `json:"operatorFeeScalar,omitempty"` // Always nil prior to the Isthmus hardfork
97-
OperatorFeeConstant *uint64 `json:"operatorFeeConstant,omitempty"` // Always nil prior to the Isthmus hardfork
89+
L1GasPrice *big.Int `json:"l1GasPrice,omitempty"` // Present from pre-bedrock. L1 Basefee after Bedrock
90+
L1BlobBaseFee *big.Int `json:"l1BlobBaseFee,omitempty"` // Always nil prior to the Ecotone hardfork
91+
L1GasUsed *big.Int `json:"l1GasUsed,omitempty"` // Present from pre-bedrock, deprecated as of Fjord
92+
L1Fee *big.Int `json:"l1Fee,omitempty"` // Present from pre-bedrock
93+
FeeScalar *big.Float `json:"l1FeeScalar,omitempty"` // Present from pre-bedrock to Ecotone. Nil after Ecotone
94+
L1BaseFeeScalar *uint64 `json:"l1BaseFeeScalar,omitempty"` // Always nil prior to the Ecotone hardfork
95+
L1BlobBaseFeeScalar *uint64 `json:"l1BlobBaseFeeScalar,omitempty"` // Always nil prior to the Ecotone hardfork
96+
OperatorFeeScalar *uint64 `json:"operatorFeeScalar,omitempty"` // Always nil prior to the Isthmus hardfork
97+
OperatorFeeConstant *uint64 `json:"operatorFeeConstant,omitempty"` // Always nil prior to the Isthmus hardfork
98+
DAFootprintGasScalar *uint64 `json:"daFootprintGasScalar,omitempty"` // Always nil prior to the Jovian hardfork
9899
}
99100

100101
type receiptMarshaling struct {
@@ -121,6 +122,7 @@ type receiptMarshaling struct {
121122
DepositReceiptVersion *hexutil.Uint64
122123
OperatorFeeScalar *hexutil.Uint64
123124
OperatorFeeConstant *hexutil.Uint64
125+
DAFootprintGasScalar *hexutil.Uint64
124126
}
125127

126128
// receiptRLP is the consensus encoding of a receipt.
@@ -612,26 +614,8 @@ func (rs Receipts) DeriveFields(config *params.ChainConfig, blockHash common.Has
612614
logIndex += uint(len(rs[i].Logs))
613615
}
614616

615-
if config.Optimism != nil && len(txs) >= 2 && config.IsBedrock(new(big.Int).SetUint64(blockNumber)) {
616-
gasParams, err := extractL1GasParams(config, blockTime, txs[0].Data())
617-
if err != nil {
618-
return err
619-
}
620-
for i := 0; i < len(rs); i++ {
621-
if txs[i].IsDepositTx() {
622-
continue
623-
}
624-
rs[i].L1GasPrice = gasParams.l1BaseFee
625-
rs[i].L1BlobBaseFee = gasParams.l1BlobBaseFee
626-
rs[i].L1Fee, rs[i].L1GasUsed = gasParams.costFunc(txs[i].RollupCostData())
627-
rs[i].FeeScalar = gasParams.feeScalar
628-
rs[i].L1BaseFeeScalar = u32ptrTou64ptr(gasParams.l1BaseFeeScalar)
629-
rs[i].L1BlobBaseFeeScalar = u32ptrTou64ptr(gasParams.l1BlobBaseFeeScalar)
630-
if gasParams.operatorFeeScalar != nil && gasParams.operatorFeeConstant != nil && (*gasParams.operatorFeeScalar != 0 || *gasParams.operatorFeeConstant != 0) {
631-
rs[i].OperatorFeeScalar = u32ptrTou64ptr(gasParams.operatorFeeScalar)
632-
rs[i].OperatorFeeConstant = gasParams.operatorFeeConstant
633-
}
634-
}
617+
if config.IsOptimismBedrock(new(big.Int).SetUint64(blockNumber)) && len(txs) >= 2 {
618+
return rs.deriveOPStackFields(config, blockTime, txs)
635619
}
636620
return nil
637621
}

core/types/receipt_opstack.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package types
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/ethereum/go-ethereum/params"
7+
)
8+
9+
// deriveOPStackFields derives the OP Stack specific fields for each receipt.
10+
// It must only be called for blocks with at least one transaction (the L1 attributes deposit).
11+
func (rs Receipts) deriveOPStackFields(config *params.ChainConfig, blockTime uint64, txs []*Transaction) error {
12+
// Exit early if there are only deposit transactions, for which no fields are derived.
13+
if txs[len(txs)-1].IsDepositTx() {
14+
return nil
15+
}
16+
17+
l1AttributesData := txs[0].Data()
18+
gasParams, err := extractL1GasParams(config, blockTime, l1AttributesData)
19+
if err != nil {
20+
return fmt.Errorf("failed to extract L1 gas params: %w", err)
21+
}
22+
23+
var daFootprintGasScalar uint64
24+
isJovian := config.IsJovian(blockTime)
25+
if isJovian {
26+
scalar, err := ExtractDAFootprintGasScalar(l1AttributesData)
27+
if err != nil {
28+
return fmt.Errorf("failed to extract DA footprint gas scalar: %w", err)
29+
}
30+
daFootprintGasScalar = uint64(scalar)
31+
}
32+
33+
for i := range rs {
34+
if txs[i].IsDepositTx() {
35+
continue
36+
}
37+
rs[i].L1GasPrice = gasParams.l1BaseFee
38+
rs[i].L1BlobBaseFee = gasParams.l1BlobBaseFee
39+
rcd := txs[i].RollupCostData()
40+
rs[i].L1Fee, rs[i].L1GasUsed = gasParams.costFunc(rcd)
41+
rs[i].FeeScalar = gasParams.feeScalar
42+
rs[i].L1BaseFeeScalar = u32ptrTou64ptr(gasParams.l1BaseFeeScalar)
43+
rs[i].L1BlobBaseFeeScalar = u32ptrTou64ptr(gasParams.l1BlobBaseFeeScalar)
44+
if gasParams.operatorFeeScalar != nil && gasParams.operatorFeeConstant != nil && (*gasParams.operatorFeeScalar != 0 || *gasParams.operatorFeeConstant != 0) {
45+
rs[i].OperatorFeeScalar = u32ptrTou64ptr(gasParams.operatorFeeScalar)
46+
rs[i].OperatorFeeConstant = gasParams.operatorFeeConstant
47+
}
48+
if isJovian {
49+
rs[i].DAFootprintGasScalar = &daFootprintGasScalar
50+
rs[i].BlobGasUsed = daFootprintGasScalar * rcd.EstimatedDASize().Uint64()
51+
}
52+
}
53+
return nil
54+
}

core/types/receipt_opstack_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ var (
3737
conf.IsthmusTime = &time
3838
return &conf
3939
}()
40+
jovianTestConfig = func() *params.ChainConfig {
41+
conf := *isthmusTestConfig // copy the config
42+
time := uint64(0)
43+
conf.JovianTime = &time
44+
return &conf
45+
}()
4046

4147
depositReceiptNoNonce = &Receipt{
4248
Status: ReceiptStatusFailed,
@@ -95,6 +101,8 @@ var (
95101
},
96102
Type: DepositTxType,
97103
}
104+
105+
daFootprintGasScalar = uint16(400)
98106
)
99107

100108
func clearComputedFieldsOnOPStackReceipts(receipts []*Receipt) []*Receipt {
@@ -109,6 +117,7 @@ func clearComputedFieldsOnOPStackReceipts(receipts []*Receipt) []*Receipt {
109117
receipt.L1BlobBaseFeeScalar = nil
110118
receipt.OperatorFeeScalar = nil
111119
receipt.OperatorFeeConstant = nil
120+
receipt.DAFootprintGasScalar = nil
112121
}
113122
return receipts
114123
}
@@ -200,6 +209,15 @@ func getOptimismIsthmusTxReceipts(l1AttributesPayload []byte, l1GasPrice, l1Blob
200209
return txs, receipts
201210
}
202211

212+
func getOptimismJovianTxReceipts(l1AttributesPayload []byte, l1GasPrice, l1BlobBaseFee, l1GasUsed, l1Fee *big.Int, baseFeeScalar, blobBaseFeeScalar, operatorFeeScalar, operatorFeeConstant, daFootprintGasScalar *uint64) ([]*Transaction, []*Receipt) {
213+
txs, receipts := getOptimismIsthmusTxReceipts(l1AttributesPayload, l1GasPrice, l1BlobBaseFee, l1GasUsed, l1Fee, baseFeeScalar, blobBaseFeeScalar, operatorFeeScalar, operatorFeeConstant)
214+
receipts[1].DAFootprintGasScalar = daFootprintGasScalar
215+
if daFootprintGasScalar != nil {
216+
receipts[1].BlobGasUsed = *daFootprintGasScalar * txs[1].RollupCostData().EstimatedDASize().Uint64()
217+
}
218+
return txs, receipts
219+
}
220+
203221
func TestDeriveOptimismBedrockTxReceipts(t *testing.T) {
204222
// Bedrock style l1 attributes with L1Scalar=7_000_000 (becomes 7 after division), L1Overhead=50, L1BaseFee=1000*1e6
205223
payload := common.Hex2Bytes("015d8eb900000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d2000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d2000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000006acfc0015d8eb900000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d2000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d2000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000006acfc0")
@@ -286,6 +304,29 @@ func TestDeriveOptimismIsthmusTxReceiptsNoOperatorFee(t *testing.T) {
286304
diffReceipts(t, receipts, derivedReceipts)
287305
}
288306

307+
func TestDeriveOptimismJovianTxReceipts(t *testing.T) {
308+
// Jovian style l1 attributes with baseFeeScalar=2, blobBaseFeeScalar=3, baseFee=1000*1e6, blobBaseFee=10*1e6, operatorFeeScalar=1439103868, operatorFeeConstant=1256417826609331460, daFootprintGasScalar=400
309+
payload := common.Hex2Bytes("3db6be2b000000020000000300000000000004d200000000000004d200000000000004d2000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000000098968000000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d255c6fb7c116fb15b44847d040190")
310+
// the parameters we use below are defined in rollup_test.go
311+
baseFeeScalarUint64 := baseFeeScalar.Uint64()
312+
blobBaseFeeScalarUint64 := blobBaseFeeScalar.Uint64()
313+
operatorFeeScalarUint64 := operatorFeeScalar.Uint64()
314+
operatorFeeConstantUint64 := operatorFeeConstant.Uint64()
315+
daFootprintGasScalarUint64 := uint64(daFootprintGasScalar)
316+
txs, receipts := getOptimismJovianTxReceipts(payload, baseFee, blobBaseFee, minimumFjordGas, fjordFee, &baseFeeScalarUint64, &blobBaseFeeScalarUint64, &operatorFeeScalarUint64, &operatorFeeConstantUint64, &daFootprintGasScalarUint64)
317+
318+
// Re-derive receipts.
319+
baseFee := big.NewInt(1000)
320+
derivedReceipts := clearComputedFieldsOnOPStackReceipts(receipts)
321+
// Should error out if we try to process this with a pre-Jovian config
322+
err := Receipts(derivedReceipts).DeriveFields(bedrockGenesisTestConfig, blockHash, blockNumber.Uint64(), 0, baseFee, nil, txs)
323+
require.Error(t, err)
324+
325+
err = Receipts(derivedReceipts).DeriveFields(jovianTestConfig, blockHash, blockNumber.Uint64(), 0, baseFee, nil, txs)
326+
require.NoError(t, err)
327+
diffReceipts(t, receipts, derivedReceipts)
328+
}
329+
289330
func diffReceipts(t *testing.T, receipts, derivedReceipts []*Receipt) {
290331
// Check diff of receipts against derivedReceipts.
291332
r1, err := json.MarshalIndent(receipts, "", " ")

fork.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,12 +253,15 @@ def:
253253
- title: "User API enhancements"
254254
description: "Encode the Deposit Tx properties, the L1 costs, and daisy-chain RPC-calls for pre-Bedrock historical data"
255255
sub:
256-
- title: "Receipts metadata"
256+
- title: "Receipts metadata & deposit receipts"
257257
description: |
258258
Pre-Bedrock L1-cost receipt data is loaded from the database if available, and post-Bedrock the L1-cost
259259
metadata is hydrated on-the-fly based on the L1 fee information in the corresponding block.
260+
We also populate receipts with L1 block attributes like Operator Fee and DA Footprint parameters.
261+
Furthermore, OP Stack introduces Deposit receipts, a special kind of receipts for Deposit transactions.
260262
globs:
261263
- "core/types/receipt.go"
264+
- "core/types/receipt_opstack.go"
262265
- "core/types/gen_receipt_json.go"
263266
- "core/rawdb/accessors_chain.go"
264267
- title: "API Backend"

internal/ethapi/api.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,7 +1710,7 @@ func marshalReceipt(receipt *types.Receipt, blockHash common.Hash, blockNumber u
17101710
"effectiveGasPrice": (*hexutil.Big)(receipt.EffectiveGasPrice),
17111711
}
17121712

1713-
if chainConfig.Optimism != nil && !tx.IsDepositTx() {
1713+
if chainConfig.IsOptimism() && !tx.IsDepositTx() {
17141714
fields["l1GasPrice"] = (*hexutil.Big)(receipt.L1GasPrice)
17151715
fields["l1GasUsed"] = (*hexutil.Big)(receipt.L1GasUsed)
17161716
fields["l1Fee"] = (*hexutil.Big)(receipt.L1Fee)
@@ -1735,8 +1735,14 @@ func marshalReceipt(receipt *types.Receipt, blockHash common.Hash, blockNumber u
17351735
if receipt.OperatorFeeConstant != nil {
17361736
fields["operatorFeeConstant"] = hexutil.Uint64(*receipt.OperatorFeeConstant)
17371737
}
1738+
// Fields added in Jovian
1739+
if receipt.DAFootprintGasScalar != nil {
1740+
fields["daFootprintGasScalar"] = hexutil.Uint64(*receipt.OperatorFeeScalar)
1741+
// Jovian repurposes blobGasUsed for DA footprint gas used
1742+
fields["blobGasUsed"] = hexutil.Uint64(receipt.BlobGasUsed)
1743+
}
17381744
}
1739-
if chainConfig.Optimism != nil && tx.IsDepositTx() && receipt.DepositNonce != nil {
1745+
if chainConfig.IsOptimism() && tx.IsDepositTx() && receipt.DepositNonce != nil {
17401746
fields["depositNonce"] = hexutil.Uint64(*receipt.DepositNonce)
17411747
if receipt.DepositReceiptVersion != nil {
17421748
fields["depositReceiptVersion"] = hexutil.Uint64(*receipt.DepositReceiptVersion)

0 commit comments

Comments
 (0)