github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/cache/depositcache/pending_deposits.go (about)

     1  package depositcache
     2  
     3  import (
     4  	"context"
     5  	"math/big"
     6  	"sort"
     7  
     8  	"github.com/prometheus/client_golang/prometheus"
     9  	"github.com/prometheus/client_golang/prometheus/promauto"
    10  	dbpb "github.com/prysmaticlabs/prysm/proto/beacon/db"
    11  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    12  	"github.com/prysmaticlabs/prysm/shared/hashutil"
    13  	"github.com/sirupsen/logrus"
    14  	"go.opencensus.io/trace"
    15  )
    16  
    17  var (
    18  	pendingDepositsCount = promauto.NewGauge(prometheus.GaugeOpts{
    19  		Name: "beacondb_pending_deposits",
    20  		Help: "The number of pending deposits in the beaconDB in-memory database",
    21  	})
    22  )
    23  
    24  // PendingDepositsFetcher specifically outlines a struct that can retrieve deposits
    25  // which have not yet been included in the chain.
    26  type PendingDepositsFetcher interface {
    27  	PendingContainers(ctx context.Context, untilBlk *big.Int) []*dbpb.DepositContainer
    28  }
    29  
    30  // InsertPendingDeposit into the database. If deposit or block number are nil
    31  // then this method does nothing.
    32  func (dc *DepositCache) InsertPendingDeposit(ctx context.Context, d *ethpb.Deposit, blockNum uint64, index int64, depositRoot [32]byte) {
    33  	ctx, span := trace.StartSpan(ctx, "DepositsCache.InsertPendingDeposit")
    34  	defer span.End()
    35  	if d == nil {
    36  		log.WithFields(logrus.Fields{
    37  			"block":   blockNum,
    38  			"deposit": d,
    39  		}).Debug("Ignoring nil deposit insertion")
    40  		return
    41  	}
    42  	dc.depositsLock.Lock()
    43  	defer dc.depositsLock.Unlock()
    44  	dc.pendingDeposits = append(dc.pendingDeposits,
    45  		&dbpb.DepositContainer{Deposit: d, Eth1BlockHeight: blockNum, Index: index, DepositRoot: depositRoot[:]})
    46  	pendingDepositsCount.Inc()
    47  	span.AddAttributes(trace.Int64Attribute("count", int64(len(dc.pendingDeposits))))
    48  }
    49  
    50  // PendingDeposits returns a list of deposits until the given block number
    51  // (inclusive). If no block is specified then this method returns all pending
    52  // deposits.
    53  func (dc *DepositCache) PendingDeposits(ctx context.Context, untilBlk *big.Int) []*ethpb.Deposit {
    54  	ctx, span := trace.StartSpan(ctx, "DepositsCache.PendingDeposits")
    55  	defer span.End()
    56  
    57  	depositCntrs := dc.PendingContainers(ctx, untilBlk)
    58  
    59  	var deposits []*ethpb.Deposit
    60  	for _, dep := range depositCntrs {
    61  		deposits = append(deposits, dep.Deposit)
    62  	}
    63  
    64  	return deposits
    65  }
    66  
    67  // PendingContainers returns a list of deposit containers until the given block number
    68  // (inclusive).
    69  func (dc *DepositCache) PendingContainers(ctx context.Context, untilBlk *big.Int) []*dbpb.DepositContainer {
    70  	ctx, span := trace.StartSpan(ctx, "DepositsCache.PendingDeposits")
    71  	defer span.End()
    72  	dc.depositsLock.RLock()
    73  	defer dc.depositsLock.RUnlock()
    74  
    75  	var depositCntrs []*dbpb.DepositContainer
    76  	for _, ctnr := range dc.pendingDeposits {
    77  		if untilBlk == nil || untilBlk.Uint64() >= ctnr.Eth1BlockHeight {
    78  			depositCntrs = append(depositCntrs, ctnr)
    79  		}
    80  	}
    81  	// Sort the deposits by Merkle index.
    82  	sort.SliceStable(depositCntrs, func(i, j int) bool {
    83  		return depositCntrs[i].Index < depositCntrs[j].Index
    84  	})
    85  
    86  	span.AddAttributes(trace.Int64Attribute("count", int64(len(depositCntrs))))
    87  
    88  	return depositCntrs
    89  }
    90  
    91  // RemovePendingDeposit from the database. The deposit is indexed by the
    92  // Index. This method does nothing if deposit ptr is nil.
    93  func (dc *DepositCache) RemovePendingDeposit(ctx context.Context, d *ethpb.Deposit) {
    94  	ctx, span := trace.StartSpan(ctx, "DepositsCache.RemovePendingDeposit")
    95  	defer span.End()
    96  
    97  	if d == nil {
    98  		log.Debug("Ignoring nil deposit removal")
    99  		return
   100  	}
   101  
   102  	depRoot, err := hashutil.HashProto(d)
   103  	if err != nil {
   104  		log.Errorf("Could not remove deposit %v", err)
   105  		return
   106  	}
   107  
   108  	dc.depositsLock.Lock()
   109  	defer dc.depositsLock.Unlock()
   110  
   111  	idx := -1
   112  	for i, ctnr := range dc.pendingDeposits {
   113  		hash, err := hashutil.HashProto(ctnr.Deposit)
   114  		if err != nil {
   115  			log.Errorf("Could not hash deposit %v", err)
   116  			continue
   117  		}
   118  		if hash == depRoot {
   119  			idx = i
   120  			break
   121  		}
   122  	}
   123  
   124  	if idx >= 0 {
   125  		dc.pendingDeposits = append(dc.pendingDeposits[:idx], dc.pendingDeposits[idx+1:]...)
   126  		pendingDepositsCount.Dec()
   127  	}
   128  }
   129  
   130  // PrunePendingDeposits removes any deposit which is older than the given deposit merkle tree index.
   131  func (dc *DepositCache) PrunePendingDeposits(ctx context.Context, merkleTreeIndex int64) {
   132  	ctx, span := trace.StartSpan(ctx, "DepositsCache.PrunePendingDeposits")
   133  	defer span.End()
   134  
   135  	if merkleTreeIndex == 0 {
   136  		log.Debug("Ignoring 0 deposit removal")
   137  		return
   138  	}
   139  
   140  	dc.depositsLock.Lock()
   141  	defer dc.depositsLock.Unlock()
   142  
   143  	var cleanDeposits []*dbpb.DepositContainer
   144  	for _, dp := range dc.pendingDeposits {
   145  		if dp.Index >= merkleTreeIndex {
   146  			cleanDeposits = append(cleanDeposits, dp)
   147  		}
   148  	}
   149  
   150  	dc.pendingDeposits = cleanDeposits
   151  	pendingDepositsCount.Set(float64(len(dc.pendingDeposits)))
   152  }