core/txpool: drop support for v0 blob sidecar (#35191)

This PR drops support for v0 blob sidecar in blobpool. Since the
osaka fork activation time has passed, these code paths are
now unused. It is assumed that only v1 transactions exist in
the blobpool.
This commit is contained in:
Bosul Mun 2026-06-22 10:31:51 +02:00 committed by GitHub
parent af7bf37b53
commit eea629b9b3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 69 additions and 304 deletions

View file

@ -1013,11 +1013,11 @@ func makeSidecar(data ...byte) *types.BlobTxSidecar {
for i := range blobs { for i := range blobs {
blobs[i][0] = data[i] blobs[i][0] = data[i]
c, _ := kzg4844.BlobToCommitment(&blobs[i]) c, _ := kzg4844.BlobToCommitment(&blobs[i])
p, _ := kzg4844.ComputeBlobProof(&blobs[i], c) cellProofs, _ := kzg4844.ComputeCellProofs(&blobs[i])
commitments = append(commitments, c) commitments = append(commitments, c)
proofs = append(proofs, p) proofs = append(proofs, cellProofs...)
} }
return types.NewBlobTxSidecar(types.BlobSidecarVersion0, blobs, commitments, proofs) return types.NewBlobTxSidecar(types.BlobSidecarVersion1, blobs, commitments, proofs)
} }
func (s *Suite) makeBlobTxs(count, blobs int, discriminator byte) (txs types.Transactions) { func (s *Suite) makeBlobTxs(count, blobs int, discriminator byte) (txs types.Transactions) {

View file

@ -228,22 +228,17 @@ func encodeForNetwork(storedRLP []byte) ([]byte, error) {
// 2. Find the version of sidecar. // 2. Find the version of sidecar.
version, _, err := rlp.SplitUint64(elems[1]) version, _, err := rlp.SplitUint64(elems[1])
if err != nil || version > 255 { if err != nil || version > 255 || version == 0 {
return nil, fmt.Errorf("invalid version: %w", err) return nil, fmt.Errorf("invalid version: %w", err)
} }
versionByte := byte(version)
// 3. Extract sidecar elements. // 3. Extract sidecar elements.
commitmentsRLP := elems[2] commitmentsRLP := elems[2]
proofsRLP := elems[3] proofsRLP := elems[3]
blobsRLP := elems[4] blobsRLP := elems[4]
// 4. Reconstruct into the network format. // 4. Reconstruct into the network format.
var outer [][]byte outer := [][]byte{txRLP, elems[1], blobsRLP, commitmentsRLP, proofsRLP}
if versionByte == types.BlobSidecarVersion0 {
outer = [][]byte{txRLP, blobsRLP, commitmentsRLP, proofsRLP}
} else {
outer = [][]byte{txRLP, elems[1], blobsRLP, commitmentsRLP, proofsRLP}
}
body, err := rlp.MergeListValues(outer) body, err := rlp.MergeListValues(outer)
if err != nil { if err != nil {
return nil, err return nil, err
@ -555,7 +550,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserver txpool.Reser
p.state = state p.state = state
// Create new slotter for pre-Osaka blob configuration. // Create new slotter for pre-Osaka blob configuration.
slotter := newSlotter(params.BlobTxMaxBlobs) slotter := newSlotterEIP7594(params.BlobTxMaxBlobs)
// See if we need to migrate the queue blob store after fusaka // See if we need to migrate the queue blob store after fusaka
slotter, err = tryMigrate(p.chain.Config(), slotter, queuedir) slotter, err = tryMigrate(p.chain.Config(), slotter, queuedir)

View file

@ -53,7 +53,6 @@ import (
var ( var (
testBlobs []*kzg4844.Blob testBlobs []*kzg4844.Blob
testBlobCommits []kzg4844.Commitment testBlobCommits []kzg4844.Commitment
testBlobProofs []kzg4844.Proof
testBlobCellProofs [][]kzg4844.Proof testBlobCellProofs [][]kzg4844.Proof
testBlobVHashes [][32]byte testBlobVHashes [][32]byte
testBlobIndices = make(map[[32]byte]int) testBlobIndices = make(map[[32]byte]int)
@ -69,9 +68,6 @@ func init() {
testBlobCommit, _ := kzg4844.BlobToCommitment(testBlob) testBlobCommit, _ := kzg4844.BlobToCommitment(testBlob)
testBlobCommits = append(testBlobCommits, testBlobCommit) testBlobCommits = append(testBlobCommits, testBlobCommit)
testBlobProof, _ := kzg4844.ComputeBlobProof(testBlob, testBlobCommit)
testBlobProofs = append(testBlobProofs, testBlobProof)
testBlobCellProof, _ := kzg4844.ComputeCellProofs(testBlob) testBlobCellProof, _ := kzg4844.ComputeCellProofs(testBlob)
testBlobCellProofs = append(testBlobCellProofs, testBlobCellProof) testBlobCellProofs = append(testBlobCellProofs, testBlobCellProof)
@ -243,7 +239,7 @@ func encodeForPool(tx *types.Transaction) []byte {
// makeMultiBlobTx is a utility method to construct a random blob tx with // makeMultiBlobTx is a utility method to construct a random blob tx with
// certain number of blobs in its sidecar. // certain number of blobs in its sidecar.
func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, blobCount int, blobOffset int, key *ecdsa.PrivateKey, version byte) *types.Transaction { func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, blobCount int, blobOffset int, key *ecdsa.PrivateKey) *types.Transaction {
var ( var (
blobs []kzg4844.Blob blobs []kzg4844.Blob
blobHashes []common.Hash blobHashes []common.Hash
@ -253,12 +249,8 @@ func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCa
for i := 0; i < blobCount; i++ { for i := 0; i < blobCount; i++ {
blobs = append(blobs, *testBlobs[blobOffset+i]) blobs = append(blobs, *testBlobs[blobOffset+i])
commitments = append(commitments, testBlobCommits[blobOffset+i]) commitments = append(commitments, testBlobCommits[blobOffset+i])
if version == types.BlobSidecarVersion0 { cellProofs, _ := kzg4844.ComputeCellProofs(testBlobs[blobOffset+i])
proofs = append(proofs, testBlobProofs[blobOffset+i]) proofs = append(proofs, cellProofs...)
} else {
cellProofs, _ := kzg4844.ComputeCellProofs(testBlobs[blobOffset+i])
proofs = append(proofs, cellProofs...)
}
blobHashes = append(blobHashes, testBlobVHashes[blobOffset+i]) blobHashes = append(blobHashes, testBlobVHashes[blobOffset+i])
} }
blobtx := &types.BlobTx{ blobtx := &types.BlobTx{
@ -270,7 +262,7 @@ func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCa
BlobFeeCap: uint256.NewInt(blobFeeCap), BlobFeeCap: uint256.NewInt(blobFeeCap),
BlobHashes: blobHashes, BlobHashes: blobHashes,
Value: uint256.NewInt(100), Value: uint256.NewInt(100),
Sidecar: types.NewBlobTxSidecar(version, blobs, commitments, proofs), Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion1, blobs, commitments, proofs),
} }
return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx) return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
} }
@ -293,7 +285,7 @@ func makeUnsignedTxWithTestBlob(nonce uint64, gasTipCap uint64, gasFeeCap uint64
BlobFeeCap: uint256.NewInt(blobFeeCap), BlobFeeCap: uint256.NewInt(blobFeeCap),
BlobHashes: []common.Hash{testBlobVHashes[blobIdx]}, BlobHashes: []common.Hash{testBlobVHashes[blobIdx]},
Value: uint256.NewInt(100), Value: uint256.NewInt(100),
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, []kzg4844.Blob{*testBlobs[blobIdx]}, []kzg4844.Commitment{testBlobCommits[blobIdx]}, []kzg4844.Proof{testBlobProofs[blobIdx]}), Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion1, []kzg4844.Blob{*testBlobs[blobIdx]}, []kzg4844.Commitment{testBlobCommits[blobIdx]}, testBlobCellProofs[blobIdx]),
} }
} }
@ -440,36 +432,18 @@ func verifyBlobRetrievals(t *testing.T, pool *BlobPool) {
hashes = append(hashes, tx.vhashes...) hashes = append(hashes, tx.vhashes...)
} }
} }
blobs1, _, proofs1, err := pool.getBlobs(hashes, types.BlobSidecarVersion0) blobs, _, proofs, err := pool.getBlobs(hashes, types.BlobSidecarVersion1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
blobs2, _, proofs2, err := pool.getBlobs(hashes, types.BlobSidecarVersion1) if len(blobs) != len(hashes) || len(proofs) != len(hashes) {
if err != nil { t.Errorf("retrieved blobs/proofs size mismatch: have %d/%d, want blobs %d, want proofs: %d", len(blobs), len(proofs), len(hashes), len(hashes))
t.Fatal(err)
}
// Cross validate what we received vs what we wanted
if len(blobs1) != len(hashes) || len(proofs1) != len(hashes) {
t.Errorf("retrieved blobs/proofs size mismatch: have %d/%d, want %d", len(blobs1), len(proofs1), len(hashes))
return
}
if len(blobs2) != len(hashes) || len(proofs2) != len(hashes) {
t.Errorf("retrieved blobs/proofs size mismatch: have %d/%d, want blobs %d, want proofs: %d", len(blobs2), len(proofs2), len(hashes), len(hashes))
return return
} }
for i, hash := range hashes { for i, hash := range hashes {
// If an item is missing from both, but shouldn't, error
if (blobs1[i] == nil || proofs1[i] == nil) && (blobs2[i] == nil || proofs2[i] == nil) {
t.Errorf("tracked blob retrieval failed: item %d, hash %x", i, hash)
continue
}
// Item retrieved, make sure it matches the expectation // Item retrieved, make sure it matches the expectation
index := testBlobIndices[hash] index := testBlobIndices[hash]
if blobs1[i] != nil && (*blobs1[i] != *testBlobs[index] || proofs1[i][0] != testBlobProofs[index]) { if blobs[i] != nil && (*blobs[i] != *testBlobs[index] || !slices.Equal(proofs[i], testBlobCellProofs[index])) {
t.Errorf("retrieved blob or proof mismatch: item %d, hash %x", i, hash)
continue
}
if blobs2[i] != nil && (*blobs2[i] != *testBlobs[index] || !slices.Equal(proofs2[i], testBlobCellProofs[index])) {
t.Errorf("retrieved blob or proof mismatch: item %d, hash %x", i, hash) t.Errorf("retrieved blob or proof mismatch: item %d, hash %x", i, hash)
continue continue
} }
@ -503,7 +477,7 @@ func TestOpenDrops(t *testing.T) {
storage := t.TempDir() storage := t.TempDir()
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotterEIP7594(testMaxBlobsPerBlock), nil)
// Insert a malformed transaction to verify that decoding errors (or format // Insert a malformed transaction to verify that decoding errors (or format
// changes) are handled gracefully (case 1) // changes) are handled gracefully (case 1)
@ -825,7 +799,7 @@ func TestOpenIndex(t *testing.T) {
storage := t.TempDir() storage := t.TempDir()
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotterEIP7594(testMaxBlobsPerBlock), nil)
// Insert a sequence of transactions with varying price points to check that // Insert a sequence of transactions with varying price points to check that
// the cumulative minimum will be maintained. // the cumulative minimum will be maintained.
@ -913,7 +887,7 @@ func TestOpenHeap(t *testing.T) {
storage := t.TempDir() storage := t.TempDir()
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotterEIP7594(testMaxBlobsPerBlock), nil)
// Insert a few transactions from a few accounts. To remove randomness from // Insert a few transactions from a few accounts. To remove randomness from
// the heap initialization, use a deterministic account/tx/priority ordering. // the heap initialization, use a deterministic account/tx/priority ordering.
@ -1088,7 +1062,7 @@ func TestChangingSlotterSize(t *testing.T) {
storage := t.TempDir() storage := t.TempDir()
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(6), nil) store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotterEIP7594(6), nil)
// Create transactions from a few accounts. // Create transactions from a few accounts.
var ( var (
@ -1100,9 +1074,9 @@ func TestChangingSlotterSize(t *testing.T) {
addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey)
tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0) tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1)
tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 0, key2, types.BlobSidecarVersion0) tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 0, key2)
tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, 0, key3, types.BlobSidecarVersion0) tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, 0, key3)
blob1 = encodeForPool(tx1) blob1 = encodeForPool(tx1)
blob2 = encodeForPool(tx2) blob2 = encodeForPool(tx2)
@ -1203,9 +1177,9 @@ func TestBillyMigration(t *testing.T) {
addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey)
tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0) tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1)
tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 0, key2, types.BlobSidecarVersion0) tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 0, key2)
tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, 0, key3, types.BlobSidecarVersion0) tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, 0, key3)
blob1 = encodeForPool(tx1) blob1 = encodeForPool(tx1)
blob2 = encodeForPool(tx2) blob2 = encodeForPool(tx2)
@ -1299,7 +1273,7 @@ func TestLegacyTxConversion(t *testing.T) {
// Initialize the pending store with two blob transactions encoded in the // Initialize the pending store with two blob transactions encoded in the
// legacy format. // legacy format.
queuedir := filepath.Join(storage, pendingTransactionStore) queuedir := filepath.Join(storage, pendingTransactionStore)
store, err := billy.Open(billy.Options{Path: queuedir}, newSlotter(testMaxBlobsPerBlock), nil) store, err := billy.Open(billy.Options{Path: queuedir}, newSlotterEIP7594(testMaxBlobsPerBlock), nil)
if err != nil { if err != nil {
t.Fatalf("failed to open billy: %v", err) t.Fatalf("failed to open billy: %v", err)
} }
@ -1309,8 +1283,8 @@ func TestLegacyTxConversion(t *testing.T) {
addr1 := crypto.PubkeyToAddress(key1.PublicKey) addr1 := crypto.PubkeyToAddress(key1.PublicKey)
addr2 := crypto.PubkeyToAddress(key2.PublicKey) addr2 := crypto.PubkeyToAddress(key2.PublicKey)
tx1 := makeMultiBlobTx(0, 1, 1000, 100, 2, 0, key1, types.BlobSidecarVersion0) tx1 := makeMultiBlobTx(0, 1, 1000, 100, 2, 0, key1)
tx2 := makeMultiBlobTx(0, 1, 1000, 100, 2, 2, key2, types.BlobSidecarVersion0) tx2 := makeMultiBlobTx(0, 1, 1000, 100, 2, 2, key2)
for _, tx := range []*types.Transaction{tx1, tx2} { for _, tx := range []*types.Transaction{tx1, tx2} {
legacy, err := rlp.EncodeToBytes(tx) legacy, err := rlp.EncodeToBytes(tx)
@ -1408,8 +1382,8 @@ func TestBlobCountLimit(t *testing.T) {
// Attempt to add transactions. // Attempt to add transactions.
var ( var (
tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0) tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1)
tx2 = makeMultiBlobTx(0, 1, 800, 70, 7, 0, key2, types.BlobSidecarVersion0) tx2 = makeMultiBlobTx(0, 1, 800, 70, 7, 0, key2)
) )
errs := pool.Add([]*types.Transaction{tx1, tx2}, true) errs := pool.Add([]*types.Transaction{tx1, tx2}, true)
@ -1811,7 +1785,7 @@ func TestAdd(t *testing.T) {
storage := filepath.Join(t.TempDir(), fmt.Sprintf("test-%d", i)) storage := filepath.Join(t.TempDir(), fmt.Sprintf("test-%d", i))
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotterEIP7594(testMaxBlobsPerBlock), nil)
// Insert the seed transactions for the pool startup // Insert the seed transactions for the pool startup
var ( var (
@ -1922,7 +1896,7 @@ func TestGetBlobs(t *testing.T) {
storage := t.TempDir() storage := t.TempDir()
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(params.BlobTxMaxBlobs), nil) store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotterEIP7594(params.BlobTxMaxBlobs), nil)
// Create transactions from a few accounts. // Create transactions from a few accounts.
var ( var (
@ -1934,9 +1908,9 @@ func TestGetBlobs(t *testing.T) {
addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey)
tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0) // [0, 6) tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1) // [0, 6)
tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 6, key2, types.BlobSidecarVersion1) // [6, 12) tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 6, key2) // [6, 12)
tx3 = makeMultiBlobTx(0, 1, 800, 110, 6, 12, key3, types.BlobSidecarVersion0) // [12, 18) tx3 = makeMultiBlobTx(0, 1, 800, 110, 6, 12, key3) // [12, 18)
blob1 = encodeForPool(tx1) blob1 = encodeForPool(tx1)
blob2 = encodeForPool(tx2) blob2 = encodeForPool(tx2)
@ -2004,7 +1978,7 @@ func TestGetBlobs(t *testing.T) {
}{ }{
{ {
start: 0, limit: 6, start: 0, limit: 6,
version: types.BlobSidecarVersion0, version: types.BlobSidecarVersion1,
}, },
{ {
start: 0, limit: 6, start: 0, limit: 6,
@ -2012,7 +1986,7 @@ func TestGetBlobs(t *testing.T) {
}, },
{ {
start: 0, limit: 6, fillRandom: true, start: 0, limit: 6, fillRandom: true,
version: types.BlobSidecarVersion0, version: types.BlobSidecarVersion1,
}, },
{ {
start: 0, limit: 6, fillRandom: true, start: 0, limit: 6, fillRandom: true,
@ -2020,7 +1994,7 @@ func TestGetBlobs(t *testing.T) {
}, },
{ {
start: 3, limit: 9, start: 3, limit: 9,
version: types.BlobSidecarVersion0, version: types.BlobSidecarVersion1,
}, },
{ {
start: 3, limit: 9, start: 3, limit: 9,
@ -2028,7 +2002,7 @@ func TestGetBlobs(t *testing.T) {
}, },
{ {
start: 3, limit: 9, fillRandom: true, start: 3, limit: 9, fillRandom: true,
version: types.BlobSidecarVersion0, version: types.BlobSidecarVersion1,
}, },
{ {
start: 3, limit: 9, fillRandom: true, start: 3, limit: 9, fillRandom: true,
@ -2036,7 +2010,7 @@ func TestGetBlobs(t *testing.T) {
}, },
{ {
start: 3, limit: 15, start: 3, limit: 15,
version: types.BlobSidecarVersion0, version: types.BlobSidecarVersion1,
}, },
{ {
start: 3, limit: 15, start: 3, limit: 15,
@ -2044,7 +2018,7 @@ func TestGetBlobs(t *testing.T) {
}, },
{ {
start: 3, limit: 15, fillRandom: true, start: 3, limit: 15, fillRandom: true,
version: types.BlobSidecarVersion0, version: types.BlobSidecarVersion1,
}, },
{ {
start: 3, limit: 15, fillRandom: true, start: 3, limit: 15, fillRandom: true,
@ -2052,7 +2026,7 @@ func TestGetBlobs(t *testing.T) {
}, },
{ {
start: 0, limit: 18, start: 0, limit: 18,
version: types.BlobSidecarVersion0, version: types.BlobSidecarVersion1,
}, },
{ {
start: 0, limit: 18, start: 0, limit: 18,
@ -2060,7 +2034,7 @@ func TestGetBlobs(t *testing.T) {
}, },
{ {
start: 0, limit: 18, fillRandom: true, start: 0, limit: 18, fillRandom: true,
version: types.BlobSidecarVersion0, version: types.BlobSidecarVersion1,
}, },
{ {
start: 0, limit: 18, fillRandom: true, start: 0, limit: 18, fillRandom: true,
@ -2114,7 +2088,7 @@ func TestGetBlobs(t *testing.T) {
if blobs[j] == nil || proofs[j] == nil { if blobs[j] == nil || proofs[j] == nil {
// This is only an error if there was no version mismatch // This is only an error if there was no version mismatch
if (c.version == types.BlobSidecarVersion1 && 6 <= testBlobIndex && testBlobIndex < 12) || if (c.version == types.BlobSidecarVersion1 && 6 <= testBlobIndex && testBlobIndex < 12) ||
(c.version == types.BlobSidecarVersion0 && (testBlobIndex < 6 || 12 <= testBlobIndex)) { (c.version == types.BlobSidecarVersion1 && (testBlobIndex < 6 || 12 <= testBlobIndex)) {
t.Errorf("tracked blob retrieval failed: item %d, hash %x", j, vhashes[j]) t.Errorf("tracked blob retrieval failed: item %d, hash %x", j, vhashes[j])
} }
continue continue
@ -2125,15 +2099,9 @@ func TestGetBlobs(t *testing.T) {
continue continue
} }
// Item retrieved, make sure the proof matches the expectation // Item retrieved, make sure the proof matches the expectation
if c.version == types.BlobSidecarVersion0 { want, _ := kzg4844.ComputeCellProofs(blobs[j])
if proofs[j][0] != testBlobProofs[testBlobIndex] { if !reflect.DeepEqual(want, proofs[j]) {
t.Errorf("retrieved proof mismatch: item %d, hash %x", j, vhashes[j]) t.Errorf("retrieved proof mismatch: item %d, hash %x", j, vhashes[j])
}
} else {
want, _ := kzg4844.ComputeCellProofs(blobs[j])
if !reflect.DeepEqual(want, proofs[j]) {
t.Errorf("retrieved proof mismatch: item %d, hash %x", j, vhashes[j])
}
} }
} }
} }
@ -2143,13 +2111,12 @@ func TestGetBlobs(t *testing.T) {
// TestEncodeForNetwork verifies that encodeForNetwork produces output identical // TestEncodeForNetwork verifies that encodeForNetwork produces output identical
// to rlp.EncodeToBytes on the original transaction, for both V0 and V1 sidecars. // to rlp.EncodeToBytes on the original transaction, for both V0 and V1 sidecars.
func TestEncodeForNetwork(t *testing.T) { func TestEncodeForNetwork(t *testing.T) {
t.Run("v0", func(t *testing.T) { testEncodeForNetwork(t, types.BlobSidecarVersion0) }) t.Run("v1", func(t *testing.T) { testEncodeForNetwork(t) })
t.Run("v1", func(t *testing.T) { testEncodeForNetwork(t, types.BlobSidecarVersion1) })
} }
func testEncodeForNetwork(t *testing.T, version byte) { func testEncodeForNetwork(t *testing.T) {
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
tx := makeMultiBlobTx(0, 1, 1, 1, 1, 0, key, version) tx := makeMultiBlobTx(0, 1, 1, 1, 1, 0, key)
wantRLP, err := rlp.EncodeToBytes(tx) wantRLP, err := rlp.EncodeToBytes(tx)
if err != nil { if err != nil {
@ -2162,7 +2129,7 @@ func testEncodeForNetwork(t *testing.T, version byte) {
t.Fatalf("encodeForNetwork failed: %v", err) t.Fatalf("encodeForNetwork failed: %v", err)
} }
if !bytes.Equal(gotRLP, wantRLP) { if !bytes.Equal(gotRLP, wantRLP) {
t.Fatalf("network encoding mismatch (version %d): got %d bytes, want %d bytes", version, len(gotRLP), len(wantRLP)) t.Fatalf("network encoding mismatch: got %d bytes, want %d bytes", len(gotRLP), len(wantRLP))
} }
} }

View file

@ -343,22 +343,15 @@ func (c *Cache) update(want []common.Hash) {
if _, exists := c.entries[v]; exists { if _, exists := c.entries[v]; exists {
continue // recompute only new entries continue // recompute only new entries
} }
var pf []kzg4844.Proof cellProofs, err := sidecar.CellProofsAt(i)
switch sidecar.Version { if err != nil {
case types.BlobSidecarVersion0: log.Error("Failed to get cell proofs", "txhash", ptx.Tx.Hash(), "err", err)
pf = []kzg4844.Proof{sidecar.Proofs[i]} continue
case types.BlobSidecarVersion1:
cellProofs, err := sidecar.CellProofsAt(i)
if err != nil {
log.Error("Failed to get cell proofs", "txhash", ptx.Tx.Hash(), "err", err)
continue
}
pf = cellProofs
} }
c.entries[v] = &cachedBlob{ c.entries[v] = &cachedBlob{
blob: &sidecar.Blobs[i], blob: &sidecar.Blobs[i],
commitment: sidecar.Commitments[i], commitment: sidecar.Commitments[i],
proofs: pf, proofs: cellProofs,
version: sidecar.Version, version: sidecar.Version,
} }
cacheBlobsGauge.Inc(1) cacheBlobsGauge.Inc(1)

View file

@ -58,7 +58,7 @@ func newTestCache(t *testing.T, txConfig []txSpec) *testCache {
if err := os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700); err != nil { if err := os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700); err != nil {
t.Fatalf("mkdir: %v", err) t.Fatalf("mkdir: %v", err)
} }
store, err := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(params.BlobTxMaxBlobs), nil) store, err := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotterEIP7594(params.BlobTxMaxBlobs), nil)
if err != nil { if err != nil {
t.Fatalf("billy open: %v", err) t.Fatalf("billy open: %v", err)
} }
@ -70,7 +70,7 @@ func newTestCache(t *testing.T, txConfig []txSpec) *testCache {
) )
for _, s := range txConfig { for _, s := range txConfig {
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
tx := makeMultiBlobTx(0, s.tip, 1_000_000, 1_000_000, s.blobs, offset, key, types.BlobSidecarVersion1) tx := makeMultiBlobTx(0, s.tip, 1_000_000, 1_000_000, s.blobs, offset, key)
if _, err := store.Put(encodeForPool(tx)); err != nil { if _, err := store.Put(encodeForPool(tx)); err != nil {
t.Fatalf("store put: %v", err) t.Fatalf("store put: %v", err)
} }
@ -143,7 +143,7 @@ func newTestCache(t *testing.T, txConfig []txSpec) *testCache {
func (tc *testCache) inject(t *testing.T, spec txSpec) []common.Hash { func (tc *testCache) inject(t *testing.T, spec txSpec) []common.Hash {
t.Helper() t.Helper()
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
tx := makeMultiBlobTx(0, spec.tip, 1_000_000, 1_000_000, spec.blobs, tc.offset, key, types.BlobSidecarVersion1) tx := makeMultiBlobTx(0, spec.tip, 1_000_000, 1_000_000, spec.blobs, tc.offset, key)
tc.offset += spec.blobs tc.offset += spec.blobs
ptx := newBlobTxForPool(tx) ptx := newBlobTxForPool(tx)

View file

@ -56,7 +56,7 @@ func newLimbo(config *params.ChainConfig, datadir string) (*limbo, error) {
} }
// Create new slotter for pre-Osaka blob configuration. // Create new slotter for pre-Osaka blob configuration.
slotter := newSlotter(params.BlobTxMaxBlobs) slotter := newSlotterEIP7594(params.BlobTxMaxBlobs)
// See if we need to migrate the limbo after fusaka. // See if we need to migrate the limbo after fusaka.
slotter, err := tryMigrate(config, slotter, datadir) slotter, err := tryMigrate(config, slotter, datadir)

View file

@ -58,27 +58,6 @@ func tryMigrate(config *params.ChainConfig, slotter billy.SlotSizeFn, datadir st
return slotter, nil return slotter, nil
} }
// newSlotter creates a helper method for the Billy datastore that returns the
// individual shelf sizes used to store transactions in.
//
// The slotter will create shelves for each possible blob count + some tx metadata
// wiggle room, up to the max permitted limits.
//
// The slotter also creates a shelf for 0-blob transactions. Whilst those are not
// allowed in the current protocol, having an empty shelf is not a relevant use
// of resources, but it makes stress testing with junk transactions simpler.
func newSlotter(maxBlobsPerTransaction int) billy.SlotSizeFn {
slotsize := uint32(txAvgSize)
slotsize -= uint32(blobSize) // underflows, it's ok, will overflow back in the first return
return func() (size uint32, done bool) {
slotsize += blobSize
finished := slotsize > uint32(maxBlobsPerTransaction)*blobSize+txMaxSize
return slotsize, finished
}
}
// newSlotterEIP7594 creates a different slotter for EIP-7594 transactions. // newSlotterEIP7594 creates a different slotter for EIP-7594 transactions.
// EIP-7594 (PeerDAS) changes the average transaction size which means the current // EIP-7594 (PeerDAS) changes the average transaction size which means the current
// static 4KB average size is not enough anymore. // static 4KB average size is not enough anymore.

View file

@ -20,47 +20,6 @@ import (
"testing" "testing"
) )
// Tests that the slotter creates the expected database shelves.
func TestNewSlotter(t *testing.T) {
// Generate the database shelve sizes
slotter := newSlotter(6)
var shelves []uint32
for {
shelf, done := slotter()
shelves = append(shelves, shelf)
if done {
break
}
}
// Compare the database shelves to the expected ones
want := []uint32{
0*blobSize + txAvgSize, // 0 blob + some expected tx infos
1*blobSize + txAvgSize, // 1 blob + some expected tx infos
2*blobSize + txAvgSize, // 2 blob + some expected tx infos (could be fewer blobs and more tx data)
3*blobSize + txAvgSize, // 3 blob + some expected tx infos (could be fewer blobs and more tx data)
4*blobSize + txAvgSize, // 4 blob + some expected tx infos (could be fewer blobs and more tx data)
5*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size
6*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size
7*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size
8*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size
9*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size
10*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size
11*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size
12*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size
13*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos < 4 blobs + max tx metadata size
14*blobSize + txAvgSize, // 1-6 blobs + unexpectedly large tx infos >= 4 blobs + max tx metadata size
}
if len(shelves) != len(want) {
t.Errorf("shelves count mismatch: have %d, want %d", len(shelves), len(want))
}
for i := 0; i < len(shelves) && i < len(want); i++ {
if shelves[i] != want[i] {
t.Errorf("shelf %d mismatch: have %d, want %d", i, shelves[i], want[i])
}
}
}
// Tests that the slotter creates the expected database shelves. // Tests that the slotter creates the expected database shelves.
func TestNewSlotterEIP7594(t *testing.T) { func TestNewSlotterEIP7594(t *testing.T) {
// Generate the database shelve sizes // Generate the database shelve sizes

View file

@ -154,7 +154,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
return fmt.Errorf("%w: gas tip cap %v, minimum needed %v", ErrTxGasPriceTooLow, tx.GasTipCap(), opts.MinTip) return fmt.Errorf("%w: gas tip cap %v, minimum needed %v", ErrTxGasPriceTooLow, tx.GasTipCap(), opts.MinTip)
} }
if tx.Type() == types.BlobTxType { if tx.Type() == types.BlobTxType {
return validateBlobTx(tx, head, opts) return validateBlobTx(tx)
} }
if tx.Type() == types.SetCodeTxType { if tx.Type() == types.SetCodeTxType {
if len(tx.SetCodeAuthorizations()) == 0 { if len(tx.SetCodeAuthorizations()) == 0 {
@ -165,19 +165,14 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
} }
// validateBlobTx implements the blob-transaction specific validations. // validateBlobTx implements the blob-transaction specific validations.
func validateBlobTx(tx *types.Transaction, head *types.Header, opts *ValidationOptions) error { func validateBlobTx(tx *types.Transaction) error {
sidecar := tx.BlobTxSidecar() sidecar := tx.BlobTxSidecar()
if sidecar == nil { if sidecar == nil {
return errors.New("missing sidecar in blob transaction") return errors.New("missing sidecar in blob transaction")
} }
// Ensure the sidecar is constructed with the correct version, consistent // Ensure the sidecar is constructed with the correct version
// with the current fork. if sidecar.Version != types.BlobSidecarVersion1 {
version := types.BlobSidecarVersion0 return fmt.Errorf("unexpected sidecar version, want: %d, got: %d", types.BlobSidecarVersion1, sidecar.Version)
if opts.Config.IsOsaka(head.Number, head.Time) {
version = types.BlobSidecarVersion1
}
if sidecar.Version != version {
return fmt.Errorf("unexpected sidecar version, want: %d, got: %d", version, sidecar.Version)
} }
// Ensure the blob fee cap satisfies the minimum blob gas price // Ensure the blob fee cap satisfies the minimum blob gas price
if tx.BlobGasFeeCapIntCmp(blobTxMinBlobGasPrice) < 0 { if tx.BlobGasFeeCapIntCmp(blobTxMinBlobGasPrice) < 0 {
@ -198,26 +193,8 @@ func validateBlobTx(tx *types.Transaction, head *types.Header, opts *ValidationO
if err := sidecar.ValidateBlobCommitmentHashes(hashes); err != nil { if err := sidecar.ValidateBlobCommitmentHashes(hashes); err != nil {
return err return err
} }
// Fork-specific sidecar checks, including proof verification. return validateBlobSidecarOsaka(sidecar, hashes)
if sidecar.Version == types.BlobSidecarVersion1 {
return validateBlobSidecarOsaka(sidecar, hashes)
} else {
return validateBlobSidecarLegacy(sidecar, hashes)
}
} }
func validateBlobSidecarLegacy(sidecar *types.BlobTxSidecar, hashes []common.Hash) error {
if len(sidecar.Proofs) != len(hashes) {
return fmt.Errorf("invalid number of %d blob proofs expected %d", len(sidecar.Proofs), len(hashes))
}
for i := range sidecar.Blobs {
if err := kzg4844.VerifyBlobProof(&sidecar.Blobs[i], sidecar.Commitments[i], sidecar.Proofs[i]); err != nil {
return fmt.Errorf("%w: invalid blob proof: %v", ErrKZGVerificationError, err)
}
}
return nil
}
func validateBlobSidecarOsaka(sidecar *types.BlobTxSidecar, hashes []common.Hash) error { func validateBlobSidecarOsaka(sidecar *types.BlobTxSidecar, hashes []common.Hash) error {
if len(sidecar.Proofs) != len(hashes)*kzg4844.CellProofsPerBlob { if len(sidecar.Proofs) != len(hashes)*kzg4844.CellProofsPerBlob {
return fmt.Errorf("invalid number of %d blob proofs expected %d", len(sidecar.Proofs), len(hashes)*kzg4844.CellProofsPerBlob) return fmt.Errorf("invalid number of %d blob proofs expected %d", len(sidecar.Proofs), len(hashes)*kzg4844.CellProofsPerBlob)

View file

@ -1917,111 +1917,6 @@ func newGetBlobEnv(t testing.TB, version byte) (*node.Node, *ConsensusAPI) {
api := newConsensusAPIWithoutHeartbeat(ethServ) api := newConsensusAPIWithoutHeartbeat(ethServ)
return n, api return n, api
} }
func TestGetBlobsV1(t *testing.T) {
n, api := newGetBlobEnv(t, 0)
defer n.Close()
suites := []struct {
start int
limit int
fillRandom bool
}{
{
start: 0, limit: 1,
},
{
start: 0, limit: 1, fillRandom: true,
},
{
start: 0, limit: 2,
},
{
start: 0, limit: 2, fillRandom: true,
},
{
start: 1, limit: 3,
},
{
start: 1, limit: 3, fillRandom: true,
},
{
start: 0, limit: 6,
},
{
start: 0, limit: 6, fillRandom: true,
},
{
start: 1, limit: 5,
},
{
start: 1, limit: 5, fillRandom: true,
},
}
for i, suite := range suites {
// Fill the request for retrieving blobs
var (
vhashes []common.Hash
expect engine.BlobAndProofListV1
)
// fill missing blob at the beginning
if suite.fillRandom {
vhashes = append(vhashes, testrand.Hash())
expect = append(expect, nil)
}
for j := suite.start; j < suite.limit; j++ {
vhashes = append(vhashes, testBlobVHashes[j])
expect = append(expect, &engine.BlobAndProofV1{
Blob: testBlobs[j][:],
Proof: testBlobProofs[j][:],
})
// fill missing blobs in the middle
if suite.fillRandom && rand.Intn(2) == 0 {
vhashes = append(vhashes, testrand.Hash())
expect = append(expect, nil)
}
}
// fill missing blobs at the end
if suite.fillRandom {
vhashes = append(vhashes, testrand.Hash())
expect = append(expect, nil)
}
result, err := api.GetBlobsV1(context.Background(), vhashes)
if err != nil {
t.Errorf("Unexpected error for case %d, %v", i, err)
}
if !reflect.DeepEqual(result, expect) {
t.Fatalf("Unexpected result for case %d", i)
}
}
}
func TestGetBlobsV1AfterOsakaFork(t *testing.T) {
genesis := &core.Genesis{
Config: params.MergedTestChainConfig,
Alloc: types.GenesisAlloc{testAddr: {Balance: testBalance}},
Difficulty: common.Big0,
Timestamp: 1, // Timestamp > 0 to ensure Osaka fork is active
}
n, ethServ := startEthService(t, genesis, nil)
defer n.Close()
var engineErr *engine.EngineAPIError
api := newConsensusAPIWithoutHeartbeat(ethServ)
_, err := api.GetBlobsV1(context.Background(), []common.Hash{testrand.Hash()})
if !errors.As(err, &engineErr) {
t.Fatalf("Unexpected error: %T", err)
} else {
if engineErr.ErrorCode() != -38005 {
t.Fatalf("Expected error code -38005, got %d", engineErr.ErrorCode())
}
if engineErr.Error() != "Unsupported fork" {
t.Fatalf("Expected error message 'Unsupported fork', got '%s'", engineErr.Error())
}
}
}
func TestGetBlobsV2And3(t *testing.T) { func TestGetBlobsV2And3(t *testing.T) {
n, api := newGetBlobEnv(t, 1) n, api := newGetBlobEnv(t, 1)
defer n.Close() defer n.Close()

View file

@ -858,7 +858,7 @@ func testGetPooledTransaction(t *testing.T, blobTx bool) {
emptyBlob = kzg4844.Blob{} emptyBlob = kzg4844.Blob{}
emptyBlobs = []kzg4844.Blob{emptyBlob} emptyBlobs = []kzg4844.Blob{emptyBlob}
emptyBlobCommit, _ = kzg4844.BlobToCommitment(&emptyBlob) emptyBlobCommit, _ = kzg4844.BlobToCommitment(&emptyBlob)
emptyBlobProof, _ = kzg4844.ComputeBlobProof(&emptyBlob, emptyBlobCommit) emptyCellProof, _ = kzg4844.ComputeCellProofs(&emptyBlob)
emptyBlobHash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit) emptyBlobHash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit)
) )
backend := newTestBackendWithGenerator(0, true, true, nil) backend := newTestBackendWithGenerator(0, true, true, nil)
@ -882,7 +882,7 @@ func testGetPooledTransaction(t *testing.T, blobTx bool) {
To: testAddr, To: testAddr,
BlobHashes: []common.Hash{emptyBlobHash}, BlobHashes: []common.Hash{emptyBlobHash},
BlobFeeCap: uint256.MustFromBig(common.Big1), BlobFeeCap: uint256.MustFromBig(common.Big1),
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion0, emptyBlobs, []kzg4844.Commitment{emptyBlobCommit}, []kzg4844.Proof{emptyBlobProof}), Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion1, emptyBlobs, []kzg4844.Commitment{emptyBlobCommit}, emptyCellProof),
}) })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)