github.com/hyperion-hyn/go-ethereum@v2.4.0+incompatible/consensus/istanbul/core/testbackend_test.go (about)

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