github.com/onflow/flow-go@v0.33.17/engine/access/integration_unsecure_grpc_server_test.go (about) 1 package access 2 3 import ( 4 "context" 5 "io" 6 "os" 7 "testing" 8 "time" 9 10 accessproto "github.com/onflow/flow/protobuf/go/flow/access" 11 executiondataproto "github.com/onflow/flow/protobuf/go/flow/executiondata" 12 "github.com/rs/zerolog" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/mock" 15 "github.com/stretchr/testify/require" 16 "github.com/stretchr/testify/suite" 17 "google.golang.org/grpc" 18 "google.golang.org/grpc/credentials" 19 "google.golang.org/grpc/credentials/insecure" 20 21 "github.com/onflow/flow-go/engine" 22 accessmock "github.com/onflow/flow-go/engine/access/mock" 23 "github.com/onflow/flow-go/engine/access/rpc" 24 "github.com/onflow/flow-go/engine/access/rpc/backend" 25 "github.com/onflow/flow-go/engine/access/state_stream" 26 statestreambackend "github.com/onflow/flow-go/engine/access/state_stream/backend" 27 "github.com/onflow/flow-go/model/flow" 28 "github.com/onflow/flow-go/module/blobs" 29 "github.com/onflow/flow-go/module/execution" 30 "github.com/onflow/flow-go/module/executiondatasync/execution_data" 31 "github.com/onflow/flow-go/module/executiondatasync/execution_data/cache" 32 "github.com/onflow/flow-go/module/grpcserver" 33 "github.com/onflow/flow-go/module/irrecoverable" 34 "github.com/onflow/flow-go/module/mempool/herocache" 35 "github.com/onflow/flow-go/module/metrics" 36 module "github.com/onflow/flow-go/module/mock" 37 "github.com/onflow/flow-go/network" 38 protocol "github.com/onflow/flow-go/state/protocol/mock" 39 "github.com/onflow/flow-go/storage" 40 storagemock "github.com/onflow/flow-go/storage/mock" 41 "github.com/onflow/flow-go/utils/grpcutils" 42 "github.com/onflow/flow-go/utils/unittest" 43 ) 44 45 // SameGRPCPortTestSuite verifies both AccessAPI and ExecutionDataAPI client continue to work when configured 46 // on the same port 47 type SameGRPCPortTestSuite struct { 48 suite.Suite 49 state *protocol.State 50 snapshot *protocol.Snapshot 51 epochQuery *protocol.EpochQuery 52 log zerolog.Logger 53 net *network.EngineRegistry 54 request *module.Requester 55 collClient *accessmock.AccessAPIClient 56 execClient *accessmock.ExecutionAPIClient 57 me *module.Local 58 chainID flow.ChainID 59 metrics *metrics.NoopCollector 60 rpcEng *rpc.Engine 61 stateStreamEng *statestreambackend.Engine 62 63 // storage 64 blocks *storagemock.Blocks 65 headers *storagemock.Headers 66 events *storagemock.Events 67 collections *storagemock.Collections 68 transactions *storagemock.Transactions 69 receipts *storagemock.ExecutionReceipts 70 seals *storagemock.Seals 71 results *storagemock.ExecutionResults 72 registers *execution.RegistersAsyncStore 73 74 ctx irrecoverable.SignalerContext 75 cancel context.CancelFunc 76 77 // grpc servers 78 secureGrpcServer *grpcserver.GrpcServer 79 unsecureGrpcServer *grpcserver.GrpcServer 80 81 bs blobs.Blobstore 82 eds execution_data.ExecutionDataStore 83 broadcaster *engine.Broadcaster 84 execDataCache *cache.ExecutionDataCache 85 execDataHeroCache *herocache.BlockExecutionData 86 87 blockMap map[uint64]*flow.Block 88 } 89 90 func (suite *SameGRPCPortTestSuite) SetupTest() { 91 suite.log = zerolog.New(os.Stdout) 92 suite.net = new(network.EngineRegistry) 93 suite.state = new(protocol.State) 94 suite.snapshot = new(protocol.Snapshot) 95 params := new(protocol.Params) 96 suite.registers = execution.NewRegistersAsyncStore() 97 98 suite.epochQuery = new(protocol.EpochQuery) 99 suite.state.On("Sealed").Return(suite.snapshot, nil).Maybe() 100 suite.state.On("Final").Return(suite.snapshot, nil).Maybe() 101 suite.state.On("Params").Return(params) 102 suite.snapshot.On("Epochs").Return(suite.epochQuery).Maybe() 103 suite.blocks = new(storagemock.Blocks) 104 suite.headers = new(storagemock.Headers) 105 suite.events = new(storagemock.Events) 106 suite.transactions = new(storagemock.Transactions) 107 suite.collections = new(storagemock.Collections) 108 suite.receipts = new(storagemock.ExecutionReceipts) 109 suite.results = new(storagemock.ExecutionResults) 110 suite.seals = new(storagemock.Seals) 111 112 suite.collClient = new(accessmock.AccessAPIClient) 113 suite.execClient = new(accessmock.ExecutionAPIClient) 114 115 suite.request = new(module.Requester) 116 suite.request.On("EntityByID", mock.Anything, mock.Anything) 117 118 suite.me = new(module.Local) 119 suite.eds = execution_data.NewExecutionDataStore(suite.bs, execution_data.DefaultSerializer) 120 121 suite.broadcaster = engine.NewBroadcaster() 122 123 suite.execDataHeroCache = herocache.NewBlockExecutionData(state_stream.DefaultCacheSize, suite.log, metrics.NewNoopCollector()) 124 suite.execDataCache = cache.NewExecutionDataCache(suite.eds, suite.headers, suite.seals, suite.results, suite.execDataHeroCache) 125 126 accessIdentity := unittest.IdentityFixture(unittest.WithRole(flow.RoleAccess)) 127 suite.me. 128 On("NodeID"). 129 Return(accessIdentity.NodeID) 130 131 suite.chainID = flow.Testnet 132 suite.metrics = metrics.NewNoopCollector() 133 134 config := rpc.Config{ 135 UnsecureGRPCListenAddr: unittest.DefaultAddress, 136 SecureGRPCListenAddr: unittest.DefaultAddress, 137 HTTPListenAddr: unittest.DefaultAddress, 138 } 139 140 blockCount := 5 141 suite.blockMap = make(map[uint64]*flow.Block, blockCount) 142 // generate blockCount consecutive blocks with associated seal, result and execution data 143 rootBlock := unittest.BlockFixture() 144 parent := rootBlock.Header 145 suite.blockMap[rootBlock.Header.Height] = &rootBlock 146 147 for i := 0; i < blockCount; i++ { 148 block := unittest.BlockWithParentFixture(parent) 149 suite.blockMap[block.Header.Height] = block 150 } 151 152 params.On("SporkID").Return(unittest.IdentifierFixture(), nil) 153 params.On("ProtocolVersion").Return(uint(unittest.Uint64InRange(10, 30)), nil) 154 params.On("SporkRootBlockHeight").Return(rootBlock.Header.Height, nil) 155 params.On("SealedRoot").Return(rootBlock.Header, nil) 156 157 // generate a server certificate that will be served by the GRPC server 158 networkingKey := unittest.NetworkingPrivKeyFixture() 159 x509Certificate, err := grpcutils.X509Certificate(networkingKey) 160 assert.NoError(suite.T(), err) 161 tlsConfig := grpcutils.DefaultServerTLSConfig(x509Certificate) 162 // set the transport credentials for the server to use 163 config.TransportCredentials = credentials.NewTLS(tlsConfig) 164 165 suite.secureGrpcServer = grpcserver.NewGrpcServerBuilder(suite.log, 166 config.SecureGRPCListenAddr, 167 grpcutils.DefaultMaxMsgSize, 168 false, 169 nil, 170 nil, 171 grpcserver.WithTransportCredentials(config.TransportCredentials)).Build() 172 173 suite.unsecureGrpcServer = grpcserver.NewGrpcServerBuilder(suite.log, 174 config.UnsecureGRPCListenAddr, 175 grpcutils.DefaultMaxMsgSize, 176 false, 177 nil, 178 nil).Build() 179 180 block := unittest.BlockHeaderFixture() 181 suite.snapshot.On("Head").Return(block, nil) 182 183 bnd, err := backend.New(backend.Params{ 184 State: suite.state, 185 CollectionRPC: suite.collClient, 186 Blocks: suite.blocks, 187 Headers: suite.headers, 188 Collections: suite.collections, 189 Transactions: suite.transactions, 190 ChainID: suite.chainID, 191 AccessMetrics: suite.metrics, 192 MaxHeightRange: 0, 193 Log: suite.log, 194 SnapshotHistoryLimit: 0, 195 Communicator: backend.NewNodeCommunicator(false), 196 }) 197 require.NoError(suite.T(), err) 198 199 stateStreamConfig := statestreambackend.Config{} 200 // create rpc engine builder 201 rpcEngBuilder, err := rpc.NewBuilder( 202 suite.log, 203 suite.state, 204 config, 205 suite.chainID, 206 suite.metrics, 207 false, 208 suite.me, 209 bnd, 210 bnd, 211 suite.secureGrpcServer, 212 suite.unsecureGrpcServer, 213 nil, 214 stateStreamConfig, 215 ) 216 assert.NoError(suite.T(), err) 217 suite.rpcEng, err = rpcEngBuilder.WithLegacy().Build() 218 assert.NoError(suite.T(), err) 219 suite.ctx, suite.cancel = irrecoverable.NewMockSignalerContextWithCancel(suite.T(), context.Background()) 220 221 suite.headers.On("BlockIDByHeight", mock.AnythingOfType("uint64")).Return( 222 func(height uint64) flow.Identifier { 223 if block, ok := suite.blockMap[height]; ok { 224 return block.Header.ID() 225 } 226 return flow.ZeroID 227 }, 228 func(height uint64) error { 229 if _, ok := suite.blockMap[height]; ok { 230 return nil 231 } 232 return storage.ErrNotFound 233 }, 234 ).Maybe() 235 236 conf := statestreambackend.Config{ 237 ClientSendTimeout: state_stream.DefaultSendTimeout, 238 ClientSendBufferSize: state_stream.DefaultSendBufferSize, 239 } 240 241 stateStreamBackend, err := statestreambackend.New( 242 suite.log, 243 conf, 244 suite.state, 245 suite.headers, 246 suite.seals, 247 suite.results, 248 nil, 249 suite.execDataCache, 250 nil, 251 rootBlock.Header.Height, 252 rootBlock.Header.Height, 253 suite.registers, 254 backend.NewEventsIndex(suite.events), 255 false, 256 ) 257 assert.NoError(suite.T(), err) 258 259 // create state stream engine 260 suite.stateStreamEng, err = statestreambackend.NewEng( 261 suite.log, 262 conf, 263 suite.execDataCache, 264 suite.headers, 265 suite.chainID, 266 suite.unsecureGrpcServer, 267 stateStreamBackend, 268 nil, 269 ) 270 assert.NoError(suite.T(), err) 271 272 suite.rpcEng.Start(suite.ctx) 273 suite.stateStreamEng.Start(suite.ctx) 274 275 suite.secureGrpcServer.Start(suite.ctx) 276 suite.unsecureGrpcServer.Start(suite.ctx) 277 278 // wait for the servers to startup 279 unittest.AssertClosesBefore(suite.T(), suite.secureGrpcServer.Ready(), 2*time.Second) 280 unittest.AssertClosesBefore(suite.T(), suite.unsecureGrpcServer.Ready(), 2*time.Second) 281 282 // wait for the rpc engine to startup 283 unittest.AssertClosesBefore(suite.T(), suite.rpcEng.Ready(), 2*time.Second) 284 // wait for the state stream engine to startup 285 unittest.AssertClosesBefore(suite.T(), suite.stateStreamEng.Ready(), 2*time.Second) 286 } 287 288 // TestEnginesOnTheSameGrpcPort verifies if both AccessAPI and ExecutionDataAPI client successfully connect and continue 289 // to work when configured on the same port 290 func (suite *SameGRPCPortTestSuite) TestEnginesOnTheSameGrpcPort() { 291 ctx := context.Background() 292 293 conn, err := grpc.Dial( 294 suite.unsecureGrpcServer.GRPCAddress().String(), 295 grpc.WithTransportCredentials(insecure.NewCredentials())) 296 assert.NoError(suite.T(), err) 297 closer := io.Closer(conn) 298 299 suite.Run("happy path - grpc access api client can connect successfully", func() { 300 req := &accessproto.GetNetworkParametersRequest{} 301 302 // expect 2 upstream calls 303 suite.execClient.On("GetNetworkParameters", mock.Anything, mock.Anything).Return(nil, nil).Twice() 304 suite.collClient.On("GetNetworkParameters", mock.Anything, mock.Anything).Return(nil, nil).Twice() 305 306 client := suite.unsecureAccessAPIClient(conn) 307 308 _, err := client.GetNetworkParameters(ctx, req) 309 assert.NoError(suite.T(), err, "failed to get network") 310 }) 311 312 suite.Run("happy path - grpc execution data api client can connect successfully", func() { 313 req := &executiondataproto.SubscribeEventsRequest{} 314 315 client := suite.unsecureExecutionDataAPIClient(conn) 316 317 _, err := client.SubscribeEvents(ctx, req) 318 assert.NoError(suite.T(), err, "failed to subscribe events") 319 }) 320 defer closer.Close() 321 } 322 323 func TestSameGRPCTestSuite(t *testing.T) { 324 suite.Run(t, new(SameGRPCPortTestSuite)) 325 } 326 327 // unsecureAccessAPIClient creates an unsecure grpc AccessAPI client 328 func (suite *SameGRPCPortTestSuite) unsecureAccessAPIClient(conn *grpc.ClientConn) accessproto.AccessAPIClient { 329 client := accessproto.NewAccessAPIClient(conn) 330 return client 331 } 332 333 // unsecureExecutionDataAPIClient creates an unsecure ExecutionDataAPI client 334 func (suite *SameGRPCPortTestSuite) unsecureExecutionDataAPIClient(conn *grpc.ClientConn) executiondataproto.ExecutionDataAPIClient { 335 client := executiondataproto.NewExecutionDataAPIClient(conn) 336 return client 337 }