github.com/Finschia/finschia-sdk@v0.48.1/store/internal/proofs/create.go (about) 1 package proofs 2 3 import ( 4 "errors" 5 "fmt" 6 "sort" 7 8 ics23 "github.com/confio/ics23/go" 9 10 sdkmaps "github.com/Finschia/finschia-sdk/store/internal/maps" 11 ) 12 13 var ( 14 ErrEmptyKey = errors.New("key is empty") 15 ErrEmptyKeyInData = errors.New("data contains empty key") 16 ) 17 18 // TendermintSpec constrains the format from ics23-tendermint (crypto/merkle SimpleProof) 19 var TendermintSpec = &ics23.ProofSpec{ 20 LeafSpec: &ics23.LeafOp{ 21 Prefix: []byte{0}, 22 Hash: ics23.HashOp_SHA256, 23 PrehashValue: ics23.HashOp_SHA256, 24 Length: ics23.LengthOp_VAR_PROTO, 25 }, 26 InnerSpec: &ics23.InnerSpec{ 27 ChildOrder: []int32{0, 1}, 28 MinPrefixLength: 1, 29 MaxPrefixLength: 1, // fixed prefix + one child 30 ChildSize: 32, // (no length byte) 31 Hash: ics23.HashOp_SHA256, 32 }, 33 } 34 35 /* 36 CreateMembershipProof will produce a CommitmentProof that the given key (and queries value) exists in the iavl tree. 37 If the key doesn't exist in the tree, this will return an error. 38 */ 39 func CreateMembershipProof(data map[string][]byte, key []byte) (*ics23.CommitmentProof, error) { 40 if len(key) == 0 { 41 return nil, ErrEmptyKey 42 } 43 exist, err := createExistenceProof(data, key) 44 if err != nil { 45 return nil, err 46 } 47 proof := &ics23.CommitmentProof{ 48 Proof: &ics23.CommitmentProof_Exist{ 49 Exist: exist, 50 }, 51 } 52 return proof, nil 53 } 54 55 /* 56 CreateNonMembershipProof will produce a CommitmentProof that the given key doesn't exist in the iavl tree. 57 If the key exists in the tree, this will return an error. 58 */ 59 func CreateNonMembershipProof(data map[string][]byte, key []byte) (*ics23.CommitmentProof, error) { 60 if len(key) == 0 { 61 return nil, ErrEmptyKey 62 } 63 // ensure this key is not in the store 64 if _, ok := data[string(key)]; ok { 65 return nil, fmt.Errorf("cannot create non-membership proof if key is in map") 66 } 67 68 keys := SortedKeys(data) 69 rightidx := sort.SearchStrings(keys, string(key)) 70 71 var err error 72 nonexist := &ics23.NonExistenceProof{ 73 Key: key, 74 } 75 76 // include left proof unless key is left of entire map 77 if rightidx >= 1 { 78 leftkey := keys[rightidx-1] 79 nonexist.Left, err = createExistenceProof(data, []byte(leftkey)) 80 if err != nil { 81 return nil, err 82 } 83 } 84 85 // include right proof unless key is right of entire map 86 if rightidx < len(keys) { 87 rightkey := keys[rightidx] 88 nonexist.Right, err = createExistenceProof(data, []byte(rightkey)) 89 if err != nil { 90 return nil, err 91 } 92 93 } 94 95 proof := &ics23.CommitmentProof{ 96 Proof: &ics23.CommitmentProof_Nonexist{ 97 Nonexist: nonexist, 98 }, 99 } 100 return proof, nil 101 } 102 103 func createExistenceProof(data map[string][]byte, key []byte) (*ics23.ExistenceProof, error) { 104 for k := range data { 105 if k == "" { 106 return nil, ErrEmptyKeyInData 107 } 108 } 109 value, ok := data[string(key)] 110 if !ok { 111 return nil, fmt.Errorf("cannot make existence proof if key is not in map") 112 } 113 114 _, ics23, _ := sdkmaps.ProofsFromMap(data) 115 proof := ics23[string(key)] 116 if proof == nil { 117 return nil, fmt.Errorf("returned no proof for key") 118 } 119 120 return ConvertExistenceProof(proof, key, value) 121 }