From 0f82f8c7e5c0f87772ad5d7f917badabc4e7b86e Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Thu, 3 Aug 2023 11:59:13 +0100 Subject: [PATCH 01/66] 4585 Add more testable backend constructor with unit tests --- engine/access/rpc/backend/backend.go | 161 ++++++++- engine/access/rpc/backend/backend_accounts.go | 2 +- engine/access/rpc/backend/backend_events.go | 2 +- engine/access/rpc/backend/backend_scripts.go | 2 +- engine/access/rpc/backend/backend_test.go | 7 + .../rpc/backend/backend_transactions.go | 7 +- .../rpc/backend/backend_transactions_test.go | 310 ++++++++++++++++++ 7 files changed, 481 insertions(+), 10 deletions(-) create mode 100644 engine/access/rpc/backend/backend_transactions_test.go diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 9b10cc5b539..52ec7fe286b 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -8,10 +8,7 @@ import ( "time" lru "github.com/hashicorp/golang-lru" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - + lru2 "github.com/hashicorp/golang-lru/v2" "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/cmd/build" "github.com/onflow/flow-go/engine/access/rpc/connection" @@ -22,8 +19,11 @@ import ( "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - + "github.com/onflow/flow-go/storage/badger" accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) // minExecutionNodesCnt is the minimum number of execution nodes expected to have sent the execution receipt for a block @@ -76,6 +76,7 @@ type Backend struct { collections storage.Collections executionReceipts storage.ExecutionReceipts connFactory connection.ConnectionFactory + resultCache *badger.Cache[flow.Identifier, *access.TransactionResult] } // Config defines the configurable options for creating Backend @@ -90,6 +91,148 @@ type Config struct { CircuitBreakerConfig connection.CircuitBreakerConfig // the configuration for circuit breaker } +type Communicator interface { + CallAvailableNode( + nodes flow.IdentityList, + call NodeAction, + shouldTerminateOnError ErrorTerminator, + ) error +} + +// NewBackend creates backend accepting Communicator interfaces instead of circuitBreakerEnabled flag +// More convenient fur unit testing scenarios when you need to pass test NodeCommunicator objects. +func NewBackend(state protocol.State, + collectionRPC accessproto.AccessAPIClient, + historicalAccessNodes []accessproto.AccessAPIClient, + blocks storage.Blocks, + headers storage.Headers, + collections storage.Collections, + transactions storage.Transactions, + executionReceipts storage.ExecutionReceipts, + executionResults storage.ExecutionResults, + chainID flow.ChainID, + accessMetrics module.AccessMetrics, + connFactory connection.ConnectionFactory, + retryEnabled bool, + maxHeightRange uint, + preferredExecutionNodeIDs []string, + fixedExecutionNodeIDs []string, + log zerolog.Logger, + snapshotHistoryLimit int, + archiveAddressList []string, + communicator Communicator) *Backend { + retry := newRetry() + if retryEnabled { + retry.Activate() + } + + loggedScripts, err := lru.New(DefaultLoggedScriptsCacheSize) + if err != nil { + log.Fatal().Err(err).Msg("failed to initialize script logging cache") + } + + archivePorts := make([]uint, len(archiveAddressList)) + for idx, addr := range archiveAddressList { + port, err := findPortFromAddress(addr) + if err != nil { + log.Fatal().Err(err).Msg("failed to find archive node port") + } + archivePorts[idx] = port + } + + txResCache, err := lru2.New[flow.Identifier, *access.TransactionResult](int(badger.DefaultCacheSize)) + if err != nil { + log.Fatal().Err(err).Msg("failed to init cache for transaction results") + } + + b := &Backend{ + state: state, + // create the sub-backends + backendScripts: backendScripts{ + headers: headers, + executionReceipts: executionReceipts, + connFactory: connFactory, + state: state, + log: log, + metrics: accessMetrics, + loggedScripts: loggedScripts, + archiveAddressList: archiveAddressList, + archivePorts: archivePorts, + nodeCommunicator: communicator, + }, + backendTransactions: backendTransactions{ + staticCollectionRPC: collectionRPC, + state: state, + chainID: chainID, + collections: collections, + blocks: blocks, + transactions: transactions, + executionReceipts: executionReceipts, + transactionValidator: configureTransactionValidator(state, chainID), + transactionMetrics: accessMetrics, + retry: retry, + connFactory: connFactory, + previousAccessNodes: historicalAccessNodes, + log: log, + nodeCommunicator: communicator, + txResultCache: txResCache, + }, + backendEvents: backendEvents{ + state: state, + headers: headers, + executionReceipts: executionReceipts, + connFactory: connFactory, + log: log, + maxHeightRange: maxHeightRange, + nodeCommunicator: communicator, + }, + backendBlockHeaders: backendBlockHeaders{ + headers: headers, + state: state, + }, + backendBlockDetails: backendBlockDetails{ + blocks: blocks, + state: state, + }, + backendAccounts: backendAccounts{ + state: state, + headers: headers, + executionReceipts: executionReceipts, + connFactory: connFactory, + log: log, + nodeCommunicator: communicator, + }, + backendExecutionResults: backendExecutionResults{ + executionResults: executionResults, + }, + backendNetwork: backendNetwork{ + state: state, + chainID: chainID, + snapshotHistoryLimit: snapshotHistoryLimit, + }, + collections: collections, + executionReceipts: executionReceipts, + connFactory: connFactory, + chainID: chainID, + } + + retry.SetBackend(b) + + preferredENIdentifiers, err = identifierList(preferredExecutionNodeIDs) + if err != nil { + log.Fatal().Err(err).Msg("failed to convert node id string to Flow Identifier for preferred EN map") + } + + fixedENIdentifiers, err = identifierList(fixedExecutionNodeIDs) + if err != nil { + log.Fatal().Err(err).Msg("failed to convert node id string to Flow Identifier for fixed EN map") + } + + return b +} + +// New create new backend instance +// Deprecated: Use NewBackend for enhanced testability func New( state protocol.State, collectionRPC accessproto.AccessAPIClient, @@ -134,6 +277,11 @@ func New( // create node communicator, that will be used in sub-backend logic for interacting with API calls nodeCommunicator := NewNodeCommunicator(circuitBreakerEnabled) + txResCache, err := lru2.New[flow.Identifier, *access.TransactionResult](int(badger.DefaultCacheSize)) + if err != nil { + log.Fatal().Err(err).Msg("failed to init cache for transaction results") + } + b := &Backend{ state: state, // create the sub-backends @@ -164,6 +312,7 @@ func New( previousAccessNodes: historicalAccessNodes, log: log, nodeCommunicator: nodeCommunicator, + txResultCache: txResCache, }, backendEvents: backendEvents{ state: state, @@ -219,6 +368,8 @@ func New( return b } +//TODO: refactor cache, replace with generic lru.Cache alternative + // NewCache constructs cache for storing connections to other nodes. // No errors are expected during normal operations. func NewCache( diff --git a/engine/access/rpc/backend/backend_accounts.go b/engine/access/rpc/backend/backend_accounts.go index 35f8f0bf4df..470b91048ab 100644 --- a/engine/access/rpc/backend/backend_accounts.go +++ b/engine/access/rpc/backend/backend_accounts.go @@ -24,7 +24,7 @@ type backendAccounts struct { executionReceipts storage.ExecutionReceipts connFactory connection.ConnectionFactory log zerolog.Logger - nodeCommunicator *NodeCommunicator + nodeCommunicator Communicator } func (b *backendAccounts) GetAccount(ctx context.Context, address flow.Address) (*flow.Account, error) { diff --git a/engine/access/rpc/backend/backend_events.go b/engine/access/rpc/backend/backend_events.go index d0b52820ee4..43b42cde2f5 100644 --- a/engine/access/rpc/backend/backend_events.go +++ b/engine/access/rpc/backend/backend_events.go @@ -27,7 +27,7 @@ type backendEvents struct { connFactory connection.ConnectionFactory log zerolog.Logger maxHeightRange uint - nodeCommunicator *NodeCommunicator + nodeCommunicator Communicator } // GetEventsForHeightRange retrieves events for all sealed blocks between the start block height and diff --git a/engine/access/rpc/backend/backend_scripts.go b/engine/access/rpc/backend/backend_scripts.go index 62d32c56211..c1b1bfc344a 100644 --- a/engine/access/rpc/backend/backend_scripts.go +++ b/engine/access/rpc/backend/backend_scripts.go @@ -35,7 +35,7 @@ type backendScripts struct { loggedScripts *lru.Cache archiveAddressList []string archivePorts []uint - nodeCommunicator *NodeCommunicator + nodeCommunicator Communicator } func (b *backendScripts) ExecuteScriptAtLatestBlock( diff --git a/engine/access/rpc/backend/backend_test.go b/engine/access/rpc/backend/backend_test.go index d40ff45890e..83fb3020c04 100644 --- a/engine/access/rpc/backend/backend_test.go +++ b/engine/access/rpc/backend/backend_test.go @@ -46,11 +46,16 @@ type Suite struct { transactions *storagemock.Transactions receipts *storagemock.ExecutionReceipts results *storagemock.ExecutionResults + + colClient *access.AccessAPIClient execClient *access.ExecutionAPIClient historicalAccessClient *access.AccessAPIClient archiveClient *access.AccessAPIClient + connectionFactory *backendmock.ConnectionFactory + communicator *NodeCommunicatorMock + chainID flow.ChainID } @@ -79,6 +84,8 @@ func (suite *Suite) SetupTest() { suite.chainID = flow.Testnet suite.historicalAccessClient = new(access.AccessAPIClient) suite.connectionFactory = new(backendmock.ConnectionFactory) + + suite.communicator = new(NodeCommunicatorMock) } func (suite *Suite) TestPing() { diff --git a/engine/access/rpc/backend/backend_transactions.go b/engine/access/rpc/backend/backend_transactions.go index 79579d420e6..b3debaaac27 100644 --- a/engine/access/rpc/backend/backend_transactions.go +++ b/engine/access/rpc/backend/backend_transactions.go @@ -24,6 +24,8 @@ import ( "github.com/onflow/flow-go/storage" ) + + type backendTransactions struct { staticCollectionRPC accessproto.AccessAPIClient // rpc client tied to a fixed collection node transactions storage.Transactions @@ -39,7 +41,7 @@ type backendTransactions struct { previousAccessNodes []accessproto.AccessAPIClient log zerolog.Logger - nodeCommunicator *NodeCommunicator + nodeCommunicator Communicator } // SendTransaction forwards the transaction to the collection node @@ -229,12 +231,13 @@ func (b *backendTransactions) GetTransactionResult( ) (*access.TransactionResult, error) { // look up transaction from storage start := time.Now() - tx, err := b.transactions.ByID(txID) + tx, err := b.transactions.ByID(txID) if err != nil { txErr := rpc.ConvertStorageError(err) if status.Code(txErr) == codes.NotFound { // Tx not found. If we have historical Sporks setup, lets look through those as well + historicalTxResult, err := b.getHistoricalTransactionResult(ctx, txID) if err != nil { // if tx not found in old access nodes either, then assume that the tx was submitted to a different AN diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go new file mode 100644 index 00000000000..d6d73e6363c --- /dev/null +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -0,0 +1,310 @@ +package backend + +import ( + "context" + "fmt" + + "github.com/dgraph-io/badger/v2" + "github.com/onflow/flow-go/model/flow" + "github.com/onflow/flow-go/module/metrics" + bprotocol "github.com/onflow/flow-go/state/protocol/badger" + "github.com/onflow/flow-go/state/protocol/util" + "github.com/onflow/flow-go/storage" + "github.com/onflow/flow-go/utils/unittest" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (suite *Suite) TestGetTransactionResultReturnsUnknown() { + + identities := unittest.CompleteIdentitySet() + rootSnapshot := unittest.RootSnapshotFixture(identities) + util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { + epochBuilder := unittest.NewEpochBuilder(suite.T(), state) + + epochBuilder. + BuildEpoch(). + CompleteEpoch() + + // get heights of each phase in built epochs + epoch1, ok := epochBuilder.EpochHeights(1) + require.True(suite.T(), ok) + + // setup AtHeight mock returns for state + for _, height := range epoch1.Range() { + suite.state.On("AtHeisght", epoch1.Range()).Return(state.AtHeight(height)) + } + + snap := state.AtHeight(epoch1.Range()[0]) + suite.state.On("Final").Return(snap).Once() + suite.communicator.On("CallAvailableNode", + mock.Anything, + mock.Anything, + mock.Anything). + Return(nil) + + block := unittest.BlockFixture() + tbody := unittest.TransactionBodyFixture() + tx := unittest.TransactionFixture() + tx.TransactionBody = tbody + + coll := flow.CollectionFromTransactions([]*flow.Transaction{&tx}) + + suite.transactions. + On("ByID", tx.ID()). + Return(nil, storage.ErrNotFound) + + suite.blocks. + On("ByID", block.ID()). + Return(&block, nil). + Once() + + receipt := unittest.ExecutionReceiptFixture() + identity := unittest.IdentityFixture() + identity.Role = flow.RoleExecution + + suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() + + l := flow.ExecutionReceiptList{receipt} + + suite.receipts. + On("ByBlockID", block.ID()). + Return(l, nil) + + backend := NewBackend( + suite.state, + suite.colClient, + nil, + suite.blocks, + nil, + nil, + suite.transactions, + suite.receipts, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + suite.communicator, + ) + res, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) + suite.Require().NoError(err) + suite.Require().Equal(res.Status, flow.TransactionStatusUnknown) + }) +} + +func (suite *Suite) TestGetTransactionResultReturnsTransactionError() { + + identities := unittest.CompleteIdentitySet() + rootSnapshot := unittest.RootSnapshotFixture(identities) + util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { + epochBuilder := unittest.NewEpochBuilder(suite.T(), state) + + // building 2 epochs allows us to take a snapshot at a point in time where + // an epoch transition happens + epochBuilder. + BuildEpoch(). + CompleteEpoch() + + epochBuilder. + BuildEpoch(). + CompleteEpoch() + + // get heights of each phase in built epochs + epoch1, ok := epochBuilder.EpochHeights(1) + require.True(suite.T(), ok) + epoch2, ok := epochBuilder.EpochHeights(2) + require.True(suite.T(), ok) + + // setup AtHeight mock returns for state + for _, height := range append(epoch1.Range(), epoch2.Range()...) { + suite.state.On("AtHeight", height).Return(state.AtHeight(height)) + } + + // Take snapshot at height of the first block of epoch2, the sealing segment of this snapshot + // will have contain block spanning an epoch transition as well as an epoch phase transition. + // This will cause our GetLatestProtocolStateSnapshot func to return a snapshot + // at block with height 3, the first block of the staking phase of epoch1. + + snap := state.AtHeight(epoch2.Range()[0]) + suite.state.On("Final").Return(snap).Once() + + block := unittest.BlockFixture() + tbody := unittest.TransactionBodyFixture() + tx := unittest.TransactionFixture() + tx.TransactionBody = tbody + + coll := flow.CollectionFromTransactions([]*flow.Transaction{&tx}) + + suite.transactions. + On("ByID", tx.ID()). + Return(nil, fmt.Errorf("some other error")) + + suite.blocks. + On("ByID", block.ID()). + Return(&block, nil). + Once() + + suite.communicator.On("CallAvailableNode", + mock.Anything, + mock.Anything, + mock.Anything). + Return(nil) + + receipt := unittest.ExecutionReceiptFixture() + identity := unittest.IdentityFixture() + identity.Role = flow.RoleExecution + + suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() + + l := flow.ExecutionReceiptList{receipt} + + suite.receipts. + On("ByBlockID", block.ID()). + Return(l, nil) + + backend := NewBackend( + suite.state, + suite.colClient, + nil, + suite.blocks, + nil, + nil, + suite.transactions, + suite.receipts, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + suite.communicator, + ) + _, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) + suite.Require().Equal(err, status.Errorf(codes.Internal, "failed to find: %v", fmt.Errorf("some other error"))) + }) + +} + +func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResult() { + + identities := unittest.CompleteIdentitySet() + rootSnapshot := unittest.RootSnapshotFixture(identities) + util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { + epochBuilder := unittest.NewEpochBuilder(suite.T(), state) + + // building 2 epochs allows us to take a snapshot at a point in time where + // an epoch transition happens + epochBuilder. + BuildEpoch(). + CompleteEpoch() + + epochBuilder. + BuildEpoch(). + CompleteEpoch() + + // get heights of each phase in built epochs + epoch1, ok := epochBuilder.EpochHeights(1) + require.True(suite.T(), ok) + epoch2, ok := epochBuilder.EpochHeights(2) + require.True(suite.T(), ok) + + // setup AtHeight mock returns for state + for _, height := range append(epoch1.Range(), epoch2.Range()...) { + suite.state.On("AtHeight", height).Return(state.AtHeight(height)) + } + + // Take snapshot at height of the first block of epoch2, the sealing segment of this snapshot + // will have contain block spanning an epoch transition as well as an epoch phase transition. + // This will cause our GetLatestProtocolStateSnapshot func to return a snapshot + // at block with height 3, the first block of the staking phase of epoch1. + + snap := state.AtHeight(epoch2.Range()[0]) + suite.state.On("Final").Return(snap).Once() + + block := unittest.BlockFixture() + tbody := unittest.TransactionBodyFixture() + tx := unittest.TransactionFixture() + tx.TransactionBody = tbody + + coll := flow.CollectionFromTransactions([]*flow.Transaction{&tx}) + + suite.transactions. + On("ByID", tx.ID()). + Return(nil, storage.ErrNotFound) + + suite.blocks. + On("ByID", block.ID()). + Return(&block, nil). + Once() + + suite.communicator.On("CallAvailableNode", + mock.Anything, + mock.Anything, + mock.Anything). + Return(nil) + + receipt := unittest.ExecutionReceiptFixture() + identity := unittest.IdentityFixture() + identity.Role = flow.RoleExecution + + suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() + + l := flow.ExecutionReceiptList{receipt} + + transactionResultResponse := access.TransactionResultResponse{ + Status: entities.TransactionStatus_EXECUTED, + StatusCode: uint32(entities.TransactionStatus_EXECUTED), + } + + suite.receipts. + On("ByBlockID", block.ID()). + Return(l, nil) + + suite.historicalAccessClient. + On("GetTransactionResult", mock.Anything, mock.Anything). + Return(&transactionResultResponse, nil) + + backend := NewBackend( + suite.state, + suite.colClient, + []access.AccessAPIClient{suite.historicalAccessClient}, + suite.blocks, + nil, + nil, + suite.transactions, + suite.receipts, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + suite.communicator, + ) + resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) + suite.Require().NoError(err) + suite.Require().Equal(flow.TransactionStatusExecuted, resp.Status) + suite.Require().Equal(uint(flow.TransactionStatusExecuted), resp.StatusCode) + }) +} From 3d23bcf3300eed0b96b22f55a9783c84f1924ed2 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Thu, 3 Aug 2023 12:00:51 +0100 Subject: [PATCH 02/66] 4585: Add mock file generation for NodeCommunicator --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d8b37127d1d..b09174f2dee 100644 --- a/Makefile +++ b/Makefile @@ -93,7 +93,7 @@ go-math-rand-check: # `exclude` should only specify non production code (test, bench..). # If this check fails, try updating your code by using: # - "crypto/rand" or "flow-go/utils/rand" for non-deterministic randomness - # - "flow-go/crypto/random" for deterministic randomness + # - "flow-go/crypto/random" for deterministic randomness grep --include=\*.go \ --exclude=*test* --exclude=*helper* --exclude=*example* --exclude=*fixture* --exclude=*benchmark* --exclude=*profiler* \ --exclude-dir=*test* --exclude-dir=*helper* --exclude-dir=*example* --exclude-dir=*fixture* --exclude-dir=*benchmark* --exclude-dir=*profiler* -rnw '"math/rand"'; \ @@ -194,6 +194,8 @@ generate-mocks: install-mock-generators mockery --name 'API' --dir="./engine/protocol" --case=underscore --output="./engine/protocol/mock" --outpkg="mock" mockery --name '.*' --dir="./engine/access/state_stream" --case=underscore --output="./engine/access/state_stream/mock" --outpkg="mock" mockery --name 'ConnectionFactory' --dir="./engine/access/rpc/connection" --case=underscore --output="./engine/access/rpc/connection/mock" --outpkg="mock" + mockery --name 'Communicator' --structname 'NodeCommunicatorMock' --dir="./engine/access/rpc/backend" --case=underscore --output="./engine/access/rpc/backend" --inpackage + mockery --name '.*' --dir=model/fingerprint --case=underscore --output="./model/fingerprint/mock" --outpkg="mock" mockery --name 'ExecForkActor' --structname 'ExecForkActorMock' --dir=module/mempool/consensus/mock/ --case=underscore --output="./module/mempool/consensus/mock/" --outpkg="mock" mockery --name '.*' --dir=engine/verification/fetcher/ --case=underscore --output="./engine/verification/fetcher/mock" --outpkg="mockfetcher" From f018aca1c2d726305cfd9ee91a9206858c18eb0a Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Thu, 3 Aug 2023 12:04:20 +0100 Subject: [PATCH 03/66] 4585: Add simple lru caching for transaction results and refactor it's tests --- .../rpc/backend/backend_transactions.go | 29 ++-- .../rpc/backend/backend_transactions_test.go | 160 ++++++++++-------- 2 files changed, 104 insertions(+), 85 deletions(-) diff --git a/engine/access/rpc/backend/backend_transactions.go b/engine/access/rpc/backend/backend_transactions.go index b3debaaac27..39f3454927d 100644 --- a/engine/access/rpc/backend/backend_transactions.go +++ b/engine/access/rpc/backend/backend_transactions.go @@ -6,13 +6,7 @@ import ( "fmt" "time" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - + lru2 "github.com/hashicorp/golang-lru/v2" "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" @@ -22,10 +16,14 @@ import ( "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) - - type backendTransactions struct { staticCollectionRPC accessproto.AccessAPIClient // rpc client tied to a fixed collection node transactions storage.Transactions @@ -42,6 +40,7 @@ type backendTransactions struct { previousAccessNodes []accessproto.AccessAPIClient log zerolog.Logger nodeCommunicator Communicator + txResultCache *lru2.Cache[flow.Identifier, *access.TransactionResult] } // SendTransaction forwards the transaction to the collection node @@ -232,12 +231,16 @@ func (b *backendTransactions) GetTransactionResult( // look up transaction from storage start := time.Now() - tx, err := b.transactions.ByID(txID) + tx, err := b.transactions.ByID(txID) if err != nil { txErr := rpc.ConvertStorageError(err) if status.Code(txErr) == codes.NotFound { // Tx not found. If we have historical Sporks setup, lets look through those as well + val, ok := b.txResultCache.Get(txID) + if ok { + return val, nil + } historicalTxResult, err := b.getHistoricalTransactionResult(ctx, txID) if err != nil { // if tx not found in old access nodes either, then assume that the tx was submitted to a different AN @@ -248,6 +251,8 @@ func (b *backendTransactions) GetTransactionResult( StatusCode: uint(txStatus), }, nil } + + b.txResultCache.Add(txID, historicalTxResult) return historicalTxResult, nil } return nil, txErr @@ -343,8 +348,8 @@ func (b *backendTransactions) lookupCollectionIDInBlock( // followed by the collection ID lookup. If both are missing, the default lookup by transaction ID is performed. func (b *backendTransactions) retrieveBlock( - // the requested block or collection was not found. If looking up the block based solely on the txID returns - // not found, then no error is returned. +// the requested block or collection was not found. If looking up the block based solely on the txID returns +// not found, then no error is returned. blockID flow.Identifier, collectionID flow.Identifier, txID flow.Identifier, diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index d6d73e6363c..c8032ff36fe 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -7,6 +7,7 @@ import ( "github.com/dgraph-io/badger/v2" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" + "github.com/onflow/flow-go/state/protocol" bprotocol "github.com/onflow/flow-go/state/protocol/badger" "github.com/onflow/flow-go/state/protocol/util" "github.com/onflow/flow-go/storage" @@ -19,8 +20,7 @@ import ( "google.golang.org/grpc/status" ) -func (suite *Suite) TestGetTransactionResultReturnsUnknown() { - +func (suite *Suite) WithPreConfiguredState(f func(snap protocol.Snapshot)) { identities := unittest.CompleteIdentitySet() rootSnapshot := unittest.RootSnapshotFixture(identities) util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { @@ -47,12 +47,20 @@ func (suite *Suite) TestGetTransactionResultReturnsUnknown() { mock.Anything). Return(nil) + f(snap) + }) + +} + +func (suite *Suite) TestGetTransactionResultReturnsUnknown() { + suite.WithPreConfiguredState(func(snap protocol.Snapshot) { block := unittest.BlockFixture() tbody := unittest.TransactionBodyFixture() tx := unittest.TransactionFixture() tx.TransactionBody = tbody coll := flow.CollectionFromTransactions([]*flow.Transaction{&tx}) + suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() suite.transactions. On("ByID", tx.ID()). @@ -67,8 +75,6 @@ func (suite *Suite) TestGetTransactionResultReturnsUnknown() { identity := unittest.IdentityFixture() identity.Role = flow.RoleExecution - suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() - l := flow.ExecutionReceiptList{receipt} suite.receipts. @@ -104,41 +110,7 @@ func (suite *Suite) TestGetTransactionResultReturnsUnknown() { } func (suite *Suite) TestGetTransactionResultReturnsTransactionError() { - - identities := unittest.CompleteIdentitySet() - rootSnapshot := unittest.RootSnapshotFixture(identities) - util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { - epochBuilder := unittest.NewEpochBuilder(suite.T(), state) - - // building 2 epochs allows us to take a snapshot at a point in time where - // an epoch transition happens - epochBuilder. - BuildEpoch(). - CompleteEpoch() - - epochBuilder. - BuildEpoch(). - CompleteEpoch() - - // get heights of each phase in built epochs - epoch1, ok := epochBuilder.EpochHeights(1) - require.True(suite.T(), ok) - epoch2, ok := epochBuilder.EpochHeights(2) - require.True(suite.T(), ok) - - // setup AtHeight mock returns for state - for _, height := range append(epoch1.Range(), epoch2.Range()...) { - suite.state.On("AtHeight", height).Return(state.AtHeight(height)) - } - - // Take snapshot at height of the first block of epoch2, the sealing segment of this snapshot - // will have contain block spanning an epoch transition as well as an epoch phase transition. - // This will cause our GetLatestProtocolStateSnapshot func to return a snapshot - // at block with height 3, the first block of the staking phase of epoch1. - - snap := state.AtHeight(epoch2.Range()[0]) - suite.state.On("Final").Return(snap).Once() - + suite.WithPreConfiguredState(func(snap protocol.Snapshot) { block := unittest.BlockFixture() tbody := unittest.TransactionBodyFixture() tx := unittest.TransactionFixture() @@ -155,12 +127,6 @@ func (suite *Suite) TestGetTransactionResultReturnsTransactionError() { Return(&block, nil). Once() - suite.communicator.On("CallAvailableNode", - mock.Anything, - mock.Anything, - mock.Anything). - Return(nil) - receipt := unittest.ExecutionReceiptFixture() identity := unittest.IdentityFixture() identity.Role = flow.RoleExecution @@ -197,46 +163,86 @@ func (suite *Suite) TestGetTransactionResultReturnsTransactionError() { ) _, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) suite.Require().Equal(err, status.Errorf(codes.Internal, "failed to find: %v", fmt.Errorf("some other error"))) - }) + }) } func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResult() { + suite.WithPreConfiguredState(func(snap protocol.Snapshot) { + block := unittest.BlockFixture() + tbody := unittest.TransactionBodyFixture() + tx := unittest.TransactionFixture() + tx.TransactionBody = tbody - identities := unittest.CompleteIdentitySet() - rootSnapshot := unittest.RootSnapshotFixture(identities) - util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { - epochBuilder := unittest.NewEpochBuilder(suite.T(), state) + coll := flow.CollectionFromTransactions([]*flow.Transaction{&tx}) - // building 2 epochs allows us to take a snapshot at a point in time where - // an epoch transition happens - epochBuilder. - BuildEpoch(). - CompleteEpoch() + suite.transactions. + On("ByID", tx.ID()). + Return(nil, storage.ErrNotFound) - epochBuilder. - BuildEpoch(). - CompleteEpoch() + suite.blocks. + On("ByID", block.ID()). + Return(&block, nil). + Once() - // get heights of each phase in built epochs - epoch1, ok := epochBuilder.EpochHeights(1) - require.True(suite.T(), ok) - epoch2, ok := epochBuilder.EpochHeights(2) - require.True(suite.T(), ok) + suite.communicator.On("CallAvailableNode", + mock.Anything, + mock.Anything, + mock.Anything). + Return(nil) - // setup AtHeight mock returns for state - for _, height := range append(epoch1.Range(), epoch2.Range()...) { - suite.state.On("AtHeight", height).Return(state.AtHeight(height)) + receipt := unittest.ExecutionReceiptFixture() + identity := unittest.IdentityFixture() + identity.Role = flow.RoleExecution + + suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() + + l := flow.ExecutionReceiptList{receipt} + + transactionResultResponse := access.TransactionResultResponse{ + Status: entities.TransactionStatus_EXECUTED, + StatusCode: uint32(entities.TransactionStatus_EXECUTED), } - // Take snapshot at height of the first block of epoch2, the sealing segment of this snapshot - // will have contain block spanning an epoch transition as well as an epoch phase transition. - // This will cause our GetLatestProtocolStateSnapshot func to return a snapshot - // at block with height 3, the first block of the staking phase of epoch1. + suite.receipts. + On("ByBlockID", block.ID()). + Return(l, nil) - snap := state.AtHeight(epoch2.Range()[0]) - suite.state.On("Final").Return(snap).Once() + suite.historicalAccessClient. + On("GetTransactionResult", mock.Anything, mock.Anything). + Return(&transactionResultResponse, nil) + backend := NewBackend( + suite.state, + suite.colClient, + []access.AccessAPIClient{suite.historicalAccessClient}, + suite.blocks, + nil, + nil, + suite.transactions, + suite.receipts, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + suite.communicator, + ) + resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) + suite.Require().NoError(err) + suite.Require().Equal(flow.TransactionStatusExecuted, resp.Status) + suite.Require().Equal(uint(flow.TransactionStatusExecuted), resp.StatusCode) + }) +} + +func (suite *Suite) TestGetTransactionResultFromCache() { + suite.WithPreConfiguredState(func(snap protocol.Snapshot) { block := unittest.BlockFixture() tbody := unittest.TransactionBodyFixture() tx := unittest.TransactionFixture() @@ -278,7 +284,7 @@ func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResult() { suite.historicalAccessClient. On("GetTransactionResult", mock.Anything, mock.Anything). - Return(&transactionResultResponse, nil) + Return(&transactionResultResponse, nil).Once() backend := NewBackend( suite.state, @@ -302,9 +308,17 @@ func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResult() { nil, suite.communicator, ) + resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) suite.Require().NoError(err) suite.Require().Equal(flow.TransactionStatusExecuted, resp.Status) suite.Require().Equal(uint(flow.TransactionStatusExecuted), resp.StatusCode) + + resp2, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) + suite.Require().NoError(err) + suite.Require().Equal(flow.TransactionStatusExecuted, resp2.Status) + suite.Require().Equal(uint(flow.TransactionStatusExecuted), resp2.StatusCode) + + suite.historicalAccessClient.AssertExpectations(suite.T()) }) } From 8dd08dbc39159e49bc8035436fbea245f5eae73f Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Thu, 3 Aug 2023 12:06:27 +0100 Subject: [PATCH 04/66] 4585: Ignore mock file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1be2e18a99f..024b0d9417e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ /cmd/testclient/testclient /cmd/util/util /cmd/bootstrap/bootstrap +/engine/access/rpc/backend/mock_communicator.go # crypto relic folder crypto/relic/ From b3865c444b651bf15c9cd95b15425ff5c48ec0ed Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Thu, 3 Aug 2023 12:15:00 +0100 Subject: [PATCH 05/66] 4585: Fix goimport issues --- engine/access/rpc/backend/backend.go | 9 +++++---- engine/access/rpc/backend/backend_test.go | 19 +++++++++---------- .../rpc/backend/backend_transactions.go | 19 ++++++++++--------- .../rpc/backend/backend_transactions_test.go | 13 +++++++------ 4 files changed, 31 insertions(+), 29 deletions(-) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 52ec7fe286b..eea7c8fdbf6 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -9,6 +9,11 @@ import ( lru "github.com/hashicorp/golang-lru" lru2 "github.com/hashicorp/golang-lru/v2" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/cmd/build" "github.com/onflow/flow-go/engine/access/rpc/connection" @@ -20,10 +25,6 @@ import ( "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" "github.com/onflow/flow-go/storage/badger" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) // minExecutionNodesCnt is the minimum number of execution nodes expected to have sent the execution receipt for a block diff --git a/engine/access/rpc/backend/backend_test.go b/engine/access/rpc/backend/backend_test.go index 83fb3020c04..48d658a899a 100644 --- a/engine/access/rpc/backend/backend_test.go +++ b/engine/access/rpc/backend/backend_test.go @@ -40,23 +40,22 @@ type Suite struct { snapshot *protocol.Snapshot log zerolog.Logger - blocks *storagemock.Blocks - headers *storagemock.Headers - collections *storagemock.Collections - transactions *storagemock.Transactions - receipts *storagemock.ExecutionReceipts - results *storagemock.ExecutionResults - + blocks *storagemock.Blocks + headers *storagemock.Headers + collections *storagemock.Collections + transactions *storagemock.Transactions + receipts *storagemock.ExecutionReceipts + results *storagemock.ExecutionResults colClient *access.AccessAPIClient execClient *access.ExecutionAPIClient historicalAccessClient *access.AccessAPIClient archiveClient *access.AccessAPIClient - connectionFactory *backendmock.ConnectionFactory - communicator *NodeCommunicatorMock + connectionFactory *backendmock.ConnectionFactory + communicator *NodeCommunicatorMock - chainID flow.ChainID + chainID flow.ChainID } func TestHandler(t *testing.T) { diff --git a/engine/access/rpc/backend/backend_transactions.go b/engine/access/rpc/backend/backend_transactions.go index 39f3454927d..d5fed8f04d6 100644 --- a/engine/access/rpc/backend/backend_transactions.go +++ b/engine/access/rpc/backend/backend_transactions.go @@ -7,6 +7,13 @@ import ( "time" lru2 "github.com/hashicorp/golang-lru/v2" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" @@ -16,12 +23,6 @@ import ( "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) type backendTransactions struct { @@ -251,7 +252,7 @@ func (b *backendTransactions) GetTransactionResult( StatusCode: uint(txStatus), }, nil } - + b.txResultCache.Add(txID, historicalTxResult) return historicalTxResult, nil } @@ -348,8 +349,8 @@ func (b *backendTransactions) lookupCollectionIDInBlock( // followed by the collection ID lookup. If both are missing, the default lookup by transaction ID is performed. func (b *backendTransactions) retrieveBlock( -// the requested block or collection was not found. If looking up the block based solely on the txID returns -// not found, then no error is returned. + // the requested block or collection was not found. If looking up the block based solely on the txID returns + // not found, then no error is returned. blockID flow.Identifier, collectionID flow.Identifier, txID flow.Identifier, diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index c8032ff36fe..c8c3b8496f3 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -5,6 +5,13 @@ import ( "fmt" "github.com/dgraph-io/badger/v2" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" "github.com/onflow/flow-go/state/protocol" @@ -12,12 +19,6 @@ import ( "github.com/onflow/flow-go/state/protocol/util" "github.com/onflow/flow-go/storage" "github.com/onflow/flow-go/utils/unittest" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) func (suite *Suite) WithPreConfiguredState(f func(snap protocol.Snapshot)) { From d3a514503c42195df6278171424866c0b03e23ad Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sat, 5 Aug 2023 13:46:33 +0100 Subject: [PATCH 06/66] Refactor backend constructor, replace old --- .../node_builder/access_node_builder.go | 9 +- cmd/observer/node_builder/observer_builder.go | 2 +- engine/access/access_test.go | 10 +- .../integration_unsecure_grpc_server_test.go | 9 +- engine/access/rest_api_test.go | 10 +- engine/access/rpc/backend/backend.go | 141 +----------------- engine/access/rpc/backend/backend_test.go | 67 ++++----- .../rpc/backend/backend_transactions_test.go | 8 +- .../rpc/backend/historical_access_test.go | 9 +- engine/access/rpc/backend/retry_test.go | 9 +- engine/access/rpc/rate_limit_test.go | 5 +- engine/access/secure_grpcr_test.go | 5 +- .../mock/get_execution_data_func.go | 3 +- .../mock/get_start_height_func.go | 3 +- 14 files changed, 72 insertions(+), 218 deletions(-) diff --git a/cmd/access/node_builder/access_node_builder.go b/cmd/access/node_builder/access_node_builder.go index f083aaed0fd..9bb8472ce71 100644 --- a/cmd/access/node_builder/access_node_builder.go +++ b/cmd/access/node_builder/access_node_builder.go @@ -12,15 +12,14 @@ import ( badger "github.com/ipfs/go-ds-badger2" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/routing" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/go-bitswap" "github.com/rs/zerolog" "github.com/spf13/pflag" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/go-bitswap" - "github.com/onflow/flow-go/admin/commands" stateSyncCommands "github.com/onflow/flow-go/admin/commands/state_synchronization" storageCommands "github.com/onflow/flow-go/admin/commands/storage" @@ -1088,7 +1087,6 @@ func (builder *FlowAccessNodeBuilder) Build() (cmd.Node, error) { backendConfig.CircuitBreakerConfig, ), } - backend := backend.New( node.State, builder.CollectionRPC, @@ -1109,7 +1107,8 @@ func (builder *FlowAccessNodeBuilder) Build() (cmd.Node, error) { node.Logger, backend.DefaultSnapshotHistoryLimit, backendConfig.ArchiveAddressList, - backendConfig.CircuitBreakerConfig.Enabled) + backend.NewNodeCommunicator(backendConfig.CircuitBreakerConfig.Enabled), + ) engineBuilder, err := rpc.NewBuilder( node.Logger, diff --git a/cmd/observer/node_builder/observer_builder.go b/cmd/observer/node_builder/observer_builder.go index 1e7687578c2..78208d09656 100644 --- a/cmd/observer/node_builder/observer_builder.go +++ b/cmd/observer/node_builder/observer_builder.go @@ -946,7 +946,7 @@ func (builder *ObserverServiceBuilder) enqueueRPCServer() { node.Logger, backend.DefaultSnapshotHistoryLimit, backendConfig.ArchiveAddressList, - backendConfig.CircuitBreakerConfig.Enabled) + backend.NewNodeCommunicator(backendConfig.CircuitBreakerConfig.Enabled)) observerCollector := metrics.NewObserverCollector() restHandler, err := restapiproxy.NewRestProxyHandler( diff --git a/engine/access/access_test.go b/engine/access/access_test.go index b3979979fb9..f4d3e7c0d18 100644 --- a/engine/access/access_test.go +++ b/engine/access/access_test.go @@ -157,7 +157,7 @@ func (suite *Suite) RunTest( suite.log, backend.DefaultSnapshotHistoryLimit, nil, - false, + backend.NewNodeCommunicator(false), ) handler := access.NewHandler(suite.backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me, access.WithBlockSignerDecoder(suite.signerIndicesDecoder)) f(handler, db, all) @@ -330,7 +330,7 @@ func (suite *Suite) TestSendTransactionToRandomCollectionNode() { suite.log, backend.DefaultSnapshotHistoryLimit, nil, - false, + backend.NewNodeCommunicator(false), ) handler := access.NewHandler(backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) @@ -657,7 +657,7 @@ func (suite *Suite) TestGetSealedTransaction() { suite.log, backend.DefaultSnapshotHistoryLimit, nil, - false, + backend.NewNodeCommunicator(false), ) handler := access.NewHandler(backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) @@ -797,7 +797,7 @@ func (suite *Suite) TestGetTransactionResult() { suite.log, backend.DefaultSnapshotHistoryLimit, nil, - false, + backend.NewNodeCommunicator(false), ) handler := access.NewHandler(backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) @@ -989,7 +989,7 @@ func (suite *Suite) TestExecuteScript() { suite.log, backend.DefaultSnapshotHistoryLimit, nil, - false, + backend.NewNodeCommunicator(false), ) handler := access.NewHandler(suite.backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) diff --git a/engine/access/integration_unsecure_grpc_server_test.go b/engine/access/integration_unsecure_grpc_server_test.go index e2cf78ade5a..46aba64c76f 100644 --- a/engine/access/integration_unsecure_grpc_server_test.go +++ b/engine/access/integration_unsecure_grpc_server_test.go @@ -2,17 +2,17 @@ package access import ( "context" - "io" "os" "testing" "time" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + executiondataproto "github.com/onflow/flow/protobuf/go/flow/executiondata" "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" - "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" @@ -37,9 +37,6 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" - - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - executiondataproto "github.com/onflow/flow/protobuf/go/flow/executiondata" ) // SameGRPCPortTestSuite verifies both AccessAPI and ExecutionDataAPI client continue to work when configured @@ -189,7 +186,7 @@ func (suite *SameGRPCPortTestSuite) SetupTest() { suite.log, 0, nil, - false) + backend.NewNodeCommunicator(false)) // create rpc engine builder rpcEngBuilder, err := rpc.NewBuilder( diff --git a/engine/access/rest_api_test.go b/engine/access/rest_api_test.go index 091c5e2e3ad..1e4388b5a32 100644 --- a/engine/access/rest_api_test.go +++ b/engine/access/rest_api_test.go @@ -10,11 +10,6 @@ import ( "testing" "time" - "google.golang.org/grpc/credentials" - - "github.com/onflow/flow-go/module/grpcserver" - "github.com/onflow/flow-go/utils/grpcutils" - "github.com/antihax/optional" restclient "github.com/onflow/flow/openapi/go-client-generated" "github.com/rs/zerolog" @@ -22,6 +17,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "google.golang.org/grpc/credentials" accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rest/request" @@ -29,6 +25,7 @@ import ( "github.com/onflow/flow-go/engine/access/rpc" "github.com/onflow/flow-go/engine/access/rpc/backend" "github.com/onflow/flow-go/model/flow" + "github.com/onflow/flow-go/module/grpcserver" "github.com/onflow/flow-go/module/irrecoverable" "github.com/onflow/flow-go/module/metrics" module "github.com/onflow/flow-go/module/mock" @@ -36,6 +33,7 @@ import ( protocol "github.com/onflow/flow-go/state/protocol/mock" "github.com/onflow/flow-go/storage" storagemock "github.com/onflow/flow-go/storage/mock" + "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" ) @@ -170,7 +168,7 @@ func (suite *RestAPITestSuite) SetupTest() { suite.log, 0, nil, - false) + backend.NewNodeCommunicator(false)) rpcEngBuilder, err := rpc.NewBuilder( suite.log, diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index eea7c8fdbf6..998fb877e3c 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -100,9 +100,9 @@ type Communicator interface { ) error } -// NewBackend creates backend accepting Communicator interfaces instead of circuitBreakerEnabled flag +// New creates backend accepting Communicator interfaces instead of circuitBreakerEnabled flag // More convenient fur unit testing scenarios when you need to pass test NodeCommunicator objects. -func NewBackend(state protocol.State, +func New(state protocol.State, collectionRPC accessproto.AccessAPIClient, historicalAccessNodes []accessproto.AccessAPIClient, blocks storage.Blocks, @@ -232,143 +232,6 @@ func NewBackend(state protocol.State, return b } -// New create new backend instance -// Deprecated: Use NewBackend for enhanced testability -func New( - state protocol.State, - collectionRPC accessproto.AccessAPIClient, - historicalAccessNodes []accessproto.AccessAPIClient, - blocks storage.Blocks, - headers storage.Headers, - collections storage.Collections, - transactions storage.Transactions, - executionReceipts storage.ExecutionReceipts, - executionResults storage.ExecutionResults, - chainID flow.ChainID, - accessMetrics module.AccessMetrics, - connFactory connection.ConnectionFactory, - retryEnabled bool, - maxHeightRange uint, - preferredExecutionNodeIDs []string, - fixedExecutionNodeIDs []string, - log zerolog.Logger, - snapshotHistoryLimit int, - archiveAddressList []string, - circuitBreakerEnabled bool, -) *Backend { - retry := newRetry() - if retryEnabled { - retry.Activate() - } - - loggedScripts, err := lru.New(DefaultLoggedScriptsCacheSize) - if err != nil { - log.Fatal().Err(err).Msg("failed to initialize script logging cache") - } - - archivePorts := make([]uint, len(archiveAddressList)) - for idx, addr := range archiveAddressList { - port, err := findPortFromAddress(addr) - if err != nil { - log.Fatal().Err(err).Msg("failed to find archive node port") - } - archivePorts[idx] = port - } - - // create node communicator, that will be used in sub-backend logic for interacting with API calls - nodeCommunicator := NewNodeCommunicator(circuitBreakerEnabled) - - txResCache, err := lru2.New[flow.Identifier, *access.TransactionResult](int(badger.DefaultCacheSize)) - if err != nil { - log.Fatal().Err(err).Msg("failed to init cache for transaction results") - } - - b := &Backend{ - state: state, - // create the sub-backends - backendScripts: backendScripts{ - headers: headers, - executionReceipts: executionReceipts, - connFactory: connFactory, - state: state, - log: log, - metrics: accessMetrics, - loggedScripts: loggedScripts, - archiveAddressList: archiveAddressList, - archivePorts: archivePorts, - nodeCommunicator: nodeCommunicator, - }, - backendTransactions: backendTransactions{ - staticCollectionRPC: collectionRPC, - state: state, - chainID: chainID, - collections: collections, - blocks: blocks, - transactions: transactions, - executionReceipts: executionReceipts, - transactionValidator: configureTransactionValidator(state, chainID), - transactionMetrics: accessMetrics, - retry: retry, - connFactory: connFactory, - previousAccessNodes: historicalAccessNodes, - log: log, - nodeCommunicator: nodeCommunicator, - txResultCache: txResCache, - }, - backendEvents: backendEvents{ - state: state, - headers: headers, - executionReceipts: executionReceipts, - connFactory: connFactory, - log: log, - maxHeightRange: maxHeightRange, - nodeCommunicator: nodeCommunicator, - }, - backendBlockHeaders: backendBlockHeaders{ - headers: headers, - state: state, - }, - backendBlockDetails: backendBlockDetails{ - blocks: blocks, - state: state, - }, - backendAccounts: backendAccounts{ - state: state, - headers: headers, - executionReceipts: executionReceipts, - connFactory: connFactory, - log: log, - nodeCommunicator: nodeCommunicator, - }, - backendExecutionResults: backendExecutionResults{ - executionResults: executionResults, - }, - backendNetwork: backendNetwork{ - state: state, - chainID: chainID, - snapshotHistoryLimit: snapshotHistoryLimit, - }, - collections: collections, - executionReceipts: executionReceipts, - connFactory: connFactory, - chainID: chainID, - } - - retry.SetBackend(b) - - preferredENIdentifiers, err = identifierList(preferredExecutionNodeIDs) - if err != nil { - log.Fatal().Err(err).Msg("failed to convert node id string to Flow Identifier for preferred EN map") - } - - fixedENIdentifiers, err = identifierList(fixedExecutionNodeIDs) - if err != nil { - log.Fatal().Err(err).Msg("failed to convert node id string to Flow Identifier for fixed EN map") - } - - return b -} - //TODO: refactor cache, replace with generic lru.Cache alternative // NewCache constructs cache for storing connections to other nodes. diff --git a/engine/access/rpc/backend/backend_test.go b/engine/access/rpc/backend/backend_test.go index 48d658a899a..cc99138864e 100644 --- a/engine/access/rpc/backend/backend_test.go +++ b/engine/access/rpc/backend/backend_test.go @@ -6,8 +6,6 @@ import ( "strconv" "testing" - "github.com/onflow/flow-go/engine/access/rpc/connection" - "github.com/dgraph-io/badger/v2" accessproto "github.com/onflow/flow/protobuf/go/flow/access" entitiesproto "github.com/onflow/flow/protobuf/go/flow/entities" @@ -22,6 +20,7 @@ import ( access "github.com/onflow/flow-go/engine/access/mock" backendmock "github.com/onflow/flow-go/engine/access/rpc/backend/mock" + "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc/convert" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" @@ -116,7 +115,7 @@ func (suite *Suite) TestPing() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) err := backend.Ping(context.Background()) @@ -152,7 +151,7 @@ func (suite *Suite) TestGetLatestFinalizedBlockHeader() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // query the handler for the latest finalized block @@ -218,7 +217,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_NoTransitionSpan() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // query the handler for the latest finalized snapshot @@ -291,7 +290,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_TransitionSpans() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // query the handler for the latest finalized snapshot @@ -357,7 +356,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // query the handler for the latest finalized snapshot @@ -434,7 +433,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_EpochTransitionSpan() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // query the handler for the latest finalized snapshot @@ -495,7 +494,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_HistoryLimit() { suite.log, snapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // the handler should return a snapshot history limit error @@ -534,7 +533,7 @@ func (suite *Suite) TestGetLatestSealedBlockHeader() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // query the handler for the latest sealed block @@ -581,7 +580,7 @@ func (suite *Suite) TestGetTransaction() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) actual, err := backend.GetTransaction(context.Background(), transaction.ID()) @@ -622,7 +621,7 @@ func (suite *Suite) TestGetCollection() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) actual, err := backend.GetCollectionByID(context.Background(), expected.ID()) @@ -686,7 +685,7 @@ func (suite *Suite) TestGetTransactionResultByIndex() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) suite.execClient. On("GetTransactionResultByIndex", ctx, exeEventReq). @@ -750,7 +749,7 @@ func (suite *Suite) TestGetTransactionResultsByBlockID() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) suite.execClient. On("GetTransactionResultsByBlockID", ctx, exeEventReq). @@ -842,7 +841,7 @@ func (suite *Suite) TestTransactionStatusTransition() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // Successfully return empty event list @@ -963,7 +962,7 @@ func (suite *Suite) TestTransactionExpiredStatusTransition() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // should return pending status when we have not observed an expiry block @@ -1131,7 +1130,7 @@ func (suite *Suite) TestTransactionPendingToFinalizedStatusTransition() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) preferredENIdentifiers = flow.IdentifierList{receipts[0].ExecutorID} @@ -1190,7 +1189,7 @@ func (suite *Suite) TestTransactionResultUnknown() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // first call - when block under test is greater height than the sealed head, but execution node does not know about Tx @@ -1245,7 +1244,7 @@ func (suite *Suite) TestGetLatestFinalizedBlock() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // query the handler for the latest finalized header @@ -1376,7 +1375,7 @@ func (suite *Suite) TestGetEventsForBlockIDs() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // execute request @@ -1409,7 +1408,7 @@ func (suite *Suite) TestGetEventsForBlockIDs() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // execute request with an empty block id list and expect an empty list of events and no error @@ -1469,7 +1468,7 @@ func (suite *Suite) TestGetExecutionResultByID() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // execute request @@ -1500,7 +1499,7 @@ func (suite *Suite) TestGetExecutionResultByID() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // execute request @@ -1564,7 +1563,7 @@ func (suite *Suite) TestGetExecutionResultByBlockID() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // execute request @@ -1747,7 +1746,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) _, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), maxHeight, minHeight) @@ -1787,7 +1786,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // execute request @@ -1826,7 +1825,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) actualResp, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), minHeight, maxHeight) @@ -1864,7 +1863,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) _, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), minHeight, minHeight+1) @@ -1902,7 +1901,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) _, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), minHeight, maxHeight) @@ -1980,7 +1979,7 @@ func (suite *Suite) TestGetAccount() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) preferredENIdentifiers = flow.IdentifierList{receipts[0].ExecutorID} @@ -2062,7 +2061,7 @@ func (suite *Suite) TestGetAccountAtBlockHeight() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) preferredENIdentifiers = flow.IdentifierList{receipts[0].ExecutorID} @@ -2102,7 +2101,7 @@ func (suite *Suite) TestGetNetworkParameters() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) params := backend.GetNetworkParameters(context.Background()) @@ -2305,7 +2304,7 @@ func (suite *Suite) TestExecuteScriptOnExecutionNode() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // mock parameters @@ -2382,7 +2381,7 @@ func (suite *Suite) TestExecuteScriptOnArchiveNode() { suite.log, DefaultSnapshotHistoryLimit, []string{fullArchiveAddress}, - false, + NewNodeCommunicator(false), ) // mock parameters diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index c8c3b8496f3..b1ccf656eeb 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -82,7 +82,7 @@ func (suite *Suite) TestGetTransactionResultReturnsUnknown() { On("ByBlockID", block.ID()). Return(l, nil) - backend := NewBackend( + backend := New( suite.state, suite.colClient, nil, @@ -140,7 +140,7 @@ func (suite *Suite) TestGetTransactionResultReturnsTransactionError() { On("ByBlockID", block.ID()). Return(l, nil) - backend := NewBackend( + backend := New( suite.state, suite.colClient, nil, @@ -213,7 +213,7 @@ func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResult() { On("GetTransactionResult", mock.Anything, mock.Anything). Return(&transactionResultResponse, nil) - backend := NewBackend( + backend := New( suite.state, suite.colClient, []access.AccessAPIClient{suite.historicalAccessClient}, @@ -287,7 +287,7 @@ func (suite *Suite) TestGetTransactionResultFromCache() { On("GetTransactionResult", mock.Anything, mock.Anything). Return(&transactionResultResponse, nil).Once() - backend := NewBackend( + backend := New( suite.state, suite.colClient, []access.AccessAPIClient{suite.historicalAccessClient}, diff --git a/engine/access/rpc/backend/historical_access_test.go b/engine/access/rpc/backend/historical_access_test.go index 42dd829dbbc..42f26e72ffb 100644 --- a/engine/access/rpc/backend/historical_access_test.go +++ b/engine/access/rpc/backend/historical_access_test.go @@ -3,11 +3,10 @@ package backend import ( "context" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" "github.com/onflow/flow/protobuf/go/flow/entities" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "github.com/onflow/flow-go/engine/common/rpc/convert" "github.com/onflow/flow-go/model/flow" @@ -56,7 +55,7 @@ func (suite *Suite) TestHistoricalTransactionResult() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // Successfully return the transaction from the historical node @@ -115,7 +114,7 @@ func (suite *Suite) TestHistoricalTransaction() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) // Successfully return the transaction from the historical node diff --git a/engine/access/rpc/backend/retry_test.go b/engine/access/rpc/backend/retry_test.go index 2189223118a..6402d0fad44 100644 --- a/engine/access/rpc/backend/retry_test.go +++ b/engine/access/rpc/backend/retry_test.go @@ -3,13 +3,12 @@ package backend import ( "context" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/execution" "github.com/stretchr/testify/mock" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" protocol "github.com/onflow/flow-go/state/protocol/mock" @@ -61,7 +60,7 @@ func (suite *Suite) TestTransactionRetry() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) retry := newRetry().SetBackend(backend).Activate() backend.retry = retry @@ -151,7 +150,7 @@ func (suite *Suite) TestSuccessfulTransactionsDontRetry() { suite.log, DefaultSnapshotHistoryLimit, nil, - false, + NewNodeCommunicator(false), ) retry := newRetry().SetBackend(backend).Activate() backend.retry = retry diff --git a/engine/access/rpc/rate_limit_test.go b/engine/access/rpc/rate_limit_test.go index 8ff5695c3c6..f9a16cba4a5 100644 --- a/engine/access/rpc/rate_limit_test.go +++ b/engine/access/rpc/rate_limit_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -31,8 +32,6 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" - - accessproto "github.com/onflow/flow/protobuf/go/flow/access" ) type RateLimitTestSuite struct { @@ -168,7 +167,7 @@ func (suite *RateLimitTestSuite) SetupTest() { suite.log, 0, nil, - false) + backend.NewNodeCommunicator(false)) rpcEngBuilder, err := NewBuilder( suite.log, diff --git a/engine/access/secure_grpcr_test.go b/engine/access/secure_grpcr_test.go index 783ed0d3110..ceb4d7ba221 100644 --- a/engine/access/secure_grpcr_test.go +++ b/engine/access/secure_grpcr_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -15,8 +16,6 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow-go/crypto" accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rpc" @@ -151,7 +150,7 @@ func (suite *SecureGRPCTestSuite) SetupTest() { suite.log, 0, nil, - false) + backend.NewNodeCommunicator(false)) rpcEngBuilder, err := rpc.NewBuilder( suite.log, diff --git a/engine/access/state_stream/mock/get_execution_data_func.go b/engine/access/state_stream/mock/get_execution_data_func.go index 50fe8087e21..506cc8d3d1c 100644 --- a/engine/access/state_stream/mock/get_execution_data_func.go +++ b/engine/access/state_stream/mock/get_execution_data_func.go @@ -5,8 +5,9 @@ package mock import ( context "context" - execution_data "github.com/onflow/flow-go/module/executiondatasync/execution_data" mock "github.com/stretchr/testify/mock" + + execution_data "github.com/onflow/flow-go/module/executiondatasync/execution_data" ) // GetExecutionDataFunc is an autogenerated mock type for the GetExecutionDataFunc type diff --git a/engine/access/state_stream/mock/get_start_height_func.go b/engine/access/state_stream/mock/get_start_height_func.go index b97a77e1d39..d1c93d2ed1c 100644 --- a/engine/access/state_stream/mock/get_start_height_func.go +++ b/engine/access/state_stream/mock/get_start_height_func.go @@ -3,8 +3,9 @@ package mock import ( - flow "github.com/onflow/flow-go/model/flow" mock "github.com/stretchr/testify/mock" + + flow "github.com/onflow/flow-go/model/flow" ) // GetStartHeightFunc is an autogenerated mock type for the GetStartHeightFunc type From 8c6fbb4f31486bd9c952b26ff54bb3a5a5b18474 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 8 Aug 2023 10:54:06 +0100 Subject: [PATCH 07/66] Upgrade lru cache in backend --- engine/access/rpc/backend/backend.go | 19 ++- engine/access/rpc/backend/backend_scripts.go | 27 ++-- engine/access/rpc/connection/cache.go | 10 +- .../access/rpc/connection/connection_test.go | 134 ++++-------------- engine/access/rpc/connection/mock_node.go | 93 ++++++++++++ 5 files changed, 144 insertions(+), 139 deletions(-) create mode 100644 engine/access/rpc/connection/mock_node.go diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 9b10cc5b539..9c7aaea417f 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -7,11 +7,7 @@ import ( "strconv" "time" - lru "github.com/hashicorp/golang-lru" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - + lru "github.com/hashicorp/golang-lru/v2" "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/cmd/build" "github.com/onflow/flow-go/engine/access/rpc/connection" @@ -22,8 +18,10 @@ import ( "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) // minExecutionNodesCnt is the minimum number of execution nodes expected to have sent the execution receipt for a block @@ -117,7 +115,7 @@ func New( retry.Activate() } - loggedScripts, err := lru.New(DefaultLoggedScriptsCacheSize) + loggedScripts, err := lru.New[[16]byte, time.Time](DefaultLoggedScriptsCacheSize) if err != nil { log.Fatal().Err(err).Msg("failed to initialize script logging cache") } @@ -225,14 +223,13 @@ func NewCache( log zerolog.Logger, accessMetrics module.AccessMetrics, connectionPoolSize uint, -) (*lru.Cache, uint, error) { +) (*lru.Cache[string, *connection.CachedClient], uint, error) { - var cache *lru.Cache + var cache *lru.Cache[string, *connection.CachedClient] cacheSize := connectionPoolSize if cacheSize > 0 { var err error - cache, err = lru.NewWithEvict(int(cacheSize), func(_, evictedValue interface{}) { - store := evictedValue.(*connection.CachedClient) + cache, err = lru.NewWithEvict[string, *connection.CachedClient](int(cacheSize), func(_ string, store *connection.CachedClient) { store.Close() log.Debug().Str("grpc_conn_evicted", store.Address).Msg("closing grpc connection evicted from pool") if accessMetrics != nil { diff --git a/engine/access/rpc/backend/backend_scripts.go b/engine/access/rpc/backend/backend_scripts.go index 62d32c56211..46804e170eb 100644 --- a/engine/access/rpc/backend/backend_scripts.go +++ b/engine/access/rpc/backend/backend_scripts.go @@ -1,25 +1,23 @@ package backend import ( - "context" "crypto/md5" //nolint:gosec + "context" "io" "time" - lru "github.com/hashicorp/golang-lru" - "github.com/onflow/flow/protobuf/go/flow/access" - - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - + lru "github.com/hashicorp/golang-lru/v2" "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" + "github.com/onflow/flow/protobuf/go/flow/access" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) // uniqueScriptLoggingTimeWindow is the duration for checking the uniqueness of scripts sent for execution @@ -32,7 +30,7 @@ type backendScripts struct { connFactory connection.ConnectionFactory log zerolog.Logger metrics module.BackendScriptsMetrics - loggedScripts *lru.Cache + loggedScripts *lru.Cache[[16]byte, time.Time] archiveAddressList []string archivePorts []uint nodeCommunicator *NodeCommunicator @@ -202,14 +200,11 @@ func (b *backendScripts) executeScriptOnExecutor( // shouldLogScript checks if the script hash is unique in the time window func (b *backendScripts) shouldLogScript(execTime time.Time, scriptHash [16]byte) bool { - rawTimestamp, seen := b.loggedScripts.Get(scriptHash) - if !seen || rawTimestamp == nil { + timestamp, seen := b.loggedScripts.Get(scriptHash) + if !seen { return true - } else { - // safe cast - timestamp := rawTimestamp.(time.Time) - return execTime.Sub(timestamp) >= uniqueScriptLoggingTimeWindow } + return execTime.Sub(timestamp) >= uniqueScriptLoggingTimeWindow } func (b *backendScripts) tryExecuteScriptOnExecutionNode( diff --git a/engine/access/rpc/connection/cache.go b/engine/access/rpc/connection/cache.go index 9aa53d3d251..133cac9dd12 100644 --- a/engine/access/rpc/connection/cache.go +++ b/engine/access/rpc/connection/cache.go @@ -4,7 +4,7 @@ import ( "sync" "time" - lru "github.com/hashicorp/golang-lru" + lru "github.com/hashicorp/golang-lru/v2" "go.uber.org/atomic" "google.golang.org/grpc" ) @@ -38,12 +38,12 @@ func (s *CachedClient) Close() { // Cache represents a cache of CachedClient instances with a given maximum size. type Cache struct { - cache *lru.Cache + cache *lru.Cache[string, *CachedClient] size int } // NewCache creates a new Cache with the specified maximum size and the underlying LRU cache. -func NewCache(cache *lru.Cache, size int) *Cache { +func NewCache(cache *lru.Cache[string, *CachedClient], size int) *Cache { return &Cache{ cache: cache, size: size, @@ -57,7 +57,7 @@ func (c *Cache) Get(address string) (*CachedClient, bool) { if !ok { return nil, false } - return val.(*CachedClient), true + return val, true } // GetOrAdd atomically gets the CachedClient for the given address from the cache, or adds a new one @@ -71,7 +71,7 @@ func (c *Cache) GetOrAdd(address string, timeout time.Duration) (*CachedClient, val, existed, _ := c.cache.PeekOrAdd(address, client) if existed { - return val.(*CachedClient), true + return val, true } client.Address = address diff --git a/engine/access/rpc/connection/connection_test.go b/engine/access/rpc/connection/connection_test.go index a961816605e..4dd9778c2cf 100644 --- a/engine/access/rpc/connection/connection_test.go +++ b/engine/access/rpc/connection/connection_test.go @@ -4,31 +4,25 @@ import ( "context" "fmt" "net" - "strconv" - "strings" "sync" "testing" "time" - "github.com/sony/gobreaker" - - "go.uber.org/atomic" - "pgregory.net/rapid" - - lru "github.com/hashicorp/golang-lru" + lru "github.com/hashicorp/golang-lru/v2" + "github.com/onflow/flow-go/module/metrics" + "github.com/onflow/flow-go/utils/unittest" "github.com/onflow/flow/protobuf/go/flow/access" "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/sony/gobreaker" "github.com/stretchr/testify/assert" testifymock "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "go.uber.org/atomic" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/connectivity" "google.golang.org/grpc/status" - - "github.com/onflow/flow-go/engine/access/mock" - "github.com/onflow/flow-go/module/metrics" - "github.com/onflow/flow-go/utils/unittest" + "pgregory.net/rapid" ) func TestProxyAccessAPI(t *testing.T) { @@ -129,8 +123,8 @@ func TestProxyAccessAPIConnectionReuse(t *testing.T) { connectionFactory.CollectionGRPCPort = cn.port // set the connection pool cache size cacheSize := 1 - cache, _ := lru.NewWithEvict(cacheSize, func(_, evictedValue interface{}) { - evictedValue.(*CachedClient).Close() + cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { + client.Close() }) connectionCache := NewCache(cache, cacheSize) @@ -184,8 +178,8 @@ func TestProxyExecutionAPIConnectionReuse(t *testing.T) { connectionFactory.ExecutionGRPCPort = en.port // set the connection pool cache size cacheSize := 5 - cache, _ := lru.NewWithEvict(cacheSize, func(_, evictedValue interface{}) { - evictedValue.(*CachedClient).Close() + cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { + client.Close() }) connectionCache := NewCache(cache, cacheSize) // set metrics reporting @@ -245,8 +239,8 @@ func TestExecutionNodeClientTimeout(t *testing.T) { connectionFactory.ExecutionNodeGRPCTimeout = timeout // set the connection pool cache size cacheSize := 5 - cache, _ := lru.NewWithEvict(cacheSize, func(_, evictedValue interface{}) { - evictedValue.(*CachedClient).Close() + cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { + client.Close() }) connectionCache := NewCache(cache, cacheSize) // set metrics reporting @@ -294,8 +288,8 @@ func TestCollectionNodeClientTimeout(t *testing.T) { connectionFactory.CollectionNodeGRPCTimeout = timeout // set the connection pool cache size cacheSize := 5 - cache, _ := lru.NewWithEvict(cacheSize, func(_, evictedValue interface{}) { - evictedValue.(*CachedClient).Close() + cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { + client.Close() }) connectionCache := NewCache(cache, cacheSize) // set metrics reporting @@ -343,9 +337,10 @@ func TestConnectionPoolFull(t *testing.T) { connectionFactory.CollectionGRPCPort = cn1.port // set the connection pool cache size cacheSize := 2 - cache, _ := lru.NewWithEvict(cacheSize, func(_, evictedValue interface{}) { - evictedValue.(*CachedClient).Close() + cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { + client.Close() }) + connectionCache := NewCache(cache, cacheSize) // set metrics reporting connectionFactory.AccessMetrics = metrics.NewNoopCollector() @@ -419,9 +414,10 @@ func TestConnectionPoolStale(t *testing.T) { connectionFactory.CollectionGRPCPort = cn.port // set the connection pool cache size cacheSize := 5 - cache, _ := lru.NewWithEvict(cacheSize, func(_, evictedValue interface{}) { - evictedValue.(*CachedClient).Close() + cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { + client.Close() }) + connectionCache := NewCache(cache, cacheSize) // set metrics reporting connectionFactory.AccessMetrics = metrics.NewNoopCollector() @@ -508,9 +504,10 @@ func TestExecutionNodeClientClosedGracefully(t *testing.T) { connectionFactory.ExecutionNodeGRPCTimeout = time.Second // set the connection pool cache size cacheSize := 1 - cache, _ := lru.NewWithEvict(cacheSize, func(_, evictedValue interface{}) { - evictedValue.(*CachedClient).Close() + cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { + client.Close() }) + connectionCache := NewCache(cache, cacheSize) // set metrics reporting connectionFactory.AccessMetrics = metrics.NewNoopCollector() @@ -592,7 +589,7 @@ func TestExecutionEvictingCacheClients(t *testing.T) { connectionFactory.CollectionNodeGRPCTimeout = 5 * time.Second // Set the connection pool cache size cacheSize := 1 - cache, err := lru.New(cacheSize) + cache, err := lru.New[string, *CachedClient](cacheSize) require.NoError(t, err) connectionCache := NewCache(cache, cacheSize) @@ -614,8 +611,7 @@ func TestExecutionEvictingCacheClients(t *testing.T) { ctx := context.Background() // Retrieve the cached client from the cache - result, _ := cache.Get(clientAddress) - cachedClient := result.(*CachedClient) + cachedClient, _ := cache.Get(clientAddress) // Schedule the invalidation of the access API client after a delay time.AfterFunc(250*time.Millisecond, func() { @@ -671,7 +667,7 @@ func TestCircuitBreakerExecutionNode(t *testing.T) { // Set the connection pool cache size. cacheSize := 1 - connectionCache, _ := lru.New(cacheSize) + connectionCache, _ := lru.New[string, *CachedClient](cacheSize) connectionFactory.Manager = NewManager( NewCache(connectionCache, cacheSize), @@ -755,8 +751,8 @@ func TestCircuitBreakerCollectionNode(t *testing.T) { // Set the connection pool cache size. cacheSize := 1 - connectionCache, _ := lru.New(cacheSize) + connectionCache, _ := lru.New[string, *CachedClient](cacheSize) connectionFactory.Manager = NewManager( NewCache(connectionCache, cacheSize), unittest.Logger(), @@ -812,79 +808,3 @@ func TestCircuitBreakerCollectionNode(t *testing.T) { assert.Greater(t, requestTimeout, duration) assert.Equal(t, nil, err) } - -// node mocks a flow node that runs a GRPC server -type node struct { - server *grpc.Server - listener net.Listener - port uint -} - -func (n *node) setupNode(t *testing.T) { - n.server = grpc.NewServer() - listener, err := net.Listen("tcp4", unittest.DefaultAddress) - assert.NoError(t, err) - n.listener = listener - assert.Eventually(t, func() bool { - return !strings.HasSuffix(listener.Addr().String(), ":0") - }, time.Second*4, 10*time.Millisecond) - - _, port, err := net.SplitHostPort(listener.Addr().String()) - assert.NoError(t, err) - portAsUint, err := strconv.ParseUint(port, 10, 32) - assert.NoError(t, err) - n.port = uint(portAsUint) -} - -func (n *node) start(t *testing.T) { - // using a wait group here to ensure the goroutine has started before returning. Otherwise, - // there's a race condition where the server is sometimes stopped before it has started - wg := sync.WaitGroup{} - wg.Add(1) - go func() { - wg.Done() - err := n.server.Serve(n.listener) - assert.NoError(t, err) - }() - unittest.RequireReturnsBefore(t, wg.Wait, 10*time.Millisecond, "could not start goroutine on time") -} - -func (n *node) stop(t *testing.T) { - if n.server != nil { - n.server.Stop() - } -} - -type executionNode struct { - node - handler *mock.ExecutionAPIServer -} - -func (en *executionNode) start(t *testing.T) { - en.setupNode(t) - handler := new(mock.ExecutionAPIServer) - execution.RegisterExecutionAPIServer(en.server, handler) - en.handler = handler - en.node.start(t) -} - -func (en *executionNode) stop(t *testing.T) { - en.node.stop(t) -} - -type collectionNode struct { - node - handler *mock.AccessAPIServer -} - -func (cn *collectionNode) start(t *testing.T) { - cn.setupNode(t) - handler := new(mock.AccessAPIServer) - access.RegisterAccessAPIServer(cn.server, handler) - cn.handler = handler - cn.node.start(t) -} - -func (cn *collectionNode) stop(t *testing.T) { - cn.node.stop(t) -} diff --git a/engine/access/rpc/connection/mock_node.go b/engine/access/rpc/connection/mock_node.go new file mode 100644 index 00000000000..f09fe11aed5 --- /dev/null +++ b/engine/access/rpc/connection/mock_node.go @@ -0,0 +1,93 @@ +package connection + +import ( + "net" + "strconv" + "strings" + "sync" + "testing" + "time" + + "github.com/onflow/flow-go/engine/access/mock" + "github.com/onflow/flow-go/utils/unittest" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/stretchr/testify/assert" + "google.golang.org/grpc" +) + +// node mocks a flow node that runs a GRPC server +type node struct { + server *grpc.Server + listener net.Listener + port uint +} + +func (n *node) setupNode(t *testing.T) { + n.server = grpc.NewServer() + listener, err := net.Listen("tcp4", unittest.DefaultAddress) + assert.NoError(t, err) + n.listener = listener + assert.Eventually(t, func() bool { + return !strings.HasSuffix(listener.Addr().String(), ":0") + }, time.Second*4, 10*time.Millisecond) + + _, port, err := net.SplitHostPort(listener.Addr().String()) + assert.NoError(t, err) + portAsUint, err := strconv.ParseUint(port, 10, 32) + assert.NoError(t, err) + n.port = uint(portAsUint) +} + +func (n *node) start(t *testing.T) { + // using a wait group here to ensure the goroutine has started before returning. Otherwise, + // there's a race condition where the server is sometimes stopped before it has started + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + wg.Done() + err := n.server.Serve(n.listener) + assert.NoError(t, err) + }() + unittest.RequireReturnsBefore(t, wg.Wait, 10*time.Millisecond, "could not start goroutine on time") +} + +func (n *node) stop(t *testing.T) { + if n.server != nil { + n.server.Stop() + } +} + +type executionNode struct { + node + handler *mock.ExecutionAPIServer +} + +func (en *executionNode) start(t *testing.T) { + en.setupNode(t) + handler := new(mock.ExecutionAPIServer) + execution.RegisterExecutionAPIServer(en.server, handler) + en.handler = handler + en.node.start(t) +} + +func (en *executionNode) stop(t *testing.T) { + en.node.stop(t) +} + +type collectionNode struct { + node + handler *mock.AccessAPIServer +} + +func (cn *collectionNode) start(t *testing.T) { + cn.setupNode(t) + handler := new(mock.AccessAPIServer) + access.RegisterAccessAPIServer(cn.server, handler) + cn.handler = handler + cn.node.start(t) +} + +func (cn *collectionNode) stop(t *testing.T) { + cn.node.stop(t) +} From 985b558a2a22fc2952073ee55781ea49518da8a0 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 8 Aug 2023 14:33:21 +0100 Subject: [PATCH 08/66] Fix goimports --- engine/access/access_test.go | 19 +++++++-------- .../integration_unsecure_grpc_server_test.go | 19 +++++++-------- engine/access/rest_api_test.go | 15 ++++++------ engine/access/rpc/backend/backend.go | 9 ++++---- engine/access/rpc/backend/backend_scripts.go | 13 ++++++----- engine/access/rpc/backend/backend_test.go | 21 +++++++++-------- .../rpc/backend/backend_transactions_test.go | 13 ++++++----- .../rpc/backend/historical_access_test.go | 9 ++++---- engine/access/rpc/backend/retry_test.go | 11 +++++---- engine/access/rpc/rate_limit_test.go | 23 ++++++++++--------- engine/access/secure_grpcr_test.go | 17 +++++++------- 11 files changed, 90 insertions(+), 79 deletions(-) diff --git a/engine/access/access_test.go b/engine/access/access_test.go index d4ef365654d..8fdf13cf5c7 100644 --- a/engine/access/access_test.go +++ b/engine/access/access_test.go @@ -8,6 +8,16 @@ import ( "github.com/dgraph-io/badger/v2" "github.com/google/go-cmp/cmp" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + entitiesproto "github.com/onflow/flow/protobuf/go/flow/entities" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "google.golang.org/protobuf/testing/protocmp" + "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/cmd/build" hsmock "github.com/onflow/flow-go/consensus/hotstuff/mocks" @@ -36,15 +46,6 @@ import ( "github.com/onflow/flow-go/storage/util" "github.com/onflow/flow-go/utils/unittest" "github.com/onflow/flow-go/utils/unittest/mocks" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - entitiesproto "github.com/onflow/flow/protobuf/go/flow/entities" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "google.golang.org/protobuf/testing/protocmp" ) type Suite struct { diff --git a/engine/access/integration_unsecure_grpc_server_test.go b/engine/access/integration_unsecure_grpc_server_test.go index fc0e3c8f180..520da185aad 100644 --- a/engine/access/integration_unsecure_grpc_server_test.go +++ b/engine/access/integration_unsecure_grpc_server_test.go @@ -7,6 +7,16 @@ import ( "testing" "time" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + executiondataproto "github.com/onflow/flow/protobuf/go/flow/executiondata" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "github.com/onflow/flow-go/engine" accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rpc" @@ -27,15 +37,6 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - executiondataproto "github.com/onflow/flow/protobuf/go/flow/executiondata" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" ) // SameGRPCPortTestSuite verifies both AccessAPI and ExecutionDataAPI client continue to work when configured diff --git a/engine/access/rest_api_test.go b/engine/access/rest_api_test.go index d85a98c0995..7ca1ef0c0f3 100644 --- a/engine/access/rest_api_test.go +++ b/engine/access/rest_api_test.go @@ -11,6 +11,14 @@ import ( "time" "github.com/antihax/optional" + restclient "github.com/onflow/flow/openapi/go-client-generated" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc/credentials" + accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rest/request" "github.com/onflow/flow-go/engine/access/rest/routes" @@ -27,13 +35,6 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" - restclient "github.com/onflow/flow/openapi/go-client-generated" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc/credentials" ) // RestAPITestSuite tests that the Access node serves the REST API defined via the OpenApi spec accurately diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index edeca15093d..48042d34da8 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -9,6 +9,11 @@ import ( lru "github.com/hashicorp/golang-lru" lru2 "github.com/hashicorp/golang-lru/v2" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/cmd/build" "github.com/onflow/flow-go/engine/access/rpc/connection" @@ -20,10 +25,6 @@ import ( "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" "github.com/onflow/flow-go/storage/badger" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) // minExecutionNodesCnt is the minimum number of execution nodes expected to have sent the execution receipt for a block diff --git a/engine/access/rpc/backend/backend_scripts.go b/engine/access/rpc/backend/backend_scripts.go index a2d411cafa5..b73aef9ce43 100644 --- a/engine/access/rpc/backend/backend_scripts.go +++ b/engine/access/rpc/backend/backend_scripts.go @@ -1,25 +1,26 @@ package backend import ( - "crypto/md5" //nolint:gosec "bytes" "context" + "crypto/md5" //nolint:gosec "io" "time" "github.com/hashicorp/go-multierror" lru "github.com/hashicorp/golang-lru" + "github.com/onflow/flow/protobuf/go/flow/access" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - "github.com/onflow/flow/protobuf/go/flow/access" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) // uniqueScriptLoggingTimeWindow is the duration for checking the uniqueness of scripts sent for execution diff --git a/engine/access/rpc/backend/backend_test.go b/engine/access/rpc/backend/backend_test.go index f564e24bb46..8c438a97897 100644 --- a/engine/access/rpc/backend/backend_test.go +++ b/engine/access/rpc/backend/backend_test.go @@ -7,6 +7,17 @@ import ( "testing" "github.com/dgraph-io/badger/v2" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + entitiesproto "github.com/onflow/flow/protobuf/go/flow/entities" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + access "github.com/onflow/flow-go/engine/access/mock" backendmock "github.com/onflow/flow-go/engine/access/rpc/backend/mock" "github.com/onflow/flow-go/engine/access/rpc/connection" @@ -19,16 +30,6 @@ import ( "github.com/onflow/flow-go/storage" storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/unittest" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - entitiesproto "github.com/onflow/flow/protobuf/go/flow/entities" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) type Suite struct { diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index 36a516a67f8..332e03a43be 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -5,6 +5,13 @@ import ( "fmt" "github.com/dgraph-io/badger/v2" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" "github.com/onflow/flow-go/state/protocol" @@ -12,12 +19,6 @@ import ( "github.com/onflow/flow-go/state/protocol/util" "github.com/onflow/flow-go/storage" "github.com/onflow/flow-go/utils/unittest" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) func (suite *Suite) WithPreConfiguredState(f func(snap protocol.Snapshot)) { diff --git a/engine/access/rpc/backend/historical_access_test.go b/engine/access/rpc/backend/historical_access_test.go index b3a0fd91156..95496ab67c7 100644 --- a/engine/access/rpc/backend/historical_access_test.go +++ b/engine/access/rpc/backend/historical_access_test.go @@ -3,14 +3,15 @@ package backend import ( "context" - "github.com/onflow/flow-go/engine/common/rpc/convert" - "github.com/onflow/flow-go/model/flow" - "github.com/onflow/flow-go/module/metrics" - "github.com/onflow/flow-go/utils/unittest" accessproto "github.com/onflow/flow/protobuf/go/flow/access" "github.com/onflow/flow/protobuf/go/flow/entities" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + "github.com/onflow/flow-go/engine/common/rpc/convert" + "github.com/onflow/flow-go/model/flow" + "github.com/onflow/flow-go/module/metrics" + "github.com/onflow/flow-go/utils/unittest" ) // TestHistoricalTransactionResult tests to see if the historical transaction status can be retrieved diff --git a/engine/access/rpc/backend/retry_test.go b/engine/access/rpc/backend/retry_test.go index e232c4f1c76..3f988fb2b54 100644 --- a/engine/access/rpc/backend/retry_test.go +++ b/engine/access/rpc/backend/retry_test.go @@ -3,16 +3,17 @@ package backend import ( "context" - "github.com/onflow/flow-go/model/flow" - "github.com/onflow/flow-go/module/metrics" - protocol "github.com/onflow/flow-go/state/protocol/mock" - realstorage "github.com/onflow/flow-go/storage" - "github.com/onflow/flow-go/utils/unittest" "github.com/onflow/flow/protobuf/go/flow/access" "github.com/onflow/flow/protobuf/go/flow/execution" "github.com/stretchr/testify/mock" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + "github.com/onflow/flow-go/model/flow" + "github.com/onflow/flow-go/module/metrics" + protocol "github.com/onflow/flow-go/state/protocol/mock" + realstorage "github.com/onflow/flow-go/storage" + "github.com/onflow/flow-go/utils/unittest" ) // TestTransactionRetry tests that the retry mechanism will send retries at specific times diff --git a/engine/access/rpc/rate_limit_test.go b/engine/access/rpc/rate_limit_test.go index 27b76955ccc..5777a4b3aee 100644 --- a/engine/access/rpc/rate_limit_test.go +++ b/engine/access/rpc/rate_limit_test.go @@ -8,6 +8,18 @@ import ( "testing" "time" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/status" + accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rpc/backend" "github.com/onflow/flow-go/model/flow" @@ -20,17 +32,6 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/status" ) type RateLimitTestSuite struct { diff --git a/engine/access/secure_grpcr_test.go b/engine/access/secure_grpcr_test.go index ec5cb41643e..ecc0156b720 100644 --- a/engine/access/secure_grpcr_test.go +++ b/engine/access/secure_grpcr_test.go @@ -7,6 +7,15 @@ import ( "testing" "time" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "github.com/onflow/flow-go/crypto" accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rpc" @@ -21,14 +30,6 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" ) // SecureGRPCTestSuite tests that Access node provides a secure GRPC server From c19b3a9cd5e61a70116bbe7ca0ae0f8fcd34a817 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Wed, 9 Aug 2023 11:57:07 +0100 Subject: [PATCH 09/66] Goimport fixes --- engine/access/rpc/backend/backend.go | 9 +++++---- engine/access/rpc/backend/backend_scripts.go | 13 +++++++------ engine/access/rpc/connection/connection_test.go | 5 +++-- engine/access/rpc/connection/mock_node.go | 5 +++-- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index b95c121fdb9..7d331a65bbb 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -8,6 +8,11 @@ import ( "time" lru "github.com/hashicorp/golang-lru/v2" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/cmd/build" "github.com/onflow/flow-go/engine/access/rpc/connection" @@ -18,10 +23,6 @@ import ( "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) // minExecutionNodesCnt is the minimum number of execution nodes expected to have sent the execution receipt for a block diff --git a/engine/access/rpc/backend/backend_scripts.go b/engine/access/rpc/backend/backend_scripts.go index ef12ca7157c..bd4851a32e0 100644 --- a/engine/access/rpc/backend/backend_scripts.go +++ b/engine/access/rpc/backend/backend_scripts.go @@ -1,25 +1,26 @@ package backend import ( - "crypto/md5" //nolint:gosec "bytes" "context" + "crypto/md5" //nolint:gosec "io" "time" "github.com/hashicorp/go-multierror" lru "github.com/hashicorp/golang-lru/v2" + "github.com/onflow/flow/protobuf/go/flow/access" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - "github.com/onflow/flow/protobuf/go/flow/access" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) // uniqueScriptLoggingTimeWindow is the duration for checking the uniqueness of scripts sent for execution diff --git a/engine/access/rpc/connection/connection_test.go b/engine/access/rpc/connection/connection_test.go index 4dd9778c2cf..3db1edc4819 100644 --- a/engine/access/rpc/connection/connection_test.go +++ b/engine/access/rpc/connection/connection_test.go @@ -9,8 +9,6 @@ import ( "time" lru "github.com/hashicorp/golang-lru/v2" - "github.com/onflow/flow-go/module/metrics" - "github.com/onflow/flow-go/utils/unittest" "github.com/onflow/flow/protobuf/go/flow/access" "github.com/onflow/flow/protobuf/go/flow/execution" "github.com/sony/gobreaker" @@ -23,6 +21,9 @@ import ( "google.golang.org/grpc/connectivity" "google.golang.org/grpc/status" "pgregory.net/rapid" + + "github.com/onflow/flow-go/module/metrics" + "github.com/onflow/flow-go/utils/unittest" ) func TestProxyAccessAPI(t *testing.T) { diff --git a/engine/access/rpc/connection/mock_node.go b/engine/access/rpc/connection/mock_node.go index f09fe11aed5..e8929ab6ef3 100644 --- a/engine/access/rpc/connection/mock_node.go +++ b/engine/access/rpc/connection/mock_node.go @@ -8,12 +8,13 @@ import ( "testing" "time" - "github.com/onflow/flow-go/engine/access/mock" - "github.com/onflow/flow-go/utils/unittest" "github.com/onflow/flow/protobuf/go/flow/access" "github.com/onflow/flow/protobuf/go/flow/execution" "github.com/stretchr/testify/assert" "google.golang.org/grpc" + + "github.com/onflow/flow-go/engine/access/mock" + "github.com/onflow/flow-go/utils/unittest" ) // node mocks a flow node that runs a GRPC server From 42897b21676f04cd3be7aa52272de7b8214d4a8c Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sat, 12 Aug 2023 16:15:33 +0100 Subject: [PATCH 10/66] Fix failing tests --- engine/access/rpc/backend/backend_test.go | 23 +++++++++---------- .../rpc/backend/backend_transactions_test.go | 21 ++++++++--------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/engine/access/rpc/backend/backend_test.go b/engine/access/rpc/backend/backend_test.go index 8c438a97897..95e2372a44b 100644 --- a/engine/access/rpc/backend/backend_test.go +++ b/engine/access/rpc/backend/backend_test.go @@ -7,17 +7,6 @@ import ( "testing" "github.com/dgraph-io/badger/v2" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - entitiesproto "github.com/onflow/flow/protobuf/go/flow/entities" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - access "github.com/onflow/flow-go/engine/access/mock" backendmock "github.com/onflow/flow-go/engine/access/rpc/backend/mock" "github.com/onflow/flow-go/engine/access/rpc/connection" @@ -30,6 +19,16 @@ import ( "github.com/onflow/flow-go/storage" storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/unittest" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + entitiesproto "github.com/onflow/flow/protobuf/go/flow/entities" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type Suite struct { @@ -2497,7 +2496,7 @@ func (suite *Suite) TestScriptExecutionValidationMode() { DefaultSnapshotHistoryLimit, []string{fullArchiveAddress}, NewNodeCommunicator(true), - false, + true, ) // mock parameters diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index 332e03a43be..6c4707ca020 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -5,13 +5,6 @@ import ( "fmt" "github.com/dgraph-io/badger/v2" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" "github.com/onflow/flow-go/state/protocol" @@ -19,6 +12,12 @@ import ( "github.com/onflow/flow-go/state/protocol/util" "github.com/onflow/flow-go/storage" "github.com/onflow/flow-go/utils/unittest" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) func (suite *Suite) WithPreConfiguredState(f func(snap protocol.Snapshot)) { @@ -102,7 +101,7 @@ func (suite *Suite) TestGetTransactionResultReturnsUnknown() { suite.log, DefaultSnapshotHistoryLimit, nil, - *suite.communicator, + suite.communicator, false, ) res, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) @@ -161,7 +160,7 @@ func (suite *Suite) TestGetTransactionResultReturnsTransactionError() { suite.log, DefaultSnapshotHistoryLimit, nil, - *suite.communicator, + suite.communicator, false, ) _, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) @@ -235,7 +234,7 @@ func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResult() { suite.log, DefaultSnapshotHistoryLimit, nil, - *suite.communicator, + suite.communicator, false, ) resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) @@ -310,7 +309,7 @@ func (suite *Suite) TestGetTransactionResultFromCache() { suite.log, DefaultSnapshotHistoryLimit, nil, - *suite.communicator, + suite.communicator, false, ) From 9935534a4a6aa6fd96ec2d7a4d74d572628112cb Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sat, 12 Aug 2023 16:31:05 +0100 Subject: [PATCH 11/66] Update backend constructor annotation --- engine/access/rpc/backend/backend.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 48042d34da8..d6d7080c38a 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -9,11 +9,6 @@ import ( lru "github.com/hashicorp/golang-lru" lru2 "github.com/hashicorp/golang-lru/v2" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/cmd/build" "github.com/onflow/flow-go/engine/access/rpc/connection" @@ -25,6 +20,10 @@ import ( "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" "github.com/onflow/flow-go/storage/badger" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) // minExecutionNodesCnt is the minimum number of execution nodes expected to have sent the execution receipt for a block @@ -101,8 +100,7 @@ type Communicator interface { ) error } -// New creates backend accepting Communicator interfaces instead of circuitBreakerEnabled flag -// More convenient fur unit testing scenarios when you need to pass test NodeCommunicator objects. +// New creates backend instance func New(state protocol.State, collectionRPC accessproto.AccessAPIClient, historicalAccessNodes []accessproto.AccessAPIClient, From 1e60d8d917e01079beae6ebc2a22dccd5503320c Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sat, 12 Aug 2023 16:32:13 +0100 Subject: [PATCH 12/66] Update mock call --- engine/access/rpc/backend/backend_transactions_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index 6c4707ca020..dfe5c644ad9 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -36,7 +36,7 @@ func (suite *Suite) WithPreConfiguredState(f func(snap protocol.Snapshot)) { // setup AtHeight mock returns for state for _, height := range epoch1.Range() { - suite.state.On("AtHeisght", epoch1.Range()).Return(state.AtHeight(height)) + suite.state.On("AtHeight", epoch1.Range()).Return(state.AtHeight(height)) } snap := state.AtHeight(epoch1.Range()[0]) From 0d51ec31da7b738a72309c263777f27b87200ff2 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sat, 12 Aug 2023 16:34:41 +0100 Subject: [PATCH 13/66] Remove unused mock setup in backend transactions --- engine/access/rpc/backend/backend_transactions_test.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index dfe5c644ad9..5ac2dd1fbb9 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -66,15 +66,7 @@ func (suite *Suite) TestGetTransactionResultReturnsUnknown() { On("ByID", tx.ID()). Return(nil, storage.ErrNotFound) - suite.blocks. - On("ByID", block.ID()). - Return(&block, nil). - Once() - receipt := unittest.ExecutionReceiptFixture() - identity := unittest.IdentityFixture() - identity.Role = flow.RoleExecution - l := flow.ExecutionReceiptList{receipt} suite.receipts. From da2c6bef7e9102f68977f06ca28ad8de43b33609 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sat, 12 Aug 2023 16:39:58 +0100 Subject: [PATCH 14/66] Refine backend transaction tests --- .../rpc/backend/backend_transactions_test.go | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index 5ac2dd1fbb9..82de9c22440 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -174,16 +174,11 @@ func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResult() { On("ByID", tx.ID()). Return(nil, storage.ErrNotFound) - suite.blocks. - On("ByID", block.ID()). - Return(&block, nil). - Once() - suite.communicator.On("CallAvailableNode", mock.Anything, mock.Anything, mock.Anything). - Return(nil) + Return(nil).Once() receipt := unittest.ExecutionReceiptFixture() identity := unittest.IdentityFixture() @@ -258,25 +253,15 @@ func (suite *Suite) TestGetTransactionResultFromCache() { mock.Anything, mock.Anything, mock.Anything). - Return(nil) - - receipt := unittest.ExecutionReceiptFixture() - identity := unittest.IdentityFixture() - identity.Role = flow.RoleExecution + Return(nil).Once() suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() - l := flow.ExecutionReceiptList{receipt} - transactionResultResponse := access.TransactionResultResponse{ Status: entities.TransactionStatus_EXECUTED, StatusCode: uint32(entities.TransactionStatus_EXECUTED), } - suite.receipts. - On("ByBlockID", block.ID()). - Return(l, nil) - suite.historicalAccessClient. On("GetTransactionResult", mock.Anything, mock.Anything). Return(&transactionResultResponse, nil).Once() From de502623f37969894f7d4f87638d8afc098e1a97 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sat, 12 Aug 2023 16:43:06 +0100 Subject: [PATCH 15/66] Simplify backend transactiont tests --- .../rpc/backend/backend_transactions_test.go | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index 82de9c22440..3fd3d679e68 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -66,13 +66,6 @@ func (suite *Suite) TestGetTransactionResultReturnsUnknown() { On("ByID", tx.ID()). Return(nil, storage.ErrNotFound) - receipt := unittest.ExecutionReceiptFixture() - l := flow.ExecutionReceiptList{receipt} - - suite.receipts. - On("ByBlockID", block.ID()). - Return(l, nil) - backend := New( suite.state, suite.colClient, @@ -120,18 +113,8 @@ func (suite *Suite) TestGetTransactionResultReturnsTransactionError() { Return(&block, nil). Once() - receipt := unittest.ExecutionReceiptFixture() - identity := unittest.IdentityFixture() - identity.Role = flow.RoleExecution - suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() - l := flow.ExecutionReceiptList{receipt} - - suite.receipts. - On("ByBlockID", block.ID()). - Return(l, nil) - backend := New( suite.state, suite.colClient, @@ -180,23 +163,13 @@ func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResult() { mock.Anything). Return(nil).Once() - receipt := unittest.ExecutionReceiptFixture() - identity := unittest.IdentityFixture() - identity.Role = flow.RoleExecution - suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() - l := flow.ExecutionReceiptList{receipt} - transactionResultResponse := access.TransactionResultResponse{ Status: entities.TransactionStatus_EXECUTED, StatusCode: uint32(entities.TransactionStatus_EXECUTED), } - suite.receipts. - On("ByBlockID", block.ID()). - Return(l, nil) - suite.historicalAccessClient. On("GetTransactionResult", mock.Anything, mock.Anything). Return(&transactionResultResponse, nil) From 01d423eeab783420da588169369f26d02858aa67 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sat, 12 Aug 2023 16:45:13 +0100 Subject: [PATCH 16/66] Rename test case --- engine/access/rpc/backend/backend_transactions_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index 3fd3d679e68..40398dbc9c2 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -144,7 +144,7 @@ func (suite *Suite) TestGetTransactionResultReturnsTransactionError() { }) } -func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResult() { +func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResultFromHistoricNode() { suite.WithPreConfiguredState(func(snap protocol.Snapshot) { block := unittest.BlockFixture() tbody := unittest.TransactionBodyFixture() From 43193d6c88a8170d77aff50e0f1f4867b9037aa9 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sat, 12 Aug 2023 16:47:31 +0100 Subject: [PATCH 17/66] Require mock to be called exactly once --- engine/access/rpc/backend/backend_transactions_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index 40398dbc9c2..f5e690ddfa3 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -172,7 +172,7 @@ func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResultFromHis suite.historicalAccessClient. On("GetTransactionResult", mock.Anything, mock.Anything). - Return(&transactionResultResponse, nil) + Return(&transactionResultResponse, nil).Once() backend := New( suite.state, From 77e65b4e342b1c8fa3d52dd157a6ecb31cda2d84 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sun, 13 Aug 2023 14:38:03 +0100 Subject: [PATCH 18/66] Refactor Access backend constructor --- .../node_builder/access_node_builder.go | 49 +- engine/access/rpc/backend/backend.go | 173 +-- .../rpc/backend/backend_block_details.go | 23 +- .../rpc/backend/backend_block_headers.go | 23 +- engine/access/rpc/backend/backend_events.go | 19 +- engine/access/rpc/backend/backend_network.go | 12 +- engine/access/rpc/backend/backend_scripts.go | 21 +- engine/access/rpc/backend/backend_test.go | 1306 ++++++----------- .../rpc/backend/backend_transactions.go | 45 +- .../rpc/backend/backend_transactions_test.go | 145 +- .../rpc/backend/historical_access_test.go | 84 +- engine/access/rpc/backend/retry.go | 8 +- engine/access/rpc/backend/retry_test.go | 95 +- 13 files changed, 792 insertions(+), 1211 deletions(-) diff --git a/cmd/access/node_builder/access_node_builder.go b/cmd/access/node_builder/access_node_builder.go index 69d3e9474fd..b68d2ce5da9 100644 --- a/cmd/access/node_builder/access_node_builder.go +++ b/cmd/access/node_builder/access_node_builder.go @@ -1088,28 +1088,29 @@ func (builder *FlowAccessNodeBuilder) Build() (cmd.Node, error) { backendConfig.CircuitBreakerConfig, ), } - backend := backend.New( - node.State, - builder.CollectionRPC, - builder.HistoricalAccessRPCs, - node.Storage.Blocks, - node.Storage.Headers, - node.Storage.Collections, - node.Storage.Transactions, - node.Storage.Receipts, - node.Storage.Results, - node.RootChainID, - builder.AccessMetrics, - connFactory, - builder.retryEnabled, - backendConfig.MaxHeightRange, - backendConfig.PreferredExecutionNodeIDs, - backendConfig.FixedExecutionNodeIDs, - node.Logger, - backend.DefaultSnapshotHistoryLimit, - backendConfig.ArchiveAddressList, - backend.NewNodeCommunicator(backendConfig.CircuitBreakerConfig.Enabled), - backendConfig.ScriptExecValidation) + + bnd := backend.New(backend.BackendParams{ + State: node.State, + CollectionRPC: builder.CollectionRPC, + HistoricalAccessNodes: builder.HistoricalAccessRPCs, + Blocks: node.Storage.Blocks, + Headers: node.Storage.Headers, + Collections: node.Storage.Collections, + Transactions: node.Storage.Transactions, + ExecutionReceipts: node.Storage.Receipts, + ExecutionResults: node.Storage.Results, + ChainID: node.RootChainID, + AccessMetrics: builder.AccessMetrics, + ConnFactory: connFactory, + RetryEnabled: builder.retryEnabled, + MaxHeightRange: backendConfig.MaxHeightRange, + PreferredExecutionNodeIDs: backendConfig.PreferredExecutionNodeIDs, + FixedExecutionNodeIDs: backendConfig.FixedExecutionNodeIDs, + Log: node.Logger, + SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, + ArchiveAddressList: backendConfig.ArchiveAddressList, + Communicator: backend.NewNodeCommunicator(backendConfig.CircuitBreakerConfig.Enabled), + ScriptExecValidation: backendConfig.ScriptExecValidation}) engineBuilder, err := rpc.NewBuilder( node.Logger, @@ -1119,8 +1120,8 @@ func (builder *FlowAccessNodeBuilder) Build() (cmd.Node, error) { builder.AccessMetrics, builder.rpcMetricsEnabled, builder.Me, - backend, - backend, + bnd, + bnd, builder.secureGrpcServer, builder.unsecureGrpcServer, ) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index d6d7080c38a..8df05d04c8b 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -35,7 +35,7 @@ const maxAttemptsForExecutionReceipt = 3 // DefaultMaxHeightRange is the default maximum size of range requests. const DefaultMaxHeightRange = 250 -// DefaultSnapshotHistoryLimit the amount of blocks to look back in state +// DefaultSnapshotHistoryLimit the amount of Blocks to look back in State // when recursively searching for a valid snapshot const DefaultSnapshotHistoryLimit = 50 @@ -100,142 +100,143 @@ type Communicator interface { ) error } +type BackendParams struct { + State protocol.State + CollectionRPC accessproto.AccessAPIClient + HistoricalAccessNodes []accessproto.AccessAPIClient + Blocks storage.Blocks + Headers storage.Headers + Collections storage.Collections + Transactions storage.Transactions + ExecutionReceipts storage.ExecutionReceipts + ExecutionResults storage.ExecutionResults + ChainID flow.ChainID + AccessMetrics module.AccessMetrics + ConnFactory connection.ConnectionFactory + RetryEnabled bool + MaxHeightRange uint + PreferredExecutionNodeIDs []string + FixedExecutionNodeIDs []string + Log zerolog.Logger + SnapshotHistoryLimit int + ArchiveAddressList []string + Communicator Communicator + ScriptExecValidation bool +} + // New creates backend instance -func New(state protocol.State, - collectionRPC accessproto.AccessAPIClient, - historicalAccessNodes []accessproto.AccessAPIClient, - blocks storage.Blocks, - headers storage.Headers, - collections storage.Collections, - transactions storage.Transactions, - executionReceipts storage.ExecutionReceipts, - executionResults storage.ExecutionResults, - chainID flow.ChainID, - accessMetrics module.AccessMetrics, - connFactory connection.ConnectionFactory, - retryEnabled bool, - maxHeightRange uint, - preferredExecutionNodeIDs []string, - fixedExecutionNodeIDs []string, - log zerolog.Logger, - snapshotHistoryLimit int, - archiveAddressList []string, - communicator Communicator, - scriptExecValidation bool, -) *Backend { +func New(params BackendParams) *Backend { retry := newRetry() - if retryEnabled { + if params.RetryEnabled { retry.Activate() } loggedScripts, err := lru.New(DefaultLoggedScriptsCacheSize) if err != nil { - log.Fatal().Err(err).Msg("failed to initialize script logging cache") + params.Log.Fatal().Err(err).Msg("failed to initialize script logging cache") } - archivePorts := make([]uint, len(archiveAddressList)) - for idx, addr := range archiveAddressList { + archivePorts := make([]uint, len(params.ArchiveAddressList)) + for idx, addr := range params.ArchiveAddressList { port, err := findPortFromAddress(addr) if err != nil { - log.Fatal().Err(err).Msg("failed to find archive node port") + params.Log.Fatal().Err(err).Msg("failed to find archive node port") } archivePorts[idx] = port } txResCache, err := lru2.New[flow.Identifier, *access.TransactionResult](int(badger.DefaultCacheSize)) if err != nil { - log.Fatal().Err(err).Msg("failed to init cache for transaction results") + params.Log.Fatal().Err(err).Msg("failed to init cache for transaction results") } b := &Backend{ - state: state, + state: params.State, // create the sub-backends backendScripts: backendScripts{ - headers: headers, - executionReceipts: executionReceipts, - connFactory: connFactory, - state: state, - log: log, - metrics: accessMetrics, + headers: params.Headers, + executionReceipts: params.ExecutionReceipts, + connFactory: params.ConnFactory, + state: params.State, + log: params.Log, + metrics: params.AccessMetrics, loggedScripts: loggedScripts, - archiveAddressList: archiveAddressList, + archiveAddressList: params.ArchiveAddressList, archivePorts: archivePorts, - nodeCommunicator: communicator, - scriptExecValidation: scriptExecValidation, + nodeCommunicator: params.Communicator, + scriptExecValidation: params.ScriptExecValidation, }, backendTransactions: backendTransactions{ - staticCollectionRPC: collectionRPC, - state: state, - chainID: chainID, - collections: collections, - blocks: blocks, - transactions: transactions, - executionReceipts: executionReceipts, - transactionValidator: configureTransactionValidator(state, chainID), - transactionMetrics: accessMetrics, + staticCollectionRPC: params.CollectionRPC, + state: params.State, + chainID: params.ChainID, + collections: params.Collections, + blocks: params.Blocks, + transactions: params.Transactions, + executionReceipts: params.ExecutionReceipts, + transactionValidator: configureTransactionValidator(params.State, params.ChainID), + transactionMetrics: params.AccessMetrics, retry: retry, - connFactory: connFactory, - previousAccessNodes: historicalAccessNodes, - log: log, - nodeCommunicator: communicator, + connFactory: params.ConnFactory, + previousAccessNodes: params.HistoricalAccessNodes, + log: params.Log, + nodeCommunicator: params.Communicator, txResultCache: txResCache, }, backendEvents: backendEvents{ - state: state, - headers: headers, - executionReceipts: executionReceipts, - connFactory: connFactory, - log: log, - maxHeightRange: maxHeightRange, - nodeCommunicator: communicator, + state: params.State, + headers: params.Headers, + executionReceipts: params.ExecutionReceipts, + connFactory: params.ConnFactory, + log: params.Log, + maxHeightRange: params.MaxHeightRange, + nodeCommunicator: params.Communicator, }, backendBlockHeaders: backendBlockHeaders{ - headers: headers, - state: state, + headers: params.Headers, + state: params.State, }, backendBlockDetails: backendBlockDetails{ - blocks: blocks, - state: state, + blocks: params.Blocks, + state: params.State, }, backendAccounts: backendAccounts{ - state: state, - headers: headers, - executionReceipts: executionReceipts, - connFactory: connFactory, - log: log, - nodeCommunicator: communicator, + state: params.State, + headers: params.Headers, + executionReceipts: params.ExecutionReceipts, + connFactory: params.ConnFactory, + log: params.Log, + nodeCommunicator: params.Communicator, }, backendExecutionResults: backendExecutionResults{ - executionResults: executionResults, + executionResults: params.ExecutionResults, }, backendNetwork: backendNetwork{ - state: state, - chainID: chainID, - snapshotHistoryLimit: snapshotHistoryLimit, + state: params.State, + chainID: params.ChainID, + snapshotHistoryLimit: params.SnapshotHistoryLimit, }, - collections: collections, - executionReceipts: executionReceipts, - connFactory: connFactory, - chainID: chainID, + collections: params.Collections, + executionReceipts: params.ExecutionReceipts, + connFactory: params.ConnFactory, + chainID: params.ChainID, } retry.SetBackend(b) - preferredENIdentifiers, err = identifierList(preferredExecutionNodeIDs) + preferredENIdentifiers, err = identifierList(params.PreferredExecutionNodeIDs) if err != nil { - log.Fatal().Err(err).Msg("failed to convert node id string to Flow Identifier for preferred EN map") + params.Log.Fatal().Err(err).Msg("failed to convert node id string to Flow Identifier for preferred EN map") } - fixedENIdentifiers, err = identifierList(fixedExecutionNodeIDs) + fixedENIdentifiers, err = identifierList(params.FixedExecutionNodeIDs) if err != nil { - log.Fatal().Err(err).Msg("failed to convert node id string to Flow Identifier for fixed EN map") + params.Log.Fatal().Err(err).Msg("failed to convert node id string to Flow Identifier for fixed EN map") } return b } -//TODO: refactor cache, replace with generic lru.Cache alternative - // NewCache constructs cache for storing connections to other nodes. // No errors are expected during normal operations. func NewCache( @@ -331,7 +332,7 @@ func (b *Backend) GetCollectionByID(_ context.Context, colID flow.Identifier) (* // retrieve the collection from the collection storage col, err := b.collections.LightByID(colID) if err != nil { - // Collections are retrieved asynchronously as we finalize blocks, so + // Collections are retrieved asynchronously as we finalize Blocks, so // it is possible for a client to request a finalized block from us // containing some collection, then get a not found error when requesting // that collection. These clients should retry. @@ -397,7 +398,7 @@ func executionNodesForBlockID( break } - // log the attempt + // Log the attempt log.Debug().Int("attempt", attempt).Int("max_attempt", maxAttemptsForExecutionReceipt). Int("execution_receipts_found", len(executorIDs)). Str("block_id", blockID.String()). @@ -471,7 +472,7 @@ func findAllExecutionNodes( } } - // if there are more than one execution result for the same block ID, log as error + // if there are more than one execution result for the same block ID, Log as error if executionResultGroupedMetaList.NumberGroups() > 1 { identicalReceiptsStr := fmt.Sprintf("%v", flow.GetIDs(allReceipts)) log.Error(). diff --git a/engine/access/rpc/backend/backend_block_details.go b/engine/access/rpc/backend/backend_block_details.go index 19336ded8a4..1398eda7a77 100644 --- a/engine/access/rpc/backend/backend_block_details.go +++ b/engine/access/rpc/backend/backend_block_details.go @@ -3,13 +3,12 @@ package backend import ( "context" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type backendBlockDetails struct { @@ -25,21 +24,21 @@ func (b *backendBlockDetails) GetLatestBlock(_ context.Context, isSealed bool) ( // get the latest seal header from storage header, err = b.state.Sealed().Head() } else { - // get the finalized header from state + // get the finalized header from State header, err = b.state.Final().Head() } if err != nil { // node should always have the latest block - // In the RPC engine, if we encounter an error from the protocol state indicating state corruption, + // In the RPC engine, if we encounter an error from the protocol State indicating State corruption, // we should halt processing requests, but do throw an exception which might cause a crash: - // - It is unsafe to process requests if we have an internally bad state. + // - It is unsafe to process requests if we have an internally bad State. // TODO: https://github.com/onflow/flow-go/issues/4028 // - We would like to avoid throwing an exception as a result of an Access API request by policy // because this can cause DOS potential - // - Since the protocol state is widely shared, we assume that in practice another component will - // observe the protocol state error and throw an exception. + // - Since the protocol State is widely shared, we assume that in practice another component will + // observe the protocol State error and throw an exception. return nil, flow.BlockStatusUnknown, status.Errorf(codes.Internal, "could not get latest block: %v", err) } @@ -85,14 +84,14 @@ func (b *backendBlockDetails) GetBlockByHeight(_ context.Context, height uint64) func (b *backendBlockDetails) getBlockStatus(block *flow.Block) (flow.BlockStatus, error) { sealed, err := b.state.Sealed().Head() if err != nil { - // In the RPC engine, if we encounter an error from the protocol state indicating state corruption, + // In the RPC engine, if we encounter an error from the protocol State indicating State corruption, // we should halt processing requests, but do throw an exception which might cause a crash: - // - It is unsafe to process requests if we have an internally bad state. + // - It is unsafe to process requests if we have an internally bad State. // TODO: https://github.com/onflow/flow-go/issues/4028 // - We would like to avoid throwing an exception as a result of an Access API request by policy // because this can cause DOS potential - // - Since the protocol state is widely shared, we assume that in practice another component will - // observe the protocol state error and throw an exception. + // - Since the protocol State is widely shared, we assume that in practice another component will + // observe the protocol State error and throw an exception. return flow.BlockStatusUnknown, status.Errorf(codes.Internal, "failed to find latest sealed header: %v", err) } diff --git a/engine/access/rpc/backend/backend_block_headers.go b/engine/access/rpc/backend/backend_block_headers.go index 178f9064f1f..10efb30c6a2 100644 --- a/engine/access/rpc/backend/backend_block_headers.go +++ b/engine/access/rpc/backend/backend_block_headers.go @@ -3,13 +3,12 @@ package backend import ( "context" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type backendBlockHeaders struct { @@ -25,20 +24,20 @@ func (b *backendBlockHeaders) GetLatestBlockHeader(_ context.Context, isSealed b // get the latest seal header from storage header, err = b.state.Sealed().Head() } else { - // get the finalized header from state + // get the finalized header from State header, err = b.state.Final().Head() } if err != nil { // node should always have the latest block - // In the RPC engine, if we encounter an error from the protocol state indicating state corruption, + // In the RPC engine, if we encounter an error from the protocol State indicating State corruption, // we should halt processing requests, but do throw an exception which might cause a crash: - // - It is unsafe to process requests if we have an internally bad state. + // - It is unsafe to process requests if we have an internally bad State. // TODO: https://github.com/onflow/flow-go/issues/4028 // - We would like to avoid throwing an exception as a result of an Access API request by policy // because this can cause DOS potential - // - Since the protocol state is widely shared, we assume that in practice another component will - // observe the protocol state error and throw an exception. + // - Since the protocol State is widely shared, we assume that in practice another component will + // observe the protocol State error and throw an exception. return nil, flow.BlockStatusUnknown, status.Errorf(codes.Internal, "could not get latest block header: %v", err) } @@ -78,14 +77,14 @@ func (b *backendBlockHeaders) GetBlockHeaderByHeight(_ context.Context, height u func (b *backendBlockHeaders) getBlockStatus(header *flow.Header) (flow.BlockStatus, error) { sealed, err := b.state.Sealed().Head() if err != nil { - // In the RPC engine, if we encounter an error from the protocol state indicating state corruption, + // In the RPC engine, if we encounter an error from the protocol State indicating State corruption, // we should halt processing requests, but do throw an exception which might cause a crash: - // - It is unsafe to process requests if we have an internally bad state. + // - It is unsafe to process requests if we have an internally bad State. // TODO: https://github.com/onflow/flow-go/issues/4028 // - We would like to avoid throwing an exception as a result of an Access API request by policy // because this can cause DOS potential - // - Since the protocol state is widely shared, we assume that in practice another component will - // observe the protocol state error and throw an exception. + // - Since the protocol State is widely shared, we assume that in practice another component will + // observe the protocol State error and throw an exception. return flow.BlockStatusUnknown, status.Errorf(codes.Internal, "failed to find latest sealed header: %v", err) } diff --git a/engine/access/rpc/backend/backend_events.go b/engine/access/rpc/backend/backend_events.go index 43b42cde2f5..a151e138740 100644 --- a/engine/access/rpc/backend/backend_events.go +++ b/engine/access/rpc/backend/backend_events.go @@ -7,17 +7,16 @@ import ( "fmt" "time" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/engine/common/rpc/convert" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type backendEvents struct { @@ -30,7 +29,7 @@ type backendEvents struct { nodeCommunicator Communicator } -// GetEventsForHeightRange retrieves events for all sealed blocks between the start block height and +// GetEventsForHeightRange retrieves events for all sealed Blocks between the start block height and // the end block height (inclusive) that have the given type. func (b *backendEvents) GetEventsForHeightRange( ctx context.Context, @@ -65,7 +64,7 @@ func (b *backendEvents) GetEventsForHeightRange( endHeight = head.Height } - // find the block headers for all the blocks between min and max height (inclusive) + // find the block Headers for all the Blocks between min and max height (inclusive) blockHeaders := make([]*flow.Header, 0) for i := startHeight; i <= endHeight; i++ { @@ -91,7 +90,7 @@ func (b *backendEvents) GetEventsForBlockIDs( return nil, status.Errorf(codes.InvalidArgument, "requested block range (%d) exceeded maximum (%d)", len(blockIDs), b.maxHeightRange) } - // find the block headers for all the block IDs + // find the block Headers for all the block IDs blockHeaders := make([]*flow.Header, 0) for _, blockID := range blockIDs { header, err := b.headers.ByBlockID(blockID) @@ -165,7 +164,7 @@ func verifyAndConvertToAccessEvents( version execproto.EventEncodingVersion, ) ([]flow.BlockEvents, error) { if len(execEvents) != len(requestedBlockHeaders) { - return nil, errors.New("number of results does not match number of blocks requested") + return nil, errors.New("number of results does not match number of Blocks requested") } requestedBlockHeaderSet := map[string]*flow.Header{} @@ -223,7 +222,7 @@ func (b *backendEvents) getEventsFromAnyExeNode(ctx context.Context, logger := b.log.With(). Str("execution_node", node.String()). Str("event", req.GetType()). - Int("blocks", len(req.BlockIds)). + Int("Blocks", len(req.BlockIds)). Int64("rtt_ms", duration.Milliseconds()). Logger() diff --git a/engine/access/rpc/backend/backend_network.go b/engine/access/rpc/backend/backend_network.go index 577ebaa8a84..ebb80bd65e8 100644 --- a/engine/access/rpc/backend/backend_network.go +++ b/engine/access/rpc/backend/backend_network.go @@ -4,15 +4,13 @@ import ( "context" "fmt" - "github.com/onflow/flow-go/cmd/build" - - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/onflow/flow-go/access" + "github.com/onflow/flow-go/cmd/build" "github.com/onflow/flow-go/engine/common/rpc/convert" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/state/protocol" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) var SnapshotHistoryLimitErr = fmt.Errorf("reached the snapshot history limit") @@ -86,8 +84,8 @@ func (b *backendNetwork) isEpochOrPhaseDifferent(counter1, counter2 uint64, phas } // getValidSnapshot will return a valid snapshot that has a sealing segment which -// 1. does not contain any blocks that span an epoch transition -// 2. does not contain any blocks that span an epoch phase transition +// 1. does not contain any Blocks that span an epoch transition +// 2. does not contain any Blocks that span an epoch phase transition // If a snapshot does contain an invalid sealing segment query the state // by height of each block in the segment and return a snapshot at the point // where the transition happens. diff --git a/engine/access/rpc/backend/backend_scripts.go b/engine/access/rpc/backend/backend_scripts.go index b73aef9ce43..97b9b3f3f1d 100644 --- a/engine/access/rpc/backend/backend_scripts.go +++ b/engine/access/rpc/backend/backend_scripts.go @@ -1,26 +1,25 @@ package backend import ( + "crypto/md5" //nolint:gosec "bytes" "context" - "crypto/md5" //nolint:gosec "io" "time" "github.com/hashicorp/go-multierror" lru "github.com/hashicorp/golang-lru" - "github.com/onflow/flow/protobuf/go/flow/access" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" + "github.com/onflow/flow/protobuf/go/flow/access" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) // uniqueScriptLoggingTimeWindow is the duration for checking the uniqueness of scripts sent for execution @@ -169,7 +168,7 @@ func (b *backendScripts) logScriptExecutionComparison( archiveError error, msg string, ) { - // over-log for ease of debug + // over-Log for ease of debug if executionError != nil || archiveError != nil { b.log.Debug().Hex("block_id", blockID[:]). Str("script", string(script)). @@ -200,7 +199,7 @@ func (b *backendScripts) executeScriptOnAvailableArchiveNodes( rnPort := b.archivePorts[idx] result, err := b.tryExecuteScriptOnArchiveNode(ctx, rnAddr, rnPort, blockID, script, arguments) if err == nil { - // log execution time + // Log execution time b.metrics.ScriptExecuted( time.Since(startTime), len(script), @@ -219,7 +218,7 @@ func (b *backendScripts) executeScriptOnAvailableArchiveNodes( Msg("script failed to execute on the execution node") return nil, err case codes.NotFound: - // failures due to unavailable blocks are explicitly marked Not found + // failures due to unavailable Blocks are explicitly marked Not found b.metrics.ScriptExecutionErrorOnArchiveNode() b.log.Error().Err(err).Msg("script execution failed for archive node") return nil, err @@ -270,7 +269,7 @@ func (b *backendScripts) executeScriptOnAvailableExecutionNodes( } } - // log execution time + // Log execution time b.metrics.ScriptExecuted( time.Since(execStartTime), len(script), diff --git a/engine/access/rpc/backend/backend_test.go b/engine/access/rpc/backend/backend_test.go index 95e2372a44b..66f956f8ea1 100644 --- a/engine/access/rpc/backend/backend_test.go +++ b/engine/access/rpc/backend/backend_test.go @@ -31,6 +31,8 @@ import ( "google.golang.org/grpc/status" ) +const TEST_MAX_HEIGHT = 100 + type Suite struct { suite.Suite @@ -94,29 +96,16 @@ func (suite *Suite) TestPing() { On("Ping", mock.Anything, &execproto.PingRequest{}). Return(&execproto.PingResponse{}, nil) - backend := New( - suite.state, - suite.colClient, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + CollectionRPC: suite.colClient, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) err := backend.Ping(context.Background()) @@ -132,45 +121,32 @@ func (suite *Suite) TestGetLatestFinalizedBlockHeader() { suite.snapshot.On("Head").Return(block, nil).Once() backend := New( - suite.state, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + BackendParams{ + State: suite.state, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) // query the handler for the latest finalized block - header, status, err := backend.GetLatestBlockHeader(context.Background(), false) + header, stat, err := backend.GetLatestBlockHeader(context.Background(), false) suite.checkResponse(header, err) // make sure we got the latest block suite.Require().Equal(block.ID(), header.ID()) suite.Require().Equal(block.Height, header.Height) suite.Require().Equal(block.ParentID, header.ParentID) - suite.Require().Equal(status, flow.BlockStatusSealed) + suite.Require().Equal(stat, flow.BlockStatusSealed) suite.assertAllExpectations() } // TestGetLatestProtocolStateSnapshot_NoTransitionSpan tests our GetLatestProtocolStateSnapshot RPC endpoint -// where the sealing segment for the state requested at latest finalized block does not contain any blocks that +// where the sealing segment for the State requested at latest finalized block does not contain any Blocks that // spans an epoch or epoch phase transition. func (suite *Suite) TestGetLatestProtocolStateSnapshot_NoTransitionSpan() { identities := unittest.CompleteIdentitySet() @@ -178,7 +154,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_NoTransitionSpan() { util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { epochBuilder := unittest.NewEpochBuilder(suite.T(), state) // build epoch 1 - // blocks in current state + // Blocks in current State // P <- A(S_P-1) <- B(S_P) <- C(S_A) <- D(S_B) |setup| <- E(S_C) <- F(S_D) |commit| epochBuilder. BuildEpoch(). @@ -188,7 +164,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_NoTransitionSpan() { epoch1, ok := epochBuilder.EpochHeights(1) require.True(suite.T(), ok) - // setup AtBlockID mock returns for state + // setup AtBlockID mock returns for State for _, height := range epoch1.Range() { suite.state.On("AtHeight", height).Return(state.AtHeight(height)).Once() } @@ -198,36 +174,22 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_NoTransitionSpan() { snap := state.AtHeight(epoch1.Range()[2]) suite.state.On("Final").Return(snap).Once() - backend := New( - suite.state, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - 100, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: TEST_MAX_HEIGHT, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) // query the handler for the latest finalized snapshot bytes, err := backend.GetLatestProtocolStateSnapshot(context.Background()) suite.Require().NoError(err) // we expect the endpoint to return the snapshot at the same height we requested - // because it has a valid sealing segment with no blocks spanning an epoch or phase transition + // because it has a valid sealing segment with no Blocks spanning an epoch or phase transition expectedSnapshotBytes, err := convert.SnapshotToBytes(snap) suite.Require().NoError(err) suite.Require().Equal(expectedSnapshotBytes, bytes) @@ -235,8 +197,8 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_NoTransitionSpan() { } // TestGetLatestProtocolStateSnapshot_TransitionSpans tests our GetLatestProtocolStateSnapshot RPC endpoint -// where the sealing segment for the state requested for latest finalized block contains a block that -// spans an epoch transition and blocks that span epoch phase transitions. +// where the sealing segment for the State requested for latest finalized block contains a block that +// spans an epoch transition and Blocks that span epoch phase transitions. func (suite *Suite) TestGetLatestProtocolStateSnapshot_TransitionSpans() { identities := unittest.CompleteIdentitySet() rootSnapshot := unittest.RootSnapshotFixture(identities) @@ -259,7 +221,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_TransitionSpans() { epoch2, ok := epochBuilder.EpochHeights(2) require.True(suite.T(), ok) - // setup AtHeight mock returns for state + // setup AtHeight mock returns for State for _, height := range append(epoch1.Range(), epoch2.Range()...) { suite.state.On("AtHeight", height).Return(state.AtHeight(height)) } @@ -273,28 +235,15 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_TransitionSpans() { suite.state.On("Final").Return(snap).Once() backend := New( - suite.state, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - 100, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + BackendParams{ + State: suite.state, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: TEST_MAX_HEIGHT, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) // query the handler for the latest finalized snapshot bytes, err := backend.GetLatestProtocolStateSnapshot(context.Background()) @@ -309,7 +258,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_TransitionSpans() { } // TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan tests our GetLatestProtocolStateSnapshot RPC endpoint -// where the sealing segment for the state requested at latest finalized block contains a blocks that +// where the sealing segment for the State requested at latest finalized block contains a Blocks that // spans an epoch phase transition. func (suite *Suite) TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan() { identities := unittest.CompleteIdentitySet() @@ -317,7 +266,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan() { util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { epochBuilder := unittest.NewEpochBuilder(suite.T(), state) // build epoch 1 - // blocks in current state + // Blocks in current State // P <- A(S_P-1) <- B(S_P) <- C(S_A) <- D(S_B) |setup| <- E(S_C) <- F(S_D) |commit| epochBuilder. BuildEpoch(). @@ -327,7 +276,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan() { epoch1, ok := epochBuilder.EpochHeights(1) require.True(suite.T(), ok) - // setup AtBlockID mock returns for state + // setup AtBlockID mock returns for State for _, height := range epoch1.Range() { suite.state.On("AtHeight", height).Return(state.AtHeight(height)) } @@ -339,29 +288,15 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan() { snap := state.AtHeight(epoch1.Range()[3]) suite.state.On("Final").Return(snap).Once() - backend := New( - suite.state, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - 100, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: TEST_MAX_HEIGHT, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) // query the handler for the latest finalized snapshot bytes, err := backend.GetLatestProtocolStateSnapshot(context.Background()) @@ -375,7 +310,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan() { } // TestGetLatestProtocolStateSnapshot_EpochTransitionSpan tests our GetLatestProtocolStateSnapshot RPC endpoint -// where the sealing segment for the state requested at latest finalized block contains a blocks that +// where the sealing segment for the State requested at latest finalized block contains a Blocks that // spans an epoch transition. func (suite *Suite) TestGetLatestProtocolStateSnapshot_EpochTransitionSpan() { identities := unittest.CompleteIdentitySet() @@ -383,11 +318,11 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_EpochTransitionSpan() { util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { epochBuilder := unittest.NewEpochBuilder(suite.T(), state) // build epoch 1 - // blocks in current state + // Blocks in current State // P <- A(S_P-1) <- B(S_P) <- C(S_A) <- D(S_B) |setup| <- E(S_C) <- F(S_D) |commit| epochBuilder.BuildEpoch() - // add more blocks to our state in the commit phase, this will allow + // add more Blocks to our State in the commit phase, this will allow // us to take a snapshot at the height where the epoch1 -> epoch2 transition // and no block spans an epoch phase transition. The third block added will // have a seal for the first block in the commit phase allowing us to avoid @@ -406,7 +341,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_EpochTransitionSpan() { epoch2, ok := epochBuilder.EpochHeights(2) require.True(suite.T(), ok) - // setup AtHeight mock returns for state + // setup AtHeight mock returns for State for _, height := range append(epoch1.Range(), epoch2.Range()...) { suite.state.On("AtHeight", height).Return(state.AtHeight(height)) } @@ -417,29 +352,15 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_EpochTransitionSpan() { snap := state.AtHeight(epoch2.Range()[0]) suite.state.On("Final").Return(snap).Once() - backend := New( - suite.state, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - 100, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: TEST_MAX_HEIGHT, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) // query the handler for the latest finalized snapshot bytes, err := backend.GetLatestProtocolStateSnapshot(context.Background()) @@ -454,7 +375,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_EpochTransitionSpan() { } // TestGetLatestProtocolStateSnapshot_EpochTransitionSpan tests our GetLatestProtocolStateSnapshot RPC endpoint -// where the length of the sealing segment is greater than the configured snapshotHistoryLimit +// where the length of the sealing segment is greater than the configured SnapshotHistoryLimit func (suite *Suite) TestGetLatestProtocolStateSnapshot_HistoryLimit() { identities := unittest.CompleteIdentitySet() rootSnapshot := unittest.RootSnapshotFixture(identities) @@ -465,7 +386,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_HistoryLimit() { epoch1, ok := epochBuilder.EpochHeights(1) require.True(suite.T(), ok) - // setup AtBlockID mock returns for state + // setup AtBlockID mock returns for State for _, height := range epoch1.Range() { suite.state.On("AtHeight", height).Return(state.AtHeight(height)) } @@ -477,31 +398,17 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_HistoryLimit() { snap := state.AtHeight(epoch1.Range()[4]) suite.state.On("Final").Return(snap).Once() - // very short history limit, any segment with any blocks spanning any transition should force the endpoint to return a history limit error + // very short history limit, any segment with any Blocks spanning any transition should force the endpoint to return a history limit error snapshotHistoryLimit := 1 - backend := New( - suite.state, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - snapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: snapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) // the handler should return a snapshot history limit error _, err := backend.GetLatestProtocolStateSnapshot(context.Background()) @@ -519,39 +426,25 @@ func (suite *Suite) TestGetLatestSealedBlockHeader() { suite.state.On("Sealed").Return(suite.snapshot, nil) suite.snapshot.On("Head").Return(block, nil).Once() - backend := New( - suite.state, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) // query the handler for the latest sealed block - header, status, err := backend.GetLatestBlockHeader(context.Background(), true) + header, stat, err := backend.GetLatestBlockHeader(context.Background(), true) suite.checkResponse(header, err) // make sure we got the latest sealed block suite.Require().Equal(block.ID(), header.ID()) suite.Require().Equal(block.Height, header.Height) suite.Require().Equal(block.ParentID, header.ParentID) - suite.Require().Equal(status, flow.BlockStatusSealed) + suite.Require().Equal(stat, flow.BlockStatusSealed) suite.assertAllExpectations() } @@ -567,29 +460,16 @@ func (suite *Suite) TestGetTransaction() { Return(&expected, nil). Once() - backend := New( - suite.state, - nil, - nil, - nil, - nil, - nil, - suite.transactions, - nil, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Transactions: suite.transactions, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) actual, err := backend.GetTransaction(context.Background(), transaction.ID()) suite.checkResponse(actual, err) @@ -609,29 +489,17 @@ func (suite *Suite) TestGetCollection() { Return(&expected, nil). Once() - backend := New( - suite.state, - nil, - nil, - nil, - nil, - suite.collections, - suite.transactions, - nil, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Collections: suite.collections, + Transactions: suite.transactions, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) actual, err := backend.GetCollectionByID(context.Background(), expected.ID()) suite.transactions.AssertExpectations(suite.T()) @@ -674,29 +542,25 @@ func (suite *Suite) TestGetTransactionResultByIndex() { Events: nil, } - backend := New( - suite.state, - nil, - nil, - suite.blocks, - suite.headers, - suite.collections, - suite.transactions, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - flow.IdentifierList(fixedENIDs.NodeIDs()).Strings(), - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Blocks: suite.blocks, + Headers: suite.headers, + Collections: suite.collections, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + // the connection factory should be used to get the execution node client + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + FixedExecutionNodeIDs: (fixedENIDs.NodeIDs()).Strings(), + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) + suite.execClient. On("GetTransactionResultByIndex", ctx, exeEventReq). Return(exeEventResp, nil). @@ -739,29 +603,25 @@ func (suite *Suite) TestGetTransactionResultsByBlockID() { TransactionResults: []*execproto.GetTransactionResultResponse{{}}, } - backend := New( - suite.state, - nil, - nil, - suite.blocks, - suite.headers, - suite.collections, - suite.transactions, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - flow.IdentifierList(fixedENIDs.NodeIDs()).Strings(), - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Blocks: suite.blocks, + Headers: suite.headers, + Collections: suite.collections, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + // the connection factory should be used to get the execution node client + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + FixedExecutionNodeIDs: (fixedENIDs.NodeIDs()).Strings(), + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) + suite.execClient. On("GetTransactionResultsByBlockID", ctx, exeEventReq). Return(exeEventResp, nil). @@ -774,7 +634,7 @@ func (suite *Suite) TestGetTransactionResultsByBlockID() { } // TestTransactionStatusTransition tests that the status of transaction changes from Finalized to Sealed -// when the protocol state is updated +// when the protocol State is updated func (suite *Suite) TestTransactionStatusTransition() { suite.state.On("Sealed").Return(suite.snapshot, nil).Maybe() @@ -832,29 +692,24 @@ func (suite *Suite) TestTransactionStatusTransition() { Events: nil, } - backend := New( - suite.state, - nil, - nil, - suite.blocks, - suite.headers, - suite.collections, - suite.transactions, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - flow.IdentifierList(fixedENIDs.NodeIDs()).Strings(), - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Blocks: suite.blocks, + Headers: suite.headers, + Collections: suite.collections, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + // the connection factory should be used to get the execution node client + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + FixedExecutionNodeIDs: (fixedENIDs.NodeIDs()).Strings(), + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) // Successfully return empty event list suite.execClient. @@ -866,7 +721,7 @@ func (suite *Suite) TestTransactionStatusTransition() { result, err := backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) suite.checkResponse(result, err) - // status should be finalized since the sealed blocks is smaller in height + // status should be finalized since the sealed Blocks is smaller in height suite.Assert().Equal(flow.TransactionStatusFinalized, result.Status) // block ID should be included in the response @@ -891,7 +746,7 @@ func (suite *Suite) TestTransactionStatusTransition() { result, err = backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) suite.checkResponse(result, err) - // status should be sealed since the sealed blocks is greater in height + // status should be sealed since the sealed Blocks is greater in height suite.Assert().Equal(flow.TransactionStatusSealed, result.Status) // now go far into the future @@ -909,7 +764,7 @@ func (suite *Suite) TestTransactionStatusTransition() { } // TestTransactionExpiredStatusTransition tests that the status -// of transaction changes from Pending to Expired when enough blocks pass +// of transaction changes from Pending to Expired when enough Blocks pass func (suite *Suite) TestTransactionExpiredStatusTransition() { suite.state.On("Sealed").Return(suite.snapshot, nil).Maybe() suite.state.On("Final").Return(suite.snapshot, nil).Maybe() @@ -954,29 +809,21 @@ func (suite *Suite) TestTransactionExpiredStatusTransition() { txID := transactionBody.ID() - backend := New( - suite.state, - nil, - nil, - suite.blocks, - suite.headers, - suite.collections, - suite.transactions, - nil, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Blocks: suite.blocks, + Headers: suite.headers, + Collections: suite.collections, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) // should return pending status when we have not observed an expiry block suite.Run("pending", func() { @@ -988,23 +835,23 @@ func (suite *Suite) TestTransactionExpiredStatusTransition() { }) // should return pending status when we have observed an expiry block but - // have not observed all intermediary collections + // have not observed all intermediary Collections suite.Run("expiry un-confirmed", func() { suite.Run("ONLY finalized expiry block", func() { // we have finalized an expiry block headBlock.Header.Height = block.Header.Height + flow.DefaultTransactionExpiry + 1 - // we have NOT observed all intermediary collections + // we have NOT observed all intermediary Collections fullHeight = block.Header.Height + flow.DefaultTransactionExpiry/2 result, err := backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) suite.checkResponse(result, err) suite.Assert().Equal(flow.TransactionStatusPending, result.Status) }) - suite.Run("ONLY observed intermediary collections", func() { + suite.Run("ONLY observed intermediary Collections", func() { // we have NOT finalized an expiry block headBlock.Header.Height = block.Header.Height + flow.DefaultTransactionExpiry/2 - // we have observed all intermediary collections + // we have observed all intermediary Collections fullHeight = block.Header.Height + flow.DefaultTransactionExpiry + 1 result, err := backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) @@ -1015,11 +862,11 @@ func (suite *Suite) TestTransactionExpiredStatusTransition() { }) // should return expired status only when we have observed an expiry block - // and have observed all intermediary collections + // and have observed all intermediary Collections suite.Run("expired", func() { // we have finalized an expiry block headBlock.Header.Height = block.Header.Height + flow.DefaultTransactionExpiry + 1 - // we have observed all intermediary collections + // we have observed all intermediary Collections fullHeight = block.Header.Height + flow.DefaultTransactionExpiry + 1 result, err := backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) @@ -1077,7 +924,7 @@ func (suite *Suite) TestTransactionPendingToFinalizedStatusTransition() { On("ByID", txID). Return(transactionBody, nil) - currentState := flow.TransactionStatusPending // marker for the current state + currentState := flow.TransactionStatusPending // marker for the current State // collection storage returns a not found error if tx is pending, else it returns the collection light reference suite.collections. On("LightByTransactionID", txID). @@ -1122,30 +969,22 @@ func (suite *Suite) TestTransactionPendingToFinalizedStatusTransition() { // create a mock connection factory connFactory := suite.setupConnectionFactory() - - backend := New( - suite.state, - nil, - nil, - suite.blocks, - suite.headers, - suite.collections, - suite.transactions, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - 100, - nil, - flow.IdentifierList(enIDs.NodeIDs()).Strings(), - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Blocks: suite.blocks, + Headers: suite.headers, + Collections: suite.collections, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + MaxHeightRange: TEST_MAX_HEIGHT, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) preferredENIdentifiers = flow.IdentifierList{receipts[0].ExecutorID} @@ -1183,29 +1022,16 @@ func (suite *Suite) TestTransactionResultUnknown() { On("ByID", txID). Return(nil, storage.ErrNotFound) - backend := New( - suite.state, - nil, - nil, - nil, - nil, - nil, - suite.transactions, - nil, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Transactions: suite.transactions, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) // first call - when block under test is greater height than the sealed head, but execution node does not know about Tx result, err := backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) @@ -1239,37 +1065,24 @@ func (suite *Suite) TestGetLatestFinalizedBlock() { On("ByHeight", header.Height). Return(&expected, nil) - backend := New( - suite.state, - nil, - nil, - suite.blocks, - nil, - nil, - nil, - nil, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Blocks: suite.blocks, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + }) // query the handler for the latest finalized header - actual, status, err := backend.GetLatestBlock(context.Background(), false) + actual, stat, err := backend.GetLatestBlock(context.Background(), false) suite.checkResponse(actual, err) // make sure we got the latest header suite.Require().Equal(expected, *actual) - suite.Assert().Equal(status, flow.BlockStatusFinalized) + suite.Assert().Equal(stat, flow.BlockStatusFinalized) suite.assertAllExpectations() } @@ -1371,29 +1184,22 @@ func (suite *Suite) TestGetEventsForBlockIDs() { suite.Run("with an execution node chosen using block ID form the list of Fixed ENs", func() { // create the handler - backend := New( - suite.state, - nil, - nil, - nil, - suite.headers, - nil, - nil, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - validENIDs.Strings(), // set the fixed EN Identifiers to the generated execution IDs - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Headers: suite.headers, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + // set the fixed EN Identifiers to the generated execution IDs + FixedExecutionNodeIDs: validENIDs.Strings(), + + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + }) // execute request actual, err := backend.GetEventsForBlockIDs(ctx, string(flow.EventAccountCreated), blockIDs) @@ -1405,29 +1211,19 @@ func (suite *Suite) TestGetEventsForBlockIDs() { suite.Run("with an empty block ID list", func() { // create the handler - backend := New( - suite.state, - nil, - nil, - nil, - suite.headers, - nil, - nil, - receipts, - nil, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - validENIDs.Strings(), // set the fixed EN Identifiers to the generated execution IDs - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Headers: suite.headers, + ExecutionReceipts: receipts, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + FixedExecutionNodeIDs: validENIDs.Strings(), + Log: suite.log, + Communicator: NewNodeCommunicator(false), + }) // execute request with an empty block id list and expect an empty list of events and no error resp, err := backend.GetEventsForBlockIDs(ctx, string(flow.EventAccountCreated), []flow.Identifier{}) @@ -1464,31 +1260,20 @@ func (suite *Suite) TestGetExecutionResultByID() { Return(executionResult, nil) suite.Run("nonexisting execution result for id", func() { - - // create the handler - backend := New( - suite.state, - nil, - nil, - nil, - suite.headers, - nil, - nil, - suite.receipts, - results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - validENIDs.Strings(), // set the fixed EN Identifiers to the generated execution IDs - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Headers: suite.headers, + ExecutionReceipts: suite.receipts, + ExecutionResults: results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + FixedExecutionNodeIDs: validENIDs.Strings(), + Log: suite.log, + Communicator: NewNodeCommunicator(false), + }) // execute request _, err := backend.GetExecutionResultByID(ctx, nonexistingID) @@ -1497,30 +1282,19 @@ func (suite *Suite) TestGetExecutionResultByID() { }) suite.Run("existing execution result id", func() { - // create the handler - backend := New( - suite.state, - nil, - nil, - nil, - suite.headers, - nil, - nil, - nil, - results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - validENIDs.Strings(), // set the fixed EN Identifiers to the generated execution IDs - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Headers: suite.headers, + ExecutionResults: results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + FixedExecutionNodeIDs: validENIDs.Strings(), + Log: suite.log, + Communicator: NewNodeCommunicator(false), + }) // execute request er, err := backend.GetExecutionResultByID(ctx, executionResult.ID()) @@ -1562,30 +1336,20 @@ func (suite *Suite) TestGetExecutionResultByBlockID() { suite.Run("nonexisting execution results", func() { - // create the handler - backend := New( - suite.state, - nil, - nil, - nil, - suite.headers, - nil, - nil, - suite.receipts, - results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - validENIDs.Strings(), // set the fixed EN Identifiers to the generated execution IDs - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Headers: suite.headers, + ExecutionReceipts: suite.receipts, + ExecutionResults: results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + FixedExecutionNodeIDs: validENIDs.Strings(), + Log: suite.log, + Communicator: NewNodeCommunicator(false), + }) // execute request _, err := backend.GetExecutionResultForBlockID(ctx, nonexistingBlockID) @@ -1595,30 +1359,19 @@ func (suite *Suite) TestGetExecutionResultByBlockID() { suite.Run("existing execution results", func() { - // create the handler - backend := New( - suite.state, - nil, - nil, - nil, - suite.headers, - nil, - nil, - nil, - results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - validENIDs.Strings(), // set the fixed EN Identifiers to the generated execution IDs - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Headers: suite.headers, + ExecutionResults: results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + FixedExecutionNodeIDs: validENIDs.Strings(), + Log: suite.log, + Communicator: NewNodeCommunicator(false), + }) // execute request er, err := backend.GetExecutionResultForBlockID(ctx, blockID) @@ -1665,7 +1418,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { func(flow.IdentityFilter) error { return nil }, ) - // mock headers to pull from headers backend + // mock Headers to pull from Headers backend suite.headers.On("ByHeight", mock.Anything).Return( func(height uint64) *flow.Header { return headersDB[height] @@ -1747,30 +1500,21 @@ func (suite *Suite) TestGetEventsForHeightRange() { connFactory := suite.setupConnectionFactory() + //suite.state = state suite.Run("invalid request max height < min height", func() { - backend := New( - suite.state, - nil, - nil, - nil, - suite.headers, - nil, - nil, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Headers: suite.headers, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) _, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), maxHeight, minHeight) suite.Require().Error(err) @@ -1788,30 +1532,21 @@ func (suite *Suite) TestGetEventsForHeightRange() { expectedResp := setupExecClient() fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() - // create handler - backend := New( - state, - nil, - nil, - suite.blocks, - suite.headers, - nil, - nil, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - fixedENIdentifiersStr, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Blocks: suite.blocks, + Headers: suite.headers, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + FixedExecutionNodeIDs: fixedENIdentifiersStr, + }) // execute request actualResp, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), minHeight, maxHeight) @@ -1829,29 +1564,21 @@ func (suite *Suite) TestGetEventsForHeightRange() { expectedResp := setupExecClient() fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() - backend := New( - state, - nil, - nil, - suite.blocks, - suite.headers, - nil, - nil, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - fixedENIdentifiersStr, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Blocks: suite.blocks, + Headers: suite.headers, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + FixedExecutionNodeIDs: fixedENIdentifiersStr, + }) actualResp, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), minHeight, maxHeight) suite.checkResponse(actualResp, err) @@ -1867,30 +1594,21 @@ func (suite *Suite) TestGetEventsForHeightRange() { blockHeaders, _, nodeIdentities = setupStorage(minHeight, headHeight) fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() - // create handler - backend := New( - state, - nil, - nil, - suite.blocks, - suite.headers, - nil, - nil, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - 1, // set maximum range to 1 - nil, - fixedENIdentifiersStr, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Blocks: suite.blocks, + Headers: suite.headers, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + MaxHeightRange: 1, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + FixedExecutionNodeIDs: fixedENIdentifiersStr, + }) _, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), minHeight, minHeight+1) suite.Require().Error(err) @@ -1906,30 +1624,21 @@ func (suite *Suite) TestGetEventsForHeightRange() { blockHeaders, _, nodeIdentities = setupStorage(minHeight, maxHeight) fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() - // create handler - backend := New( - state, - nil, - nil, - suite.blocks, - suite.headers, - nil, - nil, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - fixedENIdentifiersStr, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Blocks: suite.blocks, + Headers: suite.headers, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + FixedExecutionNodeIDs: fixedENIdentifiersStr, + }) _, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), minHeight, maxHeight) suite.Require().Error(err) @@ -1985,30 +1694,20 @@ func (suite *Suite) TestGetAccount() { connFactory := new(backendmock.ConnectionFactory) connFactory.On("GetExecutionAPIClient", mock.Anything).Return(suite.execClient, &mockCloser{}, nil) - // create the handler with the mock - backend := New( - suite.state, - nil, - nil, - nil, - suite.headers, - nil, - nil, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Blocks: suite.blocks, + Headers: suite.headers, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + }) preferredENIdentifiers = flow.IdentifierList{receipts[0].ExecutorID} @@ -2037,7 +1736,7 @@ func (suite *Suite) TestGetAccountAtBlockHeight() { b := unittest.BlockFixture() h := b.Header - // setup headers storage to return the header when queried by height + // setup Headers storage to return the header when queried by height suite.headers. On("ByHeight", height). Return(h, nil). @@ -2068,30 +1767,19 @@ func (suite *Suite) TestGetAccountAtBlockHeight() { Return(exeResp, nil). Once() - // create the handler with the mock - backend := New( - suite.state, - nil, - nil, - nil, - suite.headers, - nil, - nil, - suite.receipts, - suite.results, - flow.Testnet, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Headers: suite.headers, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: flow.Testnet, + AccessMetrics: metrics.NewNoopCollector(), + ConnFactory: connFactory, + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + }) preferredENIdentifiers = flow.IdentifierList{receipts[0].ExecutorID} @@ -2110,29 +1798,14 @@ func (suite *Suite) TestGetNetworkParameters() { expectedChainID := flow.Mainnet - backend := New( - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - flow.Mainnet, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + ChainID: flow.Mainnet, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + }) params := backend.GetNetworkParameters(context.Background()) @@ -2226,7 +1899,7 @@ func (suite *Suite) TestExecutionNodesForBlockID() { } } // if we don't find sufficient receipts, executionNodesForBlockID should return a list of random ENs - suite.Run("insufficient receipts return random ENs in state", func() { + suite.Run("insufficient receipts return random ENs in State", func() { // return no receipts at all attempts attempt1Receipts = flow.ExecutionReceiptList{} attempt2Receipts = flow.ExecutionReceiptList{} @@ -2313,30 +1986,19 @@ func (suite *Suite) TestExecuteScriptOnExecutionNode() { connFactory.On("GetExecutionAPIClient", mock.Anything).Return(suite.execClient, &mockCloser{}, nil) connFactory.On("InvalidateExecutionAPIClient", mock.Anything) - // create the handler with the mock - backend := New( - suite.state, - nil, - nil, - nil, - suite.headers, - nil, - nil, - suite.receipts, - suite.results, - flow.Mainnet, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Headers: suite.headers, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: flow.Mainnet, + ConnFactory: connFactory, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + }) // mock parameters ctx := context.Background() @@ -2391,30 +2053,20 @@ func (suite *Suite) TestExecuteScriptOnArchiveNode() { archiveNode := unittest.IdentityFixture(unittest.WithRole(flow.RoleAccess)) fullArchiveAddress := archiveNode.Address + ":" + strconv.FormatUint(uint64(mockPort), 10) - // create the handler with the mock - backend := New( - suite.state, - nil, - nil, - nil, - suite.headers, - nil, - nil, - suite.receipts, - suite.results, - flow.Mainnet, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - []string{fullArchiveAddress}, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + Headers: suite.headers, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: flow.Mainnet, + ConnFactory: connFactory, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + ArchiveAddressList: []string{fullArchiveAddress}, + }) // mock parameters ctx := context.Background() @@ -2474,30 +2126,22 @@ func (suite *Suite) TestScriptExecutionValidationMode() { connFactory.On("InvalidateAccessAPIClient", mock.Anything) archiveNode := unittest.IdentityFixture(unittest.WithRole(flow.RoleAccess)) fullArchiveAddress := archiveNode.Address + ":" + strconv.FormatUint(uint64(mockPort), 10) - // create the handler with the mock - backend := New( - suite.state, - nil, - nil, - nil, - suite.headers, - nil, - nil, - suite.receipts, - suite.results, - flow.Mainnet, - metrics.NewNoopCollector(), - connFactory, // the connection factory should be used to get the execution node client - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - []string{fullArchiveAddress}, - NewNodeCommunicator(true), - true, - ) + + backend := New(BackendParams{ + State: suite.state, + Headers: suite.headers, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: flow.Mainnet, + ConnFactory: connFactory, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + ArchiveAddressList: []string{fullArchiveAddress}, + ScriptExecValidation: true, + }) // mock parameters ctx := context.Background() diff --git a/engine/access/rpc/backend/backend_transactions.go b/engine/access/rpc/backend/backend_transactions.go index d5fed8f04d6..4abe1b8e1b3 100644 --- a/engine/access/rpc/backend/backend_transactions.go +++ b/engine/access/rpc/backend/backend_transactions.go @@ -7,13 +7,6 @@ import ( "time" lru2 "github.com/hashicorp/golang-lru/v2" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" @@ -23,6 +16,12 @@ import ( "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type backendTransactions struct { @@ -95,7 +94,7 @@ func (b *backendTransactions) trySendTransaction(ctx context.Context, tx *flow.T var sendError error logAnyError := func() { if sendError != nil { - b.log.Info().Err(err).Msg("failed to send transactions to collector nodes") + b.log.Info().Err(err).Msg("failed to send Transactions to collector nodes") } } defer logAnyError() @@ -404,7 +403,7 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( i := 0 errInsufficientResults := status.Errorf( codes.Internal, - "number of transaction results returned by execution node is less than the number of transactions in the block", + "number of transaction results returned by execution node is less than the number of Transactions in the block", ) for _, guarantee := range block.Payload.Guarantees { @@ -414,7 +413,7 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( } for _, txID := range collection.Transactions { - // bounds check. this means the EN returned fewer transaction results than the transactions in the block + // bounds check. this means the EN returned fewer transaction results than the Transactions in the block if i >= len(resp.TransactionResults) { return nil, errInsufficientResults } @@ -447,8 +446,8 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( } } - // after iterating through all transactions in each collection, i equals the total number of - // user transactions in the block + // after iterating through all Transactions in each collection, i equals the total number of + // user Transactions in the block txCount := i sporkRootBlockHeight, err := b.state.Params().SporkRootBlockHeight() @@ -468,7 +467,7 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( } // otherwise there are extra results // TODO(bft): slashable offense - return nil, status.Errorf(codes.Internal, "number of transaction results returned by execution node is more than the number of transactions in the block") + return nil, status.Errorf(codes.Internal, "number of transaction results returned by execution node is more than the number of Transactions in the block") } systemTx, err := blueprints.SystemChunkTransaction(b.chainID.Chain()) @@ -501,7 +500,7 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( } // GetTransactionResultByIndex returns TransactionsResults for an index in a block that is executed, -// pending or finalized transactions return errors +// pending or finalized Transactions return errors func (b *backendTransactions) GetTransactionResultByIndex( ctx context.Context, blockID flow.Identifier, @@ -568,7 +567,7 @@ func (b *backendTransactions) deriveTransactionStatus( return flow.TransactionStatusUnknown, err } refHeight := referenceBlock.Height - // get the latest finalized block from the state + // get the latest finalized block from the State finalized, err := b.state.Final().Head() if err != nil { return flow.TransactionStatusUnknown, err @@ -581,27 +580,27 @@ func (b *backendTransactions) deriveTransactionStatus( } // At this point, we have seen the expiry block for the transaction. - // This means that, if no collections prior to the expiry block contain + // This means that, if no Collections prior to the expiry block contain // the transaction, it can never be included and is expired. // - // To ensure this, we need to have received all collections up to the + // To ensure this, we need to have received all Collections up to the // expiry block to ensure the transaction did not appear in any. // the last full height is the height where we have received all - // collections for all blocks with a lower height + // Collections for all Blocks with a lower height fullHeight, err := b.blocks.GetLastFullBlockHeight() if err != nil { return flow.TransactionStatusUnknown, err } - // if we have received collections for all blocks up to the expiry block, the transaction is expired + // if we have received Collections for all Blocks up to the expiry block, the transaction is expired if b.isExpired(refHeight, fullHeight) { return flow.TransactionStatusExpired, nil } // tx found in transaction storage and collection storage but not in block storage // However, this will not happen as of now since the ingestion engine doesn't subscribe - // for collections + // for Collections return flow.TransactionStatusPending, nil } @@ -612,7 +611,7 @@ func (b *backendTransactions) deriveTransactionStatus( // From this point on, we know for sure this transaction has at least been executed - // get the latest sealed block from the state + // get the latest sealed block from the State sealed, err := b.state.Sealed().Head() if err != nil { return flow.TransactionStatusUnknown, err @@ -711,7 +710,7 @@ func (b *backendTransactions) getHistoricalTransactionResult( } if result.GetStatus() == entities.TransactionStatus_PENDING { - // This is on a historical node. No transactions from it will ever be + // This is on a historical node. No Transactions from it will ever be // executed, therefore we should consider this expired result.Status = entities.TransactionStatus_EXPIRED } @@ -838,7 +837,7 @@ func (b *backendTransactions) getTransactionResultsByBlockIDFromAnyExeNode( var errToReturn error defer func() { - // log the errors + // Log the errors if errToReturn != nil { b.log.Err(errToReturn).Msg("failed to get transaction results from execution nodes") } diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index f5e690ddfa3..f876b5d1372 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -34,7 +34,7 @@ func (suite *Suite) WithPreConfiguredState(f func(snap protocol.Snapshot)) { epoch1, ok := epochBuilder.EpochHeights(1) require.True(suite.T(), ok) - // setup AtHeight mock returns for state + // setup AtHeight mock returns for State for _, height := range epoch1.Range() { suite.state.On("AtHeight", epoch1.Range()).Return(state.AtHeight(height)) } @@ -67,28 +67,19 @@ func (suite *Suite) TestGetTransactionResultReturnsUnknown() { Return(nil, storage.ErrNotFound) backend := New( - suite.state, - suite.colClient, - nil, - suite.blocks, - nil, - nil, - suite.transactions, - suite.receipts, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - suite.communicator, - false, - ) + BackendParams{ + State: suite.state, + CollectionRPC: suite.colClient, + Blocks: suite.blocks, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: suite.communicator, + }) res, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) suite.Require().NoError(err) suite.Require().Equal(res.Status, flow.TransactionStatusUnknown) @@ -116,28 +107,19 @@ func (suite *Suite) TestGetTransactionResultReturnsTransactionError() { suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() backend := New( - suite.state, - suite.colClient, - nil, - suite.blocks, - nil, - nil, - suite.transactions, - suite.receipts, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - suite.communicator, - false, - ) + BackendParams{ + State: suite.state, + CollectionRPC: suite.colClient, + Blocks: suite.blocks, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: suite.communicator, + }) _, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) suite.Require().Equal(err, status.Errorf(codes.Internal, "failed to find: %v", fmt.Errorf("some other error"))) @@ -175,28 +157,20 @@ func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResultFromHis Return(&transactionResultResponse, nil).Once() backend := New( - suite.state, - suite.colClient, - []access.AccessAPIClient{suite.historicalAccessClient}, - suite.blocks, - nil, - nil, - suite.transactions, - suite.receipts, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - suite.communicator, - false, - ) + BackendParams{ + State: suite.state, + CollectionRPC: suite.colClient, + HistoricalAccessNodes: []access.AccessAPIClient{suite.historicalAccessClient}, + Blocks: suite.blocks, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: suite.communicator, + }) resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) suite.Require().NoError(err) suite.Require().Equal(flow.TransactionStatusExecuted, resp.Status) @@ -239,29 +213,20 @@ func (suite *Suite) TestGetTransactionResultFromCache() { On("GetTransactionResult", mock.Anything, mock.Anything). Return(&transactionResultResponse, nil).Once() - backend := New( - suite.state, - suite.colClient, - []access.AccessAPIClient{suite.historicalAccessClient}, - suite.blocks, - nil, - nil, - suite.transactions, - suite.receipts, - nil, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - suite.communicator, - false, - ) + backend := New(BackendParams{ + State: suite.state, + CollectionRPC: suite.colClient, + HistoricalAccessNodes: []access.AccessAPIClient{suite.historicalAccessClient}, + Blocks: suite.blocks, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: suite.communicator, + }) resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) suite.Require().NoError(err) diff --git a/engine/access/rpc/backend/historical_access_test.go b/engine/access/rpc/backend/historical_access_test.go index 95496ab67c7..4109c93e94a 100644 --- a/engine/access/rpc/backend/historical_access_test.go +++ b/engine/access/rpc/backend/historical_access_test.go @@ -3,15 +3,14 @@ package backend import ( "context" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/onflow/flow-go/engine/common/rpc/convert" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" "github.com/onflow/flow-go/utils/unittest" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) // TestHistoricalTransactionResult tests to see if the historical transaction status can be retrieved @@ -36,28 +35,21 @@ func (suite *Suite) TestHistoricalTransactionResult() { Events: nil, } - backend := New(suite.state, - nil, - []accessproto.AccessAPIClient{suite.historicalAccessClient}, - suite.blocks, - suite.headers, - suite.collections, - suite.transactions, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New(BackendParams{ + State: suite.state, + HistoricalAccessNodes: []accessproto.AccessAPIClient{suite.historicalAccessClient}, + Blocks: suite.blocks, + Headers: suite.headers, + Collections: suite.collections, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) // Successfully return the transaction from the historical node suite.historicalAccessClient. @@ -96,28 +88,22 @@ func (suite *Suite) TestHistoricalTransaction() { Transaction: convert.TransactionToMessage(*transactionBody), } - backend := New(suite.state, - nil, - []accessproto.AccessAPIClient{suite.historicalAccessClient}, - suite.blocks, - suite.headers, - suite.collections, - suite.transactions, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New( + BackendParams{ + State: suite.state, + HistoricalAccessNodes: []accessproto.AccessAPIClient{suite.historicalAccessClient}, + Blocks: suite.blocks, + Headers: suite.headers, + Collections: suite.collections, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: NewNodeCommunicator(false), + }) // Successfully return the transaction from the historical node suite.historicalAccessClient. diff --git a/engine/access/rpc/backend/retry.go b/engine/access/rpc/backend/retry.go index c5765bfbbe5..5d967e657bb 100644 --- a/engine/access/rpc/backend/retry.go +++ b/engine/access/rpc/backend/retry.go @@ -10,12 +10,12 @@ import ( ) // retryFrequency has to be less than TransactionExpiry or else this module does nothing -const retryFrequency uint64 = 120 // blocks +const retryFrequency uint64 = 120 // Blocks // Retry implements a simple retry mechanism for transaction submission. type Retry struct { mu sync.RWMutex - // pending transactions + // pending Transactions transactionByReferencBlockHeight map[uint64]map[flow.Identifier]*flow.TransactionBody backend *Backend active bool @@ -47,7 +47,7 @@ func (r *Retry) Retry(height uint64) { return } - // naive cleanup for now, prune every 120 blocks + // naive cleanup for now, prune every 120 Blocks if height%retryFrequency == 0 { r.prune(height) } @@ -84,7 +84,7 @@ func (r *Retry) RegisterTransaction(height uint64, tx *flow.TransactionBody) { func (r *Retry) prune(height uint64) { r.mu.Lock() defer r.mu.Unlock() - // If height is less than the default, there will be no expired transactions + // If height is less than the default, there will be no expired Transactions if height < flow.DefaultTransactionExpiry { return } diff --git a/engine/access/rpc/backend/retry_test.go b/engine/access/rpc/backend/retry_test.go index 3f988fb2b54..63590c219b9 100644 --- a/engine/access/rpc/backend/retry_test.go +++ b/engine/access/rpc/backend/retry_test.go @@ -3,17 +3,16 @@ package backend import ( "context" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/stretchr/testify/mock" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" protocol "github.com/onflow/flow-go/state/protocol/mock" realstorage "github.com/onflow/flow-go/storage" "github.com/onflow/flow-go/utils/unittest" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) // TestTransactionRetry tests that the retry mechanism will send retries at specific times @@ -41,28 +40,24 @@ func (suite *Suite) TestTransactionRetry() { // txID := transactionBody.ID() // blockID := block.ID() // Setup Handler + Retry - backend := New(suite.state, - suite.colClient, - nil, - suite.blocks, - suite.headers, - suite.collections, - suite.transactions, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - nil, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New( + BackendParams{ + State: suite.state, + CollectionRPC: suite.colClient, + Blocks: suite.blocks, + Headers: suite.headers, + Collections: suite.collections, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + }) + retry := newRetry().SetBackend(backend).Activate() backend.retry = retry @@ -131,29 +126,25 @@ func (suite *Suite) TestSuccessfulTransactionsDontRetry() { suite.snapshot.On("Identities", mock.Anything).Return(enIDs, nil) connFactory := suite.setupConnectionFactory() - // Setup Handler + Retry - backend := New(suite.state, - suite.colClient, - nil, - suite.blocks, - suite.headers, - suite.collections, - suite.transactions, - suite.receipts, - suite.results, - suite.chainID, - metrics.NewNoopCollector(), - connFactory, - false, - DefaultMaxHeightRange, - nil, - nil, - suite.log, - DefaultSnapshotHistoryLimit, - nil, - NewNodeCommunicator(false), - false, - ) + backend := New( + BackendParams{ + State: suite.state, + CollectionRPC: suite.colClient, + Blocks: suite.blocks, + Headers: suite.headers, + Collections: suite.collections, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ExecutionResults: suite.results, + ChainID: suite.chainID, + ConnFactory: connFactory, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Log: suite.log, + Communicator: NewNodeCommunicator(false), + }) + retry := newRetry().SetBackend(backend).Activate() backend.retry = retry @@ -167,7 +158,7 @@ func (suite *Suite) TestSuccessfulTransactionsDontRetry() { result, err := backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) suite.checkResponse(result, err) - // status should be finalized since the sealed blocks is smaller in height + // status should be finalized since the sealed Blocks is smaller in height suite.Assert().Equal(flow.TransactionStatusFinalized, result.Status) // Don't retry now now that block is finalized From ed1b3b2e2283bc800b2807e83e5590b03bc749b5 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sun, 13 Aug 2023 14:44:15 +0100 Subject: [PATCH 19/66] Fix backend tests --- engine/access/rpc/backend/backend_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/access/rpc/backend/backend_test.go b/engine/access/rpc/backend/backend_test.go index 66f956f8ea1..505ba4cbc1b 100644 --- a/engine/access/rpc/backend/backend_test.go +++ b/engine/access/rpc/backend/backend_test.go @@ -1533,7 +1533,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() backend := New(BackendParams{ - State: suite.state, + State: state, Blocks: suite.blocks, Headers: suite.headers, ExecutionReceipts: suite.receipts, @@ -1565,7 +1565,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() backend := New(BackendParams{ - State: suite.state, + State: state, Blocks: suite.blocks, Headers: suite.headers, ExecutionReceipts: suite.receipts, @@ -1625,7 +1625,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() backend := New(BackendParams{ - State: suite.state, + State: state, Blocks: suite.blocks, Headers: suite.headers, ExecutionReceipts: suite.receipts, From 4cfeafcf2d9a870e829a953b9f0189edd3ce2ac8 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sun, 13 Aug 2023 14:56:33 +0100 Subject: [PATCH 20/66] Revert comment changes, rename colliding status variable name --- engine/access/rpc/backend/backend.go | 6 ++-- .../rpc/backend/backend_block_details.go | 34 +++++++++---------- engine/access/rpc/backend/backend_events.go | 10 +++--- engine/access/rpc/backend/backend_network.go | 4 +-- engine/access/rpc/backend/backend_scripts.go | 6 ++-- .../rpc/backend/backend_transactions.go | 32 ++++++++--------- 6 files changed, 46 insertions(+), 46 deletions(-) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 8df05d04c8b..93b983c8afb 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -332,7 +332,7 @@ func (b *Backend) GetCollectionByID(_ context.Context, colID flow.Identifier) (* // retrieve the collection from the collection storage col, err := b.collections.LightByID(colID) if err != nil { - // Collections are retrieved asynchronously as we finalize Blocks, so + // Collections are retrieved asynchronously as we finalize blocks, so // it is possible for a client to request a finalized block from us // containing some collection, then get a not found error when requesting // that collection. These clients should retry. @@ -398,7 +398,7 @@ func executionNodesForBlockID( break } - // Log the attempt + // log the attempt log.Debug().Int("attempt", attempt).Int("max_attempt", maxAttemptsForExecutionReceipt). Int("execution_receipts_found", len(executorIDs)). Str("block_id", blockID.String()). @@ -472,7 +472,7 @@ func findAllExecutionNodes( } } - // if there are more than one execution result for the same block ID, Log as error + // if there are more than one execution result for the same block ID, log as error if executionResultGroupedMetaList.NumberGroups() > 1 { identicalReceiptsStr := fmt.Sprintf("%v", flow.GetIDs(allReceipts)) log.Error(). diff --git a/engine/access/rpc/backend/backend_block_details.go b/engine/access/rpc/backend/backend_block_details.go index 1398eda7a77..d9c4c913b40 100644 --- a/engine/access/rpc/backend/backend_block_details.go +++ b/engine/access/rpc/backend/backend_block_details.go @@ -24,21 +24,21 @@ func (b *backendBlockDetails) GetLatestBlock(_ context.Context, isSealed bool) ( // get the latest seal header from storage header, err = b.state.Sealed().Head() } else { - // get the finalized header from State + // get the finalized header from state header, err = b.state.Final().Head() } if err != nil { // node should always have the latest block - // In the RPC engine, if we encounter an error from the protocol State indicating State corruption, + // In the RPC engine, if we encounter an error from the protocol state indicating state corruption, // we should halt processing requests, but do throw an exception which might cause a crash: - // - It is unsafe to process requests if we have an internally bad State. + // - It is unsafe to process requests if we have an internally bad state. // TODO: https://github.com/onflow/flow-go/issues/4028 // - We would like to avoid throwing an exception as a result of an Access API request by policy // because this can cause DOS potential - // - Since the protocol State is widely shared, we assume that in practice another component will - // observe the protocol State error and throw an exception. + // - Since the protocol state is widely shared, we assume that in practice another component will + // observe the protocol state error and throw an exception. return nil, flow.BlockStatusUnknown, status.Errorf(codes.Internal, "could not get latest block: %v", err) } @@ -48,11 +48,11 @@ func (b *backendBlockDetails) GetLatestBlock(_ context.Context, isSealed bool) ( return nil, flow.BlockStatusUnknown, status.Errorf(codes.Internal, "could not get latest block: %v", err) } - status, err := b.getBlockStatus(block) + stat, err := b.getBlockStatus(block) if err != nil { - return nil, status, err + return nil, stat, err } - return block, status, nil + return block, stat, nil } func (b *backendBlockDetails) GetBlockByID(_ context.Context, id flow.Identifier) (*flow.Block, flow.BlockStatus, error) { @@ -61,11 +61,11 @@ func (b *backendBlockDetails) GetBlockByID(_ context.Context, id flow.Identifier return nil, flow.BlockStatusUnknown, rpc.ConvertStorageError(err) } - status, err := b.getBlockStatus(block) + stat, err := b.getBlockStatus(block) if err != nil { - return nil, status, err + return nil, stat, err } - return block, status, nil + return block, stat, nil } func (b *backendBlockDetails) GetBlockByHeight(_ context.Context, height uint64) (*flow.Block, flow.BlockStatus, error) { @@ -74,24 +74,24 @@ func (b *backendBlockDetails) GetBlockByHeight(_ context.Context, height uint64) return nil, flow.BlockStatusUnknown, rpc.ConvertStorageError(err) } - status, err := b.getBlockStatus(block) + stat, err := b.getBlockStatus(block) if err != nil { - return nil, status, err + return nil, stat, err } - return block, status, nil + return block, stat, nil } func (b *backendBlockDetails) getBlockStatus(block *flow.Block) (flow.BlockStatus, error) { sealed, err := b.state.Sealed().Head() if err != nil { - // In the RPC engine, if we encounter an error from the protocol State indicating State corruption, + // In the RPC engine, if we encounter an error from the protocol state indicating state corruption, // we should halt processing requests, but do throw an exception which might cause a crash: // - It is unsafe to process requests if we have an internally bad State. // TODO: https://github.com/onflow/flow-go/issues/4028 // - We would like to avoid throwing an exception as a result of an Access API request by policy // because this can cause DOS potential - // - Since the protocol State is widely shared, we assume that in practice another component will - // observe the protocol State error and throw an exception. + // - Since the protocol state is widely shared, we assume that in practice another component will + // observe the protocol state error and throw an exception. return flow.BlockStatusUnknown, status.Errorf(codes.Internal, "failed to find latest sealed header: %v", err) } diff --git a/engine/access/rpc/backend/backend_events.go b/engine/access/rpc/backend/backend_events.go index a151e138740..4038e21d922 100644 --- a/engine/access/rpc/backend/backend_events.go +++ b/engine/access/rpc/backend/backend_events.go @@ -29,7 +29,7 @@ type backendEvents struct { nodeCommunicator Communicator } -// GetEventsForHeightRange retrieves events for all sealed Blocks between the start block height and +// GetEventsForHeightRange retrieves events for all sealed blocks between the start block height and // the end block height (inclusive) that have the given type. func (b *backendEvents) GetEventsForHeightRange( ctx context.Context, @@ -64,7 +64,7 @@ func (b *backendEvents) GetEventsForHeightRange( endHeight = head.Height } - // find the block Headers for all the Blocks between min and max height (inclusive) + // find the block headers for all the blocks between min and max height (inclusive) blockHeaders := make([]*flow.Header, 0) for i := startHeight; i <= endHeight; i++ { @@ -90,7 +90,7 @@ func (b *backendEvents) GetEventsForBlockIDs( return nil, status.Errorf(codes.InvalidArgument, "requested block range (%d) exceeded maximum (%d)", len(blockIDs), b.maxHeightRange) } - // find the block Headers for all the block IDs + // find the block headers for all the block IDs blockHeaders := make([]*flow.Header, 0) for _, blockID := range blockIDs { header, err := b.headers.ByBlockID(blockID) @@ -164,7 +164,7 @@ func verifyAndConvertToAccessEvents( version execproto.EventEncodingVersion, ) ([]flow.BlockEvents, error) { if len(execEvents) != len(requestedBlockHeaders) { - return nil, errors.New("number of results does not match number of Blocks requested") + return nil, errors.New("number of results does not match number of blocks requested") } requestedBlockHeaderSet := map[string]*flow.Header{} @@ -222,7 +222,7 @@ func (b *backendEvents) getEventsFromAnyExeNode(ctx context.Context, logger := b.log.With(). Str("execution_node", node.String()). Str("event", req.GetType()). - Int("Blocks", len(req.BlockIds)). + Int("blocks", len(req.BlockIds)). Int64("rtt_ms", duration.Milliseconds()). Logger() diff --git a/engine/access/rpc/backend/backend_network.go b/engine/access/rpc/backend/backend_network.go index ebb80bd65e8..23d9c602649 100644 --- a/engine/access/rpc/backend/backend_network.go +++ b/engine/access/rpc/backend/backend_network.go @@ -84,8 +84,8 @@ func (b *backendNetwork) isEpochOrPhaseDifferent(counter1, counter2 uint64, phas } // getValidSnapshot will return a valid snapshot that has a sealing segment which -// 1. does not contain any Blocks that span an epoch transition -// 2. does not contain any Blocks that span an epoch phase transition +// 1. does not contain any blocks that span an epoch transition +// 2. does not contain any blocks that span an epoch phase transition // If a snapshot does contain an invalid sealing segment query the state // by height of each block in the segment and return a snapshot at the point // where the transition happens. diff --git a/engine/access/rpc/backend/backend_scripts.go b/engine/access/rpc/backend/backend_scripts.go index 97b9b3f3f1d..ba48b9cff04 100644 --- a/engine/access/rpc/backend/backend_scripts.go +++ b/engine/access/rpc/backend/backend_scripts.go @@ -199,7 +199,7 @@ func (b *backendScripts) executeScriptOnAvailableArchiveNodes( rnPort := b.archivePorts[idx] result, err := b.tryExecuteScriptOnArchiveNode(ctx, rnAddr, rnPort, blockID, script, arguments) if err == nil { - // Log execution time + // log execution time b.metrics.ScriptExecuted( time.Since(startTime), len(script), @@ -218,7 +218,7 @@ func (b *backendScripts) executeScriptOnAvailableArchiveNodes( Msg("script failed to execute on the execution node") return nil, err case codes.NotFound: - // failures due to unavailable Blocks are explicitly marked Not found + // failures due to unavailable blocks are explicitly marked Not found b.metrics.ScriptExecutionErrorOnArchiveNode() b.log.Error().Err(err).Msg("script execution failed for archive node") return nil, err @@ -269,7 +269,7 @@ func (b *backendScripts) executeScriptOnAvailableExecutionNodes( } } - // Log execution time + // log execution time b.metrics.ScriptExecuted( time.Since(execStartTime), len(script), diff --git a/engine/access/rpc/backend/backend_transactions.go b/engine/access/rpc/backend/backend_transactions.go index 4abe1b8e1b3..f51d90e490f 100644 --- a/engine/access/rpc/backend/backend_transactions.go +++ b/engine/access/rpc/backend/backend_transactions.go @@ -94,7 +94,7 @@ func (b *backendTransactions) trySendTransaction(ctx context.Context, tx *flow.T var sendError error logAnyError := func() { if sendError != nil { - b.log.Info().Err(err).Msg("failed to send Transactions to collector nodes") + b.log.Info().Err(err).Msg("failed to send transactions to collector nodes") } } defer logAnyError() @@ -403,7 +403,7 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( i := 0 errInsufficientResults := status.Errorf( codes.Internal, - "number of transaction results returned by execution node is less than the number of Transactions in the block", + "number of transaction results returned by execution node is less than the number of transactions in the block", ) for _, guarantee := range block.Payload.Guarantees { @@ -413,7 +413,7 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( } for _, txID := range collection.Transactions { - // bounds check. this means the EN returned fewer transaction results than the Transactions in the block + // bounds check. this means the EN returned fewer transaction results than the transactions in the block if i >= len(resp.TransactionResults) { return nil, errInsufficientResults } @@ -446,8 +446,8 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( } } - // after iterating through all Transactions in each collection, i equals the total number of - // user Transactions in the block + // after iterating through all transactions in each collection, i equals the total number of + // user transactions in the block txCount := i sporkRootBlockHeight, err := b.state.Params().SporkRootBlockHeight() @@ -467,7 +467,7 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( } // otherwise there are extra results // TODO(bft): slashable offense - return nil, status.Errorf(codes.Internal, "number of transaction results returned by execution node is more than the number of Transactions in the block") + return nil, status.Errorf(codes.Internal, "number of transaction results returned by execution node is more than the number of transactions in the block") } systemTx, err := blueprints.SystemChunkTransaction(b.chainID.Chain()) @@ -499,8 +499,8 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( return results, nil } -// GetTransactionResultByIndex returns TransactionsResults for an index in a block that is executed, -// pending or finalized Transactions return errors +// GetTransactionResultByIndex returns transactions Results for an index in a block that is executed, +// pending or finalized transactions return errors func (b *backendTransactions) GetTransactionResultByIndex( ctx context.Context, blockID flow.Identifier, @@ -567,7 +567,7 @@ func (b *backendTransactions) deriveTransactionStatus( return flow.TransactionStatusUnknown, err } refHeight := referenceBlock.Height - // get the latest finalized block from the State + // get the latest finalized block from the state finalized, err := b.state.Final().Head() if err != nil { return flow.TransactionStatusUnknown, err @@ -580,27 +580,27 @@ func (b *backendTransactions) deriveTransactionStatus( } // At this point, we have seen the expiry block for the transaction. - // This means that, if no Collections prior to the expiry block contain + // This means that, if no collections prior to the expiry block contain // the transaction, it can never be included and is expired. // - // To ensure this, we need to have received all Collections up to the + // To ensure this, we need to have received all collections up to the // expiry block to ensure the transaction did not appear in any. // the last full height is the height where we have received all - // Collections for all Blocks with a lower height + // collections for all blocks with a lower height fullHeight, err := b.blocks.GetLastFullBlockHeight() if err != nil { return flow.TransactionStatusUnknown, err } - // if we have received Collections for all Blocks up to the expiry block, the transaction is expired + // if we have received collections for all blocks up to the expiry block, the transaction is expired if b.isExpired(refHeight, fullHeight) { return flow.TransactionStatusExpired, nil } // tx found in transaction storage and collection storage but not in block storage // However, this will not happen as of now since the ingestion engine doesn't subscribe - // for Collections + // for collections return flow.TransactionStatusPending, nil } @@ -710,7 +710,7 @@ func (b *backendTransactions) getHistoricalTransactionResult( } if result.GetStatus() == entities.TransactionStatus_PENDING { - // This is on a historical node. No Transactions from it will ever be + // This is on a historical node. No transactions from it will ever be // executed, therefore we should consider this expired result.Status = entities.TransactionStatus_EXPIRED } @@ -837,7 +837,7 @@ func (b *backendTransactions) getTransactionResultsByBlockIDFromAnyExeNode( var errToReturn error defer func() { - // Log the errors + // log the errors if errToReturn != nil { b.log.Err(errToReturn).Msg("failed to get transaction results from execution nodes") } From fef906c607a0f03071c132c00f907a6829928abf Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sun, 13 Aug 2023 15:08:06 +0100 Subject: [PATCH 21/66] Revert comment changes, rename colliding status variable --- engine/access/rpc/backend/backend.go | 2 +- .../rpc/backend/backend_block_details.go | 2 +- .../rpc/backend/backend_block_headers.go | 28 +++++++++---------- engine/access/rpc/backend/backend_events.go | 4 +-- engine/access/rpc/backend/backend_scripts.go | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 93b983c8afb..63944a57a2d 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -35,7 +35,7 @@ const maxAttemptsForExecutionReceipt = 3 // DefaultMaxHeightRange is the default maximum size of range requests. const DefaultMaxHeightRange = 250 -// DefaultSnapshotHistoryLimit the amount of Blocks to look back in State +// DefaultSnapshotHistoryLimit the amount of blocks to look back in state // when recursively searching for a valid snapshot const DefaultSnapshotHistoryLimit = 50 diff --git a/engine/access/rpc/backend/backend_block_details.go b/engine/access/rpc/backend/backend_block_details.go index d9c4c913b40..9cf366736e1 100644 --- a/engine/access/rpc/backend/backend_block_details.go +++ b/engine/access/rpc/backend/backend_block_details.go @@ -86,7 +86,7 @@ func (b *backendBlockDetails) getBlockStatus(block *flow.Block) (flow.BlockStatu if err != nil { // In the RPC engine, if we encounter an error from the protocol state indicating state corruption, // we should halt processing requests, but do throw an exception which might cause a crash: - // - It is unsafe to process requests if we have an internally bad State. + // - It is unsafe to process requests if we have an internally bad state. // TODO: https://github.com/onflow/flow-go/issues/4028 // - We would like to avoid throwing an exception as a result of an Access API request by policy // because this can cause DOS potential diff --git a/engine/access/rpc/backend/backend_block_headers.go b/engine/access/rpc/backend/backend_block_headers.go index 10efb30c6a2..9e3f7354e89 100644 --- a/engine/access/rpc/backend/backend_block_headers.go +++ b/engine/access/rpc/backend/backend_block_headers.go @@ -24,28 +24,28 @@ func (b *backendBlockHeaders) GetLatestBlockHeader(_ context.Context, isSealed b // get the latest seal header from storage header, err = b.state.Sealed().Head() } else { - // get the finalized header from State + // get the finalized header from state header, err = b.state.Final().Head() } if err != nil { // node should always have the latest block - // In the RPC engine, if we encounter an error from the protocol State indicating State corruption, + // In the RPC engine, if we encounter an error from the protocol state indicating state corruption, // we should halt processing requests, but do throw an exception which might cause a crash: - // - It is unsafe to process requests if we have an internally bad State. + // - It is unsafe to process requests if we have an internally bad state. // TODO: https://github.com/onflow/flow-go/issues/4028 // - We would like to avoid throwing an exception as a result of an Access API request by policy // because this can cause DOS potential - // - Since the protocol State is widely shared, we assume that in practice another component will - // observe the protocol State error and throw an exception. + // - Since the protocol state is widely shared, we assume that in practice another component will + // observe the protocol state error and throw an exception. return nil, flow.BlockStatusUnknown, status.Errorf(codes.Internal, "could not get latest block header: %v", err) } - status, err := b.getBlockStatus(header) + stat, err := b.getBlockStatus(header) if err != nil { - return nil, status, err + return nil, stat, err } - return header, status, nil + return header, stat, nil } func (b *backendBlockHeaders) GetBlockHeaderByID(_ context.Context, id flow.Identifier) (*flow.Header, flow.BlockStatus, error) { @@ -54,11 +54,11 @@ func (b *backendBlockHeaders) GetBlockHeaderByID(_ context.Context, id flow.Iden return nil, flow.BlockStatusUnknown, rpc.ConvertStorageError(err) } - status, err := b.getBlockStatus(header) + stat, err := b.getBlockStatus(header) if err != nil { - return nil, status, err + return nil, stat, err } - return header, status, nil + return header, stat, nil } func (b *backendBlockHeaders) GetBlockHeaderByHeight(_ context.Context, height uint64) (*flow.Header, flow.BlockStatus, error) { @@ -67,11 +67,11 @@ func (b *backendBlockHeaders) GetBlockHeaderByHeight(_ context.Context, height u return nil, flow.BlockStatusUnknown, rpc.ConvertStorageError(err) } - status, err := b.getBlockStatus(header) + stat, err := b.getBlockStatus(header) if err != nil { - return nil, status, err + return nil, stat, err } - return header, status, nil + return header, stat, nil } func (b *backendBlockHeaders) getBlockStatus(header *flow.Header) (flow.BlockStatus, error) { diff --git a/engine/access/rpc/backend/backend_events.go b/engine/access/rpc/backend/backend_events.go index 4038e21d922..c19d43846a5 100644 --- a/engine/access/rpc/backend/backend_events.go +++ b/engine/access/rpc/backend/backend_events.go @@ -64,7 +64,7 @@ func (b *backendEvents) GetEventsForHeightRange( endHeight = head.Height } - // find the block headers for all the blocks between min and max height (inclusive) + // find the block headers for all the blocks between min and max height (inclusive) blockHeaders := make([]*flow.Header, 0) for i := startHeight; i <= endHeight; i++ { @@ -90,7 +90,7 @@ func (b *backendEvents) GetEventsForBlockIDs( return nil, status.Errorf(codes.InvalidArgument, "requested block range (%d) exceeded maximum (%d)", len(blockIDs), b.maxHeightRange) } - // find the block headers for all the block IDs + // find the block headers for all the block IDs blockHeaders := make([]*flow.Header, 0) for _, blockID := range blockIDs { header, err := b.headers.ByBlockID(blockID) diff --git a/engine/access/rpc/backend/backend_scripts.go b/engine/access/rpc/backend/backend_scripts.go index ba48b9cff04..e98a95b5d8a 100644 --- a/engine/access/rpc/backend/backend_scripts.go +++ b/engine/access/rpc/backend/backend_scripts.go @@ -168,7 +168,7 @@ func (b *backendScripts) logScriptExecutionComparison( archiveError error, msg string, ) { - // over-Log for ease of debug + // over-log for ease of debug if executionError != nil || archiveError != nil { b.log.Debug().Hex("block_id", blockID[:]). Str("script", string(script)). From 5b31bfa7effdfba8ec118dc7251e7e944c2c79d2 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sun, 13 Aug 2023 15:09:50 +0100 Subject: [PATCH 22/66] Rename Backend constructor params structure --- .../node_builder/access_node_builder.go | 2 +- engine/access/rpc/backend/backend.go | 4 +- engine/access/rpc/backend/backend_test.go | 68 +++++++++---------- .../rpc/backend/backend_transactions_test.go | 8 +-- .../rpc/backend/historical_access_test.go | 4 +- engine/access/rpc/backend/retry_test.go | 6 +- 6 files changed, 46 insertions(+), 46 deletions(-) diff --git a/cmd/access/node_builder/access_node_builder.go b/cmd/access/node_builder/access_node_builder.go index b68d2ce5da9..35cbcd58774 100644 --- a/cmd/access/node_builder/access_node_builder.go +++ b/cmd/access/node_builder/access_node_builder.go @@ -1089,7 +1089,7 @@ func (builder *FlowAccessNodeBuilder) Build() (cmd.Node, error) { ), } - bnd := backend.New(backend.BackendParams{ + bnd := backend.New(backend.Params{ State: node.State, CollectionRPC: builder.CollectionRPC, HistoricalAccessNodes: builder.HistoricalAccessRPCs, diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 63944a57a2d..561c1283a8b 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -100,7 +100,7 @@ type Communicator interface { ) error } -type BackendParams struct { +type Params struct { State protocol.State CollectionRPC accessproto.AccessAPIClient HistoricalAccessNodes []accessproto.AccessAPIClient @@ -125,7 +125,7 @@ type BackendParams struct { } // New creates backend instance -func New(params BackendParams) *Backend { +func New(params Params) *Backend { retry := newRetry() if params.RetryEnabled { retry.Activate() diff --git a/engine/access/rpc/backend/backend_test.go b/engine/access/rpc/backend/backend_test.go index 505ba4cbc1b..796e55c150a 100644 --- a/engine/access/rpc/backend/backend_test.go +++ b/engine/access/rpc/backend/backend_test.go @@ -96,7 +96,7 @@ func (suite *Suite) TestPing() { On("Ping", mock.Anything, &execproto.PingRequest{}). Return(&execproto.PingResponse{}, nil) - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, CollectionRPC: suite.colClient, ChainID: suite.chainID, @@ -121,7 +121,7 @@ func (suite *Suite) TestGetLatestFinalizedBlockHeader() { suite.snapshot.On("Head").Return(block, nil).Once() backend := New( - BackendParams{ + Params{ State: suite.state, ChainID: suite.chainID, AccessMetrics: metrics.NewNoopCollector(), @@ -174,7 +174,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_NoTransitionSpan() { snap := state.AtHeight(epoch1.Range()[2]) suite.state.On("Final").Return(snap).Once() - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, ChainID: suite.chainID, AccessMetrics: metrics.NewNoopCollector(), @@ -235,7 +235,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_TransitionSpans() { suite.state.On("Final").Return(snap).Once() backend := New( - BackendParams{ + Params{ State: suite.state, ChainID: suite.chainID, AccessMetrics: metrics.NewNoopCollector(), @@ -288,7 +288,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan() { snap := state.AtHeight(epoch1.Range()[3]) suite.state.On("Final").Return(snap).Once() - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, ChainID: suite.chainID, AccessMetrics: metrics.NewNoopCollector(), @@ -352,7 +352,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_EpochTransitionSpan() { snap := state.AtHeight(epoch2.Range()[0]) suite.state.On("Final").Return(snap).Once() - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, ChainID: suite.chainID, AccessMetrics: metrics.NewNoopCollector(), @@ -400,7 +400,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_HistoryLimit() { // very short history limit, any segment with any Blocks spanning any transition should force the endpoint to return a history limit error snapshotHistoryLimit := 1 - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, ChainID: suite.chainID, AccessMetrics: metrics.NewNoopCollector(), @@ -426,7 +426,7 @@ func (suite *Suite) TestGetLatestSealedBlockHeader() { suite.state.On("Sealed").Return(suite.snapshot, nil) suite.snapshot.On("Head").Return(block, nil).Once() - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, ChainID: suite.chainID, AccessMetrics: metrics.NewNoopCollector(), @@ -460,7 +460,7 @@ func (suite *Suite) TestGetTransaction() { Return(&expected, nil). Once() - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Transactions: suite.transactions, ChainID: suite.chainID, @@ -489,7 +489,7 @@ func (suite *Suite) TestGetCollection() { Return(&expected, nil). Once() - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Collections: suite.collections, Transactions: suite.transactions, @@ -542,7 +542,7 @@ func (suite *Suite) TestGetTransactionResultByIndex() { Events: nil, } - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Blocks: suite.blocks, Headers: suite.headers, @@ -603,7 +603,7 @@ func (suite *Suite) TestGetTransactionResultsByBlockID() { TransactionResults: []*execproto.GetTransactionResultResponse{{}}, } - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Blocks: suite.blocks, Headers: suite.headers, @@ -692,7 +692,7 @@ func (suite *Suite) TestTransactionStatusTransition() { Events: nil, } - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Blocks: suite.blocks, Headers: suite.headers, @@ -809,7 +809,7 @@ func (suite *Suite) TestTransactionExpiredStatusTransition() { txID := transactionBody.ID() - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Blocks: suite.blocks, Headers: suite.headers, @@ -969,7 +969,7 @@ func (suite *Suite) TestTransactionPendingToFinalizedStatusTransition() { // create a mock connection factory connFactory := suite.setupConnectionFactory() - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Blocks: suite.blocks, Headers: suite.headers, @@ -1022,7 +1022,7 @@ func (suite *Suite) TestTransactionResultUnknown() { On("ByID", txID). Return(nil, storage.ErrNotFound) - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Transactions: suite.transactions, ChainID: suite.chainID, @@ -1065,7 +1065,7 @@ func (suite *Suite) TestGetLatestFinalizedBlock() { On("ByHeight", header.Height). Return(&expected, nil) - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Blocks: suite.blocks, ChainID: suite.chainID, @@ -1184,7 +1184,7 @@ func (suite *Suite) TestGetEventsForBlockIDs() { suite.Run("with an execution node chosen using block ID form the list of Fixed ENs", func() { // create the handler - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Headers: suite.headers, ExecutionReceipts: suite.receipts, @@ -1211,7 +1211,7 @@ func (suite *Suite) TestGetEventsForBlockIDs() { suite.Run("with an empty block ID list", func() { // create the handler - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Headers: suite.headers, ExecutionReceipts: receipts, @@ -1260,7 +1260,7 @@ func (suite *Suite) TestGetExecutionResultByID() { Return(executionResult, nil) suite.Run("nonexisting execution result for id", func() { - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Headers: suite.headers, ExecutionReceipts: suite.receipts, @@ -1282,7 +1282,7 @@ func (suite *Suite) TestGetExecutionResultByID() { }) suite.Run("existing execution result id", func() { - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Headers: suite.headers, ExecutionResults: results, @@ -1336,7 +1336,7 @@ func (suite *Suite) TestGetExecutionResultByBlockID() { suite.Run("nonexisting execution results", func() { - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Headers: suite.headers, ExecutionReceipts: suite.receipts, @@ -1359,7 +1359,7 @@ func (suite *Suite) TestGetExecutionResultByBlockID() { suite.Run("existing execution results", func() { - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Headers: suite.headers, ExecutionResults: results, @@ -1502,7 +1502,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { //suite.state = state suite.Run("invalid request max height < min height", func() { - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Headers: suite.headers, ExecutionReceipts: suite.receipts, @@ -1532,7 +1532,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { expectedResp := setupExecClient() fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() - backend := New(BackendParams{ + backend := New(Params{ State: state, Blocks: suite.blocks, Headers: suite.headers, @@ -1564,7 +1564,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { expectedResp := setupExecClient() fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() - backend := New(BackendParams{ + backend := New(Params{ State: state, Blocks: suite.blocks, Headers: suite.headers, @@ -1594,7 +1594,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { blockHeaders, _, nodeIdentities = setupStorage(minHeight, headHeight) fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Blocks: suite.blocks, Headers: suite.headers, @@ -1624,7 +1624,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { blockHeaders, _, nodeIdentities = setupStorage(minHeight, maxHeight) fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() - backend := New(BackendParams{ + backend := New(Params{ State: state, Blocks: suite.blocks, Headers: suite.headers, @@ -1694,7 +1694,7 @@ func (suite *Suite) TestGetAccount() { connFactory := new(backendmock.ConnectionFactory) connFactory.On("GetExecutionAPIClient", mock.Anything).Return(suite.execClient, &mockCloser{}, nil) - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Blocks: suite.blocks, Headers: suite.headers, @@ -1767,7 +1767,7 @@ func (suite *Suite) TestGetAccountAtBlockHeight() { Return(exeResp, nil). Once() - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Headers: suite.headers, ExecutionReceipts: suite.receipts, @@ -1798,7 +1798,7 @@ func (suite *Suite) TestGetNetworkParameters() { expectedChainID := flow.Mainnet - backend := New(BackendParams{ + backend := New(Params{ ChainID: flow.Mainnet, AccessMetrics: metrics.NewNoopCollector(), MaxHeightRange: DefaultMaxHeightRange, @@ -1986,7 +1986,7 @@ func (suite *Suite) TestExecuteScriptOnExecutionNode() { connFactory.On("GetExecutionAPIClient", mock.Anything).Return(suite.execClient, &mockCloser{}, nil) connFactory.On("InvalidateExecutionAPIClient", mock.Anything) - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Headers: suite.headers, ExecutionReceipts: suite.receipts, @@ -2053,7 +2053,7 @@ func (suite *Suite) TestExecuteScriptOnArchiveNode() { archiveNode := unittest.IdentityFixture(unittest.WithRole(flow.RoleAccess)) fullArchiveAddress := archiveNode.Address + ":" + strconv.FormatUint(uint64(mockPort), 10) - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Headers: suite.headers, ExecutionReceipts: suite.receipts, @@ -2127,7 +2127,7 @@ func (suite *Suite) TestScriptExecutionValidationMode() { archiveNode := unittest.IdentityFixture(unittest.WithRole(flow.RoleAccess)) fullArchiveAddress := archiveNode.Address + ":" + strconv.FormatUint(uint64(mockPort), 10) - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, Headers: suite.headers, ExecutionReceipts: suite.receipts, diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index f876b5d1372..bbc708423d7 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -67,7 +67,7 @@ func (suite *Suite) TestGetTransactionResultReturnsUnknown() { Return(nil, storage.ErrNotFound) backend := New( - BackendParams{ + Params{ State: suite.state, CollectionRPC: suite.colClient, Blocks: suite.blocks, @@ -107,7 +107,7 @@ func (suite *Suite) TestGetTransactionResultReturnsTransactionError() { suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() backend := New( - BackendParams{ + Params{ State: suite.state, CollectionRPC: suite.colClient, Blocks: suite.blocks, @@ -157,7 +157,7 @@ func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResultFromHis Return(&transactionResultResponse, nil).Once() backend := New( - BackendParams{ + Params{ State: suite.state, CollectionRPC: suite.colClient, HistoricalAccessNodes: []access.AccessAPIClient{suite.historicalAccessClient}, @@ -213,7 +213,7 @@ func (suite *Suite) TestGetTransactionResultFromCache() { On("GetTransactionResult", mock.Anything, mock.Anything). Return(&transactionResultResponse, nil).Once() - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, CollectionRPC: suite.colClient, HistoricalAccessNodes: []access.AccessAPIClient{suite.historicalAccessClient}, diff --git a/engine/access/rpc/backend/historical_access_test.go b/engine/access/rpc/backend/historical_access_test.go index 4109c93e94a..3bacb44b4d8 100644 --- a/engine/access/rpc/backend/historical_access_test.go +++ b/engine/access/rpc/backend/historical_access_test.go @@ -35,7 +35,7 @@ func (suite *Suite) TestHistoricalTransactionResult() { Events: nil, } - backend := New(BackendParams{ + backend := New(Params{ State: suite.state, HistoricalAccessNodes: []accessproto.AccessAPIClient{suite.historicalAccessClient}, Blocks: suite.blocks, @@ -89,7 +89,7 @@ func (suite *Suite) TestHistoricalTransaction() { } backend := New( - BackendParams{ + Params{ State: suite.state, HistoricalAccessNodes: []accessproto.AccessAPIClient{suite.historicalAccessClient}, Blocks: suite.blocks, diff --git a/engine/access/rpc/backend/retry_test.go b/engine/access/rpc/backend/retry_test.go index 63590c219b9..54b13ab4c89 100644 --- a/engine/access/rpc/backend/retry_test.go +++ b/engine/access/rpc/backend/retry_test.go @@ -41,7 +41,7 @@ func (suite *Suite) TestTransactionRetry() { // blockID := block.ID() // Setup Handler + Retry backend := New( - BackendParams{ + Params{ State: suite.state, CollectionRPC: suite.colClient, Blocks: suite.blocks, @@ -127,7 +127,7 @@ func (suite *Suite) TestSuccessfulTransactionsDontRetry() { connFactory := suite.setupConnectionFactory() backend := New( - BackendParams{ + Params{ State: suite.state, CollectionRPC: suite.colClient, Blocks: suite.blocks, @@ -144,7 +144,7 @@ func (suite *Suite) TestSuccessfulTransactionsDontRetry() { Log: suite.log, Communicator: NewNodeCommunicator(false), }) - + retry := newRetry().SetBackend(backend).Activate() backend.retry = retry From ae8ccaa861d4bf23a416e69f60cedbe2bce3faf4 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sun, 13 Aug 2023 15:15:19 +0100 Subject: [PATCH 23/66] Introduce TxResultCacheParam for configuration --- engine/access/rpc/backend/backend.go | 10 +++++++--- .../rpc/backend/backend_transactions.go | 19 +++++++++++-------- .../rpc/backend/backend_transactions_test.go | 1 + 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 561c1283a8b..567f522456b 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -122,6 +122,7 @@ type Params struct { ArchiveAddressList []string Communicator Communicator ScriptExecValidation bool + TxResultCacheSize int } // New creates backend instance @@ -145,9 +146,12 @@ func New(params Params) *Backend { archivePorts[idx] = port } - txResCache, err := lru2.New[flow.Identifier, *access.TransactionResult](int(badger.DefaultCacheSize)) - if err != nil { - params.Log.Fatal().Err(err).Msg("failed to init cache for transaction results") + var txResCache *lru2.Cache[flow.Identifier, *access.TransactionResult] + if params.TxResultCacheSize > 0 { + txResCache, err = lru2.New[flow.Identifier, *access.TransactionResult](params.TxResultCacheSize) + if err != nil { + params.Log.Fatal().Err(err).Msg("failed to init cache for transaction results") + } } b := &Backend{ diff --git a/engine/access/rpc/backend/backend_transactions.go b/engine/access/rpc/backend/backend_transactions.go index f51d90e490f..7104928f8f0 100644 --- a/engine/access/rpc/backend/backend_transactions.go +++ b/engine/access/rpc/backend/backend_transactions.go @@ -236,10 +236,11 @@ func (b *backendTransactions) GetTransactionResult( txErr := rpc.ConvertStorageError(err) if status.Code(txErr) == codes.NotFound { // Tx not found. If we have historical Sporks setup, lets look through those as well - - val, ok := b.txResultCache.Get(txID) - if ok { - return val, nil + if b.txResultCache != nil { + val, ok := b.txResultCache.Get(txID) + if ok { + return val, nil + } } historicalTxResult, err := b.getHistoricalTransactionResult(ctx, txID) if err != nil { @@ -251,8 +252,10 @@ func (b *backendTransactions) GetTransactionResult( StatusCode: uint(txStatus), }, nil } - - b.txResultCache.Add(txID, historicalTxResult) + + if b.txResultCache != nil { + b.txResultCache.Add(txID, historicalTxResult) + } return historicalTxResult, nil } return nil, txErr @@ -348,8 +351,8 @@ func (b *backendTransactions) lookupCollectionIDInBlock( // followed by the collection ID lookup. If both are missing, the default lookup by transaction ID is performed. func (b *backendTransactions) retrieveBlock( - // the requested block or collection was not found. If looking up the block based solely on the txID returns - // not found, then no error is returned. +// the requested block or collection was not found. If looking up the block based solely on the txID returns +// not found, then no error is returned. blockID flow.Identifier, collectionID flow.Identifier, txID flow.Identifier, diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index bbc708423d7..9af6507aeb2 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -226,6 +226,7 @@ func (suite *Suite) TestGetTransactionResultFromCache() { Log: suite.log, SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, Communicator: suite.communicator, + TxResultCacheSize: 10, }) resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) From 37bb9a3c15cf00f45479782d6d9ce8a3445097f4 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sun, 13 Aug 2023 15:29:46 +0100 Subject: [PATCH 24/66] Initialise TxResultCacheSize from access node flags --- cmd/access/node_builder/access_node_builder.go | 8 +++++++- engine/access/rpc/backend/backend.go | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cmd/access/node_builder/access_node_builder.go b/cmd/access/node_builder/access_node_builder.go index 35cbcd58774..010d93a0bbe 100644 --- a/cmd/access/node_builder/access_node_builder.go +++ b/cmd/access/node_builder/access_node_builder.go @@ -129,6 +129,7 @@ type AccessNodeConfig struct { executionDataStartHeight uint64 executionDataConfig edrequester.ExecutionDataConfig PublicNetworkConfig PublicNetworkConfig + TxResultCacheSize uint } type PublicNetworkConfig struct { @@ -205,6 +206,7 @@ func DefaultAccessNodeConfig() *AccessNodeConfig { RetryDelay: edrequester.DefaultRetryDelay, MaxRetryDelay: edrequester.DefaultMaxRetryDelay, }, + TxResultCacheSize: 0, } } @@ -718,6 +720,8 @@ func (builder *FlowAccessNodeBuilder) extraFlags() { flags.DurationVar(&builder.stateStreamConf.ClientSendTimeout, "state-stream-send-timeout", defaultConfig.stateStreamConf.ClientSendTimeout, "maximum wait before timing out while sending a response to a streaming client e.g. 30s") flags.UintVar(&builder.stateStreamConf.ClientSendBufferSize, "state-stream-send-buffer-size", defaultConfig.stateStreamConf.ClientSendBufferSize, "maximum number of responses to buffer within a stream") flags.Float64Var(&builder.stateStreamConf.ResponseLimit, "state-stream-response-limit", defaultConfig.stateStreamConf.ResponseLimit, "max number of responses per second to send over streaming endpoints. this helps manage resources consumed by each client querying data not in the cache e.g. 3 or 0.5. 0 means no limit") + + flags.UintVar(&builder.TxResultCacheSize, "transaction-result-cache-size", defaultConfig.TxResultCacheSize, "transaction result cache size.(Disabled by default i.e 0)") }).ValidateFlags(func() error { if builder.supportsObserver && (builder.PublicNetworkConfig.BindAddress == cmd.NotSet || builder.PublicNetworkConfig.BindAddress == "") { return errors.New("public-network-address must be set if supports-observer is true") @@ -1110,7 +1114,9 @@ func (builder *FlowAccessNodeBuilder) Build() (cmd.Node, error) { SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, ArchiveAddressList: backendConfig.ArchiveAddressList, Communicator: backend.NewNodeCommunicator(backendConfig.CircuitBreakerConfig.Enabled), - ScriptExecValidation: backendConfig.ScriptExecValidation}) + ScriptExecValidation: backendConfig.ScriptExecValidation + TxResultCacheSize: builder.TxResultCacheSize, + }) engineBuilder, err := rpc.NewBuilder( node.Logger, diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 567f522456b..053f5f30079 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -122,7 +122,7 @@ type Params struct { ArchiveAddressList []string Communicator Communicator ScriptExecValidation bool - TxResultCacheSize int + TxResultCacheSize uint } // New creates backend instance @@ -148,7 +148,7 @@ func New(params Params) *Backend { var txResCache *lru2.Cache[flow.Identifier, *access.TransactionResult] if params.TxResultCacheSize > 0 { - txResCache, err = lru2.New[flow.Identifier, *access.TransactionResult](params.TxResultCacheSize) + txResCache, err = lru2.New[flow.Identifier, *access.TransactionResult](int(params.TxResultCacheSize)) if err != nil { params.Log.Fatal().Err(err).Msg("failed to init cache for transaction results") } From 33232c28cf74664e45285b96322527ae6b89e114 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sun, 13 Aug 2023 15:34:42 +0100 Subject: [PATCH 25/66] Fix linter issues --- engine/access/rpc/backend/backend.go | 11 +++++----- .../rpc/backend/backend_block_details.go | 5 +++-- .../rpc/backend/backend_block_headers.go | 5 +++-- engine/access/rpc/backend/backend_events.go | 9 ++++---- engine/access/rpc/backend/backend_network.go | 5 +++-- engine/access/rpc/backend/backend_scripts.go | 13 ++++++------ engine/access/rpc/backend/backend_test.go | 21 ++++++++++--------- .../rpc/backend/backend_transactions.go | 19 +++++++++-------- .../rpc/backend/backend_transactions_test.go | 13 ++++++------ .../rpc/backend/historical_access_test.go | 9 ++++---- engine/access/rpc/backend/retry_test.go | 11 +++++----- 11 files changed, 65 insertions(+), 56 deletions(-) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 053f5f30079..e532be24ad5 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -9,6 +9,11 @@ import ( lru "github.com/hashicorp/golang-lru" lru2 "github.com/hashicorp/golang-lru/v2" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/cmd/build" "github.com/onflow/flow-go/engine/access/rpc/connection" @@ -19,11 +24,6 @@ import ( "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - "github.com/onflow/flow-go/storage/badger" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) // minExecutionNodesCnt is the minimum number of execution nodes expected to have sent the execution receipt for a block @@ -76,7 +76,6 @@ type Backend struct { collections storage.Collections executionReceipts storage.ExecutionReceipts connFactory connection.ConnectionFactory - resultCache *badger.Cache[flow.Identifier, *access.TransactionResult] } // Config defines the configurable options for creating Backend diff --git a/engine/access/rpc/backend/backend_block_details.go b/engine/access/rpc/backend/backend_block_details.go index 9cf366736e1..fc9eee618c4 100644 --- a/engine/access/rpc/backend/backend_block_details.go +++ b/engine/access/rpc/backend/backend_block_details.go @@ -3,12 +3,13 @@ package backend import ( "context" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) type backendBlockDetails struct { diff --git a/engine/access/rpc/backend/backend_block_headers.go b/engine/access/rpc/backend/backend_block_headers.go index 9e3f7354e89..10c26a6a3f6 100644 --- a/engine/access/rpc/backend/backend_block_headers.go +++ b/engine/access/rpc/backend/backend_block_headers.go @@ -3,12 +3,13 @@ package backend import ( "context" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) type backendBlockHeaders struct { diff --git a/engine/access/rpc/backend/backend_events.go b/engine/access/rpc/backend/backend_events.go index c19d43846a5..43b42cde2f5 100644 --- a/engine/access/rpc/backend/backend_events.go +++ b/engine/access/rpc/backend/backend_events.go @@ -7,16 +7,17 @@ import ( "fmt" "time" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/engine/common/rpc/convert" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) type backendEvents struct { diff --git a/engine/access/rpc/backend/backend_network.go b/engine/access/rpc/backend/backend_network.go index 23d9c602649..cb704d93278 100644 --- a/engine/access/rpc/backend/backend_network.go +++ b/engine/access/rpc/backend/backend_network.go @@ -4,13 +4,14 @@ import ( "context" "fmt" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/cmd/build" "github.com/onflow/flow-go/engine/common/rpc/convert" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/state/protocol" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) var SnapshotHistoryLimitErr = fmt.Errorf("reached the snapshot history limit") diff --git a/engine/access/rpc/backend/backend_scripts.go b/engine/access/rpc/backend/backend_scripts.go index e98a95b5d8a..bdff9beb8d7 100644 --- a/engine/access/rpc/backend/backend_scripts.go +++ b/engine/access/rpc/backend/backend_scripts.go @@ -1,25 +1,26 @@ package backend import ( - "crypto/md5" //nolint:gosec "bytes" "context" + "crypto/md5" //nolint:gosec "io" "time" "github.com/hashicorp/go-multierror" lru "github.com/hashicorp/golang-lru" + "github.com/onflow/flow/protobuf/go/flow/access" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - "github.com/onflow/flow/protobuf/go/flow/access" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) // uniqueScriptLoggingTimeWindow is the duration for checking the uniqueness of scripts sent for execution diff --git a/engine/access/rpc/backend/backend_test.go b/engine/access/rpc/backend/backend_test.go index 796e55c150a..8c38a34920e 100644 --- a/engine/access/rpc/backend/backend_test.go +++ b/engine/access/rpc/backend/backend_test.go @@ -7,6 +7,17 @@ import ( "testing" "github.com/dgraph-io/badger/v2" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + entitiesproto "github.com/onflow/flow/protobuf/go/flow/entities" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + access "github.com/onflow/flow-go/engine/access/mock" backendmock "github.com/onflow/flow-go/engine/access/rpc/backend/mock" "github.com/onflow/flow-go/engine/access/rpc/connection" @@ -19,16 +30,6 @@ import ( "github.com/onflow/flow-go/storage" storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/unittest" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - entitiesproto "github.com/onflow/flow/protobuf/go/flow/entities" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) const TEST_MAX_HEIGHT = 100 diff --git a/engine/access/rpc/backend/backend_transactions.go b/engine/access/rpc/backend/backend_transactions.go index 7104928f8f0..25fd0071f53 100644 --- a/engine/access/rpc/backend/backend_transactions.go +++ b/engine/access/rpc/backend/backend_transactions.go @@ -7,6 +7,13 @@ import ( "time" lru2 "github.com/hashicorp/golang-lru/v2" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" @@ -16,12 +23,6 @@ import ( "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) type backendTransactions struct { @@ -252,7 +253,7 @@ func (b *backendTransactions) GetTransactionResult( StatusCode: uint(txStatus), }, nil } - + if b.txResultCache != nil { b.txResultCache.Add(txID, historicalTxResult) } @@ -351,8 +352,8 @@ func (b *backendTransactions) lookupCollectionIDInBlock( // followed by the collection ID lookup. If both are missing, the default lookup by transaction ID is performed. func (b *backendTransactions) retrieveBlock( -// the requested block or collection was not found. If looking up the block based solely on the txID returns -// not found, then no error is returned. + // the requested block or collection was not found. If looking up the block based solely on the txID returns + // not found, then no error is returned. blockID flow.Identifier, collectionID flow.Identifier, txID flow.Identifier, diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index 9af6507aeb2..bf06ae56c20 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -5,6 +5,13 @@ import ( "fmt" "github.com/dgraph-io/badger/v2" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" "github.com/onflow/flow-go/state/protocol" @@ -12,12 +19,6 @@ import ( "github.com/onflow/flow-go/state/protocol/util" "github.com/onflow/flow-go/storage" "github.com/onflow/flow-go/utils/unittest" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) func (suite *Suite) WithPreConfiguredState(f func(snap protocol.Snapshot)) { diff --git a/engine/access/rpc/backend/historical_access_test.go b/engine/access/rpc/backend/historical_access_test.go index 3bacb44b4d8..16fba999a47 100644 --- a/engine/access/rpc/backend/historical_access_test.go +++ b/engine/access/rpc/backend/historical_access_test.go @@ -3,14 +3,15 @@ package backend import ( "context" - "github.com/onflow/flow-go/engine/common/rpc/convert" - "github.com/onflow/flow-go/model/flow" - "github.com/onflow/flow-go/module/metrics" - "github.com/onflow/flow-go/utils/unittest" accessproto "github.com/onflow/flow/protobuf/go/flow/access" "github.com/onflow/flow/protobuf/go/flow/entities" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + "github.com/onflow/flow-go/engine/common/rpc/convert" + "github.com/onflow/flow-go/model/flow" + "github.com/onflow/flow-go/module/metrics" + "github.com/onflow/flow-go/utils/unittest" ) // TestHistoricalTransactionResult tests to see if the historical transaction status can be retrieved diff --git a/engine/access/rpc/backend/retry_test.go b/engine/access/rpc/backend/retry_test.go index 54b13ab4c89..d656380c204 100644 --- a/engine/access/rpc/backend/retry_test.go +++ b/engine/access/rpc/backend/retry_test.go @@ -3,16 +3,17 @@ package backend import ( "context" - "github.com/onflow/flow-go/model/flow" - "github.com/onflow/flow-go/module/metrics" - protocol "github.com/onflow/flow-go/state/protocol/mock" - realstorage "github.com/onflow/flow-go/storage" - "github.com/onflow/flow-go/utils/unittest" "github.com/onflow/flow/protobuf/go/flow/access" "github.com/onflow/flow/protobuf/go/flow/execution" "github.com/stretchr/testify/mock" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + "github.com/onflow/flow-go/model/flow" + "github.com/onflow/flow-go/module/metrics" + protocol "github.com/onflow/flow-go/state/protocol/mock" + realstorage "github.com/onflow/flow-go/storage" + "github.com/onflow/flow-go/utils/unittest" ) // TestTransactionRetry tests that the retry mechanism will send retries at specific times From 00768db47d4c6b0267eedae0d80e40de495cccc5 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Sun, 13 Aug 2023 15:38:29 +0100 Subject: [PATCH 26/66] Remove comment changes --- engine/access/rpc/backend/backend_block_headers.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/engine/access/rpc/backend/backend_block_headers.go b/engine/access/rpc/backend/backend_block_headers.go index 10c26a6a3f6..9b51201d067 100644 --- a/engine/access/rpc/backend/backend_block_headers.go +++ b/engine/access/rpc/backend/backend_block_headers.go @@ -3,13 +3,12 @@ package backend import ( "context" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type backendBlockHeaders struct { @@ -78,14 +77,14 @@ func (b *backendBlockHeaders) GetBlockHeaderByHeight(_ context.Context, height u func (b *backendBlockHeaders) getBlockStatus(header *flow.Header) (flow.BlockStatus, error) { sealed, err := b.state.Sealed().Head() if err != nil { - // In the RPC engine, if we encounter an error from the protocol State indicating State corruption, + // In the RPC engine, if we encounter an error from the protocol state indicating state corruption, // we should halt processing requests, but do throw an exception which might cause a crash: // - It is unsafe to process requests if we have an internally bad State. // TODO: https://github.com/onflow/flow-go/issues/4028 // - We would like to avoid throwing an exception as a result of an Access API request by policy // because this can cause DOS potential - // - Since the protocol State is widely shared, we assume that in practice another component will - // observe the protocol State error and throw an exception. + // - Since the protocol state is widely shared, we assume that in practice another component will + // observe the protocol state error and throw an exception. return flow.BlockStatusUnknown, status.Errorf(codes.Internal, "failed to find latest sealed header: %v", err) } From 507af3e883ae4d36eb4930fe6b5cae38e588c618 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Mon, 14 Aug 2023 12:18:08 +0100 Subject: [PATCH 27/66] Fix syntax error --- cmd/access/node_builder/access_node_builder.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/access/node_builder/access_node_builder.go b/cmd/access/node_builder/access_node_builder.go index 010d93a0bbe..0bcef17d6a6 100644 --- a/cmd/access/node_builder/access_node_builder.go +++ b/cmd/access/node_builder/access_node_builder.go @@ -1114,8 +1114,8 @@ func (builder *FlowAccessNodeBuilder) Build() (cmd.Node, error) { SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, ArchiveAddressList: backendConfig.ArchiveAddressList, Communicator: backend.NewNodeCommunicator(backendConfig.CircuitBreakerConfig.Enabled), - ScriptExecValidation: backendConfig.ScriptExecValidation - TxResultCacheSize: builder.TxResultCacheSize, + ScriptExecValidation: backendConfig.ScriptExecValidation, + TxResultCacheSize: builder.TxResultCacheSize, }) engineBuilder, err := rpc.NewBuilder( From d7c82aa7219a5c0fe36dc47fdac2a2a329d4287e Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Mon, 14 Aug 2023 12:21:13 +0100 Subject: [PATCH 28/66] Rearrange imports according to convention --- cmd/access/node_builder/access_node_builder.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/cmd/access/node_builder/access_node_builder.go b/cmd/access/node_builder/access_node_builder.go index 0bcef17d6a6..68d32a9efa4 100644 --- a/cmd/access/node_builder/access_node_builder.go +++ b/cmd/access/node_builder/access_node_builder.go @@ -12,6 +12,14 @@ import ( badger "github.com/ipfs/go-ds-badger2" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/routing" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/go-bitswap" + "github.com/rs/zerolog" + "github.com/spf13/pflag" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "github.com/onflow/flow-go/admin/commands" stateSyncCommands "github.com/onflow/flow-go/admin/commands/state_synchronization" storageCommands "github.com/onflow/flow-go/admin/commands/storage" @@ -79,13 +87,6 @@ import ( "github.com/onflow/flow-go/storage" bstorage "github.com/onflow/flow-go/storage/badger" "github.com/onflow/flow-go/utils/grpcutils" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/go-bitswap" - "github.com/rs/zerolog" - "github.com/spf13/pflag" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" ) // AccessNodeBuilder extends cmd.NodeBuilder and declares additional functions needed to bootstrap an Access node. From 3da4a39e34c344e8767ee51d9c1a17f0570e1619 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Mon, 14 Aug 2023 16:47:49 +0100 Subject: [PATCH 29/66] Add caching for transactions not found anywhere with respective tests --- .../rpc/backend/backend_transactions.go | 21 +-- .../rpc/backend/backend_transactions_test.go | 141 +++++++++++++++++- 2 files changed, 146 insertions(+), 16 deletions(-) diff --git a/engine/access/rpc/backend/backend_transactions.go b/engine/access/rpc/backend/backend_transactions.go index 25fd0071f53..e030093d32f 100644 --- a/engine/access/rpc/backend/backend_transactions.go +++ b/engine/access/rpc/backend/backend_transactions.go @@ -7,13 +7,6 @@ import ( "time" lru2 "github.com/hashicorp/golang-lru/v2" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" @@ -23,6 +16,12 @@ import ( "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type backendTransactions struct { @@ -248,10 +247,14 @@ func (b *backendTransactions) GetTransactionResult( // if tx not found in old access nodes either, then assume that the tx was submitted to a different AN // and return status as unknown txStatus := flow.TransactionStatusUnknown - return &access.TransactionResult{ + result := &access.TransactionResult{ Status: txStatus, StatusCode: uint(txStatus), - }, nil + } + if b.txResultCache != nil { + b.txResultCache.Add(txID, result) + } + return result, nil } if b.txResultCache != nil { diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index bf06ae56c20..d4567bec44c 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -5,13 +5,7 @@ import ( "fmt" "github.com/dgraph-io/badger/v2" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - + acc "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" "github.com/onflow/flow-go/state/protocol" @@ -19,6 +13,12 @@ import ( "github.com/onflow/flow-go/state/protocol/util" "github.com/onflow/flow-go/storage" "github.com/onflow/flow-go/utils/unittest" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) func (suite *Suite) WithPreConfiguredState(f func(snap protocol.Snapshot)) { @@ -243,3 +243,130 @@ func (suite *Suite) TestGetTransactionResultFromCache() { suite.historicalAccessClient.AssertExpectations(suite.T()) }) } + +func (suite *Suite) TestGetTransactionResultCacheNonExistent() { + suite.WithPreConfiguredState(func(snap protocol.Snapshot) { + block := unittest.BlockFixture() + tbody := unittest.TransactionBodyFixture() + tx := unittest.TransactionFixture() + tx.TransactionBody = tbody + + coll := flow.CollectionFromTransactions([]*flow.Transaction{&tx}) + + suite.transactions. + On("ByID", tx.ID()). + Return(nil, storage.ErrNotFound) + + suite.communicator.On("CallAvailableNode", + mock.Anything, + mock.Anything, + mock.Anything). + Return(nil).Once() + + suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() + + suite.historicalAccessClient. + On("GetTransactionResult", mock.Anything, mock.Anything). + Return(nil, status.Errorf(codes.NotFound, "no known transaction with ID %s", tx.ID())).Once() + + backend := New(Params{ + State: suite.state, + CollectionRPC: suite.colClient, + HistoricalAccessNodes: []access.AccessAPIClient{suite.historicalAccessClient}, + Blocks: suite.blocks, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: suite.communicator, + TxResultCacheSize: 10, + }) + + resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) + suite.Require().NoError(err) + suite.Require().Equal(flow.TransactionStatusUnknown, resp.Status) + suite.Require().Equal(uint(flow.TransactionStatusUnknown), resp.StatusCode) + + // ensure the unknown transaction is cached when not found anywhere + //panic("here") + txStatus := flow.TransactionStatusUnknown + res, ok := backend.txResultCache.Get(tx.ID()) + suite.Require().True(ok) + suite.Require().Equal(res, &acc.TransactionResult{ + Status: txStatus, + StatusCode: uint(txStatus), + }) + + suite.historicalAccessClient.AssertExpectations(suite.T()) + + }) +} + +func (suite *Suite) TestGetTransactionResultUnknownFromCache() { + suite.WithPreConfiguredState(func(snap protocol.Snapshot) { + block := unittest.BlockFixture() + tbody := unittest.TransactionBodyFixture() + tx := unittest.TransactionFixture() + tx.TransactionBody = tbody + + coll := flow.CollectionFromTransactions([]*flow.Transaction{&tx}) + + suite.transactions. + On("ByID", tx.ID()). + Return(nil, storage.ErrNotFound) + + suite.communicator.On("CallAvailableNode", + mock.Anything, + mock.Anything, + mock.Anything). + Return(nil).Once() + + suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() + + suite.historicalAccessClient. + On("GetTransactionResult", mock.Anything, mock.Anything). + Return(nil, status.Errorf(codes.NotFound, "no known transaction with ID %s", tx.ID())).Once() + + backend := New(Params{ + State: suite.state, + CollectionRPC: suite.colClient, + HistoricalAccessNodes: []access.AccessAPIClient{suite.historicalAccessClient}, + Blocks: suite.blocks, + Transactions: suite.transactions, + ExecutionReceipts: suite.receipts, + ChainID: suite.chainID, + AccessMetrics: metrics.NewNoopCollector(), + MaxHeightRange: DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, + Communicator: suite.communicator, + TxResultCacheSize: 10, + }) + + resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) + suite.Require().NoError(err) + suite.Require().Equal(flow.TransactionStatusUnknown, resp.Status) + suite.Require().Equal(uint(flow.TransactionStatusUnknown), resp.StatusCode) + + // ensure the unknown transaction is cached when not found anywhere + //panic("here") + txStatus := flow.TransactionStatusUnknown + res, ok := backend.txResultCache.Get(tx.ID()) + suite.Require().True(ok) + suite.Require().Equal(res, &acc.TransactionResult{ + Status: txStatus, + StatusCode: uint(txStatus), + }) + + resp2, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) + suite.Require().NoError(err) + suite.Require().Equal(flow.TransactionStatusUnknown, resp2.Status) + suite.Require().Equal(uint(flow.TransactionStatusUnknown), resp2.StatusCode) + + suite.historicalAccessClient.AssertExpectations(suite.T()) + + }) +} From 3af348b49e1c2c90e209f63f88f0019ba4fedcdf Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Mon, 14 Aug 2023 16:50:34 +0100 Subject: [PATCH 30/66] Fix imports --- engine/access/rpc/backend/backend_transactions.go | 13 +++++++------ .../access/rpc/backend/backend_transactions_test.go | 2 -- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/engine/access/rpc/backend/backend_transactions.go b/engine/access/rpc/backend/backend_transactions.go index e030093d32f..f9ef781cb63 100644 --- a/engine/access/rpc/backend/backend_transactions.go +++ b/engine/access/rpc/backend/backend_transactions.go @@ -7,6 +7,13 @@ import ( "time" lru2 "github.com/hashicorp/golang-lru/v2" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" @@ -16,12 +23,6 @@ import ( "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) type backendTransactions struct { diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index d4567bec44c..fb2a1712a1a 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -291,7 +291,6 @@ func (suite *Suite) TestGetTransactionResultCacheNonExistent() { suite.Require().Equal(uint(flow.TransactionStatusUnknown), resp.StatusCode) // ensure the unknown transaction is cached when not found anywhere - //panic("here") txStatus := flow.TransactionStatusUnknown res, ok := backend.txResultCache.Get(tx.ID()) suite.Require().True(ok) @@ -352,7 +351,6 @@ func (suite *Suite) TestGetTransactionResultUnknownFromCache() { suite.Require().Equal(uint(flow.TransactionStatusUnknown), resp.StatusCode) // ensure the unknown transaction is cached when not found anywhere - //panic("here") txStatus := flow.TransactionStatusUnknown res, ok := backend.txResultCache.Get(tx.ID()) suite.Require().True(ok) From 6aee5d7d32dfa7be64043354452a456ec862b268 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Mon, 14 Aug 2023 17:16:46 +0100 Subject: [PATCH 31/66] Deduplicate caching related backend transactions unit tests --- .../rpc/backend/backend_transactions_test.go | 62 +++++-------------- 1 file changed, 15 insertions(+), 47 deletions(-) diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index fb2a1712a1a..c0f464840e9 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -179,24 +179,17 @@ func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResultFromHis }) } -func (suite *Suite) TestGetTransactionResultFromCache() { +func (suite *Suite) WithGetTransactionCachingTestSetup(f func(b *flow.Block, t *flow.Transaction)) { suite.WithPreConfiguredState(func(snap protocol.Snapshot) { block := unittest.BlockFixture() tbody := unittest.TransactionBodyFixture() tx := unittest.TransactionFixture() tx.TransactionBody = tbody - coll := flow.CollectionFromTransactions([]*flow.Transaction{&tx}) - suite.transactions. On("ByID", tx.ID()). Return(nil, storage.ErrNotFound) - suite.blocks. - On("ByID", block.ID()). - Return(&block, nil). - Once() - suite.communicator.On("CallAvailableNode", mock.Anything, mock.Anything, @@ -205,6 +198,12 @@ func (suite *Suite) TestGetTransactionResultFromCache() { suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() + f(&block, &tx) + }) +} + +func (suite *Suite) TestGetTransactionResultFromCache() { + suite.WithGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { transactionResultResponse := access.TransactionResultResponse{ Status: entities.TransactionStatus_EXECUTED, StatusCode: uint32(entities.TransactionStatus_EXECUTED), @@ -230,6 +229,8 @@ func (suite *Suite) TestGetTransactionResultFromCache() { TxResultCacheSize: 10, }) + coll := flow.CollectionFromTransactions([]*flow.Transaction{tx}) + resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) suite.Require().NoError(err) suite.Require().Equal(flow.TransactionStatusExecuted, resp.Status) @@ -245,25 +246,7 @@ func (suite *Suite) TestGetTransactionResultFromCache() { } func (suite *Suite) TestGetTransactionResultCacheNonExistent() { - suite.WithPreConfiguredState(func(snap protocol.Snapshot) { - block := unittest.BlockFixture() - tbody := unittest.TransactionBodyFixture() - tx := unittest.TransactionFixture() - tx.TransactionBody = tbody - - coll := flow.CollectionFromTransactions([]*flow.Transaction{&tx}) - - suite.transactions. - On("ByID", tx.ID()). - Return(nil, storage.ErrNotFound) - - suite.communicator.On("CallAvailableNode", - mock.Anything, - mock.Anything, - mock.Anything). - Return(nil).Once() - - suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() + suite.WithGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { suite.historicalAccessClient. On("GetTransactionResult", mock.Anything, mock.Anything). @@ -285,6 +268,8 @@ func (suite *Suite) TestGetTransactionResultCacheNonExistent() { TxResultCacheSize: 10, }) + coll := flow.CollectionFromTransactions([]*flow.Transaction{tx}) + resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) suite.Require().NoError(err) suite.Require().Equal(flow.TransactionStatusUnknown, resp.Status) @@ -305,26 +290,7 @@ func (suite *Suite) TestGetTransactionResultCacheNonExistent() { } func (suite *Suite) TestGetTransactionResultUnknownFromCache() { - suite.WithPreConfiguredState(func(snap protocol.Snapshot) { - block := unittest.BlockFixture() - tbody := unittest.TransactionBodyFixture() - tx := unittest.TransactionFixture() - tx.TransactionBody = tbody - - coll := flow.CollectionFromTransactions([]*flow.Transaction{&tx}) - - suite.transactions. - On("ByID", tx.ID()). - Return(nil, storage.ErrNotFound) - - suite.communicator.On("CallAvailableNode", - mock.Anything, - mock.Anything, - mock.Anything). - Return(nil).Once() - - suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() - + suite.WithGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { suite.historicalAccessClient. On("GetTransactionResult", mock.Anything, mock.Anything). Return(nil, status.Errorf(codes.NotFound, "no known transaction with ID %s", tx.ID())).Once() @@ -345,6 +311,8 @@ func (suite *Suite) TestGetTransactionResultUnknownFromCache() { TxResultCacheSize: 10, }) + coll := flow.CollectionFromTransactions([]*flow.Transaction{tx}) + resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) suite.Require().NoError(err) suite.Require().Equal(flow.TransactionStatusUnknown, resp.Status) From 33bb8b72e284a5d1be18feff14febb2dba9a5b8a Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Mon, 14 Aug 2023 17:27:03 +0100 Subject: [PATCH 32/66] Deduplicate backend transaction tests --- .../rpc/backend/backend_transactions_test.go | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index c0f464840e9..c577886912c 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -46,7 +46,7 @@ func (suite *Suite) WithPreConfiguredState(f func(snap protocol.Snapshot)) { mock.Anything, mock.Anything, mock.Anything). - Return(nil) + Return(nil).Once() f(snap) }) @@ -140,12 +140,6 @@ func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResultFromHis On("ByID", tx.ID()). Return(nil, storage.ErrNotFound) - suite.communicator.On("CallAvailableNode", - mock.Anything, - mock.Anything, - mock.Anything). - Return(nil).Once() - suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() transactionResultResponse := access.TransactionResultResponse{ @@ -190,12 +184,6 @@ func (suite *Suite) WithGetTransactionCachingTestSetup(f func(b *flow.Block, t * On("ByID", tx.ID()). Return(nil, storage.ErrNotFound) - suite.communicator.On("CallAvailableNode", - mock.Anything, - mock.Anything, - mock.Anything). - Return(nil).Once() - suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() f(&block, &tx) @@ -312,7 +300,7 @@ func (suite *Suite) TestGetTransactionResultUnknownFromCache() { }) coll := flow.CollectionFromTransactions([]*flow.Transaction{tx}) - + resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) suite.Require().NoError(err) suite.Require().Equal(flow.TransactionStatusUnknown, resp.Status) From 800ec4cfbbf91f903d8a724c27234f6704395915 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 15 Aug 2023 11:30:42 +0100 Subject: [PATCH 33/66] Minor backend transactions history conditional refactoring --- .../rpc/backend/backend_transactions.go | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/engine/access/rpc/backend/backend_transactions.go b/engine/access/rpc/backend/backend_transactions.go index f9ef781cb63..80bb2d07402 100644 --- a/engine/access/rpc/backend/backend_transactions.go +++ b/engine/access/rpc/backend/backend_transactions.go @@ -235,35 +235,37 @@ func (b *backendTransactions) GetTransactionResult( tx, err := b.transactions.ByID(txID) if err != nil { txErr := rpc.ConvertStorageError(err) - if status.Code(txErr) == codes.NotFound { - // Tx not found. If we have historical Sporks setup, lets look through those as well - if b.txResultCache != nil { - val, ok := b.txResultCache.Get(txID) - if ok { - return val, nil - } + + if status.Code(txErr) != codes.NotFound { + return nil, txErr + } + + // Tx not found. If we have historical Sporks setup, lets look through those as well + if b.txResultCache != nil { + val, ok := b.txResultCache.Get(txID) + if ok { + return val, nil } - historicalTxResult, err := b.getHistoricalTransactionResult(ctx, txID) - if err != nil { - // if tx not found in old access nodes either, then assume that the tx was submitted to a different AN - // and return status as unknown - txStatus := flow.TransactionStatusUnknown - result := &access.TransactionResult{ - Status: txStatus, - StatusCode: uint(txStatus), - } - if b.txResultCache != nil { - b.txResultCache.Add(txID, result) - } - return result, nil + } + historicalTxResult, err := b.getHistoricalTransactionResult(ctx, txID) + if err != nil { + // if tx not found in old access nodes either, then assume that the tx was submitted to a different AN + // and return status as unknown + txStatus := flow.TransactionStatusUnknown + result := &access.TransactionResult{ + Status: txStatus, + StatusCode: uint(txStatus), } - if b.txResultCache != nil { - b.txResultCache.Add(txID, historicalTxResult) + b.txResultCache.Add(txID, result) } - return historicalTxResult, nil + return result, nil } - return nil, txErr + + if b.txResultCache != nil { + b.txResultCache.Add(txID, historicalTxResult) + } + return historicalTxResult, nil } block, err := b.retrieveBlock(blockID, collectionID, txID) From 5967df8202618bd8625f5b5b7b01685f82275c78 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 15 Aug 2023 12:29:42 +0100 Subject: [PATCH 34/66] Fix backend invocation in observer builder --- cmd/observer/node_builder/observer_builder.go | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/cmd/observer/node_builder/observer_builder.go b/cmd/observer/node_builder/observer_builder.go index b3245986122..8cd55297347 100644 --- a/cmd/observer/node_builder/observer_builder.go +++ b/cmd/observer/node_builder/observer_builder.go @@ -924,29 +924,30 @@ func (builder *ObserverServiceBuilder) enqueueRPCServer() { backendConfig.CircuitBreakerConfig, ), } - - accessBackend := backend.New( - node.State, - nil, - nil, - node.Storage.Blocks, - node.Storage.Headers, - node.Storage.Collections, - node.Storage.Transactions, - node.Storage.Receipts, - node.Storage.Results, - node.RootChainID, - accessMetrics, - connFactory, - false, - backendConfig.MaxHeightRange, - backendConfig.PreferredExecutionNodeIDs, - backendConfig.FixedExecutionNodeIDs, - node.Logger, - backend.DefaultSnapshotHistoryLimit, - backendConfig.ArchiveAddressList, - backend.NewNodeCommunicator(backendConfig.CircuitBreakerConfig.Enabled), - backendConfig.ScriptExecValidation) + + + + accessBackend := backend.New(backend.Params{ + State:node.State, + Blocks: node.Storage.Blocks, + Headers: node.Storage.Headers, + Collections: node.Storage.Collections, + Transactions: node.Storage.Transactions, + ExecutionReceipts: node.Storage.Receipts, + ExecutionResults: node.Storage.Results, + ChainID: node.RootChainID, + AccessMetrics: accessMetrics, + ConnFactory: connFactory, + RetryEnabled: false, + MaxHeightRange: backendConfig.MaxHeightRange, + PreferredExecutionNodeIDs: backendConfig.PreferredExecutionNodeIDs, + FixedExecutionNodeIDs: backendConfig.FixedExecutionNodeIDs, + Log:node.Logger, + SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, + ArchiveAddressList: backendConfig.ArchiveAddressList, + Communicator: backend.NewNodeCommunicator(backendConfig.CircuitBreakerConfig.Enabled), + ScriptExecValidation: backendConfig.ScriptExecValidation, + }) observerCollector := metrics.NewObserverCollector() restHandler, err := restapiproxy.NewRestProxyHandler( From 47fe8258e59e309ca155c6ae2ed1154fa4b87f7b Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 15 Aug 2023 12:49:21 +0100 Subject: [PATCH 35/66] Fix backend invocation in access test --- engine/access/access_test.go | 201 +++++++++++++++-------------------- 1 file changed, 85 insertions(+), 116 deletions(-) diff --git a/engine/access/access_test.go b/engine/access/access_test.go index 8fdf13cf5c7..d09835a4395 100644 --- a/engine/access/access_test.go +++ b/engine/access/access_test.go @@ -138,28 +138,23 @@ func (suite *Suite) RunTest( unittest.RunWithBadgerDB(suite.T(), func(db *badger.DB) { all := util.StorageLayer(suite.T(), db) - suite.backend = backend.New(suite.state, - suite.collClient, - nil, - all.Blocks, - all.Headers, - all.Collections, - all.Transactions, - all.Receipts, - all.Results, - suite.chainID, - suite.metrics, - nil, - false, - backend.DefaultMaxHeightRange, - nil, - nil, - suite.log, - backend.DefaultSnapshotHistoryLimit, - nil, - backend.NewNodeCommunicator(false), - false, - ) + suite.backend = backend.New( + backend.Params{ + State: suite.state, + CollectionRPC: suite.collClient, + Blocks: all.Blocks, + Headers: all.Headers, + Collections: all.Collections, + Transactions: all.Transactions, + ExecutionResults: all.Results, + ExecutionReceipts: all.Receipts, + ChainID: suite.chainID, + AccessMetrics: suite.metrics, + MaxHeightRange: backend.DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, + Communicator: backend.NewNodeCommunicator(false), + }) handler := access.NewHandler(suite.backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me, access.WithBlockSignerDecoder(suite.signerIndicesDecoder)) f(handler, db, all) }) @@ -312,30 +307,19 @@ func (suite *Suite) TestSendTransactionToRandomCollectionNode() { connFactory.On("GetAccessAPIClient", collNode1.Address).Return(col1ApiClient, &mockCloser{}, nil) connFactory.On("GetAccessAPIClient", collNode2.Address).Return(col2ApiClient, &mockCloser{}, nil) - backend := backend.New(suite.state, - nil, - nil, - nil, - nil, - collections, - transactions, - nil, - nil, - suite.chainID, - metrics, - connFactory, - false, - backend.DefaultMaxHeightRange, - nil, - nil, - suite.log, - backend.DefaultSnapshotHistoryLimit, - nil, - backend.NewNodeCommunicator(false), - false, - ) - - handler := access.NewHandler(backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) + bnd := backend.New(backend.Params{State: suite.state, + Collections: collections, + Transactions: transactions, + ChainID: suite.chainID, + AccessMetrics: metrics, + ConnFactory: connFactory, + MaxHeightRange: backend.DefaultMaxHeightRange, + Log: suite.log, + SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, + Communicator: backend.NewNodeCommunicator(false), + }) + + handler := access.NewHandler(bnd, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) // Send transaction 1 resp, err := handler.SendTransaction(context.Background(), sendReq1) @@ -640,30 +624,25 @@ func (suite *Suite) TestGetSealedTransaction() { blocksToMarkExecuted, err := stdmap.NewTimes(100) require.NoError(suite.T(), err) - backend := backend.New(suite.state, - suite.collClient, - nil, - all.Blocks, - all.Headers, - collections, - transactions, - receipts, - results, - suite.chainID, - suite.metrics, - connFactory, - false, - backend.DefaultMaxHeightRange, - nil, - enNodeIDs.Strings(), - suite.log, - backend.DefaultSnapshotHistoryLimit, - nil, - backend.NewNodeCommunicator(false), - false, - ) - - handler := access.NewHandler(backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) + bnd := backend.New(backend.Params{State: suite.state, + CollectionRPC: suite.collClient, + Blocks: all.Blocks, + Headers: all.Headers, + Collections: collections, + Transactions: transactions, + ExecutionReceipts: receipts, + ExecutionResults: results, + ChainID: suite.chainID, + AccessMetrics: suite.metrics, + ConnFactory: connFactory, + MaxHeightRange: backend.DefaultMaxHeightRange, + PreferredExecutionNodeIDs: enNodeIDs.Strings(), + Log: suite.log, + SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, + Communicator: backend.NewNodeCommunicator(false), + }) + + handler := access.NewHandler(bnd, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) // create the ingest engine ingestEng, err := ingestion.New(suite.log, suite.net, suite.state, suite.me, suite.request, all.Blocks, all.Headers, collections, @@ -781,30 +760,25 @@ func (suite *Suite) TestGetTransactionResult() { blocksToMarkExecuted, err := stdmap.NewTimes(100) require.NoError(suite.T(), err) - backend := backend.New(suite.state, - suite.collClient, - nil, - all.Blocks, - all.Headers, - collections, - transactions, - receipts, - results, - suite.chainID, - suite.metrics, - connFactory, - false, - backend.DefaultMaxHeightRange, - nil, - enNodeIDs.Strings(), - suite.log, - backend.DefaultSnapshotHistoryLimit, - nil, - backend.NewNodeCommunicator(false), - false, - ) - - handler := access.NewHandler(backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) + bnd := backend.New(backend.Params{State: suite.state, + CollectionRPC: suite.collClient, + Blocks: all.Blocks, + Headers: all.Headers, + Collections: collections, + Transactions: transactions, + ExecutionReceipts: receipts, + ExecutionResults: results, + ChainID: suite.chainID, + AccessMetrics: suite.metrics, + ConnFactory: connFactory, + MaxHeightRange: backend.DefaultMaxHeightRange, + PreferredExecutionNodeIDs: enNodeIDs.Strings(), + Log: suite.log, + SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, + Communicator: backend.NewNodeCommunicator(false), + }) + + handler := access.NewHandler(bnd, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) // create the ingest engine ingestEng, err := ingestion.New(suite.log, suite.net, suite.state, suite.me, suite.request, all.Blocks, all.Headers, collections, @@ -974,28 +948,23 @@ func (suite *Suite) TestExecuteScript() { connFactory := new(factorymock.ConnectionFactory) connFactory.On("GetExecutionAPIClient", mock.Anything).Return(suite.execClient, &mockCloser{}, nil) - suite.backend = backend.New(suite.state, - suite.collClient, - nil, - all.Blocks, - all.Headers, - collections, - transactions, - receipts, - results, - suite.chainID, - suite.metrics, - connFactory, - false, - backend.DefaultMaxHeightRange, - nil, - flow.IdentifierList(identities.NodeIDs()).Strings(), - suite.log, - backend.DefaultSnapshotHistoryLimit, - nil, - backend.NewNodeCommunicator(false), - false, - ) + suite.backend = backend.New(backend.Params{State: suite.state, + CollectionRPC: suite.collClient, + Blocks: all.Blocks, + Headers: all.Headers, + Collections: collections, + Transactions: transactions, + ExecutionReceipts: receipts, + ExecutionResults: results, + ChainID: suite.chainID, + AccessMetrics: suite.metrics, + ConnFactory: connFactory, + MaxHeightRange: backend.DefaultMaxHeightRange, + FixedExecutionNodeIDs: (identities.NodeIDs()).Strings(), + Log: suite.log, + SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, + Communicator: backend.NewNodeCommunicator(false), + }) handler := access.NewHandler(suite.backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) From 77678a422b5d6cf93fce5525b08568a10051d847 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 15 Aug 2023 17:29:28 +0100 Subject: [PATCH 36/66] Fix backend instance invocation --- .../integration_unsecure_grpc_server_test.go | 41 +++++++----------- engine/access/rest_api_test.go | 42 ++++++++----------- engine/access/secure_grpcr_test.go | 37 +++++++--------- 3 files changed, 48 insertions(+), 72 deletions(-) diff --git a/engine/access/integration_unsecure_grpc_server_test.go b/engine/access/integration_unsecure_grpc_server_test.go index 520da185aad..cf9ec1fa744 100644 --- a/engine/access/integration_unsecure_grpc_server_test.go +++ b/engine/access/integration_unsecure_grpc_server_test.go @@ -166,29 +166,20 @@ func (suite *SameGRPCPortTestSuite) SetupTest() { block := unittest.BlockHeaderFixture() suite.snapshot.On("Head").Return(block, nil) - backend := backend.New( - suite.state, - suite.collClient, - nil, - suite.blocks, - suite.headers, - suite.collections, - suite.transactions, - nil, - nil, - suite.chainID, - suite.metrics, - nil, - false, - 0, - nil, - nil, - suite.log, - 0, - nil, - backend.NewNodeCommunicator(false), - false, - ) + bnd := backend.New(backend.Params{ + State: suite.state, + CollectionRPC: suite.collClient, + Blocks: suite.blocks, + Headers: suite.headers, + Collections: suite.collections, + Transactions: suite.transactions, + ChainID: suite.chainID, + AccessMetrics: suite.metrics, + MaxHeightRange: 0, + Log: suite.log, + SnapshotHistoryLimit: 0, + Communicator: backend.NewNodeCommunicator(false), + }) // create rpc engine builder rpcEngBuilder, err := rpc.NewBuilder( @@ -199,8 +190,8 @@ func (suite *SameGRPCPortTestSuite) SetupTest() { suite.metrics, false, suite.me, - backend, - backend, + bnd, + bnd, suite.secureGrpcServer, suite.unsecureGrpcServer, ) diff --git a/engine/access/rest_api_test.go b/engine/access/rest_api_test.go index 7ca1ef0c0f3..1b891832249 100644 --- a/engine/access/rest_api_test.go +++ b/engine/access/rest_api_test.go @@ -149,28 +149,22 @@ func (suite *RestAPITestSuite) SetupTest() { nil, nil).Build() - backend := backend.New(suite.state, - suite.collClient, - nil, - suite.blocks, - suite.headers, - suite.collections, - suite.transactions, - nil, - suite.executionResults, - suite.chainID, - suite.metrics, - nil, - false, - 0, - nil, - nil, - suite.log, - 0, - nil, - backend.NewNodeCommunicator(false), - false, - ) + bnd := backend.New( + backend.Params{ + State: suite.state, + CollectionRPC: suite.collClient, + Blocks: suite.blocks, + Headers: suite.headers, + Collections: suite.collections, + Transactions: suite.transactions, + ExecutionResults: suite.executionResults, + ChainID: suite.chainID, + AccessMetrics: suite.metrics, + MaxHeightRange: 0, + Log: suite.log, + SnapshotHistoryLimit: 0, + Communicator: backend.NewNodeCommunicator(false), + }) rpcEngBuilder, err := rpc.NewBuilder( suite.log, @@ -180,8 +174,8 @@ func (suite *RestAPITestSuite) SetupTest() { suite.metrics, false, suite.me, - backend, - backend, + bnd, + bnd, suite.secureGrpcServer, suite.unsecureGrpcServer, ) diff --git a/engine/access/secure_grpcr_test.go b/engine/access/secure_grpcr_test.go index ecc0156b720..d5f64352cf6 100644 --- a/engine/access/secure_grpcr_test.go +++ b/engine/access/secure_grpcr_test.go @@ -130,29 +130,20 @@ func (suite *SecureGRPCTestSuite) SetupTest() { block := unittest.BlockHeaderFixture() suite.snapshot.On("Head").Return(block, nil) - bnd := backend.New( - suite.state, - suite.collClient, - nil, - suite.blocks, - suite.headers, - suite.collections, - suite.transactions, - nil, - nil, - suite.chainID, - suite.metrics, - nil, - false, - 0, - nil, - nil, - suite.log, - 0, - nil, - backend.NewNodeCommunicator(false), - false, - ) + bnd := backend.New(backend.Params{ + State: suite.state, + CollectionRPC: suite.collClient, + Blocks: suite.blocks, + Headers: suite.headers, + Collections: suite.collections, + Transactions: suite.transactions, + ChainID: suite.chainID, + AccessMetrics: suite.metrics, + MaxHeightRange: 0, + Log: suite.log, + SnapshotHistoryLimit: 0, + Communicator: backend.NewNodeCommunicator(false), + }) rpcEngBuilder, err := rpc.NewBuilder( suite.log, From a1d926834672517fdab685b9181e4ee9e503b633 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 15 Aug 2023 18:19:04 +0100 Subject: [PATCH 37/66] wip --- .../integration_unsecure_grpc_server_test.go | 19 +++++++++---------- engine/access/rest_api_test.go | 15 +++++++-------- engine/access/secure_grpcr_test.go | 17 ++++++++--------- module/metrics.go | 15 +++++++++++++-- module/metrics/access.go | 7 ++++--- 5 files changed, 41 insertions(+), 32 deletions(-) diff --git a/engine/access/integration_unsecure_grpc_server_test.go b/engine/access/integration_unsecure_grpc_server_test.go index cf9ec1fa744..9ad3e7f54df 100644 --- a/engine/access/integration_unsecure_grpc_server_test.go +++ b/engine/access/integration_unsecure_grpc_server_test.go @@ -7,16 +7,6 @@ import ( "testing" "time" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - executiondataproto "github.com/onflow/flow/protobuf/go/flow/executiondata" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" - "github.com/onflow/flow-go/engine" accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rpc" @@ -37,6 +27,15 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + executiondataproto "github.com/onflow/flow/protobuf/go/flow/executiondata" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" ) // SameGRPCPortTestSuite verifies both AccessAPI and ExecutionDataAPI client continue to work when configured diff --git a/engine/access/rest_api_test.go b/engine/access/rest_api_test.go index 1b891832249..5164bba6106 100644 --- a/engine/access/rest_api_test.go +++ b/engine/access/rest_api_test.go @@ -11,14 +11,6 @@ import ( "time" "github.com/antihax/optional" - restclient "github.com/onflow/flow/openapi/go-client-generated" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc/credentials" - accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rest/request" "github.com/onflow/flow-go/engine/access/rest/routes" @@ -35,6 +27,13 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" + restclient "github.com/onflow/flow/openapi/go-client-generated" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc/credentials" ) // RestAPITestSuite tests that the Access node serves the REST API defined via the OpenApi spec accurately diff --git a/engine/access/secure_grpcr_test.go b/engine/access/secure_grpcr_test.go index d5f64352cf6..d8d4f71b732 100644 --- a/engine/access/secure_grpcr_test.go +++ b/engine/access/secure_grpcr_test.go @@ -7,15 +7,6 @@ import ( "testing" "time" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" - "github.com/onflow/flow-go/crypto" accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rpc" @@ -30,6 +21,14 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" ) // SecureGRPCTestSuite tests that Access node provides a secure GRPC server diff --git a/module/metrics.go b/module/metrics.go index 3c1d6dfdc37..e5bc5b6fecd 100644 --- a/module/metrics.go +++ b/module/metrics.go @@ -6,12 +6,11 @@ import ( "github.com/libp2p/go-libp2p/core/peer" rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" - httpmetrics "github.com/slok/go-http-metrics/metrics" - "github.com/onflow/flow-go/model/chainsync" "github.com/onflow/flow-go/model/cluster" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/network/channels" + httpmetrics "github.com/slok/go-http-metrics/metrics" ) type EntriesFunc func() uint @@ -647,6 +646,8 @@ type AccessMetrics interface { TransactionMetrics BackendScriptsMetrics + //TrnasactionResultMetrics + // UpdateExecutionReceiptMaxHeight is called whenever we store an execution receipt from a block from a newer height UpdateExecutionReceiptMaxHeight(height uint64) @@ -654,6 +655,16 @@ type AccessMetrics interface { UpdateLastFullBlockHeight(height uint64) } +type TrnasactionResultMetrics interface { + OnKeyHitSuccess() + OnKeyHitFailure() + + OnKeyAddSuccess() + OnKeyEviction() + + OnKeyAddFailureDueToFullCache() +} + type ExecutionResultStats struct { ComputationUsed uint64 MemoryUsed uint64 diff --git a/module/metrics/access.go b/module/metrics/access.go index 1116f87f433..56e24b70da2 100644 --- a/module/metrics/access.go +++ b/module/metrics/access.go @@ -1,11 +1,10 @@ package metrics import ( - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/module/counters" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" ) type AccessCollectorOpts func(*AccessCollector) @@ -33,6 +32,8 @@ type AccessCollector struct { module.TransactionMetrics module.BackendScriptsMetrics + //module.TransactionResultMetrics + connectionReused prometheus.Counter connectionsInPool *prometheus.GaugeVec connectionAdded prometheus.Counter From 4ef02f3dda67af38ce89c4b0bc639c2fc9482afb Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 15 Aug 2023 18:48:44 +0100 Subject: [PATCH 38/66] Refactor magic number hash size in cache key --- engine/access/rpc/backend/backend.go | 3 ++- engine/access/rpc/backend/backend_scripts.go | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 7d331a65bbb..033b8b96303 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -2,6 +2,7 @@ package backend import ( "context" + "crypto/md5" "fmt" "net" "strconv" @@ -118,7 +119,7 @@ func New( retry.Activate() } - loggedScripts, err := lru.New[[16]byte, time.Time](DefaultLoggedScriptsCacheSize) + loggedScripts, err := lru.New[[md5.Size]byte, time.Time](DefaultLoggedScriptsCacheSize) if err != nil { log.Fatal().Err(err).Msg("failed to initialize script logging cache") } diff --git a/engine/access/rpc/backend/backend_scripts.go b/engine/access/rpc/backend/backend_scripts.go index bd4851a32e0..90433cf8a1f 100644 --- a/engine/access/rpc/backend/backend_scripts.go +++ b/engine/access/rpc/backend/backend_scripts.go @@ -1,9 +1,9 @@ package backend import ( + "crypto/md5" //nolint:gosec "bytes" "context" - "crypto/md5" //nolint:gosec "io" "time" @@ -33,7 +33,7 @@ type backendScripts struct { connFactory connection.ConnectionFactory log zerolog.Logger metrics module.BackendScriptsMetrics - loggedScripts *lru.Cache[[16]byte, time.Time] + loggedScripts *lru.Cache[[md5.Size]byte, time.Time] archiveAddressList []string archivePorts []uint From e1695557fa595606badd277611b21325f29b999c Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 15 Aug 2023 18:59:00 +0100 Subject: [PATCH 39/66] Refactor newcache creation in connectiont tests --- .../access/rpc/connection/connection_test.go | 51 +++++++------------ 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/engine/access/rpc/connection/connection_test.go b/engine/access/rpc/connection/connection_test.go index 3db1edc4819..4364409ba32 100644 --- a/engine/access/rpc/connection/connection_test.go +++ b/engine/access/rpc/connection/connection_test.go @@ -108,6 +108,14 @@ func TestProxyExecutionAPI(t *testing.T) { assert.Equal(t, resp, expected) } +func getCache(t *testing.T, cacheSize int) *lru.Cache[string, *CachedClient] { + cache, err := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { + client.Close() + }) + require.NoError(t, err) + return cache +} + func TestProxyAccessAPIConnectionReuse(t *testing.T) { // create a collection node cn := new(collectionNode) @@ -124,10 +132,7 @@ func TestProxyAccessAPIConnectionReuse(t *testing.T) { connectionFactory.CollectionGRPCPort = cn.port // set the connection pool cache size cacheSize := 1 - cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { - client.Close() - }) - connectionCache := NewCache(cache, cacheSize) + connectionCache := NewCache(getCache(t, cacheSize), cacheSize) // set metrics reporting connectionFactory.AccessMetrics = metrics.NewNoopCollector() @@ -179,10 +184,7 @@ func TestProxyExecutionAPIConnectionReuse(t *testing.T) { connectionFactory.ExecutionGRPCPort = en.port // set the connection pool cache size cacheSize := 5 - cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { - client.Close() - }) - connectionCache := NewCache(cache, cacheSize) + connectionCache := NewCache(getCache(t, cacheSize), cacheSize) // set metrics reporting connectionFactory.AccessMetrics = metrics.NewNoopCollector() connectionFactory.Manager = NewManager( @@ -240,10 +242,7 @@ func TestExecutionNodeClientTimeout(t *testing.T) { connectionFactory.ExecutionNodeGRPCTimeout = timeout // set the connection pool cache size cacheSize := 5 - cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { - client.Close() - }) - connectionCache := NewCache(cache, cacheSize) + connectionCache := NewCache(getCache(t, cacheSize), cacheSize) // set metrics reporting connectionFactory.AccessMetrics = metrics.NewNoopCollector() connectionFactory.Manager = NewManager( @@ -289,10 +288,7 @@ func TestCollectionNodeClientTimeout(t *testing.T) { connectionFactory.CollectionNodeGRPCTimeout = timeout // set the connection pool cache size cacheSize := 5 - cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { - client.Close() - }) - connectionCache := NewCache(cache, cacheSize) + connectionCache := NewCache(getCache(t, cacheSize), cacheSize) // set metrics reporting connectionFactory.AccessMetrics = metrics.NewNoopCollector() connectionFactory.Manager = NewManager( @@ -338,11 +334,8 @@ func TestConnectionPoolFull(t *testing.T) { connectionFactory.CollectionGRPCPort = cn1.port // set the connection pool cache size cacheSize := 2 - cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { - client.Close() - }) - connectionCache := NewCache(cache, cacheSize) + connectionCache := NewCache(getCache(t, cacheSize), cacheSize) // set metrics reporting connectionFactory.AccessMetrics = metrics.NewNoopCollector() connectionFactory.Manager = NewManager( @@ -415,11 +408,8 @@ func TestConnectionPoolStale(t *testing.T) { connectionFactory.CollectionGRPCPort = cn.port // set the connection pool cache size cacheSize := 5 - cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { - client.Close() - }) - connectionCache := NewCache(cache, cacheSize) + connectionCache := NewCache(getCache(t, cacheSize), cacheSize) // set metrics reporting connectionFactory.AccessMetrics = metrics.NewNoopCollector() connectionFactory.Manager = NewManager( @@ -474,18 +464,18 @@ func TestConnectionPoolStale(t *testing.T) { // - Invalidate the execution API client. // - Wait for all goroutines to finish. // - Verify that the number of completed requests matches the number of sent responses. -func TestExecutionNodeClientClosedGracefully(t *testing.T) { +func TestExecutionNodeClientClosedGracefully(tt *testing.T) { // Add createExecNode function to recreate it each time for rapid test createExecNode := func() (*executionNode, func()) { en := new(executionNode) - en.start(t) + en.start(tt) return en, func() { - en.stop(t) + en.stop(tt) } } // Add rapid test, to check graceful close on different number of requests - rapid.Check(t, func(t *rapid.T) { + rapid.Check(tt, func(t *rapid.T) { en, closer := createExecNode() defer closer() @@ -505,11 +495,8 @@ func TestExecutionNodeClientClosedGracefully(t *testing.T) { connectionFactory.ExecutionNodeGRPCTimeout = time.Second // set the connection pool cache size cacheSize := 1 - cache, _ := lru.NewWithEvict[string, *CachedClient](cacheSize, func(_ string, client *CachedClient) { - client.Close() - }) - connectionCache := NewCache(cache, cacheSize) + connectionCache := NewCache(getCache(tt, cacheSize), cacheSize) // set metrics reporting connectionFactory.AccessMetrics = metrics.NewNoopCollector() connectionFactory.Manager = NewManager( From 72d13303f587af13b3ea3e1d1e7c9432d61d9514 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 15 Aug 2023 19:02:32 +0100 Subject: [PATCH 40/66] Refactor connection tests, add error and flag check --- engine/access/rpc/connection/connection_test.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/engine/access/rpc/connection/connection_test.go b/engine/access/rpc/connection/connection_test.go index 4364409ba32..a5f79a35db5 100644 --- a/engine/access/rpc/connection/connection_test.go +++ b/engine/access/rpc/connection/connection_test.go @@ -599,8 +599,8 @@ func TestExecutionEvictingCacheClients(t *testing.T) { ctx := context.Background() // Retrieve the cached client from the cache - cachedClient, _ := cache.Get(clientAddress) - + cachedClient, ok := cache.Get(clientAddress) + require.True(t, ok) // Schedule the invalidation of the access API client after a delay time.AfterFunc(250*time.Millisecond, func() { // Invalidate the access API client @@ -655,8 +655,8 @@ func TestCircuitBreakerExecutionNode(t *testing.T) { // Set the connection pool cache size. cacheSize := 1 - connectionCache, _ := lru.New[string, *CachedClient](cacheSize) - + connectionCache, err := lru.New[string, *CachedClient](cacheSize) + require.Nil(t, err) connectionFactory.Manager = NewManager( NewCache(connectionCache, cacheSize), unittest.Logger(), @@ -740,7 +740,8 @@ func TestCircuitBreakerCollectionNode(t *testing.T) { // Set the connection pool cache size. cacheSize := 1 - connectionCache, _ := lru.New[string, *CachedClient](cacheSize) + connectionCache, err := lru.New[string, *CachedClient](cacheSize) + require.Nil(t, err) connectionFactory.Manager = NewManager( NewCache(connectionCache, cacheSize), unittest.Logger(), From 3eed6dfafda231f9a25cc1f9c2718a6d231ea336 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Wed, 16 Aug 2023 11:39:10 +0100 Subject: [PATCH 41/66] Refactor simple cache to generic version --- engine/consensus/approvals/approvals_lru_cache.go | 14 ++++++-------- fvm/storage/derived/derived_chain_data.go | 11 +++++------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/engine/consensus/approvals/approvals_lru_cache.go b/engine/consensus/approvals/approvals_lru_cache.go index f4b84d008a1..001f2994fa1 100644 --- a/engine/consensus/approvals/approvals_lru_cache.go +++ b/engine/consensus/approvals/approvals_lru_cache.go @@ -3,15 +3,14 @@ package approvals import ( "sync" - "github.com/hashicorp/golang-lru/simplelru" - + "github.com/hashicorp/golang-lru/v2/simplelru" "github.com/onflow/flow-go/model/flow" ) // LruCache is a wrapper over `simplelru.LRUCache` that provides needed api for processing result approvals // Extends functionality of `simplelru.LRUCache` by introducing additional index for quicker access. type LruCache struct { - lru simplelru.LRUCache + lru simplelru.LRUCache[flow.Identifier, *flow.ResultApproval] lock sync.RWMutex // secondary index by result id, since multiple approvals could // reference same result @@ -21,8 +20,7 @@ type LruCache struct { func NewApprovalsLRUCache(limit uint) *LruCache { byResultID := make(map[flow.Identifier]map[flow.Identifier]struct{}) // callback has to be called while we are holding lock - lru, _ := simplelru.NewLRU(int(limit), func(key interface{}, value interface{}) { - approval := value.(*flow.ResultApproval) + lru, _ := simplelru.NewLRU(int(limit), func(key flow.Identifier, approval *flow.ResultApproval) { delete(byResultID[approval.Body.ExecutionResultID], approval.Body.PartialID()) if len(byResultID[approval.Body.ExecutionResultID]) == 0 { delete(byResultID, approval.Body.ExecutionResultID) @@ -40,7 +38,7 @@ func (c *LruCache) Peek(approvalID flow.Identifier) *flow.ResultApproval { // check if we have it in the cache resource, cached := c.lru.Peek(approvalID) if cached { - return resource.(*flow.ResultApproval) + return resource } return nil @@ -52,7 +50,7 @@ func (c *LruCache) Get(approvalID flow.Identifier) *flow.ResultApproval { // check if we have it in the cache resource, cached := c.lru.Get(approvalID) if cached { - return resource.(*flow.ResultApproval) + return resource } return nil @@ -74,7 +72,7 @@ func (c *LruCache) TakeByResultID(resultID flow.Identifier) []*flow.ResultApprov // no need to cleanup secondary index since it will be // cleaned up in evict callback _ = c.lru.Remove(approvalID) - approvals = append(approvals, resource.(*flow.ResultApproval)) + approvals = append(approvals, resource) } } diff --git a/fvm/storage/derived/derived_chain_data.go b/fvm/storage/derived/derived_chain_data.go index a3ec9a488df..35880b0c827 100644 --- a/fvm/storage/derived/derived_chain_data.go +++ b/fvm/storage/derived/derived_chain_data.go @@ -4,8 +4,7 @@ import ( "fmt" "sync" - "github.com/hashicorp/golang-lru/simplelru" - + "github.com/hashicorp/golang-lru/v2/simplelru" "github.com/onflow/flow-go/model/flow" ) @@ -21,11 +20,11 @@ type DerivedChainData struct { // on Get. mutex sync.Mutex - lru *simplelru.LRU + lru *simplelru.LRU[flow.Identifier, *DerivedBlockData] } func NewDerivedChainData(chainCacheSize uint) (*DerivedChainData, error) { - lru, err := simplelru.NewLRU(int(chainCacheSize), nil) + lru, err := simplelru.NewLRU[flow.Identifier, *DerivedBlockData](int(chainCacheSize), nil) if err != nil { return nil, fmt.Errorf("cannot create LRU cache: %w", err) } @@ -40,7 +39,7 @@ func (chain *DerivedChainData) unsafeGet( ) *DerivedBlockData { currentEntry, ok := chain.lru.Get(currentBlockId) if ok { - return currentEntry.(*DerivedBlockData) + return currentEntry } return nil @@ -70,7 +69,7 @@ func (chain *DerivedChainData) GetOrCreateDerivedBlockData( var current *DerivedBlockData parentEntry, ok := chain.lru.Get(parentBlockId) if ok { - current = parentEntry.(*DerivedBlockData).NewChildDerivedBlockData() + current = parentEntry.NewChildDerivedBlockData() } else { current = NewEmptyDerivedBlockData(0) } From 659e22f12550fccc8b37697ea98b97e457be91d2 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Wed, 16 Aug 2023 11:48:51 +0100 Subject: [PATCH 42/66] Group imports in connection test --- engine/access/rpc/connection/connection_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/engine/access/rpc/connection/connection_test.go b/engine/access/rpc/connection/connection_test.go index a5f79a35db5..ba602c4a619 100644 --- a/engine/access/rpc/connection/connection_test.go +++ b/engine/access/rpc/connection/connection_test.go @@ -9,8 +9,6 @@ import ( "time" lru "github.com/hashicorp/golang-lru/v2" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/execution" "github.com/sony/gobreaker" "github.com/stretchr/testify/assert" testifymock "github.com/stretchr/testify/mock" @@ -24,6 +22,9 @@ import ( "github.com/onflow/flow-go/module/metrics" "github.com/onflow/flow-go/utils/unittest" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/execution" + ) func TestProxyAccessAPI(t *testing.T) { From a4ae34397108a70180ba7acc48b0a3c551934784 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Mon, 21 Aug 2023 14:11:23 +0100 Subject: [PATCH 43/66] Remove mock file from gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 024b0d9417e..1be2e18a99f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ /cmd/testclient/testclient /cmd/util/util /cmd/bootstrap/bootstrap -/engine/access/rpc/backend/mock_communicator.go # crypto relic folder crypto/relic/ From a6e33aa58afc77f550be9de8fcba4a46af095566 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Mon, 21 Aug 2023 15:41:42 +0100 Subject: [PATCH 44/66] Move node communicator interface out of backend file --- engine/access/rpc/backend/backend.go | 8 -------- engine/access/rpc/backend/node_communicator.go | 10 ++++++++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index e532be24ad5..8dfbf993b8f 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -91,14 +91,6 @@ type Config struct { CircuitBreakerConfig connection.CircuitBreakerConfig // the configuration for circuit breaker } -type Communicator interface { - CallAvailableNode( - nodes flow.IdentityList, - call NodeAction, - shouldTerminateOnError ErrorTerminator, - ) error -} - type Params struct { State protocol.State CollectionRPC accessproto.AccessAPIClient diff --git a/engine/access/rpc/backend/node_communicator.go b/engine/access/rpc/backend/node_communicator.go index d75432b0b29..b3a73e5b545 100644 --- a/engine/access/rpc/backend/node_communicator.go +++ b/engine/access/rpc/backend/node_communicator.go @@ -20,6 +20,16 @@ type NodeAction func(node *flow.Identity) error // It takes an error as input and returns a boolean value indicating whether the error should be considered terminal. type ErrorTerminator func(node *flow.Identity, err error) bool +type Communicator interface { + CallAvailableNode( + nodes flow.IdentityList, + call NodeAction, + shouldTerminateOnError ErrorTerminator, + ) error +} + +var _ Communicator = (*NodeCommunicator)(nil) + // NodeCommunicator is responsible for calling available nodes in the backend. type NodeCommunicator struct { nodeSelectorFactory NodeSelectorFactory From 6b95d409b4f2a65044e7ee40a1d696bbf88077fb Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Mon, 21 Aug 2023 16:32:43 +0100 Subject: [PATCH 45/66] Remove irrelevant code --- module/metrics.go | 12 ------------ module/metrics/access.go | 2 -- 2 files changed, 14 deletions(-) diff --git a/module/metrics.go b/module/metrics.go index e5bc5b6fecd..b1bfbad81ae 100644 --- a/module/metrics.go +++ b/module/metrics.go @@ -646,8 +646,6 @@ type AccessMetrics interface { TransactionMetrics BackendScriptsMetrics - //TrnasactionResultMetrics - // UpdateExecutionReceiptMaxHeight is called whenever we store an execution receipt from a block from a newer height UpdateExecutionReceiptMaxHeight(height uint64) @@ -655,16 +653,6 @@ type AccessMetrics interface { UpdateLastFullBlockHeight(height uint64) } -type TrnasactionResultMetrics interface { - OnKeyHitSuccess() - OnKeyHitFailure() - - OnKeyAddSuccess() - OnKeyEviction() - - OnKeyAddFailureDueToFullCache() -} - type ExecutionResultStats struct { ComputationUsed uint64 MemoryUsed uint64 diff --git a/module/metrics/access.go b/module/metrics/access.go index 56e24b70da2..effb24c4326 100644 --- a/module/metrics/access.go +++ b/module/metrics/access.go @@ -32,8 +32,6 @@ type AccessCollector struct { module.TransactionMetrics module.BackendScriptsMetrics - //module.TransactionResultMetrics - connectionReused prometheus.Counter connectionsInPool *prometheus.GaugeVec connectionAdded prometheus.Counter From 5ff6b101b649f59882616ffc8ebb099ef7613d9f Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Mon, 21 Aug 2023 22:07:03 +0100 Subject: [PATCH 46/66] Fix imports order according to convention --- engine/access/rpc/backend/backend_block_headers.go | 5 +++-- .../access/rpc/backend/backend_transactions_test.go | 13 +++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/engine/access/rpc/backend/backend_block_headers.go b/engine/access/rpc/backend/backend_block_headers.go index 9b51201d067..ac4116224d4 100644 --- a/engine/access/rpc/backend/backend_block_headers.go +++ b/engine/access/rpc/backend/backend_block_headers.go @@ -3,12 +3,13 @@ package backend import ( "context" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) type backendBlockHeaders struct { diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index c577886912c..26bd3c7ffbf 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -5,6 +5,13 @@ import ( "fmt" "github.com/dgraph-io/badger/v2" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + acc "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" @@ -13,12 +20,6 @@ import ( "github.com/onflow/flow-go/state/protocol/util" "github.com/onflow/flow-go/storage" "github.com/onflow/flow-go/utils/unittest" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) func (suite *Suite) WithPreConfiguredState(f func(snap protocol.Snapshot)) { From 1e289828c0dfbf61ff604439e8701c7259cbe6cf Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 22 Aug 2023 10:45:07 +0100 Subject: [PATCH 47/66] Fix imports ordering --- engine/access/rpc/connection/connection_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/access/rpc/connection/connection_test.go b/engine/access/rpc/connection/connection_test.go index ba602c4a619..4d7a0535225 100644 --- a/engine/access/rpc/connection/connection_test.go +++ b/engine/access/rpc/connection/connection_test.go @@ -20,11 +20,11 @@ import ( "google.golang.org/grpc/status" "pgregory.net/rapid" - "github.com/onflow/flow-go/module/metrics" - "github.com/onflow/flow-go/utils/unittest" "github.com/onflow/flow/protobuf/go/flow/access" "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/onflow/flow-go/module/metrics" + "github.com/onflow/flow-go/utils/unittest" ) func TestProxyAccessAPI(t *testing.T) { From 7a2cbb4a8b52d2c386d59405b5d5fcc74d7ab40e Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 22 Aug 2023 10:48:56 +0100 Subject: [PATCH 48/66] Fix linter related issues for security libs --- engine/access/rpc/backend/backend.go | 2 +- engine/access/rpc/backend/backend_scripts.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 033b8b96303..eafed29e301 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -2,7 +2,7 @@ package backend import ( "context" - "crypto/md5" + "crypto/md5" // #nosec "fmt" "net" "strconv" diff --git a/engine/access/rpc/backend/backend_scripts.go b/engine/access/rpc/backend/backend_scripts.go index 90433cf8a1f..93d18d72e25 100644 --- a/engine/access/rpc/backend/backend_scripts.go +++ b/engine/access/rpc/backend/backend_scripts.go @@ -1,9 +1,9 @@ package backend import ( - "crypto/md5" //nolint:gosec "bytes" "context" + "crypto/md5" //nolint:gosec "io" "time" From fc26728abdd52cdfa7cc37695729127bddc544f6 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 22 Aug 2023 10:51:25 +0100 Subject: [PATCH 49/66] Fix imports in derived_chain_data.go --- fvm/storage/derived/derived_chain_data.go | 1 + 1 file changed, 1 insertion(+) diff --git a/fvm/storage/derived/derived_chain_data.go b/fvm/storage/derived/derived_chain_data.go index 35880b0c827..8bcf0b03d00 100644 --- a/fvm/storage/derived/derived_chain_data.go +++ b/fvm/storage/derived/derived_chain_data.go @@ -5,6 +5,7 @@ import ( "sync" "github.com/hashicorp/golang-lru/v2/simplelru" + "github.com/onflow/flow-go/model/flow" ) From 56e03073d70469707b5b5ec8178a10e21d3834ad Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 22 Aug 2023 12:52:14 +0100 Subject: [PATCH 50/66] Bring mock generation command to conventional way --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b09174f2dee..46b87640022 100644 --- a/Makefile +++ b/Makefile @@ -194,7 +194,7 @@ generate-mocks: install-mock-generators mockery --name 'API' --dir="./engine/protocol" --case=underscore --output="./engine/protocol/mock" --outpkg="mock" mockery --name '.*' --dir="./engine/access/state_stream" --case=underscore --output="./engine/access/state_stream/mock" --outpkg="mock" mockery --name 'ConnectionFactory' --dir="./engine/access/rpc/connection" --case=underscore --output="./engine/access/rpc/connection/mock" --outpkg="mock" - mockery --name 'Communicator' --structname 'NodeCommunicatorMock' --dir="./engine/access/rpc/backend" --case=underscore --output="./engine/access/rpc/backend" --inpackage + mockery --name 'Communicator' --dir="./engine/access/rpc/backend" --case=underscore --output="./engine/access/rpc/backend/mock" --outpkg="mock" mockery --name '.*' --dir=model/fingerprint --case=underscore --output="./model/fingerprint/mock" --outpkg="mock" mockery --name 'ExecForkActor' --structname 'ExecForkActorMock' --dir=module/mempool/consensus/mock/ --case=underscore --output="./module/mempool/consensus/mock/" --outpkg="mock" From b69632bb3b5424dad3734cf3b1591f6b0edd1933 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 22 Aug 2023 12:56:11 +0100 Subject: [PATCH 51/66] Refactor communicator interface to reduce dependency between packages --- .../integration_unsecure_grpc_server_test.go | 19 ++++++++++--------- engine/access/rest_api_test.go | 15 ++++++++------- engine/access/rpc/backend/backend_test.go | 4 ++-- .../access/rpc/backend/node_communicator.go | 8 ++++---- engine/access/secure_grpcr_test.go | 17 +++++++++-------- 5 files changed, 33 insertions(+), 30 deletions(-) diff --git a/engine/access/integration_unsecure_grpc_server_test.go b/engine/access/integration_unsecure_grpc_server_test.go index 9ad3e7f54df..cf9ec1fa744 100644 --- a/engine/access/integration_unsecure_grpc_server_test.go +++ b/engine/access/integration_unsecure_grpc_server_test.go @@ -7,6 +7,16 @@ import ( "testing" "time" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + executiondataproto "github.com/onflow/flow/protobuf/go/flow/executiondata" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "github.com/onflow/flow-go/engine" accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rpc" @@ -27,15 +37,6 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - executiondataproto "github.com/onflow/flow/protobuf/go/flow/executiondata" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" ) // SameGRPCPortTestSuite verifies both AccessAPI and ExecutionDataAPI client continue to work when configured diff --git a/engine/access/rest_api_test.go b/engine/access/rest_api_test.go index 5164bba6106..1b891832249 100644 --- a/engine/access/rest_api_test.go +++ b/engine/access/rest_api_test.go @@ -11,6 +11,14 @@ import ( "time" "github.com/antihax/optional" + restclient "github.com/onflow/flow/openapi/go-client-generated" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc/credentials" + accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rest/request" "github.com/onflow/flow-go/engine/access/rest/routes" @@ -27,13 +35,6 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" - restclient "github.com/onflow/flow/openapi/go-client-generated" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc/credentials" ) // RestAPITestSuite tests that the Access node serves the REST API defined via the OpenApi spec accurately diff --git a/engine/access/rpc/backend/backend_test.go b/engine/access/rpc/backend/backend_test.go index 8c38a34920e..1a4989dac79 100644 --- a/engine/access/rpc/backend/backend_test.go +++ b/engine/access/rpc/backend/backend_test.go @@ -54,7 +54,7 @@ type Suite struct { archiveClient *access.AccessAPIClient connectionFactory *backendmock.ConnectionFactory - communicator *NodeCommunicatorMock + communicator *backendmock.Communicator chainID flow.ChainID } @@ -85,7 +85,7 @@ func (suite *Suite) SetupTest() { suite.historicalAccessClient = new(access.AccessAPIClient) suite.connectionFactory = new(backendmock.ConnectionFactory) - suite.communicator = new(NodeCommunicatorMock) + suite.communicator = new(backendmock.Communicator) } func (suite *Suite) TestPing() { diff --git a/engine/access/rpc/backend/node_communicator.go b/engine/access/rpc/backend/node_communicator.go index b3a73e5b545..448b0c7b267 100644 --- a/engine/access/rpc/backend/node_communicator.go +++ b/engine/access/rpc/backend/node_communicator.go @@ -23,8 +23,8 @@ type ErrorTerminator func(node *flow.Identity, err error) bool type Communicator interface { CallAvailableNode( nodes flow.IdentityList, - call NodeAction, - shouldTerminateOnError ErrorTerminator, + call func(node *flow.Identity) error, + shouldTerminateOnError func(node *flow.Identity, err error) bool, ) error } @@ -49,8 +49,8 @@ func NewNodeCommunicator(circuitBreakerEnabled bool) *NodeCommunicator { // If the maximum failed request count is reached, it returns the accumulated errors. func (b *NodeCommunicator) CallAvailableNode( nodes flow.IdentityList, - call NodeAction, - shouldTerminateOnError ErrorTerminator, + call func(id *flow.Identity) error, + shouldTerminateOnError func(node *flow.Identity, err error) bool, ) error { var errs *multierror.Error nodeSelector, err := b.nodeSelectorFactory.SelectNodes(nodes) diff --git a/engine/access/secure_grpcr_test.go b/engine/access/secure_grpcr_test.go index d8d4f71b732..d5f64352cf6 100644 --- a/engine/access/secure_grpcr_test.go +++ b/engine/access/secure_grpcr_test.go @@ -7,6 +7,15 @@ import ( "testing" "time" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "github.com/onflow/flow-go/crypto" accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rpc" @@ -21,14 +30,6 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" ) // SecureGRPCTestSuite tests that Access node provides a secure GRPC server From fff2cf2db368ae019a563f1b82b0313cdb07ae26 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 22 Aug 2023 13:00:49 +0100 Subject: [PATCH 52/66] Rename bnd variable in access_node_builder --- cmd/access/node_builder/access_node_builder.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/access/node_builder/access_node_builder.go b/cmd/access/node_builder/access_node_builder.go index 68d32a9efa4..2e607b1ab63 100644 --- a/cmd/access/node_builder/access_node_builder.go +++ b/cmd/access/node_builder/access_node_builder.go @@ -1094,7 +1094,7 @@ func (builder *FlowAccessNodeBuilder) Build() (cmd.Node, error) { ), } - bnd := backend.New(backend.Params{ + nodeBackend := backend.New(backend.Params{ State: node.State, CollectionRPC: builder.CollectionRPC, HistoricalAccessNodes: builder.HistoricalAccessRPCs, @@ -1127,8 +1127,8 @@ func (builder *FlowAccessNodeBuilder) Build() (cmd.Node, error) { builder.AccessMetrics, builder.rpcMetricsEnabled, builder.Me, - bnd, - bnd, + nodeBackend, + nodeBackend, builder.secureGrpcServer, builder.unsecureGrpcServer, ) From a59b7630db01d5c32cb5a53390f95963094228af Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 22 Aug 2023 13:19:30 +0100 Subject: [PATCH 53/66] Refine mock call expectations with type arguments in backend transactions tests --- engine/access/rpc/backend/backend_transactions_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index 26bd3c7ffbf..9d7e12f5024 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -199,7 +199,7 @@ func (suite *Suite) TestGetTransactionResultFromCache() { } suite.historicalAccessClient. - On("GetTransactionResult", mock.Anything, mock.Anything). + On("GetTransactionResult", mock.AnythingOfType("*context.emptyCtx"), mock.AnythingOfType("*access.GetTransactionRequest")). Return(&transactionResultResponse, nil).Once() backend := New(Params{ @@ -238,7 +238,7 @@ func (suite *Suite) TestGetTransactionResultCacheNonExistent() { suite.WithGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { suite.historicalAccessClient. - On("GetTransactionResult", mock.Anything, mock.Anything). + On("GetTransactionResult", mock.AnythingOfType("*context.emptyCtx"), mock.AnythingOfType("*access.GetTransactionRequest")). Return(nil, status.Errorf(codes.NotFound, "no known transaction with ID %s", tx.ID())).Once() backend := New(Params{ @@ -281,7 +281,7 @@ func (suite *Suite) TestGetTransactionResultCacheNonExistent() { func (suite *Suite) TestGetTransactionResultUnknownFromCache() { suite.WithGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { suite.historicalAccessClient. - On("GetTransactionResult", mock.Anything, mock.Anything). + On("GetTransactionResult", mock.AnythingOfType("*context.emptyCtx"), mock.AnythingOfType("*access.GetTransactionRequest")). Return(nil, status.Errorf(codes.NotFound, "no known transaction with ID %s", tx.ID())).Once() backend := New(Params{ From 730b46e1f2f6454bd4ab3a7c96ec56c25b3300ac Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 22 Aug 2023 17:42:41 +0100 Subject: [PATCH 54/66] Add backend transaction tests annotations --- .../rpc/backend/backend_transactions_test.go | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go index 9d7e12f5024..3b1464a3e13 100644 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ b/engine/access/rpc/backend/backend_transactions_test.go @@ -22,7 +22,7 @@ import ( "github.com/onflow/flow-go/utils/unittest" ) -func (suite *Suite) WithPreConfiguredState(f func(snap protocol.Snapshot)) { +func (suite *Suite) withPreConfiguredState(f func(snap protocol.Snapshot)) { identities := unittest.CompleteIdentitySet() rootSnapshot := unittest.RootSnapshotFixture(identities) util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { @@ -54,8 +54,9 @@ func (suite *Suite) WithPreConfiguredState(f func(snap protocol.Snapshot)) { } +// TestGetTransactionResultReturnsUnknown returns unknown result when tx not found func (suite *Suite) TestGetTransactionResultReturnsUnknown() { - suite.WithPreConfiguredState(func(snap protocol.Snapshot) { + suite.withPreConfiguredState(func(snap protocol.Snapshot) { block := unittest.BlockFixture() tbody := unittest.TransactionBodyFixture() tx := unittest.TransactionFixture() @@ -88,8 +89,9 @@ func (suite *Suite) TestGetTransactionResultReturnsUnknown() { }) } +// TestGetTransactionResultReturnsTransactionError returns error from transaction storage func (suite *Suite) TestGetTransactionResultReturnsTransactionError() { - suite.WithPreConfiguredState(func(snap protocol.Snapshot) { + suite.withPreConfiguredState(func(snap protocol.Snapshot) { block := unittest.BlockFixture() tbody := unittest.TransactionBodyFixture() tx := unittest.TransactionFixture() @@ -128,8 +130,9 @@ func (suite *Suite) TestGetTransactionResultReturnsTransactionError() { }) } +// TestGetTransactionResultReturnsValidTransactionResultFromHistoricNode tests lookup in historic nodes func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResultFromHistoricNode() { - suite.WithPreConfiguredState(func(snap protocol.Snapshot) { + suite.withPreConfiguredState(func(snap protocol.Snapshot) { block := unittest.BlockFixture() tbody := unittest.TransactionBodyFixture() tx := unittest.TransactionFixture() @@ -174,8 +177,8 @@ func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResultFromHis }) } -func (suite *Suite) WithGetTransactionCachingTestSetup(f func(b *flow.Block, t *flow.Transaction)) { - suite.WithPreConfiguredState(func(snap protocol.Snapshot) { +func (suite *Suite) withGetTransactionCachingTestSetup(f func(b *flow.Block, t *flow.Transaction)) { + suite.withPreConfiguredState(func(snap protocol.Snapshot) { block := unittest.BlockFixture() tbody := unittest.TransactionBodyFixture() tx := unittest.TransactionFixture() @@ -191,8 +194,9 @@ func (suite *Suite) WithGetTransactionCachingTestSetup(f func(b *flow.Block, t * }) } +// TestGetTransactionResultFromCache get historic transaction result from cache func (suite *Suite) TestGetTransactionResultFromCache() { - suite.WithGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { + suite.withGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { transactionResultResponse := access.TransactionResultResponse{ Status: entities.TransactionStatus_EXECUTED, StatusCode: uint32(entities.TransactionStatus_EXECUTED), @@ -234,8 +238,9 @@ func (suite *Suite) TestGetTransactionResultFromCache() { }) } +// TestGetTransactionResultCacheNonExistent tests caches non existing result func (suite *Suite) TestGetTransactionResultCacheNonExistent() { - suite.WithGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { + suite.withGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { suite.historicalAccessClient. On("GetTransactionResult", mock.AnythingOfType("*context.emptyCtx"), mock.AnythingOfType("*access.GetTransactionRequest")). @@ -278,8 +283,9 @@ func (suite *Suite) TestGetTransactionResultCacheNonExistent() { }) } +// TestGetTransactionResultUnknownFromCache retrive unknown result from cache func (suite *Suite) TestGetTransactionResultUnknownFromCache() { - suite.WithGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { + suite.withGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { suite.historicalAccessClient. On("GetTransactionResult", mock.AnythingOfType("*context.emptyCtx"), mock.AnythingOfType("*access.GetTransactionRequest")). Return(nil, status.Errorf(codes.NotFound, "no known transaction with ID %s", tx.ID())).Once() From 2af6f84404552c9e6ce08ce1c4cfb272ee6b5c73 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Tue, 22 Aug 2023 17:58:59 +0100 Subject: [PATCH 55/66] fix imports with locals at the bottom --- engine/access/state_stream/mock/get_execution_data_func.go | 3 ++- engine/access/state_stream/mock/get_start_height_func.go | 3 ++- engine/consensus/approvals/approvals_lru_cache.go | 1 + engine/consensus/mock/matching_core.go | 3 ++- engine/consensus/mock/proposal_provider.go | 3 ++- engine/consensus/mock/sealing_core.go | 3 ++- engine/consensus/mock/sealing_observation.go | 3 ++- 7 files changed, 13 insertions(+), 6 deletions(-) diff --git a/engine/access/state_stream/mock/get_execution_data_func.go b/engine/access/state_stream/mock/get_execution_data_func.go index 50fe8087e21..506cc8d3d1c 100644 --- a/engine/access/state_stream/mock/get_execution_data_func.go +++ b/engine/access/state_stream/mock/get_execution_data_func.go @@ -5,8 +5,9 @@ package mock import ( context "context" - execution_data "github.com/onflow/flow-go/module/executiondatasync/execution_data" mock "github.com/stretchr/testify/mock" + + execution_data "github.com/onflow/flow-go/module/executiondatasync/execution_data" ) // GetExecutionDataFunc is an autogenerated mock type for the GetExecutionDataFunc type diff --git a/engine/access/state_stream/mock/get_start_height_func.go b/engine/access/state_stream/mock/get_start_height_func.go index b97a77e1d39..d1c93d2ed1c 100644 --- a/engine/access/state_stream/mock/get_start_height_func.go +++ b/engine/access/state_stream/mock/get_start_height_func.go @@ -3,8 +3,9 @@ package mock import ( - flow "github.com/onflow/flow-go/model/flow" mock "github.com/stretchr/testify/mock" + + flow "github.com/onflow/flow-go/model/flow" ) // GetStartHeightFunc is an autogenerated mock type for the GetStartHeightFunc type diff --git a/engine/consensus/approvals/approvals_lru_cache.go b/engine/consensus/approvals/approvals_lru_cache.go index 001f2994fa1..26fccc715ff 100644 --- a/engine/consensus/approvals/approvals_lru_cache.go +++ b/engine/consensus/approvals/approvals_lru_cache.go @@ -4,6 +4,7 @@ import ( "sync" "github.com/hashicorp/golang-lru/v2/simplelru" + "github.com/onflow/flow-go/model/flow" ) diff --git a/engine/consensus/mock/matching_core.go b/engine/consensus/mock/matching_core.go index 331d467cf90..b7b1bfca244 100644 --- a/engine/consensus/mock/matching_core.go +++ b/engine/consensus/mock/matching_core.go @@ -3,8 +3,9 @@ package mock import ( - flow "github.com/onflow/flow-go/model/flow" mock "github.com/stretchr/testify/mock" + + flow "github.com/onflow/flow-go/model/flow" ) // MatchingCore is an autogenerated mock type for the MatchingCore type diff --git a/engine/consensus/mock/proposal_provider.go b/engine/consensus/mock/proposal_provider.go index b53cef236e1..ad0b3d5923b 100644 --- a/engine/consensus/mock/proposal_provider.go +++ b/engine/consensus/mock/proposal_provider.go @@ -3,8 +3,9 @@ package mock import ( - messages "github.com/onflow/flow-go/model/messages" mock "github.com/stretchr/testify/mock" + + messages "github.com/onflow/flow-go/model/messages" ) // ProposalProvider is an autogenerated mock type for the ProposalProvider type diff --git a/engine/consensus/mock/sealing_core.go b/engine/consensus/mock/sealing_core.go index ee3e9bbb63a..002694a5e38 100644 --- a/engine/consensus/mock/sealing_core.go +++ b/engine/consensus/mock/sealing_core.go @@ -3,8 +3,9 @@ package mock import ( - flow "github.com/onflow/flow-go/model/flow" mock "github.com/stretchr/testify/mock" + + flow "github.com/onflow/flow-go/model/flow" ) // SealingCore is an autogenerated mock type for the SealingCore type diff --git a/engine/consensus/mock/sealing_observation.go b/engine/consensus/mock/sealing_observation.go index 040f3a27217..831e27a564a 100644 --- a/engine/consensus/mock/sealing_observation.go +++ b/engine/consensus/mock/sealing_observation.go @@ -3,8 +3,9 @@ package mock import ( - flow "github.com/onflow/flow-go/model/flow" mock "github.com/stretchr/testify/mock" + + flow "github.com/onflow/flow-go/model/flow" ) // SealingObservation is an autogenerated mock type for the SealingObservation type From 689ac6d8f03f45a8ac2bb95dc5720ca659d41078 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Wed, 23 Aug 2023 14:39:52 +0100 Subject: [PATCH 56/66] Revert import change in mock folders --- engine/access/state_stream/mock/get_execution_data_func.go | 3 +-- engine/access/state_stream/mock/get_start_height_func.go | 3 +-- engine/consensus/mock/matching_core.go | 3 +-- engine/consensus/mock/sealing_core.go | 3 +-- engine/consensus/mock/sealing_observation.go | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/engine/access/state_stream/mock/get_execution_data_func.go b/engine/access/state_stream/mock/get_execution_data_func.go index 506cc8d3d1c..50fe8087e21 100644 --- a/engine/access/state_stream/mock/get_execution_data_func.go +++ b/engine/access/state_stream/mock/get_execution_data_func.go @@ -5,9 +5,8 @@ package mock import ( context "context" - mock "github.com/stretchr/testify/mock" - execution_data "github.com/onflow/flow-go/module/executiondatasync/execution_data" + mock "github.com/stretchr/testify/mock" ) // GetExecutionDataFunc is an autogenerated mock type for the GetExecutionDataFunc type diff --git a/engine/access/state_stream/mock/get_start_height_func.go b/engine/access/state_stream/mock/get_start_height_func.go index d1c93d2ed1c..b97a77e1d39 100644 --- a/engine/access/state_stream/mock/get_start_height_func.go +++ b/engine/access/state_stream/mock/get_start_height_func.go @@ -3,9 +3,8 @@ package mock import ( - mock "github.com/stretchr/testify/mock" - flow "github.com/onflow/flow-go/model/flow" + mock "github.com/stretchr/testify/mock" ) // GetStartHeightFunc is an autogenerated mock type for the GetStartHeightFunc type diff --git a/engine/consensus/mock/matching_core.go b/engine/consensus/mock/matching_core.go index b7b1bfca244..331d467cf90 100644 --- a/engine/consensus/mock/matching_core.go +++ b/engine/consensus/mock/matching_core.go @@ -3,9 +3,8 @@ package mock import ( - mock "github.com/stretchr/testify/mock" - flow "github.com/onflow/flow-go/model/flow" + mock "github.com/stretchr/testify/mock" ) // MatchingCore is an autogenerated mock type for the MatchingCore type diff --git a/engine/consensus/mock/sealing_core.go b/engine/consensus/mock/sealing_core.go index 002694a5e38..ee3e9bbb63a 100644 --- a/engine/consensus/mock/sealing_core.go +++ b/engine/consensus/mock/sealing_core.go @@ -3,9 +3,8 @@ package mock import ( - mock "github.com/stretchr/testify/mock" - flow "github.com/onflow/flow-go/model/flow" + mock "github.com/stretchr/testify/mock" ) // SealingCore is an autogenerated mock type for the SealingCore type diff --git a/engine/consensus/mock/sealing_observation.go b/engine/consensus/mock/sealing_observation.go index 831e27a564a..040f3a27217 100644 --- a/engine/consensus/mock/sealing_observation.go +++ b/engine/consensus/mock/sealing_observation.go @@ -3,9 +3,8 @@ package mock import ( - mock "github.com/stretchr/testify/mock" - flow "github.com/onflow/flow-go/model/flow" + mock "github.com/stretchr/testify/mock" ) // SealingObservation is an autogenerated mock type for the SealingObservation type From eb2ba851f1ded4f8b08b72e57e58aaf8c293edc8 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Wed, 23 Aug 2023 14:49:04 +0100 Subject: [PATCH 57/66] Add generated mock files --- .../access/rpc/backend/mock/communicator.go | 42 +++++++++++++++++++ .../mock/get_execution_data_func.go | 3 +- .../mock/get_start_height_func.go | 3 +- 3 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 engine/access/rpc/backend/mock/communicator.go diff --git a/engine/access/rpc/backend/mock/communicator.go b/engine/access/rpc/backend/mock/communicator.go new file mode 100644 index 00000000000..ab7498ac8f8 --- /dev/null +++ b/engine/access/rpc/backend/mock/communicator.go @@ -0,0 +1,42 @@ +// Code generated by mockery v2.21.4. DO NOT EDIT. + +package mock + +import ( + flow "github.com/onflow/flow-go/model/flow" + mock "github.com/stretchr/testify/mock" +) + +// Communicator is an autogenerated mock type for the Communicator type +type Communicator struct { + mock.Mock +} + +// CallAvailableNode provides a mock function with given fields: nodes, call, shouldTerminateOnError +func (_m *Communicator) CallAvailableNode(nodes flow.IdentityList, call func(*flow.Identity) error, shouldTerminateOnError func(*flow.Identity, error) bool) error { + ret := _m.Called(nodes, call, shouldTerminateOnError) + + var r0 error + if rf, ok := ret.Get(0).(func(flow.IdentityList, func(*flow.Identity) error, func(*flow.Identity, error) bool) error); ok { + r0 = rf(nodes, call, shouldTerminateOnError) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewCommunicator interface { + mock.TestingT + Cleanup(func()) +} + +// NewCommunicator creates a new instance of Communicator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewCommunicator(t mockConstructorTestingTNewCommunicator) *Communicator { + mock := &Communicator{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/engine/access/state_stream/mock/get_execution_data_func.go b/engine/access/state_stream/mock/get_execution_data_func.go index 506cc8d3d1c..50fe8087e21 100644 --- a/engine/access/state_stream/mock/get_execution_data_func.go +++ b/engine/access/state_stream/mock/get_execution_data_func.go @@ -5,9 +5,8 @@ package mock import ( context "context" - mock "github.com/stretchr/testify/mock" - execution_data "github.com/onflow/flow-go/module/executiondatasync/execution_data" + mock "github.com/stretchr/testify/mock" ) // GetExecutionDataFunc is an autogenerated mock type for the GetExecutionDataFunc type diff --git a/engine/access/state_stream/mock/get_start_height_func.go b/engine/access/state_stream/mock/get_start_height_func.go index d1c93d2ed1c..b97a77e1d39 100644 --- a/engine/access/state_stream/mock/get_start_height_func.go +++ b/engine/access/state_stream/mock/get_start_height_func.go @@ -3,9 +3,8 @@ package mock import ( - mock "github.com/stretchr/testify/mock" - flow "github.com/onflow/flow-go/model/flow" + mock "github.com/stretchr/testify/mock" ) // GetStartHeightFunc is an autogenerated mock type for the GetStartHeightFunc type From 8ff9fb849f377be864233e47b29432cbda24967b Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Wed, 23 Aug 2023 14:51:42 +0100 Subject: [PATCH 58/66] Refactor test check for error --- engine/access/rpc/connection/connection_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/access/rpc/connection/connection_test.go b/engine/access/rpc/connection/connection_test.go index 4d7a0535225..d821638fd10 100644 --- a/engine/access/rpc/connection/connection_test.go +++ b/engine/access/rpc/connection/connection_test.go @@ -657,7 +657,7 @@ func TestCircuitBreakerExecutionNode(t *testing.T) { // Set the connection pool cache size. cacheSize := 1 connectionCache, err := lru.New[string, *CachedClient](cacheSize) - require.Nil(t, err) + require.NoError(t, err) connectionFactory.Manager = NewManager( NewCache(connectionCache, cacheSize), unittest.Logger(), @@ -742,7 +742,7 @@ func TestCircuitBreakerCollectionNode(t *testing.T) { cacheSize := 1 connectionCache, err := lru.New[string, *CachedClient](cacheSize) - require.Nil(t, err) + require.NoError(t, err) connectionFactory.Manager = NewManager( NewCache(connectionCache, cacheSize), unittest.Logger(), From e3a49d2393aa7e7816983e62813c9f245a444860 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Fri, 25 Aug 2023 11:01:05 +0100 Subject: [PATCH 59/66] Remove unrelevant changes --- Makefile | 4 +- .../node_builder/access_node_builder.go | 59 +- cmd/observer/node_builder/observer_builder.go | 52 +- engine/access/access_test.go | 201 +-- .../integration_unsecure_grpc_server_test.go | 48 +- engine/access/rest_api_test.go | 50 +- engine/access/rpc/backend/backend.go | 191 ++- engine/access/rpc/backend/backend_accounts.go | 2 +- engine/access/rpc/backend/backend_events.go | 2 +- engine/access/rpc/backend/backend_scripts.go | 15 +- engine/access/rpc/backend/backend_test.go | 1331 +++++++++++------ .../rpc/backend/backend_transactions.go | 76 +- .../rpc/backend/backend_transactions_test.go | 333 ----- .../access/rpc/backend/mock/communicator.go | 3 +- .../access/rpc/backend/node_communicator.go | 14 +- engine/access/rpc/backend/retry.go | 8 +- engine/access/rpc/backend/retry_test.go | 89 +- engine/access/rpc/rate_limit_test.go | 31 +- engine/access/secure_grpcr_test.go | 44 +- .../executiondatasync/tracker/mock/storage.go | 3 +- .../mempool/consensus/mock/exec_fork_actor.go | 3 +- module/metrics.go | 3 +- module/metrics/access.go | 5 +- .../mock/execution_data_requester.go | 3 +- 24 files changed, 1309 insertions(+), 1261 deletions(-) delete mode 100644 engine/access/rpc/backend/backend_transactions_test.go diff --git a/Makefile b/Makefile index 46b87640022..d8b37127d1d 100644 --- a/Makefile +++ b/Makefile @@ -93,7 +93,7 @@ go-math-rand-check: # `exclude` should only specify non production code (test, bench..). # If this check fails, try updating your code by using: # - "crypto/rand" or "flow-go/utils/rand" for non-deterministic randomness - # - "flow-go/crypto/random" for deterministic randomness + # - "flow-go/crypto/random" for deterministic randomness grep --include=\*.go \ --exclude=*test* --exclude=*helper* --exclude=*example* --exclude=*fixture* --exclude=*benchmark* --exclude=*profiler* \ --exclude-dir=*test* --exclude-dir=*helper* --exclude-dir=*example* --exclude-dir=*fixture* --exclude-dir=*benchmark* --exclude-dir=*profiler* -rnw '"math/rand"'; \ @@ -194,8 +194,6 @@ generate-mocks: install-mock-generators mockery --name 'API' --dir="./engine/protocol" --case=underscore --output="./engine/protocol/mock" --outpkg="mock" mockery --name '.*' --dir="./engine/access/state_stream" --case=underscore --output="./engine/access/state_stream/mock" --outpkg="mock" mockery --name 'ConnectionFactory' --dir="./engine/access/rpc/connection" --case=underscore --output="./engine/access/rpc/connection/mock" --outpkg="mock" - mockery --name 'Communicator' --dir="./engine/access/rpc/backend" --case=underscore --output="./engine/access/rpc/backend/mock" --outpkg="mock" - mockery --name '.*' --dir=model/fingerprint --case=underscore --output="./model/fingerprint/mock" --outpkg="mock" mockery --name 'ExecForkActor' --structname 'ExecForkActorMock' --dir=module/mempool/consensus/mock/ --case=underscore --output="./module/mempool/consensus/mock/" --outpkg="mock" mockery --name '.*' --dir=engine/verification/fetcher/ --case=underscore --output="./engine/verification/fetcher/mock" --outpkg="mockfetcher" diff --git a/cmd/access/node_builder/access_node_builder.go b/cmd/access/node_builder/access_node_builder.go index 01f76c695bc..e87f1e6327d 100644 --- a/cmd/access/node_builder/access_node_builder.go +++ b/cmd/access/node_builder/access_node_builder.go @@ -12,14 +12,15 @@ import ( badger "github.com/ipfs/go-ds-badger2" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/routing" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/go-bitswap" "github.com/rs/zerolog" "github.com/spf13/pflag" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/go-bitswap" + "github.com/onflow/flow-go/admin/commands" stateSyncCommands "github.com/onflow/flow-go/admin/commands/state_synchronization" storageCommands "github.com/onflow/flow-go/admin/commands/storage" @@ -130,7 +131,6 @@ type AccessNodeConfig struct { executionDataStartHeight uint64 executionDataConfig edrequester.ExecutionDataConfig PublicNetworkConfig PublicNetworkConfig - TxResultCacheSize uint } type PublicNetworkConfig struct { @@ -207,7 +207,6 @@ func DefaultAccessNodeConfig() *AccessNodeConfig { RetryDelay: edrequester.DefaultRetryDelay, MaxRetryDelay: edrequester.DefaultMaxRetryDelay, }, - TxResultCacheSize: 0, } } @@ -721,8 +720,6 @@ func (builder *FlowAccessNodeBuilder) extraFlags() { flags.DurationVar(&builder.stateStreamConf.ClientSendTimeout, "state-stream-send-timeout", defaultConfig.stateStreamConf.ClientSendTimeout, "maximum wait before timing out while sending a response to a streaming client e.g. 30s") flags.UintVar(&builder.stateStreamConf.ClientSendBufferSize, "state-stream-send-buffer-size", defaultConfig.stateStreamConf.ClientSendBufferSize, "maximum number of responses to buffer within a stream") flags.Float64Var(&builder.stateStreamConf.ResponseLimit, "state-stream-response-limit", defaultConfig.stateStreamConf.ResponseLimit, "max number of responses per second to send over streaming endpoints. this helps manage resources consumed by each client querying data not in the cache e.g. 3 or 0.5. 0 means no limit") - - flags.UintVar(&builder.TxResultCacheSize, "transaction-result-cache-size", defaultConfig.TxResultCacheSize, "transaction result cache size.(Disabled by default i.e 0)") }).ValidateFlags(func() error { if builder.supportsObserver && (builder.PublicNetworkConfig.BindAddress == cmd.NotSet || builder.PublicNetworkConfig.BindAddress == "") { return errors.New("public-network-address must be set if supports-observer is true") @@ -1095,30 +1092,28 @@ func (builder *FlowAccessNodeBuilder) Build() (cmd.Node, error) { ), } - nodeBackend := backend.New(backend.Params{ - State: node.State, - CollectionRPC: builder.CollectionRPC, - HistoricalAccessNodes: builder.HistoricalAccessRPCs, - Blocks: node.Storage.Blocks, - Headers: node.Storage.Headers, - Collections: node.Storage.Collections, - Transactions: node.Storage.Transactions, - ExecutionReceipts: node.Storage.Receipts, - ExecutionResults: node.Storage.Results, - ChainID: node.RootChainID, - AccessMetrics: builder.AccessMetrics, - ConnFactory: connFactory, - RetryEnabled: builder.retryEnabled, - MaxHeightRange: backendConfig.MaxHeightRange, - PreferredExecutionNodeIDs: backendConfig.PreferredExecutionNodeIDs, - FixedExecutionNodeIDs: backendConfig.FixedExecutionNodeIDs, - Log: node.Logger, - SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, - ArchiveAddressList: backendConfig.ArchiveAddressList, - Communicator: backend.NewNodeCommunicator(backendConfig.CircuitBreakerConfig.Enabled), - ScriptExecValidation: backendConfig.ScriptExecValidation, - TxResultCacheSize: builder.TxResultCacheSize, - }) + backend := backend.New( + node.State, + builder.CollectionRPC, + builder.HistoricalAccessRPCs, + node.Storage.Blocks, + node.Storage.Headers, + node.Storage.Collections, + node.Storage.Transactions, + node.Storage.Receipts, + node.Storage.Results, + node.RootChainID, + builder.AccessMetrics, + connFactory, + builder.retryEnabled, + backendConfig.MaxHeightRange, + backendConfig.PreferredExecutionNodeIDs, + backendConfig.FixedExecutionNodeIDs, + node.Logger, + backend.DefaultSnapshotHistoryLimit, + backendConfig.ArchiveAddressList, + backendConfig.ScriptExecValidation, + backendConfig.CircuitBreakerConfig.Enabled) engineBuilder, err := rpc.NewBuilder( node.Logger, @@ -1128,8 +1123,8 @@ func (builder *FlowAccessNodeBuilder) Build() (cmd.Node, error) { builder.AccessMetrics, builder.rpcMetricsEnabled, builder.Me, - nodeBackend, - nodeBackend, + backend, + backend, builder.secureGrpcServer, builder.unsecureGrpcServer, ) diff --git a/cmd/observer/node_builder/observer_builder.go b/cmd/observer/node_builder/observer_builder.go index a33fdae79ab..1e294e70d01 100644 --- a/cmd/observer/node_builder/observer_builder.go +++ b/cmd/observer/node_builder/observer_builder.go @@ -13,6 +13,9 @@ import ( "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/routing" + "github.com/rs/zerolog" + "github.com/spf13/pflag" + "github.com/onflow/flow-go/cmd" "github.com/onflow/flow-go/consensus" "github.com/onflow/flow-go/consensus/hotstuff" @@ -70,8 +73,6 @@ import ( "github.com/onflow/flow-go/state/protocol/events/gadgets" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/io" - "github.com/rs/zerolog" - "github.com/spf13/pflag" ) // ObserverBuilder extends cmd.NodeBuilder and declares additional functions needed to bootstrap an Access node @@ -925,30 +926,29 @@ func (builder *ObserverServiceBuilder) enqueueRPCServer() { backendConfig.CircuitBreakerConfig, ), } - - - - accessBackend := backend.New(backend.Params{ - State:node.State, - Blocks: node.Storage.Blocks, - Headers: node.Storage.Headers, - Collections: node.Storage.Collections, - Transactions: node.Storage.Transactions, - ExecutionReceipts: node.Storage.Receipts, - ExecutionResults: node.Storage.Results, - ChainID: node.RootChainID, - AccessMetrics: accessMetrics, - ConnFactory: connFactory, - RetryEnabled: false, - MaxHeightRange: backendConfig.MaxHeightRange, - PreferredExecutionNodeIDs: backendConfig.PreferredExecutionNodeIDs, - FixedExecutionNodeIDs: backendConfig.FixedExecutionNodeIDs, - Log:node.Logger, - SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, - ArchiveAddressList: backendConfig.ArchiveAddressList, - Communicator: backend.NewNodeCommunicator(backendConfig.CircuitBreakerConfig.Enabled), - ScriptExecValidation: backendConfig.ScriptExecValidation, - }) + + accessBackend := backend.New( + node.State, + nil, + nil, + node.Storage.Blocks, + node.Storage.Headers, + node.Storage.Collections, + node.Storage.Transactions, + node.Storage.Receipts, + node.Storage.Results, + node.RootChainID, + accessMetrics, + connFactory, + false, + backendConfig.MaxHeightRange, + backendConfig.PreferredExecutionNodeIDs, + backendConfig.FixedExecutionNodeIDs, + node.Logger, + backend.DefaultSnapshotHistoryLimit, + backendConfig.ArchiveAddressList, + backendConfig.ScriptExecValidation, + backendConfig.CircuitBreakerConfig.Enabled) observerCollector := metrics.NewObserverCollector() restHandler, err := restapiproxy.NewRestProxyHandler( diff --git a/engine/access/access_test.go b/engine/access/access_test.go index d09835a4395..75a69892389 100644 --- a/engine/access/access_test.go +++ b/engine/access/access_test.go @@ -138,23 +138,28 @@ func (suite *Suite) RunTest( unittest.RunWithBadgerDB(suite.T(), func(db *badger.DB) { all := util.StorageLayer(suite.T(), db) - suite.backend = backend.New( - backend.Params{ - State: suite.state, - CollectionRPC: suite.collClient, - Blocks: all.Blocks, - Headers: all.Headers, - Collections: all.Collections, - Transactions: all.Transactions, - ExecutionResults: all.Results, - ExecutionReceipts: all.Receipts, - ChainID: suite.chainID, - AccessMetrics: suite.metrics, - MaxHeightRange: backend.DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, - Communicator: backend.NewNodeCommunicator(false), - }) + suite.backend = backend.New(suite.state, + suite.collClient, + nil, + all.Blocks, + all.Headers, + all.Collections, + all.Transactions, + all.Receipts, + all.Results, + suite.chainID, + suite.metrics, + nil, + false, + backend.DefaultMaxHeightRange, + nil, + nil, + suite.log, + backend.DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) handler := access.NewHandler(suite.backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me, access.WithBlockSignerDecoder(suite.signerIndicesDecoder)) f(handler, db, all) }) @@ -307,19 +312,30 @@ func (suite *Suite) TestSendTransactionToRandomCollectionNode() { connFactory.On("GetAccessAPIClient", collNode1.Address).Return(col1ApiClient, &mockCloser{}, nil) connFactory.On("GetAccessAPIClient", collNode2.Address).Return(col2ApiClient, &mockCloser{}, nil) - bnd := backend.New(backend.Params{State: suite.state, - Collections: collections, - Transactions: transactions, - ChainID: suite.chainID, - AccessMetrics: metrics, - ConnFactory: connFactory, - MaxHeightRange: backend.DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, - Communicator: backend.NewNodeCommunicator(false), - }) - - handler := access.NewHandler(bnd, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) + backend := backend.New(suite.state, + nil, + nil, + nil, + nil, + collections, + transactions, + nil, + nil, + suite.chainID, + metrics, + connFactory, + false, + backend.DefaultMaxHeightRange, + nil, + nil, + suite.log, + backend.DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) + + handler := access.NewHandler(backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) // Send transaction 1 resp, err := handler.SendTransaction(context.Background(), sendReq1) @@ -624,25 +640,30 @@ func (suite *Suite) TestGetSealedTransaction() { blocksToMarkExecuted, err := stdmap.NewTimes(100) require.NoError(suite.T(), err) - bnd := backend.New(backend.Params{State: suite.state, - CollectionRPC: suite.collClient, - Blocks: all.Blocks, - Headers: all.Headers, - Collections: collections, - Transactions: transactions, - ExecutionReceipts: receipts, - ExecutionResults: results, - ChainID: suite.chainID, - AccessMetrics: suite.metrics, - ConnFactory: connFactory, - MaxHeightRange: backend.DefaultMaxHeightRange, - PreferredExecutionNodeIDs: enNodeIDs.Strings(), - Log: suite.log, - SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, - Communicator: backend.NewNodeCommunicator(false), - }) - - handler := access.NewHandler(bnd, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) + backend := backend.New(suite.state, + suite.collClient, + nil, + all.Blocks, + all.Headers, + collections, + transactions, + receipts, + results, + suite.chainID, + suite.metrics, + connFactory, + false, + backend.DefaultMaxHeightRange, + nil, + enNodeIDs.Strings(), + suite.log, + backend.DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) + + handler := access.NewHandler(backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) // create the ingest engine ingestEng, err := ingestion.New(suite.log, suite.net, suite.state, suite.me, suite.request, all.Blocks, all.Headers, collections, @@ -760,25 +781,30 @@ func (suite *Suite) TestGetTransactionResult() { blocksToMarkExecuted, err := stdmap.NewTimes(100) require.NoError(suite.T(), err) - bnd := backend.New(backend.Params{State: suite.state, - CollectionRPC: suite.collClient, - Blocks: all.Blocks, - Headers: all.Headers, - Collections: collections, - Transactions: transactions, - ExecutionReceipts: receipts, - ExecutionResults: results, - ChainID: suite.chainID, - AccessMetrics: suite.metrics, - ConnFactory: connFactory, - MaxHeightRange: backend.DefaultMaxHeightRange, - PreferredExecutionNodeIDs: enNodeIDs.Strings(), - Log: suite.log, - SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, - Communicator: backend.NewNodeCommunicator(false), - }) - - handler := access.NewHandler(bnd, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) + backend := backend.New(suite.state, + suite.collClient, + nil, + all.Blocks, + all.Headers, + collections, + transactions, + receipts, + results, + suite.chainID, + suite.metrics, + connFactory, + false, + backend.DefaultMaxHeightRange, + nil, + enNodeIDs.Strings(), + suite.log, + backend.DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) + + handler := access.NewHandler(backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) // create the ingest engine ingestEng, err := ingestion.New(suite.log, suite.net, suite.state, suite.me, suite.request, all.Blocks, all.Headers, collections, @@ -948,23 +974,28 @@ func (suite *Suite) TestExecuteScript() { connFactory := new(factorymock.ConnectionFactory) connFactory.On("GetExecutionAPIClient", mock.Anything).Return(suite.execClient, &mockCloser{}, nil) - suite.backend = backend.New(backend.Params{State: suite.state, - CollectionRPC: suite.collClient, - Blocks: all.Blocks, - Headers: all.Headers, - Collections: collections, - Transactions: transactions, - ExecutionReceipts: receipts, - ExecutionResults: results, - ChainID: suite.chainID, - AccessMetrics: suite.metrics, - ConnFactory: connFactory, - MaxHeightRange: backend.DefaultMaxHeightRange, - FixedExecutionNodeIDs: (identities.NodeIDs()).Strings(), - Log: suite.log, - SnapshotHistoryLimit: backend.DefaultSnapshotHistoryLimit, - Communicator: backend.NewNodeCommunicator(false), - }) + suite.backend = backend.New(suite.state, + suite.collClient, + nil, + all.Blocks, + all.Headers, + collections, + transactions, + receipts, + results, + suite.chainID, + suite.metrics, + connFactory, + false, + backend.DefaultMaxHeightRange, + nil, + flow.IdentifierList(identities.NodeIDs()).Strings(), + suite.log, + backend.DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) handler := access.NewHandler(suite.backend, suite.chainID.Chain(), suite.finalizedHeaderCache, suite.me) diff --git a/engine/access/integration_unsecure_grpc_server_test.go b/engine/access/integration_unsecure_grpc_server_test.go index cf9ec1fa744..b5660eece2d 100644 --- a/engine/access/integration_unsecure_grpc_server_test.go +++ b/engine/access/integration_unsecure_grpc_server_test.go @@ -2,17 +2,17 @@ package access import ( "context" + "io" "os" "testing" "time" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - executiondataproto "github.com/onflow/flow/protobuf/go/flow/executiondata" "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" + "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" @@ -37,6 +37,9 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" + + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + executiondataproto "github.com/onflow/flow/protobuf/go/flow/executiondata" ) // SameGRPCPortTestSuite verifies both AccessAPI and ExecutionDataAPI client continue to work when configured @@ -166,20 +169,29 @@ func (suite *SameGRPCPortTestSuite) SetupTest() { block := unittest.BlockHeaderFixture() suite.snapshot.On("Head").Return(block, nil) - bnd := backend.New(backend.Params{ - State: suite.state, - CollectionRPC: suite.collClient, - Blocks: suite.blocks, - Headers: suite.headers, - Collections: suite.collections, - Transactions: suite.transactions, - ChainID: suite.chainID, - AccessMetrics: suite.metrics, - MaxHeightRange: 0, - Log: suite.log, - SnapshotHistoryLimit: 0, - Communicator: backend.NewNodeCommunicator(false), - }) + backend := backend.New( + suite.state, + suite.collClient, + nil, + suite.blocks, + suite.headers, + suite.collections, + suite.transactions, + nil, + nil, + suite.chainID, + suite.metrics, + nil, + false, + 0, + nil, + nil, + suite.log, + 0, + nil, + false, + false, + ) // create rpc engine builder rpcEngBuilder, err := rpc.NewBuilder( @@ -190,8 +202,8 @@ func (suite *SameGRPCPortTestSuite) SetupTest() { suite.metrics, false, suite.me, - bnd, - bnd, + backend, + backend, suite.secureGrpcServer, suite.unsecureGrpcServer, ) diff --git a/engine/access/rest_api_test.go b/engine/access/rest_api_test.go index 1b891832249..0f7a9058dc4 100644 --- a/engine/access/rest_api_test.go +++ b/engine/access/rest_api_test.go @@ -10,6 +10,11 @@ import ( "testing" "time" + "google.golang.org/grpc/credentials" + + "github.com/onflow/flow-go/module/grpcserver" + "github.com/onflow/flow-go/utils/grpcutils" + "github.com/antihax/optional" restclient "github.com/onflow/flow/openapi/go-client-generated" "github.com/rs/zerolog" @@ -17,7 +22,6 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - "google.golang.org/grpc/credentials" accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rest/request" @@ -25,7 +29,6 @@ import ( "github.com/onflow/flow-go/engine/access/rpc" "github.com/onflow/flow-go/engine/access/rpc/backend" "github.com/onflow/flow-go/model/flow" - "github.com/onflow/flow-go/module/grpcserver" "github.com/onflow/flow-go/module/irrecoverable" "github.com/onflow/flow-go/module/metrics" module "github.com/onflow/flow-go/module/mock" @@ -33,7 +36,6 @@ import ( protocol "github.com/onflow/flow-go/state/protocol/mock" "github.com/onflow/flow-go/storage" storagemock "github.com/onflow/flow-go/storage/mock" - "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" ) @@ -149,22 +151,28 @@ func (suite *RestAPITestSuite) SetupTest() { nil, nil).Build() - bnd := backend.New( - backend.Params{ - State: suite.state, - CollectionRPC: suite.collClient, - Blocks: suite.blocks, - Headers: suite.headers, - Collections: suite.collections, - Transactions: suite.transactions, - ExecutionResults: suite.executionResults, - ChainID: suite.chainID, - AccessMetrics: suite.metrics, - MaxHeightRange: 0, - Log: suite.log, - SnapshotHistoryLimit: 0, - Communicator: backend.NewNodeCommunicator(false), - }) + backend := backend.New(suite.state, + suite.collClient, + nil, + suite.blocks, + suite.headers, + suite.collections, + suite.transactions, + nil, + suite.executionResults, + suite.chainID, + suite.metrics, + nil, + false, + 0, + nil, + nil, + suite.log, + 0, + nil, + false, + false, + ) rpcEngBuilder, err := rpc.NewBuilder( suite.log, @@ -174,8 +182,8 @@ func (suite *RestAPITestSuite) SetupTest() { suite.metrics, false, suite.me, - bnd, - bnd, + backend, + backend, suite.secureGrpcServer, suite.unsecureGrpcServer, ) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 8fb44017802..30559fef6e3 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -1,14 +1,19 @@ package backend import ( - "crypto/md5" // #nosec "context" + "crypto/md5" "fmt" "net" "strconv" "time" lru2 "github.com/hashicorp/golang-lru/v2" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/cmd/build" "github.com/onflow/flow-go/engine/access/rpc/connection" @@ -19,10 +24,6 @@ import ( "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) // minExecutionNodesCnt is the minimum number of execution nodes expected to have sent the execution receipt for a block @@ -90,142 +91,132 @@ type Config struct { CircuitBreakerConfig connection.CircuitBreakerConfig // the configuration for circuit breaker } -type Params struct { - State protocol.State - CollectionRPC accessproto.AccessAPIClient - HistoricalAccessNodes []accessproto.AccessAPIClient - Blocks storage.Blocks - Headers storage.Headers - Collections storage.Collections - Transactions storage.Transactions - ExecutionReceipts storage.ExecutionReceipts - ExecutionResults storage.ExecutionResults - ChainID flow.ChainID - AccessMetrics module.AccessMetrics - ConnFactory connection.ConnectionFactory - RetryEnabled bool - MaxHeightRange uint - PreferredExecutionNodeIDs []string - FixedExecutionNodeIDs []string - Log zerolog.Logger - SnapshotHistoryLimit int - ArchiveAddressList []string - Communicator Communicator - ScriptExecValidation bool - TxResultCacheSize uint -} - -// New creates backend instance -func New(params Params) *Backend { +func New( + state protocol.State, + collectionRPC accessproto.AccessAPIClient, + historicalAccessNodes []accessproto.AccessAPIClient, + blocks storage.Blocks, + headers storage.Headers, + collections storage.Collections, + transactions storage.Transactions, + executionReceipts storage.ExecutionReceipts, + executionResults storage.ExecutionResults, + chainID flow.ChainID, + accessMetrics module.AccessMetrics, + connFactory connection.ConnectionFactory, + retryEnabled bool, + maxHeightRange uint, + preferredExecutionNodeIDs []string, + fixedExecutionNodeIDs []string, + log zerolog.Logger, + snapshotHistoryLimit int, + archiveAddressList []string, + scriptExecValidation bool, + circuitBreakerEnabled bool, +) *Backend { retry := newRetry() - if params.RetryEnabled { + if retryEnabled { retry.Activate() } loggedScripts, err := lru2.New[[md5.Size]byte, time.Time](DefaultLoggedScriptsCacheSize) if err != nil { - params.Log.Fatal().Err(err).Msg("failed to initialize script logging cache") + log.Fatal().Err(err).Msg("failed to initialize script logging cache") } - archivePorts := make([]uint, len(params.ArchiveAddressList)) - for idx, addr := range params.ArchiveAddressList { + archivePorts := make([]uint, len(archiveAddressList)) + for idx, addr := range archiveAddressList { port, err := findPortFromAddress(addr) if err != nil { - params.Log.Fatal().Err(err).Msg("failed to find archive node port") + log.Fatal().Err(err).Msg("failed to find archive node port") } archivePorts[idx] = port } - var txResCache *lru2.Cache[flow.Identifier, *access.TransactionResult] - if params.TxResultCacheSize > 0 { - txResCache, err = lru2.New[flow.Identifier, *access.TransactionResult](int(params.TxResultCacheSize)) - if err != nil { - params.Log.Fatal().Err(err).Msg("failed to init cache for transaction results") - } - } + // create node communicator, that will be used in sub-backend logic for interacting with API calls + nodeCommunicator := NewNodeCommunicator(circuitBreakerEnabled) b := &Backend{ - state: params.State, + state: state, // create the sub-backends backendScripts: backendScripts{ - headers: params.Headers, - executionReceipts: params.ExecutionReceipts, - connFactory: params.ConnFactory, - state: params.State, - log: params.Log, - metrics: params.AccessMetrics, + headers: headers, + executionReceipts: executionReceipts, + connFactory: connFactory, + state: state, + log: log, + metrics: accessMetrics, loggedScripts: loggedScripts, - archiveAddressList: params.ArchiveAddressList, + archiveAddressList: archiveAddressList, archivePorts: archivePorts, - nodeCommunicator: params.Communicator, - scriptExecValidation: params.ScriptExecValidation, + scriptExecValidation: scriptExecValidation, + nodeCommunicator: nodeCommunicator, }, backendTransactions: backendTransactions{ - staticCollectionRPC: params.CollectionRPC, - state: params.State, - chainID: params.ChainID, - collections: params.Collections, - blocks: params.Blocks, - transactions: params.Transactions, - executionReceipts: params.ExecutionReceipts, - transactionValidator: configureTransactionValidator(params.State, params.ChainID), - transactionMetrics: params.AccessMetrics, + staticCollectionRPC: collectionRPC, + state: state, + chainID: chainID, + collections: collections, + blocks: blocks, + transactions: transactions, + executionReceipts: executionReceipts, + transactionValidator: configureTransactionValidator(state, chainID), + transactionMetrics: accessMetrics, retry: retry, - connFactory: params.ConnFactory, - previousAccessNodes: params.HistoricalAccessNodes, - log: params.Log, - nodeCommunicator: params.Communicator, - txResultCache: txResCache, + connFactory: connFactory, + previousAccessNodes: historicalAccessNodes, + log: log, + nodeCommunicator: nodeCommunicator, }, backendEvents: backendEvents{ - state: params.State, - headers: params.Headers, - executionReceipts: params.ExecutionReceipts, - connFactory: params.ConnFactory, - log: params.Log, - maxHeightRange: params.MaxHeightRange, - nodeCommunicator: params.Communicator, + state: state, + headers: headers, + executionReceipts: executionReceipts, + connFactory: connFactory, + log: log, + maxHeightRange: maxHeightRange, + nodeCommunicator: nodeCommunicator, }, backendBlockHeaders: backendBlockHeaders{ - headers: params.Headers, - state: params.State, + headers: headers, + state: state, }, backendBlockDetails: backendBlockDetails{ - blocks: params.Blocks, - state: params.State, + blocks: blocks, + state: state, }, backendAccounts: backendAccounts{ - state: params.State, - headers: params.Headers, - executionReceipts: params.ExecutionReceipts, - connFactory: params.ConnFactory, - log: params.Log, - nodeCommunicator: params.Communicator, + state: state, + headers: headers, + executionReceipts: executionReceipts, + connFactory: connFactory, + log: log, + nodeCommunicator: nodeCommunicator, }, backendExecutionResults: backendExecutionResults{ - executionResults: params.ExecutionResults, + executionResults: executionResults, }, backendNetwork: backendNetwork{ - state: params.State, - chainID: params.ChainID, - snapshotHistoryLimit: params.SnapshotHistoryLimit, + state: state, + chainID: chainID, + snapshotHistoryLimit: snapshotHistoryLimit, }, - collections: params.Collections, - executionReceipts: params.ExecutionReceipts, - connFactory: params.ConnFactory, - chainID: params.ChainID, + collections: collections, + executionReceipts: executionReceipts, + connFactory: connFactory, + chainID: chainID, } retry.SetBackend(b) - preferredENIdentifiers, err = identifierList(params.PreferredExecutionNodeIDs) + preferredENIdentifiers, err = identifierList(preferredExecutionNodeIDs) if err != nil { - params.Log.Fatal().Err(err).Msg("failed to convert node id string to Flow Identifier for preferred EN map") + log.Fatal().Err(err).Msg("failed to convert node id string to Flow Identifier for preferred EN map") } - fixedENIdentifiers, err = identifierList(params.FixedExecutionNodeIDs) + fixedENIdentifiers, err = identifierList(fixedExecutionNodeIDs) if err != nil { - params.Log.Fatal().Err(err).Msg("failed to convert node id string to Flow Identifier for fixed EN map") + log.Fatal().Err(err).Msg("failed to convert node id string to Flow Identifier for fixed EN map") } return b @@ -237,13 +228,13 @@ func NewCache( log zerolog.Logger, accessMetrics module.AccessMetrics, connectionPoolSize uint, -) (*lru2.Cache[string, *connection.CachedClient], uint, error) { +) (*lru2.Cache[flow.Identifier, *connection.CachedClient], uint, error) { - var cache *lru2.Cache[string, *connection.CachedClient] + var cache *lru2.Cache[flow.Identifier, *connection.CachedClient] cacheSize := connectionPoolSize if cacheSize > 0 { var err error - cache, err = lru2.NewWithEvict[string, *connection.CachedClient](int(cacheSize), func(_ string, store *connection.CachedClient) { + cache, err = lru2.NewWithEvict[flow.Identifier, *connection.CachedClient](int(cacheSize), func(_ flow.Identifier, store *connection.CachedClient) { store.Close() log.Debug().Str("grpc_conn_evicted", store.Address).Msg("closing grpc connection evicted from pool") if accessMetrics != nil { diff --git a/engine/access/rpc/backend/backend_accounts.go b/engine/access/rpc/backend/backend_accounts.go index 470b91048ab..35f8f0bf4df 100644 --- a/engine/access/rpc/backend/backend_accounts.go +++ b/engine/access/rpc/backend/backend_accounts.go @@ -24,7 +24,7 @@ type backendAccounts struct { executionReceipts storage.ExecutionReceipts connFactory connection.ConnectionFactory log zerolog.Logger - nodeCommunicator Communicator + nodeCommunicator *NodeCommunicator } func (b *backendAccounts) GetAccount(ctx context.Context, address flow.Address) (*flow.Account, error) { diff --git a/engine/access/rpc/backend/backend_events.go b/engine/access/rpc/backend/backend_events.go index 43b42cde2f5..d0b52820ee4 100644 --- a/engine/access/rpc/backend/backend_events.go +++ b/engine/access/rpc/backend/backend_events.go @@ -27,7 +27,7 @@ type backendEvents struct { connFactory connection.ConnectionFactory log zerolog.Logger maxHeightRange uint - nodeCommunicator Communicator + nodeCommunicator *NodeCommunicator } // GetEventsForHeightRange retrieves events for all sealed blocks between the start block height and diff --git a/engine/access/rpc/backend/backend_scripts.go b/engine/access/rpc/backend/backend_scripts.go index 6ca975718d6..c09b1cbf4e7 100644 --- a/engine/access/rpc/backend/backend_scripts.go +++ b/engine/access/rpc/backend/backend_scripts.go @@ -1,26 +1,25 @@ package backend import ( + "crypto/md5" //nolint:gosec "bytes" "context" - "crypto/md5" //nolint:gosec "io" "time" "github.com/hashicorp/go-multierror" lru "github.com/hashicorp/golang-lru/v2" - "github.com/onflow/flow/protobuf/go/flow/access" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" + "github.com/onflow/flow/protobuf/go/flow/access" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) // uniqueScriptLoggingTimeWindow is the duration for checking the uniqueness of scripts sent for execution @@ -38,7 +37,7 @@ type backendScripts struct { archiveAddressList []string archivePorts []uint scriptExecValidation bool - nodeCommunicator Communicator + nodeCommunicator *NodeCommunicator } func (b *backendScripts) ExecuteScriptAtLatestBlock( diff --git a/engine/access/rpc/backend/backend_test.go b/engine/access/rpc/backend/backend_test.go index 1a4989dac79..9c87d88a4e4 100644 --- a/engine/access/rpc/backend/backend_test.go +++ b/engine/access/rpc/backend/backend_test.go @@ -6,6 +6,8 @@ import ( "strconv" "testing" + "github.com/onflow/flow-go/engine/access/rpc/connection" + "github.com/dgraph-io/badger/v2" accessproto "github.com/onflow/flow/protobuf/go/flow/access" entitiesproto "github.com/onflow/flow/protobuf/go/flow/entities" @@ -20,7 +22,6 @@ import ( access "github.com/onflow/flow-go/engine/access/mock" backendmock "github.com/onflow/flow-go/engine/access/rpc/backend/mock" - "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc/convert" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" @@ -32,8 +33,6 @@ import ( "github.com/onflow/flow-go/utils/unittest" ) -const TEST_MAX_HEIGHT = 100 - type Suite struct { suite.Suite @@ -41,22 +40,18 @@ type Suite struct { snapshot *protocol.Snapshot log zerolog.Logger - blocks *storagemock.Blocks - headers *storagemock.Headers - collections *storagemock.Collections - transactions *storagemock.Transactions - receipts *storagemock.ExecutionReceipts - results *storagemock.ExecutionResults - + blocks *storagemock.Blocks + headers *storagemock.Headers + collections *storagemock.Collections + transactions *storagemock.Transactions + receipts *storagemock.ExecutionReceipts + results *storagemock.ExecutionResults colClient *access.AccessAPIClient execClient *access.ExecutionAPIClient historicalAccessClient *access.AccessAPIClient archiveClient *access.AccessAPIClient - - connectionFactory *backendmock.ConnectionFactory - communicator *backendmock.Communicator - - chainID flow.ChainID + connectionFactory *backendmock.ConnectionFactory + chainID flow.ChainID } func TestHandler(t *testing.T) { @@ -84,8 +79,6 @@ func (suite *Suite) SetupTest() { suite.chainID = flow.Testnet suite.historicalAccessClient = new(access.AccessAPIClient) suite.connectionFactory = new(backendmock.ConnectionFactory) - - suite.communicator = new(backendmock.Communicator) } func (suite *Suite) TestPing() { @@ -97,16 +90,29 @@ func (suite *Suite) TestPing() { On("Ping", mock.Anything, &execproto.PingRequest{}). Return(&execproto.PingResponse{}, nil) - backend := New(Params{ - State: suite.state, - CollectionRPC: suite.colClient, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + suite.colClient, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) err := backend.Ping(context.Background()) @@ -122,32 +128,45 @@ func (suite *Suite) TestGetLatestFinalizedBlockHeader() { suite.snapshot.On("Head").Return(block, nil).Once() backend := New( - Params{ - State: suite.state, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + suite.state, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // query the handler for the latest finalized block - header, stat, err := backend.GetLatestBlockHeader(context.Background(), false) + header, status, err := backend.GetLatestBlockHeader(context.Background(), false) suite.checkResponse(header, err) // make sure we got the latest block suite.Require().Equal(block.ID(), header.ID()) suite.Require().Equal(block.Height, header.Height) suite.Require().Equal(block.ParentID, header.ParentID) - suite.Require().Equal(stat, flow.BlockStatusSealed) + suite.Require().Equal(status, flow.BlockStatusSealed) suite.assertAllExpectations() } // TestGetLatestProtocolStateSnapshot_NoTransitionSpan tests our GetLatestProtocolStateSnapshot RPC endpoint -// where the sealing segment for the State requested at latest finalized block does not contain any Blocks that +// where the sealing segment for the state requested at latest finalized block does not contain any blocks that // spans an epoch or epoch phase transition. func (suite *Suite) TestGetLatestProtocolStateSnapshot_NoTransitionSpan() { identities := unittest.CompleteIdentitySet() @@ -155,7 +174,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_NoTransitionSpan() { util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { epochBuilder := unittest.NewEpochBuilder(suite.T(), state) // build epoch 1 - // Blocks in current State + // blocks in current state // P <- A(S_P-1) <- B(S_P) <- C(S_A) <- D(S_B) |setup| <- E(S_C) <- F(S_D) |commit| epochBuilder. BuildEpoch(). @@ -165,7 +184,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_NoTransitionSpan() { epoch1, ok := epochBuilder.EpochHeights(1) require.True(suite.T(), ok) - // setup AtBlockID mock returns for State + // setup AtBlockID mock returns for state for _, height := range epoch1.Range() { suite.state.On("AtHeight", height).Return(state.AtHeight(height)).Once() } @@ -175,22 +194,36 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_NoTransitionSpan() { snap := state.AtHeight(epoch1.Range()[2]) suite.state.On("Final").Return(snap).Once() - backend := New(Params{ - State: suite.state, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: TEST_MAX_HEIGHT, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + 100, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // query the handler for the latest finalized snapshot bytes, err := backend.GetLatestProtocolStateSnapshot(context.Background()) suite.Require().NoError(err) // we expect the endpoint to return the snapshot at the same height we requested - // because it has a valid sealing segment with no Blocks spanning an epoch or phase transition + // because it has a valid sealing segment with no blocks spanning an epoch or phase transition expectedSnapshotBytes, err := convert.SnapshotToBytes(snap) suite.Require().NoError(err) suite.Require().Equal(expectedSnapshotBytes, bytes) @@ -198,8 +231,8 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_NoTransitionSpan() { } // TestGetLatestProtocolStateSnapshot_TransitionSpans tests our GetLatestProtocolStateSnapshot RPC endpoint -// where the sealing segment for the State requested for latest finalized block contains a block that -// spans an epoch transition and Blocks that span epoch phase transitions. +// where the sealing segment for the state requested for latest finalized block contains a block that +// spans an epoch transition and blocks that span epoch phase transitions. func (suite *Suite) TestGetLatestProtocolStateSnapshot_TransitionSpans() { identities := unittest.CompleteIdentitySet() rootSnapshot := unittest.RootSnapshotFixture(identities) @@ -222,7 +255,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_TransitionSpans() { epoch2, ok := epochBuilder.EpochHeights(2) require.True(suite.T(), ok) - // setup AtHeight mock returns for State + // setup AtHeight mock returns for state for _, height := range append(epoch1.Range(), epoch2.Range()...) { suite.state.On("AtHeight", height).Return(state.AtHeight(height)) } @@ -236,15 +269,28 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_TransitionSpans() { suite.state.On("Final").Return(snap).Once() backend := New( - Params{ - State: suite.state, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: TEST_MAX_HEIGHT, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + suite.state, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + 100, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // query the handler for the latest finalized snapshot bytes, err := backend.GetLatestProtocolStateSnapshot(context.Background()) @@ -259,7 +305,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_TransitionSpans() { } // TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan tests our GetLatestProtocolStateSnapshot RPC endpoint -// where the sealing segment for the State requested at latest finalized block contains a Blocks that +// where the sealing segment for the state requested at latest finalized block contains a blocks that // spans an epoch phase transition. func (suite *Suite) TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan() { identities := unittest.CompleteIdentitySet() @@ -267,7 +313,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan() { util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { epochBuilder := unittest.NewEpochBuilder(suite.T(), state) // build epoch 1 - // Blocks in current State + // blocks in current state // P <- A(S_P-1) <- B(S_P) <- C(S_A) <- D(S_B) |setup| <- E(S_C) <- F(S_D) |commit| epochBuilder. BuildEpoch(). @@ -277,7 +323,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan() { epoch1, ok := epochBuilder.EpochHeights(1) require.True(suite.T(), ok) - // setup AtBlockID mock returns for State + // setup AtBlockID mock returns for state for _, height := range epoch1.Range() { suite.state.On("AtHeight", height).Return(state.AtHeight(height)) } @@ -289,15 +335,29 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan() { snap := state.AtHeight(epoch1.Range()[3]) suite.state.On("Final").Return(snap).Once() - backend := New(Params{ - State: suite.state, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: TEST_MAX_HEIGHT, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + 100, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // query the handler for the latest finalized snapshot bytes, err := backend.GetLatestProtocolStateSnapshot(context.Background()) @@ -311,7 +371,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_PhaseTransitionSpan() { } // TestGetLatestProtocolStateSnapshot_EpochTransitionSpan tests our GetLatestProtocolStateSnapshot RPC endpoint -// where the sealing segment for the State requested at latest finalized block contains a Blocks that +// where the sealing segment for the state requested at latest finalized block contains a blocks that // spans an epoch transition. func (suite *Suite) TestGetLatestProtocolStateSnapshot_EpochTransitionSpan() { identities := unittest.CompleteIdentitySet() @@ -319,11 +379,11 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_EpochTransitionSpan() { util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { epochBuilder := unittest.NewEpochBuilder(suite.T(), state) // build epoch 1 - // Blocks in current State + // blocks in current state // P <- A(S_P-1) <- B(S_P) <- C(S_A) <- D(S_B) |setup| <- E(S_C) <- F(S_D) |commit| epochBuilder.BuildEpoch() - // add more Blocks to our State in the commit phase, this will allow + // add more blocks to our state in the commit phase, this will allow // us to take a snapshot at the height where the epoch1 -> epoch2 transition // and no block spans an epoch phase transition. The third block added will // have a seal for the first block in the commit phase allowing us to avoid @@ -342,7 +402,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_EpochTransitionSpan() { epoch2, ok := epochBuilder.EpochHeights(2) require.True(suite.T(), ok) - // setup AtHeight mock returns for State + // setup AtHeight mock returns for state for _, height := range append(epoch1.Range(), epoch2.Range()...) { suite.state.On("AtHeight", height).Return(state.AtHeight(height)) } @@ -353,15 +413,29 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_EpochTransitionSpan() { snap := state.AtHeight(epoch2.Range()[0]) suite.state.On("Final").Return(snap).Once() - backend := New(Params{ - State: suite.state, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: TEST_MAX_HEIGHT, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + 100, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // query the handler for the latest finalized snapshot bytes, err := backend.GetLatestProtocolStateSnapshot(context.Background()) @@ -376,7 +450,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_EpochTransitionSpan() { } // TestGetLatestProtocolStateSnapshot_EpochTransitionSpan tests our GetLatestProtocolStateSnapshot RPC endpoint -// where the length of the sealing segment is greater than the configured SnapshotHistoryLimit +// where the length of the sealing segment is greater than the configured snapshotHistoryLimit func (suite *Suite) TestGetLatestProtocolStateSnapshot_HistoryLimit() { identities := unittest.CompleteIdentitySet() rootSnapshot := unittest.RootSnapshotFixture(identities) @@ -387,7 +461,7 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_HistoryLimit() { epoch1, ok := epochBuilder.EpochHeights(1) require.True(suite.T(), ok) - // setup AtBlockID mock returns for State + // setup AtBlockID mock returns for state for _, height := range epoch1.Range() { suite.state.On("AtHeight", height).Return(state.AtHeight(height)) } @@ -399,17 +473,31 @@ func (suite *Suite) TestGetLatestProtocolStateSnapshot_HistoryLimit() { snap := state.AtHeight(epoch1.Range()[4]) suite.state.On("Final").Return(snap).Once() - // very short history limit, any segment with any Blocks spanning any transition should force the endpoint to return a history limit error + // very short history limit, any segment with any blocks spanning any transition should force the endpoint to return a history limit error snapshotHistoryLimit := 1 - backend := New(Params{ - State: suite.state, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: snapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + snapshotHistoryLimit, + nil, + false, + false, + ) // the handler should return a snapshot history limit error _, err := backend.GetLatestProtocolStateSnapshot(context.Background()) @@ -427,25 +515,39 @@ func (suite *Suite) TestGetLatestSealedBlockHeader() { suite.state.On("Sealed").Return(suite.snapshot, nil) suite.snapshot.On("Head").Return(block, nil).Once() - backend := New(Params{ - State: suite.state, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // query the handler for the latest sealed block - header, stat, err := backend.GetLatestBlockHeader(context.Background(), true) + header, status, err := backend.GetLatestBlockHeader(context.Background(), true) suite.checkResponse(header, err) // make sure we got the latest sealed block suite.Require().Equal(block.ID(), header.ID()) suite.Require().Equal(block.Height, header.Height) suite.Require().Equal(block.ParentID, header.ParentID) - suite.Require().Equal(stat, flow.BlockStatusSealed) + suite.Require().Equal(status, flow.BlockStatusSealed) suite.assertAllExpectations() } @@ -461,16 +563,29 @@ func (suite *Suite) TestGetTransaction() { Return(&expected, nil). Once() - backend := New(Params{ - State: suite.state, - Transactions: suite.transactions, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + nil, + nil, + nil, + suite.transactions, + nil, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) actual, err := backend.GetTransaction(context.Background(), transaction.ID()) suite.checkResponse(actual, err) @@ -490,17 +605,29 @@ func (suite *Suite) TestGetCollection() { Return(&expected, nil). Once() - backend := New(Params{ - State: suite.state, - Collections: suite.collections, - Transactions: suite.transactions, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + nil, + nil, + suite.collections, + suite.transactions, + nil, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) actual, err := backend.GetCollectionByID(context.Background(), expected.ID()) suite.transactions.AssertExpectations(suite.T()) @@ -543,25 +670,29 @@ func (suite *Suite) TestGetTransactionResultByIndex() { Events: nil, } - backend := New(Params{ - State: suite.state, - Blocks: suite.blocks, - Headers: suite.headers, - Collections: suite.collections, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - // the connection factory should be used to get the execution node client - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - FixedExecutionNodeIDs: (fixedENIDs.NodeIDs()).Strings(), - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) - + backend := New( + suite.state, + nil, + nil, + suite.blocks, + suite.headers, + suite.collections, + suite.transactions, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + flow.IdentifierList(fixedENIDs.NodeIDs()).Strings(), + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) suite.execClient. On("GetTransactionResultByIndex", ctx, exeEventReq). Return(exeEventResp, nil). @@ -604,25 +735,29 @@ func (suite *Suite) TestGetTransactionResultsByBlockID() { TransactionResults: []*execproto.GetTransactionResultResponse{{}}, } - backend := New(Params{ - State: suite.state, - Blocks: suite.blocks, - Headers: suite.headers, - Collections: suite.collections, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - // the connection factory should be used to get the execution node client - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - FixedExecutionNodeIDs: (fixedENIDs.NodeIDs()).Strings(), - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) - + backend := New( + suite.state, + nil, + nil, + suite.blocks, + suite.headers, + suite.collections, + suite.transactions, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + flow.IdentifierList(fixedENIDs.NodeIDs()).Strings(), + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) suite.execClient. On("GetTransactionResultsByBlockID", ctx, exeEventReq). Return(exeEventResp, nil). @@ -635,7 +770,7 @@ func (suite *Suite) TestGetTransactionResultsByBlockID() { } // TestTransactionStatusTransition tests that the status of transaction changes from Finalized to Sealed -// when the protocol State is updated +// when the protocol state is updated func (suite *Suite) TestTransactionStatusTransition() { suite.state.On("Sealed").Return(suite.snapshot, nil).Maybe() @@ -693,24 +828,29 @@ func (suite *Suite) TestTransactionStatusTransition() { Events: nil, } - backend := New(Params{ - State: suite.state, - Blocks: suite.blocks, - Headers: suite.headers, - Collections: suite.collections, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - // the connection factory should be used to get the execution node client - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - FixedExecutionNodeIDs: (fixedENIDs.NodeIDs()).Strings(), - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + suite.blocks, + suite.headers, + suite.collections, + suite.transactions, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + flow.IdentifierList(fixedENIDs.NodeIDs()).Strings(), + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // Successfully return empty event list suite.execClient. @@ -722,7 +862,7 @@ func (suite *Suite) TestTransactionStatusTransition() { result, err := backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) suite.checkResponse(result, err) - // status should be finalized since the sealed Blocks is smaller in height + // status should be finalized since the sealed blocks is smaller in height suite.Assert().Equal(flow.TransactionStatusFinalized, result.Status) // block ID should be included in the response @@ -747,7 +887,7 @@ func (suite *Suite) TestTransactionStatusTransition() { result, err = backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) suite.checkResponse(result, err) - // status should be sealed since the sealed Blocks is greater in height + // status should be sealed since the sealed blocks is greater in height suite.Assert().Equal(flow.TransactionStatusSealed, result.Status) // now go far into the future @@ -765,7 +905,7 @@ func (suite *Suite) TestTransactionStatusTransition() { } // TestTransactionExpiredStatusTransition tests that the status -// of transaction changes from Pending to Expired when enough Blocks pass +// of transaction changes from Pending to Expired when enough blocks pass func (suite *Suite) TestTransactionExpiredStatusTransition() { suite.state.On("Sealed").Return(suite.snapshot, nil).Maybe() suite.state.On("Final").Return(suite.snapshot, nil).Maybe() @@ -810,21 +950,29 @@ func (suite *Suite) TestTransactionExpiredStatusTransition() { txID := transactionBody.ID() - backend := New(Params{ - State: suite.state, - Blocks: suite.blocks, - Headers: suite.headers, - Collections: suite.collections, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + suite.blocks, + suite.headers, + suite.collections, + suite.transactions, + nil, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // should return pending status when we have not observed an expiry block suite.Run("pending", func() { @@ -836,23 +984,23 @@ func (suite *Suite) TestTransactionExpiredStatusTransition() { }) // should return pending status when we have observed an expiry block but - // have not observed all intermediary Collections + // have not observed all intermediary collections suite.Run("expiry un-confirmed", func() { suite.Run("ONLY finalized expiry block", func() { // we have finalized an expiry block headBlock.Header.Height = block.Header.Height + flow.DefaultTransactionExpiry + 1 - // we have NOT observed all intermediary Collections + // we have NOT observed all intermediary collections fullHeight = block.Header.Height + flow.DefaultTransactionExpiry/2 result, err := backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) suite.checkResponse(result, err) suite.Assert().Equal(flow.TransactionStatusPending, result.Status) }) - suite.Run("ONLY observed intermediary Collections", func() { + suite.Run("ONLY observed intermediary collections", func() { // we have NOT finalized an expiry block headBlock.Header.Height = block.Header.Height + flow.DefaultTransactionExpiry/2 - // we have observed all intermediary Collections + // we have observed all intermediary collections fullHeight = block.Header.Height + flow.DefaultTransactionExpiry + 1 result, err := backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) @@ -863,11 +1011,11 @@ func (suite *Suite) TestTransactionExpiredStatusTransition() { }) // should return expired status only when we have observed an expiry block - // and have observed all intermediary Collections + // and have observed all intermediary collections suite.Run("expired", func() { // we have finalized an expiry block headBlock.Header.Height = block.Header.Height + flow.DefaultTransactionExpiry + 1 - // we have observed all intermediary Collections + // we have observed all intermediary collections fullHeight = block.Header.Height + flow.DefaultTransactionExpiry + 1 result, err := backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) @@ -925,7 +1073,7 @@ func (suite *Suite) TestTransactionPendingToFinalizedStatusTransition() { On("ByID", txID). Return(transactionBody, nil) - currentState := flow.TransactionStatusPending // marker for the current State + currentState := flow.TransactionStatusPending // marker for the current state // collection storage returns a not found error if tx is pending, else it returns the collection light reference suite.collections. On("LightByTransactionID", txID). @@ -970,22 +1118,30 @@ func (suite *Suite) TestTransactionPendingToFinalizedStatusTransition() { // create a mock connection factory connFactory := suite.setupConnectionFactory() - backend := New(Params{ - State: suite.state, - Blocks: suite.blocks, - Headers: suite.headers, - Collections: suite.collections, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - MaxHeightRange: TEST_MAX_HEIGHT, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + + backend := New( + suite.state, + nil, + nil, + suite.blocks, + suite.headers, + suite.collections, + suite.transactions, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + 100, + nil, + flow.IdentifierList(enIDs.NodeIDs()).Strings(), + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) preferredENIdentifiers = flow.IdentifierList{receipts[0].ExecutorID} @@ -1023,16 +1179,29 @@ func (suite *Suite) TestTransactionResultUnknown() { On("ByID", txID). Return(nil, storage.ErrNotFound) - backend := New(Params{ - State: suite.state, - Transactions: suite.transactions, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + nil, + nil, + nil, + suite.transactions, + nil, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // first call - when block under test is greater height than the sealed head, but execution node does not know about Tx result, err := backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) @@ -1066,24 +1235,37 @@ func (suite *Suite) TestGetLatestFinalizedBlock() { On("ByHeight", header.Height). Return(&expected, nil) - backend := New(Params{ - State: suite.state, - Blocks: suite.blocks, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + suite.blocks, + nil, + nil, + nil, + nil, + nil, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // query the handler for the latest finalized header - actual, stat, err := backend.GetLatestBlock(context.Background(), false) + actual, status, err := backend.GetLatestBlock(context.Background(), false) suite.checkResponse(actual, err) // make sure we got the latest header suite.Require().Equal(expected, *actual) - suite.Assert().Equal(stat, flow.BlockStatusFinalized) + suite.Assert().Equal(status, flow.BlockStatusFinalized) suite.assertAllExpectations() } @@ -1185,22 +1367,29 @@ func (suite *Suite) TestGetEventsForBlockIDs() { suite.Run("with an execution node chosen using block ID form the list of Fixed ENs", func() { // create the handler - backend := New(Params{ - State: suite.state, - Headers: suite.headers, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - // set the fixed EN Identifiers to the generated execution IDs - FixedExecutionNodeIDs: validENIDs.Strings(), - - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + nil, + suite.headers, + nil, + nil, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + validENIDs.Strings(), // set the fixed EN Identifiers to the generated execution IDs + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // execute request actual, err := backend.GetEventsForBlockIDs(ctx, string(flow.EventAccountCreated), blockIDs) @@ -1212,19 +1401,29 @@ func (suite *Suite) TestGetEventsForBlockIDs() { suite.Run("with an empty block ID list", func() { // create the handler - backend := New(Params{ - State: suite.state, - Headers: suite.headers, - ExecutionReceipts: receipts, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - FixedExecutionNodeIDs: validENIDs.Strings(), - Log: suite.log, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + nil, + suite.headers, + nil, + nil, + receipts, + nil, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + validENIDs.Strings(), // set the fixed EN Identifiers to the generated execution IDs + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // execute request with an empty block id list and expect an empty list of events and no error resp, err := backend.GetEventsForBlockIDs(ctx, string(flow.EventAccountCreated), []flow.Identifier{}) @@ -1261,20 +1460,31 @@ func (suite *Suite) TestGetExecutionResultByID() { Return(executionResult, nil) suite.Run("nonexisting execution result for id", func() { - backend := New(Params{ - State: suite.state, - Headers: suite.headers, - ExecutionReceipts: suite.receipts, - ExecutionResults: results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - FixedExecutionNodeIDs: validENIDs.Strings(), - Log: suite.log, - Communicator: NewNodeCommunicator(false), - }) + + // create the handler + backend := New( + suite.state, + nil, + nil, + nil, + suite.headers, + nil, + nil, + suite.receipts, + results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + validENIDs.Strings(), // set the fixed EN Identifiers to the generated execution IDs + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // execute request _, err := backend.GetExecutionResultByID(ctx, nonexistingID) @@ -1283,19 +1493,30 @@ func (suite *Suite) TestGetExecutionResultByID() { }) suite.Run("existing execution result id", func() { - backend := New(Params{ - State: suite.state, - Headers: suite.headers, - ExecutionResults: results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - FixedExecutionNodeIDs: validENIDs.Strings(), - Log: suite.log, - Communicator: NewNodeCommunicator(false), - }) + // create the handler + backend := New( + suite.state, + nil, + nil, + nil, + suite.headers, + nil, + nil, + nil, + results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + validENIDs.Strings(), // set the fixed EN Identifiers to the generated execution IDs + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // execute request er, err := backend.GetExecutionResultByID(ctx, executionResult.ID()) @@ -1337,20 +1558,30 @@ func (suite *Suite) TestGetExecutionResultByBlockID() { suite.Run("nonexisting execution results", func() { - backend := New(Params{ - State: suite.state, - Headers: suite.headers, - ExecutionReceipts: suite.receipts, - ExecutionResults: results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - FixedExecutionNodeIDs: validENIDs.Strings(), - Log: suite.log, - Communicator: NewNodeCommunicator(false), - }) + // create the handler + backend := New( + suite.state, + nil, + nil, + nil, + suite.headers, + nil, + nil, + suite.receipts, + results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + validENIDs.Strings(), // set the fixed EN Identifiers to the generated execution IDs + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // execute request _, err := backend.GetExecutionResultForBlockID(ctx, nonexistingBlockID) @@ -1360,19 +1591,30 @@ func (suite *Suite) TestGetExecutionResultByBlockID() { suite.Run("existing execution results", func() { - backend := New(Params{ - State: suite.state, - Headers: suite.headers, - ExecutionResults: results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - FixedExecutionNodeIDs: validENIDs.Strings(), - Log: suite.log, - Communicator: NewNodeCommunicator(false), - }) + // create the handler + backend := New( + suite.state, + nil, + nil, + nil, + suite.headers, + nil, + nil, + nil, + results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + validENIDs.Strings(), // set the fixed EN Identifiers to the generated execution IDs + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // execute request er, err := backend.GetExecutionResultForBlockID(ctx, blockID) @@ -1419,7 +1661,7 @@ func (suite *Suite) TestGetEventsForHeightRange() { func(flow.IdentityFilter) error { return nil }, ) - // mock Headers to pull from Headers backend + // mock headers to pull from headers backend suite.headers.On("ByHeight", mock.Anything).Return( func(height uint64) *flow.Header { return headersDB[height] @@ -1501,21 +1743,30 @@ func (suite *Suite) TestGetEventsForHeightRange() { connFactory := suite.setupConnectionFactory() - //suite.state = state suite.Run("invalid request max height < min height", func() { - backend := New(Params{ - State: suite.state, - Headers: suite.headers, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + suite.state, + nil, + nil, + nil, + suite.headers, + nil, + nil, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) _, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), maxHeight, minHeight) suite.Require().Error(err) @@ -1533,21 +1784,30 @@ func (suite *Suite) TestGetEventsForHeightRange() { expectedResp := setupExecClient() fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() - backend := New(Params{ - State: state, - Blocks: suite.blocks, - Headers: suite.headers, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - FixedExecutionNodeIDs: fixedENIdentifiersStr, - }) + // create handler + backend := New( + state, + nil, + nil, + suite.blocks, + suite.headers, + nil, + nil, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + fixedENIdentifiersStr, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // execute request actualResp, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), minHeight, maxHeight) @@ -1565,21 +1825,29 @@ func (suite *Suite) TestGetEventsForHeightRange() { expectedResp := setupExecClient() fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() - backend := New(Params{ - State: state, - Blocks: suite.blocks, - Headers: suite.headers, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - FixedExecutionNodeIDs: fixedENIdentifiersStr, - }) + backend := New( + state, + nil, + nil, + suite.blocks, + suite.headers, + nil, + nil, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + fixedENIdentifiersStr, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) actualResp, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), minHeight, maxHeight) suite.checkResponse(actualResp, err) @@ -1595,21 +1863,30 @@ func (suite *Suite) TestGetEventsForHeightRange() { blockHeaders, _, nodeIdentities = setupStorage(minHeight, headHeight) fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() - backend := New(Params{ - State: suite.state, - Blocks: suite.blocks, - Headers: suite.headers, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - MaxHeightRange: 1, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - FixedExecutionNodeIDs: fixedENIdentifiersStr, - }) + // create handler + backend := New( + state, + nil, + nil, + suite.blocks, + suite.headers, + nil, + nil, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + 1, // set maximum range to 1 + nil, + fixedENIdentifiersStr, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) _, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), minHeight, minHeight+1) suite.Require().Error(err) @@ -1625,21 +1902,30 @@ func (suite *Suite) TestGetEventsForHeightRange() { blockHeaders, _, nodeIdentities = setupStorage(minHeight, maxHeight) fixedENIdentifiersStr := flow.IdentifierList(nodeIdentities.NodeIDs()).Strings() - backend := New(Params{ - State: state, - Blocks: suite.blocks, - Headers: suite.headers, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - FixedExecutionNodeIDs: fixedENIdentifiersStr, - }) + // create handler + backend := New( + state, + nil, + nil, + suite.blocks, + suite.headers, + nil, + nil, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + fixedENIdentifiersStr, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) _, err := backend.GetEventsForHeightRange(ctx, string(flow.EventAccountCreated), minHeight, maxHeight) suite.Require().Error(err) @@ -1695,20 +1981,30 @@ func (suite *Suite) TestGetAccount() { connFactory := new(backendmock.ConnectionFactory) connFactory.On("GetExecutionAPIClient", mock.Anything).Return(suite.execClient, &mockCloser{}, nil) - backend := New(Params{ - State: suite.state, - Blocks: suite.blocks, - Headers: suite.headers, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - }) + // create the handler with the mock + backend := New( + suite.state, + nil, + nil, + nil, + suite.headers, + nil, + nil, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) preferredENIdentifiers = flow.IdentifierList{receipts[0].ExecutorID} @@ -1737,7 +2033,7 @@ func (suite *Suite) TestGetAccountAtBlockHeight() { b := unittest.BlockFixture() h := b.Header - // setup Headers storage to return the header when queried by height + // setup headers storage to return the header when queried by height suite.headers. On("ByHeight", height). Return(h, nil). @@ -1768,19 +2064,30 @@ func (suite *Suite) TestGetAccountAtBlockHeight() { Return(exeResp, nil). Once() - backend := New(Params{ - State: suite.state, - Headers: suite.headers, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: flow.Testnet, - AccessMetrics: metrics.NewNoopCollector(), - ConnFactory: connFactory, - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - }) + // create the handler with the mock + backend := New( + suite.state, + nil, + nil, + nil, + suite.headers, + nil, + nil, + suite.receipts, + suite.results, + flow.Testnet, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) preferredENIdentifiers = flow.IdentifierList{receipts[0].ExecutorID} @@ -1799,14 +2106,29 @@ func (suite *Suite) TestGetNetworkParameters() { expectedChainID := flow.Mainnet - backend := New(Params{ - ChainID: flow.Mainnet, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - }) + backend := New( + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + flow.Mainnet, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) params := backend.GetNetworkParameters(context.Background()) @@ -1900,7 +2222,7 @@ func (suite *Suite) TestExecutionNodesForBlockID() { } } // if we don't find sufficient receipts, executionNodesForBlockID should return a list of random ENs - suite.Run("insufficient receipts return random ENs in State", func() { + suite.Run("insufficient receipts return random ENs in state", func() { // return no receipts at all attempts attempt1Receipts = flow.ExecutionReceiptList{} attempt2Receipts = flow.ExecutionReceiptList{} @@ -1987,19 +2309,30 @@ func (suite *Suite) TestExecuteScriptOnExecutionNode() { connFactory.On("GetExecutionAPIClient", mock.Anything).Return(suite.execClient, &mockCloser{}, nil) connFactory.On("InvalidateExecutionAPIClient", mock.Anything) - backend := New(Params{ - State: suite.state, - Headers: suite.headers, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: flow.Mainnet, - ConnFactory: connFactory, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - }) + // create the handler with the mock + backend := New( + suite.state, + nil, + nil, + nil, + suite.headers, + nil, + nil, + suite.receipts, + suite.results, + flow.Mainnet, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // mock parameters ctx := context.Background() @@ -2054,20 +2387,30 @@ func (suite *Suite) TestExecuteScriptOnArchiveNode() { archiveNode := unittest.IdentityFixture(unittest.WithRole(flow.RoleAccess)) fullArchiveAddress := archiveNode.Address + ":" + strconv.FormatUint(uint64(mockPort), 10) - backend := New(Params{ - State: suite.state, - Headers: suite.headers, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: flow.Mainnet, - ConnFactory: connFactory, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - ArchiveAddressList: []string{fullArchiveAddress}, - }) + // create the handler with the mock + backend := New( + suite.state, + nil, + nil, + nil, + suite.headers, + nil, + nil, + suite.receipts, + suite.results, + flow.Mainnet, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + []string{fullArchiveAddress}, + false, + false, + ) // mock parameters ctx := context.Background() @@ -2127,22 +2470,30 @@ func (suite *Suite) TestScriptExecutionValidationMode() { connFactory.On("InvalidateAccessAPIClient", mock.Anything) archiveNode := unittest.IdentityFixture(unittest.WithRole(flow.RoleAccess)) fullArchiveAddress := archiveNode.Address + ":" + strconv.FormatUint(uint64(mockPort), 10) - - backend := New(Params{ - State: suite.state, - Headers: suite.headers, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: flow.Mainnet, - ConnFactory: connFactory, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - ArchiveAddressList: []string{fullArchiveAddress}, - ScriptExecValidation: true, - }) + // create the handler with the mock + backend := New( + suite.state, + nil, + nil, + nil, + suite.headers, + nil, + nil, + suite.receipts, + suite.results, + flow.Mainnet, + metrics.NewNoopCollector(), + connFactory, // the connection factory should be used to get the execution node client + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + []string{fullArchiveAddress}, + true, + false, + ) // mock parameters ctx := context.Background() diff --git a/engine/access/rpc/backend/backend_transactions.go b/engine/access/rpc/backend/backend_transactions.go index 80bb2d07402..79579d420e6 100644 --- a/engine/access/rpc/backend/backend_transactions.go +++ b/engine/access/rpc/backend/backend_transactions.go @@ -6,7 +6,6 @@ import ( "fmt" "time" - lru2 "github.com/hashicorp/golang-lru/v2" accessproto "github.com/onflow/flow/protobuf/go/flow/access" "github.com/onflow/flow/protobuf/go/flow/entities" execproto "github.com/onflow/flow/protobuf/go/flow/execution" @@ -40,8 +39,7 @@ type backendTransactions struct { previousAccessNodes []accessproto.AccessAPIClient log zerolog.Logger - nodeCommunicator Communicator - txResultCache *lru2.Cache[flow.Identifier, *access.TransactionResult] + nodeCommunicator *NodeCommunicator } // SendTransaction forwards the transaction to the collection node @@ -95,7 +93,7 @@ func (b *backendTransactions) trySendTransaction(ctx context.Context, tx *flow.T var sendError error logAnyError := func() { if sendError != nil { - b.log.Info().Err(err).Msg("failed to send transactions to collector nodes") + b.log.Info().Err(err).Msg("failed to send transactions to collector nodes") } } defer logAnyError() @@ -231,41 +229,25 @@ func (b *backendTransactions) GetTransactionResult( ) (*access.TransactionResult, error) { // look up transaction from storage start := time.Now() - tx, err := b.transactions.ByID(txID) + if err != nil { txErr := rpc.ConvertStorageError(err) - - if status.Code(txErr) != codes.NotFound { - return nil, txErr - } - - // Tx not found. If we have historical Sporks setup, lets look through those as well - if b.txResultCache != nil { - val, ok := b.txResultCache.Get(txID) - if ok { - return val, nil - } - } - historicalTxResult, err := b.getHistoricalTransactionResult(ctx, txID) - if err != nil { - // if tx not found in old access nodes either, then assume that the tx was submitted to a different AN - // and return status as unknown - txStatus := flow.TransactionStatusUnknown - result := &access.TransactionResult{ - Status: txStatus, - StatusCode: uint(txStatus), - } - if b.txResultCache != nil { - b.txResultCache.Add(txID, result) + if status.Code(txErr) == codes.NotFound { + // Tx not found. If we have historical Sporks setup, lets look through those as well + historicalTxResult, err := b.getHistoricalTransactionResult(ctx, txID) + if err != nil { + // if tx not found in old access nodes either, then assume that the tx was submitted to a different AN + // and return status as unknown + txStatus := flow.TransactionStatusUnknown + return &access.TransactionResult{ + Status: txStatus, + StatusCode: uint(txStatus), + }, nil } - return result, nil + return historicalTxResult, nil } - - if b.txResultCache != nil { - b.txResultCache.Add(txID, historicalTxResult) - } - return historicalTxResult, nil + return nil, txErr } block, err := b.retrieveBlock(blockID, collectionID, txID) @@ -413,7 +395,7 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( i := 0 errInsufficientResults := status.Errorf( codes.Internal, - "number of transaction results returned by execution node is less than the number of transactions in the block", + "number of transaction results returned by execution node is less than the number of transactions in the block", ) for _, guarantee := range block.Payload.Guarantees { @@ -423,7 +405,7 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( } for _, txID := range collection.Transactions { - // bounds check. this means the EN returned fewer transaction results than the transactions in the block + // bounds check. this means the EN returned fewer transaction results than the transactions in the block if i >= len(resp.TransactionResults) { return nil, errInsufficientResults } @@ -456,8 +438,8 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( } } - // after iterating through all transactions in each collection, i equals the total number of - // user transactions in the block + // after iterating through all transactions in each collection, i equals the total number of + // user transactions in the block txCount := i sporkRootBlockHeight, err := b.state.Params().SporkRootBlockHeight() @@ -477,7 +459,7 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( } // otherwise there are extra results // TODO(bft): slashable offense - return nil, status.Errorf(codes.Internal, "number of transaction results returned by execution node is more than the number of transactions in the block") + return nil, status.Errorf(codes.Internal, "number of transaction results returned by execution node is more than the number of transactions in the block") } systemTx, err := blueprints.SystemChunkTransaction(b.chainID.Chain()) @@ -509,8 +491,8 @@ func (b *backendTransactions) GetTransactionResultsByBlockID( return results, nil } -// GetTransactionResultByIndex returns transactions Results for an index in a block that is executed, -// pending or finalized transactions return errors +// GetTransactionResultByIndex returns TransactionsResults for an index in a block that is executed, +// pending or finalized transactions return errors func (b *backendTransactions) GetTransactionResultByIndex( ctx context.Context, blockID flow.Identifier, @@ -590,20 +572,20 @@ func (b *backendTransactions) deriveTransactionStatus( } // At this point, we have seen the expiry block for the transaction. - // This means that, if no collections prior to the expiry block contain + // This means that, if no collections prior to the expiry block contain // the transaction, it can never be included and is expired. // - // To ensure this, we need to have received all collections up to the + // To ensure this, we need to have received all collections up to the // expiry block to ensure the transaction did not appear in any. // the last full height is the height where we have received all - // collections for all blocks with a lower height + // collections for all blocks with a lower height fullHeight, err := b.blocks.GetLastFullBlockHeight() if err != nil { return flow.TransactionStatusUnknown, err } - // if we have received collections for all blocks up to the expiry block, the transaction is expired + // if we have received collections for all blocks up to the expiry block, the transaction is expired if b.isExpired(refHeight, fullHeight) { return flow.TransactionStatusExpired, nil } @@ -621,7 +603,7 @@ func (b *backendTransactions) deriveTransactionStatus( // From this point on, we know for sure this transaction has at least been executed - // get the latest sealed block from the State + // get the latest sealed block from the state sealed, err := b.state.Sealed().Head() if err != nil { return flow.TransactionStatusUnknown, err @@ -720,7 +702,7 @@ func (b *backendTransactions) getHistoricalTransactionResult( } if result.GetStatus() == entities.TransactionStatus_PENDING { - // This is on a historical node. No transactions from it will ever be + // This is on a historical node. No transactions from it will ever be // executed, therefore we should consider this expired result.Status = entities.TransactionStatus_EXPIRED } diff --git a/engine/access/rpc/backend/backend_transactions_test.go b/engine/access/rpc/backend/backend_transactions_test.go deleted file mode 100644 index 3b1464a3e13..00000000000 --- a/engine/access/rpc/backend/backend_transactions_test.go +++ /dev/null @@ -1,333 +0,0 @@ -package backend - -import ( - "context" - "fmt" - - "github.com/dgraph-io/badger/v2" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - acc "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/model/flow" - "github.com/onflow/flow-go/module/metrics" - "github.com/onflow/flow-go/state/protocol" - bprotocol "github.com/onflow/flow-go/state/protocol/badger" - "github.com/onflow/flow-go/state/protocol/util" - "github.com/onflow/flow-go/storage" - "github.com/onflow/flow-go/utils/unittest" -) - -func (suite *Suite) withPreConfiguredState(f func(snap protocol.Snapshot)) { - identities := unittest.CompleteIdentitySet() - rootSnapshot := unittest.RootSnapshotFixture(identities) - util.RunWithFullProtocolState(suite.T(), rootSnapshot, func(db *badger.DB, state *bprotocol.ParticipantState) { - epochBuilder := unittest.NewEpochBuilder(suite.T(), state) - - epochBuilder. - BuildEpoch(). - CompleteEpoch() - - // get heights of each phase in built epochs - epoch1, ok := epochBuilder.EpochHeights(1) - require.True(suite.T(), ok) - - // setup AtHeight mock returns for State - for _, height := range epoch1.Range() { - suite.state.On("AtHeight", epoch1.Range()).Return(state.AtHeight(height)) - } - - snap := state.AtHeight(epoch1.Range()[0]) - suite.state.On("Final").Return(snap).Once() - suite.communicator.On("CallAvailableNode", - mock.Anything, - mock.Anything, - mock.Anything). - Return(nil).Once() - - f(snap) - }) - -} - -// TestGetTransactionResultReturnsUnknown returns unknown result when tx not found -func (suite *Suite) TestGetTransactionResultReturnsUnknown() { - suite.withPreConfiguredState(func(snap protocol.Snapshot) { - block := unittest.BlockFixture() - tbody := unittest.TransactionBodyFixture() - tx := unittest.TransactionFixture() - tx.TransactionBody = tbody - - coll := flow.CollectionFromTransactions([]*flow.Transaction{&tx}) - suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() - - suite.transactions. - On("ByID", tx.ID()). - Return(nil, storage.ErrNotFound) - - backend := New( - Params{ - State: suite.state, - CollectionRPC: suite.colClient, - Blocks: suite.blocks, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: suite.communicator, - }) - res, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) - suite.Require().NoError(err) - suite.Require().Equal(res.Status, flow.TransactionStatusUnknown) - }) -} - -// TestGetTransactionResultReturnsTransactionError returns error from transaction storage -func (suite *Suite) TestGetTransactionResultReturnsTransactionError() { - suite.withPreConfiguredState(func(snap protocol.Snapshot) { - block := unittest.BlockFixture() - tbody := unittest.TransactionBodyFixture() - tx := unittest.TransactionFixture() - tx.TransactionBody = tbody - - coll := flow.CollectionFromTransactions([]*flow.Transaction{&tx}) - - suite.transactions. - On("ByID", tx.ID()). - Return(nil, fmt.Errorf("some other error")) - - suite.blocks. - On("ByID", block.ID()). - Return(&block, nil). - Once() - - suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() - - backend := New( - Params{ - State: suite.state, - CollectionRPC: suite.colClient, - Blocks: suite.blocks, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: suite.communicator, - }) - _, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) - suite.Require().Equal(err, status.Errorf(codes.Internal, "failed to find: %v", fmt.Errorf("some other error"))) - - }) -} - -// TestGetTransactionResultReturnsValidTransactionResultFromHistoricNode tests lookup in historic nodes -func (suite *Suite) TestGetTransactionResultReturnsValidTransactionResultFromHistoricNode() { - suite.withPreConfiguredState(func(snap protocol.Snapshot) { - block := unittest.BlockFixture() - tbody := unittest.TransactionBodyFixture() - tx := unittest.TransactionFixture() - tx.TransactionBody = tbody - - coll := flow.CollectionFromTransactions([]*flow.Transaction{&tx}) - - suite.transactions. - On("ByID", tx.ID()). - Return(nil, storage.ErrNotFound) - - suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() - - transactionResultResponse := access.TransactionResultResponse{ - Status: entities.TransactionStatus_EXECUTED, - StatusCode: uint32(entities.TransactionStatus_EXECUTED), - } - - suite.historicalAccessClient. - On("GetTransactionResult", mock.Anything, mock.Anything). - Return(&transactionResultResponse, nil).Once() - - backend := New( - Params{ - State: suite.state, - CollectionRPC: suite.colClient, - HistoricalAccessNodes: []access.AccessAPIClient{suite.historicalAccessClient}, - Blocks: suite.blocks, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: suite.communicator, - }) - resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) - suite.Require().NoError(err) - suite.Require().Equal(flow.TransactionStatusExecuted, resp.Status) - suite.Require().Equal(uint(flow.TransactionStatusExecuted), resp.StatusCode) - }) -} - -func (suite *Suite) withGetTransactionCachingTestSetup(f func(b *flow.Block, t *flow.Transaction)) { - suite.withPreConfiguredState(func(snap protocol.Snapshot) { - block := unittest.BlockFixture() - tbody := unittest.TransactionBodyFixture() - tx := unittest.TransactionFixture() - tx.TransactionBody = tbody - - suite.transactions. - On("ByID", tx.ID()). - Return(nil, storage.ErrNotFound) - - suite.state.On("AtBlockID", block.ID()).Return(snap, nil).Once() - - f(&block, &tx) - }) -} - -// TestGetTransactionResultFromCache get historic transaction result from cache -func (suite *Suite) TestGetTransactionResultFromCache() { - suite.withGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { - transactionResultResponse := access.TransactionResultResponse{ - Status: entities.TransactionStatus_EXECUTED, - StatusCode: uint32(entities.TransactionStatus_EXECUTED), - } - - suite.historicalAccessClient. - On("GetTransactionResult", mock.AnythingOfType("*context.emptyCtx"), mock.AnythingOfType("*access.GetTransactionRequest")). - Return(&transactionResultResponse, nil).Once() - - backend := New(Params{ - State: suite.state, - CollectionRPC: suite.colClient, - HistoricalAccessNodes: []access.AccessAPIClient{suite.historicalAccessClient}, - Blocks: suite.blocks, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: suite.communicator, - TxResultCacheSize: 10, - }) - - coll := flow.CollectionFromTransactions([]*flow.Transaction{tx}) - - resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) - suite.Require().NoError(err) - suite.Require().Equal(flow.TransactionStatusExecuted, resp.Status) - suite.Require().Equal(uint(flow.TransactionStatusExecuted), resp.StatusCode) - - resp2, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) - suite.Require().NoError(err) - suite.Require().Equal(flow.TransactionStatusExecuted, resp2.Status) - suite.Require().Equal(uint(flow.TransactionStatusExecuted), resp2.StatusCode) - - suite.historicalAccessClient.AssertExpectations(suite.T()) - }) -} - -// TestGetTransactionResultCacheNonExistent tests caches non existing result -func (suite *Suite) TestGetTransactionResultCacheNonExistent() { - suite.withGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { - - suite.historicalAccessClient. - On("GetTransactionResult", mock.AnythingOfType("*context.emptyCtx"), mock.AnythingOfType("*access.GetTransactionRequest")). - Return(nil, status.Errorf(codes.NotFound, "no known transaction with ID %s", tx.ID())).Once() - - backend := New(Params{ - State: suite.state, - CollectionRPC: suite.colClient, - HistoricalAccessNodes: []access.AccessAPIClient{suite.historicalAccessClient}, - Blocks: suite.blocks, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: suite.communicator, - TxResultCacheSize: 10, - }) - - coll := flow.CollectionFromTransactions([]*flow.Transaction{tx}) - - resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) - suite.Require().NoError(err) - suite.Require().Equal(flow.TransactionStatusUnknown, resp.Status) - suite.Require().Equal(uint(flow.TransactionStatusUnknown), resp.StatusCode) - - // ensure the unknown transaction is cached when not found anywhere - txStatus := flow.TransactionStatusUnknown - res, ok := backend.txResultCache.Get(tx.ID()) - suite.Require().True(ok) - suite.Require().Equal(res, &acc.TransactionResult{ - Status: txStatus, - StatusCode: uint(txStatus), - }) - - suite.historicalAccessClient.AssertExpectations(suite.T()) - - }) -} - -// TestGetTransactionResultUnknownFromCache retrive unknown result from cache -func (suite *Suite) TestGetTransactionResultUnknownFromCache() { - suite.withGetTransactionCachingTestSetup(func(block *flow.Block, tx *flow.Transaction) { - suite.historicalAccessClient. - On("GetTransactionResult", mock.AnythingOfType("*context.emptyCtx"), mock.AnythingOfType("*access.GetTransactionRequest")). - Return(nil, status.Errorf(codes.NotFound, "no known transaction with ID %s", tx.ID())).Once() - - backend := New(Params{ - State: suite.state, - CollectionRPC: suite.colClient, - HistoricalAccessNodes: []access.AccessAPIClient{suite.historicalAccessClient}, - Blocks: suite.blocks, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - Log: suite.log, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: suite.communicator, - TxResultCacheSize: 10, - }) - - coll := flow.CollectionFromTransactions([]*flow.Transaction{tx}) - - resp, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) - suite.Require().NoError(err) - suite.Require().Equal(flow.TransactionStatusUnknown, resp.Status) - suite.Require().Equal(uint(flow.TransactionStatusUnknown), resp.StatusCode) - - // ensure the unknown transaction is cached when not found anywhere - txStatus := flow.TransactionStatusUnknown - res, ok := backend.txResultCache.Get(tx.ID()) - suite.Require().True(ok) - suite.Require().Equal(res, &acc.TransactionResult{ - Status: txStatus, - StatusCode: uint(txStatus), - }) - - resp2, err := backend.GetTransactionResult(context.Background(), tx.ID(), block.ID(), coll.ID()) - suite.Require().NoError(err) - suite.Require().Equal(flow.TransactionStatusUnknown, resp2.Status) - suite.Require().Equal(uint(flow.TransactionStatusUnknown), resp2.StatusCode) - - suite.historicalAccessClient.AssertExpectations(suite.T()) - - }) -} diff --git a/engine/access/rpc/backend/mock/communicator.go b/engine/access/rpc/backend/mock/communicator.go index ab7498ac8f8..9989e30753b 100644 --- a/engine/access/rpc/backend/mock/communicator.go +++ b/engine/access/rpc/backend/mock/communicator.go @@ -3,8 +3,9 @@ package mock import ( - flow "github.com/onflow/flow-go/model/flow" mock "github.com/stretchr/testify/mock" + + flow "github.com/onflow/flow-go/model/flow" ) // Communicator is an autogenerated mock type for the Communicator type diff --git a/engine/access/rpc/backend/node_communicator.go b/engine/access/rpc/backend/node_communicator.go index 448b0c7b267..d75432b0b29 100644 --- a/engine/access/rpc/backend/node_communicator.go +++ b/engine/access/rpc/backend/node_communicator.go @@ -20,16 +20,6 @@ type NodeAction func(node *flow.Identity) error // It takes an error as input and returns a boolean value indicating whether the error should be considered terminal. type ErrorTerminator func(node *flow.Identity, err error) bool -type Communicator interface { - CallAvailableNode( - nodes flow.IdentityList, - call func(node *flow.Identity) error, - shouldTerminateOnError func(node *flow.Identity, err error) bool, - ) error -} - -var _ Communicator = (*NodeCommunicator)(nil) - // NodeCommunicator is responsible for calling available nodes in the backend. type NodeCommunicator struct { nodeSelectorFactory NodeSelectorFactory @@ -49,8 +39,8 @@ func NewNodeCommunicator(circuitBreakerEnabled bool) *NodeCommunicator { // If the maximum failed request count is reached, it returns the accumulated errors. func (b *NodeCommunicator) CallAvailableNode( nodes flow.IdentityList, - call func(id *flow.Identity) error, - shouldTerminateOnError func(node *flow.Identity, err error) bool, + call NodeAction, + shouldTerminateOnError ErrorTerminator, ) error { var errs *multierror.Error nodeSelector, err := b.nodeSelectorFactory.SelectNodes(nodes) diff --git a/engine/access/rpc/backend/retry.go b/engine/access/rpc/backend/retry.go index 5d967e657bb..c5765bfbbe5 100644 --- a/engine/access/rpc/backend/retry.go +++ b/engine/access/rpc/backend/retry.go @@ -10,12 +10,12 @@ import ( ) // retryFrequency has to be less than TransactionExpiry or else this module does nothing -const retryFrequency uint64 = 120 // Blocks +const retryFrequency uint64 = 120 // blocks // Retry implements a simple retry mechanism for transaction submission. type Retry struct { mu sync.RWMutex - // pending Transactions + // pending transactions transactionByReferencBlockHeight map[uint64]map[flow.Identifier]*flow.TransactionBody backend *Backend active bool @@ -47,7 +47,7 @@ func (r *Retry) Retry(height uint64) { return } - // naive cleanup for now, prune every 120 Blocks + // naive cleanup for now, prune every 120 blocks if height%retryFrequency == 0 { r.prune(height) } @@ -84,7 +84,7 @@ func (r *Retry) RegisterTransaction(height uint64, tx *flow.TransactionBody) { func (r *Retry) prune(height uint64) { r.mu.Lock() defer r.mu.Unlock() - // If height is less than the default, there will be no expired Transactions + // If height is less than the default, there will be no expired transactions if height < flow.DefaultTransactionExpiry { return } diff --git a/engine/access/rpc/backend/retry_test.go b/engine/access/rpc/backend/retry_test.go index d656380c204..07bb77aa8a9 100644 --- a/engine/access/rpc/backend/retry_test.go +++ b/engine/access/rpc/backend/retry_test.go @@ -3,12 +3,13 @@ package backend import ( "context" - "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/execution" "github.com/stretchr/testify/mock" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" protocol "github.com/onflow/flow-go/state/protocol/mock" @@ -41,24 +42,28 @@ func (suite *Suite) TestTransactionRetry() { // txID := transactionBody.ID() // blockID := block.ID() // Setup Handler + Retry - backend := New( - Params{ - State: suite.state, - CollectionRPC: suite.colClient, - Blocks: suite.blocks, - Headers: suite.headers, - Collections: suite.collections, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - }) - + backend := New(suite.state, + suite.colClient, + nil, + suite.blocks, + suite.headers, + suite.collections, + suite.transactions, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) retry := newRetry().SetBackend(backend).Activate() backend.retry = retry @@ -127,25 +132,29 @@ func (suite *Suite) TestSuccessfulTransactionsDontRetry() { suite.snapshot.On("Identities", mock.Anything).Return(enIDs, nil) connFactory := suite.setupConnectionFactory() - backend := New( - Params{ - State: suite.state, - CollectionRPC: suite.colClient, - Blocks: suite.blocks, - Headers: suite.headers, - Collections: suite.collections, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - ConnFactory: connFactory, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Log: suite.log, - Communicator: NewNodeCommunicator(false), - }) - + // Setup Handler + Retry + backend := New(suite.state, + suite.colClient, + nil, + suite.blocks, + suite.headers, + suite.collections, + suite.transactions, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + connFactory, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) retry := newRetry().SetBackend(backend).Activate() backend.retry = retry @@ -159,7 +168,7 @@ func (suite *Suite) TestSuccessfulTransactionsDontRetry() { result, err := backend.GetTransactionResult(ctx, txID, flow.ZeroID, flow.ZeroID) suite.checkResponse(result, err) - // status should be finalized since the sealed Blocks is smaller in height + // status should be finalized since the sealed blocks is smaller in height suite.Assert().Equal(flow.TransactionStatusFinalized, result.Status) // Don't retry now now that block is finalized diff --git a/engine/access/rpc/rate_limit_test.go b/engine/access/rpc/rate_limit_test.go index 5777a4b3aee..e24190af34a 100644 --- a/engine/access/rpc/rate_limit_test.go +++ b/engine/access/rpc/rate_limit_test.go @@ -8,18 +8,6 @@ import ( "testing" "time" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/status" - accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rpc/backend" "github.com/onflow/flow-go/model/flow" @@ -32,6 +20,17 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/status" ) type RateLimitTestSuite struct { @@ -147,7 +146,7 @@ func (suite *RateLimitTestSuite) SetupTest() { block := unittest.BlockHeaderFixture() suite.snapshot.On("Head").Return(block, nil) - bnd := backend.New( + backend := backend.New( suite.state, suite.collClient, nil, @@ -167,7 +166,7 @@ func (suite *RateLimitTestSuite) SetupTest() { suite.log, 0, nil, - backend.NewNodeCommunicator(false), + false, false, ) @@ -179,8 +178,8 @@ func (suite *RateLimitTestSuite) SetupTest() { suite.metrics, false, suite.me, - bnd, - bnd, + backend, + backend, suite.secureGrpcServer, suite.unsecureGrpcServer) diff --git a/engine/access/secure_grpcr_test.go b/engine/access/secure_grpcr_test.go index d5f64352cf6..5e122951eb0 100644 --- a/engine/access/secure_grpcr_test.go +++ b/engine/access/secure_grpcr_test.go @@ -7,7 +7,6 @@ import ( "testing" "time" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -16,6 +15,8 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow-go/crypto" accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rpc" @@ -130,20 +131,29 @@ func (suite *SecureGRPCTestSuite) SetupTest() { block := unittest.BlockHeaderFixture() suite.snapshot.On("Head").Return(block, nil) - bnd := backend.New(backend.Params{ - State: suite.state, - CollectionRPC: suite.collClient, - Blocks: suite.blocks, - Headers: suite.headers, - Collections: suite.collections, - Transactions: suite.transactions, - ChainID: suite.chainID, - AccessMetrics: suite.metrics, - MaxHeightRange: 0, - Log: suite.log, - SnapshotHistoryLimit: 0, - Communicator: backend.NewNodeCommunicator(false), - }) + backend := backend.New( + suite.state, + suite.collClient, + nil, + suite.blocks, + suite.headers, + suite.collections, + suite.transactions, + nil, + nil, + suite.chainID, + suite.metrics, + nil, + false, + 0, + nil, + nil, + suite.log, + 0, + nil, + false, + false, + ) rpcEngBuilder, err := rpc.NewBuilder( suite.log, @@ -153,8 +163,8 @@ func (suite *SecureGRPCTestSuite) SetupTest() { suite.metrics, false, suite.me, - bnd, - bnd, + backend, + backend, suite.secureGrpcServer, suite.unsecureGrpcServer, ) diff --git a/module/executiondatasync/tracker/mock/storage.go b/module/executiondatasync/tracker/mock/storage.go index 6eef7092ffd..e071a4ce67f 100644 --- a/module/executiondatasync/tracker/mock/storage.go +++ b/module/executiondatasync/tracker/mock/storage.go @@ -3,8 +3,9 @@ package mocktracker import ( - tracker "github.com/onflow/flow-go/module/executiondatasync/tracker" mock "github.com/stretchr/testify/mock" + + tracker "github.com/onflow/flow-go/module/executiondatasync/tracker" ) // Storage is an autogenerated mock type for the Storage type diff --git a/module/mempool/consensus/mock/exec_fork_actor.go b/module/mempool/consensus/mock/exec_fork_actor.go index ae567dd9e7c..3e92f3130e3 100644 --- a/module/mempool/consensus/mock/exec_fork_actor.go +++ b/module/mempool/consensus/mock/exec_fork_actor.go @@ -3,8 +3,9 @@ package mock import ( - flow "github.com/onflow/flow-go/model/flow" mock "github.com/stretchr/testify/mock" + + flow "github.com/onflow/flow-go/model/flow" ) // ExecForkActorMock is an autogenerated mock type for the ExecForkActor type diff --git a/module/metrics.go b/module/metrics.go index b1bfbad81ae..3c1d6dfdc37 100644 --- a/module/metrics.go +++ b/module/metrics.go @@ -6,11 +6,12 @@ import ( "github.com/libp2p/go-libp2p/core/peer" rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" + httpmetrics "github.com/slok/go-http-metrics/metrics" + "github.com/onflow/flow-go/model/chainsync" "github.com/onflow/flow-go/model/cluster" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/network/channels" - httpmetrics "github.com/slok/go-http-metrics/metrics" ) type EntriesFunc func() uint diff --git a/module/metrics/access.go b/module/metrics/access.go index effb24c4326..1116f87f433 100644 --- a/module/metrics/access.go +++ b/module/metrics/access.go @@ -1,10 +1,11 @@ package metrics import ( - "github.com/onflow/flow-go/module" - "github.com/onflow/flow-go/module/counters" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + + "github.com/onflow/flow-go/module" + "github.com/onflow/flow-go/module/counters" ) type AccessCollectorOpts func(*AccessCollector) diff --git a/module/state_synchronization/mock/execution_data_requester.go b/module/state_synchronization/mock/execution_data_requester.go index 2aee152ac57..97e0fb6b593 100644 --- a/module/state_synchronization/mock/execution_data_requester.go +++ b/module/state_synchronization/mock/execution_data_requester.go @@ -3,9 +3,10 @@ package state_synchronization import ( - irrecoverable "github.com/onflow/flow-go/module/irrecoverable" mock "github.com/stretchr/testify/mock" + irrecoverable "github.com/onflow/flow-go/module/irrecoverable" + model "github.com/onflow/flow-go/consensus/hotstuff/model" state_synchronization "github.com/onflow/flow-go/module/state_synchronization" From 41c81a64e5550f77b992f642630243c022f186bb Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Fri, 25 Aug 2023 11:02:25 +0100 Subject: [PATCH 60/66] Fix imports in backend scripts --- engine/access/rpc/backend/backend_scripts.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/engine/access/rpc/backend/backend_scripts.go b/engine/access/rpc/backend/backend_scripts.go index c09b1cbf4e7..0bceaac3815 100644 --- a/engine/access/rpc/backend/backend_scripts.go +++ b/engine/access/rpc/backend/backend_scripts.go @@ -1,25 +1,26 @@ package backend import ( - "crypto/md5" //nolint:gosec "bytes" "context" + "crypto/md5" //nolint:gosec "io" "time" "github.com/hashicorp/go-multierror" lru "github.com/hashicorp/golang-lru/v2" + "github.com/onflow/flow/protobuf/go/flow/access" + execproto "github.com/onflow/flow/protobuf/go/flow/execution" + "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/onflow/flow-go/engine/access/rpc/connection" "github.com/onflow/flow-go/engine/common/rpc" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module" "github.com/onflow/flow-go/state/protocol" "github.com/onflow/flow-go/storage" - "github.com/onflow/flow/protobuf/go/flow/access" - execproto "github.com/onflow/flow/protobuf/go/flow/execution" - "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) // uniqueScriptLoggingTimeWindow is the duration for checking the uniqueness of scripts sent for execution From f7805a02d4d524ff46bbdcf1bf9e480d5ec40789 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Fri, 25 Aug 2023 11:04:07 +0100 Subject: [PATCH 61/66] Remove unrelated changes from historical access test --- .../rpc/backend/historical_access_test.go | 80 +++++++++++-------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/engine/access/rpc/backend/historical_access_test.go b/engine/access/rpc/backend/historical_access_test.go index 16fba999a47..2632d216792 100644 --- a/engine/access/rpc/backend/historical_access_test.go +++ b/engine/access/rpc/backend/historical_access_test.go @@ -3,11 +3,12 @@ package backend import ( "context" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/onflow/flow/protobuf/go/flow/entities" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/onflow/flow/protobuf/go/flow/entities" + "github.com/onflow/flow-go/engine/common/rpc/convert" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" @@ -36,21 +37,28 @@ func (suite *Suite) TestHistoricalTransactionResult() { Events: nil, } - backend := New(Params{ - State: suite.state, - HistoricalAccessNodes: []accessproto.AccessAPIClient{suite.historicalAccessClient}, - Blocks: suite.blocks, - Headers: suite.headers, - Collections: suite.collections, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New(suite.state, + nil, + []accessproto.AccessAPIClient{suite.historicalAccessClient}, + suite.blocks, + suite.headers, + suite.collections, + suite.transactions, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // Successfully return the transaction from the historical node suite.historicalAccessClient. @@ -89,22 +97,28 @@ func (suite *Suite) TestHistoricalTransaction() { Transaction: convert.TransactionToMessage(*transactionBody), } - backend := New( - Params{ - State: suite.state, - HistoricalAccessNodes: []accessproto.AccessAPIClient{suite.historicalAccessClient}, - Blocks: suite.blocks, - Headers: suite.headers, - Collections: suite.collections, - Transactions: suite.transactions, - ExecutionReceipts: suite.receipts, - ExecutionResults: suite.results, - ChainID: suite.chainID, - AccessMetrics: metrics.NewNoopCollector(), - MaxHeightRange: DefaultMaxHeightRange, - SnapshotHistoryLimit: DefaultSnapshotHistoryLimit, - Communicator: NewNodeCommunicator(false), - }) + backend := New(suite.state, + nil, + []accessproto.AccessAPIClient{suite.historicalAccessClient}, + suite.blocks, + suite.headers, + suite.collections, + suite.transactions, + suite.receipts, + suite.results, + suite.chainID, + metrics.NewNoopCollector(), + nil, + false, + DefaultMaxHeightRange, + nil, + nil, + suite.log, + DefaultSnapshotHistoryLimit, + nil, + false, + false, + ) // Successfully return the transaction from the historical node suite.historicalAccessClient. From 4936f8b066c4abc7173ae7a43369d6a60838e75c Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Fri, 25 Aug 2023 11:12:26 +0100 Subject: [PATCH 62/66] Fix imports --- engine/access/rpc/rate_limit_test.go | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/engine/access/rpc/rate_limit_test.go b/engine/access/rpc/rate_limit_test.go index e24190af34a..8eb1b51c064 100644 --- a/engine/access/rpc/rate_limit_test.go +++ b/engine/access/rpc/rate_limit_test.go @@ -8,6 +8,18 @@ import ( "testing" "time" + accessproto "github.com/onflow/flow/protobuf/go/flow/access" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/status" + accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rpc/backend" "github.com/onflow/flow-go/model/flow" @@ -20,17 +32,6 @@ import ( storagemock "github.com/onflow/flow-go/storage/mock" "github.com/onflow/flow-go/utils/grpcutils" "github.com/onflow/flow-go/utils/unittest" - accessproto "github.com/onflow/flow/protobuf/go/flow/access" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/status" ) type RateLimitTestSuite struct { From 9efd1316ceeda03efb216e46f4da0cba41ec817f Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Fri, 25 Aug 2023 11:14:18 +0100 Subject: [PATCH 63/66] Remove unused mock --- .../access/rpc/backend/mock/communicator.go | 43 ------------------- 1 file changed, 43 deletions(-) delete mode 100644 engine/access/rpc/backend/mock/communicator.go diff --git a/engine/access/rpc/backend/mock/communicator.go b/engine/access/rpc/backend/mock/communicator.go deleted file mode 100644 index 9989e30753b..00000000000 --- a/engine/access/rpc/backend/mock/communicator.go +++ /dev/null @@ -1,43 +0,0 @@ -// Code generated by mockery v2.21.4. DO NOT EDIT. - -package mock - -import ( - mock "github.com/stretchr/testify/mock" - - flow "github.com/onflow/flow-go/model/flow" -) - -// Communicator is an autogenerated mock type for the Communicator type -type Communicator struct { - mock.Mock -} - -// CallAvailableNode provides a mock function with given fields: nodes, call, shouldTerminateOnError -func (_m *Communicator) CallAvailableNode(nodes flow.IdentityList, call func(*flow.Identity) error, shouldTerminateOnError func(*flow.Identity, error) bool) error { - ret := _m.Called(nodes, call, shouldTerminateOnError) - - var r0 error - if rf, ok := ret.Get(0).(func(flow.IdentityList, func(*flow.Identity) error, func(*flow.Identity, error) bool) error); ok { - r0 = rf(nodes, call, shouldTerminateOnError) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -type mockConstructorTestingTNewCommunicator interface { - mock.TestingT - Cleanup(func()) -} - -// NewCommunicator creates a new instance of Communicator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewCommunicator(t mockConstructorTestingTNewCommunicator) *Communicator { - mock := &Communicator{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} From d6a71cd7bf1608f8b753cefebce2cb5787e57feb Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Fri, 25 Aug 2023 12:03:24 +0100 Subject: [PATCH 64/66] Fix compilation errors --- engine/access/rpc/backend/backend.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 30559fef6e3..5896f853d00 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -228,13 +228,13 @@ func NewCache( log zerolog.Logger, accessMetrics module.AccessMetrics, connectionPoolSize uint, -) (*lru2.Cache[flow.Identifier, *connection.CachedClient], uint, error) { +) (*lru2.Cache[string, *connection.CachedClient], uint, error) { - var cache *lru2.Cache[flow.Identifier, *connection.CachedClient] + var cache *lru2.Cache[string, *connection.CachedClient] cacheSize := connectionPoolSize if cacheSize > 0 { var err error - cache, err = lru2.NewWithEvict[flow.Identifier, *connection.CachedClient](int(cacheSize), func(_ flow.Identifier, store *connection.CachedClient) { + cache, err = lru2.NewWithEvict[string, *connection.CachedClient](int(cacheSize), func(_ string, store *connection.CachedClient) { store.Close() log.Debug().Str("grpc_conn_evicted", store.Address).Msg("closing grpc connection evicted from pool") if accessMetrics != nil { From eb1808a2f6c47fa022e7a97d6da629a1401c1903 Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Thu, 31 Aug 2023 12:36:00 +0100 Subject: [PATCH 65/66] Revert mock import changes --- module/executiondatasync/tracker/mock/storage.go | 3 +-- module/mempool/consensus/mock/exec_fork_actor.go | 3 +-- module/state_synchronization/mock/execution_data_requester.go | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/module/executiondatasync/tracker/mock/storage.go b/module/executiondatasync/tracker/mock/storage.go index e071a4ce67f..6eef7092ffd 100644 --- a/module/executiondatasync/tracker/mock/storage.go +++ b/module/executiondatasync/tracker/mock/storage.go @@ -3,9 +3,8 @@ package mocktracker import ( - mock "github.com/stretchr/testify/mock" - tracker "github.com/onflow/flow-go/module/executiondatasync/tracker" + mock "github.com/stretchr/testify/mock" ) // Storage is an autogenerated mock type for the Storage type diff --git a/module/mempool/consensus/mock/exec_fork_actor.go b/module/mempool/consensus/mock/exec_fork_actor.go index 3e92f3130e3..ae567dd9e7c 100644 --- a/module/mempool/consensus/mock/exec_fork_actor.go +++ b/module/mempool/consensus/mock/exec_fork_actor.go @@ -3,9 +3,8 @@ package mock import ( - mock "github.com/stretchr/testify/mock" - flow "github.com/onflow/flow-go/model/flow" + mock "github.com/stretchr/testify/mock" ) // ExecForkActorMock is an autogenerated mock type for the ExecForkActor type diff --git a/module/state_synchronization/mock/execution_data_requester.go b/module/state_synchronization/mock/execution_data_requester.go index 97e0fb6b593..2aee152ac57 100644 --- a/module/state_synchronization/mock/execution_data_requester.go +++ b/module/state_synchronization/mock/execution_data_requester.go @@ -3,9 +3,8 @@ package state_synchronization import ( - mock "github.com/stretchr/testify/mock" - irrecoverable "github.com/onflow/flow-go/module/irrecoverable" + mock "github.com/stretchr/testify/mock" model "github.com/onflow/flow-go/consensus/hotstuff/model" From 9a6979879cce833a39ddd48008abafb41eced3eb Mon Sep 17 00:00:00 2001 From: Nozim Mehrubonov Date: Fri, 1 Sep 2023 12:24:31 +0100 Subject: [PATCH 66/66] Add nosec annotation to import --- engine/access/rpc/backend/backend.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/access/rpc/backend/backend.go b/engine/access/rpc/backend/backend.go index 5896f853d00..8809dabd120 100644 --- a/engine/access/rpc/backend/backend.go +++ b/engine/access/rpc/backend/backend.go @@ -2,7 +2,7 @@ package backend import ( "context" - "crypto/md5" + "crypto/md5" //nolint:gosec "fmt" "net" "strconv"