Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IBC SDK Integration #5124

Closed
Closed
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
608a819
Bump gopkg.in/yaml.v2 from 2.2.2 to 2.2.3 (#5121)
dependabot-preview[bot] Oct 1, 2019
e2a3257
Merge commit 'fea2ba628ccd4a374cf7a33b0a10a5099f19bfc6' of https://gi…
fedekunze Oct 1, 2019
60aa995
Merge branch 'joon/ics-04-implementation' of https://github.com/cosmo…
fedekunze Oct 1, 2019
d53afec
changes Fede removed by accident on #5057
fedekunze Oct 1, 2019
1e45d0b
Merge PR #5137: IBC Multi-Verifier Cherry Pick
alexanderbez Oct 3, 2019
7ba0b7e
Pass in chain-id properly to second cliCtx
jackzampolin Oct 4, 2019
5719c35
Attempt to fix panic
jackzampolin Oct 4, 2019
9eaa5d7
Explicitly set chain-id before each ctx call
jackzampolin Oct 4, 2019
902cbae
Extra logging
jackzampolin Oct 4, 2019
d02becc
Change cliCtx initialization
jackzampolin Oct 4, 2019
8b5e7e6
Fix build failure for cliCtx intitialization
jackzampolin Oct 4, 2019
6e34599
Make sure right txbldr is being used
jackzampolin Oct 7, 2019
1c0ae72
Remove loggin
jackzampolin Oct 7, 2019
24877f8
Fix clictx generation in connection command
jackzampolin Oct 7, 2019
c620897
Undefined var error in channel command
jackzampolin Oct 7, 2019
42b3079
Fix chain-id issue
jackzampolin Oct 7, 2019
1addcdf
Fix chain-id issue
jackzampolin Oct 7, 2019
a927a7b
Demo working until flush
jackzampolin Oct 7, 2019
59bfb70
cli send/receive debug in progress
mossid Oct 9, 2019
b0ad578
fix packet sending
mossid Oct 10, 2019
e690291
Update IBC CLI UX
jackzampolin Oct 11, 2019
1a74d7f
Update x/ibc/02-client/msgs.go
jackzampolin Oct 11, 2019
3d5c97e
Update x/ibc/02-client/client/cli/tx.go
jackzampolin Oct 11, 2019
cf4cc59
utilize ante for packet verification
mossid Oct 12, 2019
8d74a34
Merge branch 'fedekunze/ibc-sdk-interface' of github.com:cosmos/cosmo…
mossid Oct 12, 2019
11d4258
fix typo
mossid Oct 12, 2019
142a15a
mv port.name string -> port.key *StoreKey
mossid Oct 14, 2019
d5159c6
fix next sequence query (#5187)
chengwenxi Oct 14, 2019
af28eeb
initialize map in ics-04 Manager type ensuring that demo is working
jackzampolin Oct 14, 2019
ee5d7f3
CLI UX for demo
jackzampolin Oct 15, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 64 additions & 58 deletions client/context/context.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
package context

import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"

"github.com/pkg/errors"
"github.com/spf13/viper"
yaml "gopkg.in/yaml.v2"

"github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/log"
tmlite "github.com/tendermint/tendermint/lite"
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
rpcclient "github.com/tendermint/tendermint/rpc/client"

"github.com/cosmos/cosmos-sdk/client/flags"
Expand All @@ -24,27 +20,23 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

var (
verifier tmlite.Verifier
verifierHome string
)

// CLIContext implements a typical CLI context created in SDK modules for
// transaction handling and queries.
type CLIContext struct {
Codec *codec.Codec
Client rpcclient.Client
ChainID string
Keybase cryptokeys.Keybase
Output io.Writer
OutputFormat string
Height int64
HomeDir string
NodeURI string
From string
TrustNode bool
UseLedger bool
BroadcastMode string
Verifier tmlite.Verifier
VerifierHome string
Simulate bool
GenerateOnly bool
FromAddress sdk.AccAddress
Expand All @@ -55,7 +47,10 @@ type CLIContext struct {

// NewCLIContextWithFrom returns a new initialized CLIContext with parameters from the
// command line using Viper. It takes a key name or address and populates the FromName and
// FromAddress field accordingly.
// FromAddress field accordingly. It will also create Tendermint verifier using
// the chain ID, home directory and RPC URI provided by the command line. If using
// a CLIContext in tests or any non CLI-based environment, the verifier will not
// be created and will be set as nil because FlagTrustNode must be set.
func NewCLIContextWithFrom(from string) CLIContext {
var nodeURI string
var rpc rpcclient.Client
Expand All @@ -74,82 +69,87 @@ func NewCLIContextWithFrom(from string) CLIContext {
}
}

// We need to use a single verifier for all contexts
if verifier == nil || verifierHome != viper.GetString(flags.FlagHome) {
verifier = createVerifier()
verifierHome = viper.GetString(flags.FlagHome)
}

return CLIContext{
ctx := CLIContext{
Client: rpc,
ChainID: viper.GetString(flags.FlagChainID),
Output: os.Stdout,
NodeURI: nodeURI,
From: viper.GetString(flags.FlagFrom),
OutputFormat: viper.GetString(cli.OutputFlag),
Height: viper.GetInt64(flags.FlagHeight),
HomeDir: viper.GetString(flags.FlagHome),
TrustNode: viper.GetBool(flags.FlagTrustNode),
UseLedger: viper.GetBool(flags.FlagUseLedger),
BroadcastMode: viper.GetString(flags.FlagBroadcastMode),
Verifier: verifier,
Simulate: viper.GetBool(flags.FlagDryRun),
GenerateOnly: genOnly,
FromAddress: fromAddress,
FromName: fromName,
Indent: viper.GetBool(flags.FlagIndentResponse),
SkipConfirm: viper.GetBool(flags.FlagSkipConfirmation),
}
}

// NewCLIContext returns a new initialized CLIContext with parameters from the
// command line using Viper.
func NewCLIContext() CLIContext { return NewCLIContextWithFrom(viper.GetString(flags.FlagFrom)) }

func createVerifier() tmlite.Verifier {
trustNodeDefined := viper.IsSet(flags.FlagTrustNode)
if !trustNodeDefined {
return nil
// create a verifier for the specific chain ID and RPC client
verifier, err := CreateVerifier(ctx, DefaultVerifierCacheSize)
if err != nil && viper.IsSet(flags.FlagTrustNode) {
fmt.Printf("failed to create verifier: %s\n", err)
os.Exit(1)
}

trustNode := viper.GetBool(flags.FlagTrustNode)
if trustNode {
return nil
}
return ctx.WithVerifier(verifier)
}

chainID := viper.GetString(flags.FlagChainID)
home := viper.GetString(flags.FlagHome)
nodeURI := viper.GetString(flags.FlagNode)
// NewCLIContextIBC takes additional arguements
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arguements is a misspelling of arguments (from misspell)

Suggested change
// NewCLIContextIBC takes additional arguements

func NewCLIContextIBC(from string, chainID string, nodeURI string) CLIContext {
var rpc rpcclient.Client

var errMsg bytes.Buffer
if chainID == "" {
errMsg.WriteString("--chain-id ")
}
if home == "" {
errMsg.WriteString("--home ")
}
if nodeURI == "" {
errMsg.WriteString("--node ")
}
if errMsg.Len() != 0 {
fmt.Printf("Must specify these options: %s when --trust-node is false\n", errMsg.String())
genOnly := viper.GetBool(flags.FlagGenerateOnly)
fromAddress, fromName, err := GetFromFields(from, genOnly)
if err != nil {
fmt.Printf("failed to get from fields: %v", err)
os.Exit(1)
}

node := rpcclient.NewHTTP(nodeURI, "/websocket")
cacheSize := 10 // TODO: determine appropriate cache size
verifier, err := tmliteProxy.NewVerifier(
chainID, filepath.Join(home, ".lite_verifier"),
node, log.NewNopLogger(), cacheSize,
)
if !genOnly {
if nodeURI != "" {
rpc = rpcclient.NewHTTP(nodeURI, "/websocket")
}
}

if err != nil {
fmt.Printf("Create verifier failed: %s\n", err.Error())
fmt.Printf("Please check network connection and verify the address of the node to connect to\n")
ctx := CLIContext{
Client: rpc,
ChainID: chainID,
Output: os.Stdout,
NodeURI: nodeURI,
From: from,
OutputFormat: viper.GetString(cli.OutputFlag),
Height: viper.GetInt64(flags.FlagHeight),
HomeDir: viper.GetString(flags.FlagHome),
TrustNode: viper.GetBool(flags.FlagTrustNode),
UseLedger: viper.GetBool(flags.FlagUseLedger),
BroadcastMode: viper.GetString(flags.FlagBroadcastMode),
Simulate: viper.GetBool(flags.FlagDryRun),
GenerateOnly: genOnly,
FromAddress: fromAddress,
FromName: fromName,
Indent: viper.GetBool(flags.FlagIndentResponse),
SkipConfirm: viper.GetBool(flags.FlagSkipConfirmation),
}

// create a verifier for the specific chain ID and RPC client
verifier, err := CreateVerifier(ctx, DefaultVerifierCacheSize)
if err != nil && viper.IsSet(flags.FlagTrustNode) {
fmt.Printf("failed to create verifier: %s\n", err)
os.Exit(1)
}

return verifier
return ctx.WithVerifier(verifier)
}

// NewCLIContext returns a new initialized CLIContext with parameters from the
// command line using Viper.
func NewCLIContext() CLIContext { return NewCLIContextWithFrom(viper.GetString(flags.FlagFrom)) }

// WithCodec returns a copy of the context with an updated codec.
func (ctx CLIContext) WithCodec(cdc *codec.Codec) CLIContext {
ctx.Codec = cdc
Expand Down Expand Up @@ -200,12 +200,18 @@ func (ctx CLIContext) WithUseLedger(useLedger bool) CLIContext {
return ctx
}

// WithVerifier - return a copy of the context with an updated Verifier
// WithVerifier returns a copy of the context with an updated Verifier.
func (ctx CLIContext) WithVerifier(verifier tmlite.Verifier) CLIContext {
ctx.Verifier = verifier
return ctx
}

// WithChainID returns a copy of the context with an updated chain ID.
func (ctx CLIContext) WithChainID(chainID string) CLIContext {
ctx.ChainID = chainID
return ctx
}

// WithGenerateOnly returns a copy of the context with updated GenerateOnly value
func (ctx CLIContext) WithGenerateOnly(generateOnly bool) CLIContext {
ctx.GenerateOnly = generateOnly
Expand Down
51 changes: 51 additions & 0 deletions client/context/verifier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package context

import (
"path/filepath"

"github.com/pkg/errors"
"github.com/tendermint/tendermint/libs/log"
tmlite "github.com/tendermint/tendermint/lite"
tmliteproxy "github.com/tendermint/tendermint/lite/proxy"
rpcclient "github.com/tendermint/tendermint/rpc/client"
)

const (
verifierDir = ".lite_verifier"

// DefaultVerifierCacheSize defines the default Tendermint cache size.
DefaultVerifierCacheSize = 10
)

// CreateVerifier returns a Tendermint verifier from a CLIContext object and
// cache size. An error is returned if the CLIContext is missing required values
// or if the verifier could not be created. A CLIContext must at the very least
// have the chain ID and home directory set. If the CLIContext has TrustNode
// enabled, no verifier will be created.
func CreateVerifier(ctx CLIContext, cacheSize int) (tmlite.Verifier, error) {
if ctx.TrustNode {
return nil, nil
}

switch {
case ctx.ChainID == "":
return nil, errors.New("must provide a valid chain ID to create verifier")

case ctx.HomeDir == "":
return nil, errors.New("must provide a valid home directory to create verifier")

case ctx.Client == nil && ctx.NodeURI == "":
return nil, errors.New("must provide a valid RPC client or RPC URI to create verifier")
}

// create an RPC client based off of the RPC URI if no RPC client exists
client := ctx.Client
if client == nil {
client = rpcclient.NewHTTP(ctx.NodeURI, "/websocket")
}

return tmliteproxy.NewVerifier(
ctx.ChainID, filepath.Join(ctx.HomeDir, ctx.ChainID, verifierDir),
client, log.NewNopLogger(), cacheSize,
)
}
35 changes: 35 additions & 0 deletions client/context/verifier_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package context_test

import (
"io/ioutil"
"testing"

"github.com/cosmos/cosmos-sdk/client/context"
"github.com/stretchr/testify/require"
)

func TestCreateVerifier(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "example")
require.NoError(t, err)

testCases := []struct {
name string
ctx context.CLIContext
expectErr bool
}{
{"no chain ID", context.CLIContext{}, true},
{"no home directory", context.CLIContext{}.WithChainID("test"), true},
{"no client or RPC URI", context.CLIContext{HomeDir: tmpDir}.WithChainID("test"), true},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
verifier, err := context.CreateVerifier(tc.ctx, context.DefaultVerifierCacheSize)
require.Equal(t, tc.expectErr, err != nil, err)

if !tc.expectErr {
require.NotNil(t, verifier)
}
})
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ require (
github.com/tendermint/iavl v0.12.4
github.com/tendermint/tendermint v0.32.3
github.com/tendermint/tm-db v0.2.0
gopkg.in/yaml.v2 v2.2.2
gopkg.in/yaml.v2 v2.2.3
)

go 1.13
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -324,5 +324,7 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
9 changes: 9 additions & 0 deletions types/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ type TxResponse struct {
Events StringEvents `json:"events,omitempty"`
}

func (res TxResponse) IsOK() bool {
for _, lg := range res.Logs {
if !lg.Success {
return false
}
}
return true
}

// NewResponseResultTx returns a TxResponse given a ResultTx from tendermint
func NewResponseResultTx(res *ctypes.ResultTx, tx Tx, timestamp string) TxResponse {
if res == nil {
Expand Down
39 changes: 39 additions & 0 deletions x/auth/client/utils/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,45 @@ func CompleteAndBroadcastTxCLI(txBldr authtypes.TxBuilder, cliCtx context.CLICon
return cliCtx.PrintOutput(res)
}

// CompleteAndBroadcastTx implements a utility function that facilitates
// sending a series of messages in a signed transaction given a TxBuilder and a
// QueryContext. It ensures that the account exists, has a proper number and
// sequence set. In addition, it builds and signs a transaction non-interactively
// with the supplied messages. Finally, it broadcasts the signed transaction to a node.
func CompleteAndBroadcastTx(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg, passphrase string) (sdk.TxResponse, error) {
var res sdk.TxResponse
txBldr, err := PrepareTxBuilder(txBldr, cliCtx)
if err != nil {
return res, err
}

fromName := cliCtx.GetFromName()

if txBldr.SimulateAndExecute() || cliCtx.Simulate {
txBldr, err = EnrichWithGas(txBldr, cliCtx, msgs)
if err != nil {
return res, err
}

gasEst := GasEstimateResponse{GasEstimate: txBldr.Gas()}
_, _ = fmt.Fprintf(os.Stderr, "%s\n", gasEst.String())
}

// build and sign the transaction
txBytes, err := txBldr.BuildAndSign(fromName, passphrase, msgs)
if err != nil {
return res, err
}

// broadcast to a Tendermint node
res, err = cliCtx.BroadcastTx(txBytes)
if err != nil {
return res, err
}

return res, err
}

// EnrichWithGas calculates the gas estimate that would be consumed by the
// transaction and set the transaction's respective value accordingly.
func EnrichWithGas(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (authtypes.TxBuilder, error) {
Expand Down
Loading