Skip to content

Commit e5d5e09

Browse files
authored
internal/ethapi: handle blobs in API methods (#28786)
EIP-4844 adds a new transaction type for blobs. Users can submit such transactions via `eth_sendRawTransaction`. In this PR we refrain from adding support to `eth_sendTransaction` and in fact it will fail if the user passes in a blob hash. However since the chain can handle such transactions it makes sense to allow simulating them. E.g. an L2 operator should be able to simulate submitting a rollup blob and updating the L2 state. Most methods that take in a transaction object should recognize blobs. The change boils down to adding `blobVersionedHashes` and `maxFeePerBlobGas` to `TransactionArgs`. In summary: - `eth_sendTransaction`: will fail for blob txes - `eth_signTransaction`: will fail for blob txes The methods that sign txes does not, as of this PR, add support the for new EIP-4844 transaction types. Resuming the summary: - `eth_sendRawTransaction`: can send blob txes - `eth_fillTransaction`: will fill in a blob tx. Note: here we simply fill in normal transaction fields + possibly `maxFeePerBlobGas` when blobs are present. One can imagine a more elaborate set-up where users can submit blobs themselves and we fill in proofs and commitments and such. Left for future PRs if desired. - `eth_call`: can simulate blob messages - `eth_estimateGas`: blobs have no effect here. They have a separate unit of gas which is not tunable in the transaction.
1 parent 2e2e89c commit e5d5e09

35 files changed

+471
-117
lines changed

core/error.go

+6
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,10 @@ var (
104104
// ErrBlobFeeCapTooLow is returned if the transaction fee cap is less than the
105105
// blob gas fee of the block.
106106
ErrBlobFeeCapTooLow = errors.New("max fee per blob gas less than block blob gas fee")
107+
108+
// ErrMissingBlobHashes is returned if a blob transaction has no blob hashes.
109+
ErrMissingBlobHashes = errors.New("blob transaction missing blob hashes")
110+
111+
// ErrBlobTxCreate is returned if a blob transaction has no explicit to field.
112+
ErrBlobTxCreate = errors.New("blob transaction of type create")
107113
)

core/state_transition.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package core
1818

1919
import (
20-
"errors"
2120
"fmt"
2221
"math"
2322
"math/big"
@@ -315,8 +314,14 @@ func (st *StateTransition) preCheck() error {
315314
}
316315
// Check the blob version validity
317316
if msg.BlobHashes != nil {
317+
// The to field of a blob tx type is mandatory, and a `BlobTx` transaction internally
318+
// has it as a non-nillable value, so any msg derived from blob transaction has it non-nil.
319+
// However, messages created through RPC (eth_call) don't have this restriction.
320+
if msg.To == nil {
321+
return ErrBlobTxCreate
322+
}
318323
if len(msg.BlobHashes) == 0 {
319-
return errors.New("blob transaction missing blob hashes")
324+
return ErrMissingBlobHashes
320325
}
321326
for i, hash := range msg.BlobHashes {
322327
if hash[0] != params.BlobTxHashVersion {

internal/ethapi/api.go

+16
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ import (
5555
// allowed to produce in order to speed up calculations.
5656
const estimateGasErrorRatio = 0.015
5757

58+
var errBlobTxNotSupported = errors.New("signing blob transactions not supported")
59+
5860
// EthereumAPI provides an API to access Ethereum related information.
5961
type EthereumAPI struct {
6062
b Backend
@@ -468,6 +470,9 @@ func (s *PersonalAccountAPI) SendTransaction(ctx context.Context, args Transacti
468470
s.nonceLock.LockAddr(args.from())
469471
defer s.nonceLock.UnlockAddr(args.from())
470472
}
473+
if args.IsEIP4844() {
474+
return common.Hash{}, errBlobTxNotSupported
475+
}
471476
signed, err := s.signTransaction(ctx, &args, passwd)
472477
if err != nil {
473478
log.Warn("Failed transaction send attempt", "from", args.from(), "to", args.To, "value", args.Value.ToInt(), "err", err)
@@ -492,6 +497,9 @@ func (s *PersonalAccountAPI) SignTransaction(ctx context.Context, args Transacti
492497
if args.GasPrice == nil && (args.MaxFeePerGas == nil || args.MaxPriorityFeePerGas == nil) {
493498
return nil, errors.New("missing gasPrice or maxFeePerGas/maxPriorityFeePerGas")
494499
}
500+
if args.IsEIP4844() {
501+
return nil, errBlobTxNotSupported
502+
}
495503
if args.Nonce == nil {
496504
return nil, errors.New("nonce not specified")
497505
}
@@ -1219,6 +1227,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
12191227
// returns error if the transaction would revert or if there are unexpected failures. The returned
12201228
// value is capped by both `args.Gas` (if non-nil & non-zero) and the backend's RPCGasCap
12211229
// configuration (if non-zero).
1230+
// Note: Required blob gas is not computed in this method.
12221231
func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Uint64, error) {
12231232
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
12241233
if blockNrOrHash != nil {
@@ -1809,6 +1818,9 @@ func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionAr
18091818
s.nonceLock.LockAddr(args.from())
18101819
defer s.nonceLock.UnlockAddr(args.from())
18111820
}
1821+
if args.IsEIP4844() {
1822+
return common.Hash{}, errBlobTxNotSupported
1823+
}
18121824

18131825
// Set some sanity defaults and terminate on failure
18141826
if err := args.setDefaults(ctx, s.b); err != nil {
@@ -1834,6 +1846,7 @@ func (s *TransactionAPI) FillTransaction(ctx context.Context, args TransactionAr
18341846
}
18351847
// Assemble the transaction and obtain rlp
18361848
tx := args.toTransaction()
1849+
// TODO(s1na): fill in blob proofs, commitments
18371850
data, err := tx.MarshalBinary()
18381851
if err != nil {
18391852
return nil, err
@@ -1892,6 +1905,9 @@ func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionAr
18921905
if args.GasPrice == nil && (args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil) {
18931906
return nil, errors.New("missing gasPrice or maxFeePerGas/maxPriorityFeePerGas")
18941907
}
1908+
if args.IsEIP4844() {
1909+
return nil, errBlobTxNotSupported
1910+
}
18951911
if args.Nonce == nil {
18961912
return nil, errors.New("nonce not specified")
18971913
}

0 commit comments

Comments
 (0)