github.com/MetalBlockchain/metalgo@v1.11.9/snow/engine/avalanche/getter/getter.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package getter
     5  
     6  import (
     7  	"context"
     8  	"time"
     9  
    10  	"github.com/prometheus/client_golang/prometheus"
    11  	"go.uber.org/zap"
    12  
    13  	"github.com/MetalBlockchain/metalgo/ids"
    14  	"github.com/MetalBlockchain/metalgo/message"
    15  	"github.com/MetalBlockchain/metalgo/snow/choices"
    16  	"github.com/MetalBlockchain/metalgo/snow/consensus/avalanche"
    17  	"github.com/MetalBlockchain/metalgo/snow/engine/avalanche/vertex"
    18  	"github.com/MetalBlockchain/metalgo/snow/engine/common"
    19  	"github.com/MetalBlockchain/metalgo/utils/constants"
    20  	"github.com/MetalBlockchain/metalgo/utils/logging"
    21  	"github.com/MetalBlockchain/metalgo/utils/metric"
    22  	"github.com/MetalBlockchain/metalgo/utils/set"
    23  	"github.com/MetalBlockchain/metalgo/utils/wrappers"
    24  )
    25  
    26  // Get requests are always served, regardless node state (bootstrapping or normal operations).
    27  var _ common.AllGetsServer = (*getter)(nil)
    28  
    29  func New(
    30  	storage vertex.Storage,
    31  	sender common.Sender,
    32  	log logging.Logger,
    33  	maxTimeGetAncestors time.Duration,
    34  	maxContainersGetAncestors int,
    35  	reg prometheus.Registerer,
    36  ) (common.AllGetsServer, error) {
    37  	gh := &getter{
    38  		storage:                   storage,
    39  		sender:                    sender,
    40  		log:                       log,
    41  		maxTimeGetAncestors:       maxTimeGetAncestors,
    42  		maxContainersGetAncestors: maxContainersGetAncestors,
    43  	}
    44  
    45  	var err error
    46  	gh.getAncestorsVtxs, err = metric.NewAverager(
    47  		"bs_get_ancestors_vtxs",
    48  		"vertices fetched in a call to GetAncestors",
    49  		reg,
    50  	)
    51  	return gh, err
    52  }
    53  
    54  type getter struct {
    55  	storage                   vertex.Storage
    56  	sender                    common.Sender
    57  	log                       logging.Logger
    58  	maxTimeGetAncestors       time.Duration
    59  	maxContainersGetAncestors int
    60  
    61  	getAncestorsVtxs metric.Averager
    62  }
    63  
    64  func (gh *getter) GetStateSummaryFrontier(_ context.Context, nodeID ids.NodeID, requestID uint32) error {
    65  	gh.log.Debug("dropping request",
    66  		zap.String("reason", "unhandled by this gear"),
    67  		zap.Stringer("messageOp", message.GetStateSummaryFrontierOp),
    68  		zap.Stringer("nodeID", nodeID),
    69  		zap.Uint32("requestID", requestID),
    70  	)
    71  	return nil
    72  }
    73  
    74  func (gh *getter) GetAcceptedStateSummary(_ context.Context, nodeID ids.NodeID, requestID uint32, _ set.Set[uint64]) error {
    75  	gh.log.Debug("dropping request",
    76  		zap.String("reason", "unhandled by this gear"),
    77  		zap.Stringer("messageOp", message.GetAcceptedStateSummaryOp),
    78  		zap.Stringer("nodeID", nodeID),
    79  		zap.Uint32("requestID", requestID),
    80  	)
    81  	return nil
    82  }
    83  
    84  func (gh *getter) GetAcceptedFrontier(_ context.Context, nodeID ids.NodeID, requestID uint32) error {
    85  	gh.log.Debug("dropping request",
    86  		zap.String("reason", "unhandled by this gear"),
    87  		zap.Stringer("messageOp", message.GetAcceptedFrontierOp),
    88  		zap.Stringer("nodeID", nodeID),
    89  		zap.Uint32("requestID", requestID),
    90  	)
    91  	return nil
    92  }
    93  
    94  func (gh *getter) GetAccepted(_ context.Context, nodeID ids.NodeID, requestID uint32, _ set.Set[ids.ID]) error {
    95  	gh.log.Debug("dropping request",
    96  		zap.String("reason", "unhandled by this gear"),
    97  		zap.Stringer("messageOp", message.GetAcceptedOp),
    98  		zap.Stringer("nodeID", nodeID),
    99  		zap.Uint32("requestID", requestID),
   100  	)
   101  	return nil
   102  }
   103  
   104  func (gh *getter) GetAncestors(ctx context.Context, nodeID ids.NodeID, requestID uint32, vtxID ids.ID) error {
   105  	startTime := time.Now()
   106  	gh.log.Verbo("called GetAncestors",
   107  		zap.Stringer("nodeID", nodeID),
   108  		zap.Uint32("requestID", requestID),
   109  		zap.Stringer("vtxID", vtxID),
   110  	)
   111  	vertex, err := gh.storage.GetVtx(ctx, vtxID)
   112  	if err != nil || vertex.Status() == choices.Unknown {
   113  		gh.log.Verbo("dropping getAncestors")
   114  		return nil // Don't have the requested vertex. Drop message.
   115  	}
   116  
   117  	queue := make([]avalanche.Vertex, 1, gh.maxContainersGetAncestors) // for BFS
   118  	queue[0] = vertex
   119  	ancestorsBytesLen := 0                                            // length, in bytes, of vertex and its ancestors
   120  	ancestorsBytes := make([][]byte, 0, gh.maxContainersGetAncestors) // vertex and its ancestors in BFS order
   121  	visited := set.Of(vertex.ID())                                    // IDs of vertices that have been in queue before
   122  
   123  	for len(ancestorsBytes) < gh.maxContainersGetAncestors && len(queue) > 0 && time.Since(startTime) < gh.maxTimeGetAncestors {
   124  		var vtx avalanche.Vertex
   125  		vtx, queue = queue[0], queue[1:] // pop
   126  		vtxBytes := vtx.Bytes()
   127  		// Ensure response size isn't too large. Include wrappers.IntLen because the size of the message
   128  		// is included with each container, and the size is repr. by an int.
   129  		newLen := wrappers.IntLen + ancestorsBytesLen + len(vtxBytes)
   130  		if newLen > constants.MaxContainersLen {
   131  			// reached maximum response size
   132  			break
   133  		}
   134  		ancestorsBytes = append(ancestorsBytes, vtxBytes)
   135  		ancestorsBytesLen = newLen
   136  		parents, err := vtx.Parents()
   137  		if err != nil {
   138  			return err
   139  		}
   140  		for _, parent := range parents {
   141  			if parent.Status() == choices.Unknown { // Don't have this vertex;ignore
   142  				continue
   143  			}
   144  			if parentID := parent.ID(); !visited.Contains(parentID) { // If already visited, ignore
   145  				queue = append(queue, parent)
   146  				visited.Add(parentID)
   147  			}
   148  		}
   149  	}
   150  
   151  	gh.getAncestorsVtxs.Observe(float64(len(ancestorsBytes)))
   152  	gh.sender.SendAncestors(ctx, nodeID, requestID, ancestorsBytes)
   153  	return nil
   154  }
   155  
   156  func (gh *getter) Get(_ context.Context, nodeID ids.NodeID, requestID uint32, _ ids.ID) error {
   157  	gh.log.Debug("dropping request",
   158  		zap.String("reason", "unhandled by this gear"),
   159  		zap.Stringer("messageOp", message.GetOp),
   160  		zap.Stringer("nodeID", nodeID),
   161  		zap.Uint32("requestID", requestID),
   162  	)
   163  	return nil
   164  }