You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

200 lines
4.9 KiB

package merkle
import (
"errors"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
tmmerkle "github.com/tendermint/tendermint/proto/crypto/merkle"
)
const ProofOpDomino = "test:domino"
// Expects given input, produces given output.
// Like the game dominos.
type DominoOp struct {
key string // unexported, may be empty
Input string
Output string
}
func NewDominoOp(key, input, output string) DominoOp {
return DominoOp{
key: key,
Input: input,
Output: output,
}
}
func (dop DominoOp) ProofOp() tmmerkle.ProofOp {
dopb := tmmerkle.DominoOp{
Key: dop.key,
Input: dop.Input,
Output: dop.Output,
}
bz, err := dopb.Marshal()
if err != nil {
panic(err)
}
return tmmerkle.ProofOp{
Type: ProofOpDomino,
Key: []byte(dop.key),
Data: bz,
}
}
func (dop DominoOp) Run(input [][]byte) (output [][]byte, err error) {
if len(input) != 1 {
return nil, errors.New("expected input of length 1")
}
if string(input[0]) != dop.Input {
return nil, fmt.Errorf("expected input %v, got %v",
dop.Input, string(input[0]))
}
return [][]byte{[]byte(dop.Output)}, nil
}
func (dop DominoOp) GetKey() []byte {
return []byte(dop.key)
}
//----------------------------------------
func TestProofOperators(t *testing.T) {
var err error
// ProofRuntime setup
// TODO test this somehow.
// ProofOperators setup
op1 := NewDominoOp("KEY1", "INPUT1", "INPUT2")
op2 := NewDominoOp("KEY2", "INPUT2", "INPUT3")
op3 := NewDominoOp("", "INPUT3", "INPUT4")
op4 := NewDominoOp("KEY4", "INPUT4", "OUTPUT4")
// Good
popz := ProofOperators([]ProofOperator{op1, op2, op3, op4})
err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
assert.Nil(t, err)
err = popz.VerifyValue(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", bz("INPUT1"))
assert.Nil(t, err)
// BAD INPUT
err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1_WRONG")})
assert.NotNil(t, err)
err = popz.VerifyValue(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", bz("INPUT1_WRONG"))
assert.NotNil(t, err)
// BAD KEY 1
err = popz.Verify(bz("OUTPUT4"), "/KEY3/KEY2/KEY1", [][]byte{bz("INPUT1")})
assert.NotNil(t, err)
// BAD KEY 2
err = popz.Verify(bz("OUTPUT4"), "KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
assert.NotNil(t, err)
// BAD KEY 3
err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1/", [][]byte{bz("INPUT1")})
assert.NotNil(t, err)
// BAD KEY 4
err = popz.Verify(bz("OUTPUT4"), "//KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
assert.NotNil(t, err)
// BAD KEY 5
err = popz.Verify(bz("OUTPUT4"), "/KEY2/KEY1", [][]byte{bz("INPUT1")})
assert.NotNil(t, err)
// BAD OUTPUT 1
err = popz.Verify(bz("OUTPUT4_WRONG"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
assert.NotNil(t, err)
// BAD OUTPUT 2
err = popz.Verify(bz(""), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
assert.NotNil(t, err)
// BAD POPZ 1
popz = []ProofOperator{op1, op2, op4}
err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
assert.NotNil(t, err)
// BAD POPZ 2
popz = []ProofOperator{op4, op3, op2, op1}
err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
assert.NotNil(t, err)
// BAD POPZ 3
popz = []ProofOperator{}
err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
assert.NotNil(t, err)
}
func bz(s string) []byte {
return []byte(s)
}
func TestProofValidateBasic(t *testing.T) {
testCases := []struct {
testName string
malleateProof func(*Proof)
errStr string
}{
{"Good", func(sp *Proof) {}, ""},
{"Negative Total", func(sp *Proof) { sp.Total = -1 }, "negative Total"},
{"Negative Index", func(sp *Proof) { sp.Index = -1 }, "negative Index"},
{"Invalid LeafHash", func(sp *Proof) { sp.LeafHash = make([]byte, 10) },
"expected LeafHash size to be 32, got 10"},
{"Too many Aunts", func(sp *Proof) { sp.Aunts = make([][]byte, MaxAunts+1) },
"expected no more than 100 aunts, got 101"},
{"Invalid Aunt", func(sp *Proof) { sp.Aunts[0] = make([]byte, 10) },
"expected Aunts#0 size to be 32, got 10"},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.testName, func(t *testing.T) {
_, proofs := ProofsFromByteSlices([][]byte{
[]byte("apple"),
[]byte("watermelon"),
[]byte("kiwi"),
})
tc.malleateProof(proofs[0])
err := proofs[0].ValidateBasic()
if tc.errStr != "" {
assert.Contains(t, err.Error(), tc.errStr)
}
})
}
}
func TestVoteProtobuf(t *testing.T) {
_, proofs := ProofsFromByteSlices([][]byte{
[]byte("apple"),
[]byte("watermelon"),
[]byte("kiwi"),
})
testCases := []struct {
testName string
v1 *Proof
expPass bool
}{
{"empty proof", &Proof{}, false},
{"failure nil", nil, false},
{"success", proofs[0], true},
}
for _, tc := range testCases {
pb := tc.v1.ToProto()
v, err := ProofFromProto(pb)
if tc.expPass {
require.NoError(t, err)
require.Equal(t, tc.v1, v, tc.testName)
} else {
require.Error(t, err)
}
}
}