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