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.

424 lines
12 KiB

add missing Timestamp to Votes Fixes: ``` panic: Panicked on a Sanity Check: can't encode times below 1970 [recovered] panic: Panicked on a Sanity Check: can't encode times below 1970 goroutine 2042 [running]: testing.tRunner.func1(0xc420e8c0f0) /usr/local/go/src/testing/testing.go:711 +0x5d9 panic(0xcd9e20, 0xc420c8c270) /usr/local/go/src/runtime/panic.go:491 +0x2a2 github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.PanicSanity(0xcd9e20, 0xf8ddd0) /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/errors.go:26 +0x120 github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.WriteTime(0x0, 0x0, 0x0, 0x1306440, 0xc4201607e0, 0xc420e31658, 0xc420e31680) /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/time.go:19 +0x11e github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.writeReflectBinary(0xdc9e40, 0xc4201fcf30, 0x199, 0x1317b80, 0xdc9e40, 0xc98451, 0x9, 0x0, 0xdc9e40, 0xc420ead9c0, ...) /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/reflect.go:525 +0x22f0 github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.writeReflectBinary(0xd25400, 0xc42000e2e8, 0x196, 0x1317b80, 0xd92d60, 0xc9a195, 0xa, 0x0, 0xcc8ce0, 0xc420164920, ...) /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/reflect.go:530 +0x21e7 github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.writeReflectBinary(0xcc8ce0, 0xc4209f95b8, 0x197, 0x1317b80, 0xcc8ce0, 0xc9a195, 0xa, 0x0, 0xcc8ce0, 0xc420164920, ...) /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/reflect.go:518 +0x2509 github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.writeReflectBinary(0xd873e0, 0xc4209f9580, 0x16, 0x1317b80, 0xd79400, 0x0, 0x0, 0x0, 0x0, 0x0, ...) /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/reflect.go:530 +0x21e7 github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.WriteBinary(0xd873e0, 0xc4209f9580, 0x1306440, 0xc4201607e0, 0xc420e31658, 0xc420e31680) /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/wire.go:80 +0x15f github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire.BinaryBytes(0xd873e0, 0xc4209f9580, 0x3, 0x8, 0xc420160798) /go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-wire/util.go:15 +0xb8 github.com/tendermint/tendermint/blockchain.(*BlockStore).SaveBlock(0xc4201342a0, 0xc420eac180, 0xc420130640, 0xc4209f9580) github.com/tendermint/tendermint/blockchain/_test/_obj_test/store.go:192 +0x439 github.com/tendermint/tendermint/blockchain.TestBlockStoreSaveLoadBlock(0xc420e8c0f0) /go/src/github.com/tendermint/tendermint/blockchain/store_test.go:128 +0x609 testing.tRunner(0xc420e8c0f0, 0xf20830) /usr/local/go/src/testing/testing.go:746 +0x16d created by testing.(*T).Run /usr/local/go/src/testing/testing.go:789 +0x569 exit status 2 FAIL ```
7 years ago
  1. package blockchain
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "runtime/debug"
  7. "strings"
  8. "testing"
  9. "time"
  10. "github.com/stretchr/testify/assert"
  11. "github.com/stretchr/testify/require"
  12. wire "github.com/tendermint/go-wire"
  13. "github.com/tendermint/tmlibs/db"
  14. "github.com/tendermint/tmlibs/log"
  15. "github.com/tendermint/tendermint/types"
  16. )
  17. func TestLoadBlockStoreStateJSON(t *testing.T) {
  18. db := db.NewMemDB()
  19. bsj := &BlockStoreStateJSON{Height: 1000}
  20. bsj.Save(db)
  21. retrBSJ := LoadBlockStoreStateJSON(db)
  22. assert.Equal(t, *bsj, retrBSJ, "expected the retrieved DBs to match")
  23. }
  24. func TestNewBlockStore(t *testing.T) {
  25. db := db.NewMemDB()
  26. db.Set(blockStoreKey, []byte(`{"height": 10000}`))
  27. bs := NewBlockStore(db)
  28. assert.Equal(t, bs.Height(), int64(10000), "failed to properly parse blockstore")
  29. panicCausers := []struct {
  30. data []byte
  31. wantErr string
  32. }{
  33. {[]byte("artful-doger"), "not unmarshal bytes"},
  34. {[]byte(" "), "unmarshal bytes"},
  35. }
  36. for i, tt := range panicCausers {
  37. // Expecting a panic here on trying to parse an invalid blockStore
  38. _, _, panicErr := doFn(func() (interface{}, error) {
  39. db.Set(blockStoreKey, tt.data)
  40. _ = NewBlockStore(db)
  41. return nil, nil
  42. })
  43. require.NotNil(t, panicErr, "#%d panicCauser: %q expected a panic", i, tt.data)
  44. assert.Contains(t, panicErr.Error(), tt.wantErr, "#%d data: %q", i, tt.data)
  45. }
  46. db.Set(blockStoreKey, nil)
  47. bs = NewBlockStore(db)
  48. assert.Equal(t, bs.Height(), int64(0), "expecting nil bytes to be unmarshaled alright")
  49. }
  50. func TestBlockStoreGetReader(t *testing.T) {
  51. db := db.NewMemDB()
  52. // Initial setup
  53. db.Set([]byte("Foo"), []byte("Bar"))
  54. db.Set([]byte("Foo1"), nil)
  55. bs := NewBlockStore(db)
  56. tests := [...]struct {
  57. key []byte
  58. want []byte
  59. }{
  60. 0: {key: []byte("Foo"), want: []byte("Bar")},
  61. 1: {key: []byte("KnoxNonExistent"), want: nil},
  62. 2: {key: []byte("Foo1"), want: []byte{}},
  63. }
  64. for i, tt := range tests {
  65. r := bs.GetReader(tt.key)
  66. if r == nil {
  67. assert.Nil(t, tt.want, "#%d: expected a non-nil reader", i)
  68. continue
  69. }
  70. slurp, err := ioutil.ReadAll(r)
  71. if err != nil {
  72. t.Errorf("#%d: unexpected Read err: %v", i, err)
  73. } else {
  74. assert.Equal(t, slurp, tt.want, "#%d: mismatch", i)
  75. }
  76. }
  77. }
  78. func freshBlockStore() (*BlockStore, db.DB) {
  79. db := db.NewMemDB()
  80. return NewBlockStore(db), db
  81. }
  82. var (
  83. state, _ = makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
  84. block = makeBlock(1, state)
  85. partSet = block.MakePartSet(2)
  86. part1 = partSet.GetPart(0)
  87. part2 = partSet.GetPart(1)
  88. seenCommit1 = &types.Commit{Precommits: []*types.Vote{{Height: 10,
  89. Timestamp: time.Now().UTC()}}}
  90. )
  91. // TODO: This test should be simplified ...
  92. func TestBlockStoreSaveLoadBlock(t *testing.T) {
  93. state, bs := makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
  94. require.Equal(t, bs.Height(), int64(0), "initially the height should be zero")
  95. // check there are no blocks at various heights
  96. noBlockHeights := []int64{0, -1, 100, 1000, 2}
  97. for i, height := range noBlockHeights {
  98. if g := bs.LoadBlock(height); g != nil {
  99. t.Errorf("#%d: height(%d) got a block; want nil", i, height)
  100. }
  101. }
  102. // save a block
  103. block := makeBlock(bs.Height()+1, state)
  104. validPartSet := block.MakePartSet(2)
  105. seenCommit := &types.Commit{Precommits: []*types.Vote{{Height: 10,
  106. Timestamp: time.Now().UTC()}}}
  107. bs.SaveBlock(block, partSet, seenCommit)
  108. require.Equal(t, bs.Height(), block.Header.Height, "expecting the new height to be changed")
  109. incompletePartSet := types.NewPartSetFromHeader(types.PartSetHeader{Total: 2})
  110. uncontiguousPartSet := types.NewPartSetFromHeader(types.PartSetHeader{Total: 0})
  111. uncontiguousPartSet.AddPart(part2, false)
  112. header1 := types.Header{
  113. Height: 1,
  114. NumTxs: 100,
  115. ChainID: "block_test",
  116. Time: time.Now(),
  117. }
  118. header2 := header1
  119. header2.Height = 4
  120. // End of setup, test data
  121. commitAtH10 := &types.Commit{Precommits: []*types.Vote{{Height: 10,
  122. Timestamp: time.Now().UTC()}}}
  123. tuples := []struct {
  124. block *types.Block
  125. parts *types.PartSet
  126. seenCommit *types.Commit
  127. wantErr bool
  128. wantPanic string
  129. corruptBlockInDB bool
  130. corruptCommitInDB bool
  131. corruptSeenCommitInDB bool
  132. eraseCommitInDB bool
  133. eraseSeenCommitInDB bool
  134. }{
  135. {
  136. block: newBlock(&header1, commitAtH10),
  137. parts: validPartSet,
  138. seenCommit: seenCommit1,
  139. },
  140. {
  141. block: nil,
  142. wantPanic: "only save a non-nil block",
  143. },
  144. {
  145. block: newBlock(&header2, commitAtH10),
  146. parts: uncontiguousPartSet,
  147. wantPanic: "only save contiguous blocks", // and incomplete and uncontiguous parts
  148. },
  149. {
  150. block: newBlock(&header1, commitAtH10),
  151. parts: incompletePartSet,
  152. wantPanic: "only save complete block", // incomplete parts
  153. },
  154. {
  155. block: newBlock(&header1, commitAtH10),
  156. parts: validPartSet,
  157. seenCommit: seenCommit1,
  158. corruptCommitInDB: true, // Corrupt the DB's commit entry
  159. wantPanic: "rror reading commit",
  160. },
  161. {
  162. block: newBlock(&header1, commitAtH10),
  163. parts: validPartSet,
  164. seenCommit: seenCommit1,
  165. wantPanic: "rror reading block",
  166. corruptBlockInDB: true, // Corrupt the DB's block entry
  167. },
  168. {
  169. block: newBlock(&header1, commitAtH10),
  170. parts: validPartSet,
  171. seenCommit: seenCommit1,
  172. // Expecting no error and we want a nil back
  173. eraseSeenCommitInDB: true,
  174. },
  175. {
  176. block: newBlock(&header1, commitAtH10),
  177. parts: validPartSet,
  178. seenCommit: seenCommit1,
  179. corruptSeenCommitInDB: true,
  180. wantPanic: "rror reading commit",
  181. },
  182. {
  183. block: newBlock(&header1, commitAtH10),
  184. parts: validPartSet,
  185. seenCommit: seenCommit1,
  186. // Expecting no error and we want a nil back
  187. eraseCommitInDB: true,
  188. },
  189. }
  190. type quad struct {
  191. block *types.Block
  192. commit *types.Commit
  193. meta *types.BlockMeta
  194. seenCommit *types.Commit
  195. }
  196. for i, tuple := range tuples {
  197. bs, db := freshBlockStore()
  198. // SaveBlock
  199. res, err, panicErr := doFn(func() (interface{}, error) {
  200. bs.SaveBlock(tuple.block, tuple.parts, tuple.seenCommit)
  201. if tuple.block == nil {
  202. return nil, nil
  203. }
  204. if tuple.corruptBlockInDB {
  205. db.Set(calcBlockMetaKey(tuple.block.Height), []byte("block-bogus"))
  206. }
  207. bBlock := bs.LoadBlock(tuple.block.Height)
  208. bBlockMeta := bs.LoadBlockMeta(tuple.block.Height)
  209. if tuple.eraseSeenCommitInDB {
  210. db.Delete(calcSeenCommitKey(tuple.block.Height))
  211. }
  212. if tuple.corruptSeenCommitInDB {
  213. db.Set(calcSeenCommitKey(tuple.block.Height), []byte("bogus-seen-commit"))
  214. }
  215. bSeenCommit := bs.LoadSeenCommit(tuple.block.Height)
  216. commitHeight := tuple.block.Height - 1
  217. if tuple.eraseCommitInDB {
  218. db.Delete(calcBlockCommitKey(commitHeight))
  219. }
  220. if tuple.corruptCommitInDB {
  221. db.Set(calcBlockCommitKey(commitHeight), []byte("foo-bogus"))
  222. }
  223. bCommit := bs.LoadBlockCommit(commitHeight)
  224. return &quad{block: bBlock, seenCommit: bSeenCommit, commit: bCommit,
  225. meta: bBlockMeta}, nil
  226. })
  227. if subStr := tuple.wantPanic; subStr != "" {
  228. if panicErr == nil {
  229. t.Errorf("#%d: want a non-nil panic", i)
  230. } else if got := panicErr.Error(); !strings.Contains(got, subStr) {
  231. t.Errorf("#%d:\n\tgotErr: %q\nwant substring: %q", i, got, subStr)
  232. }
  233. continue
  234. }
  235. if tuple.wantErr {
  236. if err == nil {
  237. t.Errorf("#%d: got nil error", i)
  238. }
  239. continue
  240. }
  241. assert.Nil(t, panicErr, "#%d: unexpected panic", i)
  242. assert.Nil(t, err, "#%d: expecting a non-nil error", i)
  243. qua, ok := res.(*quad)
  244. if !ok || qua == nil {
  245. t.Errorf("#%d: got nil quad back; gotType=%T", i, res)
  246. continue
  247. }
  248. if tuple.eraseSeenCommitInDB {
  249. assert.Nil(t, qua.seenCommit,
  250. "erased the seenCommit in the DB hence we should get back a nil seenCommit")
  251. }
  252. if tuple.eraseCommitInDB {
  253. assert.Nil(t, qua.commit,
  254. "erased the commit in the DB hence we should get back a nil commit")
  255. }
  256. }
  257. }
  258. func binarySerializeIt(v interface{}) []byte {
  259. var n int
  260. var err error
  261. buf := new(bytes.Buffer)
  262. wire.WriteBinary(v, buf, &n, &err)
  263. return buf.Bytes()
  264. }
  265. func TestLoadBlockPart(t *testing.T) {
  266. bs, db := freshBlockStore()
  267. height, index := int64(10), 1
  268. loadPart := func() (interface{}, error) {
  269. part := bs.LoadBlockPart(height, index)
  270. return part, nil
  271. }
  272. // Initially no contents.
  273. // 1. Requesting for a non-existent block shouldn't fail
  274. res, _, panicErr := doFn(loadPart)
  275. require.Nil(t, panicErr, "a non-existent block part shouldn't cause a panic")
  276. require.Nil(t, res, "a non-existent block part should return nil")
  277. // 2. Next save a corrupted block then try to load it
  278. db.Set(calcBlockPartKey(height, index), []byte("Tendermint"))
  279. res, _, panicErr = doFn(loadPart)
  280. require.NotNil(t, panicErr, "expecting a non-nil panic")
  281. require.Contains(t, panicErr.Error(), "Error reading block part")
  282. // 3. A good block serialized and saved to the DB should be retrievable
  283. db.Set(calcBlockPartKey(height, index), binarySerializeIt(part1))
  284. gotPart, _, panicErr := doFn(loadPart)
  285. require.Nil(t, panicErr, "an existent and proper block should not panic")
  286. require.Nil(t, res, "a properly saved block should return a proper block")
  287. require.Equal(t, gotPart.(*types.Part).Hash(), part1.Hash(),
  288. "expecting successful retrieval of previously saved block")
  289. }
  290. func TestLoadBlockMeta(t *testing.T) {
  291. bs, db := freshBlockStore()
  292. height := int64(10)
  293. loadMeta := func() (interface{}, error) {
  294. meta := bs.LoadBlockMeta(height)
  295. return meta, nil
  296. }
  297. // Initially no contents.
  298. // 1. Requesting for a non-existent blockMeta shouldn't fail
  299. res, _, panicErr := doFn(loadMeta)
  300. require.Nil(t, panicErr, "a non-existent blockMeta shouldn't cause a panic")
  301. require.Nil(t, res, "a non-existent blockMeta should return nil")
  302. // 2. Next save a corrupted blockMeta then try to load it
  303. db.Set(calcBlockMetaKey(height), []byte("Tendermint-Meta"))
  304. res, _, panicErr = doFn(loadMeta)
  305. require.NotNil(t, panicErr, "expecting a non-nil panic")
  306. require.Contains(t, panicErr.Error(), "Error reading block meta")
  307. // 3. A good blockMeta serialized and saved to the DB should be retrievable
  308. meta := &types.BlockMeta{}
  309. db.Set(calcBlockMetaKey(height), binarySerializeIt(meta))
  310. gotMeta, _, panicErr := doFn(loadMeta)
  311. require.Nil(t, panicErr, "an existent and proper block should not panic")
  312. require.Nil(t, res, "a properly saved blockMeta should return a proper blocMeta ")
  313. require.Equal(t, binarySerializeIt(meta), binarySerializeIt(gotMeta),
  314. "expecting successful retrieval of previously saved blockMeta")
  315. }
  316. func TestBlockFetchAtHeight(t *testing.T) {
  317. state, bs := makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
  318. require.Equal(t, bs.Height(), int64(0), "initially the height should be zero")
  319. block := makeBlock(bs.Height()+1, state)
  320. partSet := block.MakePartSet(2)
  321. seenCommit := &types.Commit{Precommits: []*types.Vote{{Height: 10,
  322. Timestamp: time.Now().UTC()}}}
  323. bs.SaveBlock(block, partSet, seenCommit)
  324. require.Equal(t, bs.Height(), block.Header.Height, "expecting the new height to be changed")
  325. blockAtHeight := bs.LoadBlock(bs.Height())
  326. require.Equal(t, block.Hash(), blockAtHeight.Hash(),
  327. "expecting a successful load of the last saved block")
  328. blockAtHeightPlus1 := bs.LoadBlock(bs.Height() + 1)
  329. require.Nil(t, blockAtHeightPlus1, "expecting an unsuccessful load of Height()+1")
  330. blockAtHeightPlus2 := bs.LoadBlock(bs.Height() + 2)
  331. require.Nil(t, blockAtHeightPlus2, "expecting an unsuccessful load of Height()+2")
  332. }
  333. func doFn(fn func() (interface{}, error)) (res interface{}, err error, panicErr error) {
  334. defer func() {
  335. if r := recover(); r != nil {
  336. switch e := r.(type) {
  337. case error:
  338. panicErr = e
  339. case string:
  340. panicErr = fmt.Errorf("%s", e)
  341. default:
  342. if st, ok := r.(fmt.Stringer); ok {
  343. panicErr = fmt.Errorf("%s", st)
  344. } else {
  345. panicErr = fmt.Errorf("%s", debug.Stack())
  346. }
  347. }
  348. }
  349. }()
  350. res, err = fn()
  351. return res, err, panicErr
  352. }
  353. func newBlock(hdr *types.Header, lastCommit *types.Commit) *types.Block {
  354. return &types.Block{
  355. Header: hdr,
  356. LastCommit: lastCommit,
  357. }
  358. }