core/txpool/blobpool: add test for migration of existing txs at osaka boundary

This commit is contained in:
lightclient 2025-09-19 07:35:31 -06:00 committed by Gary Rong
parent a7b9761f9f
commit bca071a1dd
2 changed files with 100 additions and 1 deletions

View file

@ -339,7 +339,9 @@ type BlobPool struct {
signer types.Signer // Transaction signer to use for sender recovery signer types.Signer // Transaction signer to use for sender recovery
chain BlockChain // Chain object to access the state through chain BlockChain // Chain object to access the state through
cQueue *conversionQueue // The queue for performing legacy sidecar conversion cQueue *conversionQueue // The queue for performing legacy sidecar conversion (TODO: remove after Osaka)
sidecarMigrationDoneCh chan struct{} // Channel for signaling when all txs at the boundary have been converted (TODO: remove after Osaka)
head atomic.Pointer[types.Header] // Current head of the chain head atomic.Pointer[types.Header] // Current head of the chain
state *state.StateDB // Current state at the head of the chain state *state.StateDB // Current state at the head of the chain
@ -946,6 +948,9 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
} }
} }
} }
if p.sidecarMigrationDoneCh != nil {
close(p.sidecarMigrationDoneCh)
}
log.Info("Completed the blob transaction conversion", "discarded", fail, "injected", success, "elapsed", common.PrettyDuration(time.Since(start))) log.Info("Completed the blob transaction conversion", "discarded", fail, "injected", success, "elapsed", common.PrettyDuration(time.Since(start)))
}() }()
} }

View file

@ -2098,6 +2098,98 @@ func TestGetBlobs(t *testing.T) {
pool.Close() pool.Close()
} }
// TestSidecarConversion will verify that after the Osaka fork, all legacy
// sidecars in the pool are successfully convert to v1 sidecars.
func TestSidecarConversion(t *testing.T) {
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelDebug, true)))
// Create a temporary folder for the persistent backend
storage := t.TempDir()
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
var (
count = 10
keys = make([]*ecdsa.PrivateKey, count)
addrs = make([]common.Address, count)
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
)
for i := 0; i < count; i++ {
keys[i], _ = crypto.GenerateKey()
addrs[i] = crypto.PubkeyToAddress(keys[i].PublicKey)
statedb.AddBalance(addrs[i], uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
}
statedb.Commit(0, true, false)
config := &params.ChainConfig{
ChainID: big.NewInt(1),
LondonBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
CancunTime: newUint64(0),
PragueTime: newUint64(0),
OsakaTime: newUint64(1),
BlobScheduleConfig: params.DefaultBlobSchedule,
}
chain := &testBlockChain{
config: config,
basefee: uint256.NewInt(1050),
blobfee: uint256.NewInt(105),
statedb: statedb,
}
before := chain.CurrentBlock()
before.Time = 0
after := chain.CurrentBlock()
after.Time = 1
pool := New(Config{Datadir: storage}, chain, nil)
if err := pool.Init(1, before, newReserver()); err != nil {
t.Fatalf("failed to create blob pool: %v", err)
}
for i, key := range keys {
tx := makeMultiBlobTx(0, 1, 1000, 100, 2, 0, key, types.BlobSidecarVersion0)
if errs := pool.Add([]*types.Transaction{tx}, true); errs[0] != nil {
t.Errorf("failed to insert blob tx from %s: %s", addrs[i], errs[0])
}
}
// Should kick off migration.
pool.sidecarMigrationDoneCh = make(chan struct{})
pool.Reset(before, after)
<-pool.sidecarMigrationDoneCh
// Verify all transactions in the pool were converted and verify the
// subsequent cell proofs.
pending, _ := pool.Stats()
if pending != count {
t.Errorf("expected pending count to match initial tx count: pending=%d, expected=%d", pending, count)
}
for addr, acc := range pool.index {
for _, m := range acc {
if m.version != types.BlobSidecarVersion1 {
t.Errorf("expected sidecar to have been converted: from %s, hash %s", addr, m.hash)
}
tx := pool.Get(m.hash)
if tx == nil {
t.Errorf("failed to get tx by hash: %s", m.hash)
}
sc := tx.BlobTxSidecar()
if err := kzg4844.VerifyCellProofs(sc.Blobs, sc.Commitments, sc.Proofs); err != nil {
t.Errorf("failed to verify cell proofs for tx %s after conversion: %s", m.hash, err)
}
}
}
// Verify all the calculated pool internals. Interestingly, this is **not**
// a duplication of the above checks, this actually validates the verifier
// using the above already hard coded checks.
//
// Do not remove this, nor alter the above to be generic.
verifyPoolInternals(t, pool)
pool.Close()
}
// fakeBilly is a billy.Database implementation which just drops data on the floor. // fakeBilly is a billy.Database implementation which just drops data on the floor.
type fakeBilly struct { type fakeBilly struct {
billy.Database billy.Database
@ -2180,3 +2272,5 @@ func benchmarkPoolPending(b *testing.B, datacap uint64) {
} }
} }
} }
func newUint64(val uint64) *uint64 { return &val }