backend_test.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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 backend
  17. import (
  18. "bytes"
  19. "crypto/ecdsa"
  20. "math/big"
  21. "sort"
  22. "strings"
  23. "testing"
  24. "time"
  25. "github.com/ethereum/go-ethereum/common"
  26. "github.com/ethereum/go-ethereum/consensus/istanbul"
  27. istanbulcommon "github.com/ethereum/go-ethereum/consensus/istanbul/common"
  28. "github.com/ethereum/go-ethereum/consensus/istanbul/validator"
  29. "github.com/ethereum/go-ethereum/core/types"
  30. "github.com/ethereum/go-ethereum/crypto"
  31. )
  32. func TestSign(t *testing.T) {
  33. b := newBackend()
  34. defer b.Stop()
  35. data := []byte("Here is a string....")
  36. sig, err := b.Sign(data)
  37. if err != nil {
  38. t.Errorf("error mismatch: have %v, want nil", err)
  39. }
  40. //Check signature recover
  41. hashData := crypto.Keccak256(data)
  42. pubkey, _ := crypto.Ecrecover(hashData, sig)
  43. var signer common.Address
  44. copy(signer[:], crypto.Keccak256(pubkey[1:])[12:])
  45. if signer != getAddress() {
  46. t.Errorf("address mismatch: have %v, want %s", signer.Hex(), getAddress().Hex())
  47. }
  48. }
  49. func TestCheckSignature(t *testing.T) {
  50. key, _ := generatePrivateKey()
  51. data := []byte("Here is a string....")
  52. hashData := crypto.Keccak256(data)
  53. sig, _ := crypto.Sign(hashData, key)
  54. b := newBackend()
  55. defer b.Stop()
  56. a := getAddress()
  57. err := b.CheckSignature(data, a, sig)
  58. if err != nil {
  59. t.Errorf("error mismatch: have %v, want nil", err)
  60. }
  61. a = getInvalidAddress()
  62. err = b.CheckSignature(data, a, sig)
  63. if err != istanbulcommon.ErrInvalidSignature {
  64. t.Errorf("error mismatch: have %v, want %v", err, istanbulcommon.ErrInvalidSignature)
  65. }
  66. }
  67. func TestCheckValidatorSignature(t *testing.T) {
  68. vset, keys := newTestValidatorSet(5)
  69. // 1. Positive test: sign with validator's key should succeed
  70. data := []byte("dummy data")
  71. hashData := crypto.Keccak256(data)
  72. for i, k := range keys {
  73. // Sign
  74. sig, err := crypto.Sign(hashData, k)
  75. if err != nil {
  76. t.Errorf("error mismatch: have %v, want nil", err)
  77. }
  78. // CheckValidatorSignature should succeed
  79. addr, err := istanbul.CheckValidatorSignature(vset, data, sig)
  80. if err != nil {
  81. t.Errorf("error mismatch: have %v, want nil", err)
  82. }
  83. validator := vset.GetByIndex(uint64(i))
  84. if addr != validator.Address() {
  85. t.Errorf("validator address mismatch: have %v, want %v", addr, validator.Address())
  86. }
  87. }
  88. // 2. Negative test: sign with any key other than validator's key should return error
  89. key, err := crypto.GenerateKey()
  90. if err != nil {
  91. t.Errorf("error mismatch: have %v, want nil", err)
  92. }
  93. // Sign
  94. sig, err := crypto.Sign(hashData, key)
  95. if err != nil {
  96. t.Errorf("error mismatch: have %v, want nil", err)
  97. }
  98. // CheckValidatorSignature should return ErrUnauthorizedAddress
  99. addr, err := istanbul.CheckValidatorSignature(vset, data, sig)
  100. if err != istanbul.ErrUnauthorizedAddress {
  101. t.Errorf("error mismatch: have %v, want %v", err, istanbul.ErrUnauthorizedAddress)
  102. }
  103. emptyAddr := common.Address{}
  104. if addr != emptyAddr {
  105. t.Errorf("address mismatch: have %v, want %v", addr, emptyAddr)
  106. }
  107. }
  108. func TestCommit(t *testing.T) {
  109. backend := newBackend()
  110. defer backend.Stop()
  111. commitCh := make(chan *types.Block)
  112. // Case: it's a proposer, so the backend.commit will receive channel result from backend.Commit function
  113. testCases := []struct {
  114. expectedErr error
  115. expectedSignature [][]byte
  116. expectedBlock func() *types.Block
  117. }{
  118. {
  119. // normal case
  120. nil,
  121. [][]byte{append([]byte{1}, bytes.Repeat([]byte{0x00}, types.IstanbulExtraSeal-1)...)},
  122. func() *types.Block {
  123. chain, engine := newBlockChain(1, big.NewInt(0))
  124. block := makeBlockWithoutSeal(chain, engine, chain.Genesis())
  125. return updateQBFTBlock(block, engine.Address())
  126. },
  127. },
  128. {
  129. // invalid signature
  130. istanbulcommon.ErrInvalidCommittedSeals,
  131. nil,
  132. func() *types.Block {
  133. chain, engine := newBlockChain(1, big.NewInt(0))
  134. block := makeBlockWithoutSeal(chain, engine, chain.Genesis())
  135. return updateQBFTBlock(block, engine.Address())
  136. },
  137. },
  138. }
  139. for _, test := range testCases {
  140. expBlock := test.expectedBlock()
  141. go func() {
  142. result := <-backend.commitCh
  143. commitCh <- result
  144. }()
  145. backend.proposedBlockHash = expBlock.Hash()
  146. if err := backend.Commit(expBlock, test.expectedSignature, big.NewInt(0)); err != nil {
  147. if err != test.expectedErr {
  148. t.Errorf("error mismatch: have %v, want %v", err, test.expectedErr)
  149. }
  150. }
  151. if test.expectedErr == nil {
  152. // to avoid race condition is occurred by goroutine
  153. select {
  154. case result := <-commitCh:
  155. if result.Hash() != expBlock.Hash() {
  156. t.Errorf("hash mismatch: have %v, want %v", result.Hash(), expBlock.Hash())
  157. }
  158. case <-time.After(10 * time.Second):
  159. t.Fatal("timeout")
  160. }
  161. }
  162. }
  163. }
  164. func TestGetProposer(t *testing.T) {
  165. chain, engine := newBlockChain(1, big.NewInt(0))
  166. defer engine.Stop()
  167. block := makeBlock(chain, engine, chain.Genesis())
  168. chain.InsertChain(types.Blocks{block})
  169. expected := engine.GetProposer(1)
  170. actual := engine.Address()
  171. if actual != expected {
  172. t.Errorf("proposer mismatch: have %v, want %v", actual.Hex(), expected.Hex())
  173. }
  174. }
  175. // TestQBFTTransitionDeadlock test whether a deadlock occurs when testQBFTBlock is set to 1
  176. // This was fixed as part of commit 2a8310663ecafc0233758ca7883676bf568e926e
  177. func TestQBFTTransitionDeadlock(t *testing.T) {
  178. timeout := time.After(1 * time.Minute)
  179. done := make(chan bool)
  180. go func() {
  181. chain, engine := newBlockChain(1, big.NewInt(1))
  182. defer engine.Stop()
  183. // Create an insert a new block into the chain.
  184. block := makeBlock(chain, engine, chain.Genesis())
  185. _, err := chain.InsertChain(types.Blocks{block})
  186. if err != nil {
  187. t.Errorf("Error inserting block: %v", err)
  188. }
  189. if err = engine.NewChainHead(); err != nil {
  190. t.Errorf("Error posting NewChainHead Event: %v", err)
  191. }
  192. if !engine.IsQBFTConsensus() {
  193. t.Errorf("IsQBFTConsensus() should return true after block insertion")
  194. }
  195. done <- true
  196. }()
  197. select {
  198. case <-timeout:
  199. t.Fatal("Deadlock occurred during IBFT to QBFT transition")
  200. case <-done:
  201. }
  202. }
  203. func TestIsQBFTConsensus(t *testing.T) {
  204. chain, engine := newBlockChain(1, big.NewInt(2))
  205. defer engine.Stop()
  206. qbftConsensus := engine.IsQBFTConsensus()
  207. if qbftConsensus {
  208. t.Errorf("IsQBFTConsensus() should return false")
  209. }
  210. // Create an insert a new block into the chain.
  211. block := makeBlock(chain, engine, chain.Genesis())
  212. _, err := chain.InsertChain(types.Blocks{block})
  213. if err != nil {
  214. t.Errorf("Error inserting block: %v", err)
  215. }
  216. if err = engine.NewChainHead(); err != nil {
  217. t.Errorf("Error posting NewChainHead Event: %v", err)
  218. }
  219. secondBlock := makeBlock(chain, engine, block)
  220. _, err = chain.InsertChain(types.Blocks{secondBlock})
  221. if err != nil {
  222. t.Errorf("Error inserting block: %v", err)
  223. }
  224. qbftConsensus = engine.IsQBFTConsensus()
  225. if !qbftConsensus {
  226. t.Errorf("IsQBFTConsensus() should return true after block insertion")
  227. }
  228. }
  229. /**
  230. * SimpleBackend
  231. * Private key: bb047e5940b6d83354d9432db7c449ac8fca2248008aaa7271369880f9f11cc1
  232. * Public key: 04a2bfb0f7da9e1b9c0c64e14f87e8fb82eb0144e97c25fe3a977a921041a50976984d18257d2495e7bfd3d4b280220217f429287d25ecdf2b0d7c0f7aae9aa624
  233. * Address: 0x70524d664ffe731100208a0154e556f9bb679ae6
  234. */
  235. func getAddress() common.Address {
  236. return common.HexToAddress("0x70524d664ffe731100208a0154e556f9bb679ae6")
  237. }
  238. func getInvalidAddress() common.Address {
  239. return common.HexToAddress("0x9535b2e7faaba5288511d89341d94a38063a349b")
  240. }
  241. func generatePrivateKey() (*ecdsa.PrivateKey, error) {
  242. key := "bb047e5940b6d83354d9432db7c449ac8fca2248008aaa7271369880f9f11cc1"
  243. return crypto.HexToECDSA(key)
  244. }
  245. func newTestValidatorSet(n int) (istanbul.ValidatorSet, []*ecdsa.PrivateKey) {
  246. // generate validators
  247. keys := make(Keys, n)
  248. addrs := make([]common.Address, n)
  249. for i := 0; i < n; i++ {
  250. privateKey, _ := crypto.GenerateKey()
  251. keys[i] = privateKey
  252. addrs[i] = crypto.PubkeyToAddress(privateKey.PublicKey)
  253. }
  254. vset := validator.NewSet(addrs, istanbul.NewRoundRobinProposerPolicy())
  255. sort.Sort(keys) //Keys need to be sorted by its public key address
  256. return vset, keys
  257. }
  258. type Keys []*ecdsa.PrivateKey
  259. func (slice Keys) Len() int {
  260. return len(slice)
  261. }
  262. func (slice Keys) Less(i, j int) bool {
  263. return strings.Compare(crypto.PubkeyToAddress(slice[i].PublicKey).String(), crypto.PubkeyToAddress(slice[j].PublicKey).String()) < 0
  264. }
  265. func (slice Keys) Swap(i, j int) {
  266. slice[i], slice[j] = slice[j], slice[i]
  267. }
  268. func newBackend() (b *Backend) {
  269. _, b = newBlockChain(1, big.NewInt(0))
  270. key, _ := generatePrivateKey()
  271. b.privateKey = key
  272. return
  273. }