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  }