From eea629b9b38817dffd425e0726ac6ca75c4db97d Mon Sep 17 00:00:00 2001 From: Bosul Mun Date: Mon, 22 Jun 2026 10:31:51 +0200 Subject: [PATCH] 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. --- cmd/devp2p/internal/ethtest/suite.go | 6 +- core/txpool/blobpool/blobpool.go | 13 +-- core/txpool/blobpool/blobpool_test.go | 123 ++++++++++---------------- core/txpool/blobpool/cache.go | 17 ++-- core/txpool/blobpool/cache_test.go | 6 +- core/txpool/blobpool/limbo.go | 2 +- core/txpool/blobpool/slotter.go | 21 ----- core/txpool/blobpool/slotter_test.go | 41 --------- core/txpool/validation.go | 35 ++------ eth/catalyst/api_test.go | 105 ---------------------- eth/protocols/eth/handler_test.go | 4 +- 11 files changed, 69 insertions(+), 304 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/suite.go b/cmd/devp2p/internal/ethtest/suite.go index eff573ecb1..6dc77941c1 100644 --- a/cmd/devp2p/internal/ethtest/suite.go +++ b/cmd/devp2p/internal/ethtest/suite.go @@ -1013,11 +1013,11 @@ func makeSidecar(data ...byte) *types.BlobTxSidecar { for i := range blobs { blobs[i][0] = data[i] c, _ := kzg4844.BlobToCommitment(&blobs[i]) - p, _ := kzg4844.ComputeBlobProof(&blobs[i], c) + cellProofs, _ := kzg4844.ComputeCellProofs(&blobs[i]) 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) { diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index fcd1f7566a..ee73c8e897 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -228,22 +228,17 @@ func encodeForNetwork(storedRLP []byte) ([]byte, error) { // 2. Find the version of sidecar. 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) } - versionByte := byte(version) // 3. Extract sidecar elements. commitmentsRLP := elems[2] proofsRLP := elems[3] blobsRLP := elems[4] // 4. Reconstruct into the network format. - var outer [][]byte - if versionByte == types.BlobSidecarVersion0 { - outer = [][]byte{txRLP, blobsRLP, commitmentsRLP, proofsRLP} - } else { - outer = [][]byte{txRLP, elems[1], blobsRLP, commitmentsRLP, proofsRLP} - } + outer := [][]byte{txRLP, elems[1], blobsRLP, commitmentsRLP, proofsRLP} + body, err := rlp.MergeListValues(outer) if err != nil { return nil, err @@ -555,7 +550,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserver txpool.Reser p.state = state // 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 slotter, err = tryMigrate(p.chain.Config(), slotter, queuedir) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 6b61591227..0e182947f0 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -53,7 +53,6 @@ import ( var ( testBlobs []*kzg4844.Blob testBlobCommits []kzg4844.Commitment - testBlobProofs []kzg4844.Proof testBlobCellProofs [][]kzg4844.Proof testBlobVHashes [][32]byte testBlobIndices = make(map[[32]byte]int) @@ -69,9 +68,6 @@ func init() { testBlobCommit, _ := kzg4844.BlobToCommitment(testBlob) testBlobCommits = append(testBlobCommits, testBlobCommit) - testBlobProof, _ := kzg4844.ComputeBlobProof(testBlob, testBlobCommit) - testBlobProofs = append(testBlobProofs, testBlobProof) - testBlobCellProof, _ := kzg4844.ComputeCellProofs(testBlob) 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 // 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 ( blobs []kzg4844.Blob blobHashes []common.Hash @@ -253,12 +249,8 @@ func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCa for i := 0; i < blobCount; i++ { blobs = append(blobs, *testBlobs[blobOffset+i]) commitments = append(commitments, testBlobCommits[blobOffset+i]) - if version == types.BlobSidecarVersion0 { - proofs = append(proofs, testBlobProofs[blobOffset+i]) - } else { - cellProofs, _ := kzg4844.ComputeCellProofs(testBlobs[blobOffset+i]) - proofs = append(proofs, cellProofs...) - } + cellProofs, _ := kzg4844.ComputeCellProofs(testBlobs[blobOffset+i]) + proofs = append(proofs, cellProofs...) blobHashes = append(blobHashes, testBlobVHashes[blobOffset+i]) } blobtx := &types.BlobTx{ @@ -270,7 +262,7 @@ func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCa BlobFeeCap: uint256.NewInt(blobFeeCap), BlobHashes: blobHashes, 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) } @@ -293,7 +285,7 @@ func makeUnsignedTxWithTestBlob(nonce uint64, gasTipCap uint64, gasFeeCap uint64 BlobFeeCap: uint256.NewInt(blobFeeCap), BlobHashes: []common.Hash{testBlobVHashes[blobIdx]}, 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...) } } - blobs1, _, proofs1, err := pool.getBlobs(hashes, types.BlobSidecarVersion0) + blobs, _, proofs, err := pool.getBlobs(hashes, types.BlobSidecarVersion1) if err != nil { t.Fatal(err) } - blobs2, _, proofs2, err := pool.getBlobs(hashes, types.BlobSidecarVersion1) - if err != nil { - 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)) + if len(blobs) != len(hashes) || len(proofs) != len(hashes) { + t.Errorf("retrieved blobs/proofs size mismatch: have %d/%d, want blobs %d, want proofs: %d", len(blobs), len(proofs), len(hashes), len(hashes)) return } 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 index := testBlobIndices[hash] - if blobs1[i] != nil && (*blobs1[i] != *testBlobs[index] || proofs1[i][0] != testBlobProofs[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])) { + 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 } @@ -503,7 +477,7 @@ func TestOpenDrops(t *testing.T) { storage := t.TempDir() 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 // changes) are handled gracefully (case 1) @@ -825,7 +799,7 @@ func TestOpenIndex(t *testing.T) { storage := t.TempDir() 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 // the cumulative minimum will be maintained. @@ -913,7 +887,7 @@ func TestOpenHeap(t *testing.T) { storage := t.TempDir() 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 // the heap initialization, use a deterministic account/tx/priority ordering. @@ -1088,7 +1062,7 @@ func TestChangingSlotterSize(t *testing.T) { storage := t.TempDir() 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. var ( @@ -1100,9 +1074,9 @@ func TestChangingSlotterSize(t *testing.T) { addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) - tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0) - tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 0, key2, types.BlobSidecarVersion0) - tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, 0, key3, types.BlobSidecarVersion0) + tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1) + tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 0, key2) + tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, 0, key3) blob1 = encodeForPool(tx1) blob2 = encodeForPool(tx2) @@ -1203,9 +1177,9 @@ func TestBillyMigration(t *testing.T) { addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) - tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0) - tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 0, key2, types.BlobSidecarVersion0) - tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, 0, key3, types.BlobSidecarVersion0) + tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1) + tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 0, key2) + tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, 0, key3) blob1 = encodeForPool(tx1) blob2 = encodeForPool(tx2) @@ -1299,7 +1273,7 @@ func TestLegacyTxConversion(t *testing.T) { // Initialize the pending store with two blob transactions encoded in the // legacy format. 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 { t.Fatalf("failed to open billy: %v", err) } @@ -1309,8 +1283,8 @@ func TestLegacyTxConversion(t *testing.T) { addr1 := crypto.PubkeyToAddress(key1.PublicKey) addr2 := crypto.PubkeyToAddress(key2.PublicKey) - tx1 := makeMultiBlobTx(0, 1, 1000, 100, 2, 0, key1, types.BlobSidecarVersion0) - tx2 := makeMultiBlobTx(0, 1, 1000, 100, 2, 2, key2, types.BlobSidecarVersion0) + tx1 := makeMultiBlobTx(0, 1, 1000, 100, 2, 0, key1) + tx2 := makeMultiBlobTx(0, 1, 1000, 100, 2, 2, key2) for _, tx := range []*types.Transaction{tx1, tx2} { legacy, err := rlp.EncodeToBytes(tx) @@ -1408,8 +1382,8 @@ func TestBlobCountLimit(t *testing.T) { // Attempt to add transactions. var ( - tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0) - tx2 = makeMultiBlobTx(0, 1, 800, 70, 7, 0, key2, types.BlobSidecarVersion0) + tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1) + tx2 = makeMultiBlobTx(0, 1, 800, 70, 7, 0, key2) ) 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)) 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 var ( @@ -1922,7 +1896,7 @@ func TestGetBlobs(t *testing.T) { storage := t.TempDir() 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. var ( @@ -1934,9 +1908,9 @@ func TestGetBlobs(t *testing.T) { addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) - tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1, types.BlobSidecarVersion0) // [0, 6) - tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 6, key2, types.BlobSidecarVersion1) // [6, 12) - tx3 = makeMultiBlobTx(0, 1, 800, 110, 6, 12, key3, types.BlobSidecarVersion0) // [12, 18) + tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, 0, key1) // [0, 6) + tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, 6, key2) // [6, 12) + tx3 = makeMultiBlobTx(0, 1, 800, 110, 6, 12, key3) // [12, 18) blob1 = encodeForPool(tx1) blob2 = encodeForPool(tx2) @@ -2004,7 +1978,7 @@ func TestGetBlobs(t *testing.T) { }{ { start: 0, limit: 6, - version: types.BlobSidecarVersion0, + version: types.BlobSidecarVersion1, }, { start: 0, limit: 6, @@ -2012,7 +1986,7 @@ func TestGetBlobs(t *testing.T) { }, { start: 0, limit: 6, fillRandom: true, - version: types.BlobSidecarVersion0, + version: types.BlobSidecarVersion1, }, { start: 0, limit: 6, fillRandom: true, @@ -2020,7 +1994,7 @@ func TestGetBlobs(t *testing.T) { }, { start: 3, limit: 9, - version: types.BlobSidecarVersion0, + version: types.BlobSidecarVersion1, }, { start: 3, limit: 9, @@ -2028,7 +2002,7 @@ func TestGetBlobs(t *testing.T) { }, { start: 3, limit: 9, fillRandom: true, - version: types.BlobSidecarVersion0, + version: types.BlobSidecarVersion1, }, { start: 3, limit: 9, fillRandom: true, @@ -2036,7 +2010,7 @@ func TestGetBlobs(t *testing.T) { }, { start: 3, limit: 15, - version: types.BlobSidecarVersion0, + version: types.BlobSidecarVersion1, }, { start: 3, limit: 15, @@ -2044,7 +2018,7 @@ func TestGetBlobs(t *testing.T) { }, { start: 3, limit: 15, fillRandom: true, - version: types.BlobSidecarVersion0, + version: types.BlobSidecarVersion1, }, { start: 3, limit: 15, fillRandom: true, @@ -2052,7 +2026,7 @@ func TestGetBlobs(t *testing.T) { }, { start: 0, limit: 18, - version: types.BlobSidecarVersion0, + version: types.BlobSidecarVersion1, }, { start: 0, limit: 18, @@ -2060,7 +2034,7 @@ func TestGetBlobs(t *testing.T) { }, { start: 0, limit: 18, fillRandom: true, - version: types.BlobSidecarVersion0, + version: types.BlobSidecarVersion1, }, { start: 0, limit: 18, fillRandom: true, @@ -2114,7 +2088,7 @@ func TestGetBlobs(t *testing.T) { if blobs[j] == nil || proofs[j] == nil { // This is only an error if there was no version mismatch 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]) } continue @@ -2125,15 +2099,9 @@ func TestGetBlobs(t *testing.T) { continue } // Item retrieved, make sure the proof matches the expectation - if c.version == types.BlobSidecarVersion0 { - if proofs[j][0] != testBlobProofs[testBlobIndex] { - 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]) - } + 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 // to rlp.EncodeToBytes on the original transaction, for both V0 and V1 sidecars. 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, types.BlobSidecarVersion1) }) + t.Run("v1", func(t *testing.T) { testEncodeForNetwork(t) }) } -func testEncodeForNetwork(t *testing.T, version byte) { +func testEncodeForNetwork(t *testing.T) { 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) if err != nil { @@ -2162,7 +2129,7 @@ func testEncodeForNetwork(t *testing.T, version byte) { t.Fatalf("encodeForNetwork failed: %v", err) } 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)) } } diff --git a/core/txpool/blobpool/cache.go b/core/txpool/blobpool/cache.go index de4001a1b1..12f9802775 100644 --- a/core/txpool/blobpool/cache.go +++ b/core/txpool/blobpool/cache.go @@ -343,22 +343,15 @@ func (c *Cache) update(want []common.Hash) { if _, exists := c.entries[v]; exists { continue // recompute only new entries } - var pf []kzg4844.Proof - switch sidecar.Version { - case types.BlobSidecarVersion0: - pf = []kzg4844.Proof{sidecar.Proofs[i]} - 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 + cellProofs, err := sidecar.CellProofsAt(i) + if err != nil { + log.Error("Failed to get cell proofs", "txhash", ptx.Tx.Hash(), "err", err) + continue } c.entries[v] = &cachedBlob{ blob: &sidecar.Blobs[i], commitment: sidecar.Commitments[i], - proofs: pf, + proofs: cellProofs, version: sidecar.Version, } cacheBlobsGauge.Inc(1) diff --git a/core/txpool/blobpool/cache_test.go b/core/txpool/blobpool/cache_test.go index f7ece4c1b8..da13cda4b2 100644 --- a/core/txpool/blobpool/cache_test.go +++ b/core/txpool/blobpool/cache_test.go @@ -58,7 +58,7 @@ func newTestCache(t *testing.T, txConfig []txSpec) *testCache { if err := os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700); err != nil { 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 { t.Fatalf("billy open: %v", err) } @@ -70,7 +70,7 @@ func newTestCache(t *testing.T, txConfig []txSpec) *testCache { ) for _, s := range txConfig { 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 { 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 { t.Helper() 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 ptx := newBlobTxForPool(tx) diff --git a/core/txpool/blobpool/limbo.go b/core/txpool/blobpool/limbo.go index b8bee2f22a..e696a6fcc0 100644 --- a/core/txpool/blobpool/limbo.go +++ b/core/txpool/blobpool/limbo.go @@ -56,7 +56,7 @@ func newLimbo(config *params.ChainConfig, datadir string) (*limbo, error) { } // 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. slotter, err := tryMigrate(config, slotter, datadir) diff --git a/core/txpool/blobpool/slotter.go b/core/txpool/blobpool/slotter.go index 3399361e55..49a46d4f42 100644 --- a/core/txpool/blobpool/slotter.go +++ b/core/txpool/blobpool/slotter.go @@ -58,27 +58,6 @@ func tryMigrate(config *params.ChainConfig, slotter billy.SlotSizeFn, datadir st 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. // EIP-7594 (PeerDAS) changes the average transaction size which means the current // static 4KB average size is not enough anymore. diff --git a/core/txpool/blobpool/slotter_test.go b/core/txpool/blobpool/slotter_test.go index e4cf232f4e..24ad2b5330 100644 --- a/core/txpool/blobpool/slotter_test.go +++ b/core/txpool/blobpool/slotter_test.go @@ -20,47 +20,6 @@ import ( "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. func TestNewSlotterEIP7594(t *testing.T) { // Generate the database shelve sizes diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 3b30dd30ef..4651c06b3e 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -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) } if tx.Type() == types.BlobTxType { - return validateBlobTx(tx, head, opts) + return validateBlobTx(tx) } if tx.Type() == types.SetCodeTxType { 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. -func validateBlobTx(tx *types.Transaction, head *types.Header, opts *ValidationOptions) error { +func validateBlobTx(tx *types.Transaction) error { sidecar := tx.BlobTxSidecar() if sidecar == nil { return errors.New("missing sidecar in blob transaction") } - // Ensure the sidecar is constructed with the correct version, consistent - // with the current fork. - version := types.BlobSidecarVersion0 - 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 sidecar is constructed with the correct version + if sidecar.Version != types.BlobSidecarVersion1 { + return fmt.Errorf("unexpected sidecar version, want: %d, got: %d", types.BlobSidecarVersion1, sidecar.Version) } // Ensure the blob fee cap satisfies the minimum blob gas price 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 { return err } - // Fork-specific sidecar checks, including proof verification. - if sidecar.Version == types.BlobSidecarVersion1 { - return validateBlobSidecarOsaka(sidecar, hashes) - } else { - return validateBlobSidecarLegacy(sidecar, hashes) - } + return validateBlobSidecarOsaka(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 { 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) diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 0cf2c5c8e6..849c123979 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -1917,111 +1917,6 @@ func newGetBlobEnv(t testing.TB, version byte) (*node.Node, *ConsensusAPI) { api := newConsensusAPIWithoutHeartbeat(ethServ) 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) { n, api := newGetBlobEnv(t, 1) defer n.Close() diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 3f40fdb3b3..874b4ad5a5 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -858,7 +858,7 @@ func testGetPooledTransaction(t *testing.T, blobTx bool) { emptyBlob = kzg4844.Blob{} emptyBlobs = []kzg4844.Blob{emptyBlob} emptyBlobCommit, _ = kzg4844.BlobToCommitment(&emptyBlob) - emptyBlobProof, _ = kzg4844.ComputeBlobProof(&emptyBlob, emptyBlobCommit) + emptyCellProof, _ = kzg4844.ComputeCellProofs(&emptyBlob) emptyBlobHash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit) ) backend := newTestBackendWithGenerator(0, true, true, nil) @@ -882,7 +882,7 @@ func testGetPooledTransaction(t *testing.T, blobTx bool) { To: testAddr, BlobHashes: []common.Hash{emptyBlobHash}, 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 { t.Fatal(err)