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, 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// poolMarkInvalidOldNoncesFromL2Txs marks as invalid the txs in the pool that
118// contain nonces equal or older to the highest nonce used in a forged l2Tx for
119// the
120// corresponding sender account
121func poolMarkInvalidOldNoncesFromL2Txs(l2DB *l2db.L2DB,
122	idxsNonce []common.IdxNonce, batchNum common.BatchNum) error {
123	return l2DB.CheckNonces(idxsNonce, batchNum)
124}
125
126// poolMarkInvalidOldNonces marks as invalid txs in the pool that contain
127// nonces equal or older to the nonce of the corresponding sender account
128func poolMarkInvalidOldNonces(l2DB *l2db.L2DB, stateDB *statedb.LocalStateDB,
129	batchNum common.BatchNum) error {
130	idxs, err := l2DB.GetPendingUniqueFromIdxs()
131	if err != nil {
132		return err
133	}
134	idxsNonce := make([]common.IdxNonce, len(idxs))
135	lastIdx, err := stateDB.GetIdx()
136	if err != nil {
137		return err
138	}
139	for i, idx := range idxs {
140		acc, err := stateDB.GetAccount(idx)
141		if err != nil {
142			if tracerr.Unwrap(err) != db.ErrNotFound {
143				return err
144			} else if idx <= lastIdx {
145				return fmt.Errorf("account with idx %v not found: %w", idx, err)
146			}
147		}
148		idxsNonce[i].Idx = idx
149		idxsNonce[i].Nonce = acc.Nonce
150	}
151	return l2DB.CheckNonces(idxsNonce, batchNum)
152}