testbackend_test.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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 core
  17. import (
  18. "crypto/ecdsa"
  19. "math/big"
  20. "time"
  21. "github.com/ethereum/go-ethereum/common"
  22. "github.com/ethereum/go-ethereum/consensus/istanbul"
  23. ibfttypes "github.com/ethereum/go-ethereum/consensus/istanbul/ibft/types"
  24. "github.com/ethereum/go-ethereum/consensus/istanbul/validator"
  25. "github.com/ethereum/go-ethereum/core/rawdb"
  26. "github.com/ethereum/go-ethereum/crypto"
  27. "github.com/ethereum/go-ethereum/ethdb"
  28. "github.com/ethereum/go-ethereum/event"
  29. elog "github.com/ethereum/go-ethereum/log"
  30. )
  31. var testLogger = elog.New()
  32. type testSystemBackend struct {
  33. id uint64
  34. sys *testSystem
  35. engine *core
  36. peers istanbul.ValidatorSet
  37. events *event.TypeMux
  38. committedMsgs []testCommittedMsgs
  39. sentMsgs [][]byte // store the message when Send is called by core
  40. address common.Address
  41. db ethdb.Database
  42. }
  43. type testCommittedMsgs struct {
  44. commitProposal istanbul.Proposal
  45. committedSeals [][]byte
  46. }
  47. // ==============================================
  48. //
  49. // define the functions that needs to be provided for Istanbul.
  50. func (self *testSystemBackend) Address() common.Address {
  51. return self.address
  52. }
  53. // Peers returns all connected peers
  54. func (self *testSystemBackend) Validators(proposal istanbul.Proposal) istanbul.ValidatorSet {
  55. return self.peers
  56. }
  57. func (self *testSystemBackend) EventMux() *event.TypeMux {
  58. return self.events
  59. }
  60. func (self *testSystemBackend) Send(message []byte, code uint64, target common.Address) error {
  61. testLogger.Info("enqueuing a message...", "address", self.Address())
  62. self.sentMsgs = append(self.sentMsgs, message)
  63. self.sys.queuedMessage <- istanbul.MessageEvent{
  64. Code: code,
  65. Payload: message,
  66. }
  67. return nil
  68. }
  69. func (self *testSystemBackend) Broadcast(valSet istanbul.ValidatorSet, code uint64, message []byte) error {
  70. testLogger.Info("enqueuing a message...", "address", self.Address())
  71. self.sentMsgs = append(self.sentMsgs, message)
  72. self.sys.queuedMessage <- istanbul.MessageEvent{
  73. Code: code,
  74. Payload: message,
  75. }
  76. return nil
  77. }
  78. func (self *testSystemBackend) Gossip(valSet istanbul.ValidatorSet, code uint64, message []byte) error {
  79. testLogger.Warn("not sign any data")
  80. return nil
  81. }
  82. func (self *testSystemBackend) Commit(proposal istanbul.Proposal, seals [][]byte, round *big.Int) error {
  83. testLogger.Info("commit message", "address", self.Address())
  84. self.committedMsgs = append(self.committedMsgs, testCommittedMsgs{
  85. commitProposal: proposal,
  86. committedSeals: seals,
  87. })
  88. // fake new head events
  89. go self.events.Post(istanbul.FinalCommittedEvent{})
  90. return nil
  91. }
  92. func (self *testSystemBackend) Verify(proposal istanbul.Proposal) (time.Duration, error) {
  93. return 0, nil
  94. }
  95. func (self *testSystemBackend) Sign(data []byte) ([]byte, error) {
  96. testLogger.Info("returning current backend address so that CheckValidatorSignature returns the same value")
  97. return self.address.Bytes(), nil
  98. }
  99. func (self *testSystemBackend) SignWithoutHashing(data []byte) ([]byte, error) {
  100. testLogger.Info("returning current backend address so that CheckValidatorSignature returns the same value")
  101. return self.address.Bytes(), nil
  102. }
  103. func (self *testSystemBackend) CheckSignature([]byte, common.Address, []byte) error {
  104. return nil
  105. }
  106. func (self *testSystemBackend) CheckValidatorSignature(data []byte, sig []byte) (common.Address, error) {
  107. return common.BytesToAddress(sig), nil
  108. }
  109. func (self *testSystemBackend) Hash(b interface{}) common.Hash {
  110. return common.StringToHash("Test")
  111. }
  112. func (self *testSystemBackend) NewRequest(request istanbul.Proposal) {
  113. go self.events.Post(istanbul.RequestEvent{
  114. Proposal: request,
  115. })
  116. }
  117. func (self *testSystemBackend) HasBadProposal(hash common.Hash) bool {
  118. return false
  119. }
  120. func (self *testSystemBackend) LastProposal() (istanbul.Proposal, common.Address) {
  121. l := len(self.committedMsgs)
  122. if l > 0 {
  123. return self.committedMsgs[l-1].commitProposal, common.Address{}
  124. }
  125. return makeBlock(0), common.Address{}
  126. }
  127. // Only block height 5 will return true
  128. func (self *testSystemBackend) HasPropsal(hash common.Hash, number *big.Int) bool {
  129. return number.Cmp(big.NewInt(5)) == 0
  130. }
  131. func (self *testSystemBackend) GetProposer(number uint64) common.Address {
  132. return common.Address{}
  133. }
  134. func (self *testSystemBackend) ParentValidators(proposal istanbul.Proposal) istanbul.ValidatorSet {
  135. return self.peers
  136. }
  137. func (sb *testSystemBackend) Close() error {
  138. return nil
  139. }
  140. func (sb *testSystemBackend) IsQBFTConsensusAt(*big.Int) bool {
  141. return false
  142. }
  143. func (sb *testSystemBackend) StartQBFTConsensus() error {
  144. return nil
  145. }
  146. // ==============================================
  147. //
  148. // define the struct that need to be provided for integration tests.
  149. type testSystem struct {
  150. backends []*testSystemBackend
  151. queuedMessage chan istanbul.MessageEvent
  152. quit chan struct{}
  153. }
  154. func newTestSystem(n uint64) *testSystem {
  155. testLogger.SetHandler(elog.StdoutHandler)
  156. return &testSystem{
  157. backends: make([]*testSystemBackend, n),
  158. queuedMessage: make(chan istanbul.MessageEvent),
  159. quit: make(chan struct{}),
  160. }
  161. }
  162. func generateValidators(n int) []common.Address {
  163. vals := make([]common.Address, 0)
  164. for i := 0; i < n; i++ {
  165. privateKey, _ := crypto.GenerateKey()
  166. vals = append(vals, crypto.PubkeyToAddress(privateKey.PublicKey))
  167. }
  168. return vals
  169. }
  170. func newTestValidatorSet(n int) istanbul.ValidatorSet {
  171. return validator.NewSet(generateValidators(n), istanbul.NewRoundRobinProposerPolicy())
  172. }
  173. // FIXME: int64 is needed for N and F
  174. func NewTestSystemWithBackend(n, f uint64) *testSystem {
  175. testLogger.SetHandler(elog.StdoutHandler)
  176. addrs := generateValidators(int(n))
  177. sys := newTestSystem(n)
  178. config := istanbul.DefaultConfig
  179. for i := uint64(0); i < n; i++ {
  180. vset := validator.NewSet(addrs, istanbul.NewRoundRobinProposerPolicy())
  181. backend := sys.NewBackend(i)
  182. backend.peers = vset
  183. backend.address = vset.GetByIndex(i).Address()
  184. core := New(backend, config)
  185. core.state = ibfttypes.StateAcceptRequest
  186. core.current = newRoundState(&istanbul.View{
  187. Round: big.NewInt(0),
  188. Sequence: big.NewInt(1),
  189. }, vset, common.Hash{}, nil, nil, func(hash common.Hash) bool {
  190. return false
  191. })
  192. core.valSet = vset
  193. core.logger = testLogger
  194. core.validateFn = backend.CheckValidatorSignature
  195. backend.engine = core
  196. }
  197. return sys
  198. }
  199. // listen will consume messages from queue and deliver a message to core
  200. func (t *testSystem) listen() {
  201. for {
  202. select {
  203. case <-t.quit:
  204. return
  205. case queuedMessage := <-t.queuedMessage:
  206. testLogger.Info("consuming a queue message...")
  207. for _, backend := range t.backends {
  208. go backend.EventMux().Post(queuedMessage)
  209. }
  210. }
  211. }
  212. }
  213. // Run will start system components based on given flag, and returns a closer
  214. // function that caller can control lifecycle
  215. //
  216. // Given a true for core if you want to initialize core engine.
  217. func (t *testSystem) Run(core bool) func() {
  218. for _, b := range t.backends {
  219. if core {
  220. b.engine.Start() // start Istanbul core
  221. }
  222. }
  223. go t.listen()
  224. closer := func() { t.stop(core) }
  225. return closer
  226. }
  227. func (t *testSystem) stop(core bool) {
  228. close(t.quit)
  229. for _, b := range t.backends {
  230. if core {
  231. b.engine.Stop()
  232. }
  233. }
  234. }
  235. func (t *testSystem) NewBackend(id uint64) *testSystemBackend {
  236. // assume always success
  237. ethDB := rawdb.NewMemoryDatabase()
  238. backend := &testSystemBackend{
  239. id: id,
  240. sys: t,
  241. events: new(event.TypeMux),
  242. db: ethDB,
  243. }
  244. t.backends[id] = backend
  245. return backend
  246. }
  247. // ==============================================
  248. //
  249. // helper functions.
  250. func getPublicKeyAddress(privateKey *ecdsa.PrivateKey) common.Address {
  251. return crypto.PubkeyToAddress(privateKey.PublicKey)
  252. }