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