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.

425 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. {[]byte(" "), "unmarshal bytes"},
  36. }
  37. for i, tt := range panicCausers {
  38. // Expecting a panic here on trying to parse an invalid blockStore
  39. _, _, panicErr := doFn(func() (interface{}, error) {
  40. db.Set(blockStoreKey, tt.data)
  41. _ = NewBlockStore(db)
  42. return nil, nil
  43. })
  44. require.NotNil(t, panicErr, "#%d panicCauser: %q expected a panic", i, tt.data)
  45. assert.Contains(t, panicErr.Error(), tt.wantErr, "#%d data: %q", i, tt.data)
  46. }
  47. db.Set(blockStoreKey, nil)
  48. bs = NewBlockStore(db)
  49. assert.Equal(t, bs.Height(), int64(0), "expecting nil bytes to be unmarshaled alright")
  50. }
  51. func TestBlockStoreGetReader(t *testing.T) {
  52. db := db.NewMemDB()
  53. // Initial setup
  54. db.Set([]byte("Foo"), []byte("Bar"))
  55. db.Set([]byte("Foo1"), nil)
  56. bs := NewBlockStore(db)
  57. tests := [...]struct {
  58. key []byte
  59. want []byte
  60. }{
  61. 0: {key: []byte("Foo"), want: []byte("Bar")},
  62. 1: {key: []byte("KnoxNonExistent"), want: nil},
  63. 2: {key: []byte("Foo1"), want: nil},
  64. }
  65. for i, tt := range tests {
  66. r := bs.GetReader(tt.key)
  67. if r == nil {
  68. assert.Nil(t, tt.want, "#%d: expected a non-nil reader", i)
  69. continue
  70. }
  71. slurp, err := ioutil.ReadAll(r)
  72. if err != nil {
  73. t.Errorf("#%d: unexpected Read err: %v", i, err)
  74. } else {
  75. assert.Equal(t, slurp, tt.want, "#%d: mismatch", i)
  76. }
  77. }
  78. }
  79. func freshBlockStore() (*BlockStore, db.DB) {
  80. db := db.NewMemDB()
  81. return NewBlockStore(db), db
  82. }
  83. var (
  84. state, _ = makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
  85. block = makeBlock(1, state)
  86. partSet = block.MakePartSet(2)
  87. part1 = partSet.GetPart(0)
  88. part2 = partSet.GetPart(1)
  89. seenCommit1 = &types.Commit{Precommits: []*types.Vote{{Height: 10,
  90. Timestamp: time.Now().UTC()}}}
  91. )
  92. // TODO: This test should be simplified ...
  93. func TestBlockStoreSaveLoadBlock(t *testing.T) {
  94. state, bs := makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
  95. require.Equal(t, bs.Height(), int64(0), "initially the height should be zero")
  96. // check there are no blocks at various heights
  97. noBlockHeights := []int64{0, -1, 100, 1000, 2}
  98. for i, height := range noBlockHeights {
  99. if g := bs.LoadBlock(height); g != nil {
  100. t.Errorf("#%d: height(%d) got a block; want nil", i, height)
  101. }
  102. }
  103. // save a block
  104. block := makeBlock(bs.Height()+1, state)
  105. validPartSet := block.MakePartSet(2)
  106. seenCommit := &types.Commit{Precommits: []*types.Vote{{Height: 10,
  107. Timestamp: time.Now().UTC()}}}
  108. bs.SaveBlock(block, partSet, seenCommit)
  109. require.Equal(t, bs.Height(), block.Header.Height, "expecting the new height to be changed")
  110. incompletePartSet := types.NewPartSetFromHeader(types.PartSetHeader{Total: 2})
  111. uncontiguousPartSet := types.NewPartSetFromHeader(types.PartSetHeader{Total: 0})
  112. uncontiguousPartSet.AddPart(part2, false)
  113. header1 := types.Header{
  114. Height: 1,
  115. NumTxs: 100,
  116. ChainID: "block_test",
  117. Time: time.Now(),
  118. }
  119. header2 := header1
  120. header2.Height = 4
  121. // End of setup, test data
  122. commitAtH10 := &types.Commit{Precommits: []*types.Vote{{Height: 10,
  123. Timestamp: time.Now().UTC()}}}
  124. tuples := []struct {
  125. block *types.Block
  126. parts *types.PartSet
  127. seenCommit *types.Commit
  128. wantErr bool
  129. wantPanic string
  130. corruptBlockInDB bool
  131. corruptCommitInDB bool
  132. corruptSeenCommitInDB bool
  133. eraseCommitInDB bool
  134. eraseSeenCommitInDB bool
  135. }{
  136. {
  137. block: newBlock(&header1, commitAtH10),
  138. parts: validPartSet,
  139. seenCommit: seenCommit1,
  140. },
  141. {
  142. block: nil,
  143. wantPanic: "only save a non-nil block",
  144. },
  145. {
  146. block: newBlock(&header2, commitAtH10),
  147. parts: uncontiguousPartSet,
  148. wantPanic: "only save contiguous blocks", // and incomplete and uncontiguous parts
  149. },
  150. {
  151. block: newBlock(&header1, commitAtH10),
  152. parts: incompletePartSet,
  153. wantPanic: "only save complete block", // incomplete parts
  154. },
  155. {
  156. block: newBlock(&header1, commitAtH10),
  157. parts: validPartSet,
  158. seenCommit: seenCommit1,
  159. corruptCommitInDB: true, // Corrupt the DB's commit entry
  160. wantPanic: "rror reading commit",
  161. },
  162. {
  163. block: newBlock(&header1, commitAtH10),
  164. parts: validPartSet,
  165. seenCommit: seenCommit1,
  166. wantPanic: "rror reading block",
  167. corruptBlockInDB: true, // Corrupt the DB's block entry
  168. },
  169. {
  170. block: newBlock(&header1, commitAtH10),
  171. parts: validPartSet,
  172. seenCommit: seenCommit1,
  173. // Expecting no error and we want a nil back
  174. eraseSeenCommitInDB: true,
  175. },
  176. {
  177. block: newBlock(&header1, commitAtH10),
  178. parts: validPartSet,
  179. seenCommit: seenCommit1,
  180. corruptSeenCommitInDB: true,
  181. wantPanic: "rror reading commit",
  182. },
  183. {
  184. block: newBlock(&header1, commitAtH10),
  185. parts: validPartSet,
  186. seenCommit: seenCommit1,
  187. // Expecting no error and we want a nil back
  188. eraseCommitInDB: true,
  189. },
  190. }
  191. type quad struct {
  192. block *types.Block
  193. commit *types.Commit
  194. meta *types.BlockMeta
  195. seenCommit *types.Commit
  196. }
  197. for i, tuple := range tuples {
  198. bs, db := freshBlockStore()
  199. // SaveBlock
  200. res, err, panicErr := doFn(func() (interface{}, error) {
  201. bs.SaveBlock(tuple.block, tuple.parts, tuple.seenCommit)
  202. if tuple.block == nil {
  203. return nil, nil
  204. }
  205. if tuple.corruptBlockInDB {
  206. db.Set(calcBlockMetaKey(tuple.block.Height), []byte("block-bogus"))
  207. }
  208. bBlock := bs.LoadBlock(tuple.block.Height)
  209. bBlockMeta := bs.LoadBlockMeta(tuple.block.Height)
  210. if tuple.eraseSeenCommitInDB {
  211. db.Delete(calcSeenCommitKey(tuple.block.Height))
  212. }
  213. if tuple.corruptSeenCommitInDB {
  214. db.Set(calcSeenCommitKey(tuple.block.Height), []byte("bogus-seen-commit"))
  215. }
  216. bSeenCommit := bs.LoadSeenCommit(tuple.block.Height)
  217. commitHeight := tuple.block.Height - 1
  218. if tuple.eraseCommitInDB {
  219. db.Delete(calcBlockCommitKey(commitHeight))
  220. }
  221. if tuple.corruptCommitInDB {
  222. db.Set(calcBlockCommitKey(commitHeight), []byte("foo-bogus"))
  223. }
  224. bCommit := bs.LoadBlockCommit(commitHeight)
  225. return &quad{block: bBlock, seenCommit: bSeenCommit, commit: bCommit,
  226. meta: bBlockMeta}, nil
  227. })
  228. if subStr := tuple.wantPanic; subStr != "" {
  229. if panicErr == nil {
  230. t.Errorf("#%d: want a non-nil panic", i)
  231. } else if got := panicErr.Error(); !strings.Contains(got, subStr) {
  232. t.Errorf("#%d:\n\tgotErr: %q\nwant substring: %q", i, got, subStr)
  233. }
  234. continue
  235. }
  236. if tuple.wantErr {
  237. if err == nil {
  238. t.Errorf("#%d: got nil error", i)
  239. }
  240. continue
  241. }
  242. assert.Nil(t, panicErr, "#%d: unexpected panic", i)
  243. assert.Nil(t, err, "#%d: expecting a non-nil error", i)
  244. qua, ok := res.(*quad)
  245. if !ok || qua == nil {
  246. t.Errorf("#%d: got nil quad back; gotType=%T", i, res)
  247. continue
  248. }
  249. if tuple.eraseSeenCommitInDB {
  250. assert.Nil(t, qua.seenCommit,
  251. "erased the seenCommit in the DB hence we should get back a nil seenCommit")
  252. }
  253. if tuple.eraseCommitInDB {
  254. assert.Nil(t, qua.commit,
  255. "erased the commit in the DB hence we should get back a nil commit")
  256. }
  257. }
  258. }
  259. func binarySerializeIt(v interface{}) []byte {
  260. var n int
  261. var err error
  262. buf := new(bytes.Buffer)
  263. wire.WriteBinary(v, buf, &n, &err)
  264. return buf.Bytes()
  265. }
  266. func TestLoadBlockPart(t *testing.T) {
  267. bs, db := freshBlockStore()
  268. height, index := int64(10), 1
  269. loadPart := func() (interface{}, error) {
  270. part := bs.LoadBlockPart(height, index)
  271. return part, nil
  272. }
  273. // Initially no contents.
  274. // 1. Requesting for a non-existent block shouldn't fail
  275. res, _, panicErr := doFn(loadPart)
  276. require.Nil(t, panicErr, "a non-existent block part shouldn't cause a panic")
  277. require.Nil(t, res, "a non-existent block part should return nil")
  278. // 2. Next save a corrupted block then try to load it
  279. db.Set(calcBlockPartKey(height, index), []byte("Tendermint"))
  280. res, _, panicErr = doFn(loadPart)
  281. require.NotNil(t, panicErr, "expecting a non-nil panic")
  282. require.Contains(t, panicErr.Error(), "Error reading block part")
  283. // 3. A good block serialized and saved to the DB should be retrievable
  284. db.Set(calcBlockPartKey(height, index), binarySerializeIt(part1))
  285. gotPart, _, panicErr := doFn(loadPart)
  286. require.Nil(t, panicErr, "an existent and proper block should not panic")
  287. require.Nil(t, res, "a properly saved block should return a proper block")
  288. require.Equal(t, gotPart.(*types.Part).Hash(), part1.Hash(),
  289. "expecting successful retrieval of previously saved block")
  290. }
  291. func TestLoadBlockMeta(t *testing.T) {
  292. bs, db := freshBlockStore()
  293. height := int64(10)
  294. loadMeta := func() (interface{}, error) {
  295. meta := bs.LoadBlockMeta(height)
  296. return meta, nil
  297. }
  298. // Initially no contents.
  299. // 1. Requesting for a non-existent blockMeta shouldn't fail
  300. res, _, panicErr := doFn(loadMeta)
  301. require.Nil(t, panicErr, "a non-existent blockMeta shouldn't cause a panic")
  302. require.Nil(t, res, "a non-existent blockMeta should return nil")
  303. // 2. Next save a corrupted blockMeta then try to load it
  304. db.Set(calcBlockMetaKey(height), []byte("Tendermint-Meta"))
  305. res, _, panicErr = doFn(loadMeta)
  306. require.NotNil(t, panicErr, "expecting a non-nil panic")
  307. require.Contains(t, panicErr.Error(), "Error reading block meta")
  308. // 3. A good blockMeta serialized and saved to the DB should be retrievable
  309. meta := &types.BlockMeta{}
  310. db.Set(calcBlockMetaKey(height), binarySerializeIt(meta))
  311. gotMeta, _, panicErr := doFn(loadMeta)
  312. require.Nil(t, panicErr, "an existent and proper block should not panic")
  313. require.Nil(t, res, "a properly saved blockMeta should return a proper blocMeta ")
  314. require.Equal(t, binarySerializeIt(meta), binarySerializeIt(gotMeta),
  315. "expecting successful retrieval of previously saved blockMeta")
  316. }
  317. func TestBlockFetchAtHeight(t *testing.T) {
  318. state, bs := makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
  319. require.Equal(t, bs.Height(), int64(0), "initially the height should be zero")
  320. block := makeBlock(bs.Height()+1, state)
  321. partSet := block.MakePartSet(2)
  322. seenCommit := &types.Commit{Precommits: []*types.Vote{{Height: 10,
  323. Timestamp: time.Now().UTC()}}}
  324. bs.SaveBlock(block, partSet, seenCommit)
  325. require.Equal(t, bs.Height(), block.Header.Height, "expecting the new height to be changed")
  326. blockAtHeight := bs.LoadBlock(bs.Height())
  327. require.Equal(t, block.Hash(), blockAtHeight.Hash(),
  328. "expecting a successful load of the last saved block")
  329. blockAtHeightPlus1 := bs.LoadBlock(bs.Height() + 1)
  330. require.Nil(t, blockAtHeightPlus1, "expecting an unsuccessful load of Height()+1")
  331. blockAtHeightPlus2 := bs.LoadBlock(bs.Height() + 2)
  332. require.Nil(t, blockAtHeightPlus2, "expecting an unsuccessful load of Height()+2")
  333. }
  334. func doFn(fn func() (interface{}, error)) (res interface{}, err error, panicErr error) {
  335. defer func() {
  336. if r := recover(); r != nil {
  337. switch e := r.(type) {
  338. case error:
  339. panicErr = e
  340. case string:
  341. panicErr = fmt.Errorf("%s", e)
  342. default:
  343. if st, ok := r.(fmt.Stringer); ok {
  344. panicErr = fmt.Errorf("%s", st)
  345. } else {
  346. panicErr = fmt.Errorf("%s", debug.Stack())
  347. }
  348. }
  349. }
  350. }()
  351. res, err = fn()
  352. return res, err, panicErr
  353. }
  354. func newBlock(hdr *types.Header, lastCommit *types.Commit) *types.Block {
  355. return &types.Block{
  356. Header: hdr,
  357. LastCommit: lastCommit,
  358. }
  359. }