github.com/koko1123/flow-go-1@v0.29.6/consensus/hotstuff/committees/cluster_committee.go (about) 1 package committees 2 3 import ( 4 "fmt" 5 6 "github.com/koko1123/flow-go-1/consensus/hotstuff" 7 "github.com/koko1123/flow-go-1/consensus/hotstuff/committees/leader" 8 "github.com/koko1123/flow-go-1/consensus/hotstuff/model" 9 "github.com/koko1123/flow-go-1/model/flow" 10 "github.com/koko1123/flow-go-1/model/flow/filter" 11 "github.com/koko1123/flow-go-1/state/protocol" 12 "github.com/koko1123/flow-go-1/storage" 13 ) 14 15 // Cluster represents the committee for a cluster of collection nodes. Cluster 16 // committees are epoch-scoped. 17 // 18 // Clusters build blocks on a cluster chain but must obtain identity table 19 // information from the main chain. Thus, block ID parameters in this Committee 20 // implementation reference blocks on the cluster chain, which in turn reference 21 // blocks on the main chain - this implementation manages that translation. 22 type Cluster struct { 23 state protocol.State 24 payloads storage.ClusterPayloads 25 me flow.Identifier 26 // pre-computed leader selection for the full lifecycle of the cluster 27 selection *leader.LeaderSelection 28 // a filter that returns all members of the cluster committee allowed to vote 29 clusterMemberFilter flow.IdentityFilter 30 // initial set of cluster members, WITHOUT updated weight 31 initialClusterMembers flow.IdentityList 32 } 33 34 var _ hotstuff.Committee = (*Cluster)(nil) 35 36 func NewClusterCommittee( 37 state protocol.State, 38 payloads storage.ClusterPayloads, 39 cluster protocol.Cluster, 40 epoch protocol.Epoch, 41 me flow.Identifier, 42 ) (*Cluster, error) { 43 44 selection, err := leader.SelectionForCluster(cluster, epoch) 45 if err != nil { 46 return nil, fmt.Errorf("could not compute leader selection for cluster: %w", err) 47 } 48 49 com := &Cluster{ 50 state: state, 51 payloads: payloads, 52 me: me, 53 selection: selection, 54 clusterMemberFilter: filter.And( 55 cluster.Members().Selector(), 56 filter.Not(filter.Ejected), 57 filter.HasWeight(true), 58 ), 59 initialClusterMembers: cluster.Members(), 60 } 61 return com, nil 62 } 63 64 // Identities returns the identities of all cluster members that are authorized to 65 // participate at the given block. The order of the identities is the canonical order. 66 func (c *Cluster) Identities(blockID flow.Identifier) (flow.IdentityList, error) { 67 // blockID is a collection block not a block produced by consensus, 68 // to query the identities from protocol state, we need to use the reference block id from the payload 69 // 70 // first retrieve the cluster block payload 71 payload, err := c.payloads.ByBlockID(blockID) 72 if err != nil { 73 return nil, fmt.Errorf("could not get cluster payload: %w", err) 74 } 75 76 // an empty reference block ID indicates a root block 77 isRootBlock := payload.ReferenceBlockID == flow.ZeroID 78 79 // use the initial cluster members for root block 80 if isRootBlock { 81 return c.initialClusterMembers, nil 82 } 83 84 // otherwise use the snapshot given by the reference block 85 identities, err := c.state.AtBlockID(payload.ReferenceBlockID).Identities(c.clusterMemberFilter) // remove ejected nodes 86 87 return identities, err 88 } 89 90 func (c *Cluster) Identity(blockID flow.Identifier, nodeID flow.Identifier) (*flow.Identity, error) { 91 92 // first retrieve the cluster block payload 93 payload, err := c.payloads.ByBlockID(blockID) 94 if err != nil { 95 return nil, fmt.Errorf("could not get cluster payload: %w", err) 96 } 97 98 // an empty reference block ID indicates a root block 99 isRootBlock := payload.ReferenceBlockID == flow.ZeroID 100 101 // use the initial cluster members for root block 102 if isRootBlock { 103 identity, ok := c.initialClusterMembers.ByNodeID(nodeID) 104 if !ok { 105 return nil, model.NewInvalidSignerErrorf("node %v is not an authorized hotstuff participant", nodeID) 106 } 107 return identity, nil 108 } 109 110 // otherwise use the snapshot given by the reference block 111 identity, err := c.state.AtBlockID(payload.ReferenceBlockID).Identity(nodeID) 112 if protocol.IsIdentityNotFound(err) { 113 return nil, model.NewInvalidSignerErrorf("%v is not a valid node id at block %v: %w", nodeID, payload.ReferenceBlockID, err) 114 } 115 if err != nil { 116 return nil, fmt.Errorf("could not get identity for node (id=%x): %w", nodeID, err) 117 } 118 if !c.clusterMemberFilter(identity) { 119 return nil, model.NewInvalidSignerErrorf("node %v is not an authorized hotstuff cluster member", nodeID) 120 } 121 return identity, nil 122 } 123 124 func (c *Cluster) LeaderForView(view uint64) (flow.Identifier, error) { 125 return c.selection.LeaderForView(view) 126 } 127 128 func (c *Cluster) Self() flow.Identifier { 129 return c.me 130 } 131 132 func (c *Cluster) DKG(_ flow.Identifier) (hotstuff.DKG, error) { 133 panic("queried DKG of cluster committee") 134 }