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