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.

191 lines
5.0 KiB

  1. package types
  2. import (
  3. "bytes"
  4. "testing"
  5. "github.com/stretchr/testify/assert"
  6. cmn "github.com/tendermint/tendermint/libs/common"
  7. ctest "github.com/tendermint/tendermint/libs/test"
  8. )
  9. func makeTxs(cnt, size int) Txs {
  10. txs := make(Txs, cnt)
  11. for i := 0; i < cnt; i++ {
  12. txs[i] = cmn.RandBytes(size)
  13. }
  14. return txs
  15. }
  16. func randInt(low, high int) int {
  17. off := cmn.RandInt() % (high - low)
  18. return low + off
  19. }
  20. func TestTxIndex(t *testing.T) {
  21. for i := 0; i < 20; i++ {
  22. txs := makeTxs(15, 60)
  23. for j := 0; j < len(txs); j++ {
  24. tx := txs[j]
  25. idx := txs.Index(tx)
  26. assert.Equal(t, j, idx)
  27. }
  28. assert.Equal(t, -1, txs.Index(nil))
  29. assert.Equal(t, -1, txs.Index(Tx("foodnwkf")))
  30. }
  31. }
  32. func TestTxIndexByHash(t *testing.T) {
  33. for i := 0; i < 20; i++ {
  34. txs := makeTxs(15, 60)
  35. for j := 0; j < len(txs); j++ {
  36. tx := txs[j]
  37. idx := txs.IndexByHash(tx.Hash())
  38. assert.Equal(t, j, idx)
  39. }
  40. assert.Equal(t, -1, txs.IndexByHash(nil))
  41. assert.Equal(t, -1, txs.IndexByHash(Tx("foodnwkf").Hash()))
  42. }
  43. }
  44. func TestValidTxProof(t *testing.T) {
  45. cases := []struct {
  46. txs Txs
  47. }{
  48. {Txs{{1, 4, 34, 87, 163, 1}}},
  49. {Txs{{5, 56, 165, 2}, {4, 77}}},
  50. {Txs{Tx("foo"), Tx("bar"), Tx("baz")}},
  51. {makeTxs(20, 5)},
  52. {makeTxs(7, 81)},
  53. {makeTxs(61, 15)},
  54. }
  55. for h, tc := range cases {
  56. txs := tc.txs
  57. root := txs.Hash()
  58. // make sure valid proof for every tx
  59. for i := range txs {
  60. leaf := txs[i]
  61. leafHash := leaf.Hash()
  62. proof := txs.Proof(i)
  63. assert.Equal(t, i, proof.Proof.Index, "%d: %d", h, i)
  64. assert.Equal(t, len(txs), proof.Proof.Total, "%d: %d", h, i)
  65. assert.EqualValues(t, root, proof.RootHash, "%d: %d", h, i)
  66. assert.EqualValues(t, leaf, proof.Data, "%d: %d", h, i)
  67. assert.EqualValues(t, leafHash, proof.LeafHash(), "%d: %d", h, i)
  68. assert.Nil(t, proof.Validate(root), "%d: %d", h, i)
  69. assert.NotNil(t, proof.Validate([]byte("foobar")), "%d: %d", h, i)
  70. // read-write must also work
  71. var p2 TxProof
  72. bin, err := cdc.MarshalBinaryLengthPrefixed(proof)
  73. assert.Nil(t, err)
  74. err = cdc.UnmarshalBinaryLengthPrefixed(bin, &p2)
  75. if assert.Nil(t, err, "%d: %d: %+v", h, i, err) {
  76. assert.Nil(t, p2.Validate(root), "%d: %d", h, i)
  77. }
  78. }
  79. }
  80. }
  81. func TestTxProofUnchangable(t *testing.T) {
  82. // run the other test a bunch...
  83. for i := 0; i < 40; i++ {
  84. testTxProofUnchangable(t)
  85. }
  86. }
  87. func TestComputeTxsOverhead(t *testing.T) {
  88. cases := []struct {
  89. txs Txs
  90. wantOverhead int
  91. }{
  92. {Txs{[]byte{6, 6, 6, 6, 6, 6}}, 2},
  93. // one 21 Mb transaction:
  94. {Txs{make([]byte, 22020096, 22020096)}, 5},
  95. // two 21Mb/2 sized transactions:
  96. {Txs{make([]byte, 11010048, 11010048), make([]byte, 11010048, 11010048)}, 10},
  97. {Txs{[]byte{1, 2, 3}, []byte{1, 2, 3}, []byte{4, 5, 6}}, 6},
  98. {Txs{[]byte{100, 5, 64}, []byte{42, 116, 118}, []byte{6, 6, 6}, []byte{6, 6, 6}}, 8},
  99. }
  100. for _, tc := range cases {
  101. totalBytes := int64(0)
  102. totalOverhead := int64(0)
  103. for _, tx := range tc.txs {
  104. aminoOverhead := ComputeAminoOverhead(tx, 1)
  105. totalOverhead += aminoOverhead
  106. totalBytes += aminoOverhead + int64(len(tx))
  107. }
  108. bz, err := cdc.MarshalBinaryBare(tc.txs)
  109. assert.EqualValues(t, tc.wantOverhead, totalOverhead)
  110. assert.NoError(t, err)
  111. assert.EqualValues(t, len(bz), totalBytes)
  112. }
  113. }
  114. func TestComputeAminoOverhead(t *testing.T) {
  115. cases := []struct {
  116. tx Tx
  117. fieldNum int
  118. want int
  119. }{
  120. {[]byte{6, 6, 6}, 1, 2},
  121. {[]byte{6, 6, 6}, 16, 3},
  122. {[]byte{6, 6, 6}, 32, 3},
  123. {[]byte{6, 6, 6}, 64, 3},
  124. {[]byte{6, 6, 6}, 512, 3},
  125. {[]byte{6, 6, 6}, 1024, 3},
  126. {[]byte{6, 6, 6}, 2048, 4},
  127. {make([]byte, 64), 1, 2},
  128. {make([]byte, 65), 1, 2},
  129. {make([]byte, 127), 1, 2},
  130. {make([]byte, 128), 1, 3},
  131. {make([]byte, 256), 1, 3},
  132. {make([]byte, 512), 1, 3},
  133. {make([]byte, 1024), 1, 3},
  134. {make([]byte, 128), 16, 4},
  135. }
  136. for _, tc := range cases {
  137. got := ComputeAminoOverhead(tc.tx, tc.fieldNum)
  138. assert.EqualValues(t, tc.want, got)
  139. }
  140. }
  141. func testTxProofUnchangable(t *testing.T) {
  142. // make some proof
  143. txs := makeTxs(randInt(2, 100), randInt(16, 128))
  144. root := txs.Hash()
  145. i := randInt(0, len(txs)-1)
  146. proof := txs.Proof(i)
  147. // make sure it is valid to start with
  148. assert.Nil(t, proof.Validate(root))
  149. bin, err := cdc.MarshalBinaryLengthPrefixed(proof)
  150. assert.Nil(t, err)
  151. // try mutating the data and make sure nothing breaks
  152. for j := 0; j < 500; j++ {
  153. bad := ctest.MutateByteSlice(bin)
  154. if !bytes.Equal(bad, bin) {
  155. assertBadProof(t, root, bad, proof)
  156. }
  157. }
  158. }
  159. // This makes sure that the proof doesn't deserialize into something valid.
  160. func assertBadProof(t *testing.T, root []byte, bad []byte, good TxProof) {
  161. var proof TxProof
  162. err := cdc.UnmarshalBinaryLengthPrefixed(bad, &proof)
  163. if err == nil {
  164. err = proof.Validate(root)
  165. if err == nil {
  166. // XXX Fix simple merkle proofs so the following is *not* OK.
  167. // This can happen if we have a slightly different total (where the
  168. // path ends up the same). If it is something else, we have a real
  169. // problem.
  170. assert.NotEqual(t, proof.Proof.Total, good.Proof.Total, "bad: %#v\ngood: %#v", proof, good)
  171. }
  172. }
  173. }