github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/iavl/mutable_ibc_adapter.go (about)

     1  package iavl
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  
     7  	ics23 "github.com/confio/ics23/go"
     8  )
     9  
    10  func (t *ImmutableTree) GetMembershipProof(key []byte) (*ics23.CommitmentProof, error) {
    11  	exist, err := createExistenceProof(t, key)
    12  	if err != nil {
    13  		return nil, err
    14  	}
    15  	proof := &ics23.CommitmentProof{
    16  		Proof: &ics23.CommitmentProof_Exist{
    17  			Exist: exist,
    18  		},
    19  	}
    20  	return proof, nil
    21  }
    22  
    23  // convertExistenceProof will convert the given proof into a valid
    24  // existence proof, if that's what it is.
    25  //
    26  // This is the simplest case of the range proof and we will focus on
    27  // demoing compatibility here
    28  func convertExistenceProof(p *RangeProof, key, value []byte) (*ics23.ExistenceProof, error) {
    29  	if len(p.Leaves) != 1 {
    30  		return nil, fmt.Errorf("existence proof requires RangeProof to have exactly one leaf")
    31  	}
    32  	return &ics23.ExistenceProof{
    33  		Key:   key,
    34  		Value: value,
    35  		Leaf:  convertLeafOp(p.Leaves[0].Version),
    36  		Path:  convertInnerOps(p.LeftPath),
    37  	}, nil
    38  }
    39  
    40  func convertLeafOp(version int64) *ics23.LeafOp {
    41  	var varintBuf [binary.MaxVarintLen64]byte
    42  	// this is adapted from iavl/proof.go:proofLeafNode.Hash()
    43  	prefix := convertVarIntToBytes(0, varintBuf)
    44  	prefix = append(prefix, convertVarIntToBytes(1, varintBuf)...)
    45  	prefix = append(prefix, convertVarIntToBytes(version, varintBuf)...)
    46  
    47  	return &ics23.LeafOp{
    48  		Hash:         ics23.HashOp_SHA256,
    49  		PrehashValue: ics23.HashOp_SHA256,
    50  		Length:       ics23.LengthOp_VAR_PROTO,
    51  		Prefix:       prefix,
    52  	}
    53  }
    54  
    55  // we cannot get the proofInnerNode type, so we need to do the whole path in one function
    56  func convertInnerOps(path PathToLeaf) []*ics23.InnerOp {
    57  	steps := make([]*ics23.InnerOp, 0, len(path))
    58  
    59  	// lengthByte is the length prefix prepended to each of the sha256 sub-hashes
    60  	var lengthByte byte = 0x20
    61  
    62  	var varintBuf [binary.MaxVarintLen64]byte
    63  
    64  	// we need to go in reverse order, iavl starts from root to leaf,
    65  	// we want to go up from the leaf to the root
    66  	for i := len(path) - 1; i >= 0; i-- {
    67  		// this is adapted from iavl/proof.go:proofInnerNode.Hash()
    68  		prefix := convertVarIntToBytes(int64(path[i].Height), varintBuf)
    69  		prefix = append(prefix, convertVarIntToBytes(path[i].Size, varintBuf)...)
    70  		prefix = append(prefix, convertVarIntToBytes(path[i].Version, varintBuf)...)
    71  
    72  		var suffix []byte
    73  		if len(path[i].Left) > 0 {
    74  			// length prefixed left side
    75  			prefix = append(prefix, lengthByte)
    76  			prefix = append(prefix, path[i].Left...)
    77  			// prepend the length prefix for child
    78  			prefix = append(prefix, lengthByte)
    79  		} else {
    80  			// prepend the length prefix for child
    81  			prefix = append(prefix, lengthByte)
    82  			// length-prefixed right side
    83  			suffix = []byte{lengthByte}
    84  			suffix = append(suffix, path[i].Right...)
    85  		}
    86  
    87  		op := &ics23.InnerOp{
    88  			Hash:   ics23.HashOp_SHA256,
    89  			Prefix: prefix,
    90  			Suffix: suffix,
    91  		}
    92  		steps = append(steps, op)
    93  	}
    94  	return steps
    95  }
    96  
    97  func convertVarIntToBytes(orig int64, buf [binary.MaxVarintLen64]byte) []byte {
    98  	n := binary.PutVarint(buf[:], orig)
    99  	return buf[:n]
   100  }
   101  
   102  /*
   103  GetNonMembershipProof will produce a CommitmentProof that the given key doesn't exist in the iavl tree.
   104  If the key exists in the tree, this will return an error.
   105  */
   106  func (t *ImmutableTree) GetNonMembershipProof(key []byte) (*ics23.CommitmentProof, error) {
   107  	// idx is one node right of what we want....
   108  	idx, val := t.GetWithIndex(key)
   109  	if val != nil {
   110  		return nil, fmt.Errorf("cannot create NonExistanceProof when Key in State")
   111  	}
   112  
   113  	var err error
   114  	nonexist := &ics23.NonExistenceProof{
   115  		Key: key,
   116  	}
   117  
   118  	if idx >= 1 {
   119  		leftkey, _ := t.GetByIndex(idx - 1)
   120  		nonexist.Left, err = createExistenceProof(t, leftkey)
   121  		if err != nil {
   122  			return nil, err
   123  		}
   124  	}
   125  
   126  	// this will be nil if nothing right of the queried key
   127  	rightkey, _ := t.GetByIndex(idx)
   128  	if rightkey != nil {
   129  		nonexist.Right, err = createExistenceProof(t, rightkey)
   130  		if err != nil {
   131  			return nil, err
   132  		}
   133  	}
   134  
   135  	proof := &ics23.CommitmentProof{
   136  		Proof: &ics23.CommitmentProof_Nonexist{
   137  			Nonexist: nonexist,
   138  		},
   139  	}
   140  	return proof, nil
   141  }
   142  
   143  func createExistenceProof(tree *ImmutableTree, key []byte) (*ics23.ExistenceProof, error) {
   144  	value, proof, err := tree.GetWithProof2(key)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	if value == nil {
   149  		return nil, fmt.Errorf("cannot create ExistanceProof when Key not in State")
   150  	}
   151  	return convertExistenceProof(proof, key, value)
   152  }