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

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