Add ibc query commands

This commit is contained in:
Ethan Frey 2017-07-21 17:15:49 +02:00
parent 374f078b79
commit 746ae28eaa
8 changed files with 283 additions and 30 deletions

View File

@ -19,6 +19,7 @@ import (
basecmd "github.com/tendermint/basecoin/modules/base/commands"
coincmd "github.com/tendermint/basecoin/modules/coin/commands"
feecmd "github.com/tendermint/basecoin/modules/fee/commands"
ibccmd "github.com/tendermint/basecoin/modules/ibc/commands"
noncecmd "github.com/tendermint/basecoin/modules/nonce/commands"
rolecmd "github.com/tendermint/basecoin/modules/roles/commands"
)
@ -46,6 +47,7 @@ func main() {
coincmd.AccountQueryCmd,
noncecmd.NonceQueryCmd,
rolecmd.RoleQueryCmd,
ibccmd.IBCQueryCmd,
)
proofs.TxPresenters.Register("base", txcmd.BaseTxPresenter{})

View File

@ -12,6 +12,10 @@ import (
"github.com/tendermint/basecoin/stack"
)
// TODO: other test making sure tx is output on send, balance is updated
// This makes sure we respond properly to posttx
// TODO: set credit limit
func TestIBCPostPacket(t *testing.T) {
assert := assert.New(t)
require := require.New(t)

View File

@ -0,0 +1,185 @@
package commands
import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/basecoin/client/commands"
proofcmd "github.com/tendermint/basecoin/client/commands/proofs"
"github.com/tendermint/basecoin/modules/ibc"
"github.com/tendermint/basecoin/stack"
)
// IBCQueryCmd - parent command to query ibc info
var IBCQueryCmd = &cobra.Command{
Use: "ibc",
Short: "Get information about IBC",
RunE: commands.RequireInit(ibcQueryCmd),
// HandlerInfo
}
// ChainsQueryCmd - get a list of all registered chains
var ChainsQueryCmd = &cobra.Command{
Use: "chains",
Short: "Get a list of all registered chains",
RunE: commands.RequireInit(chainsQueryCmd),
// ChainSet ([]string)
}
// ChainQueryCmd - get details on one registered chain
var ChainQueryCmd = &cobra.Command{
Use: "chain [id]",
Short: "Get details on one registered chain",
RunE: commands.RequireInit(chainQueryCmd),
// ChainInfo
}
// PacketsQueryCmd - get latest packet in a queue
var PacketsQueryCmd = &cobra.Command{
Use: "packets",
Short: "Get latest packet in a queue",
RunE: commands.RequireInit(packetsQueryCmd),
// uint64
}
// PacketQueryCmd - get the names packet (by queue and sequence)
var PacketQueryCmd = &cobra.Command{
Use: "packet",
Short: "Get packet with given sequence from the named queue",
RunE: commands.RequireInit(packetQueryCmd),
// Packet
}
//nolint
const (
FlagFromChain = "from"
FlagToChain = "to"
FlagSequence = "sequence"
)
func init() {
IBCQueryCmd.AddCommand(
ChainQueryCmd,
ChainsQueryCmd,
PacketQueryCmd,
PacketsQueryCmd,
)
fs1 := PacketsQueryCmd.Flags()
fs1.String(FlagFromChain, "", "Name of the input chain (where packets came from)")
fs1.String(FlagToChain, "", "Name of the output chain (where packets go to)")
fs2 := PacketQueryCmd.Flags()
fs2.String(FlagFromChain, "", "Name of the input chain (where packets came from)")
fs2.String(FlagToChain, "", "Name of the output chain (where packets go to)")
fs2.Int(FlagSequence, -1, "Name of the output chain (where packets go to)")
}
func ibcQueryCmd(cmd *cobra.Command, args []string) error {
var res ibc.HandlerInfo
key := stack.PrefixedKey(ibc.NameIBC, ibc.HandlerKey())
proof, err := proofcmd.GetAndParseAppProof(key, &res)
if err != nil {
return err
}
return proofcmd.OutputProof(res, proof.BlockHeight())
}
func chainsQueryCmd(cmd *cobra.Command, args []string) error {
list := [][]byte{}
key := stack.PrefixedKey(ibc.NameIBC, ibc.HandlerKey())
proof, err := proofcmd.GetAndParseAppProof(key, &list)
if err != nil {
return err
}
// convert these names to strings for better output
res := make([]string, len(list))
for i := range list {
res[i] = string(list[i])
}
return proofcmd.OutputProof(res, proof.BlockHeight())
}
func chainQueryCmd(cmd *cobra.Command, args []string) error {
arg, err := commands.GetOneArg(args, "id")
if err != nil {
return err
}
var res ibc.ChainInfo
key := stack.PrefixedKey(ibc.NameIBC, ibc.ChainKey(arg))
proof, err := proofcmd.GetAndParseAppProof(key, &res)
if err != nil {
return err
}
return proofcmd.OutputProof(res, proof.BlockHeight())
}
func assertOne(from, to string) error {
if from == "" && to == "" {
return errors.Errorf("You must specify either --%s or --%s",
FlagFromChain, FlagToChain)
}
if from != "" && to != "" {
return errors.Errorf("You can only specify one of --%s or --%s",
FlagFromChain, FlagToChain)
}
return nil
}
func packetsQueryCmd(cmd *cobra.Command, args []string) error {
from := viper.GetString(FlagFromChain)
to := viper.GetString(FlagToChain)
err := assertOne(from, to)
if err != nil {
return err
}
var key []byte
if from != "" {
key = stack.PrefixedKey(ibc.NameIBC, ibc.QueueInKey(from))
} else {
key = stack.PrefixedKey(ibc.NameIBC, ibc.QueueOutKey(to))
}
var res uint64
proof, err := proofcmd.GetAndParseAppProof(key, &res)
if err != nil {
return err
}
return proofcmd.OutputProof(res, proof.BlockHeight())
}
func packetQueryCmd(cmd *cobra.Command, args []string) error {
from := viper.GetString(FlagFromChain)
to := viper.GetString(FlagToChain)
err := assertOne(from, to)
if err != nil {
return err
}
seq := viper.GetInt(FlagSequence)
if seq < 0 {
return errors.Errorf("--%s must be a non-negative number", FlagSequence)
}
var key []byte
if from != "" {
key = stack.PrefixedKey(ibc.NameIBC, ibc.QueueInPacketKey(from, uint64(seq)))
} else {
key = stack.PrefixedKey(ibc.NameIBC, ibc.QueueOutPacketKey(to, uint64(seq)))
}
var res ibc.Packet
proof, err := proofcmd.GetAndParseAppProof(key, &res)
if err != nil {
return err
}
return proofcmd.OutputProof(res, proof.BlockHeight())
}

60
modules/ibc/keys.go Normal file
View File

@ -0,0 +1,60 @@
package ibc
import (
"github.com/tendermint/basecoin/stack"
"github.com/tendermint/basecoin/state"
)
const (
// this is the prefix for the list of chains
// we otherwise use the chainid as prefix, so this must not be an
// alpha-numeric byte
prefixChains = "**"
prefixInput = "i"
prefixOutput = "o"
)
// HandlerKey is used for the global permission info
func HandlerKey() []byte {
return []byte{0x2}
}
// ChainsKey is the key to get info on all chains
func ChainsKey() []byte {
return stack.PrefixedKey(prefixChains, state.SetKey())
}
// ChainKey is the key to get info on one chain
func ChainKey(chainID string) []byte {
bkey := state.MakeBKey([]byte(chainID))
return stack.PrefixedKey(prefixChains, bkey)
}
// QueueInKey is the key to get newest of the input queue from this chain
func QueueInKey(chainID string) []byte {
return stack.PrefixedKey(chainID,
stack.PrefixedKey(prefixInput,
state.QueueTailKey()))
}
// QueueOutKey is the key to get v of the output queue from this chain
func QueueOutKey(chainID string) []byte {
return stack.PrefixedKey(chainID,
stack.PrefixedKey(prefixOutput,
state.QueueTailKey()))
}
// QueueInPacketKey is the key to get given packet from this chain's input queue
func QueueInPacketKey(chainID string, seq uint64) []byte {
return stack.PrefixedKey(chainID,
stack.PrefixedKey(prefixInput,
state.QueueItemKey(seq)))
}
// QueueOutPacketKey is the key to get given packet from this chain's output queue
func QueueOutPacketKey(chainID string, seq uint64) []byte {
return stack.PrefixedKey(chainID,
stack.PrefixedKey(prefixOutput,
state.QueueItemKey(seq)))
}

View File

@ -7,21 +7,6 @@ import (
wire "github.com/tendermint/go-wire"
)
const (
// this is the prefix for the list of chains
// we otherwise use the chainid as prefix, so this must not be an
// alpha-numeric byte
prefixChains = "**"
prefixInput = "i"
prefixOutput = "o"
)
// this is used for the global handler info
var (
handlerKey = []byte{0x2}
)
// HandlerInfo is the global state of the ibc.Handler
type HandlerInfo struct {
Registrar basecoin.Actor `json:"registrar"`
@ -30,12 +15,12 @@ type HandlerInfo struct {
// Save the HandlerInfo to the store
func (h HandlerInfo) Save(store state.KVStore) {
b := wire.BinaryBytes(h)
store.Set(handlerKey, b)
store.Set(HandlerKey(), b)
}
// LoadInfo loads the HandlerInfo from the data store
func LoadInfo(store state.KVStore) (h HandlerInfo) {
b := store.Get(handlerKey)
b := store.Get(HandlerKey())
if len(b) > 0 {
wire.ReadBinaryBytes(b, &h)
}

View File

@ -1,10 +1,9 @@
package commands
import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
lcmd "github.com/tendermint/basecoin/client/commands"
"github.com/tendermint/basecoin/client/commands"
proofcmd "github.com/tendermint/basecoin/client/commands/proofs"
"github.com/tendermint/basecoin/modules/roles"
"github.com/tendermint/basecoin/stack"
@ -14,17 +13,15 @@ import (
var RoleQueryCmd = &cobra.Command{
Use: "role [name]",
Short: "Get details of a role, with proof",
RunE: lcmd.RequireInit(roleQueryCmd),
RunE: commands.RequireInit(roleQueryCmd),
}
func roleQueryCmd(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errors.New("Missing required argument [name]")
} else if len(args) > 1 {
return errors.New("Command only supports one name")
arg, err := commands.GetOneArg(args, "name")
if err != nil {
return err
}
role, err := parseRole(args[0])
role, err := parseRole(arg)
if err != nil {
return err
}

View File

@ -8,6 +8,21 @@ var (
dataKey = []byte("d")
)
// QueueHeadKey gives us the key for the height at head of the queue
func QueueHeadKey() []byte {
return headKey
}
// QueueTailKey gives us the key for the height at tail of the queue
func QueueTailKey() []byte {
return tailKey
}
// QueueItemKey gives us the key to look up one item by sequence
func QueueItemKey(i uint64) []byte {
return makeKey(i)
}
// Queue allows us to fill up a range of the db, and grab from either end
type Queue struct {
store KVStore

View File

@ -7,6 +7,11 @@ import (
wire "github.com/tendermint/go-wire"
)
// SetKey returns the key to get all members of this set
func SetKey() []byte {
return keys
}
// Set allows us to add arbitrary k-v pairs, check existence,
// as well as iterate through the set (always in key order)
//
@ -29,7 +34,7 @@ func NewSet(store KVStore) *Set {
// Set puts a value at a given height.
// If the value is nil, or an empty slice, remove the key from the list
func (s *Set) Set(key []byte, value []byte) {
s.store.Set(makeBKey(key), value)
s.store.Set(MakeBKey(key), value)
if len(value) > 0 {
s.addKey(key)
} else {
@ -40,7 +45,7 @@ func (s *Set) Set(key []byte, value []byte) {
// Get returns the element with a key if it exists
func (s *Set) Get(key []byte) []byte {
return s.store.Get(makeBKey(key))
return s.store.Get(MakeBKey(key))
}
// Remove deletes this key from the set (same as setting value = nil)
@ -122,8 +127,8 @@ func (s *Set) storeKeys() {
s.store.Set(keys, b)
}
// makeBKey prefixes the byte slice for the storage key
func makeBKey(key []byte) []byte {
// MakeBKey prefixes the byte slice for the storage key
func MakeBKey(key []byte) []byte {
return append(dataKey, key...)
}