github.com/koko1123/flow-go-1@v0.29.6/consensus/hotstuff/committees/cluster_committee_test.go (about) 1 package committees 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/suite" 7 8 "github.com/koko1123/flow-go-1/consensus/hotstuff/model" 9 "github.com/koko1123/flow-go-1/model/cluster" 10 "github.com/koko1123/flow-go-1/model/flow" 11 clusterstate "github.com/koko1123/flow-go-1/state/cluster" 12 "github.com/koko1123/flow-go-1/state/protocol" 13 protocolmock "github.com/koko1123/flow-go-1/state/protocol/mock" 14 "github.com/koko1123/flow-go-1/state/protocol/seed" 15 storagemock "github.com/koko1123/flow-go-1/storage/mock" 16 "github.com/koko1123/flow-go-1/utils/unittest" 17 ) 18 19 // ClusterSuite defines a test suite for the cluster committee. 20 type ClusterSuite struct { 21 suite.Suite 22 23 state *protocolmock.State 24 snap *protocolmock.Snapshot 25 cluster *protocolmock.Cluster 26 epoch *protocolmock.Epoch 27 payloads *storagemock.ClusterPayloads 28 29 members flow.IdentityList 30 root *cluster.Block 31 me *flow.Identity 32 33 com *Cluster 34 } 35 36 func TestClusterCommittee(t *testing.T) { 37 suite.Run(t, new(ClusterSuite)) 38 } 39 40 func (suite *ClusterSuite) SetupTest() { 41 42 suite.state = new(protocolmock.State) 43 suite.snap = new(protocolmock.Snapshot) 44 suite.cluster = new(protocolmock.Cluster) 45 suite.epoch = new(protocolmock.Epoch) 46 suite.payloads = new(storagemock.ClusterPayloads) 47 48 suite.members = unittest.IdentityListFixture(5, unittest.WithRole(flow.RoleCollection)) 49 suite.me = suite.members[0] 50 counter := uint64(1) 51 suite.root = clusterstate.CanonicalRootBlock(counter, suite.members) 52 53 suite.cluster.On("EpochCounter").Return(counter) 54 suite.cluster.On("Index").Return(uint(1)) 55 suite.cluster.On("Members").Return(suite.members) 56 suite.cluster.On("RootBlock").Return(suite.root) 57 suite.epoch.On("Counter").Return(counter, nil) 58 suite.epoch.On("RandomSource").Return(unittest.SeedFixture(seed.RandomSourceLength), nil) 59 60 var err error 61 suite.com, err = NewClusterCommittee( 62 suite.state, 63 suite.payloads, 64 suite.cluster, 65 suite.epoch, 66 suite.me.NodeID, 67 ) 68 suite.Require().NoError(err) 69 } 70 71 // TestInvalidSigner tests that the InvalidSignerError sentinel is 72 // returned under the appropriate conditions. 73 func (suite *ClusterSuite) TestInvalidSigner() { 74 75 // hook up cluster->main chain connection for root and non-root cluster block 76 nonRootBlockID := unittest.IdentifierFixture() 77 rootBlockID := suite.root.ID() 78 79 refID := unittest.IdentifierFixture() // reference block on main chain 80 payload := cluster.EmptyPayload(refID) // payload referencing main chain 81 rootPayload := cluster.EmptyPayload(flow.ZeroID) // root cluster block payload 82 83 suite.payloads.On("ByBlockID", nonRootBlockID).Return(&payload, nil) 84 suite.payloads.On("ByBlockID", rootBlockID).Return(&rootPayload, nil) 85 86 // a real cluster member which continues to be a valid member 87 realClusterMember := suite.members[1] 88 // a real cluster member which loses all its weight between cluster initialization 89 // and the test's reference block 90 realNoWeightClusterMember := suite.members[2] 91 realNoWeightClusterMember.Weight = 0 92 // a real cluster member which is ejected between cluster initialization and 93 // the test's reference block 94 realEjectedClusterMember := suite.members[3] 95 realEjectedClusterMember.Ejected = true 96 realNonClusterMember := unittest.IdentityFixture(unittest.WithRole(flow.RoleCollection)) 97 fakeID := unittest.IdentifierFixture() 98 99 suite.state.On("AtBlockID", refID).Return(suite.snap) 100 suite.snap.On("Identity", realClusterMember.NodeID).Return(realClusterMember, nil) 101 suite.snap.On("Identity", realNoWeightClusterMember.NodeID).Return(realNoWeightClusterMember, nil) 102 suite.snap.On("Identity", realEjectedClusterMember.NodeID).Return(realEjectedClusterMember, nil) 103 suite.snap.On("Identity", realNonClusterMember.NodeID).Return(realNonClusterMember, nil) 104 suite.snap.On("Identity", fakeID).Return(nil, protocol.IdentityNotFoundError{}) 105 106 suite.Run("should return InvalidSignerError for non-existent signer", func() { 107 suite.Run("root block", func() { 108 _, err := suite.com.Identity(rootBlockID, fakeID) 109 suite.Assert().True(model.IsInvalidSignerError(err)) 110 }) 111 suite.Run("non-root block", func() { 112 _, err := suite.com.Identity(nonRootBlockID, fakeID) 113 suite.Assert().True(model.IsInvalidSignerError(err)) 114 }) 115 }) 116 117 suite.Run("should return InvalidSignerError for existent non-cluster-member", func() { 118 suite.Run("root block", func() { 119 _, err := suite.com.Identity(rootBlockID, realNonClusterMember.NodeID) 120 suite.Assert().True(model.IsInvalidSignerError(err)) 121 }) 122 suite.Run("non-root block", func() { 123 _, err := suite.com.Identity(nonRootBlockID, realNonClusterMember.NodeID) 124 suite.Assert().True(model.IsInvalidSignerError(err)) 125 }) 126 }) 127 128 suite.Run("should return ErrInvalidSigner for existent but ejected cluster member", func() { 129 // at the root block, the cluster member is not ejected yet 130 suite.Run("root block", func() { 131 actual, err := suite.com.Identity(rootBlockID, realEjectedClusterMember.NodeID) 132 suite.Require().NoError(err) 133 suite.Assert().Equal(realEjectedClusterMember, actual) 134 }) 135 suite.Run("non-root block", func() { 136 _, err := suite.com.Identity(nonRootBlockID, realEjectedClusterMember.NodeID) 137 suite.Assert().True(model.IsInvalidSignerError(err)) 138 }) 139 }) 140 141 suite.Run("should return ErrInvalidSigner for existent but zero-weight cluster member", func() { 142 // at the root block, the cluster member has its initial weight 143 suite.Run("root block", func() { 144 actual, err := suite.com.Identity(rootBlockID, realNoWeightClusterMember.NodeID) 145 suite.Require().NoError(err) 146 suite.Assert().Equal(realNoWeightClusterMember, actual) 147 }) 148 suite.Run("non-root block", func() { 149 _, err := suite.com.Identity(nonRootBlockID, realNoWeightClusterMember.NodeID) 150 suite.Assert().True(model.IsInvalidSignerError(err)) 151 }) 152 }) 153 154 suite.Run("should return identity for existent cluster member", func() { 155 suite.Run("root block", func() { 156 actual, err := suite.com.Identity(rootBlockID, realClusterMember.NodeID) 157 suite.Require().NoError(err) 158 suite.Assert().Equal(realClusterMember, actual) 159 }) 160 suite.Run("non-root block", func() { 161 actual, err := suite.com.Identity(nonRootBlockID, realClusterMember.NodeID) 162 suite.Require().NoError(err) 163 suite.Assert().Equal(realClusterMember, actual) 164 }) 165 }) 166 }