ADR 35: Rosetta API Support (#7492)
Co-authored-by: Alessio Treglia <alessio@tendermint.com> Co-authored-by: SenorMonito <david@planet-mono.net> Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: Aaron Craelius <aaron@regen.network>
This commit is contained in:
parent
56c08d1117
commit
4d833f9ef0
|
@ -71,3 +71,4 @@ Read about the [PROCESS](./PROCESS.md).
|
||||||
- [ADR 028: Public Key Addresses](./adr-028-public-key-addresses.md)
|
- [ADR 028: Public Key Addresses](./adr-028-public-key-addresses.md)
|
||||||
- [ADR 031: Protobuf Msg Services](./adr-031-msg-service.md)
|
- [ADR 031: Protobuf Msg Services](./adr-031-msg-service.md)
|
||||||
- [ADR 032: Typed Events](./adr-032-typed-events.md)
|
- [ADR 032: Typed Events](./adr-032-typed-events.md)
|
||||||
|
- [ADR 035: Rosetta API Support](./adr-035-rosetta-api-support.md)
|
||||||
|
|
|
@ -0,0 +1,274 @@
|
||||||
|
# ADR 035: Rosetta API Support
|
||||||
|
|
||||||
|
## Authors
|
||||||
|
|
||||||
|
- Jonathan Gimeno (@jgimeno)
|
||||||
|
- David Grierson (@senormonito)
|
||||||
|
- Alessio Treglia (@alessio)
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
[Rosetta API](https://www.rosetta-api.org/) is an open-source specification and set of tools developed by Coinbase to
|
||||||
|
standardise blockchain interactions.
|
||||||
|
|
||||||
|
Through the use of a standard API for integrating blockchain applications it will
|
||||||
|
|
||||||
|
* Be easier for a user to interact with a given blockchain
|
||||||
|
* Allow exchanges to integrate new blockchains quickly and easily
|
||||||
|
* Enable application developers to build cross-blockchain applications such as block explorers, wallets and dApps at
|
||||||
|
considerably lower cost and effort.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
It is clear that adding Rosetta API support to the Cosmos SDK will bring value to all the developers and
|
||||||
|
Cosmos SDK based chains in the ecosystem. How it is implemented is key.
|
||||||
|
|
||||||
|
The driving principles of the proposed design are:
|
||||||
|
|
||||||
|
1. **Extensibility:** it must be as riskless and painless as possible for application developers to set-up network
|
||||||
|
configurations to expose Rosetta API-compliant services.
|
||||||
|
2. **Long term support:** This proposal aims to provide support for all the supported Cosmos SDK release series.
|
||||||
|
3. **Cost-efficiency:** Backporting changes to Rosetta API specifications from `master` to the various stable
|
||||||
|
branches of Cosmos SDK is a cost that needs to be reduced.
|
||||||
|
|
||||||
|
We will achieve these delivering on these principles by the following:
|
||||||
|
|
||||||
|
1. There will be an external repo called [cosmos-rosetta-gateway](https://github.com/tendermint/cosmos-rosetta-gateway)
|
||||||
|
for the implementation of the core Rosetta API features, particularly:
|
||||||
|
a. The types and interfaces. This separates design from implementation detail.
|
||||||
|
b. Some core implementations: specifically, the `Service` functionality as this is independent of the Cosmos SDK version.
|
||||||
|
2. Due to differences between the Cosmos release series, each series will have its own specific API implementations of `Network` struct and `Adapter` interface.
|
||||||
|
3. There will be two options for starting an API service in applications:
|
||||||
|
a. API shares the application process
|
||||||
|
b. API-specific process.
|
||||||
|
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### The External Repo
|
||||||
|
|
||||||
|
As section will describe the proposed external library, including the service implementation, plus the defined types and interfaces.
|
||||||
|
|
||||||
|
#### Service
|
||||||
|
|
||||||
|
`Service` is a simple `struct` that is started and listens to the port specified in the options. This is meant to be used across all the Cosmos SDK versions that are actively supported.
|
||||||
|
|
||||||
|
The constructor follows:
|
||||||
|
|
||||||
|
`func New(options Options, network Network) (*Service, error)`
|
||||||
|
|
||||||
|
#### Types
|
||||||
|
|
||||||
|
`Service` accepts an `Options` `struct` that holds service configuration values, such as the port the service would be listening to:
|
||||||
|
|
||||||
|
```golang
|
||||||
|
type Options struct {
|
||||||
|
ListenAddress string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Network` type holds network-specific properties (i.e. configuration values) and adapters. Pre-configured concrete types will be available for each Cosmos SDK release. Applications can also create their own custom types.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
type Network struct {
|
||||||
|
Properties rosetta.NetworkProperties
|
||||||
|
Adapter rosetta.Adapter
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
A `NetworkProperties` `struct` comprises basic values that are required by a Rosetta API `Service`:
|
||||||
|
|
||||||
|
```golang
|
||||||
|
type NetworkProperties struct {
|
||||||
|
// Mandatory properties
|
||||||
|
Blockchain string
|
||||||
|
Network string
|
||||||
|
SupportedOperations []string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Rosetta API services use `Blockchain` and `Network` as identifiers, e.g. the developers of _gaia_, the application that powers the Cosmos Hub, may want to set those to `Cosmos Hub` and `cosmos-hub-3` respectively.
|
||||||
|
|
||||||
|
`SupportedOperations` contains the transaction types that are supported by the library. At the present time,
|
||||||
|
only `cosmos-sdk/MsgSend` is supported in Launchpad. Additional operations will be added in due time.
|
||||||
|
|
||||||
|
For Launchpad we will map the amino type name to the operation supported, in Stargate we will use the protoc one.
|
||||||
|
|
||||||
|
#### Interfaces
|
||||||
|
|
||||||
|
Every SDK version uses a different format to connect (rpc, gRpc, etc), we have abstracted this in what is called the
|
||||||
|
Adapter. This is an interface that defines the methods an adapter implementation must provide in order to be used
|
||||||
|
in the `Network` interface.
|
||||||
|
|
||||||
|
Each Cosmos SDK release series will have their own Adapter implementations.
|
||||||
|
Developers can implement their own custom adapters as required.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
type Adapter interface {
|
||||||
|
DataAPI
|
||||||
|
ConstructionAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
type DataAPI interface {
|
||||||
|
server.NetworkAPIServicer
|
||||||
|
server.AccountAPIServicer
|
||||||
|
server.MempoolAPIServicer
|
||||||
|
server.BlockAPIServicer
|
||||||
|
server.ConstructionAPIServicer
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConstructionAPI interface {
|
||||||
|
server.ConstructionAPIServicer
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example in pseudo-code of an Adapter interface:
|
||||||
|
|
||||||
|
```golang
|
||||||
|
type SomeAdapter struct {
|
||||||
|
cosmosClient client
|
||||||
|
tendermintClient client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSomeAdapter(cosmosClient client, tendermintClient client) rosetta.Adapter {
|
||||||
|
return &SomeAdapter{cosmosClient: cosmosClient, tendermintClient: tendermintClient}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SomeAdapter) NetworkStatus(ctx context.Context, request *types.NetworkRequest) (*types.NetworkStatusResponse, *types.Error) {
|
||||||
|
resp := s.tendermintClient.CallStatus()
|
||||||
|
// ... Parse status Response
|
||||||
|
// build NetworkStatusResponse
|
||||||
|
return networkStatusResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SomeAdapter) AccountBalance(ctx context.Context, request *types.AccountBalanceRequest) (*types.AccountBalanceResponse, *types.Error) {
|
||||||
|
resp := s.cosmosClient.Account()
|
||||||
|
// ... Parse cosmos specific account response
|
||||||
|
// build AccountBalanceResponse
|
||||||
|
return AccountBalanceResponse, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// And we repeat for all the methods defined in the interface.
|
||||||
|
```
|
||||||
|
|
||||||
|
For further information about the `Servicer` interfaces, please refer to the [Coinbase's rosetta-sdk-go's documentation](https://pkg.go.dev/github.com/coinbase/rosetta-sdk-go@v0.5.9/server).
|
||||||
|
|
||||||
|
### 2. Cosmos SDK Implementation
|
||||||
|
|
||||||
|
As described, each Cosmos SDK release series will have version specific implementations of `Network` and `Adapter`, as
|
||||||
|
well as a `NewNetwork` constructor.
|
||||||
|
|
||||||
|
Due to separation of interface and implementation, application developers have the option to override as needed,
|
||||||
|
using this code as reference.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
// NewNetwork returns the default application configuration.
|
||||||
|
func NewNetwork(options Options) service.Network {
|
||||||
|
cosmosClient := cosmos.NewClient(fmt.Sprintf("http://%s", options.CosmosEndpoint))
|
||||||
|
tendermintClient := tendermint.NewClient(fmt.Sprintf("http://%s", options.TendermintEndpoint))
|
||||||
|
|
||||||
|
return service.Network{
|
||||||
|
Properties: rosetta.NetworkProperties{
|
||||||
|
Blockchain: options.Blockchain,
|
||||||
|
Network: options.Network,
|
||||||
|
SupportedOperations: []string{OperationTransfer},
|
||||||
|
},
|
||||||
|
Adapter: newAdapter(
|
||||||
|
cosmosClient,
|
||||||
|
tendermintClient,
|
||||||
|
properties{
|
||||||
|
Blockchain: options.Blockchain,
|
||||||
|
Network: options.Network,
|
||||||
|
OfflineMode: options.OfflineMode,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. API service invocation
|
||||||
|
|
||||||
|
As stated at the start, application developers will have two methods for invocation of the Rosetta API service:
|
||||||
|
|
||||||
|
1. Shared process for both application and API
|
||||||
|
2. Standalone API service
|
||||||
|
|
||||||
|
#### Shared Process (Only Stargate)
|
||||||
|
|
||||||
|
Rosetta API service could run within the same execution process as the application. New configuration option and
|
||||||
|
command line flags would be provided to support this:
|
||||||
|
|
||||||
|
```golang
|
||||||
|
if config.Rosetta.Enable {
|
||||||
|
....
|
||||||
|
get contecxt, flags, etc
|
||||||
|
...
|
||||||
|
|
||||||
|
h, err := service.New(
|
||||||
|
service.Options{ListenAddress: config.Rosetta.ListenAddress},
|
||||||
|
rosetta.NewNetwork(cdc, options),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := h.Start(config); err != nil {
|
||||||
|
errCh <- err
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Separate API service
|
||||||
|
|
||||||
|
Client application developers can write a new command to launch a Rosetta API server as a separate process too:
|
||||||
|
|
||||||
|
```golang
|
||||||
|
func RosettaCommand(cdc *codec.Codec) *cobra.Command {
|
||||||
|
|
||||||
|
...
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "rosetta",
|
||||||
|
....
|
||||||
|
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
....
|
||||||
|
get contecxt, flags, etc
|
||||||
|
...
|
||||||
|
|
||||||
|
h, err := service.New(
|
||||||
|
service.Options{Endpoint: endpoint},
|
||||||
|
rosetta.NewNetwork(cdc, options),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
h.Start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
...
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Proposed
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
### Positive
|
||||||
|
|
||||||
|
- Out-of-the-box Rosetta API support within Cosmos SDK.
|
||||||
|
- Blockchain interface standardisation
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- https://www.rosetta-api.org/
|
||||||
|
- https://github.com/tendermint/cosmos-rosetta-gateway
|
Loading…
Reference in New Issue