snapshot_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. // Copyright 2017 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package clique
  17. import (
  18. "bytes"
  19. "crypto/ecdsa"
  20. "math/big"
  21. "sort"
  22. "testing"
  23. "github.com/ethereum/go-ethereum/common"
  24. "github.com/ethereum/go-ethereum/core"
  25. "github.com/ethereum/go-ethereum/core/rawdb"
  26. "github.com/ethereum/go-ethereum/core/types"
  27. "github.com/ethereum/go-ethereum/core/vm"
  28. "github.com/ethereum/go-ethereum/crypto"
  29. "github.com/ethereum/go-ethereum/params"
  30. )
  31. // testerAccountPool is a pool to maintain currently active tester accounts,
  32. // mapped from textual names used in the tests below to actual Ethereum private
  33. // keys capable of signing transactions.
  34. type testerAccountPool struct {
  35. accounts map[string]*ecdsa.PrivateKey
  36. }
  37. func newTesterAccountPool() *testerAccountPool {
  38. return &testerAccountPool{
  39. accounts: make(map[string]*ecdsa.PrivateKey),
  40. }
  41. }
  42. // checkpoint creates a Clique checkpoint signer section from the provided list
  43. // of authorized signers and embeds it into the provided header.
  44. func (ap *testerAccountPool) checkpoint(header *types.Header, signers []string) {
  45. auths := make([]common.Address, len(signers))
  46. for i, signer := range signers {
  47. auths[i] = ap.address(signer)
  48. }
  49. sort.Sort(signersAscending(auths))
  50. for i, auth := range auths {
  51. copy(header.Extra[extraVanity+i*common.AddressLength:], auth.Bytes())
  52. }
  53. }
  54. // address retrieves the Ethereum address of a tester account by label, creating
  55. // a new account if no previous one exists yet.
  56. func (ap *testerAccountPool) address(account string) common.Address {
  57. // Return the zero account for non-addresses
  58. if account == "" {
  59. return common.Address{}
  60. }
  61. // Ensure we have a persistent key for the account
  62. if ap.accounts[account] == nil {
  63. ap.accounts[account], _ = crypto.GenerateKey()
  64. }
  65. // Resolve and return the Ethereum address
  66. return crypto.PubkeyToAddress(ap.accounts[account].PublicKey)
  67. }
  68. // sign calculates a Clique digital signature for the given block and embeds it
  69. // back into the header.
  70. func (ap *testerAccountPool) sign(header *types.Header, signer string) {
  71. // Ensure we have a persistent key for the signer
  72. if ap.accounts[signer] == nil {
  73. ap.accounts[signer], _ = crypto.GenerateKey()
  74. }
  75. // Sign the header and embed the signature in extra data
  76. sig, _ := crypto.Sign(SealHash(header).Bytes(), ap.accounts[signer])
  77. copy(header.Extra[len(header.Extra)-extraSeal:], sig)
  78. }
  79. // testerVote represents a single block signed by a parcitular account, where
  80. // the account may or may not have cast a Clique vote.
  81. type testerVote struct {
  82. signer string
  83. voted string
  84. auth bool
  85. checkpoint []string
  86. newbatch bool
  87. }
  88. // Tests that Clique signer voting is evaluated correctly for various simple and
  89. // complex scenarios, as well as that a few special corner cases fail correctly.
  90. func TestClique(t *testing.T) {
  91. // Define the various voting scenarios to test
  92. tests := []struct {
  93. epoch uint64
  94. signers []string
  95. votes []testerVote
  96. results []string
  97. failure error
  98. }{
  99. {
  100. // Single signer, no votes cast
  101. signers: []string{"A"},
  102. votes: []testerVote{{signer: "A"}},
  103. results: []string{"A"},
  104. }, {
  105. // Single signer, voting to add two others (only accept first, second needs 2 votes)
  106. signers: []string{"A"},
  107. votes: []testerVote{
  108. {signer: "A", voted: "B", auth: true},
  109. {signer: "B"},
  110. {signer: "A", voted: "C", auth: true},
  111. },
  112. results: []string{"A", "B"},
  113. }, {
  114. // Two signers, voting to add three others (only accept first two, third needs 3 votes already)
  115. signers: []string{"A", "B"},
  116. votes: []testerVote{
  117. {signer: "A", voted: "C", auth: true},
  118. {signer: "B", voted: "C", auth: true},
  119. {signer: "A", voted: "D", auth: true},
  120. {signer: "B", voted: "D", auth: true},
  121. {signer: "C"},
  122. {signer: "A", voted: "E", auth: true},
  123. {signer: "B", voted: "E", auth: true},
  124. },
  125. results: []string{"A", "B", "C", "D"},
  126. }, {
  127. // Single signer, dropping itself (weird, but one less cornercase by explicitly allowing this)
  128. signers: []string{"A"},
  129. votes: []testerVote{
  130. {signer: "A", voted: "A", auth: false},
  131. },
  132. results: []string{},
  133. }, {
  134. // Two signers, actually needing mutual consent to drop either of them (not fulfilled)
  135. signers: []string{"A", "B"},
  136. votes: []testerVote{
  137. {signer: "A", voted: "B", auth: false},
  138. },
  139. results: []string{"A", "B"},
  140. }, {
  141. // Two signers, actually needing mutual consent to drop either of them (fulfilled)
  142. signers: []string{"A", "B"},
  143. votes: []testerVote{
  144. {signer: "A", voted: "B", auth: false},
  145. {signer: "B", voted: "B", auth: false},
  146. },
  147. results: []string{"A"},
  148. }, {
  149. // Three signers, two of them deciding to drop the third
  150. signers: []string{"A", "B", "C"},
  151. votes: []testerVote{
  152. {signer: "A", voted: "C", auth: false},
  153. {signer: "B", voted: "C", auth: false},
  154. },
  155. results: []string{"A", "B"},
  156. }, {
  157. // Four signers, consensus of two not being enough to drop anyone
  158. signers: []string{"A", "B", "C", "D"},
  159. votes: []testerVote{
  160. {signer: "A", voted: "C", auth: false},
  161. {signer: "B", voted: "C", auth: false},
  162. },
  163. results: []string{"A", "B", "C", "D"},
  164. }, {
  165. // Four signers, consensus of three already being enough to drop someone
  166. signers: []string{"A", "B", "C", "D"},
  167. votes: []testerVote{
  168. {signer: "A", voted: "D", auth: false},
  169. {signer: "B", voted: "D", auth: false},
  170. {signer: "C", voted: "D", auth: false},
  171. },
  172. results: []string{"A", "B", "C"},
  173. }, {
  174. // Authorizations are counted once per signer per target
  175. signers: []string{"A", "B"},
  176. votes: []testerVote{
  177. {signer: "A", voted: "C", auth: true},
  178. {signer: "B"},
  179. {signer: "A", voted: "C", auth: true},
  180. {signer: "B"},
  181. {signer: "A", voted: "C", auth: true},
  182. },
  183. results: []string{"A", "B"},
  184. }, {
  185. // Authorizing multiple accounts concurrently is permitted
  186. signers: []string{"A", "B"},
  187. votes: []testerVote{
  188. {signer: "A", voted: "C", auth: true},
  189. {signer: "B"},
  190. {signer: "A", voted: "D", auth: true},
  191. {signer: "B"},
  192. {signer: "A"},
  193. {signer: "B", voted: "D", auth: true},
  194. {signer: "A"},
  195. {signer: "B", voted: "C", auth: true},
  196. },
  197. results: []string{"A", "B", "C", "D"},
  198. }, {
  199. // Deauthorizations are counted once per signer per target
  200. signers: []string{"A", "B"},
  201. votes: []testerVote{
  202. {signer: "A", voted: "B", auth: false},
  203. {signer: "B"},
  204. {signer: "A", voted: "B", auth: false},
  205. {signer: "B"},
  206. {signer: "A", voted: "B", auth: false},
  207. },
  208. results: []string{"A", "B"},
  209. }, {
  210. // Deauthorizing multiple accounts concurrently is permitted
  211. signers: []string{"A", "B", "C", "D"},
  212. votes: []testerVote{
  213. {signer: "A", voted: "C", auth: false},
  214. {signer: "B"},
  215. {signer: "C"},
  216. {signer: "A", voted: "D", auth: false},
  217. {signer: "B"},
  218. {signer: "C"},
  219. {signer: "A"},
  220. {signer: "B", voted: "D", auth: false},
  221. {signer: "C", voted: "D", auth: false},
  222. {signer: "A"},
  223. {signer: "B", voted: "C", auth: false},
  224. },
  225. results: []string{"A", "B"},
  226. }, {
  227. // Votes from deauthorized signers are discarded immediately (deauth votes)
  228. signers: []string{"A", "B", "C"},
  229. votes: []testerVote{
  230. {signer: "C", voted: "B", auth: false},
  231. {signer: "A", voted: "C", auth: false},
  232. {signer: "B", voted: "C", auth: false},
  233. {signer: "A", voted: "B", auth: false},
  234. },
  235. results: []string{"A", "B"},
  236. }, {
  237. // Votes from deauthorized signers are discarded immediately (auth votes)
  238. signers: []string{"A", "B", "C"},
  239. votes: []testerVote{
  240. {signer: "C", voted: "D", auth: true},
  241. {signer: "A", voted: "C", auth: false},
  242. {signer: "B", voted: "C", auth: false},
  243. {signer: "A", voted: "D", auth: true},
  244. },
  245. results: []string{"A", "B"},
  246. }, {
  247. // Cascading changes are not allowed, only the account being voted on may change
  248. signers: []string{"A", "B", "C", "D"},
  249. votes: []testerVote{
  250. {signer: "A", voted: "C", auth: false},
  251. {signer: "B"},
  252. {signer: "C"},
  253. {signer: "A", voted: "D", auth: false},
  254. {signer: "B", voted: "C", auth: false},
  255. {signer: "C"},
  256. {signer: "A"},
  257. {signer: "B", voted: "D", auth: false},
  258. {signer: "C", voted: "D", auth: false},
  259. },
  260. results: []string{"A", "B", "C"},
  261. }, {
  262. // Changes reaching consensus out of bounds (via a deauth) execute on touch
  263. signers: []string{"A", "B", "C", "D"},
  264. votes: []testerVote{
  265. {signer: "A", voted: "C", auth: false},
  266. {signer: "B"},
  267. {signer: "C"},
  268. {signer: "A", voted: "D", auth: false},
  269. {signer: "B", voted: "C", auth: false},
  270. {signer: "C"},
  271. {signer: "A"},
  272. {signer: "B", voted: "D", auth: false},
  273. {signer: "C", voted: "D", auth: false},
  274. {signer: "A"},
  275. {signer: "C", voted: "C", auth: true},
  276. },
  277. results: []string{"A", "B"},
  278. }, {
  279. // Changes reaching consensus out of bounds (via a deauth) may go out of consensus on first touch
  280. signers: []string{"A", "B", "C", "D"},
  281. votes: []testerVote{
  282. {signer: "A", voted: "C", auth: false},
  283. {signer: "B"},
  284. {signer: "C"},
  285. {signer: "A", voted: "D", auth: false},
  286. {signer: "B", voted: "C", auth: false},
  287. {signer: "C"},
  288. {signer: "A"},
  289. {signer: "B", voted: "D", auth: false},
  290. {signer: "C", voted: "D", auth: false},
  291. {signer: "A"},
  292. {signer: "B", voted: "C", auth: true},
  293. },
  294. results: []string{"A", "B", "C"},
  295. }, {
  296. // Ensure that pending votes don't survive authorization status changes. This
  297. // corner case can only appear if a signer is quickly added, removed and then
  298. // re-added (or the inverse), while one of the original voters dropped. If a
  299. // past vote is left cached in the system somewhere, this will interfere with
  300. // the final signer outcome.
  301. signers: []string{"A", "B", "C", "D", "E"},
  302. votes: []testerVote{
  303. {signer: "A", voted: "F", auth: true}, // Authorize F, 3 votes needed
  304. {signer: "B", voted: "F", auth: true},
  305. {signer: "C", voted: "F", auth: true},
  306. {signer: "D", voted: "F", auth: false}, // Deauthorize F, 4 votes needed (leave A's previous vote "unchanged")
  307. {signer: "E", voted: "F", auth: false},
  308. {signer: "B", voted: "F", auth: false},
  309. {signer: "C", voted: "F", auth: false},
  310. {signer: "D", voted: "F", auth: true}, // Almost authorize F, 2/3 votes needed
  311. {signer: "E", voted: "F", auth: true},
  312. {signer: "B", voted: "A", auth: false}, // Deauthorize A, 3 votes needed
  313. {signer: "C", voted: "A", auth: false},
  314. {signer: "D", voted: "A", auth: false},
  315. {signer: "B", voted: "F", auth: true}, // Finish authorizing F, 3/3 votes needed
  316. },
  317. results: []string{"B", "C", "D", "E", "F"},
  318. }, {
  319. // Epoch transitions reset all votes to allow chain checkpointing
  320. epoch: 3,
  321. signers: []string{"A", "B"},
  322. votes: []testerVote{
  323. {signer: "A", voted: "C", auth: true},
  324. {signer: "B"},
  325. {signer: "A", checkpoint: []string{"A", "B"}},
  326. {signer: "B", voted: "C", auth: true},
  327. },
  328. results: []string{"A", "B"},
  329. }, {
  330. // An unauthorized signer should not be able to sign blocks
  331. signers: []string{"A"},
  332. votes: []testerVote{
  333. {signer: "B"},
  334. },
  335. failure: errUnauthorizedSigner,
  336. }, {
  337. // An authorized signer that signed recently should not be able to sign again
  338. signers: []string{"A", "B"},
  339. votes: []testerVote{
  340. {signer: "A"},
  341. {signer: "A"},
  342. },
  343. failure: errRecentlySigned,
  344. }, {
  345. // Recent signatures should not reset on checkpoint blocks imported in a batch
  346. epoch: 3,
  347. signers: []string{"A", "B", "C"},
  348. votes: []testerVote{
  349. {signer: "A"},
  350. {signer: "B"},
  351. {signer: "A", checkpoint: []string{"A", "B", "C"}},
  352. {signer: "A"},
  353. },
  354. failure: errRecentlySigned,
  355. }, {
  356. // Recent signatures should not reset on checkpoint blocks imported in a new
  357. // batch (https://github.com/ethereum/go-ethereum/issues/17593). Whilst this
  358. // seems overly specific and weird, it was a Rinkeby consensus split.
  359. epoch: 3,
  360. signers: []string{"A", "B", "C"},
  361. votes: []testerVote{
  362. {signer: "A"},
  363. {signer: "B"},
  364. {signer: "A", checkpoint: []string{"A", "B", "C"}},
  365. {signer: "A", newbatch: true},
  366. },
  367. failure: errRecentlySigned,
  368. },
  369. }
  370. // Run through the scenarios and test them
  371. for i, tt := range tests {
  372. // Create the account pool and generate the initial set of signers
  373. accounts := newTesterAccountPool()
  374. signers := make([]common.Address, len(tt.signers))
  375. for j, signer := range tt.signers {
  376. signers[j] = accounts.address(signer)
  377. }
  378. for j := 0; j < len(signers); j++ {
  379. for k := j + 1; k < len(signers); k++ {
  380. if bytes.Compare(signers[j][:], signers[k][:]) > 0 {
  381. signers[j], signers[k] = signers[k], signers[j]
  382. }
  383. }
  384. }
  385. // Create the genesis block with the initial set of signers
  386. genesis := &core.Genesis{
  387. ExtraData: make([]byte, extraVanity+common.AddressLength*len(signers)+extraSeal),
  388. BaseFee: big.NewInt(params.InitialBaseFee),
  389. }
  390. for j, signer := range signers {
  391. copy(genesis.ExtraData[extraVanity+j*common.AddressLength:], signer[:])
  392. }
  393. // Create a pristine blockchain with the genesis injected
  394. db := rawdb.NewMemoryDatabase()
  395. genesisBlock := genesis.MustCommit(db)
  396. // Assemble a chain of headers from the cast votes
  397. config := *params.TestChainConfig
  398. config.Clique = &params.CliqueConfig{
  399. Period: 1,
  400. Epoch: tt.epoch,
  401. }
  402. engine := New(config.Clique, db)
  403. engine.fakeDiff = true
  404. blocks, _ := core.GenerateChain(&config, genesisBlock, engine, db, len(tt.votes), func(j int, gen *core.BlockGen) {
  405. // Cast the vote contained in this block
  406. gen.SetCoinbase(accounts.address(tt.votes[j].voted))
  407. if tt.votes[j].auth {
  408. var nonce types.BlockNonce
  409. copy(nonce[:], nonceAuthVote)
  410. gen.SetNonce(nonce)
  411. }
  412. })
  413. // Iterate through the blocks and seal them individually
  414. for j, block := range blocks {
  415. // Get the header and prepare it for signing
  416. header := block.Header()
  417. if j > 0 {
  418. header.ParentHash = blocks[j-1].Hash()
  419. }
  420. header.Extra = make([]byte, extraVanity+extraSeal)
  421. if auths := tt.votes[j].checkpoint; auths != nil {
  422. header.Extra = make([]byte, extraVanity+len(auths)*common.AddressLength+extraSeal)
  423. accounts.checkpoint(header, auths)
  424. }
  425. header.Difficulty = diffInTurn // Ignored, we just need a valid number
  426. // Generate the signature, embed it into the header and the block
  427. accounts.sign(header, tt.votes[j].signer)
  428. blocks[j] = block.WithSeal(header)
  429. }
  430. // Split the blocks up into individual import batches (cornercase testing)
  431. batches := [][]*types.Block{nil}
  432. for j, block := range blocks {
  433. if tt.votes[j].newbatch {
  434. batches = append(batches, nil)
  435. }
  436. batches[len(batches)-1] = append(batches[len(batches)-1], block)
  437. }
  438. // Pass all the headers through clique and ensure tallying succeeds
  439. chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil, nil)
  440. if err != nil {
  441. t.Errorf("test %d: failed to create test chain: %v", i, err)
  442. continue
  443. }
  444. failed := false
  445. for j := 0; j < len(batches)-1; j++ {
  446. if k, err := chain.InsertChain(batches[j]); err != nil {
  447. t.Errorf("test %d: failed to import batch %d, block %d: %v", i, j, k, err)
  448. failed = true
  449. break
  450. }
  451. }
  452. if failed {
  453. continue
  454. }
  455. if _, err = chain.InsertChain(batches[len(batches)-1]); err != tt.failure {
  456. t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure)
  457. }
  458. if tt.failure != nil {
  459. continue
  460. }
  461. // No failure was produced or requested, generate the final voting snapshot
  462. head := blocks[len(blocks)-1]
  463. snap, err := engine.snapshot(chain, head.NumberU64(), head.Hash(), nil)
  464. if err != nil {
  465. t.Errorf("test %d: failed to retrieve voting snapshot: %v", i, err)
  466. continue
  467. }
  468. // Verify the final list of signers against the expected ones
  469. signers = make([]common.Address, len(tt.results))
  470. for j, signer := range tt.results {
  471. signers[j] = accounts.address(signer)
  472. }
  473. for j := 0; j < len(signers); j++ {
  474. for k := j + 1; k < len(signers); k++ {
  475. if bytes.Compare(signers[j][:], signers[k][:]) > 0 {
  476. signers[j], signers[k] = signers[k], signers[j]
  477. }
  478. }
  479. }
  480. result := snap.signers()
  481. if len(result) != len(signers) {
  482. t.Errorf("test %d: signers mismatch: have %x, want %x", i, result, signers)
  483. continue
  484. }
  485. for j := 0; j < len(result); j++ {
  486. if !bytes.Equal(result[j][:], signers[j][:]) {
  487. t.Errorf("test %d, signer %d: signer mismatch: have %x, want %x", i, j, result[j], signers[j])
  488. }
  489. }
  490. }
  491. }