Merge pull request #265 from cosmos/feature/reorg-light-client

Reorg light client
This commit is contained in:
Ethan Frey 2017-10-25 19:54:10 +02:00 committed by GitHub
commit 8f9caa8907
32 changed files with 390 additions and 326 deletions

View File

@ -1,30 +1,32 @@
package seeds
package commits
import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/light-client/certifiers/files"
"github.com/cosmos/cosmos-sdk/client/commands"
)
var exportCmd = &cobra.Command{
Use: "export <file>",
Short: "Export selected seeds to given file",
Long: `Exports the most recent seed to a binary file.
Short: "Export selected commits to given file",
Long: `Exports the most recent commit to a binary file.
If desired, you can select by an older height or validator hash.
`,
RunE: commands.RequireInit(exportSeed),
RunE: commands.RequireInit(exportCommit),
SilenceUsage: true,
}
func init() {
exportCmd.Flags().Int(heightFlag, 0, "Show the seed with closest height to this")
exportCmd.Flags().String(hashFlag, "", "Show the seed matching the validator hash")
exportCmd.Flags().Int(heightFlag, 0, "Show the commit with closest height to this")
exportCmd.Flags().String(hashFlag, "", "Show the commit matching the validator hash")
RootCmd.AddCommand(exportCmd)
}
func exportSeed(cmd *cobra.Command, args []string) error {
func exportCommit(cmd *cobra.Command, args []string) error {
if len(args) != 1 || len(args[0]) == 0 {
return errors.New("You must provide a filepath to output")
}
@ -34,11 +36,11 @@ func exportSeed(cmd *cobra.Command, args []string) error {
trust, _ := commands.GetProviders()
h := viper.GetInt(heightFlag)
hash := viper.GetString(hashFlag)
seed, err := loadSeed(trust, h, hash, "")
fc, err := loadCommit(trust, h, hash, "")
if err != nil {
return err
}
// now get the output file and write it
return seed.WriteJSON(path)
return files.SaveFullCommitJSON(fc, path)
}

View File

@ -1,4 +1,4 @@
package seeds
package commits
import (
"fmt"
@ -7,7 +7,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/light-client/certifiers"
"github.com/tendermint/light-client/certifiers/files"
"github.com/cosmos/cosmos-sdk/client/commands"
)
@ -18,9 +18,9 @@ const (
var importCmd = &cobra.Command{
Use: "import <file>",
Short: "Imports a new seed from the given file",
Long: `Validate this file and update to the given seed if secure.`,
RunE: commands.RequireInit(importSeed),
Short: "Imports a new commit from the given file",
Long: `Validate this file and update to the given commit if secure.`,
RunE: commands.RequireInit(importCommit),
SilenceUsage: true,
}
@ -29,7 +29,7 @@ func init() {
RootCmd.AddCommand(importCmd)
}
func importSeed(cmd *cobra.Command, args []string) error {
func importCommit(cmd *cobra.Command, args []string) error {
if len(args) != 1 || len(args[0]) == 0 {
return errors.New("You must provide an input file")
}
@ -42,18 +42,18 @@ func importSeed(cmd *cobra.Command, args []string) error {
// parse the input file
path := args[0]
seed, err := certifiers.LoadSeedJSON(path)
fc, err := files.LoadFullCommitJSON(path)
if err != nil {
return err
}
// just do simple checks in --dry-run
if viper.GetBool(dryFlag) {
fmt.Printf("Testing seed %d/%X\n", seed.Height(), seed.Hash())
err = seed.ValidateBasic(cert.ChainID())
fmt.Printf("Testing commit %d/%X\n", fc.Height(), fc.ValidatorsHash())
err = fc.ValidateBasic(cert.ChainID())
} else {
fmt.Printf("Importing seed %d/%X\n", seed.Height(), seed.Hash())
err = cert.Update(seed.Checkpoint, seed.Validators)
fmt.Printf("Importing commit %d/%X\n", fc.Height(), fc.ValidatorsHash())
err = cert.Update(fc)
}
return err
}

View File

@ -1,15 +1,15 @@
package seeds
package commits
import "github.com/spf13/cobra"
// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
Use: "seeds",
Short: "Verify seeds from your local store",
Long: `Seeds allows you to inspect and update the validator set for the chain.
Use: "commits",
Short: "Verify commits from your local store",
Long: `Commits allows you to inspect and update the validator set for the chain.
Since all security in a PoS system is based on having the correct validator
set, it is important to inspect the seeds to maintain the security, which
set, it is important to inspect the commits to maintain the security, which
is used to verify all header and merkle proofs.
`,
}

View File

@ -1,4 +1,4 @@
package seeds
package commits
import (
"encoding/hex"
@ -9,6 +9,7 @@ import (
"github.com/spf13/viper"
"github.com/tendermint/light-client/certifiers"
"github.com/tendermint/light-client/certifiers/files"
"github.com/cosmos/cosmos-sdk/client/commands"
)
@ -21,53 +22,53 @@ const (
var showCmd = &cobra.Command{
Use: "show",
Short: "Show the details of one selected seed",
Short: "Show the details of one selected commit",
Long: `Shows the most recent downloaded key by default.
If desired, you can select by height, validator hash, or a file.
`,
RunE: commands.RequireInit(showSeed),
RunE: commands.RequireInit(showCommit),
SilenceUsage: true,
}
func init() {
showCmd.Flags().Int(heightFlag, 0, "Show the seed with closest height to this")
showCmd.Flags().String(hashFlag, "", "Show the seed matching the validator hash")
showCmd.Flags().String(fileFlag, "", "Show the seed stored in the given file")
showCmd.Flags().Int(heightFlag, 0, "Show the commit with closest height to this")
showCmd.Flags().String(hashFlag, "", "Show the commit matching the validator hash")
showCmd.Flags().String(fileFlag, "", "Show the commit stored in the given file")
RootCmd.AddCommand(showCmd)
}
func loadSeed(p certifiers.Provider, h int, hash, file string) (seed certifiers.Seed, err error) {
// load the seed from the proper place
func loadCommit(p certifiers.Provider, h int, hash, file string) (fc certifiers.FullCommit, err error) {
// load the commit from the proper place
if h != 0 {
seed, err = p.GetByHeight(h)
fc, err = p.GetByHeight(h)
} else if hash != "" {
var vhash []byte
vhash, err = hex.DecodeString(hash)
if err == nil {
seed, err = p.GetByHash(vhash)
fc, err = p.GetByHash(vhash)
}
} else if file != "" {
seed, err = certifiers.LoadSeedJSON(file)
fc, err = files.LoadFullCommitJSON(file)
} else {
// default is latest seed
seed, err = certifiers.LatestSeed(p)
// default is latest commit
fc, err = p.LatestCommit()
}
return
}
func showSeed(cmd *cobra.Command, args []string) error {
func showCommit(cmd *cobra.Command, args []string) error {
trust, _ := commands.GetProviders()
h := viper.GetInt(heightFlag)
hash := viper.GetString(hashFlag)
file := viper.GetString(fileFlag)
seed, err := loadSeed(trust, h, hash, file)
fc, err := loadCommit(trust, h, hash, file)
if err != nil {
return err
}
// now render it!
data, err := json.MarshalIndent(seed, "", " ")
data, err := json.MarshalIndent(fc, "", " ")
fmt.Println(string(data))
return err
}

View File

@ -1,4 +1,4 @@
package seeds
package commits
import (
"fmt"
@ -13,8 +13,8 @@ import (
var updateCmd = &cobra.Command{
Use: "update",
Short: "Update seed to current height if possible",
RunE: commands.RequireInit(updateSeed),
Short: "Update commit to current height if possible",
RunE: commands.RequireInit(updateCommit),
SilenceUsage: true,
}
@ -23,27 +23,27 @@ func init() {
RootCmd.AddCommand(updateCmd)
}
func updateSeed(cmd *cobra.Command, args []string) error {
func updateCommit(cmd *cobra.Command, args []string) error {
cert, err := commands.GetCertifier()
if err != nil {
return err
}
h := viper.GetInt(heightFlag)
var seed certifiers.Seed
var fc certifiers.FullCommit
if h <= 0 {
// get the lastest from our source
seed, err = certifiers.LatestSeed(cert.SeedSource)
fc, err = cert.Source.LatestCommit()
} else {
seed, err = cert.SeedSource.GetByHeight(h)
fc, err = cert.Source.GetByHeight(h)
}
if err != nil {
return err
}
// let the certifier do it's magic to update....
fmt.Printf("Trying to update to height: %d...\n", seed.Height())
err = cert.Update(seed.Checkpoint, seed.Validators)
fmt.Printf("Trying to update to height: %d...\n", fc.Height())
err = cert.Update(fc)
if err != nil {
return err
}

View File

@ -74,7 +74,7 @@ func GetProviders() (trusted certifiers.Provider, source certifiers.Provider) {
}
// GetCertifier constructs a dynamic certifier from the config info
func GetCertifier() (*certifiers.InquiringCertifier, error) {
func GetCertifier() (*certifiers.Inquiring, error) {
// load up the latest store....
trust := GetTrustedProvider()
source := GetSourceProvider()

View File

@ -29,7 +29,7 @@ var (
//nolint
const (
SeedFlag = "seed"
CommitFlag = "commit"
HashFlag = "valhash"
GenesisFlag = "genesis"
FlagTrustNode = "trust-node"
@ -52,7 +52,7 @@ var ResetCmd = &cobra.Command{
func init() {
InitCmd.Flags().Bool("force-reset", false, "Wipe clean an existing client store, except for keys")
InitCmd.Flags().String(SeedFlag, "", "Seed file to import (optional)")
InitCmd.Flags().String(CommitFlag, "", "Commit file to import (optional)")
InitCmd.Flags().String(HashFlag, "", "Trusted validator hash (must match to accept)")
InitCmd.Flags().String(GenesisFlag, "", "Genesis file with chainid and validators (optional)")
}
@ -92,7 +92,7 @@ func doInit(cmd *cobra.Command, root string) error {
if err != nil {
return err
}
err = initSeed()
err = initTrust()
return err
}
@ -275,27 +275,27 @@ func initConfigFile(cmd *cobra.Command) error {
return nil
}
func initSeed() (err error) {
func initTrust() (err error) {
// create a provider....
trust, source := GetProviders()
// load a seed file, or get data from the provider
var seed certifiers.Seed
seedFile := viper.GetString(SeedFlag)
if seedFile == "" {
// load a commit file, or get data from the provider
var fc certifiers.FullCommit
commitFile := viper.GetString(CommitFlag)
if commitFile == "" {
fmt.Println("Loading validator set from tendermint rpc...")
seed, err = certifiers.LatestSeed(source)
fc, err = source.LatestCommit()
} else {
fmt.Printf("Loading validators from file %s\n", seedFile)
seed, err = certifiers.LoadSeed(seedFile)
fmt.Printf("Loading validators from file %s\n", commitFile)
fc, err = files.LoadFullCommit(commitFile)
}
// can't load the seed? abort!
// can't load the commit? abort!
if err != nil {
return err
}
// make sure it is a proper seed
err = seed.ValidateBasic(viper.GetString(ChainFlag))
// make sure it is a proper commit
err = fc.ValidateBasic(viper.GetString(ChainFlag))
if err != nil {
return err
}
@ -305,30 +305,30 @@ func initSeed() (err error) {
if hash != "" {
var hashb []byte
hashb, err = hex.DecodeString(hash)
if err == nil && !bytes.Equal(hashb, seed.Hash()) {
err = errors.Errorf("Seed hash doesn't match expectation: %X", seed.Hash())
if err == nil && !bytes.Equal(hashb, fc.ValidatorsHash()) {
err = errors.Errorf("Validator hash doesn't match expectation: %X", fc.ValidatorsHash())
}
} else {
err = validateHash(seed)
err = validateHash(fc)
}
if err != nil {
return err
}
// if accepted, store seed as current state
trust.StoreSeed(seed)
// if accepted, store commit as current state
trust.StoreCommit(fc)
return nil
}
func validateHash(seed certifiers.Seed) error {
func validateHash(fc certifiers.FullCommit) error {
// ask the user to verify the validator hash
fmt.Println("\nImportant: if this is incorrect, all interaction with the chain will be insecure!")
fmt.Printf(" Given validator hash valid: %X\n", seed.Hash())
fmt.Printf(" Given validator hash valid: %X\n", fc.ValidatorsHash())
fmt.Println("Is this valid (y/n)?")
valid := askForConfirmation()
if !valid {
return errors.New("Invalid validator hash, try init with proper seed later")
return errors.New("Invalid validator hash, try init with proper commit later")
}
return nil
}

View File

@ -12,6 +12,7 @@ import (
"github.com/tendermint/go-wire/data"
"github.com/tendermint/iavl"
"github.com/tendermint/light-client/proofs"
rpcclient "github.com/tendermint/tendermint/rpc/client"
"github.com/cosmos/cosmos-sdk/client"

View File

@ -52,7 +52,7 @@ func txQueryCmd(cmd *cobra.Command, args []string) error {
return err
}
check, err := client.GetCertifiedCheckpoint(res.Height, node, cert)
check, err := client.GetCertifiedCommit(res.Height, node, cert)
if err != nil {
return err
}

View File

@ -5,8 +5,11 @@ import (
"github.com/tendermint/light-client/certifiers"
certclient "github.com/tendermint/light-client/certifiers/client"
certerr "github.com/tendermint/light-client/certifiers/errors"
"github.com/tendermint/light-client/certifiers/files"
"github.com/tendermint/light-client/proofs"
rpcclient "github.com/tendermint/tendermint/rpc/client"
)
@ -18,7 +21,7 @@ func GetNode(url string) rpcclient.Client {
// GetRPCProvider retuns a certifier compatible data source using
// tendermint RPC
func GetRPCProvider(url string) certifiers.Provider {
return certclient.NewHTTP(url)
return certclient.NewHTTPProvider(url)
}
// GetLocalProvider returns a reference to a file store of headers
@ -33,22 +36,22 @@ func GetLocalProvider(dir string) certifiers.Provider {
// GetCertifier initializes an inquiring certifier given a fixed chainID
// and a local source of trusted data with at least one seed
func GetCertifier(chainID string, trust certifiers.Provider,
source certifiers.Provider) (*certifiers.InquiringCertifier, error) {
source certifiers.Provider) (*certifiers.Inquiring, error) {
// this gets the most recent verified seed
seed, err := certifiers.LatestSeed(trust)
if certifiers.IsSeedNotFoundErr(err) {
// this gets the most recent verified commit
fc, err := trust.LatestCommit()
if certerr.IsCommitNotFoundErr(err) {
return nil, errors.New("Please run init first to establish a root of trust")
}
if err != nil {
return nil, err
}
cert := certifiers.NewInquiring(chainID, seed, trust, source)
cert := certifiers.NewInquiring(chainID, fc, trust, source)
return cert, nil
}
// SecureClient uses a given certifier to wrap an connection to an untrusted
// host and return a cryptographically secure rpc client.
func SecureClient(c rpcclient.Client, cert *certifiers.InquiringCertifier) rpcclient.Client {
return certclient.Wrap(c, cert)
func SecureClient(c rpcclient.Client, cert *certifiers.Inquiring) rpcclient.Client {
return proofs.Wrap(c, cert)
}

22
client/errors.go Normal file
View File

@ -0,0 +1,22 @@
package client
import (
"fmt"
"github.com/pkg/errors"
)
//--------------------------------------------
var errNoData = fmt.Errorf("No data returned for query")
// IsNoDataErr checks whether an error is due to a query returning empty data
func IsNoDataErr(err error) bool {
return errors.Cause(err) == errNoData
}
func ErrNoData() error {
return errors.WithStack(errNoData)
}
//--------------------------------------------

18
client/errors_test.go Normal file
View File

@ -0,0 +1,18 @@
package client
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
)
func TestErrorNoData(t *testing.T) {
e1 := ErrNoData()
e1.Error()
assert.True(t, IsNoDataErr(e1))
e2 := errors.New("foobar")
assert.False(t, IsNoDataErr(e2))
assert.False(t, IsNoDataErr(nil))
}

View File

@ -5,8 +5,8 @@ import (
"github.com/tendermint/go-wire/data"
"github.com/tendermint/iavl"
lc "github.com/tendermint/light-client"
"github.com/tendermint/light-client/certifiers"
certerr "github.com/tendermint/light-client/certifiers/errors"
"github.com/tendermint/tendermint/rpc/client"
)
@ -38,7 +38,7 @@ func GetWithProof(key []byte, reqHeight int, node client.Client,
return
}
if len(resp.Key) == 0 || len(resp.Proof) == 0 {
err = lc.ErrNoData()
err = ErrNoData()
return
}
if resp.Height == 0 {
@ -47,8 +47,8 @@ func GetWithProof(key []byte, reqHeight int, node client.Client,
}
// AppHash for height H is in header H+1
var check lc.Checkpoint
check, err = GetCertifiedCheckpoint(int(resp.Height+1), node, cert)
var commit *certifiers.Commit
commit, err = GetCertifiedCommit(int(resp.Height+1), node, cert)
if err != nil {
return
}
@ -63,7 +63,7 @@ func GetWithProof(key []byte, reqHeight int, node client.Client,
}
// Validate the proof against the certified header to ensure data integrity.
err = eproof.Verify(resp.Key, resp.Value, check.Header.AppHash)
err = eproof.Verify(resp.Key, resp.Value, commit.Header.AppHash)
if err != nil {
err = errors.Wrap(err, "Couldn't verify proof")
return
@ -79,12 +79,12 @@ func GetWithProof(key []byte, reqHeight int, node client.Client,
return
}
// Validate the proof against the certified header to ensure data integrity.
err = aproof.Verify(resp.Key, nil, check.Header.AppHash)
err = aproof.Verify(resp.Key, nil, commit.Header.AppHash)
if err != nil {
err = errors.Wrap(err, "Couldn't verify proof")
return
}
err = lc.ErrNoData()
err = ErrNoData()
proof = aproof
}
@ -92,28 +92,25 @@ func GetWithProof(key []byte, reqHeight int, node client.Client,
return
}
// GetCertifiedCheckpoint gets the signed header for a given height
// GetCertifiedCommit gets the signed header for a given height
// and certifies it. Returns error if unable to get a proven header.
func GetCertifiedCheckpoint(h int, node client.Client,
cert certifiers.Certifier) (empty lc.Checkpoint, err error) {
func GetCertifiedCommit(h int, node client.Client,
cert certifiers.Certifier) (empty *certifiers.Commit, err error) {
// FIXME: cannot use cert.GetByHeight for now, as it also requires
// Validators and will fail on querying tendermint for non-current height.
// When this is supported, we should use it instead...
client.WaitForHeight(node, h, nil)
commit, err := node.Commit(&h)
cresp, err := node.Commit(&h)
if err != nil {
return
}
check := lc.Checkpoint{
Header: commit.Header,
Commit: commit.Commit,
}
commit := certifiers.CommitFromResult(cresp)
// validate downloaded checkpoint with our request and trust store.
if check.Height() != h {
return empty, lc.ErrHeightMismatch(h, check.Height())
if commit.Height() != h {
return empty, certerr.ErrHeightMismatch(h, commit.Height())
}
err = cert.Certify(check)
return check, nil
err = cert.Certify(commit)
return commit, nil
}

View File

@ -9,14 +9,14 @@ import (
"github.com/stretchr/testify/require"
"github.com/tendermint/go-wire"
lc "github.com/tendermint/light-client"
"github.com/tendermint/light-client/certifiers"
certclient "github.com/tendermint/light-client/certifiers/client"
"github.com/tendermint/tmlibs/log"
nm "github.com/tendermint/tendermint/node"
"github.com/tendermint/tendermint/rpc/client"
rpctest "github.com/tendermint/tendermint/rpc/test"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/log"
sdkapp "github.com/cosmos/cosmos-sdk/app"
"github.com/cosmos/cosmos-sdk/modules/eyes"
@ -59,13 +59,13 @@ func TestAppProofs(t *testing.T) {
brh := br.Height
// This sets up our trust on the node based on some past point.
source := certclient.New(cl)
source := certclient.NewProvider(cl)
seed, err := source.GetByHeight(br.Height - 2)
require.NoError(err, "%+v", err)
cert := certifiers.NewStatic("my-chain", seed.Validators)
client.WaitForHeight(cl, 3, nil)
latest, err := source.GetLatestCommit()
latest, err := source.LatestCommit()
require.NoError(err, "%+v", err)
rootHash := latest.Header.AppHash
@ -75,7 +75,7 @@ func TestAppProofs(t *testing.T) {
// verify a query before the tx block has no data (and valid non-exist proof)
bs, height, proof, err := GetWithProof(k, brh-1, cl, cert)
require.NotNil(err)
require.True(lc.IsNoDataErr(err))
require.True(IsNoDataErr(err))
require.Nil(bs)
// but given that block it is good
@ -98,7 +98,7 @@ func TestAppProofs(t *testing.T) {
// Test non-existing key.
missing := []byte("my-missing-key")
bs, _, proof, err = GetWithProof(missing, 0, cl, cert)
require.True(lc.IsNoDataErr(err))
require.True(IsNoDataErr(err))
require.Nil(bs)
require.NotNil(proof)
err = proof.Verify(missing, nil, rootHash)
@ -122,7 +122,7 @@ func TestTxProofs(t *testing.T) {
require.EqualValues(0, br.DeliverTx.Code)
fmt.Printf("tx height: %d\n", br.Height)
source := certclient.New(cl)
source := certclient.NewProvider(cl)
seed, err := source.GetByHeight(br.Height - 2)
require.NoError(err, "%+v", err)
cert := certifiers.NewStatic("my-chain", seed.Validators)
@ -141,8 +141,8 @@ func TestTxProofs(t *testing.T) {
err = res.Proof.Validate(key)
assert.NoError(err, "%+v", err)
check, err := GetCertifiedCheckpoint(int(br.Height), cl, cert)
commit, err := GetCertifiedCommit(int(br.Height), cl, cert)
require.Nil(err, "%+v", err)
require.Equal(res.Proof.RootHash, check.Header.DataHash)
require.Equal(res.Proof.RootHash, commit.Header.DataHash)
}

View File

@ -237,7 +237,7 @@ info about self...
}
```
`/seeds`
`/commits`
```
{
@ -246,4 +246,4 @@ info about self...
}
```
info on last seed
info on last commit

View File

@ -9,11 +9,11 @@ import (
"github.com/cosmos/cosmos-sdk/client/commands"
"github.com/cosmos/cosmos-sdk/client/commands/auto"
"github.com/cosmos/cosmos-sdk/client/commands/commits"
"github.com/cosmos/cosmos-sdk/client/commands/keys"
"github.com/cosmos/cosmos-sdk/client/commands/proxy"
"github.com/cosmos/cosmos-sdk/client/commands/query"
rpccmd "github.com/cosmos/cosmos-sdk/client/commands/rpc"
"github.com/cosmos/cosmos-sdk/client/commands/seeds"
txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs"
authcmd "github.com/cosmos/cosmos-sdk/modules/auth/commands"
basecmd "github.com/cosmos/cosmos-sdk/modules/base/commands"
@ -77,7 +77,7 @@ func main() {
commands.InitCmd,
commands.ResetCmd,
keys.RootCmd,
seeds.RootCmd,
commits.RootCmd,
rpccmd.RootCmd,
query.RootCmd,
txcmd.RootCmd,

View File

@ -84,18 +84,18 @@ test00GetAccount() {
}
test01RegisterChains() {
# let's get the root seeds to cross-register them
ROOT_1="$BASE_DIR_1/root_seed.json"
${CLIENT_EXE} seeds export $ROOT_1 --home=${CLIENT_1}
assertTrue "line=${LINENO}, export seed failed" $?
# let's get the root commits to cross-register them
ROOT_1="$BASE_DIR_1/root_commit.json"
${CLIENT_EXE} commits export $ROOT_1 --home=${CLIENT_1}
assertTrue "line=${LINENO}, export commit failed" $?
ROOT_2="$BASE_DIR_2/root_seed.json"
${CLIENT_EXE} seeds export $ROOT_2 --home=${CLIENT_2}
assertTrue "line=${LINENO}, export seed failed" $?
ROOT_2="$BASE_DIR_2/root_commit.json"
${CLIENT_EXE} commits export $ROOT_2 --home=${CLIENT_2}
assertTrue "line=${LINENO}, export commit failed" $?
# register chain2 on chain1
TX=$(echo qwertyuiop | ${CLIENT_EXE} tx ibc-register \
--sequence=1 --seed=${ROOT_2} --name=$POOR --home=${CLIENT_1})
--sequence=1 --commit=${ROOT_2} --name=$POOR --home=${CLIENT_1})
txSucceeded $? "$TX" "register chain2 on chain 1"
# an example to quit early if there is no point in more tests
if [ $? != 0 ]; then echo "aborting!"; return 1; fi
@ -104,40 +104,40 @@ test01RegisterChains() {
# register chain1 on chain2 (no money needed... yet)
TX=$(echo qwertyuiop | ${CLIENT_EXE} tx ibc-register \
--sequence=1 --seed=${ROOT_1} --name=$POOR --home=${CLIENT_2})
--sequence=1 --commit=${ROOT_1} --name=$POOR --home=${CLIENT_2})
txSucceeded $? "$TX" "register chain1 on chain 2"
# an example to quit early if there is no point in more tests
if [ $? != 0 ]; then echo "aborting!"; return 1; fi
}
test02UpdateChains() {
# let's get the root seeds to cross-register them
# let's get the root commits to cross-register them
UPDATE_1="$BASE_DIR_1/seed_1.json"
${CLIENT_EXE} seeds update --home=${CLIENT_1} > /dev/null
${CLIENT_EXE} seeds export $UPDATE_1 --home=${CLIENT_1}
assertTrue "line=${LINENO}, export seed failed" $?
${CLIENT_EXE} commits update --home=${CLIENT_1} > /dev/null
${CLIENT_EXE} commits export $UPDATE_1 --home=${CLIENT_1}
assertTrue "line=${LINENO}, export commit failed" $?
# make sure it is newer than the other....
assertNewHeight "line=${LINENO}" $ROOT_1 $UPDATE_1
UPDATE_2="$BASE_DIR_2/seed_2.json"
${CLIENT_EXE} seeds update --home=${CLIENT_2} > /dev/null
${CLIENT_EXE} seeds export $UPDATE_2 --home=${CLIENT_2}
assertTrue "line=${LINENO}, export seed failed" $?
${CLIENT_EXE} commits update --home=${CLIENT_2} > /dev/null
${CLIENT_EXE} commits export $UPDATE_2 --home=${CLIENT_2}
assertTrue "line=${LINENO}, export commit failed" $?
assertNewHeight "line=${LINENO}" $ROOT_2 $UPDATE_2
# this is used later to check query data
REGISTER_2_HEIGHT=$(cat $ROOT_2 | jq .checkpoint.header.height)
UPDATE_2_HEIGHT=$(cat $UPDATE_2 | jq .checkpoint.header.height)
REGISTER_2_HEIGHT=$(cat $ROOT_2 | jq .commit.header.height)
UPDATE_2_HEIGHT=$(cat $UPDATE_2 | jq .commit.header.height)
# update chain2 on chain1
TX=$(echo qwertyuiop | ${CLIENT_EXE} tx ibc-update \
--sequence=2 --seed=${UPDATE_2} --name=$POOR --home=${CLIENT_1})
--sequence=2 --commit=${UPDATE_2} --name=$POOR --home=${CLIENT_1})
txSucceeded $? "$TX" "update chain2 on chain 1"
# an example to quit early if there is no point in more tests
if [ $? != 0 ]; then echo "aborting!"; return 1; fi
# update chain1 on chain2 (no money needed... yet)
TX=$(echo qwertyuiop | ${CLIENT_EXE} tx ibc-update \
--sequence=2 --seed=${UPDATE_1} --name=$POOR --home=${CLIENT_2})
--sequence=2 --commit=${UPDATE_1} --name=$POOR --home=${CLIENT_2})
txSucceeded $? "$TX" "update chain1 on chain 2"
# an example to quit early if there is no point in more tests
if [ $? != 0 ]; then echo "aborting!"; return 1; fi
@ -224,24 +224,24 @@ test05ReceiveIBCPacket() {
# now, we try to post it.... (this is PACKET from last test)
# get the seed with the proof and post it
# get the commit with the proof and post it
SRC_HEIGHT=$(echo $PACKET | jq .src_height)
PROOF_HEIGHT=$(expr $SRC_HEIGHT + 1)
# FIXME: this should auto-update on proofs...
${CLIENT_EXE} seeds update --height=$PROOF_HEIGHT --home=${CLIENT_1} > /dev/null
assertTrue "line=${LINENO}, update seed failed" $?
${CLIENT_EXE} commits update --height=$PROOF_HEIGHT --home=${CLIENT_1} > /dev/null
assertTrue "line=${LINENO}, update commit failed" $?
PACKET_SEED="$BASE_DIR_1/packet_seed.json"
${CLIENT_EXE} seeds export $PACKET_SEED --home=${CLIENT_1} --height=$PROOF_HEIGHT
assertTrue "line=${LINENO}, export seed failed" $?
PACKET_COMMIT="$BASE_DIR_1/packet_commit.json"
${CLIENT_EXE} commits export $PACKET_COMMIT --home=${CLIENT_1} --height=$PROOF_HEIGHT
assertTrue "line=${LINENO}, export commit failed" $?
if [ -n "$DEBUG" ]; then
echo "**** SEED ****"
cat $PACKET_SEED | jq .checkpoint.header
cat $PACKET_COMMIT | jq .commit.header
echo
fi
TX=$(echo qwertyuiop | ${CLIENT_EXE} tx ibc-update \
--seed=${PACKET_SEED} --name=$POOR --sequence=3)
--commit=${PACKET_COMMIT} --name=$POOR --sequence=3)
txSucceeded $? "$TX" "prepare packet chain1 on chain 2"
# an example to quit early if there is no point in more tests
if [ $? != 0 ]; then echo "aborting!"; return 1; fi
@ -268,11 +268,11 @@ test05ReceiveIBCPacket() {
}
# XXX Ex Usage: assertNewHeight $MSG $SEED_1 $SEED_2
# Desc: Asserts that seed2 has a higher block height than seed 1
# Desc: Asserts that seed2 has a higher block height than commit 1
assertNewHeight() {
H1=$(cat $2 | jq .checkpoint.header.height)
H2=$(cat $3 | jq .checkpoint.header.height)
assertTrue "$MSG" "test $H2 -gt $H1"
H1=$(cat $2 | jq .commit.header.height)
H2=$(cat $3 | jq .commit.header.height)
assertTrue "$1" "test $H2 -gt $H1"
return $?
}

View File

@ -8,10 +8,10 @@ import (
"github.com/tendermint/tmlibs/cli"
"github.com/cosmos/cosmos-sdk/client/commands"
"github.com/cosmos/cosmos-sdk/client/commands/commits"
"github.com/cosmos/cosmos-sdk/client/commands/keys"
"github.com/cosmos/cosmos-sdk/client/commands/proxy"
"github.com/cosmos/cosmos-sdk/client/commands/query"
"github.com/cosmos/cosmos-sdk/client/commands/seeds"
txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs"
bcount "github.com/cosmos/cosmos-sdk/examples/counter/cmd/countercli/commands"
@ -74,7 +74,7 @@ func main() {
commands.ResetCmd,
commands.VersionCmd,
keys.RootCmd,
seeds.RootCmd,
commits.RootCmd,
query.RootCmd,
txcmd.RootCmd,
proxy.RootCmd,

View File

@ -9,9 +9,9 @@ import (
"github.com/cosmos/cosmos-sdk/client/commands"
"github.com/cosmos/cosmos-sdk/client/commands/auto"
"github.com/cosmos/cosmos-sdk/client/commands/commits"
"github.com/cosmos/cosmos-sdk/client/commands/query"
rpccmd "github.com/cosmos/cosmos-sdk/client/commands/rpc"
"github.com/cosmos/cosmos-sdk/client/commands/seeds"
txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs"
eyescmd "github.com/cosmos/cosmos-sdk/modules/eyes/commands"
)
@ -50,7 +50,7 @@ func main() {
// we use out own init command to not require address arg
commands.InitCmd,
commands.ResetCmd,
seeds.RootCmd,
commits.RootCmd,
rpccmd.RootCmd,
query.RootCmd,
txcmd.RootCmd,

83
glide.lock generated
View File

@ -1,22 +1,24 @@
hash: fbfdd03c0367bb0785ceb81ed34059df219e55d5a9c71c12597e505fbce14165
updated: 2017-10-23T14:49:22.891642342+02:00
updated: 2017-10-25T19:24:51.90002008+02:00
imports:
- name: github.com/bgentry/speakeasy
version: 4aabc24848ce5fd31929f7d1e4ea74d3709c14cd
- name: github.com/btcsuite/btcd
version: b8df516b4b267acf2de46be593a9d948d1d2c420
version: c7588cbf7690cd9f047a28efa2dcd8f2435a4e5e
subpackages:
- btcec
- name: github.com/btcsuite/fastsha256
version: 637e656429416087660c84436a2a035d69d54e2e
- name: github.com/BurntSushi/toml
version: a368813c5e648fee92e5f6c30e3944ff9d5e8895
- name: github.com/ebuchman/fail-test
version: 95f809107225be108efcf10a3509e4ea6ceef3c4
- name: github.com/ethanfrey/ledger
version: 5e432577be582bd18a3b4a9cd75dae7a317ade36
- name: github.com/flynn/hid
version: ed06a31c6245d4552e8dbba7e32e5b010b875d65
- name: github.com/fsnotify/fsnotify
version: 4da3e2cfbabc9f751898f250b49f2439785783a1
- name: github.com/go-kit/kit
version: d67bb4c202e3b91377d1079b110a6c9ce23ab2f8
version: e2b298466b32c7cd5579a9b9b07e968fc9d9452c
subpackages:
- log
- log/level
@ -24,18 +26,21 @@ imports:
- name: github.com/go-logfmt/logfmt
version: 390ab7935ee28ec6b286364bba9b4dd6410cb3d5
- name: github.com/go-playground/locales
version: 1e5f1161c6416a5ff48840eb8724a394e48cc534
version: e4cbcb5d0652150d40ad0646651076b6bd2be4f6
subpackages:
- currency
- name: github.com/go-playground/universal-translator
version: 71201497bace774495daed26a3874fd339e0b538
- name: github.com/go-stack/stack
version: 100eb0c0a9c5b306ca2fb4f165df21d80ada4b82
version: 817915b46b97fd7bb80e8ab6b69f01a53ac3eebf
- name: github.com/golang/protobuf
version: 18c9bb3261723cd5401db4d0c9fbc5c3b6c70fe8
version: 1643683e1b54a9e88ad26d98f81400c8c9d9f4f9
subpackages:
- proto
- ptypes
- ptypes/any
- ptypes/duration
- ptypes/timestamp
- name: github.com/golang/snappy
version: 553a641470496b2327abcac10b36396bd98e45c9
- name: github.com/gorilla/context
@ -43,9 +48,9 @@ imports:
- name: github.com/gorilla/mux
version: 24fca303ac6da784b9e8269f724ddeb0b2eea5e7
- name: github.com/gorilla/websocket
version: a91eba7f97777409bc2c443f5534d41dd20c5720
version: 71fa72d4842364bc5f74185f4161e0099ea3624a
- name: github.com/hashicorp/hcl
version: 392dba7d905ed5d04a5794ba89f558b27e2ba1ca
version: 23c074d0eceb2b8a5bfdbb271ab780cde70f05a8
subpackages:
- hcl/ast
- hcl/parser
@ -64,11 +69,11 @@ imports:
- name: github.com/kr/logfmt
version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0
- name: github.com/magiconair/properties
version: 51463bfca2576e06c62a8504b5c0f06d61312647
version: 8d7837e64d3c1ee4e54a880c5a920ab4316fc90a
- name: github.com/mattn/go-isatty
version: a5cdd64afdee435007ee3e9f6ed4684af949d568
- name: github.com/mitchellh/mapstructure
version: cc8532a8e9a55ea36402aa21efdf403a60d34096
version: 06020f85339e21b2478f756a78e295255ffa4d6a
- name: github.com/pelletier/go-buffruneio
version: c37440a7cf42ac63b919c752ca73a85067e05992
- name: github.com/pelletier/go-toml
@ -78,21 +83,21 @@ imports:
- name: github.com/rcrowley/go-metrics
version: 1f30fe9094a513ce4c700b9a54458bbb0c96996c
- name: github.com/spf13/afero
version: 9be650865eab0c12963d8753212f4f9c66cdcf12
version: 5660eeed305fe5f69c8fc6cf899132a459a97064
subpackages:
- mem
- name: github.com/spf13/cast
version: acbeb36b902d72a7a4c18e8f3241075e7ab763e4
- name: github.com/spf13/cobra
version: 4cdb38c072b86bf795d2c81de50784d9fdd6eb77
version: 7b2c5ac9fc04fc5efafb60700713d4fa609b777b
- name: github.com/spf13/jwalterweatherman
version: 8f07c835e5cc1450c082fe3a439cf87b0cbb2d99
version: 12bd96e66386c1960ab0f74ced1362f66f552f7b
- name: github.com/spf13/pflag
version: e57e3eeb33f795204c1ca35f56c44f83227c6e66
version: 97afa5e7ca8a08a383cb259e06636b5e2cc7897f
- name: github.com/spf13/viper
version: 0967fc9aceab2ce9da34061253ac10fb99bba5b2
version: 8ef37cbca71638bf32f3d5e194117d4cb46da163
- name: github.com/syndtr/goleveldb
version: 8c81ea47d4c41a385645e133e15510fc6a2a74b4
version: b89cc31ef7977104127d34c1bd31ebd1a9db2199
subpackages:
- leveldb
- leveldb/cache
@ -119,7 +124,7 @@ imports:
- edwards25519
- extra25519
- name: github.com/tendermint/go-crypto
version: 8e7f0e7701f92206679ad093d013b9b162427631
version: 0a5b1d979a1bc86200c9ff829fbbcd575799a1b6
subpackages:
- bcrypt
- keys
@ -127,22 +132,24 @@ imports:
- keys/storage/filestorage
- keys/storage/memstorage
- keys/wordlist
- nano
- name: github.com/tendermint/go-wire
version: 55ae61f1fc83cfaa57ab7d54250d7a1a2be0b83c
version: 99d2169a1e39c65983eacaa1da867d6f3218e1c9
subpackages:
- data
- data/base58
- name: github.com/tendermint/iavl
version: 721710e7aa59f61dbfbf558943a207ba3fe6b926
version: 595f3dcd5b6cd4a292e90757ae6d367fd7a6e653
- name: github.com/tendermint/light-client
version: 569e1583da8a52e499764533f3a05d05be6d56d6
version: 76313d625e662ed7b284d066d68ff71edd7a9fac
subpackages:
- certifiers
- certifiers/client
- certifiers/errors
- certifiers/files
- proofs
- name: github.com/tendermint/tendermint
version: fa56e8c0ce463f77c87ab17a3d7cf5431d9f2c0b
version: b2d5546cf8f71e0e168072e118d9836862384e6c
subpackages:
- blockchain
- cmd/tendermint/commands
@ -170,7 +177,7 @@ imports:
- types
- version
- name: github.com/tendermint/tmlibs
version: 8e5266a9ef2527e68a1571f932db8228a331b556
version: 0a652499ead7cd20a57a6a592f0491a2b493bb85
subpackages:
- autofile
- cli
@ -184,7 +191,7 @@ imports:
- logger
- merkle
- name: golang.org/x/crypto
version: c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
version: edd5e9b0879d13ee6970a50153d85b8fec9f7686
subpackages:
- blowfish
- curve25519
@ -196,7 +203,7 @@ imports:
- ripemd160
- salsa20/salsa
- name: golang.org/x/net
version: feeb485667d1fdabe727840fe00adc22431bc86e
version: cd69bc3fc700721b709c3a59e16e24c67b58f6ff
subpackages:
- context
- http2
@ -206,43 +213,49 @@ imports:
- lex/httplex
- trace
- name: golang.org/x/sys
version: e62c3de784db939836898e5c19ffd41bece347da
version: 8dbc5d05d6edcc104950cc299a1ce6641235bc86
subpackages:
- unix
- name: golang.org/x/text
version: 470f45bf29f4147d6fbd7dfd0a02a848e49f5bf4
version: c01e4764d870b77f8abe5096ee19ad20d80e8075
subpackages:
- secure/bidirule
- transform
- unicode/bidi
- unicode/norm
- name: google.golang.org/genproto
version: 411e09b969b1170a9f0c467558eb4c4c110d9c77
version: f676e0f3ac6395ff1a529ae59a6670878a8371a6
subpackages:
- googleapis/rpc/status
- name: google.golang.org/grpc
version: 844f573616520565fdc6fb4db242321b5456fd6d
version: a5986a5c88227370a9c0a82e5277167229c034cd
subpackages:
- balancer
- balancer/roundrobin
- codes
- connectivity
- credentials
- grpclb/grpc_lb_v1
- grpclb/grpc_lb_v1/messages
- grpclog
- internal
- keepalive
- metadata
- naming
- peer
- resolver
- resolver/dns
- resolver/passthrough
- stats
- status
- tap
- transport
- name: gopkg.in/go-playground/validator.v9
version: 6d8c18553ea1ac493d049edd6f102f52e618f085
version: 1304298bf10d085adec514b076772a79c9cadb6b
- name: gopkg.in/yaml.v2
version: cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b
version: eb3733d160e74a9c7e442f435eb3bea458e1d19f
testImports:
- name: github.com/davecgh/go-spew
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9
subpackages:
- spew
- name: github.com/pmezard/go-difflib
@ -250,7 +263,7 @@ testImports:
subpackages:
- difflib
- name: github.com/stretchr/testify
version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0
version: 2aa2c176b9dab406a6970f6a55f513e8a8c8b18f
subpackages:
- assert
- require

View File

@ -5,8 +5,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
lc "github.com/tendermint/light-client"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/commands"
"github.com/cosmos/cosmos-sdk/client/commands/query"
"github.com/cosmos/cosmos-sdk/modules/coin"
@ -35,7 +34,7 @@ func accountQueryCmd(cmd *cobra.Command, args []string) error {
acc := coin.Account{}
prove := !viper.GetBool(commands.FlagTrustNode)
height, err := query.GetParsed(key, &acc, query.GetHeight(), prove)
if lc.IsNoDataErr(err) {
if client.IsNoDataErr(err) {
return errors.Errorf("Account bytes are empty for address %s ", addr)
} else if err != nil {
return err

View File

@ -252,7 +252,7 @@ func TestSetIssuer(t *testing.T) {
}{
{sdk.Actor{App: "sig", Address: []byte("gwkfgk")}},
// and set back to empty (nil is valid, but assert.Equals doesn't match)
{sdk.Actor{Address: []byte{}}},
{sdk.Actor{}},
{sdk.Actor{ChainID: "other", App: "role", Address: []byte("vote")}},
}

View File

@ -10,6 +10,7 @@ import (
"github.com/spf13/viper"
sdk "github.com/cosmos/cosmos-sdk"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/commands"
"github.com/cosmos/cosmos-sdk/client/commands/query"
"github.com/cosmos/cosmos-sdk/modules/auth"
@ -18,7 +19,6 @@ import (
"github.com/cosmos/cosmos-sdk/modules/fee"
"github.com/cosmos/cosmos-sdk/modules/nonce"
"github.com/cosmos/cosmos-sdk/stack"
lightclient "github.com/tendermint/light-client"
"github.com/tendermint/tmlibs/common"
)
@ -62,7 +62,7 @@ func doQueryAccount(w http.ResponseWriter, r *http.Request) {
account := new(coin.Account)
prove := !viper.GetBool(commands.FlagTrustNode)
height, err := query.GetParsed(key, account, h, prove)
if lightclient.IsNoDataErr(err) {
if client.IsNoDataErr(err) {
err := fmt.Errorf("account bytes are empty for address: %q", signature)
common.WriteError(w, err)
return

View File

@ -39,36 +39,36 @@ var PostPacketTxCmd = &cobra.Command{
//nolint
const (
FlagSeed = "seed"
FlagCommit = "commit"
FlagPacket = "packet"
)
func init() {
fs1 := RegisterChainTxCmd.Flags()
fs1.String(FlagSeed, "", "Filename with a seed file")
fs1.String(FlagCommit, "", "Filename with a commit file")
fs2 := UpdateChainTxCmd.Flags()
fs2.String(FlagSeed, "", "Filename with a seed file")
fs2.String(FlagCommit, "", "Filename with a commit file")
fs3 := PostPacketTxCmd.Flags()
fs3.String(FlagPacket, "", "Filename with a packet to post")
}
func registerChainTxCmd(cmd *cobra.Command, args []string) error {
seed, err := readSeed()
fc, err := readCommit()
if err != nil {
return err
}
tx := ibc.RegisterChainTx{seed}.Wrap()
tx := ibc.RegisterChainTx{fc}.Wrap()
return txcmd.DoTx(tx)
}
func updateChainTxCmd(cmd *cobra.Command, args []string) error {
seed, err := readSeed()
fc, err := readCommit()
if err != nil {
return err
}
tx := ibc.UpdateChainTx{seed}.Wrap()
tx := ibc.UpdateChainTx{fc}.Wrap()
return txcmd.DoTx(tx)
}
@ -80,13 +80,13 @@ func postPacketTxCmd(cmd *cobra.Command, args []string) error {
return txcmd.DoTx(post.Wrap())
}
func readSeed() (seed certifiers.Seed, err error) {
name := viper.GetString(FlagSeed)
func readCommit() (fc certifiers.FullCommit, err error) {
name := viper.GetString(FlagCommit)
if name == "" {
return seed, errors.New("You must specify a seed file")
return fc, errors.New("You must specify a commit file")
}
err = readFile(name, &seed)
err = readFile(name, &fc)
return
}

View File

@ -100,20 +100,20 @@ func (h Handler) DeliverTx(ctx sdk.Context, store state.SimpleDB, tx sdk.Tx) (re
switch t := tx.Unwrap().(type) {
case RegisterChainTx:
return h.initSeed(ctx, store, t)
return h.registerChain(ctx, store, t)
case UpdateChainTx:
return h.updateSeed(ctx, store, t)
return h.updateChain(ctx, store, t)
case CreatePacketTx:
return h.createPacket(ctx, store, t)
}
return res, errors.ErrUnknownTxType(tx.Unwrap())
}
// initSeed imports the first seed for this chain and
// registerChain imports the first seed for this chain and
// accepts it as the root of trust.
//
// only the registrar, if set, is allowed to do this
func (h Handler) initSeed(ctx sdk.Context, store state.SimpleDB,
func (h Handler) registerChain(ctx sdk.Context, store state.SimpleDB,
t RegisterChainTx) (res sdk.DeliverResult, err error) {
info := LoadInfo(store)
@ -124,20 +124,20 @@ func (h Handler) initSeed(ctx sdk.Context, store state.SimpleDB,
// verify that the header looks reasonable
chainID := t.ChainID()
s := NewChainSet(store)
err = s.Register(chainID, ctx.BlockHeight(), t.Seed.Height())
err = s.Register(chainID, ctx.BlockHeight(), t.Commit.Height())
if err != nil {
return res, err
}
space := stack.PrefixedStore(chainID, store)
provider := newDBProvider(space)
err = provider.StoreSeed(t.Seed)
err = provider.StoreCommit(t.Commit)
return res, err
}
// updateSeed checks the seed against the existing chain data and rejects it if it
// updateChain checks the seed against the existing chain data and rejects it if it
// doesn't fit (or no chain data)
func (h Handler) updateSeed(ctx sdk.Context, store state.SimpleDB,
func (h Handler) updateChain(ctx sdk.Context, store state.SimpleDB,
t UpdateChainTx) (res sdk.DeliverResult, err error) {
chainID := t.ChainID()
@ -147,21 +147,21 @@ func (h Handler) updateSeed(ctx sdk.Context, store state.SimpleDB,
}
// load the certifier for this chain
seed := t.Seed
fc := t.Commit
space := stack.PrefixedStore(chainID, store)
cert, err := newCertifier(space, chainID, seed.Height())
cert, err := newCertifier(space, chainID, fc.Height())
if err != nil {
return res, err
}
// this will import the seed if it is valid in the current context
err = cert.Update(seed.Checkpoint, seed.Validators)
// this will import the commit if it is valid in the current context
err = cert.Update(fc)
if err != nil {
return res, ErrInvalidCommit(err)
}
// update the tracked height in chain info
err = s.Update(chainID, t.Seed.Height())
err = s.Update(chainID, fc.Height())
return res, err
}

View File

@ -27,28 +27,28 @@ func TestIBCRegister(t *testing.T) {
appHash := []byte{0, 4, 7, 23}
appHash2 := []byte{12, 34, 56, 78}
// badSeed doesn't validate
badSeed := genEmptySeed(keys2, "chain-2", 123, appHash, len(keys2))
badSeed.Header.AppHash = appHash2
// badCommit doesn't validate
badCommit := genEmptyCommit(keys2, "chain-2", 123, appHash, len(keys2))
badCommit.Header.AppHash = appHash2
cases := []struct {
seed certifiers.Seed
fc certifiers.FullCommit
checker errors.CheckErr
}{
{
genEmptySeed(keys, "chain-1", 100, appHash, len(keys)),
genEmptyCommit(keys, "chain-1", 100, appHash, len(keys)),
errors.NoErr,
},
{
genEmptySeed(keys, "chain-1", 200, appHash, len(keys)),
genEmptyCommit(keys, "chain-1", 200, appHash, len(keys)),
IsAlreadyRegisteredErr,
},
{
badSeed,
badCommit,
IsInvalidCommitErr,
},
{
genEmptySeed(keys2, "chain-2", 123, appHash2, 5),
genEmptyCommit(keys2, "chain-2", 123, appHash2, 5),
errors.NoErr,
},
}
@ -58,7 +58,7 @@ func TestIBCRegister(t *testing.T) {
app := stack.New().Dispatch(stack.WrapHandler(NewHandler()))
for i, tc := range cases {
tx := RegisterChainTx{tc.seed}.Wrap()
tx := RegisterChainTx{tc.fc}.Wrap()
_, err := app.DeliverTx(ctx, store, tx)
assert.True(tc.checker(err), "%d: %+v", i, err)
}
@ -78,45 +78,45 @@ func TestIBCRegisterPermissions(t *testing.T) {
foobaz := sdk.Actor{App: "foo", Address: []byte("baz")}
cases := []struct {
seed certifiers.Seed
seed certifiers.FullCommit
registrar sdk.Actor
signer sdk.Actor
checker errors.CheckErr
}{
// no sig, no registrar
{
seed: genEmptySeed(keys, "chain-1", 100, appHash, len(keys)),
seed: genEmptyCommit(keys, "chain-1", 100, appHash, len(keys)),
checker: errors.NoErr,
},
// sig, no registrar
{
seed: genEmptySeed(keys, "chain-2", 100, appHash, len(keys)),
seed: genEmptyCommit(keys, "chain-2", 100, appHash, len(keys)),
signer: foobaz,
checker: errors.NoErr,
},
// registrar, no sig
{
seed: genEmptySeed(keys, "chain-3", 100, appHash, len(keys)),
seed: genEmptyCommit(keys, "chain-3", 100, appHash, len(keys)),
registrar: foobar,
checker: errors.IsUnauthorizedErr,
},
// registrar, wrong sig
{
seed: genEmptySeed(keys, "chain-4", 100, appHash, len(keys)),
seed: genEmptyCommit(keys, "chain-4", 100, appHash, len(keys)),
signer: foobaz,
registrar: foobar,
checker: errors.IsUnauthorizedErr,
},
// registrar, wrong sig
{
seed: genEmptySeed(keys, "chain-5", 100, appHash, len(keys)),
seed: genEmptyCommit(keys, "chain-5", 100, appHash, len(keys)),
signer: baz,
registrar: foobar,
checker: errors.IsUnauthorizedErr,
},
// registrar, proper sig
{
seed: genEmptySeed(keys, "chain-6", 100, appHash, len(keys)),
seed: genEmptyCommit(keys, "chain-6", 100, appHash, len(keys)),
signer: foobar,
registrar: foobar,
checker: errors.NoErr,
@ -151,7 +151,7 @@ func TestIBCUpdate(t *testing.T) {
keys := certifiers.GenValKeys(7)
appHash := []byte{0, 4, 7, 23}
start := 100 // initial height
root := genEmptySeed(keys, "chain-1", 100, appHash, len(keys))
root := genEmptyCommit(keys, "chain-1", 100, appHash, len(keys))
keys2 := keys.Extend(2)
keys3 := keys2.Extend(2)
@ -165,53 +165,53 @@ func TestIBCUpdate(t *testing.T) {
require.Nil(err, "%+v", err)
cases := []struct {
seed certifiers.Seed
fc certifiers.FullCommit
checker errors.CheckErr
}{
// same validator, higher up
{
genEmptySeed(keys, "chain-1", start+50, []byte{22}, len(keys)),
genEmptyCommit(keys, "chain-1", start+50, []byte{22}, len(keys)),
errors.NoErr,
},
// same validator, between existing (not most recent)
{
genEmptySeed(keys, "chain-1", start+5, []byte{15, 43}, len(keys)),
genEmptyCommit(keys, "chain-1", start+5, []byte{15, 43}, len(keys)),
errors.NoErr,
},
// same validators, before root of trust
{
genEmptySeed(keys, "chain-1", start-8, []byte{11, 77}, len(keys)),
genEmptyCommit(keys, "chain-1", start-8, []byte{11, 77}, len(keys)),
IsHeaderNotFoundErr,
},
// insufficient signatures
{
genEmptySeed(keys, "chain-1", start+60, []byte{24}, len(keys)/2),
genEmptyCommit(keys, "chain-1", start+60, []byte{24}, len(keys)/2),
IsInvalidCommitErr,
},
// unregistered chain
{
genEmptySeed(keys, "chain-2", start+60, []byte{24}, len(keys)/2),
genEmptyCommit(keys, "chain-2", start+60, []byte{24}, len(keys)/2),
IsNotRegisteredErr,
},
// too much change (keys -> keys3)
{
genEmptySeed(keys3, "chain-1", start+100, []byte{22}, len(keys3)),
genEmptyCommit(keys3, "chain-1", start+100, []byte{22}, len(keys3)),
IsInvalidCommitErr,
},
// legit update to validator set (keys -> keys2)
{
genEmptySeed(keys2, "chain-1", start+90, []byte{33}, len(keys2)),
genEmptyCommit(keys2, "chain-1", start+90, []byte{33}, len(keys2)),
errors.NoErr,
},
// now impossible jump works (keys -> keys2 -> keys3)
{
genEmptySeed(keys3, "chain-1", start+100, []byte{44}, len(keys3)),
genEmptyCommit(keys3, "chain-1", start+100, []byte{44}, len(keys3)),
errors.NoErr,
},
}
for i, tc := range cases {
tx := UpdateChainTx{tc.seed}.Wrap()
tx := UpdateChainTx{tc.fc}.Wrap()
_, err := app.DeliverTx(ctx, store, tx)
assert.True(tc.checker(err), "%d: %+v", i, err)
}
@ -227,7 +227,7 @@ func TestIBCCreatePacket(t *testing.T) {
appHash := []byte{1, 2, 3, 4}
start := 100 // initial height
chainID := "cosmos-hub"
root := genEmptySeed(keys, chainID, start, appHash, len(keys))
root := genEmptyCommit(keys, chainID, start, appHash, len(keys))
// create the app and register the root of trust (for chain-1)
ctx := stack.MockContext("hub", 50)

View File

@ -3,6 +3,7 @@ package ibc
import (
wire "github.com/tendermint/go-wire"
"github.com/tendermint/light-client/certifiers"
certerr "github.com/tendermint/light-client/certifiers/errors"
"github.com/cosmos/cosmos-sdk/stack"
"github.com/cosmos/cosmos-sdk/state"
@ -17,26 +18,26 @@ const (
// newCertifier loads up the current state of this chain to make a proper certifier
// it will load the most recent height before block h if h is positive
// if h < 0, it will load the latest height
func newCertifier(store state.SimpleDB, chainID string, h int) (*certifiers.InquiringCertifier, error) {
func newCertifier(store state.SimpleDB, chainID string, h int) (*certifiers.Inquiring, error) {
// each chain has their own prefixed subspace
p := newDBProvider(store)
var seed certifiers.Seed
var fc certifiers.FullCommit
var err error
if h > 0 {
// this gets the most recent verified seed below the specified height
seed, err = p.GetByHeight(h)
// this gets the most recent verified commit below the specified height
fc, err = p.GetByHeight(h)
} else {
// 0 or negative means start at latest seed
seed, err = certifiers.LatestSeed(p)
// 0 or negative means start at latest commit
fc, err = p.LatestCommit()
}
if err != nil {
return nil, ErrHeaderNotFound(h)
}
// we have no source for untrusted keys, but use the db to load trusted history
cert := certifiers.NewInquiring(chainID, seed, p,
certifiers.MissingProvider{})
cert := certifiers.NewInquiring(chainID, fc, p,
certifiers.NewMissingProvider())
return cert, nil
}
@ -55,40 +56,49 @@ func newDBProvider(store state.SimpleDB) *dbProvider {
var _ certifiers.Provider = &dbProvider{}
func (d *dbProvider) StoreSeed(seed certifiers.Seed) error {
func (d *dbProvider) StoreCommit(fc certifiers.FullCommit) error {
// TODO: don't duplicate data....
b := wire.BinaryBytes(seed)
d.byHash.Set(seed.Hash(), b)
d.byHeight.Set(uint64(seed.Height()), b)
b := wire.BinaryBytes(fc)
d.byHash.Set(fc.ValidatorsHash(), b)
d.byHeight.Set(uint64(fc.Height()), b)
return nil
}
func (d *dbProvider) GetByHeight(h int) (seed certifiers.Seed, err error) {
b, _ := d.byHeight.LTE(uint64(h))
func (d *dbProvider) LatestCommit() (fc certifiers.FullCommit, err error) {
b, _ := d.byHeight.Top()
if b == nil {
return seed, certifiers.ErrSeedNotFound()
return fc, certerr.ErrCommitNotFound()
}
err = wire.ReadBinaryBytes(b, &seed)
err = wire.ReadBinaryBytes(b, &fc)
return
}
func (d *dbProvider) GetByHash(hash []byte) (seed certifiers.Seed, err error) {
func (d *dbProvider) GetByHeight(h int) (fc certifiers.FullCommit, err error) {
b, _ := d.byHeight.LTE(uint64(h))
if b == nil {
return fc, certerr.ErrCommitNotFound()
}
err = wire.ReadBinaryBytes(b, &fc)
return
}
func (d *dbProvider) GetByHash(hash []byte) (fc certifiers.FullCommit, err error) {
b := d.byHash.Get(hash)
if b == nil {
return seed, certifiers.ErrSeedNotFound()
return fc, certerr.ErrCommitNotFound()
}
err = wire.ReadBinaryBytes(b, &seed)
err = wire.ReadBinaryBytes(b, &fc)
return
}
// GetExactHeight is like GetByHeight, but returns an error instead of
// closest match if there is no exact match
func (d *dbProvider) GetExactHeight(h int) (seed certifiers.Seed, err error) {
seed, err = d.GetByHeight(h)
func (d *dbProvider) GetExactHeight(h int) (fc certifiers.FullCommit, err error) {
fc, err = d.GetByHeight(h)
if err != nil {
return
}
if seed.Height() != h {
if fc.Height() != h {
err = ErrHeaderNotFound(h)
}
return

View File

@ -8,21 +8,22 @@ import (
"github.com/cosmos/cosmos-sdk/state"
"github.com/tendermint/light-client/certifiers"
certerr "github.com/tendermint/light-client/certifiers/errors"
)
func assertSeedEqual(t *testing.T, s, s2 certifiers.Seed) {
func assertCommitsEqual(t *testing.T, fc, fc2 certifiers.FullCommit) {
assert := assert.New(t)
assert.Equal(s.Height(), s2.Height())
assert.Equal(s.Hash(), s2.Hash())
assert.Equal(fc.Height(), fc2.Height())
assert.Equal(fc.ValidatorsHash(), fc2.ValidatorsHash())
// TODO: more
}
func TestProviderStore(t *testing.T) {
assert, require := assert.New(t), require.New(t)
// make a few seeds
// make a few commits
keys := certifiers.GenValKeys(2)
seeds := makeSeeds(keys, 4, "some-chain", "demo-store")
commits := makeCommits(keys, 4, "some-chain", "demo-store")
// make a provider
store := state.NewMemKVStore()
@ -31,41 +32,41 @@ func TestProviderStore(t *testing.T) {
// check it...
_, err := p.GetByHeight(20)
require.NotNil(err)
assert.True(certifiers.IsSeedNotFoundErr(err))
assert.True(certerr.IsCommitNotFoundErr(err))
// add a seed
for _, s := range seeds {
err = p.StoreSeed(s)
// add commits
for _, fc := range commits {
err = p.StoreCommit(fc)
require.Nil(err)
}
// make sure we get it...
s := seeds[0]
val, err := p.GetByHeight(s.Height())
fc := commits[0]
val, err := p.GetByHeight(fc.Height())
if assert.Nil(err) {
assertSeedEqual(t, s, val)
assertCommitsEqual(t, fc, val)
}
// make sure we get higher
val, err = p.GetByHeight(s.Height() + 2)
val, err = p.GetByHeight(fc.Height() + 2)
if assert.Nil(err) {
assertSeedEqual(t, s, val)
assertCommitsEqual(t, fc, val)
}
// below is nothing
_, err = p.GetByHeight(s.Height() - 2)
assert.True(certifiers.IsSeedNotFoundErr(err))
_, err = p.GetByHeight(fc.Height() - 2)
assert.True(certerr.IsCommitNotFoundErr(err))
// make sure we get highest
val, err = certifiers.LatestSeed(p)
val, err = p.LatestCommit()
if assert.Nil(err) {
assertSeedEqual(t, seeds[3], val)
assertCommitsEqual(t, commits[3], val)
}
// make sure by hash also (note all have same hash, so overwritten)
val, err = p.GetByHash(seeds[1].Hash())
val, err = p.GetByHash(commits[1].ValidatorsHash())
if assert.Nil(err) {
assertSeedEqual(t, seeds[3], val)
assertCommitsEqual(t, commits[3], val)
}
}
@ -75,18 +76,17 @@ func TestDBProvider(t *testing.T) {
checkProvider(t, p, "test-db", "bling")
}
func makeSeeds(keys certifiers.ValKeys, count int, chainID, app string) []certifiers.Seed {
func makeCommits(keys certifiers.ValKeys, count int, chainID, app string) []certifiers.FullCommit {
appHash := []byte(app)
seeds := make([]certifiers.Seed, count)
commits := make([]certifiers.FullCommit, count)
for i := 0; i < count; i++ {
// two seeds for each validator, to check how we handle dups
// two commits for each validator, to check how we handle dups
// (10, 0), (10, 1), (10, 1), (10, 2), (10, 2), ...
vals := keys.ToValidators(10, int64(count/2))
h := 20 + 10*i
check := keys.GenCheckpoint(chainID, h, nil, vals, appHash, 0, len(keys))
seeds[i] = certifiers.Seed{check, vals}
commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, len(keys))
}
return seeds
return commits
}
func checkProvider(t *testing.T, p certifiers.Provider, chainID, app string) {
@ -94,43 +94,43 @@ func checkProvider(t *testing.T, p certifiers.Provider, chainID, app string) {
keys := certifiers.GenValKeys(5)
count := 10
// make a bunch of seeds...
seeds := makeSeeds(keys, count, chainID, app)
// make a bunch of commits...
commits := makeCommits(keys, count, chainID, app)
// check provider is empty
seed, err := p.GetByHeight(20)
fc, err := p.GetByHeight(20)
require.NotNil(err)
assert.True(certifiers.IsSeedNotFoundErr(err))
assert.True(certerr.IsCommitNotFoundErr(err))
seed, err = p.GetByHash(seeds[3].Hash())
fc, err = p.GetByHash(commits[3].ValidatorsHash())
require.NotNil(err)
assert.True(certifiers.IsSeedNotFoundErr(err))
assert.True(certerr.IsCommitNotFoundErr(err))
// now add them all to the provider
for _, s := range seeds {
err = p.StoreSeed(s)
for _, fc := range commits {
err = p.StoreCommit(fc)
require.Nil(err)
// and make sure we can get it back
s2, err := p.GetByHash(s.Hash())
fc2, err := p.GetByHash(fc.ValidatorsHash())
assert.Nil(err)
assertSeedEqual(t, s, s2)
assertCommitsEqual(t, fc, fc2)
// by height as well
s2, err = p.GetByHeight(s.Height())
fc2, err = p.GetByHeight(fc.Height())
assert.Nil(err)
assertSeedEqual(t, s, s2)
assertCommitsEqual(t, fc, fc2)
}
// make sure we get the last hash if we overstep
seed, err = p.GetByHeight(5000)
fc, err = p.GetByHeight(5000)
if assert.Nil(err) {
assertSeedEqual(t, seeds[count-1], seed)
assertCommitsEqual(t, commits[count-1], fc)
}
// and middle ones as well
seed, err = p.GetByHeight(47)
fc, err = p.GetByHeight(47)
if assert.Nil(err) {
// we only step by 10, so 40 must be the one below this
assert.Equal(40, seed.Height())
assert.Equal(40, fc.Height())
}
}

View File

@ -32,8 +32,8 @@ func NewMockChain(chainID string, numKeys int) MockChain {
// GetRegistrationTx returns a valid tx to register this chain
func (m MockChain) GetRegistrationTx(h int) RegisterChainTx {
seed := genEmptySeed(m.keys, m.chainID, h, m.tree.Hash(), len(m.keys))
return RegisterChainTx{seed}
fc := genEmptyCommit(m.keys, m.chainID, h, m.tree.Hash(), len(m.keys))
return RegisterChainTx{fc}
}
// MakePostPacket commits the packet locally and returns the proof,
@ -42,18 +42,17 @@ func (m MockChain) MakePostPacket(packet Packet, h int) (
PostPacketTx, UpdateChainTx) {
post := makePostPacket(m.tree, packet, m.chainID, h)
seed := genEmptySeed(m.keys, m.chainID, h+1, m.tree.Hash(), len(m.keys))
update := UpdateChainTx{seed}
fc := genEmptyCommit(m.keys, m.chainID, h+1, m.tree.Hash(), len(m.keys))
update := UpdateChainTx{fc}
return post, update
}
func genEmptySeed(keys certifiers.ValKeys, chain string, h int,
appHash []byte, count int) certifiers.Seed {
func genEmptyCommit(keys certifiers.ValKeys, chain string, h int,
appHash []byte, count int) certifiers.FullCommit {
vals := keys.ToValidators(10, 0)
cp := keys.GenCheckpoint(chain, h, nil, vals, appHash, 0, count)
return certifiers.Seed{cp, vals}
return keys.GenFullCommit(chain, h, nil, vals, appHash, 0, count)
}
func makePostPacket(tree *iavl.Tree, packet Packet, fromID string, fromHeight int) PostPacketTx {

View File

@ -32,17 +32,17 @@ func init() {
// RegisterChainTx allows you to register a new chain on this blockchain
type RegisterChainTx struct {
Seed certifiers.Seed `json:"seed"`
Commit certifiers.FullCommit `json:"seed"`
}
// ChainID helps get the chain this tx refers to
func (r RegisterChainTx) ChainID() string {
return r.Seed.Header.ChainID
return r.Commit.Header.ChainID
}
// ValidateBasic makes sure this is consistent, without checking the sigs
func (r RegisterChainTx) ValidateBasic() error {
err := r.Seed.ValidateBasic(r.ChainID())
err := r.Commit.ValidateBasic(r.ChainID())
if err != nil {
err = ErrInvalidCommit(err)
}
@ -56,17 +56,17 @@ func (r RegisterChainTx) Wrap() sdk.Tx {
// UpdateChainTx updates the state of this chain
type UpdateChainTx struct {
Seed certifiers.Seed `json:"seed"`
Commit certifiers.FullCommit `json:"seed"`
}
// ChainID helps get the chain this tx refers to
func (u UpdateChainTx) ChainID() string {
return u.Seed.Header.ChainID
return u.Commit.Header.ChainID
}
// ValidateBasic makes sure this is consistent, without checking the sigs
func (u UpdateChainTx) ValidateBasic() error {
err := u.Seed.ValidateBasic(u.ChainID())
err := u.Commit.ValidateBasic(u.ChainID())
if err != nil {
err = ErrInvalidCommit(err)
}

View File

@ -7,9 +7,8 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
lc "github.com/tendermint/light-client"
sdk "github.com/cosmos/cosmos-sdk"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/commands"
"github.com/cosmos/cosmos-sdk/client/commands/query"
"github.com/cosmos/cosmos-sdk/modules/nonce"
@ -46,7 +45,7 @@ func doNonceQuery(signers []sdk.Actor) (sequence uint32, height uint64, err erro
key := stack.PrefixedKey(nonce.NameNonce, nonce.GetSeqKey(signers))
prove := !viper.GetBool(commands.FlagTrustNode)
height, err = query.GetParsed(key, &sequence, query.GetHeight(), prove)
if lc.IsNoDataErr(err) {
if client.IsNoDataErr(err) {
// no data, return sequence 0
return 0, 0, nil
}

View File

@ -9,6 +9,7 @@ import (
"github.com/spf13/viper"
sdk "github.com/cosmos/cosmos-sdk"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/commands"
"github.com/cosmos/cosmos-sdk/client/commands/query"
"github.com/cosmos/cosmos-sdk/errors"
@ -16,7 +17,6 @@ import (
"github.com/cosmos/cosmos-sdk/modules/nonce"
"github.com/cosmos/cosmos-sdk/stack"
wire "github.com/tendermint/go-wire"
lightclient "github.com/tendermint/light-client"
"github.com/tendermint/tmlibs/common"
)
@ -48,7 +48,7 @@ func doQueryNonce(w http.ResponseWriter, r *http.Request) {
// query sequence number
data, height, err := query.Get(key, h, prove)
if lightclient.IsNoDataErr(err) {
if client.IsNoDataErr(err) {
err = fmt.Errorf("nonce empty for address: %q", signature)
common.WriteError(w, err)
return