diff --git a/tools/rosetta/CHANGELOG.md b/tools/rosetta/CHANGELOG.md index 05a5c44ead07..254759f5d134 100644 --- a/tools/rosetta/CHANGELOG.md +++ b/tools/rosetta/CHANGELOG.md @@ -36,6 +36,14 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### Improvements + +* [#13832](https://github.com/cosmos/cosmos-sdk/pull/13832) Correctly populates rosetta's `/network/status` endpoint response. Roseta data api is divided into its own go files (account, block, mempool, network). + +### Bug Fixes + +* [#13832](https://github.com/cosmos/cosmos-sdk/pull/13832) Wrap tendermint RPC errors to rosetta errors. + ## v0.1.0 2022-11-04 **From `v0.1.0` the minimum version of Tendermint is `v0.37+`, due event type changes.** diff --git a/tools/rosetta/client_online.go b/tools/rosetta/client_online.go index 3c70cb561a3b..f2dc1fdabac5 100644 --- a/tools/rosetta/client_online.go +++ b/tools/rosetta/client_online.go @@ -144,6 +144,31 @@ func (c *Client) Ready() error { return nil } +func (c *Client) GenesisBlock(ctx context.Context) (crgtypes.BlockResponse, error) { + var genesisHeight int64 = 1 + return c.BlockByHeight(ctx, &genesisHeight) +} + +func (c *Client) InitialHeightBlock(ctx context.Context) (crgtypes.BlockResponse, error) { + genesisChunk, err := c.tmRPC.GenesisChunked(ctx, 0) + if err != nil { + return crgtypes.BlockResponse{}, err + } + heightNum, err := extractInitialHeightFromGenesisChunk(genesisChunk.Data) + if err != nil { + return crgtypes.BlockResponse{}, err + } + return c.BlockByHeight(ctx, &heightNum) +} + +func (c *Client) OldestBlock(ctx context.Context) (crgtypes.BlockResponse, error) { + status, err := c.tmRPC.Status(ctx) + if err != nil { + return crgtypes.BlockResponse{}, err + } + return c.BlockByHeight(ctx, &status.SyncInfo.EarliestBlockHeight) +} + func (c *Client) accountInfo(ctx context.Context, addr string, height *int64) (*SignerData, error) { if height != nil { strHeight := strconv.FormatInt(*height, 10) @@ -200,11 +225,6 @@ func (c *Client) BlockByHash(ctx context.Context, hash string) (crgtypes.BlockRe } func (c *Client) BlockByHeight(ctx context.Context, height *int64) (crgtypes.BlockResponse, error) { - height, err := c.getHeight(ctx, height) - - if err != nil { - return crgtypes.BlockResponse{}, crgerrs.WrapError(crgerrs.ErrBadGateway, err.Error()) - } block, err := c.tmRPC.Block(ctx, height) if err != nil { return crgtypes.BlockResponse{}, crgerrs.WrapError(crgerrs.ErrInternal, err.Error()) @@ -224,10 +244,6 @@ func (c *Client) BlockTransactionsByHash(ctx context.Context, hash string) (crgt } func (c *Client) BlockTransactionsByHeight(ctx context.Context, height *int64) (crgtypes.BlockTransactionsResponse, error) { - height, err := c.getHeight(ctx, height) - if err != nil { - return crgtypes.BlockTransactionsResponse{}, crgerrs.WrapError(crgerrs.ErrBadGateway, err.Error()) - } blockTxResp, err := c.blockTxs(ctx, height) if err != nil { return crgtypes.BlockTransactionsResponse{}, err @@ -535,25 +551,6 @@ func (c *Client) blockTxs(ctx context.Context, height *int64) (crgtypes.BlockTra }, nil } -func (c *Client) getHeight(ctx context.Context, height *int64) (realHeight *int64, err error) { - if height != nil && *height == -1 { - genesisChunk, err := c.tmRPC.GenesisChunked(ctx, 0) - if err != nil { - return nil, err - } - - heightNum, err := extractInitialHeightFromGenesisChunk(genesisChunk.Data) - if err != nil { - return nil, err - } - - realHeight = &heightNum - } else { - realHeight = height - } - return -} - var initialHeightRE = regexp.MustCompile(`"initial_height":"(\d+)"`) func extractInitialHeightFromGenesisChunk(genesisChunk string) (int64, error) { diff --git a/tools/rosetta/lib/errors/errors.go b/tools/rosetta/lib/errors/errors.go index f2e31b44af27..5fcc0c760279 100644 --- a/tools/rosetta/lib/errors/errors.go +++ b/tools/rosetta/lib/errors/errors.go @@ -10,6 +10,7 @@ import ( grpcstatus "google.golang.org/grpc/status" "github.com/coinbase/rosetta-sdk-go/types" + tmtypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" ) // ListErrors lists all the registered errors @@ -70,11 +71,26 @@ func ToRosetta(err error) *types.Error { // if it's null or not known rosErr, ok := err.(*Error) if rosErr == nil || !ok { + tmErr, ok := err.(*tmtypes.RPCError) + if tmErr != nil && ok { + return fromTendermintToRosettaError(tmErr).rosErr + } return ToRosetta(WrapError(ErrUnknown, ErrUnknown.Error())) } return rosErr.rosErr } +// fromTendermintToRosettaError converts a tendermint jsonrpc error to rosetta error +func fromTendermintToRosettaError(err *tmtypes.RPCError) *Error { + return &Error{rosErr: &types.Error{ + Code: int32(err.Code), + Message: err.Message, + Details: map[string]interface{}{ + "info": err.Data, + }, + }} +} + // FromGRPCToRosettaError converts a gRPC error to rosetta error func FromGRPCToRosettaError(err error) *Error { status, ok := grpcstatus.FromError(err) diff --git a/tools/rosetta/lib/errors/errors_test.go b/tools/rosetta/lib/errors/errors_test.go index 84be297e0ba1..522e70715604 100644 --- a/tools/rosetta/lib/errors/errors_test.go +++ b/tools/rosetta/lib/errors/errors_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + tmtypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" ) func TestRegisterError(t *testing.T) { @@ -55,6 +56,10 @@ func TestToRosetta(t *testing.T) { assert.NotNil(t, ToRosetta(error)) // wrong type assert.NotNil(t, ToRosetta(&MyError{})) + + tmErr := &tmtypes.RPCError{} + // RpcError case + assert.NotNil(t, ToRosetta(tmErr)) } type MyError struct{} diff --git a/tools/rosetta/lib/internal/service/account.go b/tools/rosetta/lib/internal/service/account.go new file mode 100644 index 000000000000..5c3ff3eb59c9 --- /dev/null +++ b/tools/rosetta/lib/internal/service/account.go @@ -0,0 +1,60 @@ +package service + +import ( + "context" + + "cosmossdk.io/tools/rosetta/lib/errors" + crgtypes "cosmossdk.io/tools/rosetta/lib/types" + "github.com/coinbase/rosetta-sdk-go/types" +) + +// AccountBalance retrieves the account balance of an address +// rosetta requires us to fetch the block information too +func (on OnlineNetwork) AccountBalance(ctx context.Context, request *types.AccountBalanceRequest) (*types.AccountBalanceResponse, *types.Error) { + var ( + height int64 + block crgtypes.BlockResponse + err error + ) + + switch { + case request.BlockIdentifier == nil: + syncStatus, err := on.client.Status(ctx) + if err != nil { + return nil, errors.ToRosetta(err) + } + block, err = on.client.BlockByHeight(ctx, syncStatus.CurrentIndex) + if err != nil { + return nil, errors.ToRosetta(err) + } + case request.BlockIdentifier.Hash != nil: + block, err = on.client.BlockByHash(ctx, *request.BlockIdentifier.Hash) + if err != nil { + return nil, errors.ToRosetta(err) + } + height = block.Block.Index + case request.BlockIdentifier.Index != nil: + height = *request.BlockIdentifier.Index + block, err = on.client.BlockByHeight(ctx, &height) + if err != nil { + return nil, errors.ToRosetta(err) + } + } + + accountCoins, err := on.client.Balances(ctx, request.AccountIdentifier.Address, &height) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return &types.AccountBalanceResponse{ + BlockIdentifier: block.Block, + Balances: accountCoins, + Metadata: nil, + }, nil +} + +// AccountsCoins - relevant only for UTXO based chain +// see https://www.rosetta-api.org/docs/AccountApi.html#accountcoins +func (o OnlineNetwork) AccountCoins(_ context.Context, _ *types.AccountCoinsRequest) (*types.AccountCoinsResponse, *types.Error) { + return nil, errors.ToRosetta(errors.ErrOffline) +} diff --git a/tools/rosetta/lib/internal/service/block.go b/tools/rosetta/lib/internal/service/block.go new file mode 100644 index 000000000000..48b96a4bc1c4 --- /dev/null +++ b/tools/rosetta/lib/internal/service/block.go @@ -0,0 +1,78 @@ +package service + +import ( + "context" + + "cosmossdk.io/tools/rosetta/lib/errors" + crgtypes "cosmossdk.io/tools/rosetta/lib/types" + "github.com/coinbase/rosetta-sdk-go/types" +) + +// Block gets the transactions in the given block +func (on OnlineNetwork) Block(ctx context.Context, request *types.BlockRequest) (*types.BlockResponse, *types.Error) { + var ( + blockResponse crgtypes.BlockTransactionsResponse + err error + ) + + // When fetching data by BlockIdentifier, it may be possible to only specify the index or hash. + // If neither property is specified, it is assumed that the client is making a request at the current block. + switch { + case request.BlockIdentifier == nil: // unlike AccountBalance(), BlockIdentifer is mandatory by spec 1.4.10. + err := errors.WrapError(errors.ErrBadArgument, "block identifier needs to be specified") + return nil, errors.ToRosetta(err) + + case request.BlockIdentifier.Hash != nil: + blockResponse, err = on.client.BlockTransactionsByHash(ctx, *request.BlockIdentifier.Hash) + if err != nil { + return nil, errors.ToRosetta(err) + } + case request.BlockIdentifier.Index != nil: + blockResponse, err = on.client.BlockTransactionsByHeight(ctx, request.BlockIdentifier.Index) + if err != nil { + return nil, errors.ToRosetta(err) + } + + default: + // both empty + blockResponse, err = on.client.BlockTransactionsByHeight(ctx, nil) + if err != nil { + return nil, errors.ToRosetta(err) + } + } + + // Both of index and hash can be specified in reuqest, so make sure they are not mismatching. + if request.BlockIdentifier.Index != nil && *request.BlockIdentifier.Index != blockResponse.Block.Index { + err := errors.WrapError(errors.ErrBadArgument, "mismatching index") + return nil, errors.ToRosetta(err) + } + + if request.BlockIdentifier.Hash != nil && *request.BlockIdentifier.Hash != blockResponse.Block.Hash { + err := errors.WrapError(errors.ErrBadArgument, "mismatching hash") + return nil, errors.ToRosetta(err) + } + + return &types.BlockResponse{ + Block: &types.Block{ + BlockIdentifier: blockResponse.Block, + ParentBlockIdentifier: blockResponse.ParentBlock, + Timestamp: blockResponse.MillisecondTimestamp, + Transactions: blockResponse.Transactions, + Metadata: nil, + }, + OtherTransactions: nil, + }, nil +} + +// BlockTransaction gets the given transaction in the specified block, we do not need to check the block itself too +// due to the fact that tendermint achieves instant finality +func (on OnlineNetwork) BlockTransaction(ctx context.Context, request *types.BlockTransactionRequest) (*types.BlockTransactionResponse, *types.Error) { + tx, err := on.client.GetTx(ctx, request.TransactionIdentifier.Hash) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return &types.BlockTransactionResponse{ + Transaction: tx, + }, nil +} diff --git a/tools/rosetta/lib/internal/service/data.go b/tools/rosetta/lib/internal/service/data.go deleted file mode 100644 index 0a65352bc7c0..000000000000 --- a/tools/rosetta/lib/internal/service/data.go +++ /dev/null @@ -1,182 +0,0 @@ -package service - -import ( - "context" - - "cosmossdk.io/tools/rosetta/lib/errors" - crgtypes "cosmossdk.io/tools/rosetta/lib/types" - "github.com/coinbase/rosetta-sdk-go/types" -) - -// AccountBalance retrieves the account balance of an address -// rosetta requires us to fetch the block information too -func (on OnlineNetwork) AccountBalance(ctx context.Context, request *types.AccountBalanceRequest) (*types.AccountBalanceResponse, *types.Error) { - var ( - height int64 - block crgtypes.BlockResponse - err error - ) - - switch { - case request.BlockIdentifier == nil: - syncStatus, err := on.client.Status(ctx) - if err != nil { - return nil, errors.ToRosetta(err) - } - block, err = on.client.BlockByHeight(ctx, syncStatus.CurrentIndex) - if err != nil { - return nil, errors.ToRosetta(err) - } - case request.BlockIdentifier.Hash != nil: - block, err = on.client.BlockByHash(ctx, *request.BlockIdentifier.Hash) - if err != nil { - return nil, errors.ToRosetta(err) - } - height = block.Block.Index - case request.BlockIdentifier.Index != nil: - height = *request.BlockIdentifier.Index - block, err = on.client.BlockByHeight(ctx, &height) - if err != nil { - return nil, errors.ToRosetta(err) - } - } - - accountCoins, err := on.client.Balances(ctx, request.AccountIdentifier.Address, &height) - if err != nil { - return nil, errors.ToRosetta(err) - } - - return &types.AccountBalanceResponse{ - BlockIdentifier: block.Block, - Balances: accountCoins, - Metadata: nil, - }, nil -} - -// Block gets the transactions in the given block -func (on OnlineNetwork) Block(ctx context.Context, request *types.BlockRequest) (*types.BlockResponse, *types.Error) { - var ( - blockResponse crgtypes.BlockTransactionsResponse - err error - ) - - // When fetching data by BlockIdentifier, it may be possible to only specify the index or hash. - // If neither property is specified, it is assumed that the client is making a request at the current block. - switch { - case request.BlockIdentifier == nil: // unlike AccountBalance(), BlockIdentifer is mandatory by spec 1.4.10. - err := errors.WrapError(errors.ErrBadArgument, "block identifier needs to be specified") - return nil, errors.ToRosetta(err) - - case request.BlockIdentifier.Hash != nil: - blockResponse, err = on.client.BlockTransactionsByHash(ctx, *request.BlockIdentifier.Hash) - if err != nil { - return nil, errors.ToRosetta(err) - } - case request.BlockIdentifier.Index != nil: - blockResponse, err = on.client.BlockTransactionsByHeight(ctx, request.BlockIdentifier.Index) - if err != nil { - return nil, errors.ToRosetta(err) - } - - default: - // both empty - blockResponse, err = on.client.BlockTransactionsByHeight(ctx, nil) - if err != nil { - return nil, errors.ToRosetta(err) - } - } - - // Both of index and hash can be specified in reuqest, so make sure they are not mismatching. - if request.BlockIdentifier.Index != nil && *request.BlockIdentifier.Index != blockResponse.Block.Index { - err := errors.WrapError(errors.ErrBadArgument, "mismatching index") - return nil, errors.ToRosetta(err) - } - - if request.BlockIdentifier.Hash != nil && *request.BlockIdentifier.Hash != blockResponse.Block.Hash { - err := errors.WrapError(errors.ErrBadArgument, "mismatching hash") - return nil, errors.ToRosetta(err) - } - - return &types.BlockResponse{ - Block: &types.Block{ - BlockIdentifier: blockResponse.Block, - ParentBlockIdentifier: blockResponse.ParentBlock, - Timestamp: blockResponse.MillisecondTimestamp, - Transactions: blockResponse.Transactions, - Metadata: nil, - }, - OtherTransactions: nil, - }, nil -} - -// BlockTransaction gets the given transaction in the specified block, we do not need to check the block itself too -// due to the fact that tendermint achieves instant finality -func (on OnlineNetwork) BlockTransaction(ctx context.Context, request *types.BlockTransactionRequest) (*types.BlockTransactionResponse, *types.Error) { - tx, err := on.client.GetTx(ctx, request.TransactionIdentifier.Hash) - if err != nil { - return nil, errors.ToRosetta(err) - } - - return &types.BlockTransactionResponse{ - Transaction: tx, - }, nil -} - -// Mempool fetches the transactions contained in the mempool -func (on OnlineNetwork) Mempool(ctx context.Context, _ *types.NetworkRequest) (*types.MempoolResponse, *types.Error) { - txs, err := on.client.Mempool(ctx) - if err != nil { - return nil, errors.ToRosetta(err) - } - - return &types.MempoolResponse{ - TransactionIdentifiers: txs, - }, nil -} - -// MempoolTransaction fetches a single transaction in the mempool -// NOTE: it is not implemented yet -func (on OnlineNetwork) MempoolTransaction(ctx context.Context, request *types.MempoolTransactionRequest) (*types.MempoolTransactionResponse, *types.Error) { - tx, err := on.client.GetUnconfirmedTx(ctx, request.TransactionIdentifier.Hash) - if err != nil { - return nil, errors.ToRosetta(err) - } - - return &types.MempoolTransactionResponse{ - Transaction: tx, - }, nil -} - -func (on OnlineNetwork) NetworkList(_ context.Context, _ *types.MetadataRequest) (*types.NetworkListResponse, *types.Error) { - return &types.NetworkListResponse{NetworkIdentifiers: []*types.NetworkIdentifier{on.network}}, nil -} - -func (on OnlineNetwork) NetworkOptions(_ context.Context, _ *types.NetworkRequest) (*types.NetworkOptionsResponse, *types.Error) { - return on.networkOptions, nil -} - -func (on OnlineNetwork) NetworkStatus(ctx context.Context, _ *types.NetworkRequest) (*types.NetworkStatusResponse, *types.Error) { - syncStatus, err := on.client.Status(ctx) - if err != nil { - return nil, errors.ToRosetta(err) - } - - block, err := on.client.BlockByHeight(ctx, syncStatus.CurrentIndex) - if err != nil { - return nil, errors.ToRosetta(err) - } - - peers, err := on.client.Peers(ctx) - if err != nil { - return nil, errors.ToRosetta(err) - } - - return &types.NetworkStatusResponse{ - CurrentBlockIdentifier: block.Block, - CurrentBlockTimestamp: block.MillisecondTimestamp, - GenesisBlockIdentifier: on.genesisBlockIdentifier, - OldestBlockIdentifier: nil, - SyncStatus: syncStatus, - Peers: peers, - }, nil -} diff --git a/tools/rosetta/lib/internal/service/mempool.go b/tools/rosetta/lib/internal/service/mempool.go new file mode 100644 index 000000000000..9e93085bc090 --- /dev/null +++ b/tools/rosetta/lib/internal/service/mempool.go @@ -0,0 +1,33 @@ +package service + +import ( + "context" + + "cosmossdk.io/tools/rosetta/lib/errors" + "github.com/coinbase/rosetta-sdk-go/types" +) + +// Mempool fetches the transactions contained in the mempool +func (on OnlineNetwork) Mempool(ctx context.Context, _ *types.NetworkRequest) (*types.MempoolResponse, *types.Error) { + txs, err := on.client.Mempool(ctx) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return &types.MempoolResponse{ + TransactionIdentifiers: txs, + }, nil +} + +// MempoolTransaction fetches a single transaction in the mempool +// NOTE: it is not implemented yet +func (on OnlineNetwork) MempoolTransaction(ctx context.Context, request *types.MempoolTransactionRequest) (*types.MempoolTransactionResponse, *types.Error) { + tx, err := on.client.GetUnconfirmedTx(ctx, request.TransactionIdentifier.Hash) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return &types.MempoolTransactionResponse{ + Transaction: tx, + }, nil +} diff --git a/tools/rosetta/lib/internal/service/network.go b/tools/rosetta/lib/internal/service/network.go new file mode 100644 index 000000000000..a5fd13f8e655 --- /dev/null +++ b/tools/rosetta/lib/internal/service/network.go @@ -0,0 +1,55 @@ +package service + +import ( + "context" + + "cosmossdk.io/tools/rosetta/lib/errors" + "github.com/coinbase/rosetta-sdk-go/types" +) + +func (on OnlineNetwork) NetworkList(_ context.Context, _ *types.MetadataRequest) (*types.NetworkListResponse, *types.Error) { + return &types.NetworkListResponse{NetworkIdentifiers: []*types.NetworkIdentifier{on.network}}, nil +} + +func (on OnlineNetwork) NetworkOptions(_ context.Context, _ *types.NetworkRequest) (*types.NetworkOptionsResponse, *types.Error) { + return on.networkOptions, nil +} + +func (on OnlineNetwork) NetworkStatus(ctx context.Context, _ *types.NetworkRequest) (*types.NetworkStatusResponse, *types.Error) { + syncStatus, err := on.client.Status(ctx) + if err != nil { + return nil, errors.ToRosetta(err) + } + + block, err := on.client.BlockByHeight(ctx, syncStatus.CurrentIndex) + if err != nil { + return nil, errors.ToRosetta(err) + } + + oldestBlockIdentifier, err := on.client.OldestBlock(ctx) + if err != nil { + return nil, errors.ToRosetta(err) + } + + genesisBlock, err := on.client.GenesisBlock(ctx) + if err != nil { + genesisBlock, err = on.client.InitialHeightBlock(ctx) + if err != nil { + genesisBlock = oldestBlockIdentifier + } + } + + peers, err := on.client.Peers(ctx) + if err != nil { + return nil, errors.ToRosetta(err) + } + + return &types.NetworkStatusResponse{ + CurrentBlockIdentifier: block.Block, + CurrentBlockTimestamp: block.MillisecondTimestamp, + GenesisBlockIdentifier: genesisBlock.Block, + OldestBlockIdentifier: oldestBlockIdentifier.Block, + SyncStatus: syncStatus, + Peers: peers, + }, nil +} diff --git a/tools/rosetta/lib/internal/service/online.go b/tools/rosetta/lib/internal/service/online.go index d1d0d2efb93e..399be78c8db7 100644 --- a/tools/rosetta/lib/internal/service/online.go +++ b/tools/rosetta/lib/internal/service/online.go @@ -3,7 +3,6 @@ package service import ( "context" "fmt" - "os" "time" "github.com/coinbase/rosetta-sdk-go/types" @@ -16,7 +15,6 @@ import ( // genesisBlockFetchTimeout defines a timeout to fetch the genesis block const ( genesisBlockFetchTimeout = 15 * time.Second - genesisHashEnv = "GENESIS_HASH" ) // NewOnlineNetwork builds a single network adapter. @@ -25,26 +23,16 @@ func NewOnlineNetwork(network *types.NetworkIdentifier, client crgtypes.Client, ctx, cancel := context.WithTimeout(context.Background(), genesisBlockFetchTimeout) defer cancel() - var genesisHeight int64 = -1 // to use initial_height in genesis.json - block, err := client.BlockByHeight(ctx, &genesisHeight) + var genesisHeight int64 = 1 // to get genesis block height + genesisBlock, err := client.BlockByHeight(ctx, &genesisHeight) if err != nil { - return OnlineNetwork{}, err + logger.Error(fmt.Sprintf("Could not get genesis block height. %v", err)) } - // Get genesis hash from ENV. It should be set by an external script since is not possible to get - // using tendermint API - genesisHash := os.Getenv(genesisHashEnv) - if genesisHash == "" { - logger.Error(fmt.Sprintf("Genesis hash env '%s' is not properly set!", genesisHashEnv)) - } - - block.Block.Hash = genesisHash - return OnlineNetwork{ - client: client, - network: network, - networkOptions: networkOptionsFromClient(client, block.Block), - genesisBlockIdentifier: block.Block, + client: client, + network: network, + networkOptions: networkOptionsFromClient(client, genesisBlock.Block), }, nil } @@ -54,14 +42,6 @@ type OnlineNetwork struct { network *types.NetworkIdentifier // identifies the network, it's static networkOptions *types.NetworkOptionsResponse // identifies the network options, it's static - - genesisBlockIdentifier *types.BlockIdentifier // identifies genesis block, it's static -} - -// AccountsCoins - relevant only for UTXO based chain -// see https://www.rosetta-api.org/docs/AccountApi.html#accountcoins -func (o OnlineNetwork) AccountCoins(_ context.Context, _ *types.AccountCoinsRequest) (*types.AccountCoinsResponse, *types.Error) { - return nil, crgerrs.ToRosetta(crgerrs.ErrOffline) } // networkOptionsFromClient builds network options given the client diff --git a/tools/rosetta/lib/types/types.go b/tools/rosetta/lib/types/types.go index 4f734c34fbf2..82e91186ceb2 100644 --- a/tools/rosetta/lib/types/types.go +++ b/tools/rosetta/lib/types/types.go @@ -30,6 +30,13 @@ type Client interface { // when the rosetta instance might come up before the node itself // the servicer must return nil if the node is ready Ready() error + // GenesisBlock gets the genesis block of the chain + GenesisBlock(ctx context.Context) (BlockResponse, error) + // InitialHeightBlock gets block with height InitialHeight + // from GenesisDoc by downloading the blob + InitialHeightBlock(ctx context.Context) (BlockResponse, error) + // OldestBlock gets block with height EarliestBlockHeight from syncStatus + OldestBlock(ctx context.Context) (BlockResponse, error) // Data API