From b16ce7e0c2aa620bf03c6ea3d6c0d2fde309dfb3 Mon Sep 17 00:00:00 2001 From: mossid Date: Thu, 12 Jul 2018 23:50:39 -0700 Subject: [PATCH] in progress --- crypto/merkle/merkle.pb.go | 33 ++++++++++---------- crypto/merkle/merkle.proto | 2 +- crypto/merkle/proof.go | 46 +++++++++++----------------- crypto/merkle/proof_key_path.go | 25 +++++++-------- crypto/merkle/proof_key_path_test.go | 29 ++++++++++++++++++ crypto/merkle/proof_simple_value.go | 6 ++-- 6 files changed, 80 insertions(+), 61 deletions(-) create mode 100644 crypto/merkle/proof_key_path_test.go diff --git a/crypto/merkle/merkle.pb.go b/crypto/merkle/merkle.pb.go index c778530f..8ad54b50 100644 --- a/crypto/merkle/merkle.pb.go +++ b/crypto/merkle/merkle.pb.go @@ -1,4 +1,4 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. +// Code generated by protoc-gen-go. DO NOT EDIT. // source: merkle.proto /* @@ -11,10 +11,9 @@ It has these top-level messages: ProofOp Proof */ -//nolint: gas package merkle -import proto "github.com/gogo/protobuf/proto" +import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" import _ "github.com/gogo/protobuf/gogoproto" @@ -28,18 +27,18 @@ var _ = math.Inf // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type ProofOp struct { - Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` - Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` + Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` } func (m *ProofOp) Reset() { *m = ProofOp{} } func (m *ProofOp) String() string { return proto.CompactTextString(m) } func (*ProofOp) ProtoMessage() {} -func (*ProofOp) Descriptor() ([]byte, []int) { return fileDescriptorMerkle, []int{0} } +func (*ProofOp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (m *ProofOp) GetType() string { if m != nil { @@ -48,11 +47,11 @@ func (m *ProofOp) GetType() string { return "" } -func (m *ProofOp) GetKey() string { +func (m *ProofOp) GetKey() []byte { if m != nil { return m.Key } - return "" + return nil } func (m *ProofOp) GetData() []byte { @@ -63,15 +62,15 @@ func (m *ProofOp) GetData() []byte { } type Proof struct { - Ops []ProofOp `protobuf:"bytes,1,rep,name=ops" json:"ops"` + Ops []*ProofOp `protobuf:"bytes,1,rep,name=ops" json:"ops,omitempty"` } func (m *Proof) Reset() { *m = Proof{} } func (m *Proof) String() string { return proto.CompactTextString(m) } func (*Proof) ProtoMessage() {} -func (*Proof) Descriptor() ([]byte, []int) { return fileDescriptorMerkle, []int{1} } +func (*Proof) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } -func (m *Proof) GetOps() []ProofOp { +func (m *Proof) GetOps() []*ProofOp { if m != nil { return m.Ops } @@ -83,19 +82,19 @@ func init() { proto.RegisterType((*Proof)(nil), "merkle.Proof") } -func init() { proto.RegisterFile("merkle.proto", fileDescriptorMerkle) } +func init() { proto.RegisterFile("merkle.proto", fileDescriptor0) } -var fileDescriptorMerkle = []byte{ +var fileDescriptor0 = []byte{ // 168 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xc9, 0x4d, 0x2d, 0xca, 0xce, 0x49, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x83, 0xf0, 0xa4, 0x74, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0xd3, 0xf3, 0xd3, 0xf3, 0xf5, 0xc1, 0xd2, 0x49, 0xa5, 0x69, 0x60, 0x1e, 0x98, 0x03, 0x66, 0x41, 0xb4, 0x29, 0x39, 0x73, 0xb1, 0x07, 0x14, 0xe5, 0xe7, 0xa7, 0xf9, 0x17, 0x08, 0x09, 0x71, 0xb1, 0x94, 0x54, 0x16, 0xa4, 0x4a, 0x30, 0x2a, - 0x30, 0x6a, 0x70, 0x06, 0x81, 0xd9, 0x42, 0x02, 0x5c, 0xcc, 0xd9, 0xa9, 0x95, 0x12, 0x4c, 0x60, - 0x21, 0x10, 0x13, 0xa4, 0x2a, 0x25, 0xb1, 0x24, 0x51, 0x82, 0x59, 0x81, 0x51, 0x83, 0x27, 0x08, + 0x30, 0x6a, 0x70, 0x06, 0x81, 0xd9, 0x42, 0x02, 0x5c, 0xcc, 0xd9, 0xa9, 0x95, 0x12, 0x4c, 0x0a, + 0x8c, 0x1a, 0x3c, 0x41, 0x20, 0x26, 0x48, 0x55, 0x4a, 0x62, 0x49, 0xa2, 0x04, 0x33, 0x58, 0x08, 0xcc, 0x56, 0x32, 0xe0, 0x62, 0x05, 0x1b, 0x22, 0xa4, 0xce, 0xc5, 0x9c, 0x5f, 0x50, 0x2c, 0xc1, 0xa8, 0xc0, 0xac, 0xc1, 0x6d, 0xc4, 0xaf, 0x07, 0x75, 0x20, 0xd4, 0x02, 0x27, 0x96, 0x13, 0xf7, 0xe4, 0x19, 0x82, 0x40, 0x2a, 0x92, 0xd8, 0xc0, 0xb6, 0x1b, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, - 0x52, 0x58, 0x00, 0xa7, 0xc4, 0x00, 0x00, 0x00, + 0xe0, 0x7d, 0x7c, 0x4e, 0xc4, 0x00, 0x00, 0x00, } diff --git a/crypto/merkle/merkle.proto b/crypto/merkle/merkle.proto index 053387ff..6fff6daa 100644 --- a/crypto/merkle/merkle.proto +++ b/crypto/merkle/merkle.proto @@ -10,7 +10,7 @@ import "github.com/gogo/protobuf/gogoproto/gogo.proto"; message ProofOp { string type = 1; - string key = 2; + bytes key = 2; bytes data = 3; } diff --git a/crypto/merkle/proof.go b/crypto/merkle/proof.go index ed16b997..358e8518 100644 --- a/crypto/merkle/proof.go +++ b/crypto/merkle/proof.go @@ -3,27 +3,15 @@ package merkle import ( "bytes" - "github.com/tendermint/go-amino" cmn "github.com/tendermint/tmlibs/common" ) -//---------------------------------------- -// Extension of ProofOp (defined in merkle.proto) - -func (po ProofOp) Bytes() []byte { - bz, err := amino.MarshalBinary(po) - if err != nil { - panic(err) - } - return bz -} - //---------------------------------------- // ProofOp gets converted to an instance of ProofOperator: type ProofOperator interface { Run([][]byte) ([][]byte, error) - GetKey() string + GetKey() []byte ProofOp() ProofOp } @@ -32,18 +20,20 @@ type ProofOperator interface { type ProofOperators []ProofOperator -// XXX Reorder value/keys. -// XXX Replace keys with keyString (the result of KeyPath.String()) -func (poz ProofOperators) VerifyValue(root []byte, value []byte, keys ...string) (err error) { - return poz.Verify(root, [][]byte{value}, keys...) +func (poz ProofOperators) VerifyValue(root []byte, keypath string, value []byte) (err error) { + return poz.Verify(root, keypath, [][]byte{value}) } -// XXX Replace keys with keyString (the result of KeyPath.String()) -func (poz ProofOperators) Verify(root []byte, args [][]byte, keys ...string) (err error) { +func (poz ProofOperators) Verify(root []byte, keypath string, args [][]byte) (err error) { + keys, err := KeyPathToKeys(keypath) + if err != nil { + return + } + for i, op := range poz { key := op.GetKey() - if key != "" { - if keys[0] != key { + if len(key) != 0 { + if !bytes.Equal(keys[0], key) { return cmn.NewError("Key mismatch on operation #%d: expected %+v but %+v", i, []byte(keys[0]), []byte(key)) } keys = keys[1:] @@ -93,7 +83,7 @@ func (prt *ProofRuntime) Decode(pop ProofOp) (ProofOperator, error) { func (prt *ProofRuntime) DecodeProof(proof *Proof) (poz ProofOperators, err error) { poz = ProofOperators(nil) for _, pop := range proof.Ops { - operator, err := prt.Decode(pop) + operator, err := prt.Decode(*pop) if err != nil { return nil, cmn.ErrorWrap(err, "decoding a proof operator") } @@ -104,26 +94,26 @@ func (prt *ProofRuntime) DecodeProof(proof *Proof) (poz ProofOperators, err erro // XXX Reorder value/keys. // XXX Replace keys with keyString (the result of KeyPath.String()). -func (prt *ProofRuntime) VerifyValue(proof *Proof, root []byte, value []byte, keys ...string) (err error) { - return prt.Verify(proof, root, [][]byte{value}, keys...) +func (prt *ProofRuntime) VerifyValue(proof *Proof, root []byte, keypath string, value []byte) (err error) { + return prt.Verify(proof, root, keypath, [][]byte{value}) } // XXX Reorder value/keys. // XXX Replace keys with keyString (the result of KeyPath.String()). // TODO In the long run we'll need a method of classifcation of ops, // whether existence or absence or perhaps a third? -func (prt *ProofRuntime) VerifyAbsence(proof *Proof, root []byte, keys ...string) (err error) { - return prt.Verify(proof, root, nil, keys...) +func (prt *ProofRuntime) VerifyAbsence(proof *Proof, keypath string, root []byte) (err error) { + return prt.Verify(proof, root, keypath, nil) } // XXX Reorder value/keys. // XXX Replace keys with keyString (the result of KeyPath.String()). -func (prt *ProofRuntime) Verify(proof *Proof, root []byte, args [][]byte, keys ...string) (err error) { +func (prt *ProofRuntime) Verify(proof *Proof, root []byte, keypath string, args [][]byte) (err error) { poz, err := prt.DecodeProof(proof) if err != nil { return cmn.ErrorWrap(err, "decoding proof") } - return poz.Verify(root, args, keys...) + return poz.Verify(root, keypath, args) } // DefaultProofRuntime only knows about Simple value diff --git a/crypto/merkle/proof_key_path.go b/crypto/merkle/proof_key_path.go index 823283e2..b49b9ea6 100644 --- a/crypto/merkle/proof_key_path.go +++ b/crypto/merkle/proof_key_path.go @@ -52,27 +52,28 @@ type keyEncoding int const ( KeyEncodingURL keyEncoding = iota KeyEncodingHex + KeyEncodingMax ) -type KeyPath struct { - keys [][]byte - encs []keyEncoding +type Key struct { + name []byte + enc keyEncoding } -func (pth *KeyPath) AppendKey(key []byte, enc keyEncoding) { - pth.keys = append(pth.keys, key) - pth.encs = append(pth.encs, enc) +type KeyPath []Key + +func (pth KeyPath) AppendKey(key []byte, enc keyEncoding) KeyPath { + return append(pth, Key{key, enc}) } -func (pth *KeyPath) String() string { +func (pth KeyPath) String() string { res := "" - for i := 0; i < len(pth.keys); i++ { - key, enc := pth.keys[i], pth.encs[i] - switch enc { + for _, key := range pth { + switch key.enc { case KeyEncodingURL: - res += "/" + url.PathEscape(string(key)) + res += "/" + url.PathEscape(string(key.name)) case KeyEncodingHex: - res += "/x:" + fmt.Sprintf("%X", key) + res += "/x:" + fmt.Sprintf("%X", key.name) default: panic("unexpected key encoding type") } diff --git a/crypto/merkle/proof_key_path_test.go b/crypto/merkle/proof_key_path_test.go new file mode 100644 index 00000000..b185d5e3 --- /dev/null +++ b/crypto/merkle/proof_key_path_test.go @@ -0,0 +1,29 @@ +package merkle + +import ( + "math/rand" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestKeyPath(t *testing.T) { + var path KeyPath + keys := make([][]byte, 10) + + for d := 0; d < 20; d++ { + for i := range keys { + keys[i] = make([]byte, rand.Uint32()%20) + rand.Read(keys[i]) + enc := keyEncoding(rand.Intn(int(KeyEncodingMax))) + path = path.AppendKey(keys[i], enc) + } + + res, err := KeyPathToKeys(path.String()) + require.Nil(t, err) + + for i, key := range keys { + require.Equal(t, key, res[i]) + } + } +} diff --git a/crypto/merkle/proof_simple_value.go b/crypto/merkle/proof_simple_value.go index b7fb4fb2..ebd2f171 100644 --- a/crypto/merkle/proof_simple_value.go +++ b/crypto/merkle/proof_simple_value.go @@ -22,7 +22,7 @@ const ProofOpSimpleValue = "simple:v" // proof is good. type SimpleValueOp struct { // Encoded in ProofOp.Key. - key string + key []byte // To encode in ProofOp.Data Proof *SimpleProof `json:"simple-proof"` @@ -30,7 +30,7 @@ type SimpleValueOp struct { var _ ProofOperator = SimpleValueOp{} -func NewSimpleValueOp(key string, proof *SimpleProof) SimpleValueOp { +func NewSimpleValueOp(key []byte, proof *SimpleProof) SimpleValueOp { return SimpleValueOp{ key: key, Proof: proof, @@ -86,6 +86,6 @@ func (op SimpleValueOp) Run(args [][]byte) ([][]byte, error) { }, nil } -func (op SimpleValueOp) GetKey() string { +func (op SimpleValueOp) GetKey() []byte { return op.key }