github.com/ebakus/go-ebakus@v1.0.5-0.20200520105415-dbccef9ec421/consensus/dpos/dpos.go (about)

     1  // Copyright 2019 The ebakus/go-ebakus Authors
     2  // This file is part of the ebakus/go-ebakus library.
     3  //
     4  // The ebakus/go-ebakus 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 ebakus/go-ebakus 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 ebakus/go-ebakus library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package dpos
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/binary"
    22  	"errors"
    23  	"fmt"
    24  	"io"
    25  	"math/big"
    26  	"math/bits"
    27  	"sync"
    28  	"time"
    29  
    30  	"github.com/ebakus/ebakusdb"
    31  
    32  	"github.com/ebakus/go-ebakus/accounts"
    33  	"github.com/ebakus/go-ebakus/common"
    34  	"github.com/ebakus/go-ebakus/core"
    35  	"github.com/ebakus/go-ebakus/core/rawdb"
    36  	"github.com/ebakus/go-ebakus/core/state"
    37  	"github.com/ebakus/go-ebakus/core/types"
    38  	"github.com/ebakus/go-ebakus/core/vm"
    39  	"github.com/ebakus/go-ebakus/crypto"
    40  	"github.com/ebakus/go-ebakus/metrics"
    41  
    42  	"github.com/ebakus/go-ebakus/log"
    43  	"github.com/ebakus/go-ebakus/rlp"
    44  
    45  	"github.com/ebakus/go-ebakus/consensus"
    46  	"github.com/ebakus/go-ebakus/rpc"
    47  
    48  	"github.com/ebakus/go-ebakus/ethdb"
    49  	"github.com/ebakus/go-ebakus/params"
    50  	lru "github.com/hashicorp/golang-lru"
    51  	"golang.org/x/crypto/sha3"
    52  )
    53  
    54  var (
    55  	checkpointInterval  = uint64(60 * 10)
    56  	blockPeriod         = uint64(2)   // Default block issuance period of 5 sec
    57  	initialDistribution = uint64(1e9) // EBK
    58  	yearlyInflation     = float64(0.01)
    59  
    60  	signatureCacheSize = 4096 // Number of recent block signatures to keep in memory
    61  )
    62  
    63  var (
    64  	// errUnknownBlock is returned when the list of signers is requested for a block
    65  	// that is not part of the local blockchain.
    66  	errUnknownBlock = errors.New("unknown block")
    67  
    68  	// errInvalidCheckpointBeneficiary is returned if a checkpoint/epoch transition
    69  	// block has a beneficiary set to non-zeroes.
    70  	errInvalidCheckpointBeneficiary = errors.New("beneficiary in checkpoint block non-zero")
    71  
    72  	// ErrInvalidTimestamp is returned if the timestamp of a block is lower than
    73  	// the previous block's timestamp + the minimum block period.
    74  	ErrInvalidTimestamp = errors.New("invalid timestamp")
    75  
    76  	// errUnauthorized is returned if a header is signed by a non-authorized entity.
    77  	errUnauthorized = errors.New("unauthorized")
    78  
    79  	// errInvalidVotingChain is returned when out-of-range or non-contiguous headers are provided.
    80  	errInvalidHeaderChain = errors.New("invalid header chain")
    81  
    82  	errInvalidStateHeaderAlignment = errors.New("invalid state header alignment")
    83  
    84  	// errMissingSignature is returned if a block's does not contain a 65 byte secp256k1 signature.
    85  	errMissingSignature = errors.New("65 byte signature missing")
    86  
    87  	ErrInvalidDelegateUpdateBlock = errors.New("Delegates updated at wrong block")
    88  
    89  	// ErrProductionAborted is returned when the producer is instructed to prepaturely abort
    90  	ErrProductionAborted = errors.New("Production aborted")
    91  )
    92  
    93  var blockProduceTimer = metrics.GetOrRegisterTimer("worker/blocks/produce", nil)
    94  
    95  // SignerFn is a signer callback function to request a hash to be signed by a
    96  // backing account.
    97  type SignerFn func(accounts.Account, string, []byte) ([]byte, error)
    98  
    99  // DPOS is the delegate proof-of-stake consensus engine
   100  type DPOS struct {
   101  	config     *params.DPOSConfig
   102  	db         ethdb.Database
   103  	ebakusDb   *ebakusdb.DB
   104  	blockchain *core.BlockChain
   105  	genesis    *core.Genesis
   106  
   107  	signatures *lru.ARCCache // Signatures of recent blocks to speed up address recover
   108  
   109  	signer common.Address // Ebakus address of the signing key
   110  	signFn SignerFn       // Signer function to authorize hashes with
   111  	lock   sync.RWMutex
   112  }
   113  
   114  // ecrecover extracts the Ebakus account address from a signed header.
   115  func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) {
   116  	// If the signature's already cached, return that
   117  	hash := header.Hash()
   118  	if address, known := sigcache.Get(hash); known {
   119  		return address.(common.Address), nil
   120  	}
   121  
   122  	signature := header.Signature
   123  	if len(signature) < 65 {
   124  		return common.Address{}, errMissingSignature
   125  	}
   126  
   127  	// Recover the public key and the Ebakus address
   128  	pubkey, err := crypto.Ecrecover(sigHash(header).Bytes(), signature)
   129  	if err != nil {
   130  		return common.Address{}, err
   131  	}
   132  	var signer common.Address
   133  	copy(signer[:], crypto.Keccak256(pubkey[1:])[12:])
   134  
   135  	sigcache.Add(hash, signer)
   136  	return signer, nil
   137  }
   138  
   139  // New creates a Delegated Proof of Stake consensus engine
   140  func New(config *params.DPOSConfig, db ethdb.Database, ebakusDb *ebakusdb.DB, genesis *core.Genesis) *DPOS {
   141  	conf := *config
   142  
   143  	if conf.Period == 0 {
   144  		conf.Period = blockPeriod
   145  	}
   146  
   147  	if conf.InitialDistribution == 0 {
   148  		conf.InitialDistribution = initialDistribution
   149  	}
   150  
   151  	if conf.YearlyInflation == 0 {
   152  		conf.YearlyInflation = yearlyInflation
   153  	}
   154  
   155  	signatures, _ := lru.NewARC(signatureCacheSize)
   156  
   157  	return &DPOS{
   158  		config:     &conf,
   159  		db:         db,
   160  		ebakusDb:   ebakusDb,
   161  		blockchain: nil,
   162  		genesis:    genesis,
   163  
   164  		signatures: signatures,
   165  	}
   166  }
   167  
   168  func (d *DPOS) SetBlockchain(bc *core.BlockChain) {
   169  	d.blockchain = bc
   170  }
   171  
   172  // Author implements consensus.Engine, returning the Ebakus address recovered
   173  // from the signature in the header
   174  func (d *DPOS) Author(header *types.Header) (common.Address, error) {
   175  	return ecrecover(header, d.signatures)
   176  }
   177  
   178  // VerifyHeader checks whether a header conforms to the consensus rules of a
   179  // given engine. Verifying the seal may be done optionally here, or explicitly
   180  // via the VerifySeal method.
   181  func (d *DPOS) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error {
   182  	return d.verifyHeader(chain, header, nil)
   183  }
   184  
   185  func (d *DPOS) getParent(chain consensus.ChainReader, header *types.Header, parents []*types.Header) *types.Header {
   186  	if len(parents) > 0 {
   187  		return parents[len(parents)-1]
   188  	}
   189  	return chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
   190  }
   191  
   192  func (d *DPOS) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error {
   193  	if header.Number == nil {
   194  		return errUnknownBlock
   195  	}
   196  
   197  	blockNum := header.Number.Uint64()
   198  
   199  	if header.Time > uint64(time.Now().Unix()) {
   200  		return consensus.ErrFutureBlock
   201  	}
   202  
   203  	if blockNum == 0 {
   204  		return nil
   205  	}
   206  
   207  	// Ensure that the block's timestamp isn't too close to it's parent
   208  	parent := d.getParent(chain, header, parents)
   209  	if parent == nil || parent.Number.Uint64() != blockNum-1 || parent.Hash() != header.ParentHash {
   210  		return consensus.ErrUnknownAncestor
   211  	}
   212  	if parent.Time+d.config.Period > header.Time {
   213  		return ErrInvalidTimestamp
   214  	}
   215  
   216  	return nil
   217  }
   218  
   219  // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
   220  // concurrently. The method returns a quit channel to abort the operations and
   221  // a results channel to retrieve the async verifications (the order is that of
   222  // the input slice).
   223  func (d *DPOS) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
   224  	abort := make(chan struct{})
   225  	results := make(chan error, len(headers))
   226  
   227  	go func() {
   228  		for i, header := range headers {
   229  			err := d.verifyHeader(chain, header, headers[:i])
   230  
   231  			select {
   232  			case <-abort:
   233  				return
   234  			case results <- err:
   235  			}
   236  		}
   237  	}()
   238  
   239  	return abort, results
   240  }
   241  
   242  // VerifyBlock verifies that the given block conform to the consensus
   243  // rules of a given engine.
   244  func (d *DPOS) VerifyBlock(chain consensus.ChainReader, block *types.Block) error {
   245  
   246  	return d.verifySeal(chain, block.Header(), nil)
   247  }
   248  
   249  // VerifySeal checks whether the crypto seal on a header is valid according to
   250  // the consensus rules of the given engine.
   251  func (d *DPOS) VerifySeal(chain consensus.ChainReader, header *types.Header) error {
   252  	return d.verifySeal(chain, header, nil)
   253  }
   254  
   255  func (d *DPOS) verifySeal(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error {
   256  	blockNumber := header.Number.Uint64()
   257  	if blockNumber == 0 {
   258  		return nil
   259  	}
   260  
   261  	slot := float64(header.Time) / float64(d.config.Period)
   262  
   263  	parentBlockNumber := blockNumber - 1
   264  	ebakusState, err := chain.EbakusStateAt(header.ParentHash, parentBlockNumber)
   265  	if err != nil {
   266  		return fmt.Errorf("Verify seal failed to get ebakus state: %s", err)
   267  	}
   268  
   269  	parentHeader := d.blockchain.GetHeaderByHash(header.ParentHash)
   270  
   271  	signer := d.getSignerAtSlot(chain, parentHeader, ebakusState, slot)
   272  	ebakusState.Release()
   273  
   274  	blockSigner, err := ecrecover(header, d.signatures)
   275  	if err != nil {
   276  		return err
   277  	}
   278  
   279  	if blockSigner != signer {
   280  		return errUnauthorized
   281  	}
   282  
   283  	return nil
   284  }
   285  
   286  // Close terminates any background threads maintained by the consensus engine (we don't have any).
   287  func (d *DPOS) Close() error {
   288  	var err error
   289  	return err
   290  }
   291  
   292  // Prepare initializes the consensus fields of a block header according to the
   293  // rules of a particular engine. The changes are executed inline.
   294  func (d *DPOS) Prepare(chain consensus.ChainReader, stop <-chan struct{}) (*types.Block, *types.Header, error) {
   295  	d.lock.RLock()
   296  	signer := d.signer
   297  	d.lock.RUnlock()
   298  
   299  	for {
   300  		head := chain.CurrentBlock()
   301  		headSlot := float64(head.Time()) / float64(d.config.Period)
   302  
   303  		now := unixNow()
   304  		slot := float64(now) / float64(d.config.Period)
   305  
   306  		headHash := head.Hash()
   307  		headBlockNumber := head.NumberU64()
   308  		ebakusState, err := chain.EbakusStateAt(headHash, headBlockNumber)
   309  		if err != nil {
   310  			return nil, nil, fmt.Errorf("Prepare new block failed to get ebakus state at block number %d: %s", headBlockNumber, err)
   311  		}
   312  
   313  		inTurnSigner := d.getSignerAtSlot(chain, head.Header(), ebakusState, slot)
   314  		ebakusState.Release()
   315  
   316  		log.Trace("Check turn", "slot", slot, "signer", signer, "turn for", inTurnSigner)
   317  
   318  		if slot > headSlot && signer == inTurnSigner {
   319  			// We are the chosen one. Break.
   320  			num := head.Number()
   321  
   322  			header := &types.Header{
   323  				ParentHash: headHash,
   324  				Number:     num.Add(num, common.Big1),
   325  				GasLimit:   0,
   326  				GasUsed:    0,
   327  				Time:       uint64(slot * float64(d.config.Period)),
   328  			}
   329  
   330  			// Sealing the genesis block is not supported
   331  			blockNumber := header.Number.Uint64()
   332  			if blockNumber == 0 {
   333  				return nil, nil, errUnknownBlock
   334  			}
   335  
   336  			log.Trace("Will seal block", "header", header, "slot", slot)
   337  
   338  			return head, header, nil
   339  		}
   340  
   341  		nextSlotTime := time.Unix(int64((slot+1)*float64(d.config.Period)), 0)
   342  
   343  		timeToNextSlot := nextSlotTime.Sub(time.Now())
   344  
   345  		log.Trace("Sleeping", "time", timeToNextSlot)
   346  
   347  		select {
   348  		case <-stop:
   349  			log.Info("Woke to abort")
   350  			return nil, nil, ErrProductionAborted
   351  		case <-time.After(timeToNextSlot):
   352  		}
   353  	}
   354  }
   355  
   356  // Finalize runs any post-transaction state modifications (e.g. block rewards)
   357  // and assembles the final block.
   358  // Note: The block header and state database might be updated to reflect any
   359  // consensus rules that happen at finalization (e.g. block rewards).
   360  func (d *DPOS) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, ebakusState *ebakusdb.Snapshot, coinbase common.Address, txs []*types.Transaction) {
   361  	// Accumulate any block and uncle rewards and commit the final state root
   362  	d.AccumulateRewards(chain.Config().DPOS, state, header, coinbase)
   363  	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
   364  }
   365  
   366  // FinalizeAndAssemble implements consensus.Engine, accumulating the block and
   367  // setting the final state and assembling the block.
   368  func (d *DPOS) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, state *state.StateDB, ebakusState *ebakusdb.Snapshot, coinbase common.Address, txs []*types.Transaction,
   369  	receipts []*types.Receipt) (*types.Block, error) {
   370  	// Accumulate any block and uncle rewards and commit the final state root
   371  	d.AccumulateRewards(chain.Config().DPOS, state, header, coinbase)
   372  	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
   373  
   374  	// Calculate delegate changes
   375  	oldBlockNumber := header.Number.Uint64() - 1
   376  	oldEbakusSnapshotId := rawdb.ReadSnapshot(d.db, header.ParentHash, oldBlockNumber)
   377  	if oldEbakusSnapshotId == nil {
   378  		return nil, errUnknownBlock
   379  	}
   380  	oldEbakusState := d.ebakusDb.Snapshot(*oldEbakusSnapshotId)
   381  	defer oldEbakusState.Release()
   382  
   383  	delegateCount := d.config.DelegateCount
   384  	bonusDelegateCount := d.config.BonusDelegateCount
   385  	turnBlockCount := d.config.TurnBlockCount
   386  	oldDelegates := GetDelegates(d.blockchain.GetHeaderByHash(header.ParentHash), oldEbakusState, delegateCount, bonusDelegateCount, turnBlockCount)
   387  	newDelegates := GetDelegates(header, ebakusState, delegateCount, bonusDelegateCount, turnBlockCount)
   388  	delegateDiff := oldDelegates.Diff(newDelegates)
   389  
   390  	log.Trace("Delegates", "diff", delegateDiff)
   391  
   392  	block := types.NewBlock(header, txs, receipts, &delegateDiff)
   393  
   394  	return block, nil
   395  }
   396  
   397  // Authorize injects a private key into the consensus engine to mint new blocks
   398  // with.
   399  func (d *DPOS) Authorize(signer common.Address, signFn SignerFn) {
   400  	d.lock.Lock()
   401  	defer d.lock.Unlock()
   402  
   403  	d.signer = signer
   404  	d.signFn = signFn
   405  }
   406  
   407  // Seal generates a new block for the given input block with the local miner's
   408  // seal place on top.
   409  func (d *DPOS) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
   410  	header := block.Header()
   411  
   412  	// Sealing the genesis block is not supported
   413  	blockNumber := header.Number.Uint64()
   414  	if blockNumber == 0 {
   415  		return errUnknownBlock
   416  	}
   417  
   418  	// Don't hold the signer fields for the entire sealing procedure
   419  	d.lock.RLock()
   420  	signer, signFn := d.signer, d.signFn
   421  	d.lock.RUnlock()
   422  
   423  	// Ensure the timestamp has the correct delay
   424  	parent := chain.GetHeader(header.ParentHash, blockNumber-1)
   425  	if parent == nil {
   426  		return consensus.ErrUnknownAncestor
   427  	}
   428  
   429  	// Sign
   430  	sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeDpos, RLP(header))
   431  	if err != nil {
   432  		return err
   433  	}
   434  
   435  	header.Signature = sighash
   436  
   437  	results <- block.WithSeal(header)
   438  
   439  	return nil
   440  }
   441  
   442  // SealHash returns the hash of a block prior to it being sealed.
   443  func (d *DPOS) SealHash(header *types.Header) (hash common.Hash) {
   444  	hasher := sha3.NewLegacyKeccak256()
   445  
   446  	rlp.Encode(hasher, []interface{}{
   447  		header.ParentHash,
   448  		header.Root,
   449  		header.TxHash,
   450  		header.ReceiptHash,
   451  		header.Bloom,
   452  		header.Number,
   453  		header.GasLimit,
   454  		header.GasUsed,
   455  		header.Time,
   456  	})
   457  	hasher.Sum(hash[:0])
   458  	return hash
   459  }
   460  
   461  // AccumulateRewards credits the coinbase of the given block with the reward
   462  func (d *DPOS) AccumulateRewards(config *params.DPOSConfig, state *state.StateDB, header *types.Header, coinbase common.Address) {
   463  	reward := big.NewInt(3171 * 1e14)
   464  
   465  	state.AddBalance(coinbase, reward)
   466  }
   467  
   468  // CalcDifficulty is essentialy dummy in ebakus
   469  func (d *DPOS) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
   470  	return big.NewInt(1)
   471  }
   472  
   473  // APIs implements consensus.Engine, returning the user facing RPC API to allow
   474  // controlling the delegate voting etc.
   475  func (d *DPOS) APIs(chain consensus.ChainReader) []rpc.API {
   476  	return []rpc.API{{
   477  		Namespace: "dpos",
   478  		Version:   "1.0",
   479  		Service:   &API{chain: chain, dpos: d},
   480  	}}
   481  }
   482  
   483  func unixNow() uint64 {
   484  	return uint64(time.Now().Unix())
   485  }
   486  
   487  func (d *DPOS) getSignerAtSlot(chain consensus.ChainReader, header *types.Header, state *ebakusdb.Snapshot, slot float64) common.Address {
   488  	delegates := GetDelegates(header, state, d.config.DelegateCount, d.config.BonusDelegateCount, d.config.TurnBlockCount)
   489  
   490  	if d.config.TurnBlockCount == 0 {
   491  		log.Warn("DPOS.TurnBlockCount is zero. This means that mining won't match a signer.")
   492  	}
   493  
   494  	if d.config.DelegateCount == 0 || d.config.TurnBlockCount == 0 {
   495  		return common.Address{}
   496  	}
   497  
   498  	slot = slot / float64(d.config.TurnBlockCount)
   499  	s := int(slot) % int(d.config.DelegateCount)
   500  
   501  	if s < len(delegates) {
   502  		return delegates[s].Id
   503  	}
   504  
   505  	return common.Address{}
   506  }
   507  
   508  func (d *DPOS) getBlockDensity(chain consensus.ChainReader, number rpc.BlockNumber, lookbackTime uint64) (map[string]interface{}, error) {
   509  	var prevBlock *types.Block
   510  	totalMissedBlocks := 0
   511  	latestBlockNumber := chain.CurrentBlock().NumberU64()
   512  
   513  	if number == rpc.LatestBlockNumber {
   514  		number = rpc.BlockNumber(latestBlockNumber)
   515  	}
   516  
   517  	if uint64(number) > latestBlockNumber {
   518  		return nil, consensus.ErrFutureBlock
   519  	}
   520  
   521  	initialBlock := d.blockchain.GetBlockByNumber(uint64(number))
   522  	blocksHashes := d.blockchain.GetBlockHashesFromHash(initialBlock.Hash(), lookbackTime)
   523  
   524  	// create a map using `timestamp` as key for our algorithm lookup
   525  	blocksMap := make(map[uint64]*types.Block, len(blocksHashes)+1)
   526  	blocksMap[uint64(initialBlock.Time())] = initialBlock
   527  
   528  	for _, blockHash := range blocksHashes {
   529  		block := d.blockchain.GetBlockByHash(blockHash)
   530  		blocksMap[uint64(block.Time())] = block
   531  	}
   532  
   533  	lookbackTimestamp := initialBlock.Time() - lookbackTime
   534  
   535  	blocksNumber := uint64(len(blocksHashes) + 1)
   536  	if lookbackTime > blocksNumber {
   537  		lookbackTimestamp = initialBlock.Time() - blocksNumber
   538  	}
   539  
   540  	for timestamp := initialBlock.Time(); timestamp >= lookbackTimestamp; timestamp-- {
   541  		block, blockFound := blocksMap[timestamp]
   542  		if !blockFound {
   543  			totalMissedBlocks++
   544  			continue
   545  		}
   546  
   547  		if err := d.verifySeal(chain, block.Header(), nil); err != nil {
   548  			totalMissedBlocks++
   549  		}
   550  
   551  		if prevBlock != nil && (prevBlock.NumberU64() != block.NumberU64()+1 || block.Hash() != prevBlock.ParentHash()) {
   552  			totalMissedBlocks++
   553  		}
   554  
   555  		prevBlock = block
   556  	}
   557  
   558  	result := map[string]interface{}{
   559  		"total_missed_blocks": totalMissedBlocks,
   560  	}
   561  
   562  	return result, nil
   563  }
   564  
   565  func uniformRandom(max uint64, hash common.Hash) uint64 {
   566  	bitsRequired := bits.Len64(max - 1)
   567  
   568  	startBit := 0
   569  	var rand uint64
   570  	for {
   571  		rand = 0
   572  		for i := 0; i < bitsRequired; i++ {
   573  			b := hash[((startBit+i)/8)%common.HashLength]
   574  			p := byte((startBit + i) % 8)
   575  			rand += uint64((b & (1 << p) >> p)) << i
   576  		}
   577  		if rand < max {
   578  			break
   579  		}
   580  		if startBit/8 >= common.HashLength {
   581  			rand = rand % max
   582  			break
   583  		}
   584  		startBit++
   585  	}
   586  
   587  	return rand
   588  }
   589  
   590  func GetDelegates(header *types.Header, snap *ebakusdb.Snapshot, maxWitnesses uint64, maxBonusWitnesses uint64, turnBlockCount uint64) vm.WitnessArray {
   591  	if maxWitnesses == 0 {
   592  		log.Warn("DPOS.getDelegates maxWitnesses is zero. This means that mining won't match a signer. Check if DPOS.DelegatesCount is set to zero")
   593  	}
   594  
   595  	maxWitnessesToLoad := maxWitnesses
   596  	if maxBonusWitnesses > 0 {
   597  		maxWitnessesToLoad += maxBonusWitnesses
   598  	}
   599  
   600  	delegates := vm.DelegateVotingGetDelegates(snap, maxWitnessesToLoad)
   601  
   602  	// get bonus delegate
   603  	if uint64(len(delegates)) > maxWitnesses {
   604  		bonusCandidateDelegates := delegates[maxWitnesses-1:]
   605  		delegates = delegates[:maxWitnesses-1] // excluding the last bonus position from maxWitnesses
   606  
   607  		slot := (header.Time + 1) / turnBlockCount
   608  		slotData := make([]byte, 8)
   609  		binary.BigEndian.PutUint64(slotData, slot)
   610  		rand := uniformRandom(uint64(len(bonusCandidateDelegates)), crypto.Keccak256Hash(slotData))
   611  		delegates = append(delegates, bonusCandidateDelegates[rand])
   612  	}
   613  
   614  	return delegates
   615  }
   616  
   617  // sigHash returns the hash which is used as input for the delegate proof-of-stake
   618  // signing. It is the hash of the entire header apart from the 65 byte signature
   619  // contained at the end of the extra data.
   620  func sigHash(header *types.Header) (hash common.Hash) {
   621  	hasher := sha3.NewLegacyKeccak256()
   622  	encodeSigHeader(hasher, header)
   623  	hasher.Sum(hash[:0])
   624  	return hash
   625  }
   626  
   627  // RLP returns the rlp bytes which needs to be signed for the proof-of-authority
   628  // sealing.
   629  func RLP(header *types.Header) []byte {
   630  	b := new(bytes.Buffer)
   631  	encodeSigHeader(b, header)
   632  	return b.Bytes()
   633  }
   634  
   635  func encodeSigHeader(w io.Writer, header *types.Header) {
   636  	err := rlp.Encode(w, []interface{}{
   637  		header.ParentHash,
   638  		header.Root,
   639  		header.TxHash,
   640  		header.ReceiptHash,
   641  		header.Bloom,
   642  		header.Number,
   643  		header.GasLimit,
   644  		header.GasUsed,
   645  		header.Time,
   646  		header.DelegateDiff,
   647  	})
   648  	if err != nil {
   649  		panic("can't encode: " + err.Error())
   650  	}
   651  }