github.com/codingfuture/orig-energi3@v0.8.4/energi/consensus/engine.go (about)

     1  // Copyright 2019 The Energi Core Authors
     2  // This file is part of the Energi Core library.
     3  //
     4  // The Energi Core 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 Energi Core 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 Energi Core library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package consensus
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"math/big"
    23  	"strings"
    24  	"sync/atomic"
    25  	"time"
    26  
    27  	"github.com/ethereum/go-ethereum/accounts/abi"
    28  	"github.com/ethereum/go-ethereum/common"
    29  	eth_consensus "github.com/ethereum/go-ethereum/consensus"
    30  	"github.com/ethereum/go-ethereum/consensus/misc"
    31  	"github.com/ethereum/go-ethereum/core"
    32  	"github.com/ethereum/go-ethereum/core/state"
    33  	"github.com/ethereum/go-ethereum/core/types"
    34  	"github.com/ethereum/go-ethereum/core/vm"
    35  	"github.com/ethereum/go-ethereum/crypto"
    36  	"github.com/ethereum/go-ethereum/ethdb"
    37  	"github.com/ethereum/go-ethereum/log"
    38  	"github.com/ethereum/go-ethereum/params"
    39  	"github.com/ethereum/go-ethereum/rlp"
    40  	"github.com/ethereum/go-ethereum/rpc"
    41  
    42  	lru "github.com/hashicorp/golang-lru"
    43  	"golang.org/x/crypto/sha3"
    44  
    45  	energi_abi "energi.world/core/gen3/energi/abi"
    46  	energi_params "energi.world/core/gen3/energi/params"
    47  )
    48  
    49  var (
    50  	sealLen   = 65
    51  	uncleHash = types.CalcUncleHash(nil)
    52  
    53  	errMissingSig = errors.New("Signature is missing")
    54  	errInvalidSig = errors.New("Invalid signature")
    55  
    56  	errBlacklistedCoinbase = errors.New("Blacklisted coinbase")
    57  )
    58  
    59  type ChainReader = eth_consensus.ChainReader
    60  type AccountsFn func() []common.Address
    61  type SignerFn func(common.Address, []byte) ([]byte, error)
    62  type PeerCountFn func() int
    63  type DiffFn func(ChainReader, uint64, *types.Header, *timeTarget) *big.Int
    64  
    65  type Energi struct {
    66  	config       *params.EnergiConfig
    67  	db           ethdb.Database
    68  	rewardAbi    abi.ABI
    69  	dposAbi      abi.ABI
    70  	blacklistAbi abi.ABI
    71  	sporkAbi     abi.ABI
    72  	mnregAbi     abi.ABI
    73  	treasuryAbi  abi.ABI
    74  	systemFaucet common.Address
    75  	xferGas      uint64
    76  	callGas      uint64
    77  	unlimitedGas uint64
    78  	signerFn     SignerFn
    79  	accountsFn   AccountsFn
    80  	peerCountFn  PeerCountFn
    81  	diffFn       DiffFn
    82  	testing      bool
    83  	now          func() uint64
    84  	knownStakes  KnownStakes
    85  	nextKSPurge  uint64
    86  	nonceCap     uint64
    87  	txhashMap    *lru.Cache
    88  }
    89  
    90  func New(config *params.EnergiConfig, db ethdb.Database) *Energi {
    91  	reward_abi, err := abi.JSON(strings.NewReader(energi_abi.IBlockRewardABI))
    92  	if err != nil {
    93  		panic(err)
    94  		return nil
    95  	}
    96  
    97  	dpos_abi, err := abi.JSON(strings.NewReader(energi_abi.IDelegatedPoSABI))
    98  	if err != nil {
    99  		panic(err)
   100  		return nil
   101  	}
   102  
   103  	blacklist_abi, err := abi.JSON(strings.NewReader(energi_abi.IBlacklistRegistryABI))
   104  	if err != nil {
   105  		panic(err)
   106  		return nil
   107  	}
   108  
   109  	spork_abi, err := abi.JSON(strings.NewReader(energi_abi.ISporkRegistryABI))
   110  	if err != nil {
   111  		panic(err)
   112  		return nil
   113  	}
   114  
   115  	mngreg_abi, err := abi.JSON(strings.NewReader(energi_abi.IMasternodeRegistryV2ABI))
   116  	if err != nil {
   117  		panic(err)
   118  		return nil
   119  	}
   120  
   121  	treasury_abi, err := abi.JSON(strings.NewReader(energi_abi.ITreasuryABI))
   122  	if err != nil {
   123  		panic(err)
   124  		return nil
   125  	}
   126  
   127  	txhashMap, err := lru.New(8)
   128  	if err != nil {
   129  		panic(err)
   130  		return nil
   131  	}
   132  
   133  	return &Energi{
   134  		config:       config,
   135  		db:           db,
   136  		rewardAbi:    reward_abi,
   137  		dposAbi:      dpos_abi,
   138  		blacklistAbi: blacklist_abi,
   139  		sporkAbi:     spork_abi,
   140  		mnregAbi:     mngreg_abi,
   141  		treasuryAbi:  treasury_abi,
   142  		systemFaucet: energi_params.Energi_SystemFaucet,
   143  		xferGas:      0,
   144  		callGas:      30000,
   145  		unlimitedGas: energi_params.UnlimitedGas,
   146  		diffFn:       calcPoSDifficultyV1,
   147  		now:          func() uint64 { return uint64(time.Now().Unix()) },
   148  		nextKSPurge:  0,
   149  		txhashMap:    txhashMap,
   150  	}
   151  }
   152  
   153  func (e *Energi) createEVM(
   154  	msg types.Message,
   155  	chain ChainReader,
   156  	header *types.Header,
   157  	statedb *state.StateDB,
   158  ) *vm.EVM {
   159  	vmc := &vm.Config{}
   160  
   161  	if bc, ok := chain.(*core.BlockChain); ok {
   162  		vmc = bc.GetVMConfig()
   163  	}
   164  
   165  	// Only From() is used by fact
   166  	ctx := core.NewEVMContext(msg, header, chain.(core.ChainContext), &header.Coinbase)
   167  	ctx.GasLimit = e.xferGas
   168  	return vm.NewEVM(ctx, statedb, chain.Config(), *vmc)
   169  }
   170  
   171  // Author retrieves the Ethereum address of the account that minted the given
   172  // block, which may be different from the header's coinbase if a consensus
   173  // engine is based on signatures.
   174  func (e *Energi) Author(header *types.Header) (common.Address, error) {
   175  	return common.Address{}, nil
   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 (e *Energi) VerifyHeader(chain ChainReader, header *types.Header, seal bool) error {
   182  	var err error
   183  	is_migration := header.IsGen2Migration()
   184  
   185  	// Ensure that the header's extra-data section is of a reasonable size
   186  	if uint64(len(header.Extra)) > params.MaximumExtraDataSize && !is_migration {
   187  		return fmt.Errorf("extra-data too long: %d > %d",
   188  			len(header.Extra), params.MaximumExtraDataSize)
   189  	}
   190  
   191  	// A special Migration block #1
   192  	if is_migration && (header.Coinbase != energi_params.Energi_MigrationContract) {
   193  		log.Error("PoS migration mismatch",
   194  			"signer", header.Coinbase,
   195  			"required", energi_params.Energi_MigrationContract)
   196  		return errors.New("Invalid Migration")
   197  	}
   198  
   199  	parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
   200  
   201  	if parent == nil {
   202  		if header.Number.Cmp(common.Big0) != 0 {
   203  			log.Trace("Not found parent", "number", header.Number,
   204  				"hash", header.Hash(), "parent", header.ParentHash)
   205  			return eth_consensus.ErrUnknownAncestor
   206  		}
   207  
   208  		return nil
   209  	}
   210  
   211  	time_target := e.calcTimeTarget(chain, parent)
   212  	err = e.checkTime(header, time_target)
   213  	if err != nil {
   214  		return err
   215  	}
   216  
   217  	modifier := e.calcPoSModifier(chain, header.Time, parent)
   218  	if header.MixDigest != modifier {
   219  		return fmt.Errorf("invalid modifier: have %v, want %v",
   220  			header.MixDigest, modifier)
   221  	}
   222  
   223  	difficulty := e.calcPoSDifficulty(chain, header.Time, parent, time_target)
   224  
   225  	if header.Difficulty.Cmp(difficulty) != 0 {
   226  		return fmt.Errorf("invalid difficulty: have %v, want %v",
   227  			header.Difficulty, difficulty)
   228  	}
   229  
   230  	cap := uint64(0x7fffffffffffffff)
   231  	if header.GasLimit > cap {
   232  		return fmt.Errorf("invalid gasLimit: have %v, max %v",
   233  			header.GasLimit, cap)
   234  	}
   235  
   236  	// Verify that the gasUsed is <= gasLimit, except for migration
   237  	if (header.GasUsed > header.GasLimit) && !is_migration {
   238  		return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d",
   239  			header.GasUsed, header.GasLimit)
   240  	}
   241  
   242  	// Verify that the gas limit remains within allowed bounds
   243  	diff := int64(parent.GasLimit) - int64(header.GasLimit)
   244  	if diff < 0 {
   245  		diff *= -1
   246  	}
   247  	limit := parent.GasLimit / params.GasLimitBoundDivisor
   248  
   249  	if (uint64(diff) >= limit) && !is_migration && !parent.IsGen2Migration() {
   250  		return fmt.Errorf("invalid gas limit: have %d, want %d += %d",
   251  			header.GasLimit, parent.GasLimit, limit)
   252  	}
   253  
   254  	if header.GasLimit < params.MinGasLimit {
   255  		return fmt.Errorf("invalid gas limit: have %d, minimum %d",
   256  			header.GasLimit, params.MinGasLimit)
   257  	}
   258  
   259  	// Verify that the block number is parent's +1
   260  	if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
   261  		return eth_consensus.ErrInvalidNumber
   262  	}
   263  
   264  	// We skip checks only where full previous meturity period state is required.
   265  	if seal {
   266  		// Verify the engine specific seal securing the block
   267  		err = e.VerifySeal(chain, header)
   268  		if err != nil {
   269  			return err
   270  		}
   271  
   272  		err = e.verifyPoSHash(chain, header)
   273  		if err != nil {
   274  			return err
   275  		}
   276  	}
   277  
   278  	if err = misc.VerifyForkHashes(chain.Config(), header, false); err != nil {
   279  		return err
   280  	}
   281  
   282  	// DoS protection
   283  	if seal && chain.GetHeader(header.Hash(), header.Number.Uint64()) == nil {
   284  		if err = e.checkDoS(chain, header, parent); err != nil {
   285  			return err
   286  		}
   287  	}
   288  
   289  	return nil
   290  }
   291  
   292  // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
   293  // concurrently. The method returns a quit channel to abort the operations and
   294  // a results channel to retrieve the async verifications (the order is that of
   295  // the input slice).
   296  func (e *Energi) VerifyHeaders(
   297  	chain ChainReader, headers []*types.Header, seals []bool,
   298  ) (
   299  	chan<- struct{}, <-chan error, chan<- bool,
   300  ) {
   301  	abort := make(chan struct{})
   302  	results := make(chan error, len(headers))
   303  	ready := make(chan bool, len(headers))
   304  
   305  	go func() {
   306  		for i, header := range headers {
   307  			// NOTE: unlike Ethash with DAG, there is little sense of this
   308  			//       batch async routine overhead
   309  			select {
   310  			case <-abort:
   311  				return
   312  			case <-ready:
   313  			}
   314  
   315  			err := e.VerifyHeader(chain, header, seals[i])
   316  
   317  			select {
   318  			case <-abort:
   319  				return
   320  			case results <- err:
   321  			}
   322  		}
   323  	}()
   324  
   325  	return abort, results, ready
   326  }
   327  
   328  // VerifyUncles verifies that the given block's uncles conform to the consensus
   329  // rules of a given engine.
   330  func (e *Energi) VerifyUncles(chain ChainReader, block *types.Block) error {
   331  	if len(block.Uncles()) > 0 {
   332  		return errors.New("uncles not allowed")
   333  	}
   334  	return nil
   335  }
   336  
   337  // VerifySeal checks whether the crypto seal on a header is valid according to
   338  // the consensus rules of the given engine.
   339  func (e *Energi) VerifySeal(chain ChainReader, header *types.Header) error {
   340  	parent_number := header.Number.Uint64() - 1
   341  	blockst := chain.CalculateBlockState(header.ParentHash, parent_number)
   342  	if blockst == nil {
   343  		log.Error("PoS state root failure", "header", header.ParentHash)
   344  		return eth_consensus.ErrMissingState
   345  	}
   346  
   347  	// DBL-8: blacklist block generation
   348  	if core.IsBlacklisted(blockst, header.Coinbase) {
   349  		log.Debug("Blacklisted Coinbase", "addr", header.Coinbase)
   350  		return errBlacklistedCoinbase
   351  	}
   352  
   353  	// Retrieve the signature from the header extra-data
   354  	if len(header.Signature) != sealLen {
   355  		return errMissingSig
   356  	}
   357  
   358  	sighash := e.SignatureHash(header)
   359  	log.Trace("PoS verify signature hash", "sighash", sighash)
   360  
   361  	r := new(big.Int).SetBytes(header.Signature[:32])
   362  	s := new(big.Int).SetBytes(header.Signature[32:64])
   363  	v := header.Signature[64]
   364  
   365  	if !crypto.ValidateSignatureValues(v, r, s, true) {
   366  		return types.ErrInvalidSig
   367  	}
   368  
   369  	pubkey, err := crypto.Ecrecover(sighash.Bytes(), header.Signature)
   370  	if err != nil {
   371  		return err
   372  	}
   373  
   374  	var addr common.Address
   375  	copy(addr[:], crypto.Keccak256(pubkey[1:])[12:])
   376  
   377  	if addr != header.Coinbase {
   378  		// POS-5: Delegated PoS
   379  		//--
   380  		parent := chain.GetHeader(header.ParentHash, parent_number)
   381  		if parent == nil {
   382  			return eth_consensus.ErrUnknownAncestor
   383  		}
   384  
   385  		if blockst.GetCodeSize(header.Coinbase) > 0 {
   386  			signerData, err := e.dposAbi.Pack("signerAddress")
   387  			if err != nil {
   388  				log.Error("Fail to prepare signerAddress() call", "err", err)
   389  				return err
   390  			}
   391  
   392  			msg := types.NewMessage(
   393  				e.systemFaucet,
   394  				&header.Coinbase,
   395  				0,
   396  				common.Big0,
   397  				e.callGas,
   398  				common.Big0,
   399  				signerData,
   400  				false,
   401  			)
   402  
   403  			rev_id := blockst.Snapshot()
   404  			evm := e.createEVM(msg, chain, parent, blockst)
   405  			gp := core.GasPool(e.callGas)
   406  			output, _, _, err := core.ApplyMessage(evm, msg, &gp)
   407  			blockst.RevertToSnapshot(rev_id)
   408  			if err != nil {
   409  				log.Trace("Fail to get signerAddress()", "err", err)
   410  				return err
   411  			}
   412  
   413  			//
   414  			signer := common.Address{}
   415  			err = e.dposAbi.Unpack(&signer, "signerAddress", output)
   416  			if err != nil {
   417  				log.Error("Failed to unpack signerAddress() call", "err", err)
   418  				return err
   419  			}
   420  
   421  			if signer == addr {
   422  				return nil
   423  			}
   424  
   425  			log.Trace("PoS seal compare", "addr", addr, "signer", signer)
   426  		} else {
   427  			log.Trace("PoS seal compare", "addr", addr, "coinbase", header.Coinbase)
   428  		}
   429  
   430  		return errInvalidSig
   431  	}
   432  
   433  	return nil
   434  }
   435  
   436  // Prepare initializes the consensus fields of a block header according to the
   437  // rules of a particular engine. The changes are executed inline.
   438  func (e *Energi) Prepare(chain ChainReader, header *types.Header) error {
   439  	parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
   440  
   441  	if parent == nil {
   442  		log.Error("Fail to find parent", "header", header)
   443  		return eth_consensus.ErrUnknownAncestor
   444  	}
   445  
   446  	_, err := e.posPrepare(chain, header, parent)
   447  	return err
   448  }
   449  
   450  func (e *Energi) posPrepare(
   451  	chain ChainReader,
   452  	header *types.Header,
   453  	parent *types.Header,
   454  ) (time_target *timeTarget, err error) {
   455  	// Clear field to be set in mining
   456  	header.Coinbase = common.Address{}
   457  	header.Nonce = types.BlockNonce{}
   458  
   459  	time_target = e.calcTimeTarget(chain, parent)
   460  
   461  	err = e.enforceTime(header, time_target)
   462  
   463  	// Repurpose the MixDigest field
   464  	header.MixDigest = e.calcPoSModifier(chain, header.Time, parent)
   465  
   466  	// Diff
   467  	header.Difficulty = e.calcPoSDifficulty(chain, header.Time, parent, time_target)
   468  
   469  	return time_target, err
   470  }
   471  
   472  // Finalize runs any post-transaction state modifications (e.g. block rewards)
   473  // and assembles the final block.
   474  // Note: The block header and state database might be updated to reflect any
   475  // consensus rules that happen at finalization (e.g. block rewards).
   476  func (e *Energi) Finalize(
   477  	chain ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
   478  	uncles []*types.Header, receipts []*types.Receipt,
   479  ) (*types.Block, []*types.Receipt, error) {
   480  	ctxs := types.Transactions{}
   481  
   482  	for i := (len(txs) - 1); i >= 0; i-- {
   483  		if !txs[i].IsConsensus() {
   484  			i++
   485  			ctxs = txs[i:]
   486  			txs = txs[:i]
   487  			break
   488  		} else if i == 0 {
   489  			ctxs = txs[:]
   490  			txs = txs[:0]
   491  			break
   492  		}
   493  	}
   494  
   495  	block, receipts, err := e.finalize(chain, header, state, txs, receipts)
   496  	if err != nil {
   497  		return nil, nil, err
   498  	}
   499  
   500  	ntxs := block.Transactions()[len(txs):]
   501  	if len(ntxs) != len(ctxs) {
   502  		log.Trace("Consensus TX length mismatch", "ntxs", len(ntxs), "ctxs", len(ctxs))
   503  		return nil, nil, eth_consensus.ErrInvalidConsensusTx
   504  	}
   505  	for i, tx := range ntxs {
   506  		if tx.Hash() != ctxs[i].Hash() {
   507  			log.Trace("Consensus TX hash mismatch", "pos", i, "ctx", ctxs[i].Hash(), "ntx", tx.Hash())
   508  			return nil, nil, eth_consensus.ErrInvalidConsensusTx
   509  		}
   510  	}
   511  
   512  	return block, receipts, err
   513  }
   514  
   515  func (e *Energi) finalize(
   516  	chain ChainReader, header *types.Header, state *state.StateDB,
   517  	txs []*types.Transaction, receipts []*types.Receipt,
   518  ) (*types.Block, []*types.Receipt, error) {
   519  	var err error
   520  
   521  	// Do not finalize too early in mining
   522  	if (header.Coinbase != common.Address{}) {
   523  		txs, receipts, err = e.govFinalize(chain, header, state, txs, receipts)
   524  	}
   525  
   526  	header.UncleHash = uncleHash
   527  
   528  	return types.NewBlock(header, txs, nil, receipts), receipts, err
   529  }
   530  
   531  func (e *Energi) govFinalize(
   532  	chain ChainReader,
   533  	header *types.Header,
   534  	state *state.StateDB,
   535  	txs types.Transactions,
   536  	receipts types.Receipts,
   537  ) (types.Transactions, types.Receipts, error) {
   538  	err := e.processConsensusGasLimits(chain, header, state)
   539  	if err == nil {
   540  		txs, receipts, err = e.processBlockRewards(chain, header, state, txs, receipts)
   541  	}
   542  	if err == nil {
   543  		err = e.processMasternodes(chain, header, state)
   544  	}
   545  	if err == nil {
   546  		err = e.processBlacklists(chain, header, state)
   547  	}
   548  	if err == nil {
   549  		txs, receipts, err = e.processDrainable(chain, header, state, txs, receipts)
   550  	}
   551  	if err == nil {
   552  		err = e.finalizeMigration(chain, header, state, txs)
   553  	}
   554  	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
   555  	return txs, receipts, err
   556  }
   557  
   558  // Seal generates a new sealing request for the given input block and pushes
   559  // the result into the given channel.
   560  //
   561  // Note, the method returns immediately and will send the result async. More
   562  // than one result may also be returned depending on the consensus algorithm.
   563  func (e *Energi) Seal(
   564  	chain ChainReader,
   565  	block *types.Block,
   566  	results chan<- *eth_consensus.SealResult,
   567  	stop <-chan struct{},
   568  ) (err error) {
   569  	go func() {
   570  		header := block.Header()
   571  		txhash := header.TxHash
   572  		result := eth_consensus.NewSealResult(block, nil, nil)
   573  
   574  		if header.Number.Cmp(common.Big0) != 0 {
   575  			success, err := e.mine(chain, header, stop)
   576  
   577  			// NOTE: due to the fact that PoS mining may change Coinbase
   578  			//       it is required to reprocess all transaction with correct
   579  			//       state of the block (input parameters). This is essential
   580  			//       for consensus and correct distribution of gas.
   581  			if success && err == nil {
   582  				result, err = e.recreateBlock(chain, header, block.Transactions())
   583  			}
   584  
   585  			if err != nil {
   586  				log.Error("PoS miner error", "err", err)
   587  				success = false
   588  			}
   589  
   590  			if !success {
   591  				select {
   592  				case results <- eth_consensus.NewSealResult(nil, nil, nil):
   593  				default:
   594  				}
   595  				return
   596  			}
   597  
   598  			header = result.Block.Header()
   599  		}
   600  
   601  		sighash := e.SignatureHash(header)
   602  		log.Trace("PoS seal hash", "sighash", sighash)
   603  
   604  		header.Signature, err = e.signerFn(header.Coinbase, sighash.Bytes())
   605  		if err != nil {
   606  			log.Error("PoS miner error", "err", err)
   607  			return
   608  		}
   609  
   610  		result.Block = result.Block.WithSeal(header)
   611  		e.txhashMap.Add(header.TxHash, txhash)
   612  
   613  		select {
   614  		case results <- result:
   615  			log.Info("PoS seal has submitted solution", "block", result.Block.Hash())
   616  		default:
   617  			log.Warn("PoS seal is not read by miner", "sealhash", e.SealHash(header))
   618  		}
   619  	}()
   620  
   621  	return nil
   622  }
   623  
   624  func (e *Energi) recreateBlock(
   625  	chain ChainReader,
   626  	header *types.Header,
   627  	txs types.Transactions,
   628  ) (
   629  	result *eth_consensus.SealResult, err error,
   630  ) {
   631  	var (
   632  		usedGas = new(uint64)
   633  		gp      = new(core.GasPool).AddGas(header.GasLimit)
   634  
   635  		bc *core.BlockChain
   636  		ok bool
   637  	)
   638  
   639  	blstate := chain.CalculateBlockState(header.ParentHash, header.Number.Uint64()-1)
   640  	if err != nil {
   641  		return nil, eth_consensus.ErrUnknownAncestor
   642  	}
   643  
   644  	vmc := &vm.Config{}
   645  	if bc, ok = chain.(*core.BlockChain); ok {
   646  		vmc = bc.GetVMConfig()
   647  	}
   648  
   649  	receipts := make(types.Receipts, 0, len(txs))
   650  
   651  	for i, tx := range txs {
   652  		blstate.Prepare(tx.Hash(), common.Hash{}, i)
   653  		receipt, _, err := core.ApplyTransaction(
   654  			chain.Config(), bc, nil,
   655  			gp, blstate, header, tx, usedGas, *vmc)
   656  		if err != nil {
   657  			return nil, err
   658  		}
   659  		receipts = append(receipts, receipt)
   660  	}
   661  
   662  	header.GasUsed = *usedGas
   663  	header.Bloom = types.Bloom{}
   664  
   665  	block, receipts, err := e.finalize(chain, header, blstate, txs, receipts)
   666  	return eth_consensus.NewSealResult(block, blstate, receipts), err
   667  }
   668  
   669  // SealHash returns the hash of a block prior to it being sealed.
   670  func (e *Energi) SealHash(header *types.Header) (hash common.Hash) {
   671  	hasher := sha3.NewLegacyKeccak256()
   672  
   673  	txhash := header.TxHash
   674  
   675  	if item, ok := e.txhashMap.Get(txhash); ok {
   676  		txhash = item.(common.Hash)
   677  	}
   678  
   679  	rlp.Encode(hasher, []interface{}{
   680  		// NOTE: commented parts are part of "mining" process
   681  		header.ParentHash,
   682  		header.UncleHash,
   683  		//header.Coinbase,
   684  		//header.Root,
   685  		txhash,
   686  		//header.ReceiptHash,
   687  		//header.Bloom,
   688  		//header.Difficulty,
   689  		header.Number,
   690  		header.GasLimit,
   691  		//header.GasUsed,
   692  		//header.Time,
   693  		//header.Extra,
   694  		//header.MixDigest,
   695  		//header.Nonce,
   696  		//header.Signature,
   697  	})
   698  	hasher.Sum(hash[:0])
   699  	return hash
   700  }
   701  
   702  func (e *Energi) SignatureHash(header *types.Header) (hash common.Hash) {
   703  	hasher := sha3.NewLegacyKeccak256()
   704  
   705  	rlp.Encode(hasher, []interface{}{
   706  		header.ParentHash,
   707  		header.UncleHash,
   708  		header.Coinbase,
   709  		header.Root,
   710  		header.TxHash,
   711  		header.ReceiptHash,
   712  		header.Bloom,
   713  		header.Difficulty,
   714  		header.Number,
   715  		header.GasLimit,
   716  		header.GasUsed,
   717  		header.Time,
   718  		header.Extra,
   719  		header.MixDigest,
   720  		header.Nonce,
   721  		//header.Signature,
   722  	})
   723  	hasher.Sum(hash[:0])
   724  	return hash
   725  }
   726  
   727  func (e *Energi) SetMinerNonceCap(nonceCap uint64) {
   728  	atomic.StoreUint64(&e.nonceCap, nonceCap)
   729  }
   730  func (e *Energi) GetMinerNonceCap() uint64 {
   731  	return atomic.LoadUint64(&e.nonceCap)
   732  }
   733  func (e *Energi) SetMinerCB(
   734  	accountsFn AccountsFn,
   735  	signerFn SignerFn,
   736  	peerCountFn PeerCountFn,
   737  ) {
   738  	if e.signerFn != nil {
   739  		panic("Callbacks must be set only once!")
   740  	}
   741  
   742  	e.signerFn = signerFn
   743  	e.accountsFn = accountsFn
   744  	e.peerCountFn = peerCountFn
   745  }
   746  
   747  // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty
   748  // that a new block should have.
   749  func (e *Energi) CalcDifficulty(chain ChainReader, time uint64, parent *types.Header) *big.Int {
   750  	time_target := e.calcTimeTarget(chain, parent)
   751  	return e.calcPoSDifficulty(chain, time, parent, time_target)
   752  }
   753  
   754  // APIs returns the RPC APIs this consensus engine provides.
   755  func (e *Energi) APIs(chain ChainReader) []rpc.API {
   756  	return make([]rpc.API, 0)
   757  }
   758  
   759  // Close terminates any background threads maintained by the consensus engine.
   760  func (e *Energi) Close() error {
   761  	return nil
   762  }
   763  
   764  func (e *Energi) processConsensusGasLimits(
   765  	chain ChainReader,
   766  	header *types.Header,
   767  	state *state.StateDB,
   768  ) error {
   769  	callData, err := e.sporkAbi.Pack("consensusGasLimits")
   770  	if err != nil {
   771  		log.Error("Fail to prepare consensusGasLimits() call", "err", err)
   772  		return err
   773  	}
   774  
   775  	// consensusGasLimits()
   776  	msg := types.NewMessage(
   777  		e.systemFaucet,
   778  		&energi_params.Energi_SporkRegistry,
   779  		0,
   780  		common.Big0,
   781  		e.callGas,
   782  		common.Big0,
   783  		callData,
   784  		false,
   785  	)
   786  	rev_id := state.Snapshot()
   787  	evm := e.createEVM(msg, chain, header, state)
   788  	gp := core.GasPool(e.callGas)
   789  	output, _, _, err := core.ApplyMessage(evm, msg, &gp)
   790  	state.RevertToSnapshot(rev_id)
   791  	if err != nil {
   792  		log.Error("Failed in consensusGasLimits() call", "err", err)
   793  		return err
   794  	}
   795  
   796  	//
   797  	ret := new(struct {
   798  		CallGas *big.Int
   799  		XferGas *big.Int
   800  	})
   801  	err = e.sporkAbi.Unpack(ret, "consensusGasLimits", output)
   802  	if err != nil {
   803  		log.Error("Failed to unpack consensusGasLimits() call", "err", err)
   804  		return err
   805  	}
   806  
   807  	e.callGas = ret.CallGas.Uint64()
   808  	e.xferGas = ret.XferGas.Uint64()
   809  	log.Trace("Consensus Gas", "call", e.callGas, "xfer", e.xferGas)
   810  
   811  	return nil
   812  }