github.com/MetalBlockchain/metalgo@v1.11.9/snow/consensus/snowman/bootstrapper/minority.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package bootstrapper
     5  
     6  import (
     7  	"context"
     8  
     9  	"go.uber.org/zap"
    10  
    11  	"github.com/MetalBlockchain/metalgo/ids"
    12  	"github.com/MetalBlockchain/metalgo/utils/logging"
    13  	"github.com/MetalBlockchain/metalgo/utils/set"
    14  )
    15  
    16  var _ Poll = (*Minority)(nil)
    17  
    18  // Minority implements the bootstrapping poll to determine the initial set of
    19  // potentially accaptable blocks.
    20  //
    21  // This poll fetches the last accepted block from an initial set of peers. In
    22  // order for the protocol to find a recently accepted block, there must be at
    23  // least one correct node in this set of peers. If there is not a correct node
    24  // in the set of peers, the node will not accept an incorrect block. However,
    25  // the node may be unable to find an acceptable block.
    26  type Minority struct {
    27  	requests
    28  
    29  	log logging.Logger
    30  
    31  	receivedSet set.Set[ids.ID]
    32  	received    []ids.ID
    33  }
    34  
    35  func NewMinority(
    36  	log logging.Logger,
    37  	frontierNodes set.Set[ids.NodeID],
    38  	maxOutstanding int,
    39  ) *Minority {
    40  	return &Minority{
    41  		requests: requests{
    42  			maxOutstanding: maxOutstanding,
    43  			pendingSend:    frontierNodes,
    44  		},
    45  		log: log,
    46  	}
    47  }
    48  
    49  func (m *Minority) RecordOpinion(_ context.Context, nodeID ids.NodeID, blkIDs set.Set[ids.ID]) error {
    50  	if !m.recordResponse(nodeID) {
    51  		// The chain router should have already dropped unexpected messages.
    52  		m.log.Error("received unexpected opinion",
    53  			zap.String("pollType", "minority"),
    54  			zap.Stringer("nodeID", nodeID),
    55  			zap.Reflect("blkIDs", blkIDs),
    56  		)
    57  		return nil
    58  	}
    59  
    60  	m.receivedSet.Union(blkIDs)
    61  
    62  	if !m.finished() {
    63  		return nil
    64  	}
    65  
    66  	m.received = m.receivedSet.List()
    67  
    68  	m.log.Debug("finalized bootstrapping poll",
    69  		zap.String("pollType", "minority"),
    70  		zap.Stringers("frontier", m.received),
    71  	)
    72  	return nil
    73  }
    74  
    75  func (m *Minority) Result(context.Context) ([]ids.ID, bool) {
    76  	return m.received, m.finished()
    77  }