diff --git go-ethereum/internal/ethapi/api.go op-geth/internal/ethapi/api.go
index a50295289340d876823270b7fd12714dc8066515..7712d71273f3c2521f8f5944fbf58ecf6dc08cc1 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/accounts/keystore"
"github.com/ethereum/go-ethereum/accounts/scwallet"
@@ -665,6 +666,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
@@ -705,6 +724,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))
@@ -808,7 +843,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
@@ -838,14 +873,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
}
@@ -855,7 +890,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
}
@@ -870,7 +905,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
}
@@ -885,7 +920,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
}
@@ -910,10 +945,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()
}
@@ -922,16 +976,47 @@ // 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)
}
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.
@@ -956,7 +1041,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
@@ -1160,7 +1245,7 @@ return header
}
func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *StateOverride, blockOverrides *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)
}
@@ -1257,6 +1342,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
@@ -1360,6 +1464,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, api.b.RPCGasCap())
}
@@ -1407,7 +1530,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())
@@ -1417,7 +1540,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()
@@ -1439,7 +1562,7 @@ }
if block.Header().RequestsHash != nil {
fields["requests"] = block.Requests()
}
- return fields
+ return fields, nil
}
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
@@ -1466,11 +1589,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()
@@ -1495,7 +1625,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)
@@ -1564,20 +1714,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.
@@ -1606,6 +1772,21 @@ bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
if blockNrOrHash != nil {
bNrOrHash = *blockNrOrHash
}
+
+ 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)
if err != nil {
return nil, err
@@ -1719,7 +1900,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
}
@@ -1727,7 +1908,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
}
@@ -1759,10 +1940,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()
}
@@ -1785,7 +1985,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.
@@ -1828,11 +2029,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{}{
@@ -1851,6 +2052,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)
@@ -2023,6 +2250,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")
@@ -2264,6 +2494,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
@@ -2304,3 +2538,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)
+}