diff --git a/client/commands/proofs/get.go b/client/commands/proofs/get.go index 8ad394e3ad..4edbd90b59 100644 --- a/client/commands/proofs/get.go +++ b/client/commands/proofs/get.go @@ -52,28 +52,8 @@ func GetProof(node client.Client, prover lc.Prover, key []byte, height int) (pro return proof, err } - // 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... ph := int(proof.BlockHeight()) - 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) + check, err := GetCertifiedCheckpoint(ph) if err != nil { return } @@ -87,6 +67,40 @@ func GetProof(node client.Client, prover lc.Prover, key []byte, height int) (pro return proof, err } +// GetCertifiedCheckpoint gets the signed header for a given height +// and certifies it. Returns error if unable to get a proven header. +func GetCertifiedCheckpoint(h int) (empty lc.Checkpoint, err error) { + // here is the certifier, root of all knowledge + node := commands.GetNode() + 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, h, nil) + commit, err := node.Commit(h) + if err != nil { + return + } + check := lc.Checkpoint{ + Header: commit.Header, + Commit: commit.Commit, + } + // double check we got the same height + if check.Height() != h { + return empty, lc.ErrHeightMismatch(h, check.Height()) + } + + // and now verify it matches our validators + err = cert.Certify(check) + return check, nil +} + // 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) { diff --git a/client/commands/proofs/tx.go b/client/commands/proofs/tx.go index cffc4dfc11..930c22ddc5 100644 --- a/client/commands/proofs/tx.go +++ b/client/commands/proofs/tx.go @@ -2,8 +2,10 @@ package proofs import ( "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/tendermint/light-client/proofs" + "github.com/tendermint/tendermint/types" "github.com/tendermint/basecoin/client/commands" ) @@ -24,9 +26,25 @@ data to other peers as needed. RunE: commands.RequireInit(txQueryCmd), } +// type ResultTx struct { +// Height int `json:"height"` +// Index int `json:"index"` +// TxResult abci.Result `json:"tx_result"` +// Tx types.Tx `json:"tx"` +// Proof types.TxProof `json:"proof,omitempty"` +// } + +// type TxProof struct { +// Index, Total int +// RootHash data.Bytes +// Data Tx +// Proof merkle.SimpleProof +// } + func txQueryCmd(cmd *cobra.Command, args []string) error { // parse cli - height := GetHeight() + // TODO: when querying historical heights is allowed... pass it + // height := GetHeight() bkey, err := ParseHexKey(args, "txhash") if err != nil { return err @@ -34,19 +52,36 @@ func txQueryCmd(cmd *cobra.Command, args []string) error { // get the proof -> this will be used by all prover commands node := commands.GetNode() - prover := proofs.NewTxProver(node) - proof, err := GetProof(node, prover, bkey, height) + prove := viper.GetBool(commands.FlagTrustNode) + res, err := node.Tx(bkey, prove) if err != nil { return err } + if !prove { + return showTx(res.Height, res.Tx) + } + + check, err := GetCertifiedCheckpoint(res.Height) + if err != nil { + return err + } + err = res.Proof.Validate(check.Header.DataHash) + if err != nil { + return err + } + + return showTx(res.Height, res.Proof.Data) +} + +func showTx(h int, tx types.Tx) error { // auto-determine which tx it was, over all registered tx types - info, err := TxPresenters.BruteForce(proof.Data()) + info, err := TxPresenters.BruteForce(tx) if err != nil { return err } // we can reuse this output for other commands for text/json // unless they do something special like store a file to disk - return OutputProof(info, proof.BlockHeight()) + return OutputProof(info, uint64(h)) }