github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/backend/backend.go (about)

     1  // Copyright 2020 The go-simplechain Authors
     2  // This file is part of the go-simplechain library.
     3  //
     4  // The go-simplechain 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-simplechain 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-simplechain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package backend
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"math/big"
    22  	"sync"
    23  	"time"
    24  
    25  	"github.com/bigzoro/my_simplechain/common"
    26  	"github.com/bigzoro/my_simplechain/consensus"
    27  	"github.com/bigzoro/my_simplechain/consensus/pbft"
    28  	pc "github.com/bigzoro/my_simplechain/consensus/pbft/core"
    29  	"github.com/bigzoro/my_simplechain/consensus/pbft/validator"
    30  	"github.com/bigzoro/my_simplechain/core"
    31  	"github.com/bigzoro/my_simplechain/core/types"
    32  	"github.com/bigzoro/my_simplechain/crypto"
    33  	"github.com/bigzoro/my_simplechain/ethdb"
    34  	"github.com/bigzoro/my_simplechain/event"
    35  	"github.com/bigzoro/my_simplechain/log"
    36  	lru "github.com/hashicorp/golang-lru"
    37  )
    38  
    39  const (
    40  	// fetcherID is the ID indicates the block is from Istanbul engine
    41  	fetcherID = "istanbul"
    42  )
    43  
    44  // New creates an Ethereum backend for Istanbul core engine.
    45  func New(config *pbft.Config, privateKey *ecdsa.PrivateKey, db ethdb.Database) consensus.Pbft {
    46  	// Allocate the snapshot caches and create the engine
    47  	recents, _ := lru.NewARC(inmemorySnapshots)
    48  	recentMessages, _ := lru.NewARC(inmemoryPeers)
    49  	knownMessages, _ := lru.NewARC(inmemoryMessages)
    50  	proposal2conclusion, _ := lru.NewARC(inmemoryP2C)
    51  	backend := &backend{
    52  		config:              config,
    53  		pbftEventMux:        new(event.TypeMux),
    54  		privateKey:          privateKey,
    55  		address:             crypto.PubkeyToAddress(privateKey.PublicKey),
    56  		logger:              log.New(),
    57  		db:                  db,
    58  		commitCh:            make(chan *types.Block, 1),
    59  		recents:             recents,
    60  		proposal2conclusion: proposal2conclusion,
    61  		candidates:          make(map[common.Address]bool),
    62  		coreStarted:         false,
    63  		recentMessages:      recentMessages,
    64  		knownMessages:       knownMessages,
    65  	}
    66  	backend.core = pc.New(backend, backend.config)
    67  	return backend
    68  }
    69  
    70  // ----------------------------------------------------------------------------
    71  
    72  type backend struct {
    73  	config       *pbft.Config
    74  	pbftEventMux *event.TypeMux
    75  	privateKey   *ecdsa.PrivateKey
    76  	address      common.Address
    77  	core         pc.Engine
    78  	logger       log.Logger
    79  	db           ethdb.Database
    80  	chain        consensus.ChainReader
    81  	chainWriter  consensus.ChainWriter
    82  	currentBlock func() *types.Block
    83  	hasBadBlock  func(hash common.Hash) bool
    84  
    85  	// the channels for pbft engine notifications
    86  	commitCh          chan *types.Block
    87  	proposedBlockHash common.Hash
    88  	sealMu            sync.Mutex
    89  	coreStarted       bool
    90  	coreMu            sync.RWMutex
    91  
    92  	// Current list of candidates we are pushing
    93  	candidates map[common.Address]bool
    94  	// Protects the signer fields
    95  	candidatesLock sync.RWMutex
    96  	// Snapshots for recent block to speed up reorgs
    97  	recents *lru.ARCCache
    98  	// proposal2conclusion store proposedHash to conclusionHash
    99  	proposal2conclusion *lru.ARCCache
   100  
   101  	// event subscription for ChainHeadEvent event
   102  	broadcaster consensus.Broadcaster
   103  	sealer      consensus.Sealer
   104  	txPool      consensus.TxPool
   105  
   106  	recentMessages *lru.ARCCache // the cache of peer's messages
   107  	knownMessages  *lru.ARCCache // the cache of self messages
   108  
   109  	sealStart time.Time // record engine starting seal time
   110  	execCost  time.Duration
   111  }
   112  
   113  func (sb *backend) GetCurrentBlock() *types.Block {
   114  	return sb.core.GetCurrentBlock()
   115  }
   116  
   117  // zekun: HACK
   118  func (sb *backend) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
   119  	return new(big.Int)
   120  }
   121  
   122  // Address implements pbft.Backend.Address
   123  func (sb *backend) Address() common.Address {
   124  	return sb.address
   125  }
   126  
   127  // Validators implements pbft.Backend.Validators
   128  func (sb *backend) Validators(proposal pbft.Conclusion) pbft.ValidatorSet {
   129  	return sb.getValidators(proposal.Number().Uint64(), proposal.Hash())
   130  }
   131  
   132  // Broadcast send to others. implements pbft.Backend.Broadcast
   133  func (sb *backend) Broadcast(valSet pbft.ValidatorSet, sender common.Address, payload []byte) error {
   134  	//sb.Gossip(valSet, payload)
   135  	sb.Guidance(valSet, sender, payload)
   136  	return nil
   137  }
   138  
   139  // BroadcastMsg sends a message to specific validators. implements pbft.Backend.BroadcastMsg
   140  func (sb *backend) BroadcastMsg(ps map[common.Address]consensus.Peer, hash common.Hash, payload []byte) error {
   141  	sb.knownMessages.Add(hash, true)
   142  
   143  	for addr, p := range ps {
   144  		ms, ok := sb.recentMessages.Get(addr)
   145  		var m *lru.ARCCache
   146  		if ok {
   147  			m, _ = ms.(*lru.ARCCache)
   148  			if _, k := m.Get(hash); k {
   149  				// This peer had this event, skip it
   150  				continue
   151  			}
   152  		} else {
   153  			m, _ = lru.NewARC(inmemoryMessages)
   154  		}
   155  
   156  		m.Add(hash, true)
   157  		sb.recentMessages.Add(addr, m)
   158  
   159  		go func(peer consensus.Peer) {
   160  			if err := peer.Send(PbftMsg, payload); err != nil {
   161  				log.Error("send PbftMsg failed", "error", err.Error())
   162  			}
   163  		}(p)
   164  	}
   165  
   166  	return nil
   167  }
   168  
   169  // Post send to self
   170  func (sb *backend) Post(payload []byte) {
   171  	msg := pbft.MessageEvent{
   172  		Payload: payload,
   173  	}
   174  	go sb.pbftEventMux.Post(msg)
   175  }
   176  
   177  func (sb *backend) SendMsg(val pbft.Validators, payload []byte) error {
   178  	targets := make(map[common.Address]bool, val.Len())
   179  	for _, v := range val {
   180  		targets[v.Address()] = true
   181  	}
   182  	ps := sb.broadcaster.FindPeers(targets)
   183  
   184  	for _, p := range ps {
   185  		go func(peer consensus.Peer) {
   186  			if err := peer.Send(PbftMsg, payload); err != nil {
   187  				log.Error("send PbftMsg failed", "error", err.Error())
   188  			}
   189  		}(p)
   190  	}
   191  	return nil
   192  }
   193  
   194  func (sb *backend) Guidance(valSet pbft.ValidatorSet, sender common.Address, payload []byte) {
   195  	targets := make([]common.Address, 0, valSet.Size())
   196  	myIndex, routeIndex := -1, -1 // -1 means not a route node index
   197  	for i, val := range valSet.List() {
   198  		if val.Address() == sb.Address() {
   199  			myIndex = i
   200  		}
   201  		if val.Address() == sender {
   202  			routeIndex = i
   203  		}
   204  		targets = append(targets, val.Address())
   205  	}
   206  
   207  	if sb.broadcaster != nil {
   208  		hash := pbft.RLPHash(payload)
   209  		ps := sb.broadcaster.FindRoute(targets, myIndex, routeIndex)
   210  		sb.BroadcastMsg(ps, hash, payload)
   211  	}
   212  }
   213  
   214  func (sb *backend) MarkTransactionKnownBy(val pbft.Validator, txs types.Transactions) {
   215  	ps := sb.broadcaster.FindPeers(map[common.Address]bool{val.Address(): true})
   216  	for _, p := range ps {
   217  		for _, tx := range txs {
   218  			p.MarkTransaction(tx.Hash())
   219  		}
   220  	}
   221  }
   222  
   223  // Broadcast implements pbft.Backend.Gossip
   224  func (sb *backend) Gossip(valSet pbft.ValidatorSet, payload []byte) {
   225  	targets := make(map[common.Address]bool)
   226  	for _, val := range valSet.List() {
   227  		if val.Address() != sb.Address() {
   228  			targets[val.Address()] = true
   229  		}
   230  	}
   231  
   232  	if sb.broadcaster != nil && len(targets) > 0 {
   233  		hash := pbft.RLPHash(payload)
   234  		ps := sb.broadcaster.FindPeers(targets)
   235  		sb.BroadcastMsg(ps, hash, payload)
   236  	}
   237  }
   238  
   239  // Commit implements pbft.Backend.Commit
   240  func (sb *backend) Commit(conclusion pbft.Conclusion, commitSeals [][]byte) error {
   241  	// Check if the conclusion is a valid block
   242  	block, ok := conclusion.(*types.Block)
   243  	if !ok {
   244  		sb.logger.Error("Invalid conclusion, %v", conclusion)
   245  		return errInvalidProposal
   246  	}
   247  
   248  	h := block.Header()
   249  	// Append commitSeals into extra-data
   250  	err := writeCommittedSeals(h, commitSeals)
   251  	if err != nil {
   252  		return err
   253  	}
   254  	// update block's header
   255  	block = block.WithSeal(h)
   256  
   257  	hTime := time.Unix(int64(h.Time), 0)
   258  	delay := hTime.Sub(now())
   259  	if sb.sealer != nil {
   260  		sb.sealer.OnCommit(block.NumberU64(), block.Transactions().Len())
   261  	}
   262  
   263  	//log.Report("pbft consensus seal cost",
   264  	//	"num", h.Number, "totalCost", time.Since(sb.sealStart), "execCost", sb.execCost)
   265  
   266  	// wait until block timestamp
   267  	if delay > time.Minute {
   268  		return errTooFarInFuture
   269  	}
   270  	<-time.After(delay)
   271  
   272  	// - if the proposed and committed blocks are the same, send the proposed hash
   273  	//   to commit channel, which is being watched inside the engine.Seal() function.
   274  	// - otherwise, we try to insert the block.
   275  	// -- if success, the ChainHeadEvent event will be broadcasted, try to build
   276  	//    the next block and the previous Seal() will be stopped.
   277  	// -- otherwise, a error will be returned and a round change event will be fired.
   278  	//if sb.proposedBlockHash == block.Hash() {
   279  	if sb.proposedBlockHash == block.PendingHash() {
   280  		// feed block hash to Seal() and wait the Seal() result
   281  		sb.commitCh <- block
   282  
   283  	} else {
   284  		// write block to block chain
   285  		if sb.chainWriter != nil {
   286  			err := sb.chainWriter.WriteBlock(block)
   287  			if err != nil {
   288  				return err
   289  			}
   290  		}
   291  		// broadcast new block
   292  		if sb.broadcaster != nil {
   293  			//sb.broadcaster.Enqueue(fetcherID, block)
   294  			// broadcast the block announce
   295  			sb.broadcaster.BroadcastBlock(block, false)
   296  		}
   297  	}
   298  
   299  	sb.logger.Warn("Committed new pbft block", "number", conclusion.Number().Uint64(),
   300  		"proposeHash", conclusion.PendingHash(), "hash", conclusion.Hash(), "txs", block.Transactions().Len(),
   301  		"elapsed", time.Since(hTime))
   302  
   303  	return nil
   304  }
   305  
   306  func (sb *backend) GetForwardNodes(valList pbft.Validators) (map[common.Address]consensus.Peer, []common.Address) {
   307  	var (
   308  		peers        map[common.Address]consensus.Peer
   309  		forwardNodes []common.Address
   310  	)
   311  	targets := make(map[common.Address]bool)
   312  	for _, val := range valList {
   313  		if val.Address() != sb.Address() {
   314  			targets[val.Address()] = true
   315  		}
   316  	}
   317  	if sb.broadcaster != nil && len(targets) > 0 {
   318  		peers = sb.broadcaster.FindPeers(targets)
   319  		for addr, ok := range targets {
   320  			if ok && peers[addr] == nil {
   321  				forwardNodes = append(forwardNodes, addr)
   322  			}
   323  		}
   324  	}
   325  	return peers, forwardNodes
   326  }
   327  
   328  // EventMux implements pbft.Backend.EventMux
   329  func (sb *backend) EventMux() *event.TypeMux {
   330  	return sb.pbftEventMux
   331  }
   332  
   333  // Verify implements pbft.Backend.Verify
   334  // Check if the proposal is a valid block
   335  func (sb *backend) Verify(proposal pbft.Proposal, checkHeader, checkBody bool) (time.Duration, error) {
   336  	// Unpack proposal to raw block
   337  	var block *types.Block
   338  	switch pb := proposal.(type) {
   339  	case *types.Block:
   340  		block = pb
   341  	case *types.LightBlock:
   342  		block = &pb.Block
   343  	default:
   344  		sb.logger.Error("Invalid proposal(wrong type)", "proposal", proposal)
   345  		return 0, errInvalidProposal
   346  	}
   347  
   348  	// check bad block
   349  	if sb.HasBadProposal(block.PendingHash()) { // proposal only has pendingHash (fixed in blockchain)
   350  		//if sb.HasBadProposal(block.Hash()) {
   351  		return 0, core.ErrBlacklistedHash
   352  	}
   353  
   354  	// check block body
   355  	if checkBody {
   356  		err := sb.VerifyBody(block)
   357  		if err != nil {
   358  			return 0, err
   359  		}
   360  	}
   361  
   362  	// verify the header of proposed block
   363  	if !checkHeader {
   364  		return 0, nil
   365  	}
   366  	err := sb.VerifyHeader(sb.chain, block.Header(), false)
   367  	switch err {
   368  	// ignore errEmptyCommittedSeals error because we don't have the committed seals yet
   369  	case nil, errEmptyCommittedSeals:
   370  		return 0, nil
   371  
   372  	case consensus.ErrFutureBlock:
   373  		return time.Unix(int64(block.Header().Time), 0).Sub(now()), consensus.ErrFutureBlock
   374  
   375  	default:
   376  		return 0, err
   377  	}
   378  }
   379  
   380  func (sb *backend) VerifyBody(block *types.Block) error {
   381  	txnHash := types.DeriveSha(block.Transactions())
   382  	uncleHash := types.CalcUncleHash(block.Uncles())
   383  	if txnHash != block.Header().TxHash {
   384  		return errMismatchTxhashes
   385  	}
   386  	if uncleHash != nilUncleHash {
   387  		return errInvalidUncleHash
   388  	}
   389  	return nil
   390  }
   391  
   392  func (sb *backend) FillLightProposal(proposal pbft.LightProposal) (filled bool, missed []types.MissedTx, err error) {
   393  	block, ok := proposal.(*types.LightBlock)
   394  	if !ok {
   395  		sb.logger.Error("Invalid proposal(wrong type), %v", proposal)
   396  		return false, nil, errInvalidProposal
   397  	}
   398  
   399  	if sb.txPool == nil {
   400  		return false, nil, errNonExistentTxPool
   401  	}
   402  
   403  	// resize block transactions to digests size
   404  	*block.Transactions() = make(types.Transactions, len(block.TxDigests()))
   405  	// fill block transactions by txpool
   406  	filled = sb.txPool.InitLightBlock(block)
   407  
   408  	return filled, block.MissedTxs, nil
   409  }
   410  
   411  func (sb *backend) Execute(proposal pbft.Proposal) (pbft.Conclusion, error) {
   412  	var block *types.Block
   413  	switch pb := proposal.(type) {
   414  	case *types.Block:
   415  		block = pb
   416  	case *types.LightBlock:
   417  		block = &pb.Block
   418  	default:
   419  		sb.logger.Error("Invalid proposal(wrong type)", "proposal", proposal)
   420  		return nil, errInvalidProposal
   421  	}
   422  
   423  	if sb.sealer == nil {
   424  		return block, errNonExistentSealer
   425  	}
   426  
   427  	defer func(start time.Time) {
   428  		sb.logger.Debug("Execute Proposal", "pendingHash", proposal.PendingHash(), "usedTime", time.Since(start))
   429  		sb.execCost = time.Since(start)
   430  	}(time.Now())
   431  
   432  	if err := sb.txPool.CheckAndSetSender(types.Blocks{block}); err != nil {
   433  		return nil, err
   434  	}
   435  	return sb.chainWriter.Execute(block)
   436  
   437  	//return sb.sealer.Execute(block) //TODO:delete
   438  }
   439  
   440  func (sb *backend) OnTimeout() {
   441  	if sb.sealer != nil {
   442  		sb.sealer.OnTimeout()
   443  	}
   444  }
   445  
   446  // Sign implements pbft.Backend.Sign
   447  func (sb *backend) Sign(data []byte) ([]byte, error) {
   448  	hashData := crypto.Keccak256(data)
   449  	return crypto.Sign(hashData, sb.privateKey)
   450  }
   451  
   452  // CheckSignature implements pbft.Backend.CheckSignature
   453  func (sb *backend) CheckSignature(data []byte, address common.Address, sig []byte) error {
   454  	signer, err := pbft.GetSignatureAddress(data, sig)
   455  	if err != nil {
   456  		log.Error("Failed to get signer address", "err", err)
   457  		return err
   458  	}
   459  	// Compare derived addresses
   460  	if signer != address {
   461  		return errInvalidSignature
   462  	}
   463  	return nil
   464  }
   465  
   466  // HasProposal implements pbft.Backend.HashBlock
   467  func (sb *backend) HasProposal(hash common.Hash, number *big.Int) (common.Hash, bool) {
   468  	cHash, ok := sb.proposal2conclusion.Get(hash)
   469  	if ok {
   470  		conclusionHash := cHash.(common.Hash)
   471  		return conclusionHash, sb.chain.GetHeader(conclusionHash, number.Uint64()) != nil
   472  	}
   473  	return common.Hash{}, false
   474  }
   475  
   476  func (sb *backend) AnnounceCommittedProposal(hash common.Hash, number *big.Int, to pbft.Validator) {
   477  	block := sb.chain.GetBlock(hash, number.Uint64())
   478  	if block != nil {
   479  		for _, peer := range sb.broadcaster.FindPeers(map[common.Address]bool{to.Address(): true}) {
   480  			peer.AsyncSendNewBlockHash(block)
   481  		}
   482  	}
   483  }
   484  
   485  // GetProposer implements pbft.Backend.GetProposer
   486  func (sb *backend) GetProposer(number uint64) common.Address {
   487  	if h := sb.chain.GetHeaderByNumber(number); h != nil {
   488  		a, _ := sb.Author(h)
   489  		return a
   490  	}
   491  	return common.Address{}
   492  }
   493  
   494  // ParentValidators implements pbft.Backend.ParentValidators
   495  func (sb *backend) ParentValidators(proposal pbft.Proposal) pbft.ValidatorSet {
   496  	if block, ok := proposal.(*types.Block); ok {
   497  		return sb.getValidators(block.Number().Uint64()-1, block.ParentHash())
   498  	}
   499  	return validator.NewSet(nil, sb.config.ProposerPolicy)
   500  }
   501  
   502  func (sb *backend) getValidators(number uint64, hash common.Hash) pbft.ValidatorSet {
   503  	snap, err := sb.snapshot(sb.chain, number, hash, nil)
   504  	if err != nil {
   505  		sb.logger.Warn("validators are not found in snapshot", "err", err)
   506  		return validator.NewSet(nil, sb.config.ProposerPolicy)
   507  	}
   508  	return snap.ValSet
   509  }
   510  
   511  func (sb *backend) LastProposal() (pbft.Proposal, pbft.Conclusion, common.Address) {
   512  	block := sb.currentBlock() // current block on blockchain
   513  
   514  	var proposer common.Address
   515  	if block.Number().Cmp(common.Big0) > 0 {
   516  		var err error
   517  		proposer, err = sb.Author(block.Header())
   518  		if err != nil {
   519  			sb.logger.Error("Failed to get block proposer", "err", err)
   520  			return nil, nil, common.Address{}
   521  		}
   522  	}
   523  
   524  	// Return header only block here since we don't need block body
   525  	return block, block, proposer
   526  }
   527  
   528  func (sb *backend) HasBadProposal(hash common.Hash) bool {
   529  	if sb.hasBadBlock == nil {
   530  		return false
   531  	}
   532  	return sb.hasBadBlock(hash)
   533  }
   534  
   535  func (sb *backend) IsBlockHashLocked(hash common.Hash) bool {
   536  	return sb.core.IsHashLocked(hash)
   537  }
   538  
   539  func (sb *backend) Close() error {
   540  	return nil
   541  }