From 9deed564ed8509c4326ac74b1dbcf62dbe1c01cc Mon Sep 17 00:00:00 2001 From: Peter Argue <89119817+peterargue@users.noreply.github.com> Date: Tue, 24 Oct 2023 20:50:45 -0700 Subject: [PATCH] Improve block handling in remote store --- Makefile | 3 +- adapters/access.go | 61 +++--- adapters/access_test.go | 14 +- adapters/sdk_test.go | 2 +- emulator/mocks/emulator.go | 56 +++--- go.mod | 1 + go.sum | 2 + internal/archive.go | 5 + internal/mocks/archive.go | 361 +++++++++++++++++++++++++++++++++++ server/server.go | 15 +- storage/mocks/store.go | 30 +-- storage/remote/store.go | 60 +++++- storage/remote/store_test.go | 238 ++++++++++++++++++++++- 13 files changed, 748 insertions(+), 100 deletions(-) create mode 100644 internal/archive.go create mode 100644 internal/mocks/archive.go diff --git a/Makefile b/Makefile index f1f2cf03..2ce2bc2c 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ GOPATH ?= $(HOME)/go install-tools: mkdir -p ${GOPATH}; \ cd ${GOPATH}; \ - GO111MODULE=on go install github.com/golang/mock/mockgen@v1.6.0; \ + GO111MODULE=on go install go.uber.org/mock/mockgen@v0.3.0; \ GO111MODULE=on go install github.com/axw/gocov/gocov@latest; \ GO111MODULE=on go install github.com/matm/gocov-html@latest; \ GO111MODULE=on go install github.com/sanderhahn/gozip/cmd/gozip@latest; @@ -46,6 +46,7 @@ generate: generate-mocks generate-mocks: GO111MODULE=on ${GOPATH}/bin/mockgen -destination=emulator/mocks/emulator.go -package=mocks github.com/onflow/flow-emulator/emulator Emulator GO111MODULE=on ${GOPATH}/bin/mockgen -destination=storage/mocks/store.go -package=mocks github.com/onflow/flow-emulator/storage Store + GO111MODULE=on ${GOPATH}/bin/mockgen -destination=internal/mocks/archive.go -package=mocks github.com/onflow/flow-emulator/internal ArchiveAPIClient .PHONY: ci ci: install-tools test check-tidy test coverage check-headers diff --git a/adapters/access.go b/adapters/access.go index 0767d95d..690db36f 100644 --- a/adapters/access.go +++ b/adapters/access.go @@ -21,12 +21,12 @@ package adapters import ( "context" "fmt" - "github.com/onflow/flow/protobuf/go/flow/entities" jsoncdc "github.com/onflow/cadence/encoding/json" "github.com/onflow/flow-emulator/emulator" "github.com/onflow/flow-emulator/types" "github.com/onflow/flow-emulator/utils" + "github.com/onflow/flow/protobuf/go/flow/entities" "github.com/rs/zerolog" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -36,7 +36,7 @@ import ( flowgo "github.com/onflow/flow-go/model/flow" ) -var _ access.API = &AccessAdapter{} +var _ access.API = (*AccessAdapter)(nil) // AccessAdapter wraps the emulator adapters to be compatible with access.API. type AccessAdapter struct { @@ -52,7 +52,7 @@ func NewAccessAdapter(logger *zerolog.Logger, emulator emulator.Emulator) *Acces } } -func convertError(err error) error { +func convertError(err error, defaultStatusCode codes.Code) error { if err != nil { switch err.(type) { case types.InvalidArgumentError: @@ -60,14 +60,14 @@ func convertError(err error) error { case types.NotFoundError: return status.Error(codes.NotFound, err.Error()) default: - return status.Error(codes.Internal, err.Error()) + return status.Error(defaultStatusCode, err.Error()) } } return nil } func (a *AccessAdapter) Ping(_ context.Context) error { - return convertError(a.emulator.Ping()) + return convertError(a.emulator.Ping(), codes.Internal) } func (a *AccessAdapter) GetNetworkParameters(_ context.Context) access.NetworkParameters { @@ -77,7 +77,7 @@ func (a *AccessAdapter) GetNetworkParameters(_ context.Context) access.NetworkPa func (a *AccessAdapter) GetLatestBlockHeader(_ context.Context, _ bool) (*flowgo.Header, flowgo.BlockStatus, error) { block, err := a.emulator.GetLatestBlock() if err != nil { - return nil, flowgo.BlockStatusUnknown, convertError(err) + return nil, flowgo.BlockStatusUnknown, convertError(err, codes.Internal) } a.logger.Debug().Fields(map[string]any{ @@ -91,7 +91,7 @@ func (a *AccessAdapter) GetLatestBlockHeader(_ context.Context, _ bool) (*flowgo func (a *AccessAdapter) GetBlockHeaderByHeight(_ context.Context, height uint64) (*flowgo.Header, flowgo.BlockStatus, error) { block, err := a.emulator.GetBlockByHeight(height) if err != nil { - return nil, flowgo.BlockStatusUnknown, convertError(err) + return nil, flowgo.BlockStatusUnknown, convertError(err, codes.Internal) } a.logger.Debug().Fields(map[string]any{ @@ -105,7 +105,7 @@ func (a *AccessAdapter) GetBlockHeaderByHeight(_ context.Context, height uint64) func (a *AccessAdapter) GetBlockHeaderByID(_ context.Context, id flowgo.Identifier) (*flowgo.Header, flowgo.BlockStatus, error) { block, err := a.emulator.GetBlockByID(id) if err != nil { - return nil, flowgo.BlockStatusUnknown, convertError(err) + return nil, flowgo.BlockStatusUnknown, convertError(err, codes.Internal) } a.logger.Debug().Fields(map[string]any{ @@ -119,7 +119,7 @@ func (a *AccessAdapter) GetBlockHeaderByID(_ context.Context, id flowgo.Identifi func (a *AccessAdapter) GetLatestBlock(_ context.Context, _ bool) (*flowgo.Block, flowgo.BlockStatus, error) { block, err := a.emulator.GetLatestBlock() if err != nil { - return nil, flowgo.BlockStatusUnknown, convertError(err) + return nil, flowgo.BlockStatusUnknown, convertError(err, codes.Internal) } a.logger.Debug().Fields(map[string]any{ @@ -133,7 +133,7 @@ func (a *AccessAdapter) GetLatestBlock(_ context.Context, _ bool) (*flowgo.Block func (a *AccessAdapter) GetBlockByHeight(_ context.Context, height uint64) (*flowgo.Block, flowgo.BlockStatus, error) { block, err := a.emulator.GetBlockByHeight(height) if err != nil { - return nil, flowgo.BlockStatusUnknown, convertError(err) + return nil, flowgo.BlockStatusUnknown, convertError(err, codes.Internal) } a.logger.Debug().Fields(map[string]any{ @@ -147,7 +147,7 @@ func (a *AccessAdapter) GetBlockByHeight(_ context.Context, height uint64) (*flo func (a *AccessAdapter) GetBlockByID(_ context.Context, id flowgo.Identifier) (*flowgo.Block, flowgo.BlockStatus, error) { block, err := a.emulator.GetBlockByID(id) if err != nil { - return nil, flowgo.BlockStatusUnknown, convertError(err) + return nil, flowgo.BlockStatusUnknown, convertError(err, codes.Internal) } a.logger.Debug().Fields(map[string]any{ @@ -161,7 +161,7 @@ func (a *AccessAdapter) GetBlockByID(_ context.Context, id flowgo.Identifier) (* func (a *AccessAdapter) GetCollectionByID(_ context.Context, id flowgo.Identifier) (*flowgo.LightCollection, error) { collection, err := a.emulator.GetCollectionByID(id) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } a.logger.Debug(). @@ -174,7 +174,7 @@ func (a *AccessAdapter) GetCollectionByID(_ context.Context, id flowgo.Identifie func (a *AccessAdapter) GetTransaction(_ context.Context, id flowgo.Identifier) (*flowgo.TransactionBody, error) { tx, err := a.emulator.GetTransaction(id) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } a.logger.Debug(). @@ -196,16 +196,17 @@ func (a *AccessAdapter) GetTransactionResult( ) { result, err := a.emulator.GetTransactionResult(id) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } // Convert CCF events to JSON events, else return CCF encoded version if requiredEventEncodingVersion == entities.EventEncodingVersion_JSON_CDC_V0 { result.Events, err = ConvertCCFEventsToJsonEvents(result.Events) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } } + a.logger.Debug(). Str("txID", id.String()). Msg("📝 GetTransactionResult called") @@ -216,7 +217,7 @@ func (a *AccessAdapter) GetTransactionResult( func (a *AccessAdapter) GetAccount(_ context.Context, address flowgo.Address) (*flowgo.Account, error) { account, err := a.emulator.GetAccount(address) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } a.logger.Debug(). @@ -229,7 +230,7 @@ func (a *AccessAdapter) GetAccount(_ context.Context, address flowgo.Address) (* func (a *AccessAdapter) GetAccountAtLatestBlock(ctx context.Context, address flowgo.Address) (*flowgo.Account, error) { account, err := a.GetAccount(ctx, address) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } a.logger.Debug(). @@ -252,14 +253,14 @@ func (a *AccessAdapter) GetAccountAtBlockHeight( account, err := a.emulator.GetAccountAtBlockHeight(address, height) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } return account, nil } func convertScriptResult(result *types.ScriptResult, err error) ([]byte, error) { if err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) + return nil, convertError(err, codes.InvalidArgument) } if !result.Succeeded() { @@ -331,7 +332,7 @@ func (a *AccessAdapter) GetEventsForHeightRange( ) ([]flowgo.BlockEvents, error) { events, err := a.emulator.GetEventsForHeightRange(eventType, startHeight, endHeight) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } eventCount := 0 @@ -342,7 +343,7 @@ func (a *AccessAdapter) GetEventsForHeightRange( events[i].Events, err = ConvertCCFEventsToJsonEvents(events[i].Events) eventCount = eventCount + len(events[i].Events) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } } } @@ -365,7 +366,7 @@ func (a *AccessAdapter) GetEventsForBlockIDs( ) ([]flowgo.BlockEvents, error) { events, err := a.emulator.GetEventsForBlockIDs(eventType, blockIDs) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } eventCount := 0 @@ -376,7 +377,7 @@ func (a *AccessAdapter) GetEventsForBlockIDs( events[i].Events, err = ConvertCCFEventsToJsonEvents(events[i].Events) eventCount = eventCount + len(events[i].Events) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } } } @@ -409,10 +410,10 @@ func (a *AccessAdapter) GetTransactionResultByIndex( ) (*access.TransactionResult, error) { results, err := a.emulator.GetTransactionResultsByBlockID(blockID) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } if len(results) <= int(index) { - return nil, convertError(&types.TransactionNotFoundError{ID: flowgo.Identifier{}}) + return nil, convertError(&types.TransactionNotFoundError{ID: flowgo.Identifier{}}, codes.Internal) } // Convert CCF events to JSON events, else return CCF encoded version @@ -420,7 +421,7 @@ func (a *AccessAdapter) GetTransactionResultByIndex( for i := range results { results[i].Events, err = ConvertCCFEventsToJsonEvents(results[i].Events) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } } } @@ -431,7 +432,7 @@ func (a *AccessAdapter) GetTransactionResultByIndex( func (a *AccessAdapter) GetTransactionsByBlockID(_ context.Context, blockID flowgo.Identifier) ([]*flowgo.TransactionBody, error) { result, err := a.emulator.GetTransactionsByBlockID(blockID) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } return result, nil } @@ -443,7 +444,7 @@ func (a *AccessAdapter) GetTransactionResultsByBlockID( ) ([]*access.TransactionResult, error) { result, err := a.emulator.GetTransactionResultsByBlockID(blockID) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } // Convert CCF events to JSON events, else return CCF encoded version @@ -451,7 +452,7 @@ func (a *AccessAdapter) GetTransactionResultsByBlockID( for i := range result { result[i].Events, err = ConvertCCFEventsToJsonEvents(result[i].Events) if err != nil { - return nil, convertError(err) + return nil, convertError(err, codes.Internal) } } } @@ -464,7 +465,7 @@ func (a *AccessAdapter) SendTransaction(_ context.Context, tx *flowgo.Transactio Str("txID", tx.ID().String()). Msg(`✉️ Transaction submitted`) - return convertError(a.emulator.SendTransaction(tx)) + return convertError(a.emulator.SendTransaction(tx), codes.Internal) } func (a *AccessAdapter) GetNodeVersionInfo( diff --git a/adapters/access_test.go b/adapters/access_test.go index efcaf86d..ff8e3c60 100644 --- a/adapters/access_test.go +++ b/adapters/access_test.go @@ -23,20 +23,20 @@ import ( "fmt" "testing" - "github.com/onflow/flow/protobuf/go/flow/entities" - + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" - "github.com/golang/mock/gomock" "github.com/onflow/cadence" "github.com/onflow/cadence/encoding/ccf" - "github.com/onflow/flow-emulator/emulator/mocks" - "github.com/onflow/flow-emulator/types" "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/common/rpc/convert" flowgo "github.com/onflow/flow-go/model/flow" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" + "github.com/onflow/flow/protobuf/go/flow/entities" + + "github.com/onflow/flow-emulator/emulator/mocks" + "github.com/onflow/flow-emulator/types" ) func accessTest(f func(t *testing.T, adapter *AccessAdapter, emu *mocks.MockEmulator)) func(t *testing.T) { diff --git a/adapters/sdk_test.go b/adapters/sdk_test.go index 7a12e459..451a0fc5 100644 --- a/adapters/sdk_test.go +++ b/adapters/sdk_test.go @@ -23,7 +23,6 @@ import ( "fmt" "testing" - "github.com/golang/mock/gomock" "github.com/onflow/cadence" "github.com/onflow/flow-emulator/convert" "github.com/onflow/flow-emulator/emulator/mocks" @@ -33,6 +32,7 @@ import ( flowgo "github.com/onflow/flow-go/model/flow" "github.com/rs/zerolog" "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" ) func sdkTest(f func(t *testing.T, adapter *SDKAdapter, emu *mocks.MockEmulator)) func(t *testing.T) { diff --git a/emulator/mocks/emulator.go b/emulator/mocks/emulator.go index eb0baff7..2c65d8e6 100644 --- a/emulator/mocks/emulator.go +++ b/emulator/mocks/emulator.go @@ -1,13 +1,16 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/onflow/flow-emulator/emulator (interfaces: Emulator) - +// +// Generated by this command: +// +// mockgen -destination=emulator/mocks/emulator.go -package=mocks github.com/onflow/flow-emulator/emulator Emulator +// // Package mocks is a generated GoMock package. package mocks import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" runtime "github.com/onflow/cadence/runtime" common "github.com/onflow/cadence/runtime/common" interpreter "github.com/onflow/cadence/runtime/interpreter" @@ -15,6 +18,7 @@ import ( types "github.com/onflow/flow-emulator/types" access "github.com/onflow/flow-go/access" flow "github.com/onflow/flow-go/model/flow" + gomock "go.uber.org/mock/gomock" ) // MockEmulator is a mock of Emulator interface. @@ -49,7 +53,7 @@ func (m *MockEmulator) AddTransaction(arg0 flow.TransactionBody) error { } // AddTransaction indicates an expected call of AddTransaction. -func (mr *MockEmulatorMockRecorder) AddTransaction(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) AddTransaction(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddTransaction", reflect.TypeOf((*MockEmulator)(nil).AddTransaction), arg0) } @@ -92,7 +96,7 @@ func (m *MockEmulator) CreateSnapshot(arg0 string) error { } // CreateSnapshot indicates an expected call of CreateSnapshot. -func (mr *MockEmulatorMockRecorder) CreateSnapshot(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) CreateSnapshot(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSnapshot", reflect.TypeOf((*MockEmulator)(nil).CreateSnapshot), arg0) } @@ -189,7 +193,7 @@ func (m *MockEmulator) ExecuteScript(arg0 []byte, arg1 [][]byte) (*types.ScriptR } // ExecuteScript indicates an expected call of ExecuteScript. -func (mr *MockEmulatorMockRecorder) ExecuteScript(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) ExecuteScript(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteScript", reflect.TypeOf((*MockEmulator)(nil).ExecuteScript), arg0, arg1) } @@ -204,7 +208,7 @@ func (m *MockEmulator) ExecuteScriptAtBlockHeight(arg0 []byte, arg1 [][]byte, ar } // ExecuteScriptAtBlockHeight indicates an expected call of ExecuteScriptAtBlockHeight. -func (mr *MockEmulatorMockRecorder) ExecuteScriptAtBlockHeight(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) ExecuteScriptAtBlockHeight(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteScriptAtBlockHeight", reflect.TypeOf((*MockEmulator)(nil).ExecuteScriptAtBlockHeight), arg0, arg1, arg2) } @@ -219,7 +223,7 @@ func (m *MockEmulator) ExecuteScriptAtBlockID(arg0 []byte, arg1 [][]byte, arg2 f } // ExecuteScriptAtBlockID indicates an expected call of ExecuteScriptAtBlockID. -func (mr *MockEmulatorMockRecorder) ExecuteScriptAtBlockID(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) ExecuteScriptAtBlockID(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteScriptAtBlockID", reflect.TypeOf((*MockEmulator)(nil).ExecuteScriptAtBlockID), arg0, arg1, arg2) } @@ -234,7 +238,7 @@ func (m *MockEmulator) GetAccount(arg0 flow.Address) (*flow.Account, error) { } // GetAccount indicates an expected call of GetAccount. -func (mr *MockEmulatorMockRecorder) GetAccount(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetAccount(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccount", reflect.TypeOf((*MockEmulator)(nil).GetAccount), arg0) } @@ -249,7 +253,7 @@ func (m *MockEmulator) GetAccountAtBlockHeight(arg0 flow.Address, arg1 uint64) ( } // GetAccountAtBlockHeight indicates an expected call of GetAccountAtBlockHeight. -func (mr *MockEmulatorMockRecorder) GetAccountAtBlockHeight(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetAccountAtBlockHeight(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccountAtBlockHeight", reflect.TypeOf((*MockEmulator)(nil).GetAccountAtBlockHeight), arg0, arg1) } @@ -264,7 +268,7 @@ func (m *MockEmulator) GetAccountByIndex(arg0 uint) (*flow.Account, error) { } // GetAccountByIndex indicates an expected call of GetAccountByIndex. -func (mr *MockEmulatorMockRecorder) GetAccountByIndex(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetAccountByIndex(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccountByIndex", reflect.TypeOf((*MockEmulator)(nil).GetAccountByIndex), arg0) } @@ -279,7 +283,7 @@ func (m *MockEmulator) GetAccountUnsafe(arg0 flow.Address) (*flow.Account, error } // GetAccountUnsafe indicates an expected call of GetAccountUnsafe. -func (mr *MockEmulatorMockRecorder) GetAccountUnsafe(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetAccountUnsafe(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccountUnsafe", reflect.TypeOf((*MockEmulator)(nil).GetAccountUnsafe), arg0) } @@ -294,7 +298,7 @@ func (m *MockEmulator) GetBlockByHeight(arg0 uint64) (*flow.Block, error) { } // GetBlockByHeight indicates an expected call of GetBlockByHeight. -func (mr *MockEmulatorMockRecorder) GetBlockByHeight(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetBlockByHeight(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockByHeight", reflect.TypeOf((*MockEmulator)(nil).GetBlockByHeight), arg0) } @@ -309,7 +313,7 @@ func (m *MockEmulator) GetBlockByID(arg0 flow.Identifier) (*flow.Block, error) { } // GetBlockByID indicates an expected call of GetBlockByID. -func (mr *MockEmulatorMockRecorder) GetBlockByID(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetBlockByID(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockByID", reflect.TypeOf((*MockEmulator)(nil).GetBlockByID), arg0) } @@ -324,7 +328,7 @@ func (m *MockEmulator) GetCollectionByID(arg0 flow.Identifier) (*flow.LightColle } // GetCollectionByID indicates an expected call of GetCollectionByID. -func (mr *MockEmulatorMockRecorder) GetCollectionByID(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetCollectionByID(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCollectionByID", reflect.TypeOf((*MockEmulator)(nil).GetCollectionByID), arg0) } @@ -339,7 +343,7 @@ func (m *MockEmulator) GetEventsByHeight(arg0 uint64, arg1 string) ([]flow.Event } // GetEventsByHeight indicates an expected call of GetEventsByHeight. -func (mr *MockEmulatorMockRecorder) GetEventsByHeight(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetEventsByHeight(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEventsByHeight", reflect.TypeOf((*MockEmulator)(nil).GetEventsByHeight), arg0, arg1) } @@ -354,7 +358,7 @@ func (m *MockEmulator) GetEventsForBlockIDs(arg0 string, arg1 []flow.Identifier) } // GetEventsForBlockIDs indicates an expected call of GetEventsForBlockIDs. -func (mr *MockEmulatorMockRecorder) GetEventsForBlockIDs(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetEventsForBlockIDs(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEventsForBlockIDs", reflect.TypeOf((*MockEmulator)(nil).GetEventsForBlockIDs), arg0, arg1) } @@ -369,7 +373,7 @@ func (m *MockEmulator) GetEventsForHeightRange(arg0 string, arg1, arg2 uint64) ( } // GetEventsForHeightRange indicates an expected call of GetEventsForHeightRange. -func (mr *MockEmulatorMockRecorder) GetEventsForHeightRange(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetEventsForHeightRange(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEventsForHeightRange", reflect.TypeOf((*MockEmulator)(nil).GetEventsForHeightRange), arg0, arg1, arg2) } @@ -399,7 +403,7 @@ func (m *MockEmulator) GetLogs(arg0 flow.Identifier) ([]string, error) { } // GetLogs indicates an expected call of GetLogs. -func (mr *MockEmulatorMockRecorder) GetLogs(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetLogs(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogs", reflect.TypeOf((*MockEmulator)(nil).GetLogs), arg0) } @@ -427,7 +431,7 @@ func (m *MockEmulator) GetSourceFile(arg0 common.Location) string { } // GetSourceFile indicates an expected call of GetSourceFile. -func (mr *MockEmulatorMockRecorder) GetSourceFile(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetSourceFile(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSourceFile", reflect.TypeOf((*MockEmulator)(nil).GetSourceFile), arg0) } @@ -442,7 +446,7 @@ func (m *MockEmulator) GetTransaction(arg0 flow.Identifier) (*flow.TransactionBo } // GetTransaction indicates an expected call of GetTransaction. -func (mr *MockEmulatorMockRecorder) GetTransaction(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetTransaction(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransaction", reflect.TypeOf((*MockEmulator)(nil).GetTransaction), arg0) } @@ -457,7 +461,7 @@ func (m *MockEmulator) GetTransactionResult(arg0 flow.Identifier) (*access.Trans } // GetTransactionResult indicates an expected call of GetTransactionResult. -func (mr *MockEmulatorMockRecorder) GetTransactionResult(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetTransactionResult(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransactionResult", reflect.TypeOf((*MockEmulator)(nil).GetTransactionResult), arg0) } @@ -472,7 +476,7 @@ func (m *MockEmulator) GetTransactionResultsByBlockID(arg0 flow.Identifier) ([]* } // GetTransactionResultsByBlockID indicates an expected call of GetTransactionResultsByBlockID. -func (mr *MockEmulatorMockRecorder) GetTransactionResultsByBlockID(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetTransactionResultsByBlockID(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransactionResultsByBlockID", reflect.TypeOf((*MockEmulator)(nil).GetTransactionResultsByBlockID), arg0) } @@ -487,7 +491,7 @@ func (m *MockEmulator) GetTransactionsByBlockID(arg0 flow.Identifier) ([]*flow.T } // GetTransactionsByBlockID indicates an expected call of GetTransactionsByBlockID. -func (mr *MockEmulatorMockRecorder) GetTransactionsByBlockID(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) GetTransactionsByBlockID(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransactionsByBlockID", reflect.TypeOf((*MockEmulator)(nil).GetTransactionsByBlockID), arg0) } @@ -501,7 +505,7 @@ func (m *MockEmulator) LoadSnapshot(arg0 string) error { } // LoadSnapshot indicates an expected call of LoadSnapshot. -func (mr *MockEmulatorMockRecorder) LoadSnapshot(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) LoadSnapshot(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadSnapshot", reflect.TypeOf((*MockEmulator)(nil).LoadSnapshot), arg0) } @@ -541,7 +545,7 @@ func (m *MockEmulator) RollbackToBlockHeight(arg0 uint64) error { } // RollbackToBlockHeight indicates an expected call of RollbackToBlockHeight. -func (mr *MockEmulatorMockRecorder) RollbackToBlockHeight(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) RollbackToBlockHeight(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackToBlockHeight", reflect.TypeOf((*MockEmulator)(nil).RollbackToBlockHeight), arg0) } @@ -555,7 +559,7 @@ func (m *MockEmulator) SendTransaction(arg0 *flow.TransactionBody) error { } // SendTransaction indicates an expected call of SendTransaction. -func (mr *MockEmulatorMockRecorder) SendTransaction(arg0 interface{}) *gomock.Call { +func (mr *MockEmulatorMockRecorder) SendTransaction(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTransaction", reflect.TypeOf((*MockEmulator)(nil).SendTransaction), arg0) } diff --git a/go.mod b/go.mod index 1ac310b9..ab0a1ef3 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/rs/zerolog v1.29.0 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 + go.uber.org/mock v0.3.0 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 google.golang.org/grpc v1.58.3 ) diff --git a/go.sum b/go.sum index db1ef62d..9750a93e 100644 --- a/go.sum +++ b/go.sum @@ -1113,6 +1113,8 @@ go.uber.org/fx v1.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= +go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= diff --git a/internal/archive.go b/internal/archive.go new file mode 100644 index 00000000..32789c3f --- /dev/null +++ b/internal/archive.go @@ -0,0 +1,5 @@ +package internal + +import "github.com/onflow/flow-archive/api/archive" + +type ArchiveAPIClient archive.APIClient diff --git a/internal/mocks/archive.go b/internal/mocks/archive.go new file mode 100644 index 00000000..9888d286 --- /dev/null +++ b/internal/mocks/archive.go @@ -0,0 +1,361 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/onflow/flow-emulator/internal (interfaces: ArchiveAPIClient) +// +// Generated by this command: +// +// mockgen -destination=internal/mocks/archive.go -package=mocks github.com/onflow/flow-emulator/internal ArchiveAPIClient +// +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + archive "github.com/onflow/flow-archive/api/archive" + gomock "go.uber.org/mock/gomock" + grpc "google.golang.org/grpc" +) + +// MockArchiveAPIClient is a mock of ArchiveAPIClient interface. +type MockArchiveAPIClient struct { + ctrl *gomock.Controller + recorder *MockArchiveAPIClientMockRecorder +} + +// MockArchiveAPIClientMockRecorder is the mock recorder for MockArchiveAPIClient. +type MockArchiveAPIClientMockRecorder struct { + mock *MockArchiveAPIClient +} + +// NewMockArchiveAPIClient creates a new mock instance. +func NewMockArchiveAPIClient(ctrl *gomock.Controller) *MockArchiveAPIClient { + mock := &MockArchiveAPIClient{ctrl: ctrl} + mock.recorder = &MockArchiveAPIClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockArchiveAPIClient) EXPECT() *MockArchiveAPIClientMockRecorder { + return m.recorder +} + +// GetCollection mocks base method. +func (m *MockArchiveAPIClient) GetCollection(arg0 context.Context, arg1 *archive.GetCollectionRequest, arg2 ...grpc.CallOption) (*archive.GetCollectionResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetCollection", varargs...) + ret0, _ := ret[0].(*archive.GetCollectionResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCollection indicates an expected call of GetCollection. +func (mr *MockArchiveAPIClientMockRecorder) GetCollection(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCollection", reflect.TypeOf((*MockArchiveAPIClient)(nil).GetCollection), varargs...) +} + +// GetCommit mocks base method. +func (m *MockArchiveAPIClient) GetCommit(arg0 context.Context, arg1 *archive.GetCommitRequest, arg2 ...grpc.CallOption) (*archive.GetCommitResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetCommit", varargs...) + ret0, _ := ret[0].(*archive.GetCommitResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCommit indicates an expected call of GetCommit. +func (mr *MockArchiveAPIClientMockRecorder) GetCommit(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCommit", reflect.TypeOf((*MockArchiveAPIClient)(nil).GetCommit), varargs...) +} + +// GetEvents mocks base method. +func (m *MockArchiveAPIClient) GetEvents(arg0 context.Context, arg1 *archive.GetEventsRequest, arg2 ...grpc.CallOption) (*archive.GetEventsResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetEvents", varargs...) + ret0, _ := ret[0].(*archive.GetEventsResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetEvents indicates an expected call of GetEvents. +func (mr *MockArchiveAPIClientMockRecorder) GetEvents(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEvents", reflect.TypeOf((*MockArchiveAPIClient)(nil).GetEvents), varargs...) +} + +// GetFirst mocks base method. +func (m *MockArchiveAPIClient) GetFirst(arg0 context.Context, arg1 *archive.GetFirstRequest, arg2 ...grpc.CallOption) (*archive.GetFirstResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetFirst", varargs...) + ret0, _ := ret[0].(*archive.GetFirstResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetFirst indicates an expected call of GetFirst. +func (mr *MockArchiveAPIClientMockRecorder) GetFirst(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFirst", reflect.TypeOf((*MockArchiveAPIClient)(nil).GetFirst), varargs...) +} + +// GetGuarantee mocks base method. +func (m *MockArchiveAPIClient) GetGuarantee(arg0 context.Context, arg1 *archive.GetGuaranteeRequest, arg2 ...grpc.CallOption) (*archive.GetGuaranteeResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetGuarantee", varargs...) + ret0, _ := ret[0].(*archive.GetGuaranteeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetGuarantee indicates an expected call of GetGuarantee. +func (mr *MockArchiveAPIClientMockRecorder) GetGuarantee(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGuarantee", reflect.TypeOf((*MockArchiveAPIClient)(nil).GetGuarantee), varargs...) +} + +// GetHeader mocks base method. +func (m *MockArchiveAPIClient) GetHeader(arg0 context.Context, arg1 *archive.GetHeaderRequest, arg2 ...grpc.CallOption) (*archive.GetHeaderResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetHeader", varargs...) + ret0, _ := ret[0].(*archive.GetHeaderResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetHeader indicates an expected call of GetHeader. +func (mr *MockArchiveAPIClientMockRecorder) GetHeader(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHeader", reflect.TypeOf((*MockArchiveAPIClient)(nil).GetHeader), varargs...) +} + +// GetHeightForBlock mocks base method. +func (m *MockArchiveAPIClient) GetHeightForBlock(arg0 context.Context, arg1 *archive.GetHeightForBlockRequest, arg2 ...grpc.CallOption) (*archive.GetHeightForBlockResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetHeightForBlock", varargs...) + ret0, _ := ret[0].(*archive.GetHeightForBlockResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetHeightForBlock indicates an expected call of GetHeightForBlock. +func (mr *MockArchiveAPIClientMockRecorder) GetHeightForBlock(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHeightForBlock", reflect.TypeOf((*MockArchiveAPIClient)(nil).GetHeightForBlock), varargs...) +} + +// GetHeightForTransaction mocks base method. +func (m *MockArchiveAPIClient) GetHeightForTransaction(arg0 context.Context, arg1 *archive.GetHeightForTransactionRequest, arg2 ...grpc.CallOption) (*archive.GetHeightForTransactionResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetHeightForTransaction", varargs...) + ret0, _ := ret[0].(*archive.GetHeightForTransactionResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetHeightForTransaction indicates an expected call of GetHeightForTransaction. +func (mr *MockArchiveAPIClientMockRecorder) GetHeightForTransaction(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHeightForTransaction", reflect.TypeOf((*MockArchiveAPIClient)(nil).GetHeightForTransaction), varargs...) +} + +// GetLast mocks base method. +func (m *MockArchiveAPIClient) GetLast(arg0 context.Context, arg1 *archive.GetLastRequest, arg2 ...grpc.CallOption) (*archive.GetLastResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetLast", varargs...) + ret0, _ := ret[0].(*archive.GetLastResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLast indicates an expected call of GetLast. +func (mr *MockArchiveAPIClientMockRecorder) GetLast(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLast", reflect.TypeOf((*MockArchiveAPIClient)(nil).GetLast), varargs...) +} + +// GetRegisterValues mocks base method. +func (m *MockArchiveAPIClient) GetRegisterValues(arg0 context.Context, arg1 *archive.GetRegisterValuesRequest, arg2 ...grpc.CallOption) (*archive.GetRegisterValuesResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetRegisterValues", varargs...) + ret0, _ := ret[0].(*archive.GetRegisterValuesResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetRegisterValues indicates an expected call of GetRegisterValues. +func (mr *MockArchiveAPIClientMockRecorder) GetRegisterValues(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRegisterValues", reflect.TypeOf((*MockArchiveAPIClient)(nil).GetRegisterValues), varargs...) +} + +// GetResult mocks base method. +func (m *MockArchiveAPIClient) GetResult(arg0 context.Context, arg1 *archive.GetResultRequest, arg2 ...grpc.CallOption) (*archive.GetResultResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetResult", varargs...) + ret0, _ := ret[0].(*archive.GetResultResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetResult indicates an expected call of GetResult. +func (mr *MockArchiveAPIClientMockRecorder) GetResult(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResult", reflect.TypeOf((*MockArchiveAPIClient)(nil).GetResult), varargs...) +} + +// GetSeal mocks base method. +func (m *MockArchiveAPIClient) GetSeal(arg0 context.Context, arg1 *archive.GetSealRequest, arg2 ...grpc.CallOption) (*archive.GetSealResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetSeal", varargs...) + ret0, _ := ret[0].(*archive.GetSealResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetSeal indicates an expected call of GetSeal. +func (mr *MockArchiveAPIClientMockRecorder) GetSeal(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSeal", reflect.TypeOf((*MockArchiveAPIClient)(nil).GetSeal), varargs...) +} + +// GetTransaction mocks base method. +func (m *MockArchiveAPIClient) GetTransaction(arg0 context.Context, arg1 *archive.GetTransactionRequest, arg2 ...grpc.CallOption) (*archive.GetTransactionResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetTransaction", varargs...) + ret0, _ := ret[0].(*archive.GetTransactionResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTransaction indicates an expected call of GetTransaction. +func (mr *MockArchiveAPIClientMockRecorder) GetTransaction(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransaction", reflect.TypeOf((*MockArchiveAPIClient)(nil).GetTransaction), varargs...) +} + +// ListCollectionsForHeight mocks base method. +func (m *MockArchiveAPIClient) ListCollectionsForHeight(arg0 context.Context, arg1 *archive.ListCollectionsForHeightRequest, arg2 ...grpc.CallOption) (*archive.ListCollectionsForHeightResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListCollectionsForHeight", varargs...) + ret0, _ := ret[0].(*archive.ListCollectionsForHeightResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListCollectionsForHeight indicates an expected call of ListCollectionsForHeight. +func (mr *MockArchiveAPIClientMockRecorder) ListCollectionsForHeight(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListCollectionsForHeight", reflect.TypeOf((*MockArchiveAPIClient)(nil).ListCollectionsForHeight), varargs...) +} + +// ListSealsForHeight mocks base method. +func (m *MockArchiveAPIClient) ListSealsForHeight(arg0 context.Context, arg1 *archive.ListSealsForHeightRequest, arg2 ...grpc.CallOption) (*archive.ListSealsForHeightResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListSealsForHeight", varargs...) + ret0, _ := ret[0].(*archive.ListSealsForHeightResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListSealsForHeight indicates an expected call of ListSealsForHeight. +func (mr *MockArchiveAPIClientMockRecorder) ListSealsForHeight(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSealsForHeight", reflect.TypeOf((*MockArchiveAPIClient)(nil).ListSealsForHeight), varargs...) +} + +// ListTransactionsForHeight mocks base method. +func (m *MockArchiveAPIClient) ListTransactionsForHeight(arg0 context.Context, arg1 *archive.ListTransactionsForHeightRequest, arg2 ...grpc.CallOption) (*archive.ListTransactionsForHeightResponse, error) { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListTransactionsForHeight", varargs...) + ret0, _ := ret[0].(*archive.ListTransactionsForHeightResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListTransactionsForHeight indicates an expected call of ListTransactionsForHeight. +func (mr *MockArchiveAPIClientMockRecorder) ListTransactionsForHeight(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListTransactionsForHeight", reflect.TypeOf((*MockArchiveAPIClient)(nil).ListTransactionsForHeight), varargs...) +} diff --git a/server/server.go b/server/server.go index b13c8e66..aaf5e7b3 100644 --- a/server/server.go +++ b/server/server.go @@ -352,18 +352,17 @@ func configureStorage(conf *Config) (storageProvider storage.Store, err error) { return nil, fmt.Errorf("only sqlite is supported with forked networks") } - provider, err := remote.New(baseProvider, remote.WithChainID(conf.ChainID)) - if err != nil { - return nil, err + opts := []remote.Option{ + remote.WithChainID(conf.ChainID), } - if conf.StartBlockHeight > 0 { - err = provider.SetBlockHeight(conf.StartBlockHeight) - if err != nil { - return nil, err - } + opts = append(opts, remote.WithStartBlockHeight(conf.StartBlockHeight)) } + provider, err := remote.New(baseProvider, opts...) + if err != nil { + return nil, err + } storageProvider = provider } diff --git a/storage/mocks/store.go b/storage/mocks/store.go index 4b9b5b5a..d91199ed 100644 --- a/storage/mocks/store.go +++ b/storage/mocks/store.go @@ -1,6 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/onflow/flow-emulator/storage (interfaces: Store) - +// +// Generated by this command: +// +// mockgen -destination=storage/mocks/store.go -package=mocks github.com/onflow/flow-emulator/storage Store +// // Package mocks is a generated GoMock package. package mocks @@ -8,10 +12,10 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" types "github.com/onflow/flow-emulator/types" snapshot "github.com/onflow/flow-go/fvm/storage/snapshot" flow "github.com/onflow/flow-go/model/flow" + gomock "go.uber.org/mock/gomock" ) // MockStore is a mock of Store interface. @@ -47,7 +51,7 @@ func (m *MockStore) BlockByHeight(arg0 context.Context, arg1 uint64) (*flow.Bloc } // BlockByHeight indicates an expected call of BlockByHeight. -func (mr *MockStoreMockRecorder) BlockByHeight(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) BlockByHeight(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHeight", reflect.TypeOf((*MockStore)(nil).BlockByHeight), arg0, arg1) } @@ -62,7 +66,7 @@ func (m *MockStore) BlockByID(arg0 context.Context, arg1 flow.Identifier) (*flow } // BlockByID indicates an expected call of BlockByID. -func (mr *MockStoreMockRecorder) BlockByID(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) BlockByID(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByID", reflect.TypeOf((*MockStore)(nil).BlockByID), arg0, arg1) } @@ -77,7 +81,7 @@ func (m *MockStore) CollectionByID(arg0 context.Context, arg1 flow.Identifier) ( } // CollectionByID indicates an expected call of CollectionByID. -func (mr *MockStoreMockRecorder) CollectionByID(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) CollectionByID(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CollectionByID", reflect.TypeOf((*MockStore)(nil).CollectionByID), arg0, arg1) } @@ -91,7 +95,7 @@ func (m *MockStore) CommitBlock(arg0 context.Context, arg1 flow.Block, arg2 []*f } // CommitBlock indicates an expected call of CommitBlock. -func (mr *MockStoreMockRecorder) CommitBlock(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) CommitBlock(arg0, arg1, arg2, arg3, arg4, arg5, arg6 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitBlock", reflect.TypeOf((*MockStore)(nil).CommitBlock), arg0, arg1, arg2, arg3, arg4, arg5, arg6) } @@ -106,7 +110,7 @@ func (m *MockStore) EventsByHeight(arg0 context.Context, arg1 uint64, arg2 strin } // EventsByHeight indicates an expected call of EventsByHeight. -func (mr *MockStoreMockRecorder) EventsByHeight(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) EventsByHeight(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EventsByHeight", reflect.TypeOf((*MockStore)(nil).EventsByHeight), arg0, arg1, arg2) } @@ -121,7 +125,7 @@ func (m *MockStore) LatestBlock(arg0 context.Context) (flow.Block, error) { } // LatestBlock indicates an expected call of LatestBlock. -func (mr *MockStoreMockRecorder) LatestBlock(arg0 interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) LatestBlock(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LatestBlock", reflect.TypeOf((*MockStore)(nil).LatestBlock), arg0) } @@ -136,7 +140,7 @@ func (m *MockStore) LatestBlockHeight(arg0 context.Context) (uint64, error) { } // LatestBlockHeight indicates an expected call of LatestBlockHeight. -func (mr *MockStoreMockRecorder) LatestBlockHeight(arg0 interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) LatestBlockHeight(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LatestBlockHeight", reflect.TypeOf((*MockStore)(nil).LatestBlockHeight), arg0) } @@ -151,7 +155,7 @@ func (m *MockStore) LedgerByHeight(arg0 context.Context, arg1 uint64) (snapshot. } // LedgerByHeight indicates an expected call of LedgerByHeight. -func (mr *MockStoreMockRecorder) LedgerByHeight(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) LedgerByHeight(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LedgerByHeight", reflect.TypeOf((*MockStore)(nil).LedgerByHeight), arg0, arg1) } @@ -191,7 +195,7 @@ func (m *MockStore) StoreBlock(arg0 context.Context, arg1 *flow.Block) error { } // StoreBlock indicates an expected call of StoreBlock. -func (mr *MockStoreMockRecorder) StoreBlock(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) StoreBlock(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreBlock", reflect.TypeOf((*MockStore)(nil).StoreBlock), arg0, arg1) } @@ -206,7 +210,7 @@ func (m *MockStore) TransactionByID(arg0 context.Context, arg1 flow.Identifier) } // TransactionByID indicates an expected call of TransactionByID. -func (mr *MockStoreMockRecorder) TransactionByID(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) TransactionByID(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByID", reflect.TypeOf((*MockStore)(nil).TransactionByID), arg0, arg1) } @@ -221,7 +225,7 @@ func (m *MockStore) TransactionResultByID(arg0 context.Context, arg1 flow.Identi } // TransactionResultByID indicates an expected call of TransactionResultByID. -func (mr *MockStoreMockRecorder) TransactionResultByID(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) TransactionResultByID(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionResultByID", reflect.TypeOf((*MockStore)(nil).TransactionResultByID), arg0, arg1) } diff --git a/storage/remote/store.go b/storage/remote/store.go index faae4c06..44e4842c 100644 --- a/storage/remote/store.go +++ b/storage/remote/store.go @@ -21,6 +21,8 @@ package remote import ( "context" "fmt" + "log" + "github.com/onflow/flow-archive/api/archive" "github.com/onflow/flow-archive/codec/zbor" "github.com/onflow/flow-go/fvm/errors" @@ -34,13 +36,15 @@ import ( "github.com/onflow/flow-emulator/storage" "github.com/onflow/flow-emulator/storage/sqlite" + "github.com/onflow/flow-emulator/types" ) type Store struct { *sqlite.Store - client archive.APIClient - grpcConn *grpc.ClientConn - host string + client archive.APIClient + grpcConn *grpc.ClientConn + host string + startBlockHeight uint64 } type Option func(*Store) @@ -73,6 +77,13 @@ func WithClient(client archive.APIClient) Option { } } +// WithStartBlockHeight sets the start height for the store. +func WithStartBlockHeight(height uint64) Option { + return func(store *Store) { + store.startBlockHeight = height + } +} + func New(provider *sqlite.Store, options ...Option) (*Store, error) { store := &Store{ Store: provider, @@ -99,6 +110,10 @@ func New(provider *sqlite.Store, options ...Option) (*Store, error) { store.client = archive.NewAPIClient(conn) } + if err := store.initializeStartBlock(context.Background()); err != nil { + return nil, err + } + store.DataGetter = store store.DataSetter = store store.KeyGenerator = &storage.DefaultKeyGenerator{} @@ -106,6 +121,35 @@ func New(provider *sqlite.Store, options ...Option) (*Store, error) { return store, nil } +func (s *Store) initializeStartBlock(ctx context.Context) error { + if s.startBlockHeight > 0 { + // the start height may already be set in the db if restarting from persistent store + // only set the start block height if it's not already set + _, err := s.Store.LatestBlockHeight(ctx) + if errors.Is(err, storage.ErrNotFound) { + err = s.Store.SetBlockHeight(s.startBlockHeight) + if err != nil { + return fmt.Errorf("could not set start block height: %w", err) + } + } else if err != nil { + return fmt.Errorf("error getting latest block height: %w", err) + } + return nil + } + + // otherwise, get the latest block from the archive node + resp, err := s.client.GetLast(ctx, &archive.GetLastRequest{}) + if err != nil { + return fmt.Errorf("could not get last block height: %w", err) + } + err = s.Store.SetBlockHeight(resp.Height) + if err != nil { + return fmt.Errorf("could not set start block height: %w", err) + } + + return nil +} + func (s *Store) BlockByID(ctx context.Context, blockID flowgo.Identifier) (*flowgo.Block, error) { var height uint64 block, err := s.DefaultStore.BlockByID(ctx, blockID) @@ -154,6 +198,10 @@ func (s *Store) BlockByHeight(ctx context.Context, height uint64) (*flowgo.Block return block, nil } + if latestBlockHeight, err := s.LatestBlockHeight(ctx); err == nil && height > latestBlockHeight { + return nil, &types.BlockNotFoundByHeightError{Height: height} + } + blockRes, err := s.client.GetHeader(ctx, &archive.GetHeaderRequest{Height: height}) if err != nil { return nil, err @@ -176,11 +224,6 @@ func (s *Store) LedgerByHeight( ctx context.Context, blockHeight uint64, ) (snapshot.StorageSnapshot, error) { - err := s.SetBlockHeight(blockHeight) - if err != nil { - return nil, err - } - return snapshot.NewReadFuncStorageSnapshot(func(id flowgo.RegisterID) (flowgo.RegisterValue, error) { // first try to see if we have local stored ledger value, err := s.DefaultStore.GetBytesAtVersion( @@ -193,6 +236,7 @@ func (s *Store) LedgerByHeight( return value, nil } + log.Printf("fetching register: owner: %x, key: %x", []byte(id.Owner), []byte(id.Key)) ledgerKey := convert.RegisterIDToLedgerKey(flowgo.RegisterID{Key: id.Key, Owner: id.Owner}) ledgerPath, err := pathfinder.KeyToPath(ledgerKey, complete.DefaultPathFinderVersion) if err != nil { diff --git a/storage/remote/store_test.go b/storage/remote/store_test.go index 722e6fcf..0cbf1eb3 100644 --- a/storage/remote/store_test.go +++ b/storage/remote/store_test.go @@ -26,19 +26,23 @@ import ( "testing" "github.com/rs/zerolog" - - "github.com/onflow/flow-emulator/adapters" - "github.com/onflow/flow-emulator/storage/sqlite" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "github.com/onflow/flow-archive/api/archive" "github.com/onflow/flow-archive/codec/zbor" flowsdk "github.com/onflow/flow-go-sdk" flowgo "github.com/onflow/flow-go/model/flow" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "google.golang.org/grpc" + "github.com/onflow/flow-emulator/adapters" emulator "github.com/onflow/flow-emulator/emulator" + internalmock "github.com/onflow/flow-emulator/internal/mocks" + "github.com/onflow/flow-emulator/storage/sqlite" + "github.com/onflow/flow-emulator/storage/util" ) var _ archive.APIClient = testClient{} @@ -211,6 +215,7 @@ func Test_SimulatedMainnetTransaction(t *testing.T) { func Test_SimulatedMainnetTransactionWithChanges(t *testing.T) { t.Parallel() + client, err := newTestClient() require.NoError(t, err) @@ -287,3 +292,224 @@ func Test_SimulatedMainnetTransactionWithChanges(t *testing.T) { assert.Equal(t, txRes.Events[0].String(), "A.9799f28ff0453528.Ping.PingEmitted: 0x953f6f26d61710cb0e140bfde1022483b9ef410ddd181bac287d9968c84f4778") assert.Equal(t, txRes.Events[0].Value.String(), `A.9799f28ff0453528.Ping.PingEmitted(sound: "pong pong pong")`) } + +func Test_SimulatedMainnetProgressesBlocks(t *testing.T) { + t.Parallel() + + ctx := context.Background() + logger := zerolog.Nop() + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + expectedHeight := uint64(100) + + t.Run("GetLatestBlockHeader returns the latest sealed block from archive node", func(t *testing.T) { + t.Parallel() + + client := internalmock.NewMockArchiveAPIClient(mockCtrl) + addLastBlockCall(client, expectedHeight) + addGetHeaderCall(t, client, expectedHeight) + + b, _ := getBlockchain(t, expectedHeight, WithClient(client)) + adapter := adapters.NewAccessAdapter(&logger, b) + + addGetHeaderCall(t, client, expectedHeight) + header, status, err := adapter.GetLatestBlockHeader(ctx, true) + require.NoError(t, err) + + assert.Equal(t, expectedHeight, header.Height) + assert.Equal(t, flowgo.BlockStatusSealed, status) + }) + + t.Run("GetLatestBlockHeader returns the start block", func(t *testing.T) { + t.Parallel() + + startHeight := expectedHeight + 2 + + client := internalmock.NewMockArchiveAPIClient(mockCtrl) + addGetHeaderCall(t, client, startHeight) + + b, _ := getBlockchain(t, expectedHeight, WithClient(client), WithStartBlockHeight(startHeight)) + + adapter := adapters.NewAccessAdapter(&logger, b) + + addGetHeaderCall(t, client, startHeight) + + header, status, err := adapter.GetLatestBlockHeader(ctx, true) + require.NoError(t, err) + + assert.Equal(t, startHeight, header.Height) + assert.Equal(t, flowgo.BlockStatusSealed, status) + }) + + t.Run("GetBlockHeaderByHeight calls archive node for past blocks", func(t *testing.T) { + t.Parallel() + + client := internalmock.NewMockArchiveAPIClient(mockCtrl) + addLastBlockCall(client, expectedHeight) + addGetHeaderCall(t, client, expectedHeight) + + b, _ := getBlockchain(t, expectedHeight, WithClient(client)) + adapter := adapters.NewAccessAdapter(&logger, b) + + addGetHeaderCall(t, client, expectedHeight-1) + + header, status, err := adapter.GetBlockHeaderByHeight(ctx, expectedHeight-1) + require.NoError(t, err) + + assert.Equal(t, expectedHeight-1, header.Height) + assert.Equal(t, flowgo.BlockStatusSealed, status) + }) + + t.Run("GetBlockHeaderByHeight returns NotFound for future blocks", func(t *testing.T) { + t.Parallel() + + client := internalmock.NewMockArchiveAPIClient(mockCtrl) + addLastBlockCall(client, expectedHeight) + addGetHeaderCall(t, client, expectedHeight) + + b, _ := getBlockchain(t, expectedHeight, WithClient(client)) + adapter := adapters.NewAccessAdapter(&logger, b) + + _, _, err := adapter.GetBlockHeaderByHeight(ctx, expectedHeight+1) + require.Error(t, err) + require.Equal(t, codes.NotFound, status.Code(err), "unexpected error: %v", err) + }) + + // create persistent db + dbDir := t.TempDir() + t.Logf("dbDir: %s", dbDir) + + t.Run("Starting with persistent store handles blocks", func(t *testing.T) { + startHeight := expectedHeight + 2 + + client := internalmock.NewMockArchiveAPIClient(mockCtrl) + addGetHeaderCall(t, client, startHeight) + + provider, err := util.NewSqliteStorage(dbDir) + require.NoError(t, err) + + opts := []Option{WithClient(client), WithStartBlockHeight(startHeight)} + + remoteStore := getRemoteStore(t, provider.(*sqlite.Store), opts...) + b := getEmulatorBlockchain(t, remoteStore) + + adapter := adapters.NewAccessAdapter(&logger, b) + + addGetHeaderCall(t, client, startHeight) + + header, status, err := adapter.GetLatestBlockHeader(ctx, true) + require.NoError(t, err) + + assert.Equal(t, startHeight, header.Height) + assert.Equal(t, flowgo.BlockStatusSealed, status) + + // simulate progressing one block + err = remoteStore.SetBlockHeight(startHeight + 1) + require.NoError(t, err) + + err = remoteStore.StoreBlock(ctx, &flowgo.Block{Header: &flowgo.Header{Height: startHeight + 1}}) + require.NoError(t, err) + + // make sure the new block is now latest + header, status, err = adapter.GetLatestBlockHeader(ctx, true) + require.NoError(t, err) + + assert.Equal(t, startHeight+1, header.Height) + assert.Equal(t, flowgo.BlockStatusSealed, status) + }) + + t.Run("Restarting with persistent store continues from last block", func(t *testing.T) { + startHeight := expectedHeight + 2 + lastHeight := startHeight + 1 + + client := internalmock.NewMockArchiveAPIClient(mockCtrl) + + provider, err := util.NewSqliteStorage(dbDir) + require.NoError(t, err) + + opts := []Option{WithClient(client), WithStartBlockHeight(startHeight)} + + remoteStore := getRemoteStore(t, provider.(*sqlite.Store), opts...) + b := getEmulatorBlockchain(t, remoteStore) + + adapter := adapters.NewAccessAdapter(&logger, b) + + header, status, err := adapter.GetLatestBlockHeader(ctx, true) + require.NoError(t, err) + + // blocks should start where the left off + assert.Equal(t, lastHeight, header.Height) + assert.Equal(t, flowgo.BlockStatusSealed, status) + }) +} + +func getBlockchain(t *testing.T, height uint64, opts ...Option) (*emulator.Blockchain, *Store) { + remoteStore := getRemoteStore(t, nil, opts...) + b := getEmulatorBlockchain(t, remoteStore) + + return b, remoteStore +} + +func getRemoteStore(t *testing.T, provider *sqlite.Store, opts ...Option) *Store { + var err error + if provider == nil { + provider, err = sqlite.New(sqlite.InMemory) + require.NoError(t, err) + } + remoteStore, err := New(provider, opts...) + require.NoError(t, err) + + t.Cleanup(func() { + err := remoteStore.Close() + require.NoError(t, err) + }) + + return remoteStore +} + +func getEmulatorBlockchain(t *testing.T, remoteStore *Store) *emulator.Blockchain { + b, err := emulator.New( + emulator.WithStore(remoteStore), + emulator.WithStorageLimitEnabled(false), + emulator.WithTransactionValidationEnabled(false), + emulator.WithChainID(flowgo.Mainnet), + ) + require.NoError(t, err) + + return b +} + +func addLastBlockCall(client *internalmock.MockArchiveAPIClient, height uint64) { + responseGetLast := &archive.GetLastResponse{ + Height: height, + } + + client.EXPECT(). + GetLast(context.Background(), &archive.GetLastRequest{}). + Return(responseGetLast, nil). + Times(1) +} + +func addGetHeaderCall(t *testing.T, client *internalmock.MockArchiveAPIClient, height uint64) { + request := &archive.GetHeaderRequest{ + Height: height, + } + + header := flowgo.Header{ + Height: height, + } + + data, err := zbor.NewCodec().Marshal(&header) + require.NoError(t, err) + + response := &archive.GetHeaderResponse{ + Height: height, + Data: data, + } + + client.EXPECT(). + GetHeader(context.Background(), request). + Return(response, nil). + Times(1) +}