cosmos-sdk/client/commands/proofs/get.go

119 lines
3.2 KiB
Go

package proofs
import (
"fmt"
"github.com/pkg/errors"
"github.com/spf13/viper"
wire "github.com/tendermint/go-wire"
"github.com/tendermint/go-wire/data"
lc "github.com/tendermint/light-client"
"github.com/tendermint/light-client/proofs"
"github.com/tendermint/tendermint/rpc/client"
"github.com/tendermint/basecoin/client/commands"
)
// GetAndParseAppProof does most of the work of the query commands, but is quite
// opinionated, so if you want more control, set up the items and call GetProof
// directly. Notably, it always uses go-wire.ReadBinaryBytes to deserialize,
// and Height and Node from standard flags.
//
// It will try to get the proof for the given key. If it is successful,
// it will return the proof and also unserialize proof.Data into the data
// argument (so pass in a pointer to the appropriate struct)
func GetAndParseAppProof(key []byte, data interface{}) (lc.Proof, error) {
height := GetHeight()
node := commands.GetNode()
prover := proofs.NewAppProver(node)
proof, err := GetProof(node, prover, key, height)
if err != nil {
return proof, err
}
err = wire.ReadBinaryBytes(proof.Data(), data)
return proof, err
}
// GetProof performs the get command directly from the proof (not from the CLI)
func GetProof(node client.Client, prover lc.Prover, key []byte, height int) (proof lc.Proof, err error) {
proof, err = prover.Get(key, uint64(height))
if err != nil {
return
}
ph := int(proof.BlockHeight())
// here is the certifier, root of all knowledge
cert, err := commands.GetCertifier()
if err != nil {
return
}
// get and validate a signed header for this proof
// 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, ph, nil)
commit, err := node.Commit(ph)
if err != nil {
return
}
check := lc.Checkpoint{
Header: commit.Header,
Commit: commit.Commit,
}
err = cert.Certify(check)
if err != nil {
return
}
// validate the proof against the certified header to ensure data integrity
err = proof.Validate(check)
if err != nil {
return
}
return proof, err
}
// ParseHexKey parses the key flag as hex and converts to bytes or returns error
// argname is used to customize the error message
func ParseHexKey(args []string, argname string) ([]byte, error) {
if len(args) == 0 {
return nil, errors.Errorf("Missing required argument [%s]", argname)
}
if len(args) > 1 {
return nil, errors.Errorf("Only accepts one argument [%s]", argname)
}
rawkey := args[0]
if rawkey == "" {
return nil, errors.Errorf("[%s] argument must be non-empty ", argname)
}
// with tx, we always just parse key as hex and use to lookup
return proofs.ParseHexKey(rawkey)
}
func GetHeight() int {
return viper.GetInt(heightFlag)
}
type proof struct {
Height uint64 `json:"height"`
Data interface{} `json:"data"`
}
// OutputProof prints the proof to stdout
// reuse this for printing proofs and we should enhance this for text/json,
// better presentation of height
func OutputProof(info interface{}, height uint64) error {
wrap := proof{height, info}
res, err := data.ToJSON(wrap)
if err != nil {
return err
}
fmt.Println(string(res))
return nil
}