github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dbft/backend/backend.go (about)

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