go-ethereum
go-ethereum copied to clipboard
Spec announce type-hint inconsistency for blob transactions: geth accepts non-standard Types (e.g., 0x09), reth/besu reject
System information
- Geth version:
1.16.2, reth:v1.6.0, besu:v25.8.0 - CL client & version: [email protected]
- OS & Version: Linux
- Commit hash: N/A
- Network: Ethereum Package devnet (Cancun enabled)
Expected behaviour
- When announcing a valid blob (
Type=3) transaction hash over DevP2P (eth/68) usingNewPooledTransactionHashes, theTypesandSizesfields should function as hints. Even ifTypescontains a non-standard value (e.g.,0x09or0xff), the node should still request the transaction by hash and process it if the returned transaction is valid. Ideally, all client implementations should behave consistently. - Alternatively, if
Typesis intended as a strict constraint (i.e., must accurately reflect the real transaction type), then geth should reject or ignore announcements with mismatched or unknownTypes, matching the behaviour of other clients.
Actual behaviour
- Geth accepts an announcement using
Types=0x09, sendsGetPooledTransactionsfor the hash, receives the full blob transaction (including sidecar), and successfully inserts it into the mempool. The transaction can be mined. - Reth and Besu do not request or process transactions whose announcement includes a non-standard type hint such as
0x09. The transaction never enters the mempool.
This leads to inconsistent DevP2P behaviour for blob transaction propagation across client implementations.
Steps to reproduce
-
Prepare a valid blob transaction (
Type=3), signed with the Cancun signer and including full sidecar data (blobs/commitments/proofs). -
Establish a DevP2P (
eth/68) session with a client node. -
During the announce phase, send a
NewPooledTransactionHashesmessage containing:Types: []byte{0x09}(non-standard type hint; also reproducible with0xff)Sizes: []uint32{uint32(tx.Size())}(also reproducible with0ormath.MaxUint32)Hashes: hashes(wheretxis the valid blob transaction)
-
Wait for a
GetPooledTransactionsrequest and respond with aPooledTransactionsmessage containing the full blob transaction and sidecar. -
Observe:
- Geth requests the hash, accepts the transaction, and may mine it.
- Reth and Besu do not request the hash or do not accept the transaction.
Minimal announce example (Go pseudocode using go-ethereum types)
ann := eth.NewPooledTransactionHashesPacket{
Types: []byte{0x09}, // non-standard type hint for experiment
Sizes: []uint32{uint32(tx.Size())},
Hashes: hashes, // tx is a valid Type=3 blob with sidecar
}
conn.Write(protoID, eth.NewPooledTransactionHashesMsg, ann)
req := new(eth.GetPooledTransactionsPacket)
conn.ReadMsg(protoID, eth.GetPooledTransactionsMsg, req)
resp := eth.PooledTransactionsPacket{
RequestId: req.RequestId,
PooledTransactionsResponse: eth.PooledTransactionsResponse(types.Transactions{tx}),
}
conn.Write(protoID, eth.PooledTransactionsMsg, resp)
Backtrace
No crash or error trace. Behaviour is visible in DevP2P logs:
- Geth shows
GetPooledTransactionsafter an announce withTypes=0x09, and thePooledTransactionsresponse is accepted. - Reth and Besu show no request for the hash when the announce uses a non-standard type hint.
Additional context
- The core issue appears to be whether the
TypesandSizesfields inNewPooledTransactionHashesare interpreted as strict validation filters or non-binding propagation hints. - Geth treats them as hints (still fetches by hash).
- Reth and Besu treat them as filters (ignore unknown or mismatched types).
- This misalignment results in inconsistent blob-transaction propagation across clients.