github.com/phillinzzz/newBsc@v1.1.6/core/vm/lightclient/multistoreproof.go (about)

     1  package lightclient
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"github.com/tendermint/iavl"
     8  	"github.com/tendermint/tendermint/crypto/merkle"
     9  	cmn "github.com/tendermint/tendermint/libs/common"
    10  )
    11  
    12  // MultiStoreProof defines a collection of store proofs in a multi-store
    13  type MultiStoreProof struct {
    14  	StoreInfos []StoreInfo
    15  }
    16  
    17  func NewMultiStoreProof(storeInfos []StoreInfo) *MultiStoreProof {
    18  	return &MultiStoreProof{StoreInfos: storeInfos}
    19  }
    20  
    21  // ComputeRootHash returns the root hash for a given multi-store proof.
    22  func (proof *MultiStoreProof) ComputeRootHash() []byte {
    23  	ci := CommitInfo{
    24  		Version:    -1, // TODO: Not needed; improve code.
    25  		StoreInfos: proof.StoreInfos,
    26  	}
    27  	return ci.Hash()
    28  }
    29  
    30  // RequireProof return whether proof is require for the subpath
    31  func RequireProof(subpath string) bool {
    32  	// XXX: create a better convention.
    33  	// Currently, only when query subpath is "/store" or "/key", will proof be included in response.
    34  	// If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go:212
    35  	if subpath == "/store" || subpath == "/key" {
    36  		return true
    37  	}
    38  	return false
    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, cmn.NewError("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, cmn.ErrorWrap(err, "decoding ProofOp.Data into MultiStoreProofOp")
    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, cmn.NewError("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, cmn.NewError("hash mismatch for substore %v: %X vs %X", si.Name, si.Core.CommitID.Hash, value)
   121  		}
   122  	}
   123  
   124  	return nil, cmn.NewError("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.IAVLValueOpDecoder)
   135  	prt.RegisterOpDecoder(iavl.ProofOpIAVLAbsence, iavl.IAVLAbsenceOpDecoder)
   136  	prt.RegisterOpDecoder(ProofOpMultiStore, MultiStoreProofOpDecoder)
   137  	return
   138  }