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.

462 lines
16 KiB

max-bytes PR follow-up (#2318) * ReapMaxTxs: return all txs if max is negative this mirrors ReapMaxBytes behavior See https://github.com/tendermint/tendermint/pull/2184#discussion_r214439950 * increase MaxAminoOverheadForBlock tested with: ``` func TestMaxAminoOverheadForBlock(t *testing.T) { maxChainID := "" for i := 0; i < MaxChainIDLen; i++ { maxChainID += "𠜎" } h := Header{ ChainID: maxChainID, Height: 10, Time: time.Now().UTC(), NumTxs: 100, TotalTxs: 200, LastBlockID: makeBlockID(make([]byte, 20), 300, make([]byte, 20)), LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), DataHash: tmhash.Sum([]byte("data_hash")), ValidatorsHash: tmhash.Sum([]byte("validators_hash")), NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")), ConsensusHash: tmhash.Sum([]byte("consensus_hash")), AppHash: tmhash.Sum([]byte("app_hash")), LastResultsHash: tmhash.Sum([]byte("last_results_hash")), EvidenceHash: tmhash.Sum([]byte("evidence_hash")), ProposerAddress: tmhash.Sum([]byte("proposer_address")), } b := Block{ Header: h, Data: Data{Txs: makeTxs(10000, 100)}, Evidence: EvidenceData{}, LastCommit: &Commit{}, } bz, err := cdc.MarshalBinary(b) require.NoError(t, err) assert.Equal(t, MaxHeaderBytes+MaxAminoOverheadForBlock-2, len(bz)-1000000-20000-1) } ``` * fix MaxYYY constants calculation by using math.MaxInt64 See https://github.com/tendermint/tendermint/pull/2184#discussion_r214444244 * pass mempool filter as an option See https://github.com/tendermint/tendermint/pull/2184#discussion_r214445869 * fixes after Dev's comments
6 years ago
  1. package types
  2. import (
  3. "context"
  4. "encoding/hex"
  5. "math"
  6. mrand "math/rand"
  7. "testing"
  8. "time"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/stretchr/testify/require"
  11. "github.com/tendermint/tendermint/crypto"
  12. "github.com/tendermint/tendermint/crypto/ed25519"
  13. "github.com/tendermint/tendermint/crypto/tmhash"
  14. tmrand "github.com/tendermint/tendermint/libs/rand"
  15. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  16. "github.com/tendermint/tendermint/version"
  17. )
  18. var defaultVoteTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  19. func TestEvidenceList(t *testing.T) {
  20. ctx, cancel := context.WithCancel(context.Background())
  21. defer cancel()
  22. ev := randomDuplicateVoteEvidence(ctx, t)
  23. evl := EvidenceList([]Evidence{ev})
  24. assert.NotNil(t, evl.Hash())
  25. assert.True(t, evl.Has(ev))
  26. assert.False(t, evl.Has(&DuplicateVoteEvidence{}))
  27. }
  28. // TestEvidenceListProtoBuf to ensure parity in protobuf output and input
  29. func TestEvidenceListProtoBuf(t *testing.T) {
  30. ctx, cancel := context.WithCancel(context.Background())
  31. defer cancel()
  32. const chainID = "mychain"
  33. ev, err := NewMockDuplicateVoteEvidence(ctx, math.MaxInt64, time.Now(), chainID)
  34. require.NoError(t, err)
  35. data := EvidenceList{ev}
  36. testCases := []struct {
  37. msg string
  38. data1 *EvidenceList
  39. expPass1 bool
  40. expPass2 bool
  41. }{
  42. {"success", &data, true, true},
  43. {"empty evidenceData", &EvidenceList{}, true, true},
  44. {"fail nil Data", nil, false, false},
  45. }
  46. for _, tc := range testCases {
  47. protoData, err := tc.data1.ToProto()
  48. if tc.expPass1 {
  49. require.NoError(t, err, tc.msg)
  50. } else {
  51. require.Error(t, err, tc.msg)
  52. }
  53. eviD := new(EvidenceList)
  54. err = eviD.FromProto(protoData)
  55. if tc.expPass2 {
  56. require.NoError(t, err, tc.msg)
  57. require.Equal(t, tc.data1, eviD, tc.msg)
  58. } else {
  59. require.Error(t, err, tc.msg)
  60. }
  61. }
  62. }
  63. func randomDuplicateVoteEvidence(ctx context.Context, t *testing.T) *DuplicateVoteEvidence {
  64. t.Helper()
  65. val := NewMockPV()
  66. blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash"))
  67. blockID2 := makeBlockID([]byte("blockhash2"), 1000, []byte("partshash"))
  68. const chainID = "mychain"
  69. return &DuplicateVoteEvidence{
  70. VoteA: makeVote(ctx, t, val, chainID, 0, 10, 2, 1, blockID, defaultVoteTime),
  71. VoteB: makeVote(ctx, t, val, chainID, 0, 10, 2, 1, blockID2, defaultVoteTime.Add(1*time.Minute)),
  72. TotalVotingPower: 30,
  73. ValidatorPower: 10,
  74. Timestamp: defaultVoteTime,
  75. }
  76. }
  77. func TestDuplicateVoteEvidence(t *testing.T) {
  78. const height = int64(13)
  79. ctx, cancel := context.WithCancel(context.Background())
  80. defer cancel()
  81. ev, err := NewMockDuplicateVoteEvidence(ctx, height, time.Now(), "mock-chain-id")
  82. require.NoError(t, err)
  83. assert.Equal(t, ev.Hash(), tmhash.Sum(ev.Bytes()))
  84. assert.NotNil(t, ev.String())
  85. assert.Equal(t, ev.Height(), height)
  86. }
  87. func TestDuplicateVoteEvidenceValidation(t *testing.T) {
  88. val := NewMockPV()
  89. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  90. blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  91. const chainID = "mychain"
  92. ctx, cancel := context.WithCancel(context.Background())
  93. defer cancel()
  94. testCases := []struct {
  95. testName string
  96. malleateEvidence func(*DuplicateVoteEvidence)
  97. expectErr bool
  98. }{
  99. {"Good DuplicateVoteEvidence", func(ev *DuplicateVoteEvidence) {}, false},
  100. {"Nil vote A", func(ev *DuplicateVoteEvidence) { ev.VoteA = nil }, true},
  101. {"Nil vote B", func(ev *DuplicateVoteEvidence) { ev.VoteB = nil }, true},
  102. {"Nil votes", func(ev *DuplicateVoteEvidence) {
  103. ev.VoteA = nil
  104. ev.VoteB = nil
  105. }, true},
  106. {"Invalid vote type", func(ev *DuplicateVoteEvidence) {
  107. ev.VoteA = makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0, blockID2, defaultVoteTime)
  108. }, true},
  109. {"Invalid vote order", func(ev *DuplicateVoteEvidence) {
  110. swap := ev.VoteA.Copy()
  111. ev.VoteA = ev.VoteB.Copy()
  112. ev.VoteB = swap
  113. }, true},
  114. }
  115. for _, tc := range testCases {
  116. tc := tc
  117. t.Run(tc.testName, func(t *testing.T) {
  118. vote1 := makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0x02, blockID, defaultVoteTime)
  119. vote2 := makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0x02, blockID2, defaultVoteTime)
  120. valSet := NewValidatorSet([]*Validator{val.ExtractIntoValidator(ctx, 10)})
  121. ev, err := NewDuplicateVoteEvidence(vote1, vote2, defaultVoteTime, valSet)
  122. require.NoError(t, err)
  123. tc.malleateEvidence(ev)
  124. assert.Equal(t, tc.expectErr, ev.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  125. })
  126. }
  127. }
  128. func TestLightClientAttackEvidenceBasic(t *testing.T) {
  129. ctx, cancel := context.WithCancel(context.Background())
  130. defer cancel()
  131. height := int64(5)
  132. commonHeight := height - 1
  133. nValidators := 10
  134. voteSet, valSet, privVals := randVoteSet(ctx, t, height, 1, tmproto.PrecommitType, nValidators, 1)
  135. header := makeHeaderRandom()
  136. header.Height = height
  137. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  138. commit, err := makeCommit(ctx, blockID, height, 1, voteSet, privVals, defaultVoteTime)
  139. require.NoError(t, err)
  140. lcae := &LightClientAttackEvidence{
  141. ConflictingBlock: &LightBlock{
  142. SignedHeader: &SignedHeader{
  143. Header: header,
  144. Commit: commit,
  145. },
  146. ValidatorSet: valSet,
  147. },
  148. CommonHeight: commonHeight,
  149. TotalVotingPower: valSet.TotalVotingPower(),
  150. Timestamp: header.Time,
  151. ByzantineValidators: valSet.Validators[:nValidators/2],
  152. }
  153. assert.NotNil(t, lcae.String())
  154. assert.NotNil(t, lcae.Hash())
  155. assert.Equal(t, lcae.Height(), commonHeight) // Height should be the common Height
  156. assert.NotNil(t, lcae.Bytes())
  157. // maleate evidence to test hash uniqueness
  158. testCases := []struct {
  159. testName string
  160. malleateEvidence func(*LightClientAttackEvidence)
  161. }{
  162. {"Different header", func(ev *LightClientAttackEvidence) { ev.ConflictingBlock.Header = makeHeaderRandom() }},
  163. {"Different common height", func(ev *LightClientAttackEvidence) {
  164. ev.CommonHeight = height + 1
  165. }},
  166. }
  167. for _, tc := range testCases {
  168. lcae := &LightClientAttackEvidence{
  169. ConflictingBlock: &LightBlock{
  170. SignedHeader: &SignedHeader{
  171. Header: header,
  172. Commit: commit,
  173. },
  174. ValidatorSet: valSet,
  175. },
  176. CommonHeight: commonHeight,
  177. TotalVotingPower: valSet.TotalVotingPower(),
  178. Timestamp: header.Time,
  179. ByzantineValidators: valSet.Validators[:nValidators/2],
  180. }
  181. hash := lcae.Hash()
  182. tc.malleateEvidence(lcae)
  183. assert.NotEqual(t, hash, lcae.Hash(), tc.testName)
  184. }
  185. }
  186. func TestLightClientAttackEvidenceValidation(t *testing.T) {
  187. ctx, cancel := context.WithCancel(context.Background())
  188. defer cancel()
  189. height := int64(5)
  190. commonHeight := height - 1
  191. nValidators := 10
  192. voteSet, valSet, privVals := randVoteSet(ctx, t, height, 1, tmproto.PrecommitType, nValidators, 1)
  193. header := makeHeaderRandom()
  194. header.Height = height
  195. header.ValidatorsHash = valSet.Hash()
  196. blockID := makeBlockID(header.Hash(), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  197. commit, err := makeCommit(ctx, blockID, height, 1, voteSet, privVals, time.Now())
  198. require.NoError(t, err)
  199. lcae := &LightClientAttackEvidence{
  200. ConflictingBlock: &LightBlock{
  201. SignedHeader: &SignedHeader{
  202. Header: header,
  203. Commit: commit,
  204. },
  205. ValidatorSet: valSet,
  206. },
  207. CommonHeight: commonHeight,
  208. TotalVotingPower: valSet.TotalVotingPower(),
  209. Timestamp: header.Time,
  210. ByzantineValidators: valSet.Validators[:nValidators/2],
  211. }
  212. assert.NoError(t, lcae.ValidateBasic())
  213. testCases := []struct {
  214. testName string
  215. malleateEvidence func(*LightClientAttackEvidence)
  216. expectErr bool
  217. }{
  218. {"Good LightClientAttackEvidence", func(ev *LightClientAttackEvidence) {}, false},
  219. {"Negative height", func(ev *LightClientAttackEvidence) { ev.CommonHeight = -10 }, true},
  220. {"Height is greater than divergent block", func(ev *LightClientAttackEvidence) {
  221. ev.CommonHeight = height + 1
  222. }, true},
  223. {"Height is equal to the divergent block", func(ev *LightClientAttackEvidence) {
  224. ev.CommonHeight = height
  225. }, false},
  226. {"Nil conflicting header", func(ev *LightClientAttackEvidence) { ev.ConflictingBlock.Header = nil }, true},
  227. {"Nil conflicting blocl", func(ev *LightClientAttackEvidence) { ev.ConflictingBlock = nil }, true},
  228. {"Nil validator set", func(ev *LightClientAttackEvidence) {
  229. ev.ConflictingBlock.ValidatorSet = &ValidatorSet{}
  230. }, true},
  231. {"Negative total voting power", func(ev *LightClientAttackEvidence) {
  232. ev.TotalVotingPower = -1
  233. }, true},
  234. }
  235. for _, tc := range testCases {
  236. tc := tc
  237. t.Run(tc.testName, func(t *testing.T) {
  238. lcae := &LightClientAttackEvidence{
  239. ConflictingBlock: &LightBlock{
  240. SignedHeader: &SignedHeader{
  241. Header: header,
  242. Commit: commit,
  243. },
  244. ValidatorSet: valSet,
  245. },
  246. CommonHeight: commonHeight,
  247. TotalVotingPower: valSet.TotalVotingPower(),
  248. Timestamp: header.Time,
  249. ByzantineValidators: valSet.Validators[:nValidators/2],
  250. }
  251. tc.malleateEvidence(lcae)
  252. if tc.expectErr {
  253. assert.Error(t, lcae.ValidateBasic(), tc.testName)
  254. } else {
  255. assert.NoError(t, lcae.ValidateBasic(), tc.testName)
  256. }
  257. })
  258. }
  259. }
  260. func TestMockEvidenceValidateBasic(t *testing.T) {
  261. ctx, cancel := context.WithCancel(context.Background())
  262. defer cancel()
  263. goodEvidence, err := NewMockDuplicateVoteEvidence(ctx, int64(1), time.Now(), "mock-chain-id")
  264. require.NoError(t, err)
  265. assert.Nil(t, goodEvidence.ValidateBasic())
  266. }
  267. func makeVote(
  268. ctx context.Context,
  269. t *testing.T, val PrivValidator, chainID string, valIndex int32, height int64, round int32, step int, blockID BlockID,
  270. time time.Time,
  271. ) *Vote {
  272. pubKey, err := val.GetPubKey(ctx)
  273. require.NoError(t, err)
  274. v := &Vote{
  275. ValidatorAddress: pubKey.Address(),
  276. ValidatorIndex: valIndex,
  277. Height: height,
  278. Round: round,
  279. Type: tmproto.SignedMsgType(step),
  280. BlockID: blockID,
  281. Timestamp: time,
  282. }
  283. vpb := v.ToProto()
  284. err = val.SignVote(ctx, chainID, vpb)
  285. require.NoError(t, err)
  286. v.Signature = vpb.Signature
  287. return v
  288. }
  289. func makeHeaderRandom() *Header {
  290. return &Header{
  291. Version: version.Consensus{Block: version.BlockProtocol, App: 1},
  292. ChainID: tmrand.Str(12),
  293. Height: int64(mrand.Uint32() + 1),
  294. Time: time.Now(),
  295. LastBlockID: makeBlockIDRandom(),
  296. LastCommitHash: crypto.CRandBytes(tmhash.Size),
  297. DataHash: crypto.CRandBytes(tmhash.Size),
  298. ValidatorsHash: crypto.CRandBytes(tmhash.Size),
  299. NextValidatorsHash: crypto.CRandBytes(tmhash.Size),
  300. ConsensusHash: crypto.CRandBytes(tmhash.Size),
  301. AppHash: crypto.CRandBytes(tmhash.Size),
  302. LastResultsHash: crypto.CRandBytes(tmhash.Size),
  303. EvidenceHash: crypto.CRandBytes(tmhash.Size),
  304. ProposerAddress: crypto.CRandBytes(crypto.AddressSize),
  305. }
  306. }
  307. func TestEvidenceProto(t *testing.T) {
  308. ctx, cancel := context.WithCancel(context.Background())
  309. defer cancel()
  310. // -------- Votes --------
  311. val := NewMockPV()
  312. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  313. blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  314. const chainID = "mychain"
  315. v := makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime)
  316. v2 := makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, 2, 0x01, blockID2, defaultVoteTime)
  317. tests := []struct {
  318. testName string
  319. evidence Evidence
  320. toProtoErr bool
  321. fromProtoErr bool
  322. }{
  323. {"nil fail", nil, true, true},
  324. {"DuplicateVoteEvidence empty fail", &DuplicateVoteEvidence{}, false, true},
  325. {"DuplicateVoteEvidence nil voteB", &DuplicateVoteEvidence{VoteA: v, VoteB: nil}, false, true},
  326. {"DuplicateVoteEvidence nil voteA", &DuplicateVoteEvidence{VoteA: nil, VoteB: v}, false, true},
  327. {"DuplicateVoteEvidence success", &DuplicateVoteEvidence{VoteA: v2, VoteB: v}, false, false},
  328. }
  329. for _, tt := range tests {
  330. tt := tt
  331. t.Run(tt.testName, func(t *testing.T) {
  332. pb, err := EvidenceToProto(tt.evidence)
  333. if tt.toProtoErr {
  334. assert.Error(t, err, tt.testName)
  335. return
  336. }
  337. assert.NoError(t, err, tt.testName)
  338. evi, err := EvidenceFromProto(pb)
  339. if tt.fromProtoErr {
  340. assert.Error(t, err, tt.testName)
  341. return
  342. }
  343. require.Equal(t, tt.evidence, evi, tt.testName)
  344. })
  345. }
  346. }
  347. func TestEvidenceVectors(t *testing.T) {
  348. ctx, cancel := context.WithCancel(context.Background())
  349. defer cancel()
  350. // Votes for duplicateEvidence
  351. val := NewMockPV()
  352. val.PrivKey = ed25519.GenPrivKeyFromSecret([]byte("it's a secret")) // deterministic key
  353. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  354. blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  355. const chainID = "mychain"
  356. v := makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime)
  357. v2 := makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, 2, 0x01, blockID2, defaultVoteTime)
  358. // Data for LightClientAttackEvidence
  359. height := int64(5)
  360. commonHeight := height - 1
  361. nValidators := 10
  362. voteSet, valSet, privVals := deterministicVoteSet(ctx, t, height, 1, tmproto.PrecommitType, 1)
  363. header := &Header{
  364. Version: version.Consensus{Block: 1, App: 1},
  365. ChainID: chainID,
  366. Height: height,
  367. Time: time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC),
  368. LastBlockID: BlockID{},
  369. LastCommitHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  370. DataHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  371. ValidatorsHash: valSet.Hash(),
  372. NextValidatorsHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  373. ConsensusHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  374. AppHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  375. LastResultsHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  376. EvidenceHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  377. ProposerAddress: []byte("2915b7b15f979e48ebc61774bb1d86ba3136b7eb"),
  378. }
  379. blockID3 := makeBlockID(header.Hash(), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  380. commit, err := makeCommit(ctx, blockID3, height, 1, voteSet, privVals, defaultVoteTime)
  381. require.NoError(t, err)
  382. lcae := &LightClientAttackEvidence{
  383. ConflictingBlock: &LightBlock{
  384. SignedHeader: &SignedHeader{
  385. Header: header,
  386. Commit: commit,
  387. },
  388. ValidatorSet: valSet,
  389. },
  390. CommonHeight: commonHeight,
  391. TotalVotingPower: valSet.TotalVotingPower(),
  392. Timestamp: header.Time,
  393. ByzantineValidators: valSet.Validators[:nValidators/2],
  394. }
  395. // assert.NoError(t, lcae.ValidateBasic())
  396. testCases := []struct {
  397. testName string
  398. evList EvidenceList
  399. expBytes string
  400. }{
  401. {"duplicateVoteEvidence",
  402. EvidenceList{&DuplicateVoteEvidence{VoteA: v2, VoteB: v}},
  403. "a9ce28d13bb31001fc3e5b7927051baf98f86abdbd64377643a304164c826923",
  404. },
  405. {"LightClientAttackEvidence",
  406. EvidenceList{lcae},
  407. "2f8782163c3905b26e65823ababc977fe54e97b94e60c0360b1e4726b668bb8e",
  408. },
  409. {"LightClientAttackEvidence & DuplicateVoteEvidence",
  410. EvidenceList{&DuplicateVoteEvidence{VoteA: v2, VoteB: v}, lcae},
  411. "eedb4b47d6dbc9d43f53da8aa50bb826e8d9fc7d897da777c8af6a04aa74163e",
  412. },
  413. }
  414. for _, tc := range testCases {
  415. tc := tc
  416. hash := tc.evList.Hash()
  417. require.Equal(t, tc.expBytes, hex.EncodeToString(hash), tc.testName)
  418. }
  419. }