github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/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  	"github.com/bigzoro/my_simplechain/consensus"
    22  	"github.com/bigzoro/my_simplechain/core/types"
    23  	"math/big"
    24  	"time"
    25  
    26  	"github.com/bigzoro/my_simplechain/common"
    27  	"github.com/bigzoro/my_simplechain/consensus/pbft"
    28  	"github.com/bigzoro/my_simplechain/consensus/pbft/validator"
    29  	"github.com/bigzoro/my_simplechain/core/rawdb"
    30  	"github.com/bigzoro/my_simplechain/crypto"
    31  	"github.com/bigzoro/my_simplechain/ethdb"
    32  	"github.com/bigzoro/my_simplechain/event"
    33  	elog "github.com/bigzoro/my_simplechain/log"
    34  )
    35  
    36  var testLogger = elog.New()
    37  
    38  type testSystemBackend struct {
    39  	id  uint64
    40  	sys *testSystem
    41  
    42  	engine Engine
    43  	peers  pbft.ValidatorSet
    44  	events *event.TypeMux
    45  
    46  	committedMsgs []testCommittedMsgs
    47  	sentMsgs      [][]byte // store the message when Send is called by core
    48  
    49  	address common.Address
    50  	db      ethdb.Database
    51  	filled  bool
    52  	txpool  *testSystemTxPool
    53  }
    54  
    55  func (self *testSystemBackend) BroadcastMsg(ps map[common.Address]consensus.Peer, hash common.Hash, message []byte) error {
    56  	testLogger.Info("enqueuing a message...", "address", self.Address())
    57  	self.sentMsgs = append(self.sentMsgs, message)
    58  	self.sys.queuedMessage <- pbft.MessageEvent{
    59  		Payload: message,
    60  	}
    61  	return nil
    62  }
    63  
    64  func (self *testSystemBackend) GetForwardNodes(validators pbft.Validators) (map[common.Address]consensus.Peer, []common.Address) {
    65  	return nil, nil
    66  }
    67  
    68  func (self *testSystemBackend) FillLightProposal(proposal pbft.LightProposal) (bool, []types.MissedTx, error) {
    69  	lb := proposal.(*types.LightBlock)
    70  	*lb.Transactions() = make(types.Transactions, len(lb.TxDigests()))
    71  
    72  	if self.txpool != nil {
    73  		fiiled := self.txpool.InitLightBlock(lb)
    74  		return fiiled, lb.MissedTxs, nil
    75  	}
    76  	return true, nil, nil
    77  }
    78  
    79  type testCommittedMsgs struct {
    80  	commitProposal pbft.Conclusion
    81  	committedSeals [][]byte
    82  }
    83  
    84  // ==============================================
    85  //
    86  // define the functions that needs to be provided for Istanbul.
    87  
    88  func (self *testSystemBackend) Address() common.Address {
    89  	return self.address
    90  }
    91  
    92  // Peers returns all connected peers
    93  func (self *testSystemBackend) Validators(proposal pbft.Conclusion) pbft.ValidatorSet {
    94  	return self.peers
    95  }
    96  
    97  func (self *testSystemBackend) EventMux() *event.TypeMux {
    98  	return self.events
    99  }
   100  
   101  func (self *testSystemBackend) SendMsg(val pbft.Validators, message []byte) error {
   102  	self.sys.sendMessage <- targetMessage{msg: pbft.MessageEvent{
   103  		Payload: message,
   104  	}, vals: val}
   105  	return nil
   106  }
   107  
   108  func (self *testSystemBackend) Broadcast(valSet pbft.ValidatorSet, sender common.Address, message []byte) error {
   109  	testLogger.Info("enqueuing a message...", "address", self.Address())
   110  	self.sentMsgs = append(self.sentMsgs, message)
   111  	self.sys.queuedMessage <- pbft.MessageEvent{
   112  		Payload: message,
   113  	}
   114  	return nil
   115  }
   116  
   117  func (self *testSystemBackend) Post(payload []byte) {
   118  	testLogger.Warn("not sign any data")
   119  }
   120  
   121  func (self *testSystemBackend) Gossip(valSet pbft.ValidatorSet, message []byte) {
   122  	testLogger.Warn("not sign any data")
   123  }
   124  
   125  func (self *testSystemBackend) Guidance(valSet pbft.ValidatorSet, sender common.Address, message []byte) {
   126  	testLogger.Warn("not sign any data")
   127  }
   128  
   129  func (self *testSystemBackend) Commit(proposal pbft.Conclusion, seals [][]byte) error {
   130  	testLogger.Info("commit message", "address", self.Address())
   131  	self.committedMsgs = append(self.committedMsgs, testCommittedMsgs{
   132  		commitProposal: proposal,
   133  		committedSeals: seals,
   134  	})
   135  
   136  	// fake new head events
   137  	go self.events.Post(pbft.FinalCommittedEvent{})
   138  	return nil
   139  }
   140  
   141  func (self *testSystemBackend) MarkTransactionKnownBy(val pbft.Validator, txs types.Transactions) {}
   142  
   143  func (self *testSystemBackend) Verify(proposal pbft.Proposal, _, _ bool) (time.Duration, error) {
   144  	return 0, nil
   145  }
   146  
   147  func (self *testSystemBackend) Execute(proposal pbft.Proposal) (pbft.Conclusion, error) {
   148  	return proposal.(pbft.Conclusion), nil
   149  }
   150  
   151  func (self *testSystemBackend) OnTimeout() {}
   152  
   153  func (self *testSystemBackend) Sign(data []byte) ([]byte, error) {
   154  	testLogger.Info("returning current backend address so that CheckValidatorSignature returns the same value")
   155  	return self.address.Bytes(), nil
   156  }
   157  
   158  func (self *testSystemBackend) CheckSignature([]byte, common.Address, []byte) error {
   159  	return nil
   160  }
   161  
   162  func (self *testSystemBackend) CheckValidatorSignature(data []byte, sig []byte) (common.Address, error) {
   163  	return common.BytesToAddress(sig), nil
   164  }
   165  
   166  func (self *testSystemBackend) Hash(b interface{}) common.Hash {
   167  	return common.BytesToHash([]byte("Test"))
   168  }
   169  
   170  func (self *testSystemBackend) NewRequest(request pbft.Proposal) {
   171  	go self.events.Post(pbft.RequestEvent{
   172  		Proposal: request,
   173  	})
   174  }
   175  
   176  func (self *testSystemBackend) HasBadProposal(hash common.Hash) bool {
   177  	return false
   178  }
   179  
   180  func (self *testSystemBackend) LastProposal() (pbft.Proposal, pbft.Conclusion, common.Address) {
   181  	l := len(self.committedMsgs)
   182  	var block pbft.Conclusion
   183  	if l > 0 {
   184  		block = self.committedMsgs[l-1].commitProposal
   185  	} else {
   186  		block = makeBlock(0)
   187  	}
   188  	return block, block, common.Address{}
   189  }
   190  
   191  // Only block height 5 will return true
   192  func (self *testSystemBackend) HasProposal(hash common.Hash, number *big.Int) (common.Hash, bool) {
   193  	return hash, number.Cmp(big.NewInt(5)) == 0
   194  }
   195  
   196  func (self *testSystemBackend) GetProposer(number uint64) common.Address {
   197  	return common.Address{}
   198  }
   199  
   200  func (self *testSystemBackend) ParentValidators(proposal pbft.Proposal) pbft.ValidatorSet {
   201  	return self.peers
   202  }
   203  
   204  func (self *testSystemBackend) Close() error {
   205  	return nil
   206  }
   207  
   208  type testSystemTxPool struct {
   209  	all map[common.Hash]*types.Transaction
   210  }
   211  
   212  func newTestSystemTxPool(txs ...*types.Transaction) *testSystemTxPool {
   213  	pool := &testSystemTxPool{make(map[common.Hash]*types.Transaction)}
   214  	for _, tx := range txs {
   215  		pool.all[tx.Hash()] = tx
   216  	}
   217  	return pool
   218  }
   219  
   220  func (pool *testSystemTxPool) AddLocal(tx *types.Transaction) {
   221  	pool.all[tx.Hash()] = tx
   222  }
   223  
   224  func (pool *testSystemTxPool) InitLightBlock(pb *types.LightBlock) bool {
   225  	digests := pb.TxDigests()
   226  	transactions := pb.Transactions()
   227  
   228  	for index, hash := range digests {
   229  		if tx := pool.all[hash]; tx != nil {
   230  			(*transactions)[index] = tx
   231  		} else {
   232  			pb.MissedTxs = append(pb.MissedTxs, types.MissedTx{Hash: hash, Index: uint32(index)})
   233  		}
   234  	}
   235  
   236  	return len(pb.MissedTxs) == 0
   237  }
   238  
   239  // ==============================================
   240  //
   241  // define the struct that need to be provided for integration tests.
   242  
   243  type targetMessage struct {
   244  	msg  pbft.MessageEvent
   245  	vals pbft.Validators
   246  }
   247  
   248  type testSystem struct {
   249  	backends []*testSystemBackend
   250  
   251  	queuedMessage chan pbft.MessageEvent
   252  	sendMessage   chan targetMessage
   253  	quit          chan struct{}
   254  }
   255  
   256  func newTestSystem(n uint64) *testSystem {
   257  	testLogger.SetHandler(elog.StdoutHandler)
   258  	return &testSystem{
   259  		backends: make([]*testSystemBackend, n),
   260  
   261  		queuedMessage: make(chan pbft.MessageEvent),
   262  		sendMessage:   make(chan targetMessage),
   263  		quit:          make(chan struct{}),
   264  	}
   265  }
   266  
   267  func generateValidators(n int) []common.Address {
   268  	vals := make([]common.Address, 0)
   269  	for i := 0; i < n; i++ {
   270  		privateKey, _ := crypto.GenerateKey()
   271  		vals = append(vals, crypto.PubkeyToAddress(privateKey.PublicKey))
   272  	}
   273  	return vals
   274  }
   275  
   276  func newTestValidatorSet(n int) pbft.ValidatorSet {
   277  	return validator.NewSet(generateValidators(n), pbft.RoundRobin)
   278  }
   279  
   280  // FIXME: int64 is needed for N and F
   281  func NewTestSystemWithBackend(n, f uint64) *testSystem {
   282  	testLogger.SetHandler(elog.StdoutHandler)
   283  
   284  	addrs := generateValidators(int(n))
   285  	sys := newTestSystem(n)
   286  	config := pbft.DefaultConfig
   287  
   288  	for i := uint64(0); i < n; i++ {
   289  		vset := validator.NewSet(addrs, pbft.RoundRobin)
   290  		backend := sys.NewBackend(i)
   291  		backend.peers = vset
   292  		backend.address = vset.GetByIndex(i).Address()
   293  
   294  		core := New(backend, config).(*core)
   295  		core.state = StateAcceptRequest
   296  		core.current = newRoundState(&pbft.View{
   297  			Round:    big.NewInt(0),
   298  			Sequence: big.NewInt(1),
   299  		}, vset, common.Hash{}, nil, nil, nil, func(hash common.Hash) bool {
   300  			return false
   301  		})
   302  		core.valSet = vset
   303  		core.logger = testLogger
   304  		core.validateFn = backend.CheckValidatorSignature
   305  
   306  		backend.engine = core
   307  	}
   308  
   309  	return sys
   310  }
   311  
   312  // listen will consume messages from queue and deliver a message to core
   313  func (t *testSystem) listen() {
   314  	for {
   315  		select {
   316  		case <-t.quit:
   317  			return
   318  		case queuedMessage := <-t.queuedMessage:
   319  			testLogger.Info("consuming a queue message...")
   320  			for _, backend := range t.backends {
   321  				go backend.EventMux().Post(queuedMessage)
   322  			}
   323  		case sendMessage := <-t.sendMessage:
   324  			target := make(map[common.Address]struct{})
   325  			for _, val := range sendMessage.vals {
   326  				target[val.Address()] = struct{}{}
   327  			}
   328  			for _, backend := range t.backends {
   329  				if _, ok := target[backend.address]; ok {
   330  					go backend.EventMux().Post(sendMessage)
   331  				}
   332  			}
   333  		}
   334  	}
   335  }
   336  
   337  // Run will start system components based on given flag, and returns a closer
   338  // function that caller can control lifecycle
   339  //
   340  // Given a true for core if you want to initialize core engine.
   341  func (t *testSystem) Run(core bool) func() {
   342  	for _, b := range t.backends {
   343  		if core {
   344  			b.engine.Start() // start Istanbul core
   345  		}
   346  	}
   347  
   348  	go t.listen()
   349  	closer := func() { t.stop(core) }
   350  	return closer
   351  }
   352  
   353  func (t *testSystem) stop(core bool) {
   354  	close(t.quit)
   355  
   356  	for _, b := range t.backends {
   357  		if core {
   358  			b.engine.Stop()
   359  		}
   360  	}
   361  }
   362  
   363  func (t *testSystem) NewBackend(id uint64) *testSystemBackend {
   364  	// assume always success
   365  	ethDB := rawdb.NewMemoryDatabase()
   366  	backend := &testSystemBackend{
   367  		id:     id,
   368  		sys:    t,
   369  		events: new(event.TypeMux),
   370  		db:     ethDB,
   371  	}
   372  
   373  	t.backends[id] = backend
   374  	return backend
   375  }
   376  
   377  // ==============================================
   378  //
   379  // helper functions.
   380  
   381  func getPublicKeyAddress(privateKey *ecdsa.PrivateKey) common.Address {
   382  	return crypto.PubkeyToAddress(privateKey.PublicKey)
   383  }