From 89d8cc61f0883acd2732bde9031b832bd481de52 Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Tue, 6 Jun 2017 22:21:16 -0400 Subject: [PATCH 1/9] Add proof state subcommand --- commands/proofs/state.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/commands/proofs/state.go b/commands/proofs/state.go index a769d88..27fbb4a 100644 --- a/commands/proofs/state.go +++ b/commands/proofs/state.go @@ -32,3 +32,8 @@ func init() { func stateProver(node client.Client) lc.Prover { return proofs.NewAppProver(node) } + +// RegisterProofStateSubcommand registers a subcommand to proof state cmd +func RegisterProofStateSubcommand(cmd *cobra.Command) { + stateCmd.AddCommand(cmd) +} From d2209bbd9758555e7756d9cdab135af3fecf6733 Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Tue, 6 Jun 2017 23:57:43 -0400 Subject: [PATCH 2/9] ProofCommander integration int --- .gitignore | 1 + commands/proofs/get.go | 31 +++++++++++++++++++++---------- commands/proofs/root.go | 8 +++++++- commands/proofs/state.go | 15 ++++++++------- commands/proofs/tx.go | 2 +- 5 files changed, 38 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index bd2a259..778fd92 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.swp vendor .keys tmcli diff --git a/commands/proofs/get.go b/commands/proofs/get.go index 3a4c769..60431ae 100644 --- a/commands/proofs/get.go +++ b/commands/proofs/get.go @@ -13,11 +13,12 @@ import ( "github.com/tendermint/tendermint/rpc/client" ) +// GetCmd creates the get command for a proof func (p ProofCommander) GetCmd() *cobra.Command { cmd := &cobra.Command{ Use: "get", Short: "Get a proof from the tendermint node", - RunE: p.doGet, + RunE: p.getCmd, SilenceUsage: true, } cmd.Flags().Int(heightFlag, 0, "Height to query (skip to use latest block)") @@ -26,18 +27,27 @@ func (p ProofCommander) GetCmd() *cobra.Command { return cmd } -func (p ProofCommander) doGet(cmd *cobra.Command, args []string) error { +func (p ProofCommander) getCmd(cmd *cobra.Command, args []string) error { app := viper.GetString(appFlag) - pres, err := p.Lookup(app) - if err != nil { - return err - } rawkey := viper.GetString(keyFlag) if rawkey == "" { return errors.New("missing required flag: --" + keyFlag) } + height := viper.GetInt(heightFlag) + + return p.DoGet(app, rawkey, height) +} + +// DoGet performs the get command directly from the proof (not from the CLI) +func (p ProofCommander) DoGet(app, rawkey string, height int) error { + + pres, err := p.Lookup(app) + if err != nil { + return err + } + // prepare the query in an app-dependent manner key, err := pres.MakeKey(rawkey) if err != nil { @@ -46,13 +56,11 @@ func (p ProofCommander) doGet(cmd *cobra.Command, args []string) error { // instantiate the prover instance and get a proof from the server p.Init() - h := viper.GetInt(heightFlag) - proof, err := p.Get(key, uint64(h)) + proof, err := p.Get(key, uint64(height)) if err != nil { return err } ph := int(proof.BlockHeight()) - // here is the certifier, root of all knowledge cert, err := commands.GetCertifier() if err != nil { @@ -69,7 +77,10 @@ func (p ProofCommander) doGet(cmd *cobra.Command, args []string) error { if err != nil { return err } - check := lc.Checkpoint{commit.Header, commit.Commit} + check := lc.Checkpoint{ + Header: commit.Header, + Commit: commit.Commit, + } err = cert.Certify(check) if err != nil { return err diff --git a/commands/proofs/root.go b/commands/proofs/root.go index 7d16c75..8811e02 100644 --- a/commands/proofs/root.go +++ b/commands/proofs/root.go @@ -36,7 +36,13 @@ func (p *ProofCommander) Init() { p.Prover = p.ProverFunc(p.node) } -func (p ProofCommander) Register(parent *cobra.Command) { +func (p ProofCommander) Register(parent *cobra.Command, cmdReg func(ProofCommander) *cobra.Command) { + // we add each subcommand here, so we can register the + // ProofCommander in one swoop + parent.AddCommand(cmdReg(p)) +} + +func (p ProofCommander) RegisterGet(parent *cobra.Command) { // we add each subcommand here, so we can register the // ProofCommander in one swoop parent.AddCommand(p.GetCmd()) diff --git a/commands/proofs/state.go b/commands/proofs/state.go index 27fbb4a..cfb908a 100644 --- a/commands/proofs/state.go +++ b/commands/proofs/state.go @@ -20,12 +20,13 @@ data to other peers as needed. `, } +var stateProverCommander = ProofCommander{ + ProverFunc: stateProver, + Presenters: StatePresenters, +} + func init() { - stateProver := ProofCommander{ - ProverFunc: stateProver, - Presenters: StatePresenters, - } - stateProver.Register(stateCmd) + stateProverCommander.RegisterGet(stateCmd) RootCmd.AddCommand(stateCmd) } @@ -34,6 +35,6 @@ func stateProver(node client.Client) lc.Prover { } // RegisterProofStateSubcommand registers a subcommand to proof state cmd -func RegisterProofStateSubcommand(cmd *cobra.Command) { - stateCmd.AddCommand(cmd) +func RegisterProofStateSubcommand(cmdReg func(ProofCommander) *cobra.Command) { + stateProverCommander.Register(stateCmd, cmdReg) } diff --git a/commands/proofs/tx.go b/commands/proofs/tx.go index 7f71dcf..f9313ed 100644 --- a/commands/proofs/tx.go +++ b/commands/proofs/tx.go @@ -25,7 +25,7 @@ func init() { ProverFunc: txProver, Presenters: TxPresenters, } - txProver.Register(txCmd) + txProver.RegisterGet(txCmd) RootCmd.AddCommand(txCmd) } From 490d8974e7e8d3e941bd1af7b968bc02b28d2be1 Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Wed, 7 Jun 2017 00:55:18 -0400 Subject: [PATCH 3/9] more abstraction int --- commands/proofs/get.go | 61 +++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/commands/proofs/get.go b/commands/proofs/get.go index 60431ae..491287d 100644 --- a/commands/proofs/get.go +++ b/commands/proofs/get.go @@ -7,8 +7,9 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - data "github.com/tendermint/go-wire/data" + data "github.com/tendermint/go-data" lc "github.com/tendermint/light-client" + lightclient "github.com/tendermint/light-client" "github.com/tendermint/light-client/commands" "github.com/tendermint/tendermint/rpc/client" ) @@ -37,34 +38,56 @@ func (p ProofCommander) getCmd(cmd *cobra.Command, args []string) error { height := viper.GetInt(heightFlag) - return p.DoGet(app, rawkey, height) + //get the proof + proof, err := p.GetProof(app, rawkey, height) + if err != nil { + return err + } + + pres, err := p.Lookup(app) + if err != nil { + return err + } + info, err := pres.ParseData(proof.Data()) + if err != nil { + return err + } + data, err := data.ToJSON(info) + if err != nil { + return err + } + + // TODO: store the proof or do something more interesting than just printing + fmt.Printf("Height: %d\n", proof.BlockHeight()) + fmt.Println(string(data)) + return nil } -// DoGet performs the get command directly from the proof (not from the CLI) -func (p ProofCommander) DoGet(app, rawkey string, height int) error { +// GetProof performs the get command directly from the proof (not from the CLI) +func (p ProofCommander) GetProof(app, rawkey string, height int) (proof lightclient.Proof, err error) { pres, err := p.Lookup(app) if err != nil { - return err + return } // prepare the query in an app-dependent manner key, err := pres.MakeKey(rawkey) if err != nil { - return err + return } // instantiate the prover instance and get a proof from the server p.Init() - proof, err := p.Get(key, uint64(height)) + proof, err = p.Get(key, uint64(height)) if err != nil { - return err + return } ph := int(proof.BlockHeight()) // here is the certifier, root of all knowledge cert, err := commands.GetCertifier() if err != nil { - return err + return } // get and validate a signed header for this proof @@ -75,7 +98,7 @@ func (p ProofCommander) DoGet(app, rawkey string, height int) error { client.WaitForHeight(p.node, ph, nil) commit, err := p.node.Commit(ph) if err != nil { - return err + return } check := lc.Checkpoint{ Header: commit.Header, @@ -83,26 +106,14 @@ func (p ProofCommander) DoGet(app, rawkey string, height int) error { } err = cert.Certify(check) if err != nil { - return err + return } // validate the proof against the certified header to ensure data integrity err = proof.Validate(check) if err != nil { - return err + return } - // TODO: store the proof or do something more interesting than just printing - // fmt.Println("Your data is 100% certified:") - fmt.Printf("Height: %d\n", proof.BlockHeight()) - info, err := pres.ParseData(proof.Data()) - if err != nil { - return err - } - data, err := data.ToJSON(info) - if err != nil { - return err - } - fmt.Println(string(data)) - return nil + return proof, err } From 9b6427327a4dfc728cc9d54e6b13c71ca50e24dd Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Mon, 12 Jun 2017 16:16:25 -0400 Subject: [PATCH 4/9] simplify query app requirements int int int --- commands/proofs/get.go | 28 ++++++++++++---------------- commands/proofs/root.go | 6 ------ commands/proofs/state.go | 8 ++++---- 3 files changed, 16 insertions(+), 26 deletions(-) diff --git a/commands/proofs/get.go b/commands/proofs/get.go index 491287d..08b655c 100644 --- a/commands/proofs/get.go +++ b/commands/proofs/get.go @@ -9,7 +9,6 @@ import ( "github.com/spf13/viper" data "github.com/tendermint/go-data" lc "github.com/tendermint/light-client" - lightclient "github.com/tendermint/light-client" "github.com/tendermint/light-client/commands" "github.com/tendermint/tendermint/rpc/client" ) @@ -38,20 +37,28 @@ func (p ProofCommander) getCmd(cmd *cobra.Command, args []string) error { height := viper.GetInt(heightFlag) - //get the proof - proof, err := p.GetProof(app, rawkey, height) + pres, err := p.Lookup(app) if err != nil { return err } - pres, err := p.Lookup(app) + // prepare the query in an app-dependent manner + key, err := pres.MakeKey(rawkey) + if err != nil { + return err + } + + //get the proof + proof, err := p.GetProof(key, height) if err != nil { return err } + info, err := pres.ParseData(proof.Data()) if err != nil { return err } + data, err := data.ToJSON(info) if err != nil { return err @@ -64,18 +71,7 @@ func (p ProofCommander) getCmd(cmd *cobra.Command, args []string) error { } // GetProof performs the get command directly from the proof (not from the CLI) -func (p ProofCommander) GetProof(app, rawkey string, height int) (proof lightclient.Proof, err error) { - - pres, err := p.Lookup(app) - if err != nil { - return - } - - // prepare the query in an app-dependent manner - key, err := pres.MakeKey(rawkey) - if err != nil { - return - } +func (p ProofCommander) GetProof(key []byte, height int) (proof lc.Proof, err error) { // instantiate the prover instance and get a proof from the server p.Init() diff --git a/commands/proofs/root.go b/commands/proofs/root.go index 8811e02..2db3d82 100644 --- a/commands/proofs/root.go +++ b/commands/proofs/root.go @@ -36,12 +36,6 @@ func (p *ProofCommander) Init() { p.Prover = p.ProverFunc(p.node) } -func (p ProofCommander) Register(parent *cobra.Command, cmdReg func(ProofCommander) *cobra.Command) { - // we add each subcommand here, so we can register the - // ProofCommander in one swoop - parent.AddCommand(cmdReg(p)) -} - func (p ProofCommander) RegisterGet(parent *cobra.Command) { // we add each subcommand here, so we can register the // ProofCommander in one swoop diff --git a/commands/proofs/state.go b/commands/proofs/state.go index cfb908a..186756a 100644 --- a/commands/proofs/state.go +++ b/commands/proofs/state.go @@ -20,13 +20,13 @@ data to other peers as needed. `, } -var stateProverCommander = ProofCommander{ +var StateProverCommander = ProofCommander{ ProverFunc: stateProver, Presenters: StatePresenters, } func init() { - stateProverCommander.RegisterGet(stateCmd) + StateProverCommander.RegisterGet(stateCmd) RootCmd.AddCommand(stateCmd) } @@ -35,6 +35,6 @@ func stateProver(node client.Client) lc.Prover { } // RegisterProofStateSubcommand registers a subcommand to proof state cmd -func RegisterProofStateSubcommand(cmdReg func(ProofCommander) *cobra.Command) { - stateProverCommander.Register(stateCmd, cmdReg) +func RegisterProofStateSubcommand(cmdReg *cobra.Command) { + stateCmd.AddCommand(cmdReg) } From 5777c24d8415c417b936774e3db7fcc8c1e58df8 Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Tue, 13 Jun 2017 00:08:03 -0400 Subject: [PATCH 5/9] add state list functionality --- commands/proofs/get.go | 99 +++++++++++++++++++++------------------- commands/proofs/root.go | 13 +++++- commands/proofs/state.go | 15 ++++-- 3 files changed, 76 insertions(+), 51 deletions(-) diff --git a/commands/proofs/get.go b/commands/proofs/get.go index 08b655c..2d3007b 100644 --- a/commands/proofs/get.go +++ b/commands/proofs/get.go @@ -13,61 +13,68 @@ import ( "github.com/tendermint/tendermint/rpc/client" ) -// GetCmd creates the get command for a proof -func (p ProofCommander) GetCmd() *cobra.Command { +// MakeGetCmd creates the get or list command for a proof +func (p ProofCommander) MakeGetCmd(includeKey bool, use, desc string) *cobra.Command { cmd := &cobra.Command{ - Use: "get", - Short: "Get a proof from the tendermint node", - RunE: p.getCmd, + Use: use, + Short: desc, + RunE: p.makeGetCmd(includeKey), SilenceUsage: true, } cmd.Flags().Int(heightFlag, 0, "Height to query (skip to use latest block)") cmd.Flags().String(appFlag, "raw", "App to use to interpret data") - cmd.Flags().String(keyFlag, "", "Key to query on") + if includeKey { + cmd.Flags().String(keyFlag, "", "Key to query on") + } return cmd } -func (p ProofCommander) getCmd(cmd *cobra.Command, args []string) error { - app := viper.GetString(appFlag) - - rawkey := viper.GetString(keyFlag) - if rawkey == "" { - return errors.New("missing required flag: --" + keyFlag) - } - - height := viper.GetInt(heightFlag) - - pres, err := p.Lookup(app) - if err != nil { - return err +func (p ProofCommander) makeGetCmd(includeKey bool) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + app := viper.GetString(appFlag) + + var rawkey string + if includeKey { + rawkey = viper.GetString(keyFlag) + if rawkey == "" { + return errors.New("missing required flag: --" + keyFlag) + } + } + + height := viper.GetInt(heightFlag) + + pres, err := p.Lookup(app) + if err != nil { + return err + } + + // prepare the query in an app-dependent manner + key, err := pres.MakeKey(rawkey) + if err != nil { + return err + } + + //get the proof + proof, err := p.GetProof(key, height) + if err != nil { + return err + } + + info, err := pres.ParseData(proof.Data()) + if err != nil { + return err + } + + data, err := data.ToJSON(info) + if err != nil { + return err + } + + // TODO: store the proof or do something more interesting than just printing + fmt.Printf("Height: %d\n", proof.BlockHeight()) + fmt.Println(string(data)) + return nil } - - // prepare the query in an app-dependent manner - key, err := pres.MakeKey(rawkey) - if err != nil { - return err - } - - //get the proof - proof, err := p.GetProof(key, height) - if err != nil { - return err - } - - info, err := pres.ParseData(proof.Data()) - if err != nil { - return err - } - - data, err := data.ToJSON(info) - if err != nil { - return err - } - - // TODO: store the proof or do something more interesting than just printing - fmt.Printf("Height: %d\n", proof.BlockHeight()) - fmt.Println(string(data)) - return nil } // GetProof performs the get command directly from the proof (not from the CLI) diff --git a/commands/proofs/root.go b/commands/proofs/root.go index 2db3d82..6660abc 100644 --- a/commands/proofs/root.go +++ b/commands/proofs/root.go @@ -39,7 +39,18 @@ func (p *ProofCommander) Init() { func (p ProofCommander) RegisterGet(parent *cobra.Command) { // we add each subcommand here, so we can register the // ProofCommander in one swoop - parent.AddCommand(p.GetCmd()) + parent.AddCommand(p.MakeGetCmd( + true, + "get", + "Get a proof from the tendermint node", + )) +} +func (p ProofCommander) RegisterList(parent *cobra.Command) { + parent.AddCommand(p.MakeGetCmd( + false, + "list", + "Get a list proof from the tendermint node", + )) } const ( diff --git a/commands/proofs/state.go b/commands/proofs/state.go index 186756a..da81f8d 100644 --- a/commands/proofs/state.go +++ b/commands/proofs/state.go @@ -7,7 +7,8 @@ import ( "github.com/tendermint/tendermint/rpc/client" ) -var StatePresenters = proofs.NewPresenters() +var StateGetPresenters = proofs.NewPresenters() +var StateListPresenters = proofs.NewPresenters() var stateCmd = &cobra.Command{ Use: "state", @@ -20,13 +21,19 @@ data to other peers as needed. `, } -var StateProverCommander = ProofCommander{ +var StateGetProverCommander = ProofCommander{ ProverFunc: stateProver, - Presenters: StatePresenters, + Presenters: StateGetPresenters, +} + +var StateListProverCommander = ProofCommander{ + ProverFunc: stateProver, + Presenters: StateListPresenters, } func init() { - StateProverCommander.RegisterGet(stateCmd) + StateGetProverCommander.RegisterGet(stateCmd) + StateListProverCommander.RegisterList(stateCmd) RootCmd.AddCommand(stateCmd) } From 6f1b09fc52dc407e6a48392fca16450dccd08c1c Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 13 Jun 2017 12:44:03 +0200 Subject: [PATCH 6/9] Fixed broken import --- commands/proofs/get.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/proofs/get.go b/commands/proofs/get.go index 2d3007b..616b5a4 100644 --- a/commands/proofs/get.go +++ b/commands/proofs/get.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - data "github.com/tendermint/go-data" + data "github.com/tendermint/go-wire/data" lc "github.com/tendermint/light-client" "github.com/tendermint/light-client/commands" "github.com/tendermint/tendermint/rpc/client" From 3eb4638b89bf321934e2776db3ae185636ce60ec Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 13 Jun 2017 13:48:08 +0200 Subject: [PATCH 7/9] Overhauled proof commands dir, easier to use subcommands --- commands/proofs/get.go | 82 ++------------------------------------- commands/proofs/root.go | 83 ++++++++++++++++++++++------------------ commands/proofs/state.go | 64 +++++++++++++++---------------- commands/proofs/tx.go | 39 +++++++++++++------ proofs/presenters.go | 4 ++ 5 files changed, 111 insertions(+), 161 deletions(-) diff --git a/commands/proofs/get.go b/commands/proofs/get.go index 616b5a4..e04a03c 100644 --- a/commands/proofs/get.go +++ b/commands/proofs/get.go @@ -1,88 +1,14 @@ package proofs import ( - "fmt" - - "github.com/pkg/errors" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - data "github.com/tendermint/go-wire/data" lc "github.com/tendermint/light-client" "github.com/tendermint/light-client/commands" "github.com/tendermint/tendermint/rpc/client" ) -// MakeGetCmd creates the get or list command for a proof -func (p ProofCommander) MakeGetCmd(includeKey bool, use, desc string) *cobra.Command { - cmd := &cobra.Command{ - Use: use, - Short: desc, - RunE: p.makeGetCmd(includeKey), - SilenceUsage: true, - } - cmd.Flags().Int(heightFlag, 0, "Height to query (skip to use latest block)") - cmd.Flags().String(appFlag, "raw", "App to use to interpret data") - if includeKey { - cmd.Flags().String(keyFlag, "", "Key to query on") - } - return cmd -} - -func (p ProofCommander) makeGetCmd(includeKey bool) func(cmd *cobra.Command, args []string) error { - return func(cmd *cobra.Command, args []string) error { - app := viper.GetString(appFlag) - - var rawkey string - if includeKey { - rawkey = viper.GetString(keyFlag) - if rawkey == "" { - return errors.New("missing required flag: --" + keyFlag) - } - } - - height := viper.GetInt(heightFlag) - - pres, err := p.Lookup(app) - if err != nil { - return err - } - - // prepare the query in an app-dependent manner - key, err := pres.MakeKey(rawkey) - if err != nil { - return err - } - - //get the proof - proof, err := p.GetProof(key, height) - if err != nil { - return err - } - - info, err := pres.ParseData(proof.Data()) - if err != nil { - return err - } - - data, err := data.ToJSON(info) - if err != nil { - return err - } - - // TODO: store the proof or do something more interesting than just printing - fmt.Printf("Height: %d\n", proof.BlockHeight()) - fmt.Println(string(data)) - return nil - } -} - // GetProof performs the get command directly from the proof (not from the CLI) -func (p ProofCommander) GetProof(key []byte, height int) (proof lc.Proof, err error) { - - // instantiate the prover instance and get a proof from the server - p.Init() - proof, err = p.Get(key, uint64(height)) +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 } @@ -98,8 +24,8 @@ func (p ProofCommander) GetProof(key []byte, height int) (proof lc.Proof, err er // 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(p.node, ph, nil) - commit, err := p.node.Commit(ph) + client.WaitForHeight(node, ph, nil) + commit, err := node.Commit(ph) if err != nil { return } diff --git a/commands/proofs/root.go b/commands/proofs/root.go index 6660abc..7373115 100644 --- a/commands/proofs/root.go +++ b/commands/proofs/root.go @@ -1,17 +1,24 @@ package proofs import ( + "fmt" + + "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/spf13/viper" - lc "github.com/tendermint/light-client" - "github.com/tendermint/light-client/commands" + + "github.com/tendermint/go-wire/data" + "github.com/tendermint/light-client/proofs" - "github.com/tendermint/tendermint/rpc/client" +) + +const ( + heightFlag = "height" + keyFlag = "key" ) // RootCmd represents the base command when called without any subcommands var RootCmd = &cobra.Command{ - Use: "proof", + Use: "query", Short: "Get and store merkle proofs for blockchain data", Long: `Proofs allows you to validate data and merkle proofs. @@ -21,40 +28,42 @@ data to other peers as needed. `, } -type ProofCommander struct { - node client.Client - lc.Prover - ProverFunc func(client.Client) lc.Prover - proofs.Presenters -} +func init() { + RootCmd.Flags().Int(heightFlag, 0, "Height to query (skip to use latest block)") -// Init uses configuration info to create a network connection -// as well as initializing the prover -func (p *ProofCommander) Init() { - endpoint := viper.GetString(commands.NodeFlag) - p.node = client.NewHTTP(endpoint, "/websockets") - p.Prover = p.ProverFunc(p.node) + RootCmd.AddCommand(txCmd) + RootCmd.AddCommand(stateCmd) } -func (p ProofCommander) RegisterGet(parent *cobra.Command) { - // we add each subcommand here, so we can register the - // ProofCommander in one swoop - parent.AddCommand(p.MakeGetCmd( - true, - "get", - "Get a proof from the tendermint node", - )) -} -func (p ProofCommander) RegisterList(parent *cobra.Command) { - parent.AddCommand(p.MakeGetCmd( - false, - "list", - "Get a list proof from the tendermint node", - )) +// ParseHexKey parses the key flag as hex and converts to bytes or returns error +// if prefix is non-nil, it prepends this constant to the given key (eg. "base/a/") +func ParseHexKey(args []string, prefix []byte) ([]byte, error) { + if len(args) == 0 { + return nil, errors.New("Missing required key argument") + } + if len(args) > 1 { + return nil, errors.Errorf("Only accepts one key argument") + } + rawkey := args[0] + if rawkey == "" { + return nil, errors.New("Cannot query on empty key") + } + // with tx, we always just parse key as hex and use to lookup + return proofs.KeyMaker{prefix}.MakeKey(rawkey) } -const ( - heightFlag = "height" - appFlag = "app" - keyFlag = "key" -) +// 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 { + res, err := data.ToJSON(info) + if err != nil { + return err + } + + // TODO: store the proof or do something more interesting than just printing + fmt.Printf("Height: %d\n", height) + fmt.Println(string(res)) + return nil + +} diff --git a/commands/proofs/state.go b/commands/proofs/state.go index da81f8d..9bfc385 100644 --- a/commands/proofs/state.go +++ b/commands/proofs/state.go @@ -2,46 +2,42 @@ package proofs import ( "github.com/spf13/cobra" - lc "github.com/tendermint/light-client" + "github.com/spf13/viper" + "github.com/tendermint/go-wire/data" + "github.com/tendermint/light-client/commands" "github.com/tendermint/light-client/proofs" - "github.com/tendermint/tendermint/rpc/client" ) -var StateGetPresenters = proofs.NewPresenters() -var StateListPresenters = proofs.NewPresenters() - var stateCmd = &cobra.Command{ - Use: "state", + Use: "key [key]", Short: "Handle proofs for state of abci app", - Long: `Proofs allows you to validate abci state with merkle proofs. - -These proofs tie the data to a checkpoint, which is managed by "seeds". -Here we can validate these proofs and import/export them to prove specific -data to other peers as needed. -`, -} - -var StateGetProverCommander = ProofCommander{ - ProverFunc: stateProver, - Presenters: StateGetPresenters, -} - -var StateListProverCommander = ProofCommander{ - ProverFunc: stateProver, - Presenters: StateListPresenters, -} - -func init() { - StateGetProverCommander.RegisterGet(stateCmd) - StateListProverCommander.RegisterList(stateCmd) - RootCmd.AddCommand(stateCmd) -} + Long: `This will look up a given key in the abci app, verify the proof, +and output it as hex. -func stateProver(node client.Client) lc.Prover { - return proofs.NewAppProver(node) +If you want json output, use an app-specific command that knows key and value structure.`, + RunE: doStateQuery, } -// RegisterProofStateSubcommand registers a subcommand to proof state cmd -func RegisterProofStateSubcommand(cmdReg *cobra.Command) { - stateCmd.AddCommand(cmdReg) +func doStateQuery(cmd *cobra.Command, args []string) error { + // parse cli + height := viper.GetInt(heightFlag) + bkey, err := ParseHexKey(args, nil) + if err != nil { + return err + } + + // get the proof -> this will be used by all prover commands + node := commands.GetNode() + prover := proofs.NewAppProver(node) + proof, err := GetProof(node, prover, bkey, height) + if err != nil { + return err + } + + // state just returns raw hex.... + info := data.Bytes(proof.Data()) + + // 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()) } diff --git a/commands/proofs/tx.go b/commands/proofs/tx.go index f9313ed..74941a9 100644 --- a/commands/proofs/tx.go +++ b/commands/proofs/tx.go @@ -2,15 +2,15 @@ package proofs import ( "github.com/spf13/cobra" - lc "github.com/tendermint/light-client" + "github.com/spf13/viper" + "github.com/tendermint/light-client/commands" "github.com/tendermint/light-client/proofs" - "github.com/tendermint/tendermint/rpc/client" ) var TxPresenters = proofs.NewPresenters() var txCmd = &cobra.Command{ - Use: "tx", + Use: "tx [txhash]", Short: "Handle proofs of commited txs", Long: `Proofs allows you to validate abci state with merkle proofs. @@ -18,17 +18,32 @@ These proofs tie the data to a checkpoint, which is managed by "seeds". Here we can validate these proofs and import/export them to prove specific data to other peers as needed. `, + RunE: doTxQuery, } -func init() { - txProver := ProofCommander{ - ProverFunc: txProver, - Presenters: TxPresenters, +func doTxQuery(cmd *cobra.Command, args []string) error { + // parse cli + height := viper.GetInt(heightFlag) + bkey, err := ParseHexKey(args, nil) + if err != nil { + return err + } + + // 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) + if err != nil { + return err + } + + // auto-determine which tx it was, over all registered tx types + info, err := TxPresenters.BruteForce(proof.Data()) + if err != nil { + return err } - txProver.RegisterGet(txCmd) - RootCmd.AddCommand(txCmd) -} -func txProver(node client.Client) lc.Prover { - return proofs.NewTxProver(node) + // 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()) } diff --git a/proofs/presenters.go b/proofs/presenters.go index 0108f98..758b508 100644 --- a/proofs/presenters.go +++ b/proofs/presenters.go @@ -81,3 +81,7 @@ func (k KeyMaker) MakeKey(str string) ([]byte, error) { } return r, errors.WithStack(err) } + +func ParseHexKey(str string) ([]byte, error) { + return KeyMaker{}.MakeKey(str) +} From bd36b16e4d5b6039d4835163c857a9545b04c743 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 13 Jun 2017 14:04:47 +0200 Subject: [PATCH 8/9] Clean up GetHeight(), import ordering --- commands/proofs/get.go | 3 ++- commands/proofs/root.go | 8 ++++++-- commands/proofs/state.go | 11 ++++++----- commands/proofs/tx.go | 4 ++-- proofs/presenters.go | 1 + 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/commands/proofs/get.go b/commands/proofs/get.go index e04a03c..5c723e6 100644 --- a/commands/proofs/get.go +++ b/commands/proofs/get.go @@ -1,9 +1,10 @@ package proofs import ( + "github.com/tendermint/tendermint/rpc/client" + lc "github.com/tendermint/light-client" "github.com/tendermint/light-client/commands" - "github.com/tendermint/tendermint/rpc/client" ) // GetProof performs the get command directly from the proof (not from the CLI) diff --git a/commands/proofs/root.go b/commands/proofs/root.go index 7373115..9efbc60 100644 --- a/commands/proofs/root.go +++ b/commands/proofs/root.go @@ -5,6 +5,7 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/tendermint/go-wire/data" @@ -13,7 +14,6 @@ import ( const ( heightFlag = "height" - keyFlag = "key" ) // RootCmd represents the base command when called without any subcommands @@ -32,7 +32,7 @@ func init() { RootCmd.Flags().Int(heightFlag, 0, "Height to query (skip to use latest block)") RootCmd.AddCommand(txCmd) - RootCmd.AddCommand(stateCmd) + RootCmd.AddCommand(keyCmd) } // ParseHexKey parses the key flag as hex and converts to bytes or returns error @@ -52,6 +52,10 @@ func ParseHexKey(args []string, prefix []byte) ([]byte, error) { return proofs.KeyMaker{prefix}.MakeKey(rawkey) } +func GetHeight() int { + return viper.GetInt(heightFlag) +} + // OutputProof prints the proof to stdout // reuse this for printing proofs and we should enhance this for text/json, // better presentation of height diff --git a/commands/proofs/state.go b/commands/proofs/state.go index 9bfc385..f3cbbcd 100644 --- a/commands/proofs/state.go +++ b/commands/proofs/state.go @@ -2,25 +2,26 @@ package proofs import ( "github.com/spf13/cobra" - "github.com/spf13/viper" + "github.com/tendermint/go-wire/data" + "github.com/tendermint/light-client/commands" "github.com/tendermint/light-client/proofs" ) -var stateCmd = &cobra.Command{ +var keyCmd = &cobra.Command{ Use: "key [key]", Short: "Handle proofs for state of abci app", Long: `This will look up a given key in the abci app, verify the proof, and output it as hex. If you want json output, use an app-specific command that knows key and value structure.`, - RunE: doStateQuery, + RunE: doKeyQuery, } -func doStateQuery(cmd *cobra.Command, args []string) error { +func doKeyQuery(cmd *cobra.Command, args []string) error { // parse cli - height := viper.GetInt(heightFlag) + height := GetHeight() bkey, err := ParseHexKey(args, nil) if err != nil { return err diff --git a/commands/proofs/tx.go b/commands/proofs/tx.go index 74941a9..5cbbc5e 100644 --- a/commands/proofs/tx.go +++ b/commands/proofs/tx.go @@ -2,7 +2,7 @@ package proofs import ( "github.com/spf13/cobra" - "github.com/spf13/viper" + "github.com/tendermint/light-client/commands" "github.com/tendermint/light-client/proofs" ) @@ -23,7 +23,7 @@ data to other peers as needed. func doTxQuery(cmd *cobra.Command, args []string) error { // parse cli - height := viper.GetInt(heightFlag) + height := GetHeight() bkey, err := ParseHexKey(args, nil) if err != nil { return err diff --git a/proofs/presenters.go b/proofs/presenters.go index 758b508..84e772a 100644 --- a/proofs/presenters.go +++ b/proofs/presenters.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "github.com/pkg/errors" + data "github.com/tendermint/go-wire/data" ) From c7d5799ddee67238c81a6dba66735804e472c290 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 14 Jun 2017 14:52:28 +0200 Subject: [PATCH 9/9] A bit or cleanup on hex arg parsing helper --- commands/proofs/root.go | 12 ++++++------ commands/proofs/state.go | 2 +- commands/proofs/tx.go | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/commands/proofs/root.go b/commands/proofs/root.go index 9efbc60..4312dc6 100644 --- a/commands/proofs/root.go +++ b/commands/proofs/root.go @@ -36,20 +36,20 @@ func init() { } // ParseHexKey parses the key flag as hex and converts to bytes or returns error -// if prefix is non-nil, it prepends this constant to the given key (eg. "base/a/") -func ParseHexKey(args []string, prefix []byte) ([]byte, error) { +// argname is used to customize the error message +func ParseHexKey(args []string, argname string) ([]byte, error) { if len(args) == 0 { - return nil, errors.New("Missing required key argument") + return nil, errors.Errorf("Missing required argument [%s]", argname) } if len(args) > 1 { - return nil, errors.Errorf("Only accepts one key argument") + return nil, errors.Errorf("Only accepts one argument [%s]", argname) } rawkey := args[0] if rawkey == "" { - return nil, errors.New("Cannot query on empty key") + 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.KeyMaker{prefix}.MakeKey(rawkey) + return proofs.ParseHexKey(rawkey) } func GetHeight() int { diff --git a/commands/proofs/state.go b/commands/proofs/state.go index f3cbbcd..a64d8b5 100644 --- a/commands/proofs/state.go +++ b/commands/proofs/state.go @@ -22,7 +22,7 @@ If you want json output, use an app-specific command that knows key and value st func doKeyQuery(cmd *cobra.Command, args []string) error { // parse cli height := GetHeight() - bkey, err := ParseHexKey(args, nil) + bkey, err := ParseHexKey(args, "key") if err != nil { return err } diff --git a/commands/proofs/tx.go b/commands/proofs/tx.go index 5cbbc5e..5c199ab 100644 --- a/commands/proofs/tx.go +++ b/commands/proofs/tx.go @@ -24,7 +24,7 @@ data to other peers as needed. func doTxQuery(cmd *cobra.Command, args []string) error { // parse cli height := GetHeight() - bkey, err := ParseHexKey(args, nil) + bkey, err := ParseHexKey(args, "txhash") if err != nil { return err }