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 }