diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f5d3e246..6af578b62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - [#599](https://github.com/cosmos/iavl/pull/599) Populate ImmutableTree creation in copy function with missing field - [#589](https://github.com/cosmos/iavl/pull/589) Wrap `tree.addUnsavedRemoval()` with missing `if !tree.skipFastStorageUpgrade` statement +- [#586](https://github.com/cosmos/iavl/pull/586) Remove the `RangeProof` and refactor the ics23_proof to use the internal methods. ## 0.19.3 (October 8, 2022) diff --git a/basic_test.go b/basic_test.go index 13996c7dd..7f32c62b8 100644 --- a/basic_test.go +++ b/basic_test.go @@ -513,13 +513,17 @@ func TestProof(t *testing.T) { // Now for each item, construct a proof and verify tree.Iterate(func(key []byte, value []byte) bool { - value2, proof, err := tree.GetWithProof(key) + proof, err := tree.GetMembershipProof(key) assert.NoError(t, err) - assert.Equal(t, value, value2) - if assert.NotNil(t, proof) { - hash, err := tree.WorkingHash() - require.NoError(t, err) - verifyProof(t, proof, hash) + assert.Equal(t, value, proof.GetExist().Value) + res, err := tree.VerifyMembership(proof, key) + assert.NoError(t, err) + value2, err := tree.ImmutableTree.Get(key) + assert.NoError(t, err) + if value2 != nil { + assert.True(t, res) + } else { + assert.False(t, res) } return false }) @@ -534,11 +538,8 @@ func TestTreeProof(t *testing.T) { assert.Equal(t, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", hex.EncodeToString(hash)) // should get false for proof with nil root - value, proof, err := tree.GetWithProof([]byte("foo")) - assert.Nil(t, value) - assert.Nil(t, proof) - assert.Error(t, proof.Verify([]byte(nil))) - assert.NoError(t, err) + _, err = tree.GetProof([]byte("foo")) + require.Error(t, err) // insert lots of info and store the bytes keys := make([][]byte, 200) @@ -551,27 +552,18 @@ func TestTreeProof(t *testing.T) { tree.SaveVersion() // query random key fails - value, proof, err = tree.GetWithProof([]byte("foo")) - assert.Nil(t, value) - assert.NotNil(t, proof) - assert.NoError(t, err) - hash, err = tree.Hash() - assert.NoError(t, err) - assert.NoError(t, proof.Verify(hash)) - assert.NoError(t, proof.VerifyAbsence([]byte("foo"))) + _, err = tree.GetMembershipProof([]byte("foo")) + assert.Error(t, err) // valid proof for real keys - root, err := tree.WorkingHash() - assert.NoError(t, err) for _, key := range keys { - value, proof, err := tree.GetWithProof(key) + proof, err := tree.GetMembershipProof(key) if assert.NoError(t, err) { require.Nil(t, err, "Failed to read proof from bytes: %v", err) - assert.Equal(t, key, value) - err := proof.Verify(root) - assert.NoError(t, err, "#### %v", proof.String()) - err = proof.VerifyItem(key, key) - assert.NoError(t, err, "#### %v", proof.String()) + assert.Equal(t, key, proof.GetExist().Value) + res, err := tree.VerifyMembership(proof, key) + require.NoError(t, err) + require.True(t, res) } } } diff --git a/mutable_tree_test.go b/mutable_tree_test.go index b2c2c8ac5..a5fc0f204 100644 --- a/mutable_tree_test.go +++ b/mutable_tree_test.go @@ -44,17 +44,18 @@ func TestDelete(t *testing.T) { require.NoError(t, tree.DeleteVersion(version)) - k1Value, _, _ := tree.GetVersionedWithProof([]byte("k1"), version) - require.Nil(t, k1Value) + proof, err := tree.GetVersionedProof([]byte("k1"), version) + require.EqualError(t, err, ErrVersionDoesNotExist.Error()) + require.Nil(t, proof) key := tree.ndb.rootKey(version) err = tree.ndb.db.Set(key, hash) require.NoError(t, err) tree.versions[version] = true - k1Value, _, err = tree.GetVersionedWithProof([]byte("k1"), version) + proof, err = tree.GetVersionedProof([]byte("k1"), version) require.Nil(t, err) - require.Equal(t, 0, bytes.Compare([]byte("Fred"), k1Value)) + require.Equal(t, 0, bytes.Compare([]byte("Fred"), proof.GetExist().Value)) } func TestGetRemove(t *testing.T) { diff --git a/proof.go b/proof.go index d6dd5b77f..bc7877504 100644 --- a/proof.go +++ b/proof.go @@ -4,14 +4,12 @@ import ( "bytes" "crypto/sha256" "fmt" - "math" "sync" "github.com/pkg/errors" hexbytes "github.com/cosmos/iavl/internal/bytes" "github.com/cosmos/iavl/internal/encoding" - iavlproto "github.com/cosmos/iavl/proto" ) var bufPool = &sync.Pool{ @@ -109,34 +107,6 @@ func (pin ProofInnerNode) Hash(childHash []byte) ([]byte, error) { return hasher.Sum(nil), nil } -// toProto converts the inner node proof to Protobuf, for use in ProofOps. -func (pin ProofInnerNode) toProto() *iavlproto.ProofInnerNode { - return &iavlproto.ProofInnerNode{ - Height: int32(pin.Height), - Size_: pin.Size, - Version: pin.Version, - Left: pin.Left, - Right: pin.Right, - } -} - -// proofInnerNodeFromProto converts a Protobuf ProofInnerNode to a ProofInnerNode. -func proofInnerNodeFromProto(pbInner *iavlproto.ProofInnerNode) (ProofInnerNode, error) { - if pbInner == nil { - return ProofInnerNode{}, errors.New("inner node cannot be nil") - } - if pbInner.Height > math.MaxInt8 || pbInner.Height < math.MinInt8 { - return ProofInnerNode{}, fmt.Errorf("height must fit inside an int8, got %v", pbInner.Height) - } - return ProofInnerNode{ - Height: int8(pbInner.Height), - Size: pbInner.Size_, - Version: pbInner.Version, - Left: pbInner.Left, - Right: pbInner.Right, - }, nil -} - //---------------------------------------- type ProofLeafNode struct { @@ -193,27 +163,6 @@ func (pln ProofLeafNode) Hash() ([]byte, error) { return hasher.Sum(nil), nil } -// toProto converts the leaf node proof to Protobuf, for use in ProofOps. -func (pln ProofLeafNode) toProto() *iavlproto.ProofLeafNode { - return &iavlproto.ProofLeafNode{ - Key: pln.Key, - ValueHash: pln.ValueHash, - Version: pln.Version, - } -} - -// proofLeafNodeFromProto converts a Protobuf ProofLeadNode to a ProofLeafNode. -func proofLeafNodeFromProto(pbLeaf *iavlproto.ProofLeafNode) (ProofLeafNode, error) { - if pbLeaf == nil { - return ProofLeafNode{}, errors.New("leaf node cannot be nil") - } - return ProofLeafNode{ - Key: pbLeaf.Key, - ValueHash: pbLeaf.ValueHash, - Version: pbLeaf.Version, - }, nil -} - //---------------------------------------- // If the key does not exist, returns the path to the next leaf left of key (w/ diff --git a/proof_forgery_test.go b/proof_forgery_test.go deleted file mode 100644 index 241db1cd7..000000000 --- a/proof_forgery_test.go +++ /dev/null @@ -1,106 +0,0 @@ -package iavl_test - -import ( - "encoding/hex" - "math/rand" - "strings" - "testing" - - "github.com/cosmos/iavl" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto/tmhash" - db "github.com/tendermint/tm-db" -) - -func TestProofFogery(t *testing.T) { - source := rand.NewSource(0) - r := rand.New(source) - cacheSize := 0 - tree, err := iavl.NewMutableTreeWithOpts(db.NewMemDB(), cacheSize, nil, false) - require.NoError(t, err) - - // two keys only - keys := []byte{0x11, 0x32} - values := make([][]byte, len(keys)) - // make random values and insert into tree - for i, ikey := range keys { - key := []byte{ikey} - v := r.Intn(255) - values[i] = []byte{byte(v)} - tree.Set(key, values[i]) - } - - // get root - root, err := tree.WorkingHash() - require.NoError(t, err) - // use the rightmost kv pair in the tree so the inner nodes will populate left - k := []byte{keys[1]} - v := values[1] - - val, proof, err := tree.GetWithProof(k) - require.NoError(t, err) - - err = proof.Verify(root) - require.NoError(t, err) - err = proof.VerifyItem(k, val) - require.NoError(t, err) - - // ------------------- FORGE PROOF ------------------- - - forgedPayloadBytes := mustDecode("0xabcd") - forgedValueHash := tmhash.Sum(forgedPayloadBytes) - // make a forgery of the proof by adding: - // - a new leaf node to the right - // - an empty inner node - // - a right entry in the path - _, proof2, _ := tree.GetWithProof(k) - forgedNode := proof2.Leaves[0] - forgedNode.Key = []byte{0xFF} - forgedNode.ValueHash = forgedValueHash - proof2.Leaves = append(proof2.Leaves, forgedNode) - proof2.InnerNodes = append(proof2.InnerNodes, iavl.PathToLeaf{}) - // figure out what hash we need via https://twitter.com/samczsun/status/1578181160345034752 - proof2.LeftPath[0].Right = mustDecode("82C36CED85E914DAE8FDF6DD11FD5833121AA425711EB126C470CE28FF6623D5") - - rootHashValid := proof.ComputeRootHash() - verifyErr := proof.Verify(rootHashValid) - require.NoError(t, verifyErr, "should verify") - // forgery gives empty root hash (previously it returned the same one!) - rootHashForged := proof2.ComputeRootHash() - require.Empty(t, rootHashForged, "roothash must be empty if both left and right are set") - verifyErr = proof2.Verify(rootHashForged) - require.Error(t, verifyErr, "should not verify") - - // verify proof two fails with valid proof - err = proof2.Verify(rootHashValid) - require.Error(t, err, "should not verify different root hash") - - { - // legit node verifies against legit proof (expected) - verifyErr = proof.VerifyItem(k, v) - require.NoError(t, verifyErr, "valid proof should verify") - // forged node fails to verify against legit proof (expected) - verifyErr = proof.VerifyItem(forgedNode.Key, forgedPayloadBytes) - require.Error(t, verifyErr, "forged proof should fail to verify") - } - { - // legit node fails to verify against forged proof (expected) - verifyErr = proof2.VerifyItem(k, v) - require.Error(t, verifyErr, "valid proof should verify, but has a forged sister node") - - // forged node fails to verify against forged proof (previously this succeeded!) - verifyErr = proof2.VerifyItem(forgedNode.Key, forgedPayloadBytes) - require.Error(t, verifyErr, "forged proof should fail verify") - } -} - -func mustDecode(str string) []byte { - if strings.HasPrefix(str, "0x") { - str = str[2:] - } - b, err := hex.DecodeString(str) - if err != nil { - panic(err) - } - return b -} diff --git a/proof_iavl_absence.go b/proof_iavl_absence.go deleted file mode 100644 index e18dbe3f4..000000000 --- a/proof_iavl_absence.go +++ /dev/null @@ -1,121 +0,0 @@ -package iavl - -import ( - "fmt" - - proto "github.com/gogo/protobuf/proto" - "github.com/pkg/errors" - "github.com/tendermint/tendermint/crypto/merkle" - tmmerkle "github.com/tendermint/tendermint/proto/tendermint/crypto" - - "github.com/cosmos/iavl/internal/encoding" - iavlproto "github.com/cosmos/iavl/proto" -) - -const ProofOpIAVLAbsence = "iavl:a" - -// IAVLAbsenceOp takes a key as its only argument -// -// If the produced root hash matches the expected hash, the proof -// is good. -type AbsenceOp struct { - // Encoded in ProofOp.Key. - key []byte - - // To encode in ProofOp.Data. - // Proof is nil for an empty tree. - // The hash of an empty tree is nil. - Proof *RangeProof `json:"proof"` -} - -var _ merkle.ProofOperator = AbsenceOp{} - -func NewAbsenceOp(key []byte, proof *RangeProof) AbsenceOp { - return AbsenceOp{ - key: key, - Proof: proof, - } -} - -func AbsenceOpDecoder(pop tmmerkle.ProofOp) (merkle.ProofOperator, error) { - if pop.Type != ProofOpIAVLAbsence { - return nil, errors.Errorf("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpIAVLAbsence) - } - // Strip the varint length prefix, used for backwards compatibility with Amino. - bz, n, err := encoding.DecodeBytes(pop.Data) - if err != nil { - return nil, err - } - - if n != len(pop.Data) { - return nil, fmt.Errorf("unexpected bytes, expected %v got %v", n, len(pop.Data)) - } - - pbProofOp := &iavlproto.AbsenceOp{} - err = proto.Unmarshal(bz, pbProofOp) - if err != nil { - return nil, err - } - - proof, err := RangeProofFromProto(pbProofOp.Proof) - if err != nil { - return nil, err - } - - return NewAbsenceOp(pop.Key, &proof), nil -} - -func (op AbsenceOp) ProofOp() tmmerkle.ProofOp { - pbProof := iavlproto.AbsenceOp{Proof: op.Proof.ToProto()} - bz, err := proto.Marshal(&pbProof) - if err != nil { - panic(err) - } - // We length-prefix the byte slice to retain backwards compatibility with the Amino proofs. - bz, err = encoding.EncodeBytesSlice(bz) - if err != nil { - panic(err) - } - return tmmerkle.ProofOp{ - Type: ProofOpIAVLAbsence, - Key: op.key, - Data: bz, - } -} - -func (op AbsenceOp) String() string { - return fmt.Sprintf("IAVLAbsenceOp{%v}", op.GetKey()) -} - -func (op AbsenceOp) Run(args [][]byte) ([][]byte, error) { - if len(args) != 0 { - return nil, errors.Errorf("expected 0 args, got %v", len(args)) - } - - // If the tree is nil, the proof is nil, and all keys are absent. - if op.Proof == nil { - return [][]byte{[]byte(nil)}, nil - } - - // Compute the root hash and assume it is valid. - // The caller checks the ultimate root later. - root := op.Proof.ComputeRootHash() - err := op.Proof.Verify(root) - if err != nil { - return nil, errors.Wrap(err, "computing root hash") - } - - // XXX What is the encoding for keys? - // We should decode the key depending on whether it's a string or hex, - // maybe based on quotes and 0x prefix? - err = op.Proof.VerifyAbsence(op.key) - if err != nil { - return nil, errors.Wrap(err, "verifying absence") - } - - return [][]byte{root}, nil -} - -func (op AbsenceOp) GetKey() []byte { - return op.key -} diff --git a/proof_iavl_test.go b/proof_iavl_test.go index 7047309cc..acbbc8337 100644 --- a/proof_iavl_test.go +++ b/proof_iavl_test.go @@ -1,13 +1,10 @@ package iavl import ( - "encoding/hex" "fmt" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - tmmerkle "github.com/tendermint/tendermint/proto/tendermint/crypto" db "github.com/tendermint/tm-db" ) @@ -19,81 +16,44 @@ func TestProofOp(t *testing.T) { key := []byte{ikey} tree.Set(key, key) } - root, err := tree.WorkingHash() - require.NoError(t, err) testcases := []struct { key byte expectPresent bool - expectProofOp string }{ - {0x00, false, "aa010aa7010a280808100a18012a2022b4e34a1778d6a03aac39f00d89deb886e0cc37454e300b7aebeb4f4939c0790a280804100418012a20734fad809673ab2b9672453a8b2bc8c9591e2d1d97933df5b4c3b0531bf82e720a280802100218012a20154b101a72acffe0f5e65d1e144a57dc6f97758d2049821231f02b6a5b44fe811a270a010a122001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b1801"}, - {0x0a, true, "aa010aa7010a280808100a18012a2022b4e34a1778d6a03aac39f00d89deb886e0cc37454e300b7aebeb4f4939c0790a280804100418012a20734fad809673ab2b9672453a8b2bc8c9591e2d1d97933df5b4c3b0531bf82e720a280802100218012a20154b101a72acffe0f5e65d1e144a57dc6f97758d2049821231f02b6a5b44fe811a270a010a122001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b1801"}, - {0x0b, false, "d5010ad2010a280808100a18012a2022b4e34a1778d6a03aac39f00d89deb886e0cc37454e300b7aebeb4f4939c0790a280804100418012a20734fad809673ab2b9672453a8b2bc8c9591e2d1d97933df5b4c3b0531bf82e720a280802100218012a20154b101a72acffe0f5e65d1e144a57dc6f97758d2049821231f02b6a5b44fe8112001a270a010a122001ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b18011a270a011112204a64a107f0cb32536e5bce6c98c393db21cca7f4ea187ba8c4dca8b51d4ea80a1801"}, - {0x11, true, "aa010aa7010a280808100a18012a2022b4e34a1778d6a03aac39f00d89deb886e0cc37454e300b7aebeb4f4939c0790a280804100418012a20734fad809673ab2b9672453a8b2bc8c9591e2d1d97933df5b4c3b0531bf82e720a28080210021801222053d2828f35e33aecab8e411a40afb0475288973b96aed2220e9894f43a5375ad1a270a011112204a64a107f0cb32536e5bce6c98c393db21cca7f4ea187ba8c4dca8b51d4ea80a1801"}, - {0x60, false, "d5010ad2010a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a280806100618012a20631b10ce49ece4cc9130befac927865742fb11caf2e8fc08fc00a4a25e4bc7940a280802100218012a207a4a97f565ae0b3ea8abf175208f176ac8301665ac2d26c89be3664f90e23da612001a270a015012205c62e091b8c0565f1bafad0dad5934276143ae2ccef7a5381e8ada5b1a8d26d218011a270a01721220454349e422f05297191ead13e21d3db520e5abef52055e4964b82fb213f593a11801"}, - {0x72, true, "aa010aa7010a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a280806100618012a20631b10ce49ece4cc9130befac927865742fb11caf2e8fc08fc00a4a25e4bc7940a28080210021801222035f8ea805390e084854f399b42ccdeaea33a1dedc115638ac48d0600637dba1f1a270a01721220454349e422f05297191ead13e21d3db520e5abef52055e4964b82fb213f593a11801"}, - {0x99, true, "d4010ad1010a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a2808061006180122201d6b29f2c439fc9f15703eb7031e4a216002ea36ee9496583f97b20302b6a74e0a280804100418012a2043b83a6acefd4fd33970d1bc8fc47bed81220c752b8de7053e8ee082a2c7c1290a280802100218012a208f69a1db006c0ee9fad3c7c624b92acc88e9ed00771976ea24a64796c236fef01a270a01991220fd9528b920d6d3956e9e16114523e1889c751e8c1e040182116d4c906b43f5581801"}, - {0xaa, false, "a9020aa6020a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a2808061006180122201d6b29f2c439fc9f15703eb7031e4a216002ea36ee9496583f97b20302b6a74e0a280804100418012a2043b83a6acefd4fd33970d1bc8fc47bed81220c752b8de7053e8ee082a2c7c1290a280802100218012220a303930ca8831618ac7e4ddd10546cfc366fb730d6630c030a97226bbefc6935122a0a280802100218012a2077ad141b2010cf7107de941aac5b46f44fa4f41251076656a72308263a964fb91a270a01a112208a8950f7623663222542c9469c73be3c4c81bbdf019e2c577590a61f2ce9a15718011a270a01e412205e1effe9b7bab73dce628ccd9f0cbbb16c1e6efc6c4f311e59992a467bc119fd1801"}, - {0xe4, true, "d4010ad1010a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a2808061006180122201d6b29f2c439fc9f15703eb7031e4a216002ea36ee9496583f97b20302b6a74e0a2808041004180122208bc4764843fdd745dc853fa62f2fac0001feae9e46136192f466c09773e2ed050a280802100218012a2077ad141b2010cf7107de941aac5b46f44fa4f41251076656a72308263a964fb91a270a01e412205e1effe9b7bab73dce628ccd9f0cbbb16c1e6efc6c4f311e59992a467bc119fd1801"}, - {0xf7, true, "d4010ad1010a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a2808061006180122201d6b29f2c439fc9f15703eb7031e4a216002ea36ee9496583f97b20302b6a74e0a2808041004180122208bc4764843fdd745dc853fa62f2fac0001feae9e46136192f466c09773e2ed050a28080210021801222032af6e3eec2b63d5fe1bd992a89ef3467b3cee639c068cace942f01326098f171a270a01f7122050868f20258bbc9cce0da2719e8654c108733dd2f663b8737c574ec0ead93eb31801"}, - {0xff, false, "d4010ad1010a280808100a18012220e39776faa9ef2b83ae828860d24f807efab321d02b78081c0e68e1bf801b0e220a2808061006180122201d6b29f2c439fc9f15703eb7031e4a216002ea36ee9496583f97b20302b6a74e0a2808041004180122208bc4764843fdd745dc853fa62f2fac0001feae9e46136192f466c09773e2ed050a28080210021801222032af6e3eec2b63d5fe1bd992a89ef3467b3cee639c068cace942f01326098f171a270a01f7122050868f20258bbc9cce0da2719e8654c108733dd2f663b8737c574ec0ead93eb31801"}, + {0x00, false}, + {0x0a, true}, + {0x0b, false}, + {0x11, true}, + {0x60, false}, + {0x72, true}, + {0x99, true}, + {0xaa, false}, + {0xe4, true}, + {0xf7, true}, + {0xff, false}, } for _, tc := range testcases { tc := tc t.Run(fmt.Sprintf("%02x", tc.key), func(t *testing.T) { key := []byte{tc.key} - value, proof, err := tree.GetWithProof(key) - require.NoError(t, err) - - // Verify that proof is valid. - err = proof.Verify(root) - require.NoError(t, err) - - // Encode and decode proof, either ValueOp or AbsentOp depending on key existence. - expectBytes, err := hex.DecodeString(tc.expectProofOp) - require.NoError(t, err) - if tc.expectPresent { - require.NotNil(t, value) - err = proof.VerifyItem(key, value) + proof, err := tree.GetMembershipProof(key) require.NoError(t, err) - valueOp := NewValueOp(key, proof) - proofOp := valueOp.ProofOp() - assert.Equal(t, tmmerkle.ProofOp{ - Type: ProofOpIAVLValue, - Key: key, - Data: expectBytes, - }, proofOp) - - d, e := ValueOpDecoder(proofOp) - require.NoError(t, e) - decoded := d.(ValueOp) - err = decoded.Proof.Verify(root) + // Verify that proof is valid. + res, err := tree.VerifyMembership(proof, key) require.NoError(t, err) - assert.Equal(t, valueOp, decoded) - + require.True(t, res) } else { - require.Nil(t, value) - err = proof.VerifyAbsence(key) + proof, err := tree.GetNonMembershipProof(key) require.NoError(t, err) - absenceOp := NewAbsenceOp(key, proof) - proofOp := absenceOp.ProofOp() - assert.Equal(t, tmmerkle.ProofOp{ - Type: ProofOpIAVLAbsence, - Key: key, - Data: expectBytes, - }, proofOp) - - d, e := AbsenceOpDecoder(proofOp) - require.NoError(t, e) - decoded := d.(AbsenceOp) - err = decoded.Proof.Verify(root) + // Verify that proof is valid. + res, err := tree.VerifyNonMembership(proof, key) require.NoError(t, err) - assert.Equal(t, absenceOp, decoded) + require.True(t, res) } }) } diff --git a/proof_iavl_value.go b/proof_iavl_value.go deleted file mode 100644 index 68dada259..000000000 --- a/proof_iavl_value.go +++ /dev/null @@ -1,112 +0,0 @@ -package iavl - -import ( - "fmt" - - proto "github.com/gogo/protobuf/proto" - "github.com/pkg/errors" - "github.com/tendermint/tendermint/crypto/merkle" - tmmerkle "github.com/tendermint/tendermint/proto/tendermint/crypto" - - "github.com/cosmos/iavl/internal/encoding" - iavlproto "github.com/cosmos/iavl/proto" -) - -const ProofOpIAVLValue = "iavl:v" - -// IAVLValueOp takes a key and a single value as argument and -// produces the root hash. -// -// If the produced root hash matches the expected hash, the proof -// is good. -type ValueOp struct { - // Encoded in ProofOp.Key. - key []byte - - // To encode in ProofOp.Data. - // Proof is nil for an empty tree. - // The hash of an empty tree is nil. - Proof *RangeProof `json:"proof"` -} - -var _ merkle.ProofOperator = ValueOp{} - -func NewValueOp(key []byte, proof *RangeProof) ValueOp { - return ValueOp{ - key: key, - Proof: proof, - } -} - -func ValueOpDecoder(pop tmmerkle.ProofOp) (merkle.ProofOperator, error) { - if pop.Type != ProofOpIAVLValue { - return nil, errors.Errorf("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpIAVLValue) - } - // Strip the varint length prefix, used for backwards compatibility with Amino. - bz, n, err := encoding.DecodeBytes(pop.Data) - if err != nil { - return nil, err - } - if n != len(pop.Data) { - return nil, fmt.Errorf("unexpected bytes, expected %v got %v", n, len(pop.Data)) - } - pbProofOp := &iavlproto.ValueOp{} - err = proto.Unmarshal(bz, pbProofOp) - if err != nil { - return nil, err - } - proof, err := RangeProofFromProto(pbProofOp.Proof) - if err != nil { - return nil, err - } - return NewValueOp(pop.Key, &proof), nil -} - -func (op ValueOp) ProofOp() tmmerkle.ProofOp { - pbProof := iavlproto.ValueOp{Proof: op.Proof.ToProto()} - bz, err := proto.Marshal(&pbProof) - if err != nil { - panic(err) - } - // We length-prefix the byte slice to retain backwards compatibility with the Amino proofs. - bz, err = encoding.EncodeBytesSlice(bz) - if err != nil { - panic(err) - } - return tmmerkle.ProofOp{ - Type: ProofOpIAVLValue, - Key: op.key, - Data: bz, - } -} - -func (op ValueOp) String() string { - return fmt.Sprintf("IAVLValueOp{%v}", op.GetKey()) -} - -func (op ValueOp) Run(args [][]byte) ([][]byte, error) { - if len(args) != 1 { - return nil, errors.New("value size is not 1") - } - value := args[0] - - // Compute the root hash and assume it is valid. - // The caller checks the ultimate root later. - root := op.Proof.ComputeRootHash() - err := op.Proof.Verify(root) - if err != nil { - return nil, errors.Wrap(err, "computing root hash") - } - // XXX What is the encoding for keys? - // We should decode the key depending on whether it's a string or hex, - // maybe based on quotes and 0x prefix? - err = op.Proof.VerifyItem(op.key, value) - if err != nil { - return nil, errors.Wrap(err, "verifying value") - } - return [][]byte{root}, nil -} - -func (op ValueOp) GetKey() []byte { - return op.key -} diff --git a/proof_ics23.go b/proof_ics23.go index 991359a79..497a22934 100644 --- a/proof_ics23.go +++ b/proof_ics23.go @@ -12,7 +12,7 @@ GetMembershipProof will produce a CommitmentProof that the given key (and querie If the key doesn't exist in the tree, this will return an error. */ func (t *ImmutableTree) GetMembershipProof(key []byte) (*ics23.CommitmentProof, error) { - exist, err := createExistenceProof(t, key) + exist, err := t.createExistenceProof(key) if err != nil { return nil, err } @@ -24,6 +24,20 @@ func (t *ImmutableTree) GetMembershipProof(key []byte) (*ics23.CommitmentProof, return proof, nil } +// VerifyMembership returns true iff proof is an ExistenceProof for the given key. +func (t *ImmutableTree) VerifyMembership(proof *ics23.CommitmentProof, key []byte) (bool, error) { + val, err := t.Get(key) + if err != nil { + return false, err + } + root, err := t.Hash() + if err != nil { + return false, err + } + + return ics23.VerifyMembership(ics23.IavlSpec, root, proof, key, val), nil +} + /* GetNonMembershipProof will produce a CommitmentProof that the given key doesn't exist in the iavl tree. If the key exists in the tree, this will return an error. @@ -50,7 +64,7 @@ func (t *ImmutableTree) GetNonMembershipProof(key []byte) (*ics23.CommitmentProo return nil, err } - nonexist.Left, err = createExistenceProof(t, leftkey) + nonexist.Left, err = t.createExistenceProof(leftkey) if err != nil { return nil, err } @@ -63,7 +77,7 @@ func (t *ImmutableTree) GetNonMembershipProof(key []byte) (*ics23.CommitmentProo } if rightkey != nil { - nonexist.Right, err = createExistenceProof(t, rightkey) + nonexist.Right, err = t.createExistenceProof(rightkey) if err != nil { return nil, err } @@ -77,32 +91,30 @@ func (t *ImmutableTree) GetNonMembershipProof(key []byte) (*ics23.CommitmentProo return proof, nil } -func createExistenceProof(tree *ImmutableTree, key []byte) (*ics23.ExistenceProof, error) { - value, proof, err := tree.GetWithProof(key) +// VerifyNonMembership returns true iff proof is a NonExistenceProof for the given key. +func (t *ImmutableTree) VerifyNonMembership(proof *ics23.CommitmentProof, key []byte) (bool, error) { + root, err := t.Hash() if err != nil { - return nil, err + return false, err } - if value == nil { - return nil, fmt.Errorf("cannot create ExistanceProof when Key not in State") - } - return convertExistenceProof(proof, key, value) + + return ics23.VerifyNonMembership(ics23.IavlSpec, root, proof, key), nil } -// convertExistenceProof will convert the given proof into a valid +// createExistenceProof will get the proof from the tree and convert the proof into a valid // existence proof, if that's what it is. -// -// This is the simplest case of the range proof and we will focus on -// demoing compatibility here -func convertExistenceProof(p *RangeProof, key, value []byte) (*ics23.ExistenceProof, error) { - if len(p.Leaves) != 1 { - return nil, fmt.Errorf("existence proof requires RangeProof to have exactly one leaf") +func (t *ImmutableTree) createExistenceProof(key []byte) (*ics23.ExistenceProof, error) { + _, err := t.Hash() + if err != nil { + return nil, err } + path, node, err := t.root.PathToLeaf(t, key) return &ics23.ExistenceProof{ - Key: key, - Value: value, - Leaf: convertLeafOp(p.Leaves[0].Version), - Path: convertInnerOps(p.LeftPath), - }, nil + Key: node.key, + Value: node.value, + Leaf: convertLeafOp(node.version), + Path: convertInnerOps(path), + }, err } func convertLeafOp(version int64) *ics23.LeafOp { @@ -166,3 +178,40 @@ func convertVarIntToBytes(orig int64, buf [binary.MaxVarintLen64]byte) []byte { n := binary.PutVarint(buf[:], orig) return buf[:n] } + +// GetProof gets the proof for the given key. +func (t *ImmutableTree) GetProof(key []byte) (*ics23.CommitmentProof, error) { + if t.root == nil { + return nil, fmt.Errorf("cannot generate the proof with nil root") + } + + exist, err := t.Has(key) + if err != nil { + return nil, err + } + + if exist { + return t.GetMembershipProof(key) + } + return t.GetNonMembershipProof(key) +} + +// VerifyProof checks if the proof is correct for the given key. +func (t *ImmutableTree) VerifyProof(proof *ics23.CommitmentProof, key []byte) (bool, error) { + if proof.GetExist() != nil { + return t.VerifyMembership(proof, key) + } + return t.VerifyNonMembership(proof, key) +} + +// GetVersionedProof gets the proof for the given key at the specified version. +func (tree *MutableTree) GetVersionedProof(key []byte, version int64) (*ics23.CommitmentProof, error) { + if tree.VersionExists(version) { + t, err := tree.GetImmutable(version) + if err != nil { + return nil, err + } + return t.GetProof(key) + } + return nil, ErrVersionDoesNotExist +} diff --git a/proof_ics23_test.go b/proof_ics23_test.go index fd0a6d196..97d4bd3a1 100644 --- a/proof_ics23_test.go +++ b/proof_ics23_test.go @@ -2,7 +2,6 @@ package iavl import ( "bytes" - "fmt" "math/rand" "sort" "testing" @@ -13,19 +12,6 @@ import ( db "github.com/tendermint/tm-db" ) -func TestConvertExistence(t *testing.T) { - proof, err := GenerateResult(200, Middle) - require.NoError(t, err) - - converted, err := convertExistenceProof(proof.Proof, proof.Key, proof.Value) - require.NoError(t, err) - - calc, err := converted.Calculate() - require.NoError(t, err) - - require.Equal(t, []byte(calc), proof.RootHash, "Calculated: %X\nExpected: %X", calc, proof.RootHash) -} - func TestGetMembership(t *testing.T) { cases := map[string]struct { size int @@ -51,12 +37,10 @@ func TestGetMembership(t *testing.T) { proof, err := tree.GetMembershipProof(key) require.NoError(t, err, "Creating Proof: %+v", err) - root, err := tree.Hash() + root, err := tree.WorkingHash() require.NoError(t, err) valid := ics23.VerifyMembership(ics23.IavlSpec, root, proof, key, val) - if !valid { - require.NoError(t, err, "Membership Proof Invalid") - } + require.True(t, valid, "Membership Proof Invalid") }) } } @@ -80,12 +64,10 @@ func TestGetNonMembership(t *testing.T) { proof, err := tree.GetNonMembershipProof(key) require.NoError(t, err, "Creating Proof: %+v", err) - root, err := tree.Hash() + root, err := tree.WorkingHash() require.NoError(t, err) valid := ics23.VerifyNonMembership(ics23.IavlSpec, root, proof, key) - if !valid { - require.NoError(t, err, "Non Membership Proof Invalid") - } + require.True(t, valid, "Non Membership Proof Invalid") } for name, tc := range cases { @@ -136,12 +118,10 @@ func BenchmarkGetNonMembership(b *testing.B) { require.NoError(b, err, "Creating Proof: %+v", err) b.StopTimer() - root, err := tree.Hash() + root, err := tree.WorkingHash() require.NoError(b, err) valid := ics23.VerifyNonMembership(ics23.IavlSpec, root, proof, key) - if !valid { - require.NoError(b, err, "Non Membership Proof Invalid") - } + require.True(b, valid) b.StartTimer() } @@ -185,52 +165,6 @@ func BenchmarkGetNonMembership(b *testing.B) { // Test Helpers -// Result is the result of one match -type Result struct { - Key []byte - Value []byte - Proof *RangeProof - RootHash []byte -} - -// GenerateResult makes a tree of size and returns a range proof for one random element -// -// returns a range proof and the root hash of the tree -func GenerateResult(size int, loc Where) (*Result, error) { - tree, allkeys, err := BuildTree(size, 0) - if err != nil { - return nil, err - } - _, _, err = tree.SaveVersion() - if err != nil { - return nil, err - } - key := GetKey(allkeys, loc) - - value, proof, err := tree.GetWithProof(key) - if err != nil { - return nil, err - } - if value == nil { - return nil, fmt.Errorf("tree.GetWithProof returned nil value") - } - if len(proof.Leaves) != 1 { - return nil, fmt.Errorf("tree.GetWithProof returned %d leaves", len(proof.Leaves)) - } - root, err := tree.Hash() - if err != nil { - return nil, err - } - - res := &Result{ - Key: key, - Value: value, - Proof: proof, - RootHash: root, - } - return res, nil -} - // Where selects a location for a key - Left, Right, or Middle type Where int diff --git a/proof_path.go b/proof_path.go index 690ce0ab3..19659500e 100644 --- a/proof_path.go +++ b/proof_path.go @@ -5,36 +5,6 @@ import ( "strings" ) -// pathWithLeaf is a path to a leaf node and the leaf node itself. -type pathWithLeaf struct { - Path PathToLeaf `json:"path"` - Leaf ProofLeafNode `json:"leaf"` -} - -func (pwl pathWithLeaf) String() string { - return pwl.StringIndented("") -} - -func (pwl pathWithLeaf) StringIndented(indent string) string { - return fmt.Sprintf(`pathWithLeaf{ -%s Path: %v -%s Leaf: %v -%s}`, - indent, pwl.Path.stringIndented(indent+" "), - indent, pwl.Leaf.stringIndented(indent+" "), - indent) -} - -// `computeRootHash` computes the root hash with leaf node. -// Does not verify the root hash. -func (pwl pathWithLeaf) computeRootHash() ([]byte, error) { - leafHash, err := pwl.Leaf.Hash() - if err != nil { - return nil, err - } - return pwl.Path.computeRootHash(leafHash) -} - //---------------------------------------- // PathToLeaf represents an inner path to a leaf node. @@ -65,40 +35,6 @@ func (pl PathToLeaf) stringIndented(indent string) string { indent) } -// `computeRootHash` computes the root hash assuming some leaf hash. -// Does not verify the root hash. -// Contract: Caller must verify that the roothash is correct by calling `.verify()`. -func (pl PathToLeaf) computeRootHash(leafHash []byte) ([]byte, error) { - var err error - hash := leafHash - for i := len(pl) - 1; i >= 0; i-- { - pin := pl[i] - hash, err = pin.Hash(hash) - if err != nil { - return nil, err - } - } - return hash, nil -} - -func (pl PathToLeaf) isLeftmost() bool { - for _, node := range pl { - if len(node.Left) > 0 { - return false - } - } - return true -} - -func (pl PathToLeaf) isRightmost() bool { - for _, node := range pl { - if len(node.Right) > 0 { - return false - } - } - return true -} - // returns -1 if invalid. func (pl PathToLeaf) Index() (idx int64) { for i, node := range pl { diff --git a/proof_range.go b/proof_range.go deleted file mode 100644 index 79db502b0..000000000 --- a/proof_range.go +++ /dev/null @@ -1,584 +0,0 @@ -package iavl - -import ( - "bytes" - "crypto/sha256" - "fmt" - "sort" - "strings" - - "github.com/pkg/errors" - - iavlproto "github.com/cosmos/iavl/proto" -) - -type RangeProof struct { - // You don't need the right path because - // it can be derived from what we have. - LeftPath PathToLeaf `json:"left_path"` - InnerNodes []PathToLeaf `json:"inner_nodes"` - Leaves []ProofLeafNode `json:"leaves"` - - // memoize - rootHash []byte // valid iff rootVerified is true - rootVerified bool - treeEnd bool // valid iff rootVerified is true -} - -// Keys returns all the keys in the RangeProof. NOTE: The keys here may -// include more keys than provided by tree.GetRangeWithProof or -// MutableTree.GetVersionedRangeWithProof. The keys returned there are only -// in the provided [startKey,endKey){limit} range. The keys returned here may -// include extra keys, such as: -// - the key before startKey if startKey is provided and doesn't exist; -// - the key after a queried key with tree.GetWithProof, when the key is absent. -func (proof *RangeProof) Keys() (keys [][]byte) { - if proof == nil { - return nil - } - for _, leaf := range proof.Leaves { - keys = append(keys, leaf.Key) - } - return keys -} - -// String returns a string representation of the proof. -func (proof *RangeProof) String() string { - if proof == nil { - return "" - } - return proof.StringIndented("") -} - -func (proof *RangeProof) StringIndented(indent string) string { - istrs := make([]string, 0, len(proof.InnerNodes)) - for _, ptl := range proof.InnerNodes { - istrs = append(istrs, ptl.stringIndented(indent+" ")) - } - lstrs := make([]string, 0, len(proof.Leaves)) - for _, leaf := range proof.Leaves { - lstrs = append(lstrs, leaf.stringIndented(indent+" ")) - } - return fmt.Sprintf(`RangeProof{ -%s LeftPath: %v -%s InnerNodes: -%s %v -%s Leaves: -%s %v -%s (rootVerified): %v -%s (rootHash): %X -%s (treeEnd): %v -%s}`, - indent, proof.LeftPath.stringIndented(indent+" "), - indent, - indent, strings.Join(istrs, "\n"+indent+" "), - indent, - indent, strings.Join(lstrs, "\n"+indent+" "), - indent, proof.rootVerified, - indent, proof.rootHash, - indent, proof.treeEnd, - indent) -} - -// The index of the first leaf (of the whole tree). -// Returns -1 if the proof is nil. -func (proof *RangeProof) LeftIndex() int64 { - if proof == nil { - return -1 - } - return proof.LeftPath.Index() -} - -// Also see LeftIndex(). -// Verify that a key has some value. -// Does not assume that the proof itself is valid, call Verify() first. -func (proof *RangeProof) VerifyItem(key, value []byte) error { - if proof == nil { - return errors.Wrap(ErrInvalidProof, "proof is nil") - } - - if !proof.rootVerified { - return errors.New("must call Verify(root) first") - } - - leaves := proof.Leaves - i := sort.Search(len(leaves), func(i int) bool { - return bytes.Compare(key, leaves[i].Key) <= 0 - }) - - if i >= len(leaves) || !bytes.Equal(leaves[i].Key, key) { - return errors.Wrap(ErrInvalidProof, "leaf key not found in proof") - } - - h := sha256.Sum256(value) - valueHash := h[:] - if !bytes.Equal(leaves[i].ValueHash, valueHash) { - return errors.Wrap(ErrInvalidProof, "leaf value hash not same") - } - - return nil -} - -// Verify that proof is valid absence proof for key. -// Does not assume that the proof itself is valid. -// For that, use Verify(root). -func (proof *RangeProof) VerifyAbsence(key []byte) error { - if proof == nil { - return errors.Wrap(ErrInvalidProof, "proof is nil") - } - if !proof.rootVerified { - return errors.New("must call Verify(root) first") - } - cmp := bytes.Compare(key, proof.Leaves[0].Key) - if cmp < 0 { - if proof.LeftPath.isLeftmost() { - return nil - } - return errors.New("absence not proved by left path") - - } else if cmp == 0 { - return errors.New("absence disproved via first item #0") - } - if len(proof.LeftPath) == 0 { - return nil // proof ok - } - if proof.LeftPath.isRightmost() { - return nil - } - - // See if any of the leaves are greater than key. - for i := 1; i < len(proof.Leaves); i++ { - leaf := proof.Leaves[i] - cmp := bytes.Compare(key, leaf.Key) - switch { - case cmp < 0: - return nil // proof ok - case cmp == 0: - return fmt.Errorf("absence disproved via item #%v", i) - default: - // if i == len(proof.Leaves)-1 { - // If last item, check whether - // it's the last item in the tree. - - // } - continue - } - } - - // It's still a valid proof if our last leaf is the rightmost child. - if proof.treeEnd { - return nil // OK! - } - - // It's not a valid absence proof. - if len(proof.Leaves) < 2 { - return errors.New("absence not proved by right leaf (need another leaf?)") - } - return errors.New("absence not proved by right leaf") - -} - -// Verify that proof is valid. -func (proof *RangeProof) Verify(root []byte) error { - if proof == nil { - return errors.Wrap(ErrInvalidProof, "proof is nil") - } - err := proof.verify(root) - return err -} - -func (proof *RangeProof) verify(root []byte) (err error) { - rootHash := proof.rootHash - if rootHash == nil { - derivedHash, err := proof.computeRootHash() - if err != nil { - return err - } - rootHash = derivedHash - } - if !bytes.Equal(rootHash, root) { - return errors.Wrap(ErrInvalidRoot, "root hash doesn't match") - } - proof.rootVerified = true - return nil -} - -// ComputeRootHash computes the root hash with leaves. -// Returns nil if error or proof is nil. -// Does not verify the root hash. -func (proof *RangeProof) ComputeRootHash() []byte { - if proof == nil { - return nil - } - - rootHash, _ := proof.computeRootHash() - - return rootHash -} - -func (proof *RangeProof) computeRootHash() (rootHash []byte, err error) { - rootHash, treeEnd, err := proof._computeRootHash() - if err == nil { - proof.rootHash = rootHash // memoize - proof.treeEnd = treeEnd // memoize - } - return rootHash, err -} - -func (proof *RangeProof) _computeRootHash() (rootHash []byte, treeEnd bool, err error) { - if len(proof.Leaves) == 0 { - return nil, false, errors.Wrap(ErrInvalidProof, "no leaves") - } - if len(proof.InnerNodes)+1 != len(proof.Leaves) { - return nil, false, errors.Wrap(ErrInvalidProof, "InnerNodes vs Leaves length mismatch, leaves should be 1 more.") //nolint:revive - } - - // Start from the left path and prove each leaf. - - // shared across recursive calls - var leaves = proof.Leaves - var innersq = proof.InnerNodes - var COMPUTEHASH func(path PathToLeaf, rightmost bool) (hash []byte, treeEnd bool, done bool, err error) - - // rightmost: is the root a rightmost child of the tree? - // treeEnd: true iff the last leaf is the last item of the tree. - // Returns the (possibly intermediate, possibly root) hash. - COMPUTEHASH = func(path PathToLeaf, rightmost bool) (hash []byte, treeEnd bool, done bool, err error) { - - // Pop next leaf. - nleaf, rleaves := leaves[0], leaves[1:] - leaves = rleaves - - // Compute hash. - hash, err = (pathWithLeaf{ - Path: path, - Leaf: nleaf, - }).computeRootHash() - - if err != nil { - return nil, treeEnd, false, err - } - - // If we don't have any leaves left, we're done. - if len(leaves) == 0 { - rightmost = rightmost && path.isRightmost() - return hash, rightmost, true, nil - } - - // Prove along path (until we run out of leaves). - for len(path) > 0 { - - // Drop the leaf-most (last-most) inner nodes from path - // until we encounter one with a left hash. - // We assume that the left side is already verified. - // rpath: rest of path - // lpath: last path item - rpath, lpath := path[:len(path)-1], path[len(path)-1] - path = rpath - if len(lpath.Right) == 0 { - continue - } - - // Pop next inners, a PathToLeaf (e.g. []ProofInnerNode). - inners, rinnersq := innersq[0], innersq[1:] - innersq = rinnersq - - // Recursively verify inners against remaining leaves. - derivedRoot, treeEnd, done, err := COMPUTEHASH(inners, rightmost && rpath.isRightmost()) - if err != nil { - return nil, treeEnd, false, errors.Wrap(err, "recursive COMPUTEHASH call") - } - - if !bytes.Equal(derivedRoot, lpath.Right) { - return nil, treeEnd, false, errors.Wrapf(ErrInvalidRoot, "intermediate root hash %X doesn't match, got %X", lpath.Right, derivedRoot) - } - - if done { - return hash, treeEnd, true, nil - } - } - - // We're not done yet (leaves left over). No error, not done either. - // Technically if rightmost, we know there's an error "left over leaves - // -- malformed proof", but we return that at the top level, below. - return hash, false, false, nil - } - - // Verify! - path := proof.LeftPath - rootHash, treeEnd, done, err := COMPUTEHASH(path, true) - if err != nil { - return nil, treeEnd, errors.Wrap(err, "root COMPUTEHASH call") - } else if !done { - return nil, treeEnd, errors.Wrap(ErrInvalidProof, "left over leaves -- malformed proof") - } - - // Ok! - return rootHash, treeEnd, nil -} - -// toProto converts the proof to a Protobuf representation, for use in ValueOp and AbsenceOp. -func (proof *RangeProof) ToProto() *iavlproto.RangeProof { - pb := &iavlproto.RangeProof{ - LeftPath: make([]*iavlproto.ProofInnerNode, 0, len(proof.LeftPath)), - InnerNodes: make([]*iavlproto.PathToLeaf, 0, len(proof.InnerNodes)), - Leaves: make([]*iavlproto.ProofLeafNode, 0, len(proof.Leaves)), - } - for _, inner := range proof.LeftPath { - pb.LeftPath = append(pb.LeftPath, inner.toProto()) - } - for _, path := range proof.InnerNodes { - pbPath := make([]*iavlproto.ProofInnerNode, 0, len(path)) - for _, inner := range path { - pbPath = append(pbPath, inner.toProto()) - } - pb.InnerNodes = append(pb.InnerNodes, &iavlproto.PathToLeaf{Inners: pbPath}) - } - for _, leaf := range proof.Leaves { - pb.Leaves = append(pb.Leaves, leaf.toProto()) - } - - return pb -} - -// rangeProofFromProto generates a RangeProof from a Protobuf RangeProof. -func RangeProofFromProto(pbProof *iavlproto.RangeProof) (RangeProof, error) { - proof := RangeProof{} - - for _, pbInner := range pbProof.LeftPath { - inner, err := proofInnerNodeFromProto(pbInner) - if err != nil { - return proof, err - } - proof.LeftPath = append(proof.LeftPath, inner) - } - - for _, pbPath := range pbProof.InnerNodes { - var path PathToLeaf // leave as nil unless populated, for Amino compatibility - if pbPath != nil { - for _, pbInner := range pbPath.Inners { - inner, err := proofInnerNodeFromProto(pbInner) - if err != nil { - return proof, err - } - path = append(path, inner) - } - } - proof.InnerNodes = append(proof.InnerNodes, path) - } - - for _, pbLeaf := range pbProof.Leaves { - leaf, err := proofLeafNodeFromProto(pbLeaf) - if err != nil { - return proof, err - } - proof.Leaves = append(proof.Leaves, leaf) - } - return proof, nil -} - -// keyStart is inclusive and keyEnd is exclusive. -// If keyStart or keyEnd don't exist, the leaf before keyStart -// or after keyEnd will also be included, but not be included in values. -// If keyEnd-1 exists, no later leaves will be included. -// If keyStart >= keyEnd and both not nil, errors out. -// Limit is never exceeded. - -func (t *ImmutableTree) getRangeProof(keyStart, keyEnd []byte, limit int) (proof *RangeProof, keys, values [][]byte, err error) { - if keyStart != nil && keyEnd != nil && bytes.Compare(keyStart, keyEnd) >= 0 { - return nil, nil, nil, fmt.Errorf("if keyStart and keyEnd are present, need keyStart < keyEnd") - } - if limit < 0 { - return nil, nil, nil, fmt.Errorf("limit must be greater or equal to 0 -- 0 means no limit") - } - if t.root == nil { - return nil, nil, nil, nil - } - - _, _, err = t.root.hashWithCount() // Ensure that all hashes are calculated. - if err != nil { - return nil, nil, nil, err - } - - // Get the first key/value pair proof, which provides us with the left key. - path, left, err := t.root.PathToLeaf(t, keyStart) - if err != nil { - // Key doesn't exist, but instead we got the prev leaf (or the - // first or last leaf), which provides proof of absence). - err = nil - } - startOK := keyStart == nil || bytes.Compare(keyStart, left.key) <= 0 - endOK := keyEnd == nil || bytes.Compare(left.key, keyEnd) < 0 - // If left.key is in range, add it to key/values. - if startOK && endOK { - keys = append(keys, left.key) // == keyStart - values = append(values, left.value) - } - - h := sha256.Sum256(left.value) - var leaves = []ProofLeafNode{ - { - Key: left.key, - ValueHash: h[:], - Version: left.version, - }, - } - - // 1: Special case if limit is 1. - // 2: Special case if keyEnd is left.key+1. - _stop := false - if limit == 1 { - _stop = true // case 1 - } else if keyEnd != nil && bytes.Compare(cpIncr(left.key), keyEnd) >= 0 { - _stop = true // case 2 - } - if _stop { - return &RangeProof{ - LeftPath: path, - Leaves: leaves, - }, keys, values, nil - } - - // Get the key after left.key to iterate from. - afterLeft := cpIncr(left.key) - - // Traverse starting from afterLeft, until keyEnd or the next leaf - // after keyEnd. - var allPathToLeafs = []PathToLeaf(nil) - var currentPathToLeaf = PathToLeaf(nil) - var leafCount = 1 // from left above. - var pathCount = 0 - - t.root.traverseInRange(t, afterLeft, nil, true, false, false, - func(node *Node) (stop bool) { - - // Track when we diverge from path, or when we've exhausted path, - // since the first allPathToLeafs shouldn't include it. - if pathCount != -1 { - if len(path) <= pathCount { - // We're done with path counting. - pathCount = -1 - } else { - pn := path[pathCount] - if pn.Height != node.height || - pn.Left != nil && !bytes.Equal(pn.Left, node.leftHash) || - pn.Right != nil && !bytes.Equal(pn.Right, node.rightHash) { - - // We've diverged, so start appending to allPathToLeaf. - pathCount = -1 - } else { - pathCount++ - } - } - } - - if node.height == 0 { // Leaf node - // Append all paths that we tracked so far to get to this leaf node. - allPathToLeafs = append(allPathToLeafs, currentPathToLeaf) - // Start a new one to track as we traverse the tree. - currentPathToLeaf = PathToLeaf(nil) - - h := sha256.Sum256(node.value) - leaves = append(leaves, ProofLeafNode{ - Key: node.key, - ValueHash: h[:], - Version: node.version, - }) - - leafCount++ - - // Maybe terminate because we found enough leaves. - if limit > 0 && limit <= leafCount { - return true - } - - // Terminate if we've found keyEnd or after. - if keyEnd != nil && bytes.Compare(node.key, keyEnd) >= 0 { - return true - } - - // Value is in range, append to keys and values. - keys = append(keys, node.key) - values = append(values, node.value) - - // Terminate if we've found keyEnd-1 or after. - // We don't want to fetch any leaves for it. - if keyEnd != nil && bytes.Compare(cpIncr(node.key), keyEnd) >= 0 { - return true - } - - } else if pathCount < 0 { // Inner node. - // Only store if the node is not stored in currentPathToLeaf already. We track if we are - // still going through PathToLeaf using pathCount. When pathCount goes to -1, we - // start storing the other paths we took to get to the leaf nodes. Also we skip - // storing the left node, since we are traversing the tree starting from the left - // and don't need to store unnecessary info as we only need to go down the right - // path. - currentPathToLeaf = append(currentPathToLeaf, ProofInnerNode{ - Height: node.height, - Size: node.size, - Version: node.version, - Left: nil, - Right: node.rightHash, - }) - } - return false - }, - ) - - return &RangeProof{ - LeftPath: path, - InnerNodes: allPathToLeafs, - Leaves: leaves, - }, keys, values, nil -} - -//---------------------------------------- - -// GetWithProof gets the value under the key if it exists, or returns nil. -// A proof of existence or absence is returned alongside the value. -func (t *ImmutableTree) GetWithProof(key []byte) (value []byte, proof *RangeProof, err error) { - proof, _, values, err := t.getRangeProof(key, cpIncr(key), 2) - if err != nil { - return nil, nil, errors.Wrap(err, "constructing range proof") - } - if len(values) > 0 && bytes.Equal(proof.Leaves[0].Key, key) { - return values[0], proof, nil - } - return nil, proof, nil -} - -// GetRangeWithProof gets key/value pairs within the specified range and limit. -func (t *ImmutableTree) GetRangeWithProof(startKey []byte, endKey []byte, limit int) (keys, values [][]byte, proof *RangeProof, err error) { - proof, keys, values, err = t.getRangeProof(startKey, endKey, limit) - return -} - -// GetVersionedWithProof gets the value under the key at the specified version -// if it exists, or returns nil. -func (tree *MutableTree) GetVersionedWithProof(key []byte, version int64) ([]byte, *RangeProof, error) { - if tree.VersionExists(version) { - t, err := tree.GetImmutable(version) - if err != nil { - return nil, nil, err - } - - return t.GetWithProof(key) - } - return nil, nil, errors.Wrap(ErrVersionDoesNotExist, "") -} - -// GetVersionedRangeWithProof gets key/value pairs within the specified range -// and limit. -func (tree *MutableTree) GetVersionedRangeWithProof(startKey, endKey []byte, limit int, version int64) ( - keys, values [][]byte, proof *RangeProof, err error) { - - if tree.VersionExists(version) { - t, err := tree.GetImmutable(version) - if err != nil { - return nil, nil, nil, err - } - return t.GetRangeWithProof(startKey, endKey, limit) - } - return nil, nil, nil, errors.Wrap(ErrVersionDoesNotExist, "") -} diff --git a/proof_test.go b/proof_test.go index 5e1c0ce48..0216eab5e 100644 --- a/proof_test.go +++ b/proof_test.go @@ -6,69 +6,47 @@ import ( "sort" "testing" - proto "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" iavlrand "github.com/cosmos/iavl/internal/rand" - iavlproto "github.com/cosmos/iavl/proto" ) -func TestTreeGetWithProof(t *testing.T) { - tree, err := getTestTree(0) - require.NoError(t, err) +func TestTreeGetProof(t *testing.T) { require := require.New(t) + tree, err := getTestTree(0) + require.NoError(err) for _, ikey := range []byte{0x11, 0x32, 0x50, 0x72, 0x99} { key := []byte{ikey} tree.Set(key, []byte(iavlrand.RandStr(8))) } - root, err := tree.WorkingHash() - require.NoError(err) key := []byte{0x32} - val, proof, err := tree.GetWithProof(key) + proof, err := tree.GetMembershipProof(key) require.NoError(err) - require.NotEmpty(val) require.NotNil(proof) - err = proof.VerifyItem(key, val) - require.Error(err, "%+v", err) // Verifying item before calling Verify(root) - - err = proof.Verify(root) - require.NoError(err, "%+v", err) - - err = proof.VerifyItem(key, val) + res, err := tree.VerifyMembership(proof, key) require.NoError(err, "%+v", err) + require.True(res) key = []byte{0x1} - val, proof, err = tree.GetWithProof(key) + proof, err = tree.GetNonMembershipProof(key) require.NoError(err) - require.Empty(val) require.NotNil(proof) - err = proof.VerifyAbsence(key) - require.Error(err, "%+v", err) // Verifying absence before calling Verify(root) - - err = proof.Verify(root) - require.NoError(err, "%+v", err) - - err = proof.VerifyAbsence(key) + res, err = tree.VerifyNonMembership(proof, key) require.NoError(err, "%+v", err) + require.True(res) } func TestTreeKeyExistsProof(t *testing.T) { tree, err := getTestTree(0) require.NoError(t, err) - root, err := tree.WorkingHash() - require.NoError(t, err) - // should get false for proof with nil root - proof, keys, values, err := tree.getRangeProof([]byte("foo"), nil, 1) - assert.Nil(t, proof) - assert.Error(t, proof.Verify(root)) - assert.Nil(t, keys) - assert.Nil(t, values) - assert.NoError(t, err) + // should get error + _, err = tree.GetProof([]byte("foo")) + assert.Error(t, err) // insert lots of info and store the bytes allkeys := make([][]byte, 200) @@ -79,199 +57,28 @@ func TestTreeKeyExistsProof(t *testing.T) { allkeys[i] = []byte(key) } sortByteSlices(allkeys) // Sort all keys - root, err = tree.WorkingHash() - require.NoError(t, err) // query random key fails - proof, _, _, err = tree.getRangeProof([]byte("foo"), nil, 2) - assert.Nil(t, err) - assert.Nil(t, proof.Verify(root)) - assert.Nil(t, proof.VerifyAbsence([]byte("foo")), proof.String()) - - // query min key fails - proof, _, _, err = tree.getRangeProof([]byte{0x00}, []byte{0x01}, 2) - assert.Nil(t, err) - assert.Nil(t, proof.Verify(root)) - assert.Nil(t, proof.VerifyAbsence([]byte{0x00})) + _, err = tree.GetMembershipProof([]byte("foo")) + require.Error(t, err) // valid proof for real keys - for i, key := range allkeys { - var keys, values [][]byte - proof, keys, values, err = tree.getRangeProof(key, nil, 2) - require.Nil(t, err) - + for _, key := range allkeys { + proof, err := tree.GetMembershipProof(key) + require.NoError(t, err) require.Equal(t, append([]byte("value_for_"), key...), - values[0], + proof.GetExist().Value, ) - require.Equal(t, key, keys[0]) - require.Nil(t, proof.Verify(root)) - require.Nil(t, proof.VerifyAbsence(cpIncr(key))) - require.Equal(t, 1, len(keys), proof.String()) - require.Equal(t, 1, len(values), proof.String()) - if i < len(allkeys)-1 { - if i < len(allkeys)-2 { - // No last item... not a proof of absence of large key. - require.NotNil(t, proof.VerifyAbsence(bytes.Repeat([]byte{0xFF}, 20)), proof.String()) - } else { - // Last item is included. - require.Nil(t, proof.VerifyAbsence(bytes.Repeat([]byte{0xFF}, 20))) - } - } else { - // last item of tree... valid proof of absence of large key. - require.Nil(t, proof.VerifyAbsence(bytes.Repeat([]byte{0xFF}, 20))) - } - } - // TODO: Test with single value in tree. -} - -func TestTreeKeyInRangeProofs(t *testing.T) { - tree, err := getTestTree(0) - require.NoError(t, err) - require := require.New(t) - keys := []byte{0x0a, 0x11, 0x2e, 0x32, 0x50, 0x72, 0x99, 0xa1, 0xe4, 0xf7} // 10 total. - for _, ikey := range keys { - key := []byte{ikey} - tree.Set(key, key) - } - root, err := tree.WorkingHash() - require.NoError(err) - - // For spacing: - T := 10 - // disable: don't use underscores in Go names; var nil______ should be nil (golint) - // nolint - nil______ := []byte(nil) - cases := []struct { // nolint:maligned - start byte - end byte - pkeys []byte // proof keys, one byte per key. - vals []byte // keys and values, one byte per key. - lidx int64 // proof left index (index of first proof key). - err bool // does error - }{ - {start: 0x0a, end: 0xf7, pkeys: keys[0:T], vals: keys[0:9], lidx: 0}, // #0 - {start: 0x0a, end: 0xf8, pkeys: keys[0:T], vals: keys[0:T], lidx: 0}, // #1 - {start: 0x00, end: 0xff, pkeys: keys[0:T], vals: keys[0:T], lidx: 0}, // #2 - {start: 0x14, end: 0xe4, pkeys: keys[1:9], vals: keys[2:8], lidx: 1}, // #3 - {start: 0x14, end: 0xe5, pkeys: keys[1:9], vals: keys[2:9], lidx: 1}, // #4 - {start: 0x14, end: 0xe6, pkeys: keys[1:T], vals: keys[2:9], lidx: 1}, // #5 - {start: 0x14, end: 0xf1, pkeys: keys[1:T], vals: keys[2:9], lidx: 1}, // #6 - {start: 0x14, end: 0xf7, pkeys: keys[1:T], vals: keys[2:9], lidx: 1}, // #7 - {start: 0x14, end: 0xff, pkeys: keys[1:T], vals: keys[2:T], lidx: 1}, // #8 - {start: 0x2e, end: 0x31, pkeys: keys[2:4], vals: keys[2:3], lidx: 2}, // #9 - {start: 0x2e, end: 0x32, pkeys: keys[2:4], vals: keys[2:3], lidx: 2}, // #10 - {start: 0x2f, end: 0x32, pkeys: keys[2:4], vals: nil______, lidx: 2}, // #11 - {start: 0x2e, end: 0x31, pkeys: keys[2:4], vals: keys[2:3], lidx: 2}, // #12 - {start: 0x2e, end: 0x2f, pkeys: keys[2:3], vals: keys[2:3], lidx: 2}, // #13 - {start: 0x12, end: 0x31, pkeys: keys[1:4], vals: keys[2:3], lidx: 1}, // #14 - {start: 0xf8, end: 0xff, pkeys: keys[9:T], vals: nil______, lidx: 9}, // #15 - {start: 0x12, end: 0x20, pkeys: keys[1:3], vals: nil______, lidx: 1}, // #16 - {start: 0x00, end: 0x09, pkeys: keys[0:1], vals: nil______, lidx: 0}, // #17 - {start: 0xf7, end: 0x00, err: true}, // #18 - {start: 0xf8, end: 0x00, err: true}, // #19 - {start: 0x10, end: 0x10, err: true}, // #20 - {start: 0x12, end: 0x12, err: true}, // #21 - {start: 0xff, end: 0xf7, err: true}, // #22 - } - - // fmt.Println("PRINT TREE") - // printNode(tree.ndb, tree.root, 0) - // fmt.Println("PRINT TREE END") - - for i, c := range cases { - t.Logf("case %v", i) - start := []byte{c.start} - end := []byte{c.end} - - // Compute range proof. - keys, values, proof, err := tree.GetRangeWithProof(start, end, 0) - - if c.err { - require.Error(err, "%+v", err) - } else { - require.NoError(err, "%+v", err) - require.Equal(c.pkeys, flatten(proof.Keys())) - require.Equal(c.vals, flatten(keys)) - require.Equal(c.vals, flatten(values)) - require.Equal(c.lidx, proof.LeftIndex()) - - // Verify that proof is valid. - err = proof.Verify(root) - require.NoError(err, "%+v", err) - verifyProof(t, proof, root) - - // Verify each value of pkeys. - for _, key := range c.pkeys { - err := proof.VerifyItem([]byte{key}, []byte{key}) - require.NoError(err) - } - - // Verify each value of vals. - for _, key := range c.vals { - err := proof.VerifyItem([]byte{key}, []byte{key}) - require.NoError(err) - } - } - - } -} - -func encodeProof(proof *RangeProof) ([]byte, error) { - return proto.Marshal(proof.ToProto()) -} - -func decodeProof(bz []byte) (*RangeProof, error) { - proofOp := &iavlproto.RangeProof{} - err := proto.Unmarshal(bz, proofOp) - if err != nil { - return nil, err - } - proof, err := RangeProofFromProto(proofOp) - return &proof, err -} - -func verifyProof(t *testing.T, proof *RangeProof, root []byte) { - // Proof must verify. - require.NoError(t, proof.Verify(root)) - - // Write/Read then verify. - proofBytes, err := encodeProof(proof) - require.NoError(t, err) - _, err = decodeProof(proofBytes) - require.NoError(t, err) - - // Random mutations must not verify - for i := 0; i < 1e4; i++ { - badProofBytes := MutateByteSlice(proofBytes) - badProof, err := decodeProof(badProofBytes) - if err != nil { - continue // couldn't even decode. - } - // re-encode to make sure it's actually different. - badProofBytes2, err := encodeProof(badProof) - if bytes.Equal(proofBytes, badProofBytes2) { - continue // didn't mutate successfully. - } - // may be invalid... errors are okay - if err == nil { - assert.Errorf(t, badProof.Verify(root), - "Proof was still valid after a random mutation:\n%X\n%X", - proofBytes, badProofBytes) - } + res, err := tree.VerifyMembership(proof, key) + require.NoError(t, err) + require.True(t, res) } } //---------------------------------------- -func flatten(bzz [][]byte) (res []byte) { - for _, bz := range bzz { - res = append(res, bz...) - } - return res -} - // Contract: !bytes.Equal(input, output) && len(input) >= len(output) func MutateByteSlice(bytez []byte) []byte { // If bytez is empty, panic diff --git a/proto/iavl/proof.proto b/proto/iavl/proof.proto deleted file mode 100644 index dc94c2d35..000000000 --- a/proto/iavl/proof.proto +++ /dev/null @@ -1,42 +0,0 @@ -syntax = "proto3"; -package iavl; - -option go_package = "proto"; - -// ValueOp is a Protobuf representation of iavl.ValueOp. -message ValueOp { - RangeProof proof = 1; -} - -// AbsenceOp is a Protobuf representation of iavl.AbsenceOp. -message AbsenceOp { - RangeProof proof = 1; -} - -// RangeProof is a Protobuf representation of iavl.RangeProof. -message RangeProof { - repeated ProofInnerNode left_path = 1; - repeated PathToLeaf inner_nodes = 2; - repeated ProofLeafNode leaves = 3; -} - -// PathToLeaf is a Protobuf representation of iavl.PathToLeaf. -message PathToLeaf { - repeated ProofInnerNode inners = 1; -} - -// ProofInnerNode is a Protobuf representation of iavl.ProofInnerNode. -message ProofInnerNode { - sint32 height = 1; - int64 size = 2; - int64 version = 3; - bytes left = 4; - bytes right = 5; -} - -// ProofLeafNode is a Protobuf representation of iavl.ProofInnerNode. -message ProofLeafNode { - bytes key = 1; - bytes value_hash = 2; - int64 version = 3; -} diff --git a/proto/proof.pb.go b/proto/proof.pb.go deleted file mode 100644 index 35bbbff0a..000000000 --- a/proto/proof.pb.go +++ /dev/null @@ -1,1618 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: iavl/proof.proto - -package proto - -import ( - fmt "fmt" - proto "github.com/gogo/protobuf/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -// ValueOp is a Protobuf representation of iavl.ValueOp. -type ValueOp struct { - Proof *RangeProof `protobuf:"bytes,1,opt,name=proof,proto3" json:"proof,omitempty"` -} - -func (m *ValueOp) Reset() { *m = ValueOp{} } -func (m *ValueOp) String() string { return proto.CompactTextString(m) } -func (*ValueOp) ProtoMessage() {} -func (*ValueOp) Descriptor() ([]byte, []int) { - return fileDescriptor_92b2514a05d2a2db, []int{0} -} -func (m *ValueOp) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ValueOp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ValueOp.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ValueOp) XXX_Merge(src proto.Message) { - xxx_messageInfo_ValueOp.Merge(m, src) -} -func (m *ValueOp) XXX_Size() int { - return m.Size() -} -func (m *ValueOp) XXX_DiscardUnknown() { - xxx_messageInfo_ValueOp.DiscardUnknown(m) -} - -var xxx_messageInfo_ValueOp proto.InternalMessageInfo - -func (m *ValueOp) GetProof() *RangeProof { - if m != nil { - return m.Proof - } - return nil -} - -// AbsenceOp is a Protobuf representation of iavl.AbsenceOp. -type AbsenceOp struct { - Proof *RangeProof `protobuf:"bytes,1,opt,name=proof,proto3" json:"proof,omitempty"` -} - -func (m *AbsenceOp) Reset() { *m = AbsenceOp{} } -func (m *AbsenceOp) String() string { return proto.CompactTextString(m) } -func (*AbsenceOp) ProtoMessage() {} -func (*AbsenceOp) Descriptor() ([]byte, []int) { - return fileDescriptor_92b2514a05d2a2db, []int{1} -} -func (m *AbsenceOp) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *AbsenceOp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_AbsenceOp.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *AbsenceOp) XXX_Merge(src proto.Message) { - xxx_messageInfo_AbsenceOp.Merge(m, src) -} -func (m *AbsenceOp) XXX_Size() int { - return m.Size() -} -func (m *AbsenceOp) XXX_DiscardUnknown() { - xxx_messageInfo_AbsenceOp.DiscardUnknown(m) -} - -var xxx_messageInfo_AbsenceOp proto.InternalMessageInfo - -func (m *AbsenceOp) GetProof() *RangeProof { - if m != nil { - return m.Proof - } - return nil -} - -// RangeProof is a Protobuf representation of iavl.RangeProof. -type RangeProof struct { - LeftPath []*ProofInnerNode `protobuf:"bytes,1,rep,name=left_path,json=leftPath,proto3" json:"left_path,omitempty"` - InnerNodes []*PathToLeaf `protobuf:"bytes,2,rep,name=inner_nodes,json=innerNodes,proto3" json:"inner_nodes,omitempty"` - Leaves []*ProofLeafNode `protobuf:"bytes,3,rep,name=leaves,proto3" json:"leaves,omitempty"` -} - -func (m *RangeProof) Reset() { *m = RangeProof{} } -func (m *RangeProof) String() string { return proto.CompactTextString(m) } -func (*RangeProof) ProtoMessage() {} -func (*RangeProof) Descriptor() ([]byte, []int) { - return fileDescriptor_92b2514a05d2a2db, []int{2} -} -func (m *RangeProof) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *RangeProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_RangeProof.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *RangeProof) XXX_Merge(src proto.Message) { - xxx_messageInfo_RangeProof.Merge(m, src) -} -func (m *RangeProof) XXX_Size() int { - return m.Size() -} -func (m *RangeProof) XXX_DiscardUnknown() { - xxx_messageInfo_RangeProof.DiscardUnknown(m) -} - -var xxx_messageInfo_RangeProof proto.InternalMessageInfo - -func (m *RangeProof) GetLeftPath() []*ProofInnerNode { - if m != nil { - return m.LeftPath - } - return nil -} - -func (m *RangeProof) GetInnerNodes() []*PathToLeaf { - if m != nil { - return m.InnerNodes - } - return nil -} - -func (m *RangeProof) GetLeaves() []*ProofLeafNode { - if m != nil { - return m.Leaves - } - return nil -} - -// PathToLeaf is a Protobuf representation of iavl.PathToLeaf. -type PathToLeaf struct { - Inners []*ProofInnerNode `protobuf:"bytes,1,rep,name=inners,proto3" json:"inners,omitempty"` -} - -func (m *PathToLeaf) Reset() { *m = PathToLeaf{} } -func (m *PathToLeaf) String() string { return proto.CompactTextString(m) } -func (*PathToLeaf) ProtoMessage() {} -func (*PathToLeaf) Descriptor() ([]byte, []int) { - return fileDescriptor_92b2514a05d2a2db, []int{3} -} -func (m *PathToLeaf) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PathToLeaf) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_PathToLeaf.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *PathToLeaf) XXX_Merge(src proto.Message) { - xxx_messageInfo_PathToLeaf.Merge(m, src) -} -func (m *PathToLeaf) XXX_Size() int { - return m.Size() -} -func (m *PathToLeaf) XXX_DiscardUnknown() { - xxx_messageInfo_PathToLeaf.DiscardUnknown(m) -} - -var xxx_messageInfo_PathToLeaf proto.InternalMessageInfo - -func (m *PathToLeaf) GetInners() []*ProofInnerNode { - if m != nil { - return m.Inners - } - return nil -} - -// ProofInnerNode is a Protobuf representation of iavl.ProofInnerNode. -type ProofInnerNode struct { - Height int32 `protobuf:"zigzag32,1,opt,name=height,proto3" json:"height,omitempty"` - Size_ int64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` - Version int64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"` - Left []byte `protobuf:"bytes,4,opt,name=left,proto3" json:"left,omitempty"` - Right []byte `protobuf:"bytes,5,opt,name=right,proto3" json:"right,omitempty"` -} - -func (m *ProofInnerNode) Reset() { *m = ProofInnerNode{} } -func (m *ProofInnerNode) String() string { return proto.CompactTextString(m) } -func (*ProofInnerNode) ProtoMessage() {} -func (*ProofInnerNode) Descriptor() ([]byte, []int) { - return fileDescriptor_92b2514a05d2a2db, []int{4} -} -func (m *ProofInnerNode) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ProofInnerNode) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ProofInnerNode.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ProofInnerNode) XXX_Merge(src proto.Message) { - xxx_messageInfo_ProofInnerNode.Merge(m, src) -} -func (m *ProofInnerNode) XXX_Size() int { - return m.Size() -} -func (m *ProofInnerNode) XXX_DiscardUnknown() { - xxx_messageInfo_ProofInnerNode.DiscardUnknown(m) -} - -var xxx_messageInfo_ProofInnerNode proto.InternalMessageInfo - -func (m *ProofInnerNode) GetHeight() int32 { - if m != nil { - return m.Height - } - return 0 -} - -func (m *ProofInnerNode) GetSize_() int64 { - if m != nil { - return m.Size_ - } - return 0 -} - -func (m *ProofInnerNode) GetVersion() int64 { - if m != nil { - return m.Version - } - return 0 -} - -func (m *ProofInnerNode) GetLeft() []byte { - if m != nil { - return m.Left - } - return nil -} - -func (m *ProofInnerNode) GetRight() []byte { - if m != nil { - return m.Right - } - return nil -} - -// ProofLeafNode is a Protobuf representation of iavl.ProofInnerNode. -type ProofLeafNode struct { - Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - ValueHash []byte `protobuf:"bytes,2,opt,name=value_hash,json=valueHash,proto3" json:"value_hash,omitempty"` - Version int64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"` -} - -func (m *ProofLeafNode) Reset() { *m = ProofLeafNode{} } -func (m *ProofLeafNode) String() string { return proto.CompactTextString(m) } -func (*ProofLeafNode) ProtoMessage() {} -func (*ProofLeafNode) Descriptor() ([]byte, []int) { - return fileDescriptor_92b2514a05d2a2db, []int{5} -} -func (m *ProofLeafNode) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ProofLeafNode) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ProofLeafNode.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ProofLeafNode) XXX_Merge(src proto.Message) { - xxx_messageInfo_ProofLeafNode.Merge(m, src) -} -func (m *ProofLeafNode) XXX_Size() int { - return m.Size() -} -func (m *ProofLeafNode) XXX_DiscardUnknown() { - xxx_messageInfo_ProofLeafNode.DiscardUnknown(m) -} - -var xxx_messageInfo_ProofLeafNode proto.InternalMessageInfo - -func (m *ProofLeafNode) GetKey() []byte { - if m != nil { - return m.Key - } - return nil -} - -func (m *ProofLeafNode) GetValueHash() []byte { - if m != nil { - return m.ValueHash - } - return nil -} - -func (m *ProofLeafNode) GetVersion() int64 { - if m != nil { - return m.Version - } - return 0 -} - -func init() { - proto.RegisterType((*ValueOp)(nil), "iavl.ValueOp") - proto.RegisterType((*AbsenceOp)(nil), "iavl.AbsenceOp") - proto.RegisterType((*RangeProof)(nil), "iavl.RangeProof") - proto.RegisterType((*PathToLeaf)(nil), "iavl.PathToLeaf") - proto.RegisterType((*ProofInnerNode)(nil), "iavl.ProofInnerNode") - proto.RegisterType((*ProofLeafNode)(nil), "iavl.ProofLeafNode") -} - -func init() { proto.RegisterFile("iavl/proof.proto", fileDescriptor_92b2514a05d2a2db) } - -var fileDescriptor_92b2514a05d2a2db = []byte{ - // 373 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xb1, 0x4e, 0xe3, 0x40, - 0x10, 0x86, 0xb3, 0x71, 0xec, 0x5c, 0x26, 0xb9, 0x53, 0x6e, 0x2f, 0x3a, 0x6d, 0x73, 0x3e, 0xcb, - 0x05, 0xb2, 0x04, 0x0a, 0x4a, 0xd2, 0xd1, 0x41, 0x05, 0x12, 0x82, 0x68, 0x85, 0x28, 0xd2, 0x44, - 0x1b, 0xb2, 0x89, 0x2d, 0x2c, 0xaf, 0xe5, 0x35, 0x96, 0xa0, 0xe2, 0x11, 0x78, 0x03, 0x5e, 0x87, - 0x32, 0x25, 0x25, 0x4a, 0x5e, 0x04, 0xed, 0xc4, 0x51, 0x48, 0x01, 0x12, 0x95, 0x67, 0xfe, 0xf9, - 0x66, 0xfe, 0xf1, 0xd8, 0xd0, 0x8e, 0x44, 0x11, 0x1f, 0xa6, 0x99, 0x52, 0xb3, 0x6e, 0x9a, 0xa9, - 0x5c, 0xd1, 0x9a, 0x51, 0xfc, 0x1e, 0xd4, 0xaf, 0x45, 0x7c, 0x27, 0x2f, 0x53, 0xba, 0x07, 0x36, - 0xd6, 0x19, 0xf1, 0x48, 0xd0, 0xec, 0xb7, 0xbb, 0x06, 0xe8, 0x72, 0x91, 0xcc, 0xe5, 0xd0, 0xe8, - 0x7c, 0x5d, 0xf6, 0x07, 0xd0, 0x38, 0x9e, 0x68, 0x99, 0xdc, 0x7c, 0xa7, 0xe9, 0x99, 0x00, 0x6c, - 0x55, 0xda, 0x83, 0x46, 0x2c, 0x67, 0xf9, 0x38, 0x15, 0x79, 0xc8, 0x88, 0x67, 0x05, 0xcd, 0x7e, - 0x67, 0xdd, 0x8a, 0xf5, 0xb3, 0x24, 0x91, 0xd9, 0x85, 0x9a, 0x4a, 0xfe, 0xc3, 0x60, 0x43, 0x91, - 0x87, 0xb4, 0x07, 0xcd, 0xc8, 0xc8, 0xe3, 0x44, 0x4d, 0xa5, 0x66, 0x55, 0x6c, 0x2a, 0xfd, 0x0c, - 0x70, 0xa5, 0xce, 0xa5, 0x98, 0x71, 0x88, 0x36, 0xbd, 0x9a, 0xee, 0x83, 0x13, 0x4b, 0x51, 0x48, - 0xcd, 0x2c, 0xa4, 0xff, 0x7c, 0xb0, 0x30, 0x30, 0x3a, 0x94, 0x88, 0x7f, 0x04, 0xb0, 0x1d, 0x43, - 0x0f, 0xc0, 0xc1, 0x41, 0xfa, 0xcb, 0xed, 0x4a, 0xc6, 0x7f, 0x24, 0xf0, 0x6b, 0xb7, 0x44, 0xff, - 0x82, 0x13, 0xca, 0x68, 0x1e, 0xe6, 0x78, 0x99, 0xdf, 0xbc, 0xcc, 0x28, 0x85, 0x9a, 0x8e, 0x1e, - 0x24, 0xab, 0x7a, 0x24, 0xb0, 0x38, 0xc6, 0x94, 0x41, 0xbd, 0x90, 0x99, 0x8e, 0x54, 0xc2, 0x2c, - 0x94, 0x37, 0xa9, 0xa1, 0xcd, 0x01, 0x58, 0xcd, 0x23, 0x41, 0x8b, 0x63, 0x4c, 0x3b, 0x60, 0x67, - 0x38, 0xd8, 0x46, 0x71, 0x9d, 0xf8, 0x23, 0xf8, 0xb9, 0xf3, 0x5e, 0xb4, 0x0d, 0xd6, 0xad, 0xbc, - 0x47, 0xf7, 0x16, 0x37, 0x21, 0xfd, 0x07, 0x50, 0x98, 0x6f, 0x3d, 0x0e, 0x85, 0x0e, 0x71, 0x81, - 0x16, 0x6f, 0xa0, 0x72, 0x2a, 0x74, 0xf8, 0xf9, 0x16, 0x27, 0xff, 0x5f, 0x96, 0x2e, 0x59, 0x2c, - 0x5d, 0xf2, 0xb6, 0x74, 0xc9, 0xd3, 0xca, 0xad, 0x2c, 0x56, 0x6e, 0xe5, 0x75, 0xe5, 0x56, 0x46, - 0x36, 0xfe, 0x4b, 0x13, 0x07, 0x1f, 0x83, 0xf7, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x60, 0x25, - 0x89, 0x66, 0x02, 0x00, 0x00, -} - -func (m *ValueOp) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ValueOp) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ValueOp) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Proof != nil { - { - size, err := m.Proof.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProof(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *AbsenceOp) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *AbsenceOp) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *AbsenceOp) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Proof != nil { - { - size, err := m.Proof.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProof(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *RangeProof) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *RangeProof) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *RangeProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Leaves) > 0 { - for iNdEx := len(m.Leaves) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Leaves[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProof(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - } - if len(m.InnerNodes) > 0 { - for iNdEx := len(m.InnerNodes) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.InnerNodes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProof(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - if len(m.LeftPath) > 0 { - for iNdEx := len(m.LeftPath) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.LeftPath[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProof(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *PathToLeaf) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *PathToLeaf) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PathToLeaf) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Inners) > 0 { - for iNdEx := len(m.Inners) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Inners[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintProof(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *ProofInnerNode) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ProofInnerNode) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ProofInnerNode) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Right) > 0 { - i -= len(m.Right) - copy(dAtA[i:], m.Right) - i = encodeVarintProof(dAtA, i, uint64(len(m.Right))) - i-- - dAtA[i] = 0x2a - } - if len(m.Left) > 0 { - i -= len(m.Left) - copy(dAtA[i:], m.Left) - i = encodeVarintProof(dAtA, i, uint64(len(m.Left))) - i-- - dAtA[i] = 0x22 - } - if m.Version != 0 { - i = encodeVarintProof(dAtA, i, uint64(m.Version)) - i-- - dAtA[i] = 0x18 - } - if m.Size_ != 0 { - i = encodeVarintProof(dAtA, i, uint64(m.Size_)) - i-- - dAtA[i] = 0x10 - } - if m.Height != 0 { - i = encodeVarintProof(dAtA, i, uint64((uint32(m.Height)<<1)^uint32((m.Height>>31)))) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *ProofLeafNode) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ProofLeafNode) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ProofLeafNode) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Version != 0 { - i = encodeVarintProof(dAtA, i, uint64(m.Version)) - i-- - dAtA[i] = 0x18 - } - if len(m.ValueHash) > 0 { - i -= len(m.ValueHash) - copy(dAtA[i:], m.ValueHash) - i = encodeVarintProof(dAtA, i, uint64(len(m.ValueHash))) - i-- - dAtA[i] = 0x12 - } - if len(m.Key) > 0 { - i -= len(m.Key) - copy(dAtA[i:], m.Key) - i = encodeVarintProof(dAtA, i, uint64(len(m.Key))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintProof(dAtA []byte, offset int, v uint64) int { - offset -= sovProof(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *ValueOp) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Proof != nil { - l = m.Proof.Size() - n += 1 + l + sovProof(uint64(l)) - } - return n -} - -func (m *AbsenceOp) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Proof != nil { - l = m.Proof.Size() - n += 1 + l + sovProof(uint64(l)) - } - return n -} - -func (m *RangeProof) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.LeftPath) > 0 { - for _, e := range m.LeftPath { - l = e.Size() - n += 1 + l + sovProof(uint64(l)) - } - } - if len(m.InnerNodes) > 0 { - for _, e := range m.InnerNodes { - l = e.Size() - n += 1 + l + sovProof(uint64(l)) - } - } - if len(m.Leaves) > 0 { - for _, e := range m.Leaves { - l = e.Size() - n += 1 + l + sovProof(uint64(l)) - } - } - return n -} - -func (m *PathToLeaf) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Inners) > 0 { - for _, e := range m.Inners { - l = e.Size() - n += 1 + l + sovProof(uint64(l)) - } - } - return n -} - -func (m *ProofInnerNode) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Height != 0 { - n += 1 + sozProof(uint64(m.Height)) - } - if m.Size_ != 0 { - n += 1 + sovProof(uint64(m.Size_)) - } - if m.Version != 0 { - n += 1 + sovProof(uint64(m.Version)) - } - l = len(m.Left) - if l > 0 { - n += 1 + l + sovProof(uint64(l)) - } - l = len(m.Right) - if l > 0 { - n += 1 + l + sovProof(uint64(l)) - } - return n -} - -func (m *ProofLeafNode) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Key) - if l > 0 { - n += 1 + l + sovProof(uint64(l)) - } - l = len(m.ValueHash) - if l > 0 { - n += 1 + l + sovProof(uint64(l)) - } - if m.Version != 0 { - n += 1 + sovProof(uint64(m.Version)) - } - return n -} - -func sovProof(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozProof(x uint64) (n int) { - return sovProof(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *ValueOp) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ValueOp: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ValueOp: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProof - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProof - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Proof == nil { - m.Proof = &RangeProof{} - } - if err := m.Proof.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProof(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *AbsenceOp) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: AbsenceOp: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: AbsenceOp: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProof - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProof - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Proof == nil { - m.Proof = &RangeProof{} - } - if err := m.Proof.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProof(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *RangeProof) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: RangeProof: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: RangeProof: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LeftPath", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProof - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProof - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.LeftPath = append(m.LeftPath, &ProofInnerNode{}) - if err := m.LeftPath[len(m.LeftPath)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field InnerNodes", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProof - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProof - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.InnerNodes = append(m.InnerNodes, &PathToLeaf{}) - if err := m.InnerNodes[len(m.InnerNodes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Leaves", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProof - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProof - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Leaves = append(m.Leaves, &ProofLeafNode{}) - if err := m.Leaves[len(m.Leaves)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProof(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *PathToLeaf) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: PathToLeaf: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: PathToLeaf: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Inners", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthProof - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthProof - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Inners = append(m.Inners, &ProofInnerNode{}) - if err := m.Inners[len(m.Inners)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProof(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ProofInnerNode) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ProofInnerNode: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ProofInnerNode: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) - } - var v int32 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int32(b&0x7F) << shift - if b < 0x80 { - break - } - } - v = int32((uint32(v) >> 1) ^ uint32(((v&1)<<31)>>31)) - m.Height = v - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType) - } - m.Size_ = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Size_ |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) - } - m.Version = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Version |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Left", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProof - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProof - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Left = append(m.Left[:0], dAtA[iNdEx:postIndex]...) - if m.Left == nil { - m.Left = []byte{} - } - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Right", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProof - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProof - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Right = append(m.Right[:0], dAtA[iNdEx:postIndex]...) - if m.Right == nil { - m.Right = []byte{} - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProof(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ProofLeafNode) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ProofLeafNode: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ProofLeafNode: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProof - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProof - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) - if m.Key == nil { - m.Key = []byte{} - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ValueHash", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthProof - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthProof - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ValueHash = append(m.ValueHash[:0], dAtA[iNdEx:postIndex]...) - if m.ValueHash == nil { - m.ValueHash = []byte{} - } - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) - } - m.Version = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProof - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Version |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipProof(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthProof - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipProof(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowProof - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowProof - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowProof - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthProof - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupProof - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthProof - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthProof = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowProof = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupProof = fmt.Errorf("proto: unexpected end of group") -) diff --git a/tree_test.go b/tree_test.go index c02b0de1a..12b82d29e 100644 --- a/tree_test.go +++ b/tree_test.go @@ -872,9 +872,7 @@ func TestVersionedTreeErrors(t *testing.T) { // Same thing with proof. We get an error because a proof couldn't be // constructed. - val, proof, err := tree.GetVersionedWithProof([]byte("key"), 404) - require.Nil(val) - require.Empty(proof) + _, err = tree.GetVersionedProof([]byte("key"), 404) require.Error(err) } @@ -1214,38 +1212,47 @@ func TestVersionedTreeProofs(t *testing.T) { require.NoError(err) require.NotEqual(root2, root3) - val, proof, err := tree.GetVersionedWithProof([]byte("k2"), 1) + iTree, err := tree.GetImmutable(1) require.NoError(err) - require.EqualValues(val, []byte("v1")) - require.NoError(proof.Verify(root1), proof.String()) - require.NoError(proof.VerifyItem([]byte("k2"), val)) - val, proof, err = tree.GetVersionedWithProof([]byte("k4"), 1) + proof, err := tree.GetVersionedProof([]byte("k2"), 1) require.NoError(err) - require.Nil(val) - require.NoError(proof.Verify(root1)) - require.NoError(proof.VerifyAbsence([]byte("k4"))) + require.EqualValues(proof.GetExist().Value, []byte("v1")) + res, err := iTree.VerifyProof(proof, []byte("k2")) + require.NoError(err) + require.True(res) - val, proof, err = tree.GetVersionedWithProof([]byte("k2"), 2) + proof, err = tree.GetVersionedProof([]byte("k4"), 1) + require.NoError(err) + require.EqualValues(proof.GetNonexist().Key, []byte("k4")) + res, err = iTree.VerifyProof(proof, []byte("k4")) require.NoError(err) - require.EqualValues(val, []byte("v2")) - require.NoError(proof.Verify(root2), proof.String()) - require.NoError(proof.VerifyItem([]byte("k2"), val)) + require.True(res) - val, proof, err = tree.GetVersionedWithProof([]byte("k1"), 2) + iTree, err = tree.GetImmutable(2) require.NoError(err) - require.EqualValues(val, []byte("v1")) - require.NoError(proof.Verify(root2)) - require.NoError(proof.VerifyItem([]byte("k1"), val)) + proof, err = tree.GetVersionedProof([]byte("k2"), 2) + require.NoError(err) + require.EqualValues(proof.GetExist().Value, []byte("v2")) + res, err = iTree.VerifyProof(proof, []byte("k2")) + require.NoError(err) + require.True(res) - val, proof, err = tree.GetVersionedWithProof([]byte("k2"), 3) + proof, err = tree.GetVersionedProof([]byte("k1"), 2) + require.NoError(err) + require.EqualValues(proof.GetExist().Value, []byte("v1")) + res, err = iTree.VerifyProof(proof, []byte("k1")) + require.NoError(err) + require.True(res) + iTree, err = tree.GetImmutable(3) require.NoError(err) - require.Nil(val) - require.NoError(proof.Verify(root3)) - require.NoError(proof.VerifyAbsence([]byte("k2"))) - require.Error(proof.Verify(root1)) - require.Error(proof.Verify(root2)) + proof, err = tree.GetVersionedProof([]byte("k2"), 3) + require.NoError(err) + require.EqualValues(proof.GetNonexist().Key, []byte("k2")) + res, err = iTree.VerifyProof(proof, []byte("k2")) + require.NoError(err) + require.True(res) } func TestOrphans(t *testing.T) { @@ -1304,14 +1311,17 @@ func TestVersionedTreeHash(t *testing.T) { require.NoError(err) require.EqualValues(hash1, hash) - hash2, _, err := tree.SaveVersion() + _, _, err = tree.SaveVersion() require.NoError(err) - val, proof, err := tree.GetVersionedWithProof([]byte("I"), 2) + proof, err := tree.GetVersionedProof([]byte("I"), 2) + require.NoError(err) + require.EqualValues([]byte("F"), proof.GetExist().Value) + iTree, err := tree.GetImmutable(2) + require.NoError(err) + res, err := iTree.VerifyProof(proof, []byte("I")) require.NoError(err) - require.EqualValues([]byte("F"), val) - require.NoError(proof.Verify(hash2)) - require.NoError(proof.VerifyItem([]byte("I"), val)) + require.True(res) } func TestNilValueSemantics(t *testing.T) { diff --git a/util.go b/util.go index 676da1313..22f2dcd68 100644 --- a/util.go +++ b/util.go @@ -61,34 +61,6 @@ func maxInt8(a, b int8) int8 { return b } -func cp(bz []byte) (ret []byte) { - ret = make([]byte, len(bz)) - copy(ret, bz) - return ret -} - -// Returns a slice of the same length (big endian) -// except incremented by one. -// Appends 0x00 if bz is all 0xFF. -// CONTRACT: len(bz) > 0 -func cpIncr(bz []byte) (ret []byte) { - ret = cp(bz) - for i := len(bz) - 1; i >= 0; i-- { - if ret[i] < byte(0xFF) { - ret[i]++ - return - } - ret[i] = byte(0x00) - if i == 0 { - // here, the original bz is all 0xFF, so we keep the original and append 0x00 - // instead of returning all 0x00 - ret = cp(bz) - return append(ret, 0x00) - } - } - return []byte{0x00} -} - // Colors: ------------------------------------------------ const (