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