fix: fix test error

This commit is contained in:
healthykim 2025-10-24 17:09:22 +09:00
parent c8e5daf85a
commit df81462230
4 changed files with 59 additions and 31 deletions

View file

@ -1101,7 +1101,7 @@ func (p *BlobPool) convertLegacySidecar(sender common.Address, hash common.Hash,
// loudly if possible. If the blob transaction in this slot is corrupted,
// leave it in the store, it will be dropped during the next pool
// initialization.
var tx types.Transaction
var tx pooledBlobTx
if err = rlp.DecodeBytes(data, &tx); err != nil {
log.Error("Blob transaction is corrupted", "hash", hash, "id", id, "err", err)
return false
@ -1110,11 +1110,11 @@ func (p *BlobPool) convertLegacySidecar(sender common.Address, hash common.Hash,
// Skip conversion if the transaction does not match the expected hash, or if it was
// already converted. This can occur if the original transaction was evicted from the
// pool and the slot was reused by a new one.
if tx.Hash() != hash {
log.Warn("Blob transaction was replaced", "hash", hash, "id", id, "stored", tx.Hash())
if tx.Transaction.Hash() != hash {
log.Warn("Blob transaction was replaced", "hash", hash, "id", id, "stored", tx.Transaction.Hash())
return false
}
sc := tx.BlobTxSidecar()
sc := tx.Sidecar
if sc.Version >= types.BlobSidecarVersion1 {
log.Debug("Skipping conversion of blob tx", "hash", hash, "id", id)
return false
@ -1122,7 +1122,7 @@ func (p *BlobPool) convertLegacySidecar(sender common.Address, hash common.Hash,
// Perform the sidecar conversion, the failure is not expected and report the error
// loudly if possible.
if err := tx.BlobTxSidecar().ToV1(); err != nil {
if err := tx.Sidecar.ToV1(); err != nil {
log.Error("Failed to convert blob transaction", "hash", hash, "err", err)
return false
}
@ -1131,7 +1131,7 @@ func (p *BlobPool) convertLegacySidecar(sender common.Address, hash common.Hash,
// the error loudly if possible.
blob, err := rlp.EncodeToBytes(&tx)
if err != nil {
log.Error("Failed to encode blob transaction", "hash", tx.Hash(), "err", err)
log.Error("Failed to encode blob transaction", "hash", tx.Transaction.Hash(), "err", err)
return false
}
@ -1327,16 +1327,15 @@ func (p *BlobPool) reinject(addr common.Address, txhash common.Hash) error {
// this attack is financially inefficient to execute.
head := p.head.Load()
if p.chain.Config().IsOsaka(head.Number, head.Time) && pooledTx.Sidecar.Version == types.BlobSidecarVersion0 {
tx, err := pooledTx.convert()
if err != nil {
log.Error("Failed to convert the pooledTx", "err", err)
return err
}
if err := tx.BlobTxSidecar().ToV1(); err != nil {
if err := pooledTx.Sidecar.ToV1(); err != nil {
log.Error("Failed to convert the legacy sidecar", "err", err)
return err
}
log.Info("Legacy blob transaction is reorged", "hash", tx.Hash())
log.Info("Legacy blob transaction is reorged", "hash", pooledTx.Transaction.Hash())
}
// Serialize the transaction back into the primary datastore.
blob, err := rlp.EncodeToBytes(pooledTx)
@ -1806,7 +1805,7 @@ func (p *BlobPool) AvailableBlobs(vhashes []common.Hash) int {
// the legacy sidecars if Osaka fork has been activated with a short time window.
//
// This function is pure static and lock free.
func (p *BlobPool) preCheck(tx *types.Transaction) error {
func (p *BlobPool) preCheck(tx *pooledBlobTx) error {
var (
head = p.head.Load()
isOsaka = p.chain.Config().IsOsaka(head.Number, head.Time)
@ -1817,12 +1816,12 @@ func (p *BlobPool) preCheck(tx *types.Transaction) error {
}
// Validate the transaction statically at first to avoid unnecessary
// conversion. This step doesn't require lock protection.
if err := p.ValidateTxBasics(tx); err != nil {
if err := p.ValidateTxBasics(tx.Transaction); err != nil {
return err
}
// Before the Osaka fork, reject the blob txs with cell proofs
if !isOsaka {
if tx.BlobTxSidecar().Version == types.BlobSidecarVersion0 {
if tx.Sidecar.Version == types.BlobSidecarVersion0 {
return nil
} else {
return errors.New("cell proof is not supported yet")
@ -1830,7 +1829,7 @@ func (p *BlobPool) preCheck(tx *types.Transaction) error {
}
// After the Osaka fork, reject the legacy blob txs if the conversion
// time window is passed.
if tx.BlobTxSidecar().Version == types.BlobSidecarVersion1 {
if tx.Sidecar.Version == types.BlobSidecarVersion1 {
return nil
}
if head.Time > uint64(deadline.Unix()) {
@ -1851,13 +1850,13 @@ func (p *BlobPool) Add(txs []*types.Transaction, sync bool) []error {
adds = make([]*types.Transaction, 0, len(txs))
)
for i, tx := range txs {
if errs[i] = p.preCheck(tx); errs[i] != nil {
continue
}
pooledTx, err := newPooledBlobTx(tx)
if err != nil {
continue
}
if errs[i] = p.preCheck(pooledTx); errs[i] != nil {
continue
}
errs[i] = p.add(pooledTx)
if errs[i] == nil {
adds = append(adds, tx.WithoutBlobTxSidecar())

View file

@ -23,7 +23,6 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
)
@ -34,8 +33,8 @@ const maxPendingConversionTasks = 2048
// txConvert represents a conversion task with an attached legacy blob transaction.
type txConvert struct {
tx *types.Transaction // Legacy blob transaction
done chan error // Channel for signaling back if the conversion succeeds
tx *pooledBlobTx // Legacy blob transaction
done chan error // Channel for signaling back if the conversion succeeds
}
// conversionQueue is a dedicated queue for converting legacy blob transactions
@ -73,7 +72,7 @@ func newConversionQueue() *conversionQueue {
// for conversion.
//
// This function may block for a long time until the transaction is processed.
func (q *conversionQueue) convert(tx *types.Transaction) error {
func (q *conversionQueue) convert(tx *pooledBlobTx) error {
done := make(chan error, 1)
select {
case q.tasks <- &txConvert{tx: tx, done: done}:
@ -113,7 +112,7 @@ func (q *conversionQueue) run(tasks []*txConvert, done chan struct{}, interrupt
t.done <- errors.New("conversion is interrupted")
continue
}
sidecar := t.tx.BlobTxSidecar()
sidecar := t.tx.Sidecar
if sidecar == nil {
t.done <- errors.New("tx without sidecar")
continue
@ -122,7 +121,7 @@ func (q *conversionQueue) run(tasks []*txConvert, done chan struct{}, interrupt
start := time.Now()
err := sidecar.ToV1()
t.done <- err
log.Trace("Converted legacy blob tx", "hash", t.tx.Hash(), "err", err, "elapsed", common.PrettyDuration(time.Since(start)))
log.Trace("Converted legacy blob tx", "hash", t.tx.Transaction.Hash(), "err", err, "elapsed", common.PrettyDuration(time.Since(start)))
}
}

View file

@ -30,7 +30,7 @@ import (
)
// createV1BlobTx creates a blob transaction with version 1 sidecar for testing.
func createV1BlobTx(nonce uint64, key *ecdsa.PrivateKey) *types.Transaction {
func createV1BlobTx(nonce uint64, key *ecdsa.PrivateKey) *pooledBlobTx {
blob := &kzg4844.Blob{byte(nonce)}
commitment, _ := kzg4844.BlobToCommitment(blob)
cellProofs, _ := kzg4844.ComputeCellProofs(blob)
@ -46,7 +46,9 @@ func createV1BlobTx(nonce uint64, key *ecdsa.PrivateKey) *types.Transaction {
Value: uint256.NewInt(100),
Sidecar: types.NewBlobTxSidecar(types.BlobSidecarVersion1, []kzg4844.Blob{*blob}, []kzg4844.Commitment{commitment}, cellProofs),
}
return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
tx := types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
pooledTx, _ := newPooledBlobTx(tx)
return pooledTx
}
func TestConversionQueueBasic(t *testing.T) {
@ -55,11 +57,12 @@ func TestConversionQueueBasic(t *testing.T) {
key, _ := crypto.GenerateKey()
tx := makeTx(0, 1, 1, 1, key)
if err := queue.convert(tx); err != nil {
pooledTx, _ := newPooledBlobTx(tx)
if err := queue.convert(pooledTx); err != nil {
t.Fatalf("Expected successful conversion, got error: %v", err)
}
if tx.BlobTxSidecar().Version != types.BlobSidecarVersion1 {
t.Errorf("Expected sidecar version to be %d, got %d", types.BlobSidecarVersion1, tx.BlobTxSidecar().Version)
if pooledTx.Sidecar.Version != types.BlobSidecarVersion1 {
t.Errorf("Expected sidecar version to be %d, got %d", types.BlobSidecarVersion1, pooledTx.Sidecar.Version)
}
}
@ -69,14 +72,14 @@ func TestConversionQueueV1BlobTx(t *testing.T) {
key, _ := crypto.GenerateKey()
tx := createV1BlobTx(0, key)
version := tx.BlobTxSidecar().Version
version := tx.Sidecar.Version
err := queue.convert(tx)
if err != nil {
t.Fatalf("Expected successful conversion, got error: %v", err)
}
if tx.BlobTxSidecar().Version != version {
t.Errorf("Expected sidecar version to remain %d, got %d", version, tx.BlobTxSidecar().Version)
if tx.Sidecar.Version != version {
t.Errorf("Expected sidecar version to remain %d, got %d", version, tx.Sidecar.Version)
}
}
@ -88,7 +91,8 @@ func TestConversionQueueClosed(t *testing.T) {
key, _ := crypto.GenerateKey()
tx := makeTx(0, 1, 1, 1, key)
err := queue.convert(tx)
pooledTx, _ := newPooledBlobTx(tx)
err := queue.convert(pooledTx)
if err == nil {
t.Fatal("Expected error when converting on closed queue, got nil")
}

View file

@ -207,6 +207,32 @@ func (c *BlobTxCellSidecar) ValidateBlobCommitmentHashes(hashes []common.Hash) e
return sc.ValidateBlobCommitmentHashes(hashes)
}
// ToV1 converts the BlobSidecar to version 1, attaching the cell proofs.
// This function only available when we can recover the original blob with given cells
// TODO: duplication
func (sc *BlobTxCellSidecar) ToV1() error {
if sc.Version == BlobSidecarVersion1 {
return nil
}
blobs, err := kzg4844.RecoverBlobs(sc.Cells, sc.Custody.Indices())
if err != nil {
return err
}
if sc.Version == BlobSidecarVersion0 {
proofs := make([]kzg4844.Proof, 0, len(blobs)*kzg4844.CellProofsPerBlob)
for _, blob := range blobs {
cellProofs, err := kzg4844.ComputeCellProofs(&blob)
if err != nil {
return err
}
proofs = append(proofs, cellProofs...)
}
sc.Version = BlobSidecarVersion1
sc.Proofs = proofs
}
return nil
}
// blobTxWithBlobs represents blob tx with its corresponding sidecar.
// This is an interface because sidecars are versioned.
type blobTxWithBlobs interface {