snapshot_test.go 17 KB

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