Skip to content

Commit

Permalink
Merge pull request #7854 from cosmos/sahith/impl-cons
Browse files Browse the repository at this point in the history
Add construction endpoints
  • Loading branch information
jgimeno authored Nov 16, 2020
2 parents eaebebd + 88b5e24 commit 9e46fb3
Show file tree
Hide file tree
Showing 6 changed files with 436 additions and 27 deletions.
62 changes: 47 additions & 15 deletions server/rosetta/cosmos/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ type Client struct {

ir codectypes.InterfaceRegistry

client client.Context
clientCtx client.Context
}

// NewSingle instantiates a single network client
Expand All @@ -86,29 +86,53 @@ func NewSingle(grpcEndpoint, tendermintEndpoint string, optsFunc ...OptionFunc)

authClient := auth.NewQueryClient(grpcConn)
bankClient := bank.NewQueryClient(grpcConn)

// NodeURI and Client are set from here otherwise
// WitNodeURI will require to create a new client
// it's done here because WithNodeURI panics if
// connection to tendermint node fails
clientContext := client.Context{
clientCtx := client.Context{
Client: tmRPC,
NodeURI: tendermintEndpoint,
}
clientContext = clientContext.
clientCtx = clientCtx.
WithJSONMarshaler(opts.cdc).
WithInterfaceRegistry(opts.interfaceRegistry).
WithTxConfig(tx.NewTxConfig(opts.cdc, tx.DefaultSignModes)).
WithAccountRetriever(auth.AccountRetriever{}).
WithBroadcastMode(flags.BroadcastBlock)

return &Client{
auth: authClient,
bank: bankClient,
client: clientContext,
ir: opts.interfaceRegistry,
auth: authClient,
bank: bankClient,
clientCtx: clientCtx,
ir: opts.interfaceRegistry,
}, nil
}

func (c *Client) AccountInfo(ctx context.Context, addr string, height *int64) (auth.AccountI, error) {
// if height is set, send height instruction to account
if height != nil {
strHeight := strconv.FormatInt(*height, 10)
ctx = metadata.AppendToOutgoingContext(ctx, grpctypes.GRPCBlockHeightHeader, strHeight)
}
// retrieve account info
accountInfo, err := c.auth.Account(ctx, &auth.QueryAccountRequest{
Address: addr,
})
if err != nil {
return nil, rosetta.FromGRPCToRosettaError(err)
}
// success
var account auth.AccountI
err = c.ir.UnpackAny(accountInfo.Account, &account)
if err != nil {
return nil, rosetta.WrapError(rosetta.ErrCodec, err.Error())
}

return account, nil
}

func (c *Client) Balances(ctx context.Context, addr string, height *int64) ([]sdk.Coin, error) {
if height != nil {
strHeight := strconv.FormatInt(*height, 10)
Expand All @@ -130,7 +154,7 @@ func (c *Client) BlockByHash(ctx context.Context, hash string) (*tmtypes.ResultB
return nil, nil, rosetta.WrapError(rosetta.ErrBadArgument, fmt.Sprintf("invalid block hash: %s", err))
}

block, err := c.client.Client.BlockByHash(ctx, bHash)
block, err := c.clientCtx.Client.BlockByHash(ctx, bHash)
if err != nil {
return nil, nil, rosetta.WrapError(rosetta.ErrUnknown, err.Error()) // can be either a connection error or bad argument?
}
Expand All @@ -144,7 +168,7 @@ func (c *Client) BlockByHash(ctx context.Context, hash string) (*tmtypes.ResultB

// BlockByHeight returns the block and the transactions contained inside it given its height
func (c *Client) BlockByHeight(ctx context.Context, height *int64) (*tmtypes.ResultBlock, []*rosetta.SdkTxWithHash, error) {
block, err := c.client.Client.Block(ctx, height)
block, err := c.clientCtx.Client.Block(ctx, height)
if err != nil {
return nil, nil, rosetta.WrapError(rosetta.ErrUnknown, err.Error())
}
Expand All @@ -167,12 +191,12 @@ func (c *Client) Coins(ctx context.Context) (sdk.Coins, error) {
// ListTransactionsInBlock returns the list of the transactions in a block given its height
func (c *Client) ListTransactionsInBlock(ctx context.Context, height int64) ([]*rosetta.SdkTxWithHash, error) {
txQuery := fmt.Sprintf(`tx.height=%d`, height)
txList, err := c.client.Client.TxSearch(ctx, txQuery, true, nil, nil, "")
txList, err := c.clientCtx.Client.TxSearch(ctx, txQuery, true, nil, nil, "")
if err != nil {
return nil, rosetta.WrapError(rosetta.ErrUnknown, err.Error())
}

sdkTxs, err := conversion.TmResultTxsToSdkTxs(c.client.TxConfig.TxDecoder(), txList.Txs)
sdkTxs, err := conversion.TmResultTxsToSdkTxs(c.clientCtx.TxConfig.TxDecoder(), txList.Txs)
if err != nil {
return nil, err
}
Expand All @@ -181,7 +205,7 @@ func (c *Client) ListTransactionsInBlock(ctx context.Context, height int64) ([]*

// GetTx returns a transaction given its hash
func (c *Client) GetTx(_ context.Context, hash string) (sdk.Tx, error) {
txResp, err := authclient.QueryTx(c.client, hash)
txResp, err := authclient.QueryTx(c.clientCtx, hash)
if err != nil {
return nil, rosetta.WrapError(rosetta.ErrUnknown, err.Error())
}
Expand All @@ -201,7 +225,7 @@ func (c *Client) GetUnconfirmedTx(_ context.Context, hash string) (sdk.Tx, error

// Mempool returns the unconfirmed transactions in the mempool
func (c *Client) Mempool(ctx context.Context) (*tmtypes.ResultUnconfirmedTxs, error) {
txs, err := c.client.Client.UnconfirmedTxs(ctx, nil)
txs, err := c.clientCtx.Client.UnconfirmedTxs(ctx, nil)
if err != nil {
return nil, rosetta.WrapError(rosetta.ErrUnknown, err.Error())
}
Expand All @@ -210,17 +234,25 @@ func (c *Client) Mempool(ctx context.Context) (*tmtypes.ResultUnconfirmedTxs, er

// Peers gets the number of peers
func (c *Client) Peers(ctx context.Context) ([]tmtypes.Peer, error) {
netInfo, err := c.client.Client.NetInfo(ctx)
netInfo, err := c.clientCtx.Client.NetInfo(ctx)
if err != nil {
return nil, rosetta.WrapError(rosetta.ErrUnknown, err.Error())
}
return netInfo.Peers, nil
}

func (c *Client) Status(ctx context.Context) (*tmtypes.ResultStatus, error) {
status, err := c.client.Client.Status(ctx)
status, err := c.clientCtx.Client.Status(ctx)
if err != nil {
return nil, rosetta.WrapError(rosetta.ErrUnknown, err.Error())
}
return status, err
}

func (c *Client) GetTxConfig() client.TxConfig {
return c.clientCtx.TxConfig
}

func (c *Client) PostTx(txBytes []byte) (res *sdk.TxResponse, err error) {
return c.clientCtx.BroadcastTx(txBytes)
}
41 changes: 39 additions & 2 deletions server/rosetta/cosmos/conversion/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package conversion

import (
"fmt"
"strconv"
"strings"
"time"

"github.com/coinbase/rosetta-sdk-go/types"
Expand Down Expand Up @@ -65,7 +67,7 @@ func ResultTxSearchToTransaction(txs []*rosetta.SdkTxWithHash) []*types.Transact

// SdkTxResponseToOperations converts a tx response to operations
func SdkTxToOperations(tx sdk.Tx, hasError, withoutStatus bool) []*types.Operation {
return toOperations(tx.GetMsgs(), hasError, withoutStatus)
return ToOperations(tx.GetMsgs(), hasError, withoutStatus)
}

// TendermintTxsToTxIdentifiers converts a tendermint raw transaction into a rosetta tx identifier
Expand All @@ -85,7 +87,7 @@ func TendermintBlockToBlockIdentifier(block *tmcoretypes.ResultBlock) *types.Blo
}
}

func toOperations(msgs []sdk.Msg, hasError bool, withoutStatus bool) []*types.Operation {
func ToOperations(msgs []sdk.Msg, hasError bool, withoutStatus bool) []*types.Operation {
var operations []*types.Operation
for i, msg := range msgs {
switch msg.Type() { // nolint
Expand Down Expand Up @@ -132,6 +134,41 @@ func toOperations(msgs []sdk.Msg, hasError bool, withoutStatus bool) []*types.Op
return operations
}

// GetTransferTxDataFromOperations extracts the from and to addresses from a list of operations.
// We assume that it comes formated in the correct way. And that the balance of the sender is the same
// as the receiver operations.
func GetTransferTxDataFromOperations(ops []*types.Operation) (*banktypes.MsgSend, error) {
var (
from, to sdk.AccAddress
sendAmt sdk.Coin
err error
)

for _, op := range ops {
if strings.HasPrefix(op.Amount.Value, "-") {
from, err = sdk.AccAddressFromBech32(op.Account.Address)
if err != nil {
return nil, err
}
} else {
to, err = sdk.AccAddressFromBech32(op.Account.Address)
if err != nil {
return nil, err
}

amount, err := strconv.ParseInt(op.Amount.Value, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid amount")
}

sendAmt = sdk.NewCoin(op.Amount.Currency.Symbol, sdk.NewInt(amount))
}
}

msg := banktypes.NewMsgSend(from, to, sdk.NewCoins(sendAmt))
return msg, nil
}

// TmPeersToRosettaPeers converts tendermint peers to rosetta ones
func TmPeersToRosettaPeers(peers []tmcoretypes.Peer) []*types.Peer {
converted := make([]*types.Peer, len(peers))
Expand Down
8 changes: 7 additions & 1 deletion server/rosetta/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,13 @@ var (
// ErrUnsupportedCurve is returned when the curve specified is not supported
ErrUnsupportedCurve = NewError(15, "unsupported curve, expected secp256k1", false)
// ErrInvalidPubkey is returned when the public key is invalid
ErrInvalidPubkey = NewError(8, "invalid pubkey", false)
ErrInvalidPubkey = NewError(8, "invalid pubkey", false)
ErrInterpreting = NewError(1, "error interpreting data from node", false)
ErrInvalidAddress = NewError(7, "invalid address", false)
ErrInvalidMemo = NewError(11, "invalid memo", false)
ErrInvalidOperation = NewError(4, "invalid operation", false)
ErrInvalidRequest = NewError(6, "invalid request", false)
ErrInvalidTransaction = NewError(5, "invalid transaction", false)
)

// AllowedErrors lists all the rosetta allowed errors
Expand Down
Loading

0 comments on commit 9e46fb3

Please sign in to comment.