github.com/vipernet-xyz/tm@v0.34.24/crypto/merkle/proof_test.go (about)

     1  package merkle
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  
    11  	tmcrypto "github.com/vipernet-xyz/tm/proto/tendermint/crypto"
    12  )
    13  
    14  const ProofOpDomino = "test:domino"
    15  
    16  // Expects given input, produces given output.
    17  // Like the game dominos.
    18  type DominoOp struct {
    19  	key    string // unexported, may be empty
    20  	Input  string
    21  	Output string
    22  }
    23  
    24  func NewDominoOp(key, input, output string) DominoOp {
    25  	return DominoOp{
    26  		key:    key,
    27  		Input:  input,
    28  		Output: output,
    29  	}
    30  }
    31  
    32  func (dop DominoOp) ProofOp() tmcrypto.ProofOp {
    33  	dopb := tmcrypto.DominoOp{
    34  		Key:    dop.key,
    35  		Input:  dop.Input,
    36  		Output: dop.Output,
    37  	}
    38  	bz, err := dopb.Marshal()
    39  	if err != nil {
    40  		panic(err)
    41  	}
    42  
    43  	return tmcrypto.ProofOp{
    44  		Type: ProofOpDomino,
    45  		Key:  []byte(dop.key),
    46  		Data: bz,
    47  	}
    48  }
    49  
    50  func (dop DominoOp) Run(input [][]byte) (output [][]byte, err error) {
    51  	if len(input) != 1 {
    52  		return nil, errors.New("expected input of length 1")
    53  	}
    54  	if string(input[0]) != dop.Input {
    55  		return nil, fmt.Errorf("expected input %v, got %v",
    56  			dop.Input, string(input[0]))
    57  	}
    58  	return [][]byte{[]byte(dop.Output)}, nil
    59  }
    60  
    61  func (dop DominoOp) GetKey() []byte {
    62  	return []byte(dop.key)
    63  }
    64  
    65  //----------------------------------------
    66  
    67  func TestProofOperators(t *testing.T) {
    68  	var err error
    69  
    70  	// ProofRuntime setup
    71  	// TODO test this somehow.
    72  
    73  	// ProofOperators setup
    74  	op1 := NewDominoOp("KEY1", "INPUT1", "INPUT2")
    75  	op2 := NewDominoOp("KEY2", "INPUT2", "INPUT3")
    76  	op3 := NewDominoOp("", "INPUT3", "INPUT4")
    77  	op4 := NewDominoOp("KEY4", "INPUT4", "OUTPUT4")
    78  
    79  	// Good
    80  	popz := ProofOperators([]ProofOperator{op1, op2, op3, op4})
    81  	err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
    82  	assert.Nil(t, err)
    83  	err = popz.VerifyValue(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", bz("INPUT1"))
    84  	assert.Nil(t, err)
    85  
    86  	// BAD INPUT
    87  	err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1_WRONG")})
    88  	assert.NotNil(t, err)
    89  	err = popz.VerifyValue(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", bz("INPUT1_WRONG"))
    90  	assert.NotNil(t, err)
    91  
    92  	// BAD KEY 1
    93  	err = popz.Verify(bz("OUTPUT4"), "/KEY3/KEY2/KEY1", [][]byte{bz("INPUT1")})
    94  	assert.NotNil(t, err)
    95  
    96  	// BAD KEY 2
    97  	err = popz.Verify(bz("OUTPUT4"), "KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
    98  	assert.NotNil(t, err)
    99  
   100  	// BAD KEY 3
   101  	err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1/", [][]byte{bz("INPUT1")})
   102  	assert.NotNil(t, err)
   103  
   104  	// BAD KEY 4
   105  	err = popz.Verify(bz("OUTPUT4"), "//KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
   106  	assert.NotNil(t, err)
   107  
   108  	// BAD KEY 5
   109  	err = popz.Verify(bz("OUTPUT4"), "/KEY2/KEY1", [][]byte{bz("INPUT1")})
   110  	assert.NotNil(t, err)
   111  
   112  	// BAD OUTPUT 1
   113  	err = popz.Verify(bz("OUTPUT4_WRONG"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
   114  	assert.NotNil(t, err)
   115  
   116  	// BAD OUTPUT 2
   117  	err = popz.Verify(bz(""), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
   118  	assert.NotNil(t, err)
   119  
   120  	// BAD POPZ 1
   121  	popz = []ProofOperator{op1, op2, op4}
   122  	err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
   123  	assert.NotNil(t, err)
   124  
   125  	// BAD POPZ 2
   126  	popz = []ProofOperator{op4, op3, op2, op1}
   127  	err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
   128  	assert.NotNil(t, err)
   129  
   130  	// BAD POPZ 3
   131  	popz = []ProofOperator{}
   132  	err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
   133  	assert.NotNil(t, err)
   134  }
   135  
   136  func bz(s string) []byte {
   137  	return []byte(s)
   138  }
   139  
   140  func TestProofValidateBasic(t *testing.T) {
   141  	testCases := []struct {
   142  		testName      string
   143  		malleateProof func(*Proof)
   144  		errStr        string
   145  	}{
   146  		{"Good", func(sp *Proof) {}, ""},
   147  		{"Negative Total", func(sp *Proof) { sp.Total = -1 }, "negative Total"},
   148  		{"Negative Index", func(sp *Proof) { sp.Index = -1 }, "negative Index"},
   149  		{"Invalid LeafHash", func(sp *Proof) { sp.LeafHash = make([]byte, 10) },
   150  			"expected LeafHash size to be 32, got 10"},
   151  		{"Too many Aunts", func(sp *Proof) { sp.Aunts = make([][]byte, MaxAunts+1) },
   152  			"expected no more than 100 aunts, got 101"},
   153  		{"Invalid Aunt", func(sp *Proof) { sp.Aunts[0] = make([]byte, 10) },
   154  			"expected Aunts#0 size to be 32, got 10"},
   155  	}
   156  
   157  	for _, tc := range testCases {
   158  		tc := tc
   159  		t.Run(tc.testName, func(t *testing.T) {
   160  			_, proofs := ProofsFromByteSlices([][]byte{
   161  				[]byte("apple"),
   162  				[]byte("watermelon"),
   163  				[]byte("kiwi"),
   164  			})
   165  			tc.malleateProof(proofs[0])
   166  			err := proofs[0].ValidateBasic()
   167  			if tc.errStr != "" {
   168  				assert.Contains(t, err.Error(), tc.errStr)
   169  			}
   170  		})
   171  	}
   172  }
   173  func TestVoteProtobuf(t *testing.T) {
   174  
   175  	_, proofs := ProofsFromByteSlices([][]byte{
   176  		[]byte("apple"),
   177  		[]byte("watermelon"),
   178  		[]byte("kiwi"),
   179  	})
   180  	testCases := []struct {
   181  		testName string
   182  		v1       *Proof
   183  		expPass  bool
   184  	}{
   185  		{"empty proof", &Proof{}, false},
   186  		{"failure nil", nil, false},
   187  		{"success", proofs[0], true},
   188  	}
   189  	for _, tc := range testCases {
   190  		pb := tc.v1.ToProto()
   191  
   192  		v, err := ProofFromProto(pb)
   193  		if tc.expPass {
   194  			require.NoError(t, err)
   195  			require.Equal(t, tc.v1, v, tc.testName)
   196  		} else {
   197  			require.Error(t, err)
   198  		}
   199  	}
   200  }