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 {
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) {

View file

@ -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)

View file

@ -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))
}
}

View file

@ -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)

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 {
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)

View file

@ -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)

View file

@ -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.

View file

@ -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

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)
}
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)

View file

@ -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()

View file

@ -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)