github.com/pfcoder/quorum@v2.0.3-0.20180501191142-d4a1b0958135+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.Warn("not sign any data")
   113  	return data, 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.Address{}, 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  // ==============================================
   160  //
   161  // define the struct that need to be provided for integration tests.
   162  
   163  type testSystem struct {
   164  	backends []*testSystemBackend
   165  
   166  	queuedMessage chan istanbul.MessageEvent
   167  	quit          chan struct{}
   168  }
   169  
   170  func newTestSystem(n uint64) *testSystem {
   171  	testLogger.SetHandler(elog.StdoutHandler)
   172  	return &testSystem{
   173  		backends: make([]*testSystemBackend, n),
   174  
   175  		queuedMessage: make(chan istanbul.MessageEvent),
   176  		quit:          make(chan struct{}),
   177  	}
   178  }
   179  
   180  func generateValidators(n int) []common.Address {
   181  	vals := make([]common.Address, 0)
   182  	for i := 0; i < n; i++ {
   183  		privateKey, _ := crypto.GenerateKey()
   184  		vals = append(vals, crypto.PubkeyToAddress(privateKey.PublicKey))
   185  	}
   186  	return vals
   187  }
   188  
   189  func newTestValidatorSet(n int) istanbul.ValidatorSet {
   190  	return validator.NewSet(generateValidators(n), istanbul.RoundRobin)
   191  }
   192  
   193  // FIXME: int64 is needed for N and F
   194  func NewTestSystemWithBackend(n, f uint64) *testSystem {
   195  	testLogger.SetHandler(elog.StdoutHandler)
   196  
   197  	addrs := generateValidators(int(n))
   198  	sys := newTestSystem(n)
   199  	config := istanbul.DefaultConfig
   200  
   201  	for i := uint64(0); i < n; i++ {
   202  		vset := validator.NewSet(addrs, istanbul.RoundRobin)
   203  		backend := sys.NewBackend(i)
   204  		backend.peers = vset
   205  		backend.address = vset.GetByIndex(i).Address()
   206  
   207  		core := New(backend, config).(*core)
   208  		core.state = StateAcceptRequest
   209  		core.current = newRoundState(&istanbul.View{
   210  			Round:    big.NewInt(0),
   211  			Sequence: big.NewInt(1),
   212  		}, vset, common.Hash{}, nil, nil, func(hash common.Hash) bool {
   213  			return false
   214  		})
   215  		core.valSet = vset
   216  		core.logger = testLogger
   217  		core.validateFn = backend.CheckValidatorSignature
   218  
   219  		backend.engine = core
   220  	}
   221  
   222  	return sys
   223  }
   224  
   225  // listen will consume messages from queue and deliver a message to core
   226  func (t *testSystem) listen() {
   227  	for {
   228  		select {
   229  		case <-t.quit:
   230  			return
   231  		case queuedMessage := <-t.queuedMessage:
   232  			testLogger.Info("consuming a queue message...")
   233  			for _, backend := range t.backends {
   234  				go backend.EventMux().Post(queuedMessage)
   235  			}
   236  		}
   237  	}
   238  }
   239  
   240  // Run will start system components based on given flag, and returns a closer
   241  // function that caller can control lifecycle
   242  //
   243  // Given a true for core if you want to initialize core engine.
   244  func (t *testSystem) Run(core bool) func() {
   245  	for _, b := range t.backends {
   246  		if core {
   247  			b.engine.Start() // start Istanbul core
   248  		}
   249  	}
   250  
   251  	go t.listen()
   252  	closer := func() { t.stop(core) }
   253  	return closer
   254  }
   255  
   256  func (t *testSystem) stop(core bool) {
   257  	close(t.quit)
   258  
   259  	for _, b := range t.backends {
   260  		if core {
   261  			b.engine.Stop()
   262  		}
   263  	}
   264  }
   265  
   266  func (t *testSystem) NewBackend(id uint64) *testSystemBackend {
   267  	// assume always success
   268  	ethDB, _ := ethdb.NewMemDatabase()
   269  	backend := &testSystemBackend{
   270  		id:     id,
   271  		sys:    t,
   272  		events: new(event.TypeMux),
   273  		db:     ethDB,
   274  	}
   275  
   276  	t.backends[id] = backend
   277  	return backend
   278  }
   279  
   280  // ==============================================
   281  //
   282  // helper functions.
   283  
   284  func getPublicKeyAddress(privateKey *ecdsa.PrivateKey) common.Address {
   285  	return crypto.PubkeyToAddress(privateKey.PublicKey)
   286  }