diff --git a/cmd/basecoin/cmd.go b/cmd/basecoin/cmd.go index e8873de6ca..6cb56d30e8 100644 --- a/cmd/basecoin/cmd.go +++ b/cmd/basecoin/cmd.go @@ -197,4 +197,18 @@ var ( nodeFlag, }, } + + verifyCmd = cli.Command{ + Name: "verify", + Usage: "Verify the IAVL proof", + Action: func(c *cli.Context) error { + return cmdVerify(c) + }, + Flags: []cli.Flag{ + proofFlag, + keyFlag, + valueFlag, + rootFlag, + }, + } ) diff --git a/cmd/basecoin/flags.go b/cmd/basecoin/flags.go index 5b36d854e6..dd454c53eb 100644 --- a/cmd/basecoin/flags.go +++ b/cmd/basecoin/flags.go @@ -194,3 +194,30 @@ var ( Value: 0, } ) + +// proof flags +var ( + proofFlag = cli.StringFlag{ + Name: "proof", + Usage: "hex-encoded IAVL proof", + Value: "", + } + + keyFlag = cli.StringFlag{ + Name: "key", + Usage: "key to the IAVL tree", + Value: "", + } + + valueFlag = cli.StringFlag{ + Name: "value", + Usage: "value in the IAVL tree", + Value: "", + } + + rootFlag = cli.StringFlag{ + Name: "root", + Usage: "root hash of the IAVL tree", + Value: "", + } +) diff --git a/cmd/basecoin/main.go b/cmd/basecoin/main.go index 7bc44b99ac..31dcb83525 100644 --- a/cmd/basecoin/main.go +++ b/cmd/basecoin/main.go @@ -17,6 +17,7 @@ func main() { appTxCmd, ibcCmd, queryCmd, + verifyCmd, blockCmd, accountCmd, } diff --git a/cmd/basecoin/query.go b/cmd/basecoin/query.go index c42507e44d..2aba1b8f58 100644 --- a/cmd/basecoin/query.go +++ b/cmd/basecoin/query.go @@ -9,6 +9,7 @@ import ( "github.com/urfave/cli" cmn "github.com/tendermint/go-common" + "github.com/tendermint/go-merkle" "github.com/tendermint/go-wire" tmtypes "github.com/tendermint/tendermint/types" ) @@ -115,3 +116,46 @@ type BlockJSON struct { Header *tmtypes.Header `json:"header"` Commit *tmtypes.Commit `json:"commit"` } + +func cmdVerify(c *cli.Context) error { + keyString, valueString := c.String("key"), c.String("value") + + var err error + key := []byte(keyString) + if isHex(keyString) { + key, err = hex.DecodeString(stripHex(keyString)) + if err != nil { + return errors.New(cmn.Fmt("Key (%v) is invalid hex: %v", keyString, err)) + } + } + + value := []byte(valueString) + if isHex(valueString) { + value, err = hex.DecodeString(stripHex(valueString)) + if err != nil { + return errors.New(cmn.Fmt("Value (%v) is invalid hex: %v", valueString, err)) + } + } + + root, err := hex.DecodeString(stripHex(c.String("root"))) + if err != nil { + return errors.New(cmn.Fmt("Root (%v) is invalid hex: %v", c.String("root"), err)) + } + + proofBytes, err := hex.DecodeString(stripHex(c.String("proof"))) + if err != nil { + return errors.New(cmn.Fmt("Proof (%v) is invalid hex: %v", c.String("proof"), err)) + } + + proof, err := merkle.ReadProof(proofBytes) + if err != nil { + return errors.New(cmn.Fmt("Error unmarshalling proof: %v", err)) + } + + if proof.Verify(key, value, root) { + fmt.Println("OK") + } else { + return errors.New("Proof does not verify") + } + return nil +}