github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dbft/core/testbackend_test.go (about)

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