rosetta: upgrade to newest version (#9314)
* feat: update rosetta sdk to v0.6.10 embed from v1.0.0 release branch of the library: https://github.com/tendermint/cosmos-rosetta-gateway/tree/release/v1.0.0 closes: https://github.com/cosmos/cosmos-sdk/issues/9300 Co-authored-by: Alessio Treglia <alessio@tendermint.com>
This commit is contained in:
co-authored by
Alessio Treglia
parent
925e63cf32
commit
25ecec6c15
+1
-2
@@ -5,10 +5,9 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
||||
)
|
||||
|
||||
// RosettaCommand builds the rosetta root command given
|
||||
|
||||
@@ -5,7 +5,8 @@ import (
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/coinbase/rosetta-sdk-go/types"
|
||||
crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors"
|
||||
|
||||
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
@@ -18,8 +18,8 @@ import (
|
||||
"github.com/tendermint/tendermint/rpc/client/http"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors"
|
||||
crgtypes "github.com/tendermint/cosmos-rosetta-gateway/types"
|
||||
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||
crgtypes "github.com/cosmos/cosmos-sdk/server/rosetta/lib/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
|
||||
"github.com/coinbase/rosetta-sdk-go/types"
|
||||
"github.com/spf13/pflag"
|
||||
crg "github.com/tendermint/cosmos-rosetta-gateway/server"
|
||||
|
||||
crg "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
|
||||
@@ -11,17 +11,19 @@ import (
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
crgtypes "github.com/tendermint/cosmos-rosetta-gateway/types"
|
||||
tmcoretypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
|
||||
crgtypes "github.com/cosmos/cosmos-sdk/server/rosetta/lib/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
|
||||
rosettatypes "github.com/coinbase/rosetta-sdk-go/types"
|
||||
crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||
|
||||
sdkclient "github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
@@ -251,7 +253,7 @@ func (c converter) Ops(status string, msg sdk.Msg) ([]*rosettatypes.Operation, e
|
||||
for i, signer := range msg.GetSigners() {
|
||||
op := &rosettatypes.Operation{
|
||||
Type: opName,
|
||||
Status: status,
|
||||
Status: &status,
|
||||
Account: &rosettatypes.AccountIdentifier{Address: signer.String()},
|
||||
Metadata: meta,
|
||||
}
|
||||
@@ -395,7 +397,7 @@ func sdkEventToBalanceOperations(status string, event abci.Event) (operations []
|
||||
|
||||
op := &rosettatypes.Operation{
|
||||
Type: event.Type,
|
||||
Status: status,
|
||||
Status: &status,
|
||||
Account: &rosettatypes.AccountIdentifier{Address: accountIdentifier},
|
||||
Amount: &rosettatypes.Amount{
|
||||
Value: value,
|
||||
@@ -520,7 +522,7 @@ func (c converter) SyncStatus(status *tmcoretypes.ResultStatus) *rosettatypes.Sy
|
||||
}
|
||||
|
||||
return &rosettatypes.SyncStatus{
|
||||
CurrentIndex: status.SyncInfo.LatestBlockHeight,
|
||||
CurrentIndex: &status.SyncInfo.LatestBlockHeight,
|
||||
TargetIndex: nil, // sync info does not allow us to get target height
|
||||
Stage: &stage,
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
@@ -17,7 +15,9 @@ import (
|
||||
|
||||
rosettatypes "github.com/coinbase/rosetta-sdk-go/types"
|
||||
"github.com/stretchr/testify/suite"
|
||||
crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
||||
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
package errors
|
||||
|
||||
// errors.go contains all the errors returned by the adapter implementation
|
||||
// plus some extra utilities to parse those errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
grpccodes "google.golang.org/grpc/codes"
|
||||
grpcstatus "google.golang.org/grpc/status"
|
||||
|
||||
"github.com/coinbase/rosetta-sdk-go/types"
|
||||
)
|
||||
|
||||
// ListErrors lists all the registered errors
|
||||
func ListErrors() []*types.Error {
|
||||
return registry.list()
|
||||
}
|
||||
|
||||
// SealAndListErrors seals the registry and lists its errors
|
||||
func SealAndListErrors() []*types.Error {
|
||||
registry.seal()
|
||||
return registry.list()
|
||||
}
|
||||
|
||||
// Error defines an error that can be converted to a Rosetta API error.
|
||||
type Error struct {
|
||||
rosErr *types.Error
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
if e.rosErr == nil {
|
||||
return ErrUnknown.Error()
|
||||
}
|
||||
return fmt.Sprintf("rosetta: (%d) %s", e.rosErr.Code, e.rosErr.Message)
|
||||
}
|
||||
|
||||
// Is implements errors.Is for *Error, two errors are considered equal
|
||||
// if their error codes are identical
|
||||
func (e *Error) Is(err error) bool {
|
||||
// assert it can be casted
|
||||
rosErr, ok := err.(*Error)
|
||||
if rosErr == nil || !ok {
|
||||
return false
|
||||
}
|
||||
// check that both *Error's are correctly initialized to avoid dereference panics
|
||||
if rosErr.rosErr == nil || e.rosErr == nil {
|
||||
return false
|
||||
}
|
||||
// messages are equal if their error codes match
|
||||
return rosErr.rosErr.Code == e.rosErr.Code
|
||||
}
|
||||
|
||||
// WrapError wraps the rosetta error with additional context
|
||||
func WrapError(err *Error, msg string) *Error {
|
||||
return &Error{rosErr: &types.Error{
|
||||
Code: err.rosErr.Code,
|
||||
Message: err.rosErr.Message,
|
||||
Description: err.rosErr.Description,
|
||||
Retriable: err.rosErr.Retriable,
|
||||
Details: map[string]interface{}{
|
||||
"info": msg,
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
// ToRosetta attempts to converting an error into a rosetta
|
||||
// error, if the error cannot be converted it will be parsed as unknown
|
||||
func ToRosetta(err error) *types.Error {
|
||||
// if it's null or not known
|
||||
rosErr, ok := err.(*Error)
|
||||
if rosErr == nil || !ok {
|
||||
return ToRosetta(WrapError(ErrUnknown, ErrUnknown.Error()))
|
||||
}
|
||||
return rosErr.rosErr
|
||||
}
|
||||
|
||||
// FromGRPCToRosettaError converts a gRPC error to rosetta error
|
||||
func FromGRPCToRosettaError(err error) *Error {
|
||||
status, ok := grpcstatus.FromError(err)
|
||||
if !ok {
|
||||
return WrapError(ErrUnknown, err.Error())
|
||||
}
|
||||
switch status.Code() {
|
||||
case grpccodes.NotFound:
|
||||
return WrapError(ErrNotFound, status.Message())
|
||||
case grpccodes.FailedPrecondition:
|
||||
return WrapError(ErrBadArgument, status.Message())
|
||||
case grpccodes.InvalidArgument:
|
||||
return WrapError(ErrBadArgument, status.Message())
|
||||
case grpccodes.Internal:
|
||||
return WrapError(ErrInternal, status.Message())
|
||||
default:
|
||||
return WrapError(ErrUnknown, status.Message())
|
||||
}
|
||||
}
|
||||
|
||||
func RegisterError(code int32, message string, retryable bool, description string) *Error {
|
||||
e := &Error{rosErr: &types.Error{
|
||||
Code: code,
|
||||
Message: message,
|
||||
Description: &description,
|
||||
Retriable: retryable,
|
||||
Details: nil,
|
||||
}}
|
||||
registry.add(e)
|
||||
return e
|
||||
}
|
||||
|
||||
// Default error list
|
||||
var (
|
||||
// ErrUnknown defines an unknown error, if this is returned it means
|
||||
// the library is ignoring an error
|
||||
ErrUnknown = RegisterError(0, "unknown", false, "unknown error")
|
||||
// ErrOffline is returned when there is an attempt to query an endpoint in offline mode
|
||||
ErrOffline = RegisterError(1, "cannot query endpoint in offline mode", false, "returned when querying an online endpoint in offline mode")
|
||||
// ErrNetworkNotSupported is returned when there is an attempt to query a network which is not supported
|
||||
ErrNetworkNotSupported = RegisterError(2, "network is not supported", false, "returned when querying a non supported network")
|
||||
// ErrCodec is returned when there's an error while marshalling or unmarshalling data
|
||||
ErrCodec = RegisterError(3, "encode/decode error", true, "returned when there are errors encoding or decoding information to and from the node")
|
||||
// ErrInvalidOperation is returned when the operation supplied to rosetta is not a valid one
|
||||
ErrInvalidOperation = RegisterError(4, "invalid operation", false, "returned when the operation is not valid")
|
||||
// ErrInvalidTransaction is returned when the provided hex bytes of a TX are not valid
|
||||
ErrInvalidTransaction = RegisterError(5, "invalid transaction", false, "returned when the transaction is invalid")
|
||||
// ErrInvalidAddress is returned when the byte of the address are bad
|
||||
ErrInvalidAddress = RegisterError(7, "invalid address", false, "returned when the address is malformed")
|
||||
// ErrInvalidPubkey is returned when the public key is invalid
|
||||
ErrInvalidPubkey = RegisterError(8, "invalid pubkey", false, "returned when the public key is invalid")
|
||||
// ErrInterpreting is returned when there are errors interpreting the data from the node, most likely related to breaking changes, version incompatibilities
|
||||
ErrInterpreting = RegisterError(9, "error interpreting data from node", false, "returned when there are issues interpreting requests or response from node")
|
||||
ErrInvalidMemo = RegisterError(11, "invalid memo", false, "returned when the memo is invalid")
|
||||
// ErrBadArgument is returned when the request is malformed
|
||||
ErrBadArgument = RegisterError(400, "bad argument", false, "request is malformed")
|
||||
// ErrNotFound is returned when the required object was not found
|
||||
// retry is set to true because something that is not found now
|
||||
// might be found later, example: a TX
|
||||
ErrNotFound = RegisterError(404, "not found", true, "returned when the node does not find what the client is asking for")
|
||||
// ErrInternal is returned when the node is experiencing internal errors
|
||||
ErrInternal = RegisterError(500, "internal error", false, "returned when the node experiences internal errors")
|
||||
// ErrBadGateway is returned when there are problems interacting with the nodes
|
||||
ErrBadGateway = RegisterError(502, "bad gateway", true, "return when the node is unreachable")
|
||||
// ErrNotImplemented is returned when a method is not implemented yet
|
||||
ErrNotImplemented = RegisterError(14, "not implemented", false, "returned when querying an endpoint which is not implemented")
|
||||
// ErrUnsupportedCurve is returned when the curve specified is not supported
|
||||
ErrUnsupportedCurve = RegisterError(15, "unsupported curve, expected secp256k1", false, "returned when using an unsupported crypto curve")
|
||||
)
|
||||
@@ -0,0 +1,68 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRegisterError(t *testing.T) {
|
||||
var error *Error
|
||||
// this is the number of errors registered by default in errors.go
|
||||
registeredErrorsCount := 16
|
||||
assert.Equal(t, len(registry.list()), registeredErrorsCount)
|
||||
assert.ElementsMatch(t, registry.list(), ListErrors())
|
||||
// add a new Error
|
||||
error = RegisterError(69, "nice!", false, "nice!")
|
||||
assert.NotNil(t, error)
|
||||
// now we have a new error
|
||||
registeredErrorsCount++
|
||||
assert.Equal(t, len(ListErrors()), registeredErrorsCount)
|
||||
// re-register an error should not change anything
|
||||
error = RegisterError(69, "nice!", false, "nice!")
|
||||
assert.Equal(t, len(ListErrors()), registeredErrorsCount)
|
||||
|
||||
// test sealing
|
||||
assert.Equal(t, registry.sealed, false)
|
||||
errors := SealAndListErrors()
|
||||
assert.Equal(t, registry.sealed, true)
|
||||
assert.Equal(t, len(errors), registeredErrorsCount)
|
||||
// add a new error on a sealed registry
|
||||
error = RegisterError(1024, "bytes", false, "bytes")
|
||||
assert.NotNil(t, error)
|
||||
|
||||
}
|
||||
|
||||
func TestError_Error(t *testing.T) {
|
||||
var error *Error
|
||||
// nil cases
|
||||
assert.False(t, ErrOffline.Is(error))
|
||||
error = &Error{}
|
||||
assert.False(t, ErrOffline.Is(error))
|
||||
// wrong type
|
||||
assert.False(t, ErrOffline.Is(&MyError{}))
|
||||
// test with wrapping an error
|
||||
error = WrapError(ErrOffline, "offline")
|
||||
assert.True(t, ErrOffline.Is(error))
|
||||
|
||||
// test equality
|
||||
assert.False(t, ErrOffline.Is(ErrBadGateway))
|
||||
assert.True(t, ErrBadGateway.Is(ErrBadGateway))
|
||||
}
|
||||
|
||||
func TestToRosetta(t *testing.T) {
|
||||
var error *Error
|
||||
// nil case
|
||||
assert.NotNil(t, ToRosetta(error))
|
||||
// wrong type
|
||||
assert.NotNil(t, ToRosetta(&MyError{}))
|
||||
}
|
||||
|
||||
type MyError struct {
|
||||
}
|
||||
|
||||
func (e *MyError) Error() string {
|
||||
return ""
|
||||
}
|
||||
func (e *MyError) Is(err error) bool {
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/coinbase/rosetta-sdk-go/types"
|
||||
)
|
||||
|
||||
type errorRegistry struct {
|
||||
mu *sync.RWMutex
|
||||
sealed bool
|
||||
errors map[int32]*types.Error
|
||||
}
|
||||
|
||||
func (r *errorRegistry) add(err *Error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if r.sealed {
|
||||
_, _ = fmt.Fprintln(os.Stderr, "[ROSETTA] WARNING: attempts to register errors after seal will be ignored")
|
||||
}
|
||||
if _, ok := r.errors[err.rosErr.Code]; ok {
|
||||
_, _ = fmt.Fprintln(os.Stderr, "[ROSETTA] WARNING: attempts to register an already registered error will be ignored, code: ", err.rosErr.Code)
|
||||
}
|
||||
r.errors[err.rosErr.Code] = err.rosErr
|
||||
}
|
||||
|
||||
func (r errorRegistry) list() []*types.Error {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
rosErrs := make([]*types.Error, 0, len(registry.errors))
|
||||
for _, v := range r.errors {
|
||||
rosErrs = append(rosErrs, v)
|
||||
}
|
||||
return rosErrs
|
||||
}
|
||||
|
||||
func (r *errorRegistry) seal() {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.sealed = true
|
||||
}
|
||||
|
||||
var registry = errorRegistry{
|
||||
mu: new(sync.RWMutex),
|
||||
errors: make(map[int32]*types.Error),
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
|
||||
"github.com/coinbase/rosetta-sdk-go/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||
)
|
||||
|
||||
// ConstructionCombine Combine creates a network-specific transaction from an unsigned transaction
|
||||
// and an array of provided signatures. The signed transaction returned from this method will be
|
||||
// sent to the /construction/submit endpoint by the caller.
|
||||
func (on OnlineNetwork) ConstructionCombine(ctx context.Context, request *types.ConstructionCombineRequest) (*types.ConstructionCombineResponse, *types.Error) {
|
||||
txBytes, err := hex.DecodeString(request.UnsignedTransaction)
|
||||
if err != nil {
|
||||
return nil, errors.ToRosetta(err)
|
||||
}
|
||||
|
||||
signedTx, err := on.client.SignedTx(ctx, txBytes, request.Signatures)
|
||||
if err != nil {
|
||||
return nil, errors.ToRosetta(err)
|
||||
}
|
||||
|
||||
return &types.ConstructionCombineResponse{
|
||||
SignedTransaction: hex.EncodeToString(signedTx),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ConstructionDerive Derive returns the AccountIdentifier associated with a public key.
|
||||
func (on OnlineNetwork) ConstructionDerive(_ context.Context, request *types.ConstructionDeriveRequest) (*types.ConstructionDeriveResponse, *types.Error) {
|
||||
account, err := on.client.AccountIdentifierFromPublicKey(request.PublicKey)
|
||||
if err != nil {
|
||||
return nil, errors.ToRosetta(err)
|
||||
}
|
||||
return &types.ConstructionDeriveResponse{
|
||||
AccountIdentifier: account,
|
||||
Metadata: nil,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ConstructionHash TransactionHash returns the network-specific transaction hash for a signed
|
||||
// transaction.
|
||||
func (on OnlineNetwork) ConstructionHash(ctx context.Context, request *types.ConstructionHashRequest) (*types.TransactionIdentifierResponse, *types.Error) {
|
||||
bz, err := hex.DecodeString(request.SignedTransaction)
|
||||
if err != nil {
|
||||
return nil, errors.ToRosetta(errors.WrapError(errors.ErrInvalidTransaction, "error decoding tx"))
|
||||
}
|
||||
|
||||
hash := sha256.Sum256(bz)
|
||||
bzHash := hash[:]
|
||||
hashString := hex.EncodeToString(bzHash)
|
||||
|
||||
return &types.TransactionIdentifierResponse{
|
||||
TransactionIdentifier: &types.TransactionIdentifier{
|
||||
Hash: strings.ToUpper(hashString),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ConstructionMetadata Get any information required to construct a transaction for a specific
|
||||
// network (i.e. ChainID, Gas, Memo, ...).
|
||||
func (on OnlineNetwork) ConstructionMetadata(ctx context.Context, request *types.ConstructionMetadataRequest) (*types.ConstructionMetadataResponse, *types.Error) {
|
||||
metadata, err := on.client.ConstructionMetadataFromOptions(ctx, request.Options)
|
||||
if err != nil {
|
||||
return nil, errors.ToRosetta(err)
|
||||
}
|
||||
|
||||
return &types.ConstructionMetadataResponse{
|
||||
Metadata: metadata,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ConstructionParse Parse is called on both unsigned and signed transactions to understand the
|
||||
// intent of the formulated transaction. This is run as a sanity check before signing (after
|
||||
// /construction/payloads) and before broadcast (after /construction/combine).
|
||||
func (on OnlineNetwork) ConstructionParse(ctx context.Context, request *types.ConstructionParseRequest) (*types.ConstructionParseResponse, *types.Error) {
|
||||
txBytes, err := hex.DecodeString(request.Transaction)
|
||||
if err != nil {
|
||||
err := errors.WrapError(errors.ErrInvalidTransaction, err.Error())
|
||||
return nil, errors.ToRosetta(err)
|
||||
}
|
||||
ops, signers, err := on.client.TxOperationsAndSignersAccountIdentifiers(request.Signed, txBytes)
|
||||
if err != nil {
|
||||
return nil, errors.ToRosetta(err)
|
||||
}
|
||||
return &types.ConstructionParseResponse{
|
||||
Operations: ops,
|
||||
AccountIdentifierSigners: signers,
|
||||
Metadata: nil,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
// ConstructionPayloads Payloads is called with an array of operations and the response from
|
||||
// /construction/metadata. It returns an unsigned transaction blob and a collection of payloads that
|
||||
// must be signed by particular AccountIdentifiers using a certain SignatureType.
|
||||
func (on OnlineNetwork) ConstructionPayloads(ctx context.Context, request *types.ConstructionPayloadsRequest) (*types.ConstructionPayloadsResponse, *types.Error) {
|
||||
payload, err := on.client.ConstructionPayload(ctx, request)
|
||||
if err != nil {
|
||||
return nil, errors.ToRosetta(err)
|
||||
}
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
// ConstructionPreprocess Preprocess is called prior to /construction/payloads to construct a
|
||||
// request for any metadata that is needed for transaction construction given (i.e. account nonce).
|
||||
func (on OnlineNetwork) ConstructionPreprocess(ctx context.Context, request *types.ConstructionPreprocessRequest) (*types.ConstructionPreprocessResponse, *types.Error) {
|
||||
options, err := on.client.PreprocessOperationsToOptions(ctx, request)
|
||||
if err != nil {
|
||||
return nil, errors.ToRosetta(err)
|
||||
}
|
||||
|
||||
return options, nil
|
||||
}
|
||||
|
||||
// ConstructionSubmit Submit a pre-signed transaction to the node. This call does not block on the
|
||||
// transaction being included in a block. Rather, it returns immediately with an indication of
|
||||
// whether or not the transaction was included in the mempool.
|
||||
func (on OnlineNetwork) ConstructionSubmit(ctx context.Context, request *types.ConstructionSubmitRequest) (*types.TransactionIdentifierResponse, *types.Error) {
|
||||
txBytes, err := hex.DecodeString(request.SignedTransaction)
|
||||
if err != nil {
|
||||
return nil, errors.ToRosetta(err)
|
||||
}
|
||||
|
||||
res, meta, err := on.client.PostTx(txBytes)
|
||||
if err != nil {
|
||||
return nil, errors.ToRosetta(err)
|
||||
}
|
||||
|
||||
return &types.TransactionIdentifierResponse{
|
||||
TransactionIdentifier: res,
|
||||
Metadata: meta,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coinbase/rosetta-sdk-go/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||
crgtypes "github.com/cosmos/cosmos-sdk/server/rosetta/lib/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:
|
||||
block, err = on.client.BlockByHeight(ctx, nil)
|
||||
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
|
||||
)
|
||||
// block identifier is assumed not to be nil as rosetta will do this check for us
|
||||
// check if we have to query via hash or block number
|
||||
switch {
|
||||
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:
|
||||
err := errors.WrapError(errors.ErrBadArgument, "at least one of hash or index needs to be specified")
|
||||
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) {
|
||||
block, err := on.client.BlockByHeight(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, errors.ToRosetta(err)
|
||||
}
|
||||
|
||||
peers, err := on.client.Peers(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.ToRosetta(err)
|
||||
}
|
||||
|
||||
syncStatus, err := on.client.Status(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
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coinbase/rosetta-sdk-go/types"
|
||||
|
||||
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||
crgtypes "github.com/cosmos/cosmos-sdk/server/rosetta/lib/types"
|
||||
)
|
||||
|
||||
// NewOffline instantiates the instance of an offline network
|
||||
// whilst the offline network does not support the DataAPI,
|
||||
// it supports a subset of the construction API.
|
||||
func NewOffline(network *types.NetworkIdentifier, client crgtypes.Client) (crgtypes.API, error) {
|
||||
return OfflineNetwork{
|
||||
OnlineNetwork{
|
||||
client: client,
|
||||
network: network,
|
||||
networkOptions: networkOptionsFromClient(client),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// OfflineNetwork implements an offline data API
|
||||
// which is basically a data API that constantly
|
||||
// returns errors, because it cannot be used if offline
|
||||
type OfflineNetwork struct {
|
||||
OnlineNetwork
|
||||
}
|
||||
|
||||
// Implement DataAPI in offline mode, which means no method is available
|
||||
func (o OfflineNetwork) AccountBalance(_ context.Context, _ *types.AccountBalanceRequest) (*types.AccountBalanceResponse, *types.Error) {
|
||||
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||
}
|
||||
|
||||
func (o OfflineNetwork) Block(_ context.Context, _ *types.BlockRequest) (*types.BlockResponse, *types.Error) {
|
||||
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||
}
|
||||
|
||||
func (o OfflineNetwork) BlockTransaction(_ context.Context, _ *types.BlockTransactionRequest) (*types.BlockTransactionResponse, *types.Error) {
|
||||
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||
}
|
||||
|
||||
func (o OfflineNetwork) Mempool(_ context.Context, _ *types.NetworkRequest) (*types.MempoolResponse, *types.Error) {
|
||||
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||
}
|
||||
|
||||
func (o OfflineNetwork) MempoolTransaction(_ context.Context, _ *types.MempoolTransactionRequest) (*types.MempoolTransactionResponse, *types.Error) {
|
||||
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||
}
|
||||
|
||||
func (o OfflineNetwork) NetworkStatus(_ context.Context, _ *types.NetworkRequest) (*types.NetworkStatusResponse, *types.Error) {
|
||||
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||
}
|
||||
|
||||
func (o OfflineNetwork) ConstructionSubmit(_ context.Context, _ *types.ConstructionSubmitRequest) (*types.TransactionIdentifierResponse, *types.Error) {
|
||||
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||
}
|
||||
|
||||
func (o OfflineNetwork) ConstructionMetadata(_ context.Context, _ *types.ConstructionMetadataRequest) (*types.ConstructionMetadataResponse, *types.Error) {
|
||||
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/coinbase/rosetta-sdk-go/types"
|
||||
|
||||
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||
crgtypes "github.com/cosmos/cosmos-sdk/server/rosetta/lib/types"
|
||||
)
|
||||
|
||||
// genesisBlockFetchTimeout defines a timeout to fetch the genesis block
|
||||
const genesisBlockFetchTimeout = 15 * time.Second
|
||||
|
||||
// NewOnlineNetwork builds a single network adapter.
|
||||
// It will get the Genesis block on the beginning to avoid calling it everytime.
|
||||
func NewOnlineNetwork(network *types.NetworkIdentifier, client crgtypes.Client) (crgtypes.API, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), genesisBlockFetchTimeout)
|
||||
defer cancel()
|
||||
|
||||
var genesisHeight int64 = 1
|
||||
block, err := client.BlockByHeight(ctx, &genesisHeight)
|
||||
if err != nil {
|
||||
return OnlineNetwork{}, err
|
||||
}
|
||||
|
||||
return OnlineNetwork{
|
||||
client: client,
|
||||
network: network,
|
||||
networkOptions: networkOptionsFromClient(client),
|
||||
genesisBlockIdentifier: block.Block,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// OnlineNetwork groups together all the components required for the full rosetta implementation
|
||||
type OnlineNetwork struct {
|
||||
client crgtypes.Client // used to query cosmos app + tendermint
|
||||
|
||||
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
|
||||
func networkOptionsFromClient(client crgtypes.Client) *types.NetworkOptionsResponse {
|
||||
return &types.NetworkOptionsResponse{
|
||||
Version: &types.Version{
|
||||
RosettaVersion: crgtypes.SpecVersion,
|
||||
NodeVersion: client.Version(),
|
||||
},
|
||||
Allow: &types.Allow{
|
||||
OperationStatuses: client.OperationStatuses(),
|
||||
OperationTypes: client.SupportedOperations(),
|
||||
Errors: crgerrs.SealAndListErrors(),
|
||||
HistoricalBalanceLookup: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
assert "github.com/coinbase/rosetta-sdk-go/asserter"
|
||||
"github.com/coinbase/rosetta-sdk-go/server"
|
||||
"github.com/coinbase/rosetta-sdk-go/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server/rosetta/lib/internal/service"
|
||||
crgtypes "github.com/cosmos/cosmos-sdk/server/rosetta/lib/types"
|
||||
)
|
||||
|
||||
const DefaultRetries = 5
|
||||
const DefaultRetryWait = 5 * time.Second
|
||||
|
||||
// Settings define the rosetta server settings
|
||||
type Settings struct {
|
||||
// Network contains the information regarding the network
|
||||
Network *types.NetworkIdentifier
|
||||
// Client is the online API handler
|
||||
Client crgtypes.Client
|
||||
// Listen is the address the handler will listen at
|
||||
Listen string
|
||||
// Offline defines if the rosetta service should be exposed in offline mode
|
||||
Offline bool
|
||||
// Retries is the number of readiness checks that will be attempted when instantiating the handler
|
||||
// valid only for online API
|
||||
Retries int
|
||||
// RetryWait is the time that will be waited between retries
|
||||
RetryWait time.Duration
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
h http.Handler
|
||||
addr string
|
||||
}
|
||||
|
||||
func (h Server) Start() error {
|
||||
return http.ListenAndServe(h.addr, h.h)
|
||||
}
|
||||
|
||||
func NewServer(settings Settings) (Server, error) {
|
||||
asserter, err := assert.NewServer(
|
||||
settings.Client.SupportedOperations(),
|
||||
true,
|
||||
[]*types.NetworkIdentifier{settings.Network},
|
||||
nil,
|
||||
false,
|
||||
)
|
||||
if err != nil {
|
||||
return Server{}, fmt.Errorf("cannot build asserter: %w", err)
|
||||
}
|
||||
|
||||
var (
|
||||
adapter crgtypes.API
|
||||
)
|
||||
switch settings.Offline {
|
||||
case true:
|
||||
adapter, err = newOfflineAdapter(settings)
|
||||
case false:
|
||||
adapter, err = newOnlineAdapter(settings)
|
||||
}
|
||||
if err != nil {
|
||||
return Server{}, err
|
||||
}
|
||||
h := server.NewRouter(
|
||||
server.NewAccountAPIController(adapter, asserter),
|
||||
server.NewBlockAPIController(adapter, asserter),
|
||||
server.NewNetworkAPIController(adapter, asserter),
|
||||
server.NewMempoolAPIController(adapter, asserter),
|
||||
server.NewConstructionAPIController(adapter, asserter),
|
||||
)
|
||||
|
||||
return Server{
|
||||
h: h,
|
||||
addr: settings.Listen,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func newOfflineAdapter(settings Settings) (crgtypes.API, error) {
|
||||
if settings.Client == nil {
|
||||
return nil, fmt.Errorf("client is nil")
|
||||
}
|
||||
return service.NewOffline(settings.Network, settings.Client)
|
||||
}
|
||||
|
||||
func newOnlineAdapter(settings Settings) (crgtypes.API, error) {
|
||||
if settings.Client == nil {
|
||||
return nil, fmt.Errorf("client is nil")
|
||||
}
|
||||
if settings.Retries <= 0 {
|
||||
settings.Retries = DefaultRetries
|
||||
}
|
||||
if settings.RetryWait == 0 {
|
||||
settings.RetryWait = DefaultRetryWait
|
||||
}
|
||||
|
||||
var err error
|
||||
err = settings.Client.Bootstrap()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < settings.Retries; i++ {
|
||||
err = settings.Client.Ready()
|
||||
if err != nil {
|
||||
time.Sleep(settings.RetryWait)
|
||||
continue
|
||||
}
|
||||
return service.NewOnlineNetwork(settings.Network, settings.Client)
|
||||
}
|
||||
return nil, fmt.Errorf("maximum number of retries exceeded, last error: %w", err)
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/coinbase/rosetta-sdk-go/server"
|
||||
"github.com/coinbase/rosetta-sdk-go/types"
|
||||
)
|
||||
|
||||
// SpecVersion defines the specification of rosetta
|
||||
const SpecVersion = ""
|
||||
|
||||
// NetworkInformationProvider defines the interface used to provide information regarding
|
||||
// the network and the version of the cosmos sdk used
|
||||
type NetworkInformationProvider interface {
|
||||
// SupportedOperations lists the operations supported by the implementation
|
||||
SupportedOperations() []string
|
||||
// OperationStatuses returns the list of statuses supported by the implementation
|
||||
OperationStatuses() []*types.OperationStatus
|
||||
// Version returns the version of the node
|
||||
Version() string
|
||||
}
|
||||
|
||||
// Client defines the API the client implementation should provide.
|
||||
type Client interface {
|
||||
// Bootstrap Needed if the client needs to perform some action before connecting.
|
||||
Bootstrap() error
|
||||
// Ready checks if the servicer constraints for queries are satisfied
|
||||
// for example the node might still not be ready, it's useful in process
|
||||
// when the rosetta instance might come up before the node itself
|
||||
// the servicer must return nil if the node is ready
|
||||
Ready() error
|
||||
|
||||
// Data API
|
||||
|
||||
// Balances fetches the balance of the given address
|
||||
// if height is not nil, then the balance will be displayed
|
||||
// at the provided height, otherwise last block balance will be returned
|
||||
Balances(ctx context.Context, addr string, height *int64) ([]*types.Amount, error)
|
||||
// BlockByHash gets a block and its transaction at the provided height
|
||||
BlockByHash(ctx context.Context, hash string) (BlockResponse, error)
|
||||
// BlockByHeight gets a block given its height, if height is nil then last block is returned
|
||||
BlockByHeight(ctx context.Context, height *int64) (BlockResponse, error)
|
||||
// BlockTransactionsByHash gets the block, parent block and transactions
|
||||
// given the block hash.
|
||||
BlockTransactionsByHash(ctx context.Context, hash string) (BlockTransactionsResponse, error)
|
||||
// BlockTransactionsByHeight gets the block, parent block and transactions
|
||||
// given the block hash.
|
||||
BlockTransactionsByHeight(ctx context.Context, height *int64) (BlockTransactionsResponse, error)
|
||||
// GetTx gets a transaction given its hash
|
||||
GetTx(ctx context.Context, hash string) (*types.Transaction, error)
|
||||
// GetUnconfirmedTx gets an unconfirmed Tx given its hash
|
||||
// NOTE(fdymylja): NOT IMPLEMENTED YET!
|
||||
GetUnconfirmedTx(ctx context.Context, hash string) (*types.Transaction, error)
|
||||
// Mempool returns the list of the current non confirmed transactions
|
||||
Mempool(ctx context.Context) ([]*types.TransactionIdentifier, error)
|
||||
// Peers gets the peers currently connected to the node
|
||||
Peers(ctx context.Context) ([]*types.Peer, error)
|
||||
// Status returns the node status, such as sync data, version etc
|
||||
Status(ctx context.Context) (*types.SyncStatus, error)
|
||||
|
||||
// Construction API
|
||||
|
||||
// PostTx posts txBytes to the node and returns the transaction identifier plus metadata related
|
||||
// to the transaction itself.
|
||||
PostTx(txBytes []byte) (res *types.TransactionIdentifier, meta map[string]interface{}, err error)
|
||||
// ConstructionMetadataFromOptions builds metadata map from an option map
|
||||
ConstructionMetadataFromOptions(ctx context.Context, options map[string]interface{}) (meta map[string]interface{}, err error)
|
||||
OfflineClient
|
||||
}
|
||||
|
||||
// OfflineClient defines the functionalities supported without having access to the node
|
||||
type OfflineClient interface {
|
||||
NetworkInformationProvider
|
||||
// SignedTx returns the signed transaction given the tx bytes (msgs) plus the signatures
|
||||
SignedTx(ctx context.Context, txBytes []byte, sigs []*types.Signature) (signedTxBytes []byte, err error)
|
||||
// TxOperationsAndSignersAccountIdentifiers returns the operations related to a transaction and the account
|
||||
// identifiers if the transaction is signed
|
||||
TxOperationsAndSignersAccountIdentifiers(signed bool, hexBytes []byte) (ops []*types.Operation, signers []*types.AccountIdentifier, err error)
|
||||
// ConstructionPayload returns the construction payload given the request
|
||||
ConstructionPayload(ctx context.Context, req *types.ConstructionPayloadsRequest) (resp *types.ConstructionPayloadsResponse, err error)
|
||||
// PreprocessOperationsToOptions returns the options given the preprocess operations
|
||||
PreprocessOperationsToOptions(ctx context.Context, req *types.ConstructionPreprocessRequest) (resp *types.ConstructionPreprocessResponse, err error)
|
||||
// AccountIdentifierFromPublicKey returns the account identifier given the public key
|
||||
AccountIdentifierFromPublicKey(pubKey *types.PublicKey) (*types.AccountIdentifier, error)
|
||||
}
|
||||
|
||||
type BlockTransactionsResponse struct {
|
||||
BlockResponse
|
||||
Transactions []*types.Transaction
|
||||
}
|
||||
|
||||
type BlockResponse struct {
|
||||
Block *types.BlockIdentifier
|
||||
ParentBlock *types.BlockIdentifier
|
||||
MillisecondTimestamp int64
|
||||
TxCount int64
|
||||
}
|
||||
|
||||
// API defines the exposed APIs
|
||||
// if the service is online
|
||||
type API interface {
|
||||
DataAPI
|
||||
ConstructionAPI
|
||||
}
|
||||
|
||||
// DataAPI defines the full data API implementation
|
||||
type DataAPI interface {
|
||||
server.NetworkAPIServicer
|
||||
server.AccountAPIServicer
|
||||
server.BlockAPIServicer
|
||||
server.MempoolAPIServicer
|
||||
}
|
||||
|
||||
var _ server.ConstructionAPIServicer = ConstructionAPI(nil)
|
||||
|
||||
// ConstructionAPI defines the full construction API with
|
||||
// the online and offline endpoints
|
||||
type ConstructionAPI interface {
|
||||
ConstructionOnlineAPI
|
||||
ConstructionOfflineAPI
|
||||
}
|
||||
|
||||
// ConstructionOnlineAPI defines the construction methods
|
||||
// allowed in an online implementation
|
||||
type ConstructionOnlineAPI interface {
|
||||
ConstructionMetadata(
|
||||
context.Context,
|
||||
*types.ConstructionMetadataRequest,
|
||||
) (*types.ConstructionMetadataResponse, *types.Error)
|
||||
ConstructionSubmit(
|
||||
context.Context,
|
||||
*types.ConstructionSubmitRequest,
|
||||
) (*types.TransactionIdentifierResponse, *types.Error)
|
||||
}
|
||||
|
||||
// ConstructionOfflineAPI defines the construction methods
|
||||
// allowed
|
||||
type ConstructionOfflineAPI interface {
|
||||
ConstructionCombine(
|
||||
context.Context,
|
||||
*types.ConstructionCombineRequest,
|
||||
) (*types.ConstructionCombineResponse, *types.Error)
|
||||
ConstructionDerive(
|
||||
context.Context,
|
||||
*types.ConstructionDeriveRequest,
|
||||
) (*types.ConstructionDeriveResponse, *types.Error)
|
||||
ConstructionHash(
|
||||
context.Context,
|
||||
*types.ConstructionHashRequest,
|
||||
) (*types.TransactionIdentifierResponse, *types.Error)
|
||||
ConstructionParse(
|
||||
context.Context,
|
||||
*types.ConstructionParseRequest,
|
||||
) (*types.ConstructionParseResponse, *types.Error)
|
||||
ConstructionPayloads(
|
||||
context.Context,
|
||||
*types.ConstructionPayloadsRequest,
|
||||
) (*types.ConstructionPayloadsResponse, *types.Error)
|
||||
ConstructionPreprocess(
|
||||
context.Context,
|
||||
*types.ConstructionPreprocessRequest,
|
||||
) (*types.ConstructionPreprocessResponse, *types.Error)
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors"
|
||||
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||
)
|
||||
|
||||
// timeToMilliseconds converts time to milliseconds timestamp
|
||||
|
||||
+3
-3
@@ -9,14 +9,11 @@ import (
|
||||
"runtime/pprof"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
crgserver "github.com/tendermint/cosmos-rosetta-gateway/server"
|
||||
"github.com/tendermint/tendermint/abci/server"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
@@ -26,6 +23,9 @@ import (
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
"github.com/tendermint/tendermint/rpc/client/local"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
||||
crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/server/api"
|
||||
|
||||
Reference in New Issue
Block a user