github.com/MetalBlockchain/metalgo@v1.11.9/subnets/subnet.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package subnets 5 6 import ( 7 "sync" 8 9 "github.com/MetalBlockchain/metalgo/ids" 10 "github.com/MetalBlockchain/metalgo/snow/engine/common" 11 "github.com/MetalBlockchain/metalgo/utils/set" 12 ) 13 14 var _ Subnet = (*subnet)(nil) 15 16 type Allower interface { 17 // IsAllowed filters out nodes that are not allowed to connect to this subnet 18 IsAllowed(nodeID ids.NodeID, isValidator bool) bool 19 } 20 21 // Subnet keeps track of the currently bootstrapping chains in a subnet. If no 22 // chains in the subnet are currently bootstrapping, the subnet is considered 23 // bootstrapped. 24 type Subnet interface { 25 common.BootstrapTracker 26 27 // AddChain adds a chain to this Subnet 28 AddChain(chainID ids.ID) bool 29 30 // Config returns config of this Subnet 31 Config() Config 32 33 Allower 34 } 35 36 type subnet struct { 37 lock sync.RWMutex 38 bootstrapping set.Set[ids.ID] 39 bootstrapped set.Set[ids.ID] 40 once sync.Once 41 bootstrappedSema chan struct{} 42 config Config 43 myNodeID ids.NodeID 44 } 45 46 func New(myNodeID ids.NodeID, config Config) Subnet { 47 return &subnet{ 48 bootstrappedSema: make(chan struct{}), 49 config: config, 50 myNodeID: myNodeID, 51 } 52 } 53 54 func (s *subnet) IsBootstrapped() bool { 55 s.lock.RLock() 56 defer s.lock.RUnlock() 57 58 return s.bootstrapping.Len() == 0 59 } 60 61 func (s *subnet) Bootstrapped(chainID ids.ID) { 62 s.lock.Lock() 63 defer s.lock.Unlock() 64 65 s.bootstrapping.Remove(chainID) 66 s.bootstrapped.Add(chainID) 67 if s.bootstrapping.Len() > 0 { 68 return 69 } 70 71 s.once.Do(func() { 72 close(s.bootstrappedSema) 73 }) 74 } 75 76 func (s *subnet) OnBootstrapCompleted() chan struct{} { 77 return s.bootstrappedSema 78 } 79 80 func (s *subnet) AddChain(chainID ids.ID) bool { 81 s.lock.Lock() 82 defer s.lock.Unlock() 83 84 if s.bootstrapping.Contains(chainID) || s.bootstrapped.Contains(chainID) { 85 return false 86 } 87 88 s.bootstrapping.Add(chainID) 89 return true 90 } 91 92 func (s *subnet) Config() Config { 93 return s.config 94 } 95 96 func (s *subnet) IsAllowed(nodeID ids.NodeID, isValidator bool) bool { 97 // Case 1: NodeID is this node 98 // Case 2: This subnet is not validator-only subnet 99 // Case 3: NodeID is a validator for this chain 100 // Case 4: NodeID is explicitly allowed whether it's subnet validator or not 101 return nodeID == s.myNodeID || 102 !s.config.ValidatorOnly || 103 isValidator || 104 s.config.AllowedNodes.Contains(nodeID) 105 }