simplify limbo logic

This commit is contained in:
maskpp 2025-07-23 23:26:32 +08:00
parent 3b67602c4c
commit 21f5158249

View file

@ -33,6 +33,7 @@ type limboBlob struct {
TxHash common.Hash // Owner transaction's hash to support resurrecting reorged txs TxHash common.Hash // Owner transaction's hash to support resurrecting reorged txs
Block uint64 // Block in which the blob transaction was included Block uint64 // Block in which the blob transaction was included
Tx *types.Transaction Tx *types.Transaction
id uint64 // the billy id of transction
} }
// limbo is a light, indexed database to temporarily store recently included // limbo is a light, indexed database to temporarily store recently included
@ -41,17 +42,14 @@ type limboBlob struct {
// //
// TODO(karalabe): Currently updating the inclusion block of a blob needs a full db rewrite. Can we do without? // TODO(karalabe): Currently updating the inclusion block of a blob needs a full db rewrite. Can we do without?
type limbo struct { type limbo struct {
store billy.Database // Persistent data store for limboed blobs store billy.Database // Persistent data store for limboed blobs
index map[common.Hash]*limboBlob // Mappings from tx hashes to datastore ids
index map[common.Hash]uint64 // Mappings from tx hashes to datastore ids
groups map[uint64]map[uint64]common.Hash // Set of txs included in past blocks
} }
// newLimbo opens and indexes a set of limboed blob transactions. // newLimbo opens and indexes a set of limboed blob transactions.
func newLimbo(datadir string, maxBlobsPerTransaction int) (*limbo, error) { func newLimbo(datadir string, maxBlobsPerTransaction int) (*limbo, error) {
l := &limbo{ l := &limbo{
index: make(map[common.Hash]uint64), index: make(map[common.Hash]*limboBlob),
groups: make(map[uint64]map[uint64]common.Hash),
} }
// Index all limboed blobs on disk and delete anything unprocessable // Index all limboed blobs on disk and delete anything unprocessable
var fails []uint64 var fails []uint64
@ -101,12 +99,9 @@ func (l *limbo) parseBlob(id uint64, data []byte) error {
log.Error("Dropping duplicate blob limbo entry", "owner", item.TxHash, "id", id) log.Error("Dropping duplicate blob limbo entry", "owner", item.TxHash, "id", id)
return errors.New("duplicate blob") return errors.New("duplicate blob")
} }
l.index[item.TxHash] = id // Delete tx and set id.
item.id, item.Tx = id, nil
if _, ok := l.groups[item.Block]; !ok { l.index[item.TxHash] = item
l.groups[item.Block] = make(map[uint64]common.Hash)
}
l.groups[item.Block][id] = item.TxHash
return nil return nil
} }
@ -119,17 +114,11 @@ func (l *limbo) finalize(final *types.Header) {
log.Warn("Nil finalized block cannot evict old blobs") log.Warn("Nil finalized block cannot evict old blobs")
return return
} }
for block, ids := range l.groups { for _, item := range l.index {
if block > final.Number.Uint64() { if item.Block > final.Number.Uint64() {
continue continue
} }
for id, owner := range ids { delete(l.index, item.TxHash)
if err := l.store.Delete(id); err != nil {
log.Error("Failed to drop finalized blob", "block", block, "id", id, "err", err)
}
delete(l.index, owner)
}
delete(l.groups, block)
} }
} }
@ -152,21 +141,21 @@ func (l *limbo) push(tx *types.Transaction, block uint64) error {
// pull retrieves a previously pushed set of blobs back from the limbo, removing // pull retrieves a previously pushed set of blobs back from the limbo, removing
// it at the same time. This method should be used when a previously included blob // it at the same time. This method should be used when a previously included blob
// transaction gets reorged out. // transaction gets reorged out.
func (l *limbo) pull(tx common.Hash) (*types.Transaction, error) { func (l *limbo) pull(txhash common.Hash) (*types.Transaction, error) {
// If the blobs are not tracked by the limbo, there's not much to do. This // If the blobs are not tracked by the limbo, there's not much to do. This
// can happen for example if a blob transaction is mined without pushing it // can happen for example if a blob transaction is mined without pushing it
// into the network first. // into the network first.
id, ok := l.index[tx] item, ok := l.index[txhash]
if !ok { if !ok {
log.Trace("Limbo cannot pull non-tracked blobs", "tx", tx) log.Trace("Limbo cannot pull non-tracked blobs", "tx", txhash)
return nil, errors.New("unseen blob transaction") return nil, errors.New("unseen blob transaction")
} }
item, err := l.getAndDrop(id) tx, err := l.getAndDrop(item.id)
if err != nil { if err != nil {
log.Error("Failed to get and drop limboed blobs", "tx", tx, "id", id, "err", err) log.Error("Failed to get and drop limboed blobs", "tx", txhash, "id", item.id, "err", err)
return nil, err return nil, err
} }
return item.Tx, nil return tx, nil
} }
// update changes the block number under which a blob transaction is tracked. This // update changes the block number under which a blob transaction is tracked. This
@ -180,25 +169,25 @@ func (l *limbo) update(txhash common.Hash, block uint64) {
// If the blobs are not tracked by the limbo, there's not much to do. This // If the blobs are not tracked by the limbo, there's not much to do. This
// can happen for example if a blob transaction is mined without pushing it // can happen for example if a blob transaction is mined without pushing it
// into the network first. // into the network first.
id, ok := l.index[txhash] item, ok := l.index[txhash]
if !ok { if !ok {
log.Trace("Limbo cannot update non-tracked blobs", "tx", txhash) log.Trace("Limbo cannot update non-tracked blobs", "tx", txhash)
return return
} }
// If there was no change in the blob's inclusion block, don't mess around // If there was no change in the blob's inclusion block, don't mess around
// with heavy database operations. // with heavy database operations.
if _, ok := l.groups[block][id]; ok { if item.Block == block {
log.Trace("Blob transaction unchanged in limbo", "tx", txhash, "block", block) log.Trace("Blob transaction unchanged in limbo", "tx", txhash, "block", block)
return return
} }
// Retrieve the old blobs from the data store and write them back with a new // Retrieve the old blobs from the data store and write them back with a new
// block number. IF anything fails, there's not much to do, go on. // block number. IF anything fails, there's not much to do, go on.
item, err := l.getAndDrop(id) tx, err := l.getAndDrop(item.id)
if err != nil { if err != nil {
log.Error("Failed to get and drop limboed blobs", "tx", txhash, "id", id, "err", err) log.Error("Failed to get and drop limboed blobs", "tx", txhash, "id", item.id, "err", err)
return return
} }
if err := l.setAndIndex(item.Tx, block); err != nil { if err := l.setAndIndex(tx, block); err != nil {
log.Error("Failed to set and index limboed blobs", "tx", txhash, "err", err) log.Error("Failed to set and index limboed blobs", "tx", txhash, "err", err)
return return
} }
@ -207,7 +196,7 @@ func (l *limbo) update(txhash common.Hash, block uint64) {
// getAndDrop retrieves a blob item from the limbo store and deletes it both from // getAndDrop retrieves a blob item from the limbo store and deletes it both from
// the store and indices. // the store and indices.
func (l *limbo) getAndDrop(id uint64) (*limboBlob, error) { func (l *limbo) getAndDrop(id uint64) (*types.Transaction, error) {
data, err := l.store.Get(id) data, err := l.store.Get(id)
if err != nil { if err != nil {
return nil, err return nil, err
@ -217,14 +206,11 @@ func (l *limbo) getAndDrop(id uint64) (*limboBlob, error) {
return nil, err return nil, err
} }
delete(l.index, item.TxHash) delete(l.index, item.TxHash)
delete(l.groups[item.Block], id)
if len(l.groups[item.Block]) == 0 {
delete(l.groups, item.Block)
}
if err := l.store.Delete(id); err != nil { if err := l.store.Delete(id); err != nil {
return nil, err return nil, err
} }
return item, nil
return item.Tx, nil
} }
// setAndIndex assembles a limbo blob database entry and stores it, also updating // setAndIndex assembles a limbo blob database entry and stores it, also updating
@ -244,10 +230,9 @@ func (l *limbo) setAndIndex(tx *types.Transaction, block uint64) error {
if err != nil { if err != nil {
return err return err
} }
l.index[txhash] = id // Delete tx and set id.
if _, ok := l.groups[block]; !ok { item.id, item.Tx = id, nil
l.groups[block] = make(map[uint64]common.Hash) l.index[txhash] = item
}
l.groups[block][id] = txhash
return nil return nil
} }