github.com/hyperion-hyn/go-ethereum@v2.4.0+incompatible/consensus/istanbul/backend/backend.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 backend
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"math/big"
    22  	"sync"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/consensus"
    27  	"github.com/ethereum/go-ethereum/consensus/istanbul"
    28  	istanbulCore "github.com/ethereum/go-ethereum/consensus/istanbul/core"
    29  	"github.com/ethereum/go-ethereum/consensus/istanbul/validator"
    30  	"github.com/ethereum/go-ethereum/core"
    31  	"github.com/ethereum/go-ethereum/core/types"
    32  	"github.com/ethereum/go-ethereum/crypto"
    33  	"github.com/ethereum/go-ethereum/ethdb"
    34  	"github.com/ethereum/go-ethereum/event"
    35  	"github.com/ethereum/go-ethereum/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 *istanbul.Config, privateKey *ecdsa.PrivateKey, db ethdb.Database) consensus.Istanbul {
    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  	backend := &backend{
    51  		config:           config,
    52  		istanbulEventMux: new(event.TypeMux),
    53  		privateKey:       privateKey,
    54  		address:          crypto.PubkeyToAddress(privateKey.PublicKey),
    55  		logger:           log.New(),
    56  		db:               db,
    57  		commitCh:         make(chan *types.Block, 1),
    58  		recents:          recents,
    59  		candidates:       make(map[common.Address]bool),
    60  		coreStarted:      false,
    61  		recentMessages:   recentMessages,
    62  		knownMessages:    knownMessages,
    63  	}
    64  	backend.core = istanbulCore.New(backend, backend.config)
    65  	return backend
    66  }
    67  
    68  // ----------------------------------------------------------------------------
    69  
    70  type backend struct {
    71  	config           *istanbul.Config
    72  	istanbulEventMux *event.TypeMux
    73  	privateKey       *ecdsa.PrivateKey
    74  	address          common.Address
    75  	core             istanbulCore.Engine
    76  	logger           log.Logger
    77  	db               ethdb.Database
    78  	chain            consensus.ChainReader
    79  	currentBlock     func() *types.Block
    80  	hasBadBlock      func(hash common.Hash) bool
    81  
    82  	// the channels for istanbul engine notifications
    83  	commitCh          chan *types.Block
    84  	proposedBlockHash common.Hash
    85  	sealMu            sync.Mutex
    86  	coreStarted       bool
    87  	coreMu            sync.RWMutex
    88  
    89  	// Current list of candidates we are pushing
    90  	candidates map[common.Address]bool
    91  	// Protects the signer fields
    92  	candidatesLock sync.RWMutex
    93  	// Snapshots for recent block to speed up reorgs
    94  	recents *lru.ARCCache
    95  
    96  	// event subscription for ChainHeadEvent event
    97  	broadcaster consensus.Broadcaster
    98  
    99  	recentMessages *lru.ARCCache // the cache of peer's messages
   100  	knownMessages  *lru.ARCCache // the cache of self messages
   101  }
   102  
   103  // zekun: HACK
   104  func (sb *backend) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
   105  	return new(big.Int)
   106  }
   107  
   108  // Address implements istanbul.Backend.Address
   109  func (sb *backend) Address() common.Address {
   110  	return sb.address
   111  }
   112  
   113  // Validators implements istanbul.Backend.Validators
   114  func (sb *backend) Validators(proposal istanbul.Proposal) istanbul.ValidatorSet {
   115  	return sb.getValidators(proposal.Number().Uint64(), proposal.Hash())
   116  }
   117  
   118  // Broadcast implements istanbul.Backend.Broadcast
   119  func (sb *backend) Broadcast(valSet istanbul.ValidatorSet, payload []byte) error {
   120  	// send to others
   121  	sb.Gossip(valSet, payload)
   122  	// send to self
   123  	msg := istanbul.MessageEvent{
   124  		Payload: payload,
   125  	}
   126  	go sb.istanbulEventMux.Post(msg)
   127  	return nil
   128  }
   129  
   130  // Broadcast implements istanbul.Backend.Gossip
   131  func (sb *backend) Gossip(valSet istanbul.ValidatorSet, payload []byte) error {
   132  	hash := istanbul.RLPHash(payload)
   133  	sb.knownMessages.Add(hash, true)
   134  
   135  	targets := make(map[common.Address]bool)
   136  	for _, val := range valSet.List() {
   137  		if val.Address() != sb.Address() {
   138  			targets[val.Address()] = true
   139  		}
   140  	}
   141  
   142  	if sb.broadcaster != nil && len(targets) > 0 {
   143  		ps := sb.broadcaster.FindPeers(targets)
   144  		for addr, p := range ps {
   145  			ms, ok := sb.recentMessages.Get(addr)
   146  			var m *lru.ARCCache
   147  			if ok {
   148  				m, _ = ms.(*lru.ARCCache)
   149  				if _, k := m.Get(hash); k {
   150  					// This peer had this event, skip it
   151  					continue
   152  				}
   153  			} else {
   154  				m, _ = lru.NewARC(inmemoryMessages)
   155  			}
   156  
   157  			m.Add(hash, true)
   158  			sb.recentMessages.Add(addr, m)
   159  
   160  			go p.Send(istanbulMsg, payload)
   161  		}
   162  	}
   163  	return nil
   164  }
   165  
   166  // Commit implements istanbul.Backend.Commit
   167  func (sb *backend) Commit(proposal istanbul.Proposal, seals [][]byte) error {
   168  	// Check if the proposal is a valid block
   169  	block := &types.Block{}
   170  	block, ok := proposal.(*types.Block)
   171  	if !ok {
   172  		sb.logger.Error("Invalid proposal, %v", proposal)
   173  		return errInvalidProposal
   174  	}
   175  
   176  	h := block.Header()
   177  	// Append seals into extra-data
   178  	err := writeCommittedSeals(h, seals)
   179  	if err != nil {
   180  		return err
   181  	}
   182  	// update block's header
   183  	block = block.WithSeal(h)
   184  
   185  	sb.logger.Info("Committed", "address", sb.Address(), "hash", proposal.Hash(), "number", proposal.Number().Uint64())
   186  	// - if the proposed and committed blocks are the same, send the proposed hash
   187  	//   to commit channel, which is being watched inside the engine.Seal() function.
   188  	// - otherwise, we try to insert the block.
   189  	// -- if success, the ChainHeadEvent event will be broadcasted, try to build
   190  	//    the next block and the previous Seal() will be stopped.
   191  	// -- otherwise, a error will be returned and a round change event will be fired.
   192  	if sb.proposedBlockHash == block.Hash() {
   193  		// feed block hash to Seal() and wait the Seal() result
   194  		sb.commitCh <- block
   195  		return nil
   196  	}
   197  
   198  	if sb.broadcaster != nil {
   199  		sb.broadcaster.Enqueue(fetcherID, block)
   200  	}
   201  	return nil
   202  }
   203  
   204  // EventMux implements istanbul.Backend.EventMux
   205  func (sb *backend) EventMux() *event.TypeMux {
   206  	return sb.istanbulEventMux
   207  }
   208  
   209  // Verify implements istanbul.Backend.Verify
   210  func (sb *backend) Verify(proposal istanbul.Proposal) (time.Duration, error) {
   211  	// Check if the proposal is a valid block
   212  	block := &types.Block{}
   213  	block, ok := proposal.(*types.Block)
   214  	if !ok {
   215  		sb.logger.Error("Invalid proposal, %v", proposal)
   216  		return 0, errInvalidProposal
   217  	}
   218  
   219  	// check bad block
   220  	if sb.HasBadProposal(block.Hash()) {
   221  		return 0, core.ErrBlacklistedHash
   222  	}
   223  
   224  	// check block body
   225  	txnHash := types.DeriveSha(block.Transactions())
   226  	uncleHash := types.CalcUncleHash(block.Uncles())
   227  	if txnHash != block.Header().TxHash {
   228  		return 0, errMismatchTxhashes
   229  	}
   230  	if uncleHash != nilUncleHash {
   231  		return 0, errInvalidUncleHash
   232  	}
   233  
   234  	// verify the header of proposed block
   235  	err := sb.VerifyHeader(sb.chain, block.Header(), false)
   236  	// ignore errEmptyCommittedSeals error because we don't have the committed seals yet
   237  	if err == nil || err == errEmptyCommittedSeals {
   238  		return 0, nil
   239  	} else if err == consensus.ErrFutureBlock {
   240  		return time.Unix(block.Header().Time.Int64(), 0).Sub(now()), consensus.ErrFutureBlock
   241  	}
   242  	return 0, err
   243  }
   244  
   245  // Sign implements istanbul.Backend.Sign
   246  func (sb *backend) Sign(data []byte) ([]byte, error) {
   247  	hashData := crypto.Keccak256([]byte(data))
   248  	return crypto.Sign(hashData, sb.privateKey)
   249  }
   250  
   251  // CheckSignature implements istanbul.Backend.CheckSignature
   252  func (sb *backend) CheckSignature(data []byte, address common.Address, sig []byte) error {
   253  	signer, err := istanbul.GetSignatureAddress(data, sig)
   254  	if err != nil {
   255  		log.Error("Failed to get signer address", "err", err)
   256  		return err
   257  	}
   258  	// Compare derived addresses
   259  	if signer != address {
   260  		return errInvalidSignature
   261  	}
   262  	return nil
   263  }
   264  
   265  // HasPropsal implements istanbul.Backend.HashBlock
   266  func (sb *backend) HasPropsal(hash common.Hash, number *big.Int) bool {
   267  	return sb.chain.GetHeader(hash, number.Uint64()) != nil
   268  }
   269  
   270  // GetProposer implements istanbul.Backend.GetProposer
   271  func (sb *backend) GetProposer(number uint64) common.Address {
   272  	if h := sb.chain.GetHeaderByNumber(number); h != nil {
   273  		a, _ := sb.Author(h)
   274  		return a
   275  	}
   276  	return common.Address{}
   277  }
   278  
   279  // ParentValidators implements istanbul.Backend.GetParentValidators
   280  func (sb *backend) ParentValidators(proposal istanbul.Proposal) istanbul.ValidatorSet {
   281  	if block, ok := proposal.(*types.Block); ok {
   282  		return sb.getValidators(block.Number().Uint64()-1, block.ParentHash())
   283  	}
   284  	return validator.NewSet(nil, sb.config.ProposerPolicy)
   285  }
   286  
   287  func (sb *backend) getValidators(number uint64, hash common.Hash) istanbul.ValidatorSet {
   288  	snap, err := sb.snapshot(sb.chain, number, hash, nil)
   289  	if err != nil {
   290  		return validator.NewSet(nil, sb.config.ProposerPolicy)
   291  	}
   292  	return snap.ValSet
   293  }
   294  
   295  func (sb *backend) LastProposal() (istanbul.Proposal, common.Address) {
   296  	block := sb.currentBlock()
   297  
   298  	var proposer common.Address
   299  	if block.Number().Cmp(common.Big0) > 0 {
   300  		var err error
   301  		proposer, err = sb.Author(block.Header())
   302  		if err != nil {
   303  			sb.logger.Error("Failed to get block proposer", "err", err)
   304  			return nil, common.Address{}
   305  		}
   306  	}
   307  
   308  	// Return header only block here since we don't need block body
   309  	return block, proposer
   310  }
   311  
   312  func (sb *backend) HasBadProposal(hash common.Hash) bool {
   313  	if sb.hasBadBlock == nil {
   314  		return false
   315  	}
   316  	return sb.hasBadBlock(hash)
   317  }
   318  
   319  func (sb *backend) Close() error {
   320  	return nil
   321  }