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
15 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. func randomDuplicateVoteEvidence(ctx context.Context, t *testing.T) *DuplicateVoteEvidence {
  29. t.Helper()
  30. val := NewMockPV()
  31. blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash"))
  32. blockID2 := makeBlockID([]byte("blockhash2"), 1000, []byte("partshash"))
  33. const chainID = "mychain"
  34. return &DuplicateVoteEvidence{
  35. VoteA: makeVote(ctx, t, val, chainID, 0, 10, 2, 1, blockID, defaultVoteTime),
  36. VoteB: makeVote(ctx, t, val, chainID, 0, 10, 2, 1, blockID2, defaultVoteTime.Add(1*time.Minute)),
  37. TotalVotingPower: 30,
  38. ValidatorPower: 10,
  39. Timestamp: defaultVoteTime,
  40. }
  41. }
  42. func TestDuplicateVoteEvidence(t *testing.T) {
  43. const height = int64(13)
  44. ctx, cancel := context.WithCancel(context.Background())
  45. defer cancel()
  46. ev, err := NewMockDuplicateVoteEvidence(ctx, height, time.Now(), "mock-chain-id")
  47. require.NoError(t, err)
  48. assert.Equal(t, ev.Hash(), tmhash.Sum(ev.Bytes()))
  49. assert.NotNil(t, ev.String())
  50. assert.Equal(t, ev.Height(), height)
  51. }
  52. func TestDuplicateVoteEvidenceValidation(t *testing.T) {
  53. val := NewMockPV()
  54. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  55. blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  56. const chainID = "mychain"
  57. ctx, cancel := context.WithCancel(context.Background())
  58. defer cancel()
  59. testCases := []struct {
  60. testName string
  61. malleateEvidence func(*DuplicateVoteEvidence)
  62. expectErr bool
  63. }{
  64. {"Good DuplicateVoteEvidence", func(ev *DuplicateVoteEvidence) {}, false},
  65. {"Nil vote A", func(ev *DuplicateVoteEvidence) { ev.VoteA = nil }, true},
  66. {"Nil vote B", func(ev *DuplicateVoteEvidence) { ev.VoteB = nil }, true},
  67. {"Nil votes", func(ev *DuplicateVoteEvidence) {
  68. ev.VoteA = nil
  69. ev.VoteB = nil
  70. }, true},
  71. {"Invalid vote type", func(ev *DuplicateVoteEvidence) {
  72. ev.VoteA = makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0, blockID2, defaultVoteTime)
  73. }, true},
  74. {"Invalid vote order", func(ev *DuplicateVoteEvidence) {
  75. swap := ev.VoteA.Copy()
  76. ev.VoteA = ev.VoteB.Copy()
  77. ev.VoteB = swap
  78. }, true},
  79. }
  80. for _, tc := range testCases {
  81. tc := tc
  82. t.Run(tc.testName, func(t *testing.T) {
  83. vote1 := makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0x02, blockID, defaultVoteTime)
  84. vote2 := makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0x02, blockID2, defaultVoteTime)
  85. valSet := NewValidatorSet([]*Validator{val.ExtractIntoValidator(ctx, 10)})
  86. ev, err := NewDuplicateVoteEvidence(vote1, vote2, defaultVoteTime, valSet)
  87. require.NoError(t, err)
  88. tc.malleateEvidence(ev)
  89. assert.Equal(t, tc.expectErr, ev.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  90. })
  91. }
  92. }
  93. func TestLightClientAttackEvidenceBasic(t *testing.T) {
  94. ctx, cancel := context.WithCancel(context.Background())
  95. defer cancel()
  96. height := int64(5)
  97. commonHeight := height - 1
  98. nValidators := 10
  99. voteSet, valSet, privVals := randVoteSet(ctx, t, height, 1, tmproto.PrecommitType, nValidators, 1)
  100. header := makeHeaderRandom()
  101. header.Height = height
  102. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  103. commit, err := makeCommit(ctx, blockID, height, 1, voteSet, privVals, defaultVoteTime)
  104. require.NoError(t, err)
  105. lcae := &LightClientAttackEvidence{
  106. ConflictingBlock: &LightBlock{
  107. SignedHeader: &SignedHeader{
  108. Header: header,
  109. Commit: commit,
  110. },
  111. ValidatorSet: valSet,
  112. },
  113. CommonHeight: commonHeight,
  114. TotalVotingPower: valSet.TotalVotingPower(),
  115. Timestamp: header.Time,
  116. ByzantineValidators: valSet.Validators[:nValidators/2],
  117. }
  118. assert.NotNil(t, lcae.String())
  119. assert.NotNil(t, lcae.Hash())
  120. assert.Equal(t, lcae.Height(), commonHeight) // Height should be the common Height
  121. assert.NotNil(t, lcae.Bytes())
  122. // maleate evidence to test hash uniqueness
  123. testCases := []struct {
  124. testName string
  125. malleateEvidence func(*LightClientAttackEvidence)
  126. }{
  127. {"Different header", func(ev *LightClientAttackEvidence) { ev.ConflictingBlock.Header = makeHeaderRandom() }},
  128. {"Different common height", func(ev *LightClientAttackEvidence) {
  129. ev.CommonHeight = height + 1
  130. }},
  131. }
  132. for _, tc := range testCases {
  133. lcae := &LightClientAttackEvidence{
  134. ConflictingBlock: &LightBlock{
  135. SignedHeader: &SignedHeader{
  136. Header: header,
  137. Commit: commit,
  138. },
  139. ValidatorSet: valSet,
  140. },
  141. CommonHeight: commonHeight,
  142. TotalVotingPower: valSet.TotalVotingPower(),
  143. Timestamp: header.Time,
  144. ByzantineValidators: valSet.Validators[:nValidators/2],
  145. }
  146. hash := lcae.Hash()
  147. tc.malleateEvidence(lcae)
  148. assert.NotEqual(t, hash, lcae.Hash(), tc.testName)
  149. }
  150. }
  151. func TestLightClientAttackEvidenceValidation(t *testing.T) {
  152. ctx, cancel := context.WithCancel(context.Background())
  153. defer cancel()
  154. height := int64(5)
  155. commonHeight := height - 1
  156. nValidators := 10
  157. voteSet, valSet, privVals := randVoteSet(ctx, t, height, 1, tmproto.PrecommitType, nValidators, 1)
  158. header := makeHeaderRandom()
  159. header.Height = height
  160. header.ValidatorsHash = valSet.Hash()
  161. blockID := makeBlockID(header.Hash(), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  162. commit, err := makeCommit(ctx, blockID, height, 1, voteSet, privVals, time.Now())
  163. require.NoError(t, err)
  164. lcae := &LightClientAttackEvidence{
  165. ConflictingBlock: &LightBlock{
  166. SignedHeader: &SignedHeader{
  167. Header: header,
  168. Commit: commit,
  169. },
  170. ValidatorSet: valSet,
  171. },
  172. CommonHeight: commonHeight,
  173. TotalVotingPower: valSet.TotalVotingPower(),
  174. Timestamp: header.Time,
  175. ByzantineValidators: valSet.Validators[:nValidators/2],
  176. }
  177. assert.NoError(t, lcae.ValidateBasic())
  178. testCases := []struct {
  179. testName string
  180. malleateEvidence func(*LightClientAttackEvidence)
  181. expectErr bool
  182. }{
  183. {"Good LightClientAttackEvidence", func(ev *LightClientAttackEvidence) {}, false},
  184. {"Negative height", func(ev *LightClientAttackEvidence) { ev.CommonHeight = -10 }, true},
  185. {"Height is greater than divergent block", func(ev *LightClientAttackEvidence) {
  186. ev.CommonHeight = height + 1
  187. }, true},
  188. {"Height is equal to the divergent block", func(ev *LightClientAttackEvidence) {
  189. ev.CommonHeight = height
  190. }, false},
  191. {"Nil conflicting header", func(ev *LightClientAttackEvidence) { ev.ConflictingBlock.Header = nil }, true},
  192. {"Nil conflicting blocl", func(ev *LightClientAttackEvidence) { ev.ConflictingBlock = nil }, true},
  193. {"Nil validator set", func(ev *LightClientAttackEvidence) {
  194. ev.ConflictingBlock.ValidatorSet = &ValidatorSet{}
  195. }, true},
  196. {"Negative total voting power", func(ev *LightClientAttackEvidence) {
  197. ev.TotalVotingPower = -1
  198. }, true},
  199. }
  200. for _, tc := range testCases {
  201. tc := tc
  202. t.Run(tc.testName, func(t *testing.T) {
  203. lcae := &LightClientAttackEvidence{
  204. ConflictingBlock: &LightBlock{
  205. SignedHeader: &SignedHeader{
  206. Header: header,
  207. Commit: commit,
  208. },
  209. ValidatorSet: valSet,
  210. },
  211. CommonHeight: commonHeight,
  212. TotalVotingPower: valSet.TotalVotingPower(),
  213. Timestamp: header.Time,
  214. ByzantineValidators: valSet.Validators[:nValidators/2],
  215. }
  216. tc.malleateEvidence(lcae)
  217. if tc.expectErr {
  218. assert.Error(t, lcae.ValidateBasic(), tc.testName)
  219. } else {
  220. assert.NoError(t, lcae.ValidateBasic(), tc.testName)
  221. }
  222. })
  223. }
  224. }
  225. func TestMockEvidenceValidateBasic(t *testing.T) {
  226. ctx, cancel := context.WithCancel(context.Background())
  227. defer cancel()
  228. goodEvidence, err := NewMockDuplicateVoteEvidence(ctx, int64(1), time.Now(), "mock-chain-id")
  229. require.NoError(t, err)
  230. assert.Nil(t, goodEvidence.ValidateBasic())
  231. }
  232. func makeVote(
  233. ctx context.Context,
  234. t *testing.T, val PrivValidator, chainID string, valIndex int32, height int64, round int32, step int, blockID BlockID,
  235. time time.Time,
  236. ) *Vote {
  237. pubKey, err := val.GetPubKey(ctx)
  238. require.NoError(t, err)
  239. v := &Vote{
  240. ValidatorAddress: pubKey.Address(),
  241. ValidatorIndex: valIndex,
  242. Height: height,
  243. Round: round,
  244. Type: tmproto.SignedMsgType(step),
  245. BlockID: blockID,
  246. Timestamp: time,
  247. }
  248. vpb := v.ToProto()
  249. err = val.SignVote(ctx, chainID, vpb)
  250. require.NoError(t, err)
  251. v.Signature = vpb.Signature
  252. return v
  253. }
  254. func makeHeaderRandom() *Header {
  255. return &Header{
  256. Version: version.Consensus{Block: version.BlockProtocol, App: 1},
  257. ChainID: tmrand.Str(12),
  258. Height: int64(mrand.Uint32() + 1),
  259. Time: time.Now(),
  260. LastBlockID: makeBlockIDRandom(),
  261. LastCommitHash: crypto.CRandBytes(tmhash.Size),
  262. DataHash: crypto.CRandBytes(tmhash.Size),
  263. ValidatorsHash: crypto.CRandBytes(tmhash.Size),
  264. NextValidatorsHash: crypto.CRandBytes(tmhash.Size),
  265. ConsensusHash: crypto.CRandBytes(tmhash.Size),
  266. AppHash: crypto.CRandBytes(tmhash.Size),
  267. LastResultsHash: crypto.CRandBytes(tmhash.Size),
  268. EvidenceHash: crypto.CRandBytes(tmhash.Size),
  269. ProposerAddress: crypto.CRandBytes(crypto.AddressSize),
  270. }
  271. }
  272. func TestEvidenceProto(t *testing.T) {
  273. ctx, cancel := context.WithCancel(context.Background())
  274. defer cancel()
  275. // -------- Votes --------
  276. val := NewMockPV()
  277. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  278. blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  279. const chainID = "mychain"
  280. v := makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime)
  281. v2 := makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, 2, 0x01, blockID2, defaultVoteTime)
  282. tests := []struct {
  283. testName string
  284. evidence Evidence
  285. toProtoErr bool
  286. fromProtoErr bool
  287. }{
  288. {"nil fail", nil, true, true},
  289. {"DuplicateVoteEvidence empty fail", &DuplicateVoteEvidence{}, false, true},
  290. {"DuplicateVoteEvidence nil voteB", &DuplicateVoteEvidence{VoteA: v, VoteB: nil}, false, true},
  291. {"DuplicateVoteEvidence nil voteA", &DuplicateVoteEvidence{VoteA: nil, VoteB: v}, false, true},
  292. {"DuplicateVoteEvidence success", &DuplicateVoteEvidence{VoteA: v2, VoteB: v}, false, false},
  293. }
  294. for _, tt := range tests {
  295. tt := tt
  296. t.Run(tt.testName, func(t *testing.T) {
  297. pb, err := EvidenceToProto(tt.evidence)
  298. if tt.toProtoErr {
  299. assert.Error(t, err, tt.testName)
  300. return
  301. }
  302. assert.NoError(t, err, tt.testName)
  303. evi, err := EvidenceFromProto(pb)
  304. if tt.fromProtoErr {
  305. assert.Error(t, err, tt.testName)
  306. return
  307. }
  308. require.Equal(t, tt.evidence, evi, tt.testName)
  309. })
  310. }
  311. }
  312. func TestEvidenceVectors(t *testing.T) {
  313. ctx, cancel := context.WithCancel(context.Background())
  314. defer cancel()
  315. // Votes for duplicateEvidence
  316. val := NewMockPV()
  317. val.PrivKey = ed25519.GenPrivKeyFromSecret([]byte("it's a secret")) // deterministic key
  318. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  319. blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  320. const chainID = "mychain"
  321. v := makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime)
  322. v2 := makeVote(ctx, t, val, chainID, math.MaxInt32, math.MaxInt64, 2, 0x01, blockID2, defaultVoteTime)
  323. // Data for LightClientAttackEvidence
  324. height := int64(5)
  325. commonHeight := height - 1
  326. nValidators := 10
  327. voteSet, valSet, privVals := deterministicVoteSet(ctx, t, height, 1, tmproto.PrecommitType, 1)
  328. header := &Header{
  329. Version: version.Consensus{Block: 1, App: 1},
  330. ChainID: chainID,
  331. Height: height,
  332. Time: time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC),
  333. LastBlockID: BlockID{},
  334. LastCommitHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  335. DataHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  336. ValidatorsHash: valSet.Hash(),
  337. NextValidatorsHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  338. ConsensusHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  339. AppHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  340. LastResultsHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  341. EvidenceHash: []byte("f2564c78071e26643ae9b3e2a19fa0dc10d4d9e873aa0be808660123f11a1e78"),
  342. ProposerAddress: []byte("2915b7b15f979e48ebc61774bb1d86ba3136b7eb"),
  343. }
  344. blockID3 := makeBlockID(header.Hash(), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  345. commit, err := makeCommit(ctx, blockID3, height, 1, voteSet, privVals, defaultVoteTime)
  346. require.NoError(t, err)
  347. lcae := &LightClientAttackEvidence{
  348. ConflictingBlock: &LightBlock{
  349. SignedHeader: &SignedHeader{
  350. Header: header,
  351. Commit: commit,
  352. },
  353. ValidatorSet: valSet,
  354. },
  355. CommonHeight: commonHeight,
  356. TotalVotingPower: valSet.TotalVotingPower(),
  357. Timestamp: header.Time,
  358. ByzantineValidators: valSet.Validators[:nValidators/2],
  359. }
  360. // assert.NoError(t, lcae.ValidateBasic())
  361. testCases := []struct {
  362. testName string
  363. evList EvidenceList
  364. expBytes string
  365. }{
  366. {"duplicateVoteEvidence",
  367. EvidenceList{&DuplicateVoteEvidence{VoteA: v2, VoteB: v}},
  368. "a9ce28d13bb31001fc3e5b7927051baf98f86abdbd64377643a304164c826923",
  369. },
  370. {"LightClientAttackEvidence",
  371. EvidenceList{lcae},
  372. "2f8782163c3905b26e65823ababc977fe54e97b94e60c0360b1e4726b668bb8e",
  373. },
  374. {"LightClientAttackEvidence & DuplicateVoteEvidence",
  375. EvidenceList{&DuplicateVoteEvidence{VoteA: v2, VoteB: v}, lcae},
  376. "eedb4b47d6dbc9d43f53da8aa50bb826e8d9fc7d897da777c8af6a04aa74163e",
  377. },
  378. }
  379. for _, tc := range testCases {
  380. tc := tc
  381. hash := tc.evList.Hash()
  382. require.Equal(t, tc.expBytes, hex.EncodeToString(hash), tc.testName)
  383. }
  384. }