github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/store/rootmulti/proof.go (about) 1 package rootmulti 2 3 import ( 4 "bytes" 5 "fmt" 6 7 "github.com/gnolang/gno/tm2/pkg/amino" 8 "github.com/gnolang/gno/tm2/pkg/crypto/merkle" 9 "github.com/gnolang/gno/tm2/pkg/errors" 10 "github.com/gnolang/gno/tm2/pkg/iavl" 11 ) 12 13 // MultiStoreProof defines a collection of store proofs in a multi-store 14 type MultiStoreProof struct { 15 StoreInfos []storeInfo 16 } 17 18 func NewMultiStoreProof(storeInfos []storeInfo) *MultiStoreProof { 19 return &MultiStoreProof{StoreInfos: storeInfos} 20 } 21 22 // ComputeRootHash returns the root hash for a given multi-store proof. 23 func (proof *MultiStoreProof) ComputeRootHash() []byte { 24 ci := commitInfo{ 25 Version: -1, // TODO: Not needed; improve code. 26 StoreInfos: proof.StoreInfos, 27 } 28 return ci.Hash() 29 } 30 31 // RequireProof returns whether proof is required for the subpath. 32 func RequireProof(subpath string) bool { 33 // XXX: create a better convention. 34 // Currently, only when query subpath is "/key", will proof be included in 35 // response. If there are some changes about proof building in iavlstore.go, 36 // we must change code here to keep consistency with iavlStore#Query. 37 return subpath == "/key" 38 } 39 40 //----------------------------------------------------------------------------- 41 42 var _ merkle.ProofOperator = MultiStoreProofOp{} 43 44 // the multi-store proof operation constant value 45 const ProofOpMultiStore = "multistore" 46 47 // TODO: document 48 type MultiStoreProofOp struct { 49 // Encoded in ProofOp.Key 50 key []byte 51 52 // To encode in ProofOp.Data. 53 Proof *MultiStoreProof `json:"proof"` 54 } 55 56 func NewMultiStoreProofOp(key []byte, proof *MultiStoreProof) MultiStoreProofOp { 57 return MultiStoreProofOp{ 58 key: key, 59 Proof: proof, 60 } 61 } 62 63 // MultiStoreProofOpDecoder returns a multi-store merkle proof operator from a 64 // given proof operation. 65 func MultiStoreProofOpDecoder(pop merkle.ProofOp) (merkle.ProofOperator, error) { 66 if pop.Type != ProofOpMultiStore { 67 return nil, errors.New("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpMultiStore) 68 } 69 70 // XXX: a bit strange as we'll discard this, but it works 71 var op MultiStoreProofOp 72 73 err := amino.UnmarshalSized(pop.Data, &op) 74 if err != nil { 75 return nil, errors.Wrap(err, "decoding ProofOp.Data into MultiStoreProofOp") 76 } 77 78 return NewMultiStoreProofOp(pop.Key, op.Proof), nil 79 } 80 81 // ProofOp return a merkle proof operation from a given multi-store proof 82 // operation. 83 func (op MultiStoreProofOp) ProofOp() merkle.ProofOp { 84 bz := amino.MustMarshalSized(op) 85 return merkle.ProofOp{ 86 Type: ProofOpMultiStore, 87 Key: op.key, 88 Data: bz, 89 } 90 } 91 92 // String implements the Stringer interface for a mult-store proof operation. 93 func (op MultiStoreProofOp) String() string { 94 return fmt.Sprintf("MultiStoreProofOp{%v}", op.GetKey()) 95 } 96 97 // GetKey returns the key for a multi-store proof operation. 98 func (op MultiStoreProofOp) GetKey() []byte { 99 return op.key 100 } 101 102 // Run executes a multi-store proof operation for a given value. It returns 103 // the root hash if the value matches all the store's commitID's hash or an 104 // error otherwise. 105 func (op MultiStoreProofOp) Run(args [][]byte) ([][]byte, error) { 106 if len(args) != 1 { 107 return nil, errors.New("Value size is not 1") 108 } 109 110 value := args[0] 111 root := op.Proof.ComputeRootHash() 112 113 for _, si := range op.Proof.StoreInfos { 114 if si.Name == string(op.key) { 115 if bytes.Equal(value, si.Core.CommitID.Hash) { 116 return [][]byte{root}, nil 117 } 118 119 return nil, errors.New("hash mismatch for substore %v: %X vs %X", si.Name, si.Core.CommitID.Hash, value) 120 } 121 } 122 123 return nil, errors.New("key %v not found in multistore proof", op.key) 124 } 125 126 //---------------------------------------- 127 128 // XXX: This should be managed by the rootMultiStore which may want to register 129 // more proof ops? 130 func DefaultProofRuntime() (prt *merkle.ProofRuntime) { 131 prt = merkle.NewProofRuntime() 132 prt.RegisterOpDecoder(merkle.ProofOpSimpleValue, merkle.SimpleValueOpDecoder) 133 prt.RegisterOpDecoder(iavl.ProofOpIAVLValue, iavl.IAVLValueOpDecoder) 134 prt.RegisterOpDecoder(iavl.ProofOpIAVLAbsence, iavl.IAVLAbsenceOpDecoder) 135 prt.RegisterOpDecoder(ProofOpMultiStore, MultiStoreProofOpDecoder) 136 return 137 }