diff --git go-ethereum/internal/ethapi/api.go op-geth/internal/ethapi/api.go
index d9cec560ea2f8574ae080b56c48b6c185ad06837..34daf5a229eddcc55ff55dc050cc2392beb7f17b 100644
--- go-ethereum/internal/ethapi/api.go
+++ op-geth/internal/ethapi/api.go
@@ -27,6 +27,7 @@ "strings"
"time"
"github.com/davecgh/go-spew/spew"
+ "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -323,6 +324,24 @@ // GetBalance returns the amount of wei for the given address in the state of the
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
// block numbers are also allowed.
func (api *BlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) {
+ header, err := headerByNumberOrHash(ctx, api.b, blockNrOrHash)
+ if err != nil {
+ return nil, err
+ }
+
+ if api.b.ChainConfig().IsOptimismPreBedrock(header.Number) {
+ if api.b.HistoricalRPCService() != nil {
+ var res hexutil.Big
+ err := api.b.HistoricalRPCService().CallContext(ctx, &res, "eth_getBalance", address, blockNrOrHash)
+ if err != nil {
+ return nil, fmt.Errorf("historical backend error: %w", err)
+ }
+ return &res, nil
+ } else {
+ return nil, rpc.ErrNoHistoricalFallback
+ }
+ }
+
state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
if state == nil || err != nil {
return nil, err
@@ -363,6 +382,22 @@ }
// GetProof returns the Merkle-proof for a given account and optionally some storage keys.
func (api *BlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) {
+ header, err := headerByNumberOrHash(ctx, api.b, blockNrOrHash)
+ if err != nil {
+ return nil, err
+ }
+ if api.b.ChainConfig().IsOptimismPreBedrock(header.Number) {
+ if api.b.HistoricalRPCService() != nil {
+ var res AccountResult
+ err := api.b.HistoricalRPCService().CallContext(ctx, &res, "eth_getProof", address, storageKeys, blockNrOrHash)
+ if err != nil {
+ return nil, fmt.Errorf("historical backend error: %w", err)
+ }
+ return &res, nil
+ } else {
+ return nil, rpc.ErrNoHistoricalFallback
+ }
+ }
var (
keys = make([]common.Hash, len(storageKeys))
keyLengths = make([]int, len(storageKeys))
@@ -466,7 +501,7 @@ func (api *BlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) {
header, err := api.b.HeaderByNumber(ctx, number)
if header != nil && err == nil {
response := RPCMarshalHeader(header)
- if number == rpc.PendingBlockNumber {
+ if number == rpc.PendingBlockNumber && api.b.ChainConfig().Optimism == nil {
// Pending header need to nil out a few fields
for _, field := range []string{"hash", "nonce", "miner"} {
response[field] = nil
@@ -496,14 +531,14 @@ // only the transaction hash is returned.
func (api *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
block, err := api.b.BlockByNumber(ctx, number)
if block != nil && err == nil {
- response := RPCMarshalBlock(block, true, fullTx, api.b.ChainConfig())
- if number == rpc.PendingBlockNumber {
+ response, err := RPCMarshalBlock(ctx, block, true, fullTx, api.b.ChainConfig(), api.b)
+ if err == nil && number == rpc.PendingBlockNumber && api.b.ChainConfig().Optimism == nil {
// Pending blocks need to nil out a few fields
for _, field := range []string{"hash", "nonce", "miner"} {
response[field] = nil
}
}
- return response, nil
+ return response, err
}
return nil, err
}
@@ -513,7 +548,7 @@ // detail, otherwise only the transaction hash is returned.
func (api *BlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) {
block, err := api.b.BlockByHash(ctx, hash)
if block != nil {
- return RPCMarshalBlock(block, true, fullTx, api.b.ChainConfig()), nil
+ return RPCMarshalBlock(ctx, block, true, fullTx, api.b.ChainConfig(), api.b)
}
return nil, err
}
@@ -528,7 +563,7 @@ log.Debug("Requested uncle not found", "number", blockNr, "hash", block.Hash(), "index", index)
return nil, nil
}
block = types.NewBlockWithHeader(uncles[index])
- return RPCMarshalBlock(block, false, false, api.b.ChainConfig()), nil
+ return RPCMarshalBlock(ctx, block, false, false, api.b.ChainConfig(), api.b)
}
return nil, err
}
@@ -543,7 +578,7 @@ log.Debug("Requested uncle not found", "number", block.Number(), "hash", blockHash, "index", index)
return nil, nil
}
block = types.NewBlockWithHeader(uncles[index])
- return RPCMarshalBlock(block, false, false, api.b.ChainConfig()), nil
+ return RPCMarshalBlock(ctx, block, false, false, api.b.ChainConfig(), api.b)
}
return nil, err
}
@@ -568,10 +603,29 @@ }
// GetCode returns the code stored at the given address in the state for the given block number.
func (api *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
+ header, err := headerByNumberOrHash(ctx, api.b, blockNrOrHash)
+ if err != nil {
+ return nil, err
+ }
+
+ if api.b.ChainConfig().IsOptimismPreBedrock(header.Number) {
+ if api.b.HistoricalRPCService() != nil {
+ var res hexutil.Bytes
+ err := api.b.HistoricalRPCService().CallContext(ctx, &res, "eth_getCode", address, blockNrOrHash)
+ if err != nil {
+ return nil, fmt.Errorf("historical backend error: %w", err)
+ }
+ return res, nil
+ } else {
+ return nil, rpc.ErrNoHistoricalFallback
+ }
+ }
+
state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
if state == nil || err != nil {
return nil, err
}
+
code := state.GetCode(address)
return code, state.Error()
}
@@ -580,10 +634,29 @@ // GetStorageAt returns the storage from the state at the given address, key and
// block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
// numbers are also allowed.
func (api *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, hexKey string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
+ header, err := headerByNumberOrHash(ctx, api.b, blockNrOrHash)
+ if err != nil {
+ return nil, err
+ }
+
+ if api.b.ChainConfig().IsOptimismPreBedrock(header.Number) {
+ if api.b.HistoricalRPCService() != nil {
+ var res hexutil.Bytes
+ err := api.b.HistoricalRPCService().CallContext(ctx, &res, "eth_getStorageAt", address, hexKey, blockNrOrHash)
+ if err != nil {
+ return nil, fmt.Errorf("historical backend error: %w", err)
+ }
+ return res, nil
+ } else {
+ return nil, rpc.ErrNoHistoricalFallback
+ }
+ }
+
state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
if state == nil || err != nil {
return nil, err
}
+
key, _, err := decodeHash(hexKey)
if err != nil {
return nil, fmt.Errorf("unable to decode storage key: %s", err)
@@ -592,6 +665,18 @@ res := state.GetState(address, key)
return res[:], state.Error()
}
+// The HeaderByNumberOrHash method returns a nil error and nil header
+// if the header is not found, but only for nonexistent block numbers. This is
+// different from StateAndHeaderByNumberOrHash. To account for this discrepancy,
+// headerOrNumberByHash will properly convert the error into an ethereum.NotFound.
+func headerByNumberOrHash(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) {
+ header, err := b.HeaderByNumberOrHash(ctx, blockNrOrHash)
+ if header == nil {
+ return nil, fmt.Errorf("header %w", ethereum.NotFound)
+ }
+ return header, err
+}
+
// GetBlockReceipts returns the block receipts for the given block hash or number or tag.
func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]map[string]interface{}, error) {
block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash)
@@ -614,7 +699,7 @@ signer := types.MakeSigner(api.b.ChainConfig(), block.Number(), block.Time())
result := make([]map[string]interface{}, len(receipts))
for i, receipt := range receipts {
- result[i] = marshalReceipt(receipt, block.Hash(), block.NumberU64(), signer, txs[i], i)
+ result[i] = marshalReceipt(receipt, block.Hash(), block.NumberU64(), signer, txs[i], i, api.b.ChainConfig())
}
return result, nil
@@ -653,7 +738,7 @@ return header
}
func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
- blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
+ blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil, b.ChainConfig(), state)
if blockOverrides != nil {
blockOverrides.Apply(&blockCtx)
}
@@ -752,6 +837,25 @@ if blockNrOrHash == nil {
latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
blockNrOrHash = &latest
}
+
+ header, err := headerByNumberOrHash(ctx, api.b, *blockNrOrHash)
+ if err != nil {
+ return nil, err
+ }
+
+ if api.b.ChainConfig().IsOptimismPreBedrock(header.Number) {
+ if api.b.HistoricalRPCService() != nil {
+ var res hexutil.Bytes
+ err := api.b.HistoricalRPCService().CallContext(ctx, &res, "eth_call", args, blockNrOrHash, overrides)
+ if err != nil {
+ return nil, fmt.Errorf("historical backend error: %w", err)
+ }
+ return res, nil
+ } else {
+ return nil, rpc.ErrNoHistoricalFallback
+ }
+ }
+
result, err := DoCall(ctx, api.b, args, *blockNrOrHash, overrides, blockOverrides, api.b.RPCEVMTimeout(), api.b.RPCGasCap())
if err != nil {
return nil, err
@@ -856,6 +960,25 @@ bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
if blockNrOrHash != nil {
bNrOrHash = *blockNrOrHash
}
+
+ header, err := headerByNumberOrHash(ctx, api.b, bNrOrHash)
+ if err != nil {
+ return 0, err
+ }
+
+ if api.b.ChainConfig().IsOptimismPreBedrock(header.Number) {
+ if api.b.HistoricalRPCService() != nil {
+ var res hexutil.Uint64
+ err := api.b.HistoricalRPCService().CallContext(ctx, &res, "eth_estimateGas", args, blockNrOrHash)
+ if err != nil {
+ return 0, fmt.Errorf("historical backend error: %w", err)
+ }
+ return res, nil
+ } else {
+ return 0, rpc.ErrNoHistoricalFallback
+ }
+ }
+
return DoEstimateGas(ctx, api.b, args, bNrOrHash, overrides, blockOverrides, api.b.RPCGasCap())
}
@@ -903,7 +1026,7 @@
// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
// transaction hashes.
-func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig) map[string]interface{} {
+func RPCMarshalBlock(ctx context.Context, block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig, backend Backend) (map[string]interface{}, error) {
fields := RPCMarshalHeader(block.Header())
fields["size"] = hexutil.Uint64(block.Size())
@@ -913,7 +1036,7 @@ return tx.Hash()
}
if fullTx {
formatTx = func(idx int, tx *types.Transaction) interface{} {
- return newRPCTransactionFromBlockIndex(block, uint64(idx), config)
+ return newRPCTransactionFromBlockIndex(ctx, block, uint64(idx), config, backend)
}
}
txs := block.Transactions()
@@ -932,7 +1055,7 @@ fields["uncles"] = uncleHashes
if block.Withdrawals() != nil {
fields["withdrawals"] = block.Withdrawals()
}
- return fields
+ return fields, nil
}
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
@@ -960,11 +1083,18 @@ V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"`
YParity *hexutil.Uint64 `json:"yParity,omitempty"`
+
+ // deposit-tx only
+ SourceHash *common.Hash `json:"sourceHash,omitempty"`
+ Mint *hexutil.Big `json:"mint,omitempty"`
+ IsSystemTx *bool `json:"isSystemTx,omitempty"`
+ // deposit-tx post-Canyon only
+ DepositReceiptVersion *hexutil.Uint64 `json:"depositReceiptVersion,omitempty"`
}
// newRPCTransaction returns a transaction that will serialize to the RPC
// representation, with the given location metadata set (if available).
-func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, blockTime uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction {
+func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, blockTime uint64, index uint64, baseFee *big.Int, config *params.ChainConfig, receipt *types.Receipt) *RPCTransaction {
signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime)
from, _ := types.Sender(signer, tx)
v, r, s := tx.RawSignatureValues()
@@ -989,7 +1119,27 @@ result.TransactionIndex = (*hexutil.Uint64)(&index)
}
switch tx.Type() {
+ case types.DepositTxType:
+ srcHash := tx.SourceHash()
+ isSystemTx := tx.IsSystemTx()
+ result.SourceHash = &srcHash
+ if isSystemTx {
+ // Only include IsSystemTx when true
+ result.IsSystemTx = &isSystemTx
+ }
+ result.Mint = (*hexutil.Big)(tx.Mint())
+ if receipt != nil && receipt.DepositNonce != nil {
+ result.Nonce = hexutil.Uint64(*receipt.DepositNonce)
+ if receipt.DepositReceiptVersion != nil {
+ result.DepositReceiptVersion = new(hexutil.Uint64)
+ *result.DepositReceiptVersion = hexutil.Uint64(*receipt.DepositReceiptVersion)
+ }
+ }
case types.LegacyTxType:
+ if v.Sign() == 0 && r.Sign() == 0 && s.Sign() == 0 { // pre-bedrock relayed tx does not have a signature
+ result.ChainID = (*hexutil.Big)(new(big.Int).Set(config.ChainID))
+ break
+ }
// if a legacy transaction has an EIP-155 chain id, include it explicitly
if id := tx.ChainId(); id.Sign() != 0 {
result.ChainID = (*hexutil.Big)(id)
@@ -1074,20 +1224,36 @@ blockNumber = uint64(0)
blockTime = uint64(0)
)
if current != nil {
- baseFee = eip1559.CalcBaseFee(config, current)
+ baseFee = eip1559.CalcBaseFee(config, current, current.Time+1)
blockNumber = current.Number.Uint64()
blockTime = current.Time
}
- return newRPCTransaction(tx, common.Hash{}, blockNumber, blockTime, 0, baseFee, config)
+ return newRPCTransaction(tx, common.Hash{}, blockNumber, blockTime, 0, baseFee, config, nil)
}
// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
-func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *params.ChainConfig) *RPCTransaction {
+func newRPCTransactionFromBlockIndex(ctx context.Context, b *types.Block, index uint64, config *params.ChainConfig, backend Backend) *RPCTransaction {
txs := b.Transactions()
if index >= uint64(len(txs)) {
return nil
}
- return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), b.Time(), index, b.BaseFee(), config)
+ tx := txs[index]
+ rcpt := depositTxReceipt(ctx, b.Hash(), index, backend, tx)
+ return newRPCTransaction(tx, b.Hash(), b.NumberU64(), b.Time(), index, b.BaseFee(), config, rcpt)
+}
+
+func depositTxReceipt(ctx context.Context, blockHash common.Hash, index uint64, backend Backend, tx *types.Transaction) *types.Receipt {
+ if tx.Type() != types.DepositTxType {
+ return nil
+ }
+ receipts, err := backend.GetReceipts(ctx, blockHash)
+ if err != nil {
+ return nil
+ }
+ if index >= uint64(len(receipts)) {
+ return nil
+ }
+ return receipts[index]
}
// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
@@ -1111,12 +1277,27 @@ }
// CreateAccessList creates an EIP-2930 type AccessList for the given transaction.
// Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state.
-func (api *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) {
+func (api *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, state *state.StateDB, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) {
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
if blockNrOrHash != nil {
bNrOrHash = *blockNrOrHash
}
- acl, gasUsed, vmerr, err := AccessList(ctx, api.b, bNrOrHash, args)
+
+ header, err := headerByNumberOrHash(ctx, api.b, bNrOrHash)
+ if err == nil && header != nil && api.b.ChainConfig().IsOptimismPreBedrock(header.Number) {
+ if api.b.HistoricalRPCService() != nil {
+ var res accessListResult
+ err := api.b.HistoricalRPCService().CallContext(ctx, &res, "eth_createAccessList", args, blockNrOrHash)
+ if err != nil {
+ return nil, fmt.Errorf("historical backend error: %w", err)
+ }
+ return &res, nil
+ } else {
+ return nil, rpc.ErrNoHistoricalFallback
+ }
+ }
+
+ acl, gasUsed, vmerr, err := AccessList(ctx, api.b, bNrOrHash, args, state)
if err != nil {
return nil, err
}
@@ -1130,7 +1311,7 @@
// AccessList creates an access list for the given transaction.
// If the accesslist creation fails an error is returned.
// If the transaction itself fails, an vmErr is returned.
-func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrHash, args TransactionArgs) (acl types.AccessList, gasUsed uint64, vmErr error, err error) {
+func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrHash, args TransactionArgs, state *state.StateDB) (acl types.AccessList, gasUsed uint64, vmErr error, err error) {
// Retrieve the execution context
db, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
if db == nil || err != nil {
@@ -1145,7 +1326,7 @@ if args.Nonce == nil {
nonce := hexutil.Uint64(db.GetNonce(args.from()))
args.Nonce = &nonce
}
- blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
+ blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil, b.ChainConfig(), state)
if err = args.CallDefaults(b.RPCGasCap(), blockCtx.BaseFee, b.ChainConfig().ChainID); err != nil {
return nil, 0, nil, err
}
@@ -1239,7 +1420,7 @@
// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index.
func (api *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction {
if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil {
- return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig())
+ return newRPCTransactionFromBlockIndex(ctx, block, uint64(index), api.b.ChainConfig(), api.b)
}
return nil
}
@@ -1247,7 +1428,7 @@
// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index.
func (api *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction {
if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil {
- return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig())
+ return newRPCTransactionFromBlockIndex(ctx, block, uint64(index), api.b.ChainConfig(), api.b)
}
return nil
}
@@ -1279,10 +1460,29 @@ }
return (*hexutil.Uint64)(&nonce), nil
}
// Resolve block number and use its state to ask for the nonce
+ header, err := headerByNumberOrHash(ctx, api.b, blockNrOrHash)
+ if err != nil {
+ return nil, err
+ }
+
+ if api.b.ChainConfig().IsOptimismPreBedrock(header.Number) {
+ if api.b.HistoricalRPCService() != nil {
+ var res hexutil.Uint64
+ err := api.b.HistoricalRPCService().CallContext(ctx, &res, "eth_getTransactionCount", address, blockNrOrHash)
+ if err != nil {
+ return nil, fmt.Errorf("historical backend error: %w", err)
+ }
+ return &res, nil
+ } else {
+ return nil, rpc.ErrNoHistoricalFallback
+ }
+ }
+
state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
if state == nil || err != nil {
return nil, err
}
+
nonce := state.GetNonce(address)
return (*hexutil.Uint64)(&nonce), state.Error()
}
@@ -1305,7 +1505,8 @@ header, err := api.b.HeaderByHash(ctx, blockHash)
if err != nil {
return nil, err
}
- return newRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, api.b.ChainConfig()), nil
+ rcpt := depositTxReceipt(ctx, blockHash, index, api.b, tx)
+ return newRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, api.b.ChainConfig(), rcpt), nil
}
// GetRawTransactionByHash returns the bytes of the transaction for the given hash.
@@ -1348,11 +1549,11 @@ receipt := receipts[index]
// Derive the sender.
signer := types.MakeSigner(api.b.ChainConfig(), header.Number, header.Time)
- return marshalReceipt(receipt, blockHash, blockNumber, signer, tx, int(index)), nil
+ return marshalReceipt(receipt, blockHash, blockNumber, signer, tx, int(index), api.b.ChainConfig()), nil
}
// marshalReceipt marshals a transaction receipt into a JSON object.
-func marshalReceipt(receipt *types.Receipt, blockHash common.Hash, blockNumber uint64, signer types.Signer, tx *types.Transaction, txIndex int) map[string]interface{} {
+func marshalReceipt(receipt *types.Receipt, blockHash common.Hash, blockNumber uint64, signer types.Signer, tx *types.Transaction, txIndex int, chainConfig *params.ChainConfig) map[string]interface{} {
from, _ := types.Sender(signer, tx)
fields := map[string]interface{}{
@@ -1371,6 +1572,32 @@ "type": hexutil.Uint(tx.Type()),
"effectiveGasPrice": (*hexutil.Big)(receipt.EffectiveGasPrice),
}
+ if chainConfig.Optimism != nil && !tx.IsDepositTx() {
+ fields["l1GasPrice"] = (*hexutil.Big)(receipt.L1GasPrice)
+ fields["l1GasUsed"] = (*hexutil.Big)(receipt.L1GasUsed)
+ fields["l1Fee"] = (*hexutil.Big)(receipt.L1Fee)
+ // Fields removed with Ecotone
+ if receipt.FeeScalar != nil {
+ fields["l1FeeScalar"] = receipt.FeeScalar.String()
+ }
+ // Fields added in Ecotone
+ if receipt.L1BlobBaseFee != nil {
+ fields["l1BlobBaseFee"] = (*hexutil.Big)(receipt.L1BlobBaseFee)
+ }
+ if receipt.L1BaseFeeScalar != nil {
+ fields["l1BaseFeeScalar"] = hexutil.Uint64(*receipt.L1BaseFeeScalar)
+ }
+ if receipt.L1BlobBaseFeeScalar != nil {
+ fields["l1BlobBaseFeeScalar"] = hexutil.Uint64(*receipt.L1BlobBaseFeeScalar)
+ }
+ }
+ if chainConfig.Optimism != nil && tx.IsDepositTx() && receipt.DepositNonce != nil {
+ fields["depositNonce"] = hexutil.Uint64(*receipt.DepositNonce)
+ if receipt.DepositReceiptVersion != nil {
+ fields["depositReceiptVersion"] = hexutil.Uint64(*receipt.DepositReceiptVersion)
+ }
+ }
+
// Assign receipt status or post state.
if len(receipt.PostState) > 0 {
fields["root"] = hexutil.Bytes(receipt.PostState)
@@ -1543,6 +1770,9 @@ return nil, errors.New("gas not specified")
}
if args.GasPrice == nil && (args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil) {
return nil, errors.New("missing gasPrice or maxFeePerGas/maxPriorityFeePerGas")
+ }
+ if args.IsEIP4844() {
+ return nil, errBlobTxNotSupported
}
if args.Nonce == nil {
return nil, errors.New("nonce not specified")
@@ -1784,6 +2014,10 @@ func (api *DebugAPI) SetHead(number hexutil.Uint64) {
api.b.SetHead(uint64(number))
}
+func (api *DebugAPI) ChainConfig() *params.ChainConfig {
+ return api.b.ChainConfig()
+}
+
// NetAPI offers network related RPC methods
type NetAPI struct {
net *p2p.Server
@@ -1824,3 +2058,8 @@ return fmt.Errorf("tx fee (%.2f ether) exceeds the configured cap (%.2f ether)", feeFloat, cap)
}
return nil
}
+
+// CheckTxFee exports a helper function used to check whether the fee is reasonable
+func CheckTxFee(gasPrice *big.Int, gas uint64, cap float64) error {
+ return checkTxFee(gasPrice, gas, cap)
+}