arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/coordinator/purger.go
coordinator/purger.goRaw
  1package coordinator
  2
  3import (
  4	"fmt"
  5
  6	"github.com/hermeznetwork/hermez-node/common"
  7	"github.com/hermeznetwork/hermez-node/db/l2db"
  8	"github.com/hermeznetwork/hermez-node/db/statedb"
  9	"github.com/hermeznetwork/hermez-node/log"
 10	"github.com/hermeznetwork/tracerr"
 11	"github.com/iden3/go-merkletree/db"
 12)
 13
 14// PurgerCfg is the purger configuration
 15type PurgerCfg struct {
 16	// PurgeBatchDelay is the delay between batches to purge outdated transactions
 17	PurgeBatchDelay int64
 18	// InvalidateBatchDelay is the delay between batches to mark invalid transactions
 19	InvalidateBatchDelay int64
 20	// PurgeBlockDelay is the delay between blocks to purge outdated transactions
 21	PurgeBlockDelay int64
 22	// InvalidateBlockDelay is the delay between blocks to mark invalid transactions
 23	InvalidateBlockDelay int64
 24}
 25
 26// Purger manages cleanup of transactions in the pool
 27type Purger struct {
 28	cfg                 PurgerCfg
 29	lastPurgeBlock      int64
 30	lastPurgeBatch      int64
 31	lastInvalidateBlock int64
 32	lastInvalidateBatch int64
 33}
 34
 35// CanPurge returns true if it's a good time to purge according to the
 36// configuration
 37func (p *Purger) CanPurge(blockNum, batchNum int64) bool {
 38	if blockNum >= p.lastPurgeBlock+p.cfg.PurgeBlockDelay {
 39		return true
 40	}
 41	if batchNum >= p.lastPurgeBatch+p.cfg.PurgeBatchDelay {
 42		return true
 43	}
 44	return false
 45}
 46
 47// CanInvalidate returns true if it's a good time to invalidate according to
 48// the configuration
 49func (p *Purger) CanInvalidate(blockNum, batchNum int64) bool {
 50	if blockNum >= p.lastInvalidateBlock+p.cfg.InvalidateBlockDelay {
 51		return true
 52	}
 53	if batchNum >= p.lastInvalidateBatch+p.cfg.InvalidateBatchDelay {
 54		return true
 55	}
 56	return false
 57}
 58
 59// PurgeMaybe purges txs if it's a good time to do so
 60func (p *Purger) PurgeMaybe(l2DB *l2db.L2DB, blockNum, batchNum int64) (bool, error) {
 61	if !p.CanPurge(blockNum, batchNum) {
 62		return false, nil
 63	}
 64	p.lastPurgeBlock = blockNum
 65	p.lastPurgeBatch = batchNum
 66	log.Debugw("Purger: purging l2txs in pool", "block", blockNum, "batch", batchNum)
 67	err := l2DB.Purge(common.BatchNum(batchNum))
 68	return true, tracerr.Wrap(err)
 69}
 70
 71// InvalidateMaybe invalidates txs if it's a good time to do so
 72func (p *Purger) InvalidateMaybe(l2DB *l2db.L2DB, stateDB *statedb.LocalStateDB,
 73	blockNum, batchNum int64) (bool, error) {
 74	if !p.CanInvalidate(blockNum, batchNum) {
 75		return false, nil
 76	}
 77	p.lastInvalidateBlock = blockNum
 78	p.lastInvalidateBatch = batchNum
 79	log.Debugw("Purger: invalidating l2txs in pool", "block", blockNum, "batch", batchNum)
 80	err := poolMarkInvalidOldNonces(l2DB, stateDB, common.BatchNum(batchNum))
 81	return true, tracerr.Wrap(err)
 82}
 83
 84//nolint:unused,deadcode
 85func idxsNonceFromL2Txs(txs []common.L2Tx) []common.IdxNonce {
 86	idxNonceMap := map[common.Idx]common.Nonce{}
 87	for _, tx := range txs {
 88		if nonce, ok := idxNonceMap[tx.FromIdx]; !ok {
 89			idxNonceMap[tx.FromIdx] = tx.Nonce
 90		} else if tx.Nonce > nonce {
 91			idxNonceMap[tx.FromIdx] = tx.Nonce
 92		}
 93	}
 94	idxsNonce := make([]common.IdxNonce, 0, len(idxNonceMap))
 95	for idx, nonce := range idxNonceMap {
 96		idxsNonce = append(idxsNonce, common.IdxNonce{Idx: idx, Nonce: nonce})
 97	}
 98	return idxsNonce
 99}
100
101func idxsNonceFromPoolL2Txs(txs []common.PoolL2Tx) []common.IdxNonce {
102	idxNonceMap := map[common.Idx]common.Nonce{}
103	for _, tx := range txs {
104		if nonce, ok := idxNonceMap[tx.FromIdx]; !ok {
105			idxNonceMap[tx.FromIdx] = tx.Nonce
106		} else if tx.Nonce > nonce {
107			idxNonceMap[tx.FromIdx] = tx.Nonce
108		}
109	}
110	idxsNonce := make([]common.IdxNonce, 0, len(idxNonceMap))
111	for idx, nonce := range idxNonceMap {
112		idxsNonce = append(idxsNonce, common.IdxNonce{Idx: idx, Nonce: nonce})
113	}
114	return idxsNonce
115}
116
117// poolMarkInvalidOldNonces marks as invalid txs in the pool that contain
118// nonces equal or older to the nonce of the corresponding sender account
119func poolMarkInvalidOldNonces(l2DB *l2db.L2DB, stateDB *statedb.LocalStateDB,
120	batchNum common.BatchNum) error {
121	idxs, err := l2DB.GetPendingUniqueFromIdxs()
122	if err != nil {
123		return tracerr.Wrap(err)
124	}
125	idxsNonce := make([]common.IdxNonce, len(idxs))
126	lastIdx, err := stateDB.GetCurrentIdx()
127	if err != nil {
128		return tracerr.Wrap(err)
129	}
130	for i, idx := range idxs {
131		acc, err := stateDB.GetAccount(idx)
132		if err != nil {
133			if tracerr.Unwrap(err) != db.ErrNotFound {
134				return tracerr.Wrap(err)
135			} else if idx <= lastIdx {
136				return tracerr.Wrap(fmt.Errorf("account with idx %v not found: %w", idx, err))
137			} else {
138				return tracerr.Wrap(fmt.Errorf("unexpected stateDB error with idx %v: %w", idx, err))
139			}
140		}
141		idxsNonce[i].Idx = idx
142		idxsNonce[i].Nonce = acc.Nonce
143	}
144	return l2DB.InvalidateOldNonces(idxsNonce, batchNum)
145}