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)