github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/consensus/podc/core/testbackend_test.go (about)

     1  // Copyright 2017 AMIS Technologies
     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/ethereum/go-ethereum/p2p/discover"
    22  	"math/big"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/consensus/podc"
    26  	"github.com/ethereum/go-ethereum/consensus/podc/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  podc.ValidatorSet
    41  	events *event.TypeMux
    42  
    43  	commitMsgs     []podc.Proposal
    44  	committedSeals [][]byte
    45  	sentMsgs       [][]byte // store the message when Send is called by core
    46  
    47  	address common.Address
    48  	db      ethdb.Database
    49  }
    50  
    51  // ==============================================
    52  //
    53  // define the functions that needs to be provided for Istanbul.
    54  
    55  func (self *testSystemBackend) Address() common.Address {
    56  	return self.address
    57  }
    58  
    59  // Peers returns all connected peers
    60  func (self *testSystemBackend) Validators(proposal podc.Proposal) podc.ValidatorSet {
    61  	return self.peers
    62  }
    63  
    64  func (self *testSystemBackend) EventMux() *event.TypeMux {
    65  	return self.events
    66  }
    67  
    68  func (self *testSystemBackend) Send(message []byte, target common.Address) error {
    69  	testLogger.Info("enqueuing a message...", "address", self.Address())
    70  	self.sentMsgs = append(self.sentMsgs, message)
    71  	self.sys.queuedMessage <- podc.MessageEvent{
    72  		Payload: message,
    73  	}
    74  	return nil
    75  }
    76  
    77  func (self *testSystemBackend) Broadcast(valSet podc.ValidatorSet, message []byte) error {
    78  	testLogger.Info("enqueuing a message...", "address", self.Address())
    79  	self.sentMsgs = append(self.sentMsgs, message)
    80  	self.sys.queuedMessage <- podc.MessageEvent{
    81  		Payload: message,
    82  	}
    83  	return nil
    84  }
    85  
    86  
    87  // Multicast sends a message to specific targets
    88  func (self *testSystemBackend) Multicast( payload []byte, targets []common.Address ) error {
    89  	testLogger.Info("enqueuing a message...", "address", self.Address())
    90  	self.sentMsgs = append(self.sentMsgs, payload)
    91  	self.sys.queuedMessage <- podc.MessageEvent{
    92  		Payload: payload,
    93  	}
    94  	return nil
    95  }
    96  //end
    97  
    98  
    99  func (self *testSystemBackend) NextRound() error {
   100  	testLogger.Warn("nothing to happen")
   101  	return nil
   102  }
   103  
   104  func (self *testSystemBackend) Commit(proposal podc.Proposal, seals []byte) error {
   105  	testLogger.Info("commit message", "address", self.Address())
   106  	self.commitMsgs = append(self.commitMsgs, proposal)
   107  	self.committedSeals = append(self.committedSeals, seals)
   108  
   109  	// fake new head events
   110  	go self.events.Post(podc.FinalCommittedEvent{
   111  		Proposal: proposal,
   112  	})
   113  	return nil
   114  }
   115  
   116  func (self *testSystemBackend) Verify(proposal podc.Proposal) error {
   117  	return nil
   118  }
   119  
   120  func (self *testSystemBackend) Sign(data []byte) ([]byte, error) {
   121  	testLogger.Warn("not sign any data")
   122  	return data, 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.Address{}, 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 podc.Proposal) {
   138  	go self.events.Post(podc.RequestEvent{
   139  		Proposal: request,
   140  	})
   141  }
   142  
   143  // define the struct that need to be provided for integration tests.
   144  
   145  type testSystem struct {
   146  	backends []*testSystemBackend
   147  
   148  	queuedMessage chan podc.MessageEvent
   149  	quit          chan struct{}
   150  }
   151  
   152  func newTestSystem(n uint64) *testSystem {
   153  	testLogger.SetHandler(elog.StdoutHandler)
   154  	return &testSystem{
   155  		backends: make([]*testSystemBackend, n),
   156  
   157  		queuedMessage: make(chan podc.MessageEvent),
   158  		quit:          make(chan struct{}),
   159  	}
   160  }
   161  
   162  func generateValidators(n int) []common.Address {
   163  	vals := make([]common.Address, 0)
   164  	for i := 0; i < n; i++ {
   165  		privateKey, _ := crypto.GenerateKey()
   166  		vals = append(vals, crypto.PubkeyToAddress(privateKey.PublicKey))
   167  	}
   168  	return vals
   169  }
   170  
   171  func newTestValidatorSet(n int) podc.ValidatorSet {
   172  	return validator.NewSet(generateValidators(n), podc.RoundRobin)
   173  }
   174  
   175  // FIXME: int64 is needed for N and F
   176  func NewTestSystemWithBackend(n, f uint64) *testSystem {
   177  	testLogger.SetHandler(elog.StdoutHandler)
   178  
   179  	addrs := generateValidators(int(n))
   180  	sys := newTestSystem(n)
   181  	config := podc.DefaultConfig
   182  
   183  	for i := uint64(0); i < n; i++ {
   184  		vset := validator.NewSet(addrs, podc.RoundRobin)
   185  		backend := sys.NewBackend(i)
   186  		backend.peers = vset
   187  		backend.address = vset.GetByIndex(i).Address()
   188  
   189  		core := New(backend, config).(*core)
   190  		core.state = StateAcceptRequest
   191  		core.lastProposer = common.Address{}
   192  		core.current = newRoundState(&podc.View{
   193  			Round:    big.NewInt(0),
   194  			Sequence: big.NewInt(1),
   195  		}, vset)
   196  		core.logger = testLogger
   197  		core.validateFn = backend.CheckValidatorSignature
   198  
   199  		backend.engine = core
   200  	}
   201  
   202  	return sys
   203  }
   204  
   205  // listen will consume messages from queue and deliver a message to core
   206  func (t *testSystem) listen() {
   207  	for {
   208  		select {
   209  		case <-t.quit:
   210  			return
   211  		case queuedMessage := <-t.queuedMessage:
   212  			testLogger.Info("consuming a queue message...")
   213  			for _, backend := range t.backends {
   214  				go backend.EventMux().Post(queuedMessage)
   215  			}
   216  		}
   217  	}
   218  }
   219  
   220  // Run will start system components based on given flag, and returns a closer
   221  // function that caller can control lifecycle
   222  //
   223  // Given a true for core if you want to initialize core engine.
   224  func (t *testSystem) Run(core bool) func() {
   225  
   226  	var qman []*discover.Node
   227  	for _, b := range t.backends {
   228  		if core {
   229  			b.engine.Start(common.Big0, common.Address{}, nil, qman) // start PoDC core
   230  		}
   231  	}
   232  
   233  	go t.listen()
   234  	closer := func() { t.stop(core) }
   235  	return closer
   236  }
   237  
   238  func (t *testSystem) stop(core bool) {
   239  	close(t.quit)
   240  
   241  	for _, b := range t.backends {
   242  		if core {
   243  			b.engine.Stop()
   244  		}
   245  	}
   246  }
   247  
   248  func (t *testSystem) NewBackend(id uint64) *testSystemBackend {
   249  	// assume always success
   250  	ethDB, _ := ethdb.NewMemDatabase()
   251  	backend := &testSystemBackend{
   252  		id:     id,
   253  		sys:    t,
   254  		events: new(event.TypeMux),
   255  		db:     ethDB,
   256  	}
   257  
   258  	t.backends[id] = backend
   259  	return backend
   260  }
   261  
   262  // helper functions.
   263  
   264  func getPublicKeyAddress(privateKey *ecdsa.PrivateKey) common.Address {
   265  	return crypto.PubkeyToAddress(privateKey.PublicKey)
   266  }