github.com/Elemental-core/elementalcore@v0.0.0-20191206075037-63891242267a/consensus/dpos/dpos.go (about)

     1  package dpos
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	lru "github.com/hashicorp/golang-lru"
     9  	"github.com/Elemental-core/elementalcore/accounts"
    10  	"github.com/Elemental-core/elementalcore/common"
    11  	"github.com/Elemental-core/elementalcore/consensus"
    12  	"github.com/Elemental-core/elementalcore/consensus/misc"
    13  	"github.com/Elemental-core/elementalcore/core/state"
    14  	"github.com/Elemental-core/elementalcore/core/types"
    15  	"github.com/Elemental-core/elementalcore/crypto"
    16  	"github.com/Elemental-core/elementalcore/crypto/sha3"
    17  	"github.com/Elemental-core/elementalcore/ethdb"
    18  	"github.com/Elemental-core/elementalcore/log"
    19  	"github.com/Elemental-core/elementalcore/params"
    20  	"github.com/Elemental-core/elementalcore/rlp"
    21  	"github.com/Elemental-core/elementalcore/rpc"
    22  	"github.com/Elemental-core/elementalcore/trie"
    23  	"math/big"
    24  	"sync"
    25  	"time"
    26  )
    27  
    28  const (
    29  	extraVanity        = 32   // Fixed number of extra-data prefix bytes reserved for signer vanity
    30  	extraSeal          = 65   // Fixed number of extra-data suffix bytes reserved for signer seal
    31  	inmemorySignatures = 4096 // Number of recent block signatures to keep in memory
    32  
    33  	blockInterval    = int64(5)
    34  	epochInterval    = int64(5)
    35  	maxValidatorSize = 3
    36  	safeSize         = maxValidatorSize*2/3 + 1
    37  	consensusSize    = maxValidatorSize*2/3 + 1
    38  )
    39  
    40  var (
    41  	big0  = big.NewInt(0)
    42  	big8  = big.NewInt(8)
    43  	big32 = big.NewInt(32)
    44  
    45  	frontierBlockReward  *big.Int = big.NewInt(5e+18) // Block reward in wei for successfully mining a block
    46  	byzantiumBlockReward *big.Int = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium
    47  
    48  	timeOfFirstBlock = int64(0)
    49  
    50  	confirmedBlockHead = []byte("confirmed-block-head")
    51  )
    52  
    53  var (
    54  	// errUnknownBlock is returned when the list of signers is requested for a block
    55  	// that is not part of the local blockchain.
    56  	errUnknownBlock = errors.New("unknown block")
    57  	// errMissingVanity is returned if a block's extra-data section is shorter than
    58  	// 32 bytes, which is required to store the signer vanity.
    59  	errMissingVanity = errors.New("extra-data 32 byte vanity prefix missing")
    60  	// errMissingSignature is returned if a block's extra-data section doesn't seem
    61  	// to contain a 65 byte secp256k1 signature.
    62  	errMissingSignature = errors.New("extra-data 65 byte suffix signature missing")
    63  	// errInvalidMixDigest is returned if a block's mix digest is non-zero.
    64  	errInvalidMixDigest = errors.New("non-zero mix digest")
    65  	// errInvalidUncleHash is returned if a block contains an non-empty uncle list.
    66  	errInvalidUncleHash  = errors.New("non empty uncle hash")
    67  	errInvalidDifficulty = errors.New("invalid difficulty")
    68  
    69  	// ErrInvalidTimestamp is returned if the timestamp of a block is lower than
    70  	// the previous block's timestamp + the minimum block period.
    71  	ErrInvalidTimestamp           = errors.New("invalid timestamp")
    72  	ErrWaitForPrevBlock           = errors.New("wait for last block arrived")
    73  	ErrMintFutureBlock            = errors.New("mint the future block")
    74  	ErrMismatchSignerAndValidator = errors.New("mismatch block signer and validator")
    75  	ErrInvalidBlockValidator      = errors.New("invalid block validator")
    76  	ErrInvalidMintBlockTime       = errors.New("invalid time to mint the block")
    77  	ErrNilBlockHeader             = errors.New("nil block header returned")
    78  )
    79  var (
    80  	uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.
    81  )
    82  
    83  type Dpos struct {
    84  	config *params.DposConfig // Consensus engine configuration parameters
    85  	db     ethdb.Database     // Database to store and retrieve snapshot checkpoints
    86  
    87  	signer               common.Address
    88  	signFn               SignerFn
    89  	signatures           *lru.ARCCache // Signatures of recent blocks to speed up mining
    90  	confirmedBlockHeader *types.Header
    91  
    92  	mu   sync.RWMutex
    93  	stop chan bool
    94  }
    95  
    96  type SignerFn func(accounts.Account, []byte) ([]byte, error)
    97  
    98  // NOTE: sigHash was copy from clique
    99  // sigHash returns the hash which is used as input for the proof-of-authority
   100  // signing. It is the hash of the entire header apart from the 65 byte signature
   101  // contained at the end of the extra data.
   102  //
   103  // Note, the method requires the extra data to be at least 65 bytes, otherwise it
   104  // panics. This is done to avoid accidentally using both forms (signature present
   105  // or not), which could be abused to produce different hashes for the same header.
   106  func sigHash(header *types.Header) (hash common.Hash) {
   107  	hasher := sha3.NewKeccak256()
   108  
   109  	rlp.Encode(hasher, []interface{}{
   110  		header.ParentHash,
   111  		header.UncleHash,
   112  		header.Validator,
   113  		header.Coinbase,
   114  		header.Root,
   115  		header.TxHash,
   116  		header.ReceiptHash,
   117  		header.Bloom,
   118  		header.Difficulty,
   119  		header.Number,
   120  		header.GasLimit,
   121  		header.GasUsed,
   122  		header.Time,
   123  		header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
   124  		header.MixDigest,
   125  		header.Nonce,
   126  		header.DposContext.Root(),
   127  	})
   128  	hasher.Sum(hash[:0])
   129  	return hash
   130  }
   131  
   132  func New(config *params.DposConfig, db ethdb.Database) *Dpos {
   133  	signatures, _ := lru.NewARC(inmemorySignatures)
   134  	return &Dpos{
   135  		config:     config,
   136  		db:         db,
   137  		signatures: signatures,
   138  	}
   139  }
   140  
   141  func (d *Dpos) Author(header *types.Header) (common.Address, error) {
   142  	return header.Validator, nil
   143  }
   144  
   145  func (d *Dpos) Coinbase(header *types.Header) (common.Address, error) {
   146  	return header.Coinbase, nil
   147  }
   148  
   149  func (d *Dpos) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error {
   150  	return d.verifyHeader(chain, header, nil)
   151  }
   152  
   153  func (d *Dpos) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error {
   154  	if header.Number == nil {
   155  		return errUnknownBlock
   156  	}
   157  	number := header.Number.Uint64()
   158  	// Unnecssary to verify the block from feature
   159  	if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 {
   160  		return consensus.ErrFutureBlock
   161  	}
   162  	// Check that the extra-data contains both the vanity and signature
   163  	if len(header.Extra) < extraVanity {
   164  		return errMissingVanity
   165  	}
   166  	if len(header.Extra) < extraVanity+extraSeal {
   167  		return errMissingSignature
   168  	}
   169  	// Ensure that the mix digest is zero as we don't have fork protection currently
   170  	if header.MixDigest != (common.Hash{}) {
   171  		return errInvalidMixDigest
   172  	}
   173  	// Difficulty always 1
   174  	if header.Difficulty.Uint64() != 1 {
   175  		return errInvalidDifficulty
   176  	}
   177  	// Ensure that the block doesn't contain any uncles which are meaningless in DPoS
   178  	if header.UncleHash != uncleHash {
   179  		return errInvalidUncleHash
   180  	}
   181  	// If all checks passed, validate any special fields for hard forks
   182  	if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil {
   183  		return err
   184  	}
   185  
   186  	var parent *types.Header
   187  	if len(parents) > 0 {
   188  		parent = parents[len(parents)-1]
   189  	} else {
   190  		parent = chain.GetHeader(header.ParentHash, number-1)
   191  	}
   192  	if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
   193  		return consensus.ErrUnknownAncestor
   194  	}
   195  	if parent.Time.Uint64()+uint64(blockInterval) > header.Time.Uint64() {
   196  		return ErrInvalidTimestamp
   197  	}
   198  	return nil
   199  }
   200  
   201  func (d *Dpos) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
   202  	abort := make(chan struct{})
   203  	results := make(chan error, len(headers))
   204  
   205  	go func() {
   206  		for i, header := range headers {
   207  			err := d.verifyHeader(chain, header, headers[:i])
   208  			select {
   209  			case <-abort:
   210  				return
   211  			case results <- err:
   212  			}
   213  		}
   214  	}()
   215  	return abort, results
   216  }
   217  
   218  // VerifyUncles implements consensus.Engine, always returning an error for any
   219  // uncles as this consensus mechanism doesn't permit uncles.
   220  func (d *Dpos) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
   221  	if len(block.Uncles()) > 0 {
   222  		return errors.New("uncles not allowed")
   223  	}
   224  	return nil
   225  }
   226  
   227  // VerifySeal implements consensus.Engine, checking whether the signature contained
   228  // in the header satisfies the consensus protocol requirements.
   229  func (d *Dpos) VerifySeal(chain consensus.ChainReader, header *types.Header) error {
   230  	return d.verifySeal(chain, header, nil)
   231  }
   232  
   233  func (d *Dpos) verifySeal(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error {
   234  	// Verifying the genesis block is not supported
   235  	number := header.Number.Uint64()
   236  	if number == 0 {
   237  		return errUnknownBlock
   238  	}
   239  	var parent *types.Header
   240  	if len(parents) > 0 {
   241  		parent = parents[len(parents)-1]
   242  	} else {
   243  		parent = chain.GetHeader(header.ParentHash, number-1)
   244  	}
   245  	
   246  	return d.updateConfirmedBlockHeader(chain)
   247  }
   248  
   249  func (d *Dpos) verifyBlockSigner(validator common.Address, header *types.Header) error {
   250  	signer, err := ecrecover(header, d.signatures)
   251  	if err != nil {
   252  		return err
   253  	}
   254  	if bytes.Compare(signer.Bytes(), validator.Bytes()) != 0 {
   255  		return ErrInvalidBlockValidator
   256  	}
   257  	if bytes.Compare(signer.Bytes(), header.Validator.Bytes()) != 0 {
   258  		return ErrMismatchSignerAndValidator
   259  	}
   260  	return nil
   261  }
   262  
   263  func (d *Dpos) updateConfirmedBlockHeader(chain consensus.ChainReader) error {
   264  	
   265  }
   266  
   267  func (d *Dpos) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
   268  	uncles []*types.Header, receipts []*types.Receipt, dposContext *types.DposContext) (*types.Block, error) {
   269  
   270  
   271  	header.DposContext = dposContext.ToProto()
   272  	return types.NewBlock(header, txs, uncles, receipts), nil
   273  }
   274  
   275  func (d *Dpos) checkDeadline(lastBlock *types.Block, now int64) error {
   276  	prevSlot := PrevSlot(now)
   277  	nextSlot := NextSlot(now)
   278  	if lastBlock.Time().Int64() >= nextSlot {
   279  		return ErrMintFutureBlock
   280  	}
   281  	// last block was arrived, or time's up
   282  	if lastBlock.Time().Int64() == prevSlot || nextSlot-now <= 1 {
   283  		return nil
   284  	}
   285  	return ErrWaitForPrevBlock
   286  }
   287  
   288  func (d *Dpos) CheckValidator(lastBlock *types.Block, now int64) error {
   289  	if err := d.checkDeadline(lastBlock, now); err != nil {
   290  		return err
   291  	}
   292  	dposContext, err := types.NewDposContextFromProto(d.db, lastBlock.Header().DposContext)
   293  	if err != nil {
   294  		return idator
   295  	}
   296  	return nil
   297  }
   298  
   299  // Seal generates a new block for the given input block with the local miner's
   300  // seal place on top.
   301  func (d *Dpos) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) {
   302  	header := block.Header()
   303  	number := header.Number.Uint64()
   304  	// Sealing the genesis block is not supported
   305  	if number == 0 {
   306  		return nil, errUnknownBlock
   307  	}
   308  
   309  	return block.WithSeal(header), nil
   310  }
   311  
   312  func (d *Dpos) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
   313  	return big.NewInt(1)
   314  }
   315  
   316  func (d *Dpos) APIs(chain consensus.ChainReader) []rpc.API {
   317  	return []rpc.API{{
   318  		Namespace: "dpos",
   319  		Version:   "1.0",
   320  		Service:   &API{chain: chain, dpos: d},
   321  		Public:    true,
   322  	}}
   323  }
   324  
   325  func (d *Dpos) Authorize(signer common.Address, signFn SignerFn) {
   326  	d.mu.Lock()
   327  	d.signer = signer
   328  	d.signFn = signFn
   329  	d.mu.Unlock()
   330  }
   331  
   332  // ecrecover extracts the Ethereum account address from a signed header.
   333  func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) {
   334  	// If the signature's already cached, return that
   335  	hash := header.Hash()
   336  	if address, known := sigcache.Get(hash); known {
   337  		return address.(common.Address), nil
   338  	}
   339  	
   340  	var signer common.Address
   341  	copy(signer[:], crypto.Keccak256(pubkey[1:])[12:])
   342  	sigcache.Add(hash, signer)
   343  	return signer, nil
   344  }
   345  
   346  func PrevSlot(now int64) int64 {
   347  	return int64((now-1)/blockInterval) * blockInterval
   348  }
   349  
   350  func NextSlot(now int64) int64 {
   351  	return int64((now+blockInterval-1)/blockInterval) * blockInterval
   352  }
   353  
   354  // update counts in MintCntTrie for the miner of newBlock
   355  func updateMintCnt(parentBlockTime, currentBlockTime int64, validator common.Address, dposContext *types.DposContext) {
   356  	currentMintCntTrie := dposContext.MintCntTrie()
   357  	currentEpoch := parentBlockTime / epochInterval
   358  	currentEpochBytes := make([]byte, 8)
   359  	binary.BigEndian.PutUint64(currentEpochBytes, uint64(currentEpoch))
   360  
   361  
   362  
   363  	newCntBytes := make([]byte, 8)
   364  	newEpochBytes := make([]byte, 8)
   365  	binary.BigEndian.PutUint64(newEpochBytes, uint64(newEpoch))
   366  	binary.BigEndian.PutUint64(newCntBytes, uint64(cnt))
   367  	dposContext.MintCntTrie().TryUpdate(append(newEpochBytes, validator.Bytes()...), newCntBytes)
   368  }
   369