github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/consensus/datong/consensus.go (about)

     1  package datong
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/base64"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"math/big"
    10  	"sort"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/FusionFoundation/efsn/accounts"
    15  	"github.com/FusionFoundation/efsn/common"
    16  	"github.com/FusionFoundation/efsn/common/hexutil"
    17  	"github.com/FusionFoundation/efsn/consensus"
    18  	"github.com/FusionFoundation/efsn/core/rawdb"
    19  	"github.com/FusionFoundation/efsn/core/state"
    20  	"github.com/FusionFoundation/efsn/core/types"
    21  	"github.com/FusionFoundation/efsn/crypto"
    22  	"github.com/FusionFoundation/efsn/crypto/sha3"
    23  	"github.com/FusionFoundation/efsn/ethdb"
    24  	"github.com/FusionFoundation/efsn/log"
    25  	"github.com/FusionFoundation/efsn/params"
    26  	"github.com/FusionFoundation/efsn/rlp"
    27  	"github.com/FusionFoundation/efsn/rpc"
    28  
    29  	cmath "github.com/FusionFoundation/efsn/common/math"
    30  )
    31  
    32  const (
    33  	delayTimeModifier    = 15 // adjust factor
    34  	adjustIntervalBlocks = 10 // adjust delay time by blocks
    35  
    36  	maxNumberOfDeletedTickets = 7 // maximum number of tickets to be deleted because not mining block in time
    37  )
    38  
    39  var (
    40  	errUnknownBlock = errors.New("unknown block")
    41  
    42  	errCoinbase = errors.New("error coinbase")
    43  
    44  	errMissingVanity = errors.New("extra-data 32 byte vanity prefix missing")
    45  
    46  	errMissingSignature = errors.New("extra-data 65 byte suffix signature missing")
    47  
    48  	errUnauthorized = errors.New("unauthorized")
    49  
    50  	ErrNoTicket = errors.New("Miner doesn't have ticket")
    51  )
    52  
    53  // SignerFn is a signer callback function to request a hash to be signed by a
    54  // backing account.
    55  type SignerFn func(accounts.Account, []byte) ([]byte, error)
    56  
    57  var (
    58  	extraVanity         = 32
    59  	extraSeal           = 65
    60  	MinBlockTime int64  = 7   // 7 seconds
    61  	maxBlockTime uint64 = 600 // 10 minutes
    62  )
    63  
    64  // DaTong wacom
    65  type DaTong struct {
    66  	config     *params.DaTongConfig
    67  	db         ethdb.Database
    68  	stateCache state.Database
    69  
    70  	signer common.Address
    71  	signFn SignerFn
    72  	lock   sync.RWMutex
    73  }
    74  
    75  // New wacom
    76  func New(config *params.DaTongConfig, db ethdb.Database) *DaTong {
    77  	return &DaTong{
    78  		config:     config,
    79  		db:         db,
    80  		stateCache: nil,
    81  	}
    82  }
    83  
    84  // Authorize wacom
    85  func (dt *DaTong) Authorize(signer common.Address, signFn SignerFn) {
    86  	dt.lock.Lock()
    87  	defer dt.lock.Unlock()
    88  	dt.signer = signer
    89  	dt.signFn = signFn
    90  }
    91  
    92  // Author retrieves the Ethereum address of the account that minted the given
    93  // block, which may be different from the header's coinbase if a consensus
    94  // engine is based on signatures.
    95  func (dt *DaTong) Author(header *types.Header) (common.Address, error) {
    96  	return header.Coinbase, nil
    97  }
    98  
    99  func VerifySignature(header *types.Header) error {
   100  	signature := header.Extra[len(header.Extra)-extraSeal:]
   101  	pubkey, err := crypto.Ecrecover(sigHash(header).Bytes(), signature)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	var signer common.Address
   106  	copy(signer[:], crypto.Keccak256(pubkey[1:])[12:])
   107  	if header.Coinbase != signer {
   108  		return errors.New("Coinbase is not the signer")
   109  	}
   110  	return nil
   111  }
   112  
   113  // VerifyHeader checks whether a header conforms to the consensus rules of the
   114  // stock Ethereum ethash engine.
   115  func (dt *DaTong) verifyHeader(chain consensus.ChainReader, header *types.Header, seal bool, parents []*types.Header) error {
   116  	if header.Number == nil || header.Number.Sign() == 0 {
   117  		return errUnknownBlock
   118  	}
   119  	// Checkpoint blocks need to enforce zero beneficiary
   120  	if header.Coinbase == (common.Address{}) {
   121  		return errCoinbase
   122  	}
   123  	if len(header.Extra) < extraVanity {
   124  		return errMissingVanity
   125  	}
   126  	if len(header.Extra) < extraVanity+extraSeal {
   127  		return errMissingSignature
   128  	}
   129  	if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 {
   130  		return consensus.ErrFutureBlock
   131  	}
   132  	// verify Ancestor
   133  	parent, err := getParent(chain, header, parents)
   134  	if err != nil {
   135  		return err
   136  	}
   137  	// verify pos hash
   138  	if common.GetPoSHashVersion(header.Number) < common.PosV2 {
   139  		if header.UncleHash != types.EmptyUncleHash {
   140  			return fmt.Errorf("non empty uncle hash")
   141  		}
   142  	} else if header.UncleHash != posHash(parent) {
   143  		return fmt.Errorf("PoS hash mismatch: have %x, want %x", header.UncleHash, posHash(parent))
   144  	}
   145  	// verify header time
   146  	if header.Time.Int64()-parent.Time.Int64() < MinBlockTime {
   147  		return fmt.Errorf("block %v header.Time:%v < parent.Time:%v + %v Second",
   148  			header.Number, header.Time.Int64(), parent.Time.Int64(), MinBlockTime)
   149  
   150  	}
   151  	// verify signature
   152  	if err := VerifySignature(header); err != nil {
   153  		return err
   154  	}
   155  	// check block time
   156  	if err = dt.checkBlockTime(chain, header, parent); err != nil {
   157  		return err
   158  	}
   159  	if isInRange, err := CheckPoint(chain.Config().ChainID, header.Number.Uint64(), header.Hash()); isInRange {
   160  		if err == nil {
   161  			selected, retreat, err := dt.getSelectedAndRetreatedTickets(chain, header, parent)
   162  			if err != nil {
   163  				return err
   164  			}
   165  			// assign selected and retreated tickets (used in Finalize)
   166  			header.SetSelectedTicket(selected)
   167  			header.SetRetreatTickets(retreat)
   168  		}
   169  		return err
   170  	}
   171  	return dt.verifySeal(chain, header, parent)
   172  }
   173  
   174  // VerifyHeader checks whether a header conforms to the consensus rules of the
   175  // stock Ethereum ethash engine.
   176  func (dt *DaTong) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error {
   177  	return dt.verifyHeader(chain, header, seal, glb_parents)
   178  }
   179  
   180  // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
   181  // concurrently. The method returns a quit channel to abort the operations and
   182  // a results channel to retrieve the async verifications.
   183  func (dt *DaTong) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
   184  	abort := make(chan struct{})
   185  	results := make(chan error, len(headers))
   186  	go func() {
   187  		for i, header := range headers {
   188  			err := dt.verifyHeader(chain, header, seals[i], headers[:i])
   189  			select {
   190  			case <-abort:
   191  				return
   192  			case results <- err:
   193  			}
   194  		}
   195  	}()
   196  
   197  	return abort, results
   198  }
   199  
   200  // VerifyUncles verifies that the given block's uncles conform to the consensus
   201  // rules of the stock Ethereum ethash engine.
   202  func (dt *DaTong) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
   203  	return nil
   204  }
   205  
   206  // VerifySeal implements consensus.Engine, checking whether the signature contained
   207  // in the header satisfies the consensus protocol requirements.
   208  func (c *DaTong) VerifySeal(chain consensus.ChainReader, header *types.Header) error {
   209  	return c.verifySeal(chain, header, nil)
   210  }
   211  
   212  var glb_parents []*types.Header
   213  
   214  func SetHeaders(parents []*types.Header) {
   215  	glb_parents = parents
   216  }
   217  
   218  func getParent(chain consensus.ChainReader, header *types.Header, parents []*types.Header) (*types.Header, error) {
   219  	number := header.Number.Uint64()
   220  	var parent *types.Header
   221  	if parents != nil && len(parents) > 0 {
   222  		parent = parents[len(parents)-1]
   223  	} else {
   224  		parent = chain.GetHeader(header.ParentHash, number-1)
   225  	}
   226  	if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
   227  		return nil, consensus.ErrUnknownAncestor
   228  	}
   229  	return parent, nil
   230  }
   231  
   232  // VerifySeal checks whether the crypto seal on a header is valid according to
   233  // the consensus rules of the given engine.
   234  func (dt *DaTong) verifySeal(chain consensus.ChainReader, header *types.Header, parent *types.Header) error {
   235  	// verify ticket
   236  	snap, err := NewSnapshotFromHeader(header)
   237  	if err != nil {
   238  		return err
   239  	}
   240  	// verify ticket: list squence, ID , ticket Info, difficulty
   241  	diff, tk, listSq, retreat, errv := dt.calcBlockDifficulty(chain, header, parent)
   242  	if errv != nil {
   243  		return errv
   244  	}
   245  	// verify ticket with signer
   246  	if tk.Owner != header.Coinbase {
   247  		return errors.New("Coinbase is not the voted ticket owner")
   248  	}
   249  	// check ticket ID
   250  	if tk.ID != snap.Selected {
   251  		return fmt.Errorf("verifySeal ticketID mismatch, have %v, want %v", snap.Selected.String(), tk.ID.String())
   252  	}
   253  	if common.IsHeaderSnapCheckingEnabled(header.Number) {
   254  		// check retreat tickets
   255  		if len(retreat) != len(snap.Retreat) {
   256  			return fmt.Errorf("verifySeal retreat tickets count mismatch")
   257  		}
   258  		for i := 0; i < len(retreat); i++ {
   259  			if retreat[i].ID != snap.Retreat[i] {
   260  				return fmt.Errorf("verifySeal retreat tickets mismatch")
   261  			}
   262  		}
   263  	}
   264  	// check ticket info
   265  	errt := dt.checkTicketInfo(header, tk)
   266  	if errt != nil {
   267  		return errt
   268  	}
   269  	// check ticket order
   270  	if header.Nonce != types.EncodeNonce(listSq) {
   271  		return fmt.Errorf("verifySeal ticket order mismatch, have %v, want %v", header.Nonce.Uint64(), listSq)
   272  	}
   273  
   274  	// check difficulty
   275  	if diff.Cmp(header.Difficulty) != 0 {
   276  		return fmt.Errorf("verifySeal difficulty mismatch, have %v, want %v", header.Difficulty, diff)
   277  	}
   278  
   279  	return nil
   280  }
   281  
   282  // Prepare initializes the consensus fields of a block header according to the
   283  // rules of a particular engine. The changes are executed inline.
   284  func (dt *DaTong) Prepare(chain consensus.ChainReader, header *types.Header) error {
   285  	number := header.Number.Uint64()
   286  	parent := chain.GetHeader(header.ParentHash, number-1)
   287  	if parent == nil {
   288  		return consensus.ErrUnknownAncestor
   289  	}
   290  	if len(header.Extra) < extraVanity {
   291  		header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
   292  	}
   293  	header.Extra = header.Extra[:extraVanity]
   294  	header.Extra = append(header.Extra, make([]byte, extraSeal)...)
   295  	if common.GetPoSHashVersion(header.Number) < common.PosV2 {
   296  		header.UncleHash = types.EmptyUncleHash
   297  	} else {
   298  		header.UncleHash = posHash(parent)
   299  	}
   300  	difficulty, _, order, _, err := dt.calcBlockDifficulty(chain, header, parent)
   301  	if err != nil {
   302  		return err
   303  	}
   304  	header.Nonce = types.EncodeNonce(order)
   305  	header.Difficulty = difficulty
   306  	// adjust block time if illegal
   307  	if order > 0 {
   308  		recvTime := header.Time.Int64() - parent.Time.Int64()
   309  		maxDelaySeconds := int64(maxBlockTime + dt.config.Period)
   310  		if recvTime < maxDelaySeconds {
   311  			expectTime := int64(dt.config.Period + order*delayTimeModifier)
   312  			if recvTime < expectTime {
   313  				if expectTime > maxDelaySeconds {
   314  					expectTime = maxDelaySeconds
   315  				}
   316  				header.Time = big.NewInt(parent.Time.Int64() + expectTime)
   317  			}
   318  		}
   319  	}
   320  	return nil
   321  }
   322  
   323  type DisInfo struct {
   324  	tk  *common.Ticket
   325  	res *big.Int
   326  }
   327  type DistanceSlice []*DisInfo
   328  
   329  func (s DistanceSlice) Len() int {
   330  	return len(s)
   331  }
   332  
   333  func (s DistanceSlice) Less(i, j int) bool {
   334  	return s[i].res.Cmp(s[j].res) < 0
   335  }
   336  
   337  func (s DistanceSlice) Swap(i, j int) {
   338  	s[i], s[j] = s[j], s[i]
   339  }
   340  
   341  // Finalize runs any post-transaction state modifications (e.g. block rewards)
   342  // and assembles the final block.
   343  // Note: The block header and state database might be updated to reflect any
   344  // consensus rules that happen at finalization (e.g. block rewards).
   345  func (dt *DaTong) Finalize(chain consensus.ChainReader, header *types.Header, statedb *state.StateDB, txs []*types.Transaction,
   346  	uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
   347  	parent, err := getParent(chain, header, glb_parents)
   348  	if err != nil {
   349  		return nil, err
   350  	}
   351  	selected := header.GetSelectedTicket()
   352  	retreat := header.GetRetreatTickets()
   353  	if selected == nil {
   354  		log.Warn("Finalize shouldn't calc difficulty, as it's done in VerifyHeader or Prepare")
   355  		common.DebugCall(func() {
   356  			panic("Finalize shouldn't calc difficulty, as it's done in VerifyHeader or Prepare")
   357  		})
   358  		_, selected, _, retreat, err = dt.calcBlockDifficulty(chain, header, parent)
   359  		if err != nil {
   360  			return nil, err
   361  		}
   362  	}
   363  
   364  	snap := newSnapshot()
   365  	isInMining := header.MixDigest == (common.Hash{})
   366  
   367  	//update tickets
   368  	headerState := statedb
   369  	tickets, err := headerState.AllTickets()
   370  	if err != nil {
   371  		return nil, err
   372  	}
   373  	numTickets := tickets.NumberOfTickets()
   374  	if numTickets <= 1 {
   375  		log.Warn("Next block doesn't have ticket, wait buy ticket")
   376  		return nil, errors.New("Next block doesn't have ticket, wait buy ticket")
   377  	}
   378  
   379  	returnTicket := func(ticket *common.Ticket) {
   380  		if ticket.ExpireTime <= header.Time.Uint64() {
   381  			return
   382  		}
   383  		value := common.NewTimeLock(&common.TimeLockItem{
   384  			StartTime: ticket.StartTime,
   385  			EndTime:   ticket.ExpireTime,
   386  			Value:     ticket.Value(),
   387  		})
   388  		headerState.AddTimeLockBalance(ticket.Owner, common.SystemAssetID, value, header.Number, header.Time.Uint64())
   389  	}
   390  
   391  	deleteTicket := func(ticket *common.Ticket, logType ticketLogType, returnBack bool) {
   392  		id := ticket.ID
   393  		headerState.RemoveTicket(id)
   394  		snap.AddLog(&ticketLog{
   395  			TicketID: id,
   396  			Type:     logType,
   397  		})
   398  		if returnBack {
   399  			returnTicket(ticket)
   400  		}
   401  	}
   402  
   403  	deleteTicket(selected, ticketSelect, !selected.IsInGenesis())
   404  
   405  	//delete tickets before coinbase if selected miner did not Seal
   406  	for i, t := range retreat {
   407  		if !isInMining && i == 0 {
   408  			common.DebugInfo("retreat ticket", "nonce", header.Nonce.Uint64(), "id", retreat[0].ID.String(), "owner", retreat[0].Owner, "blockHeight", header.Number, "ticketHeight", retreat[0].Height)
   409  		}
   410  		deleteTicket(t, ticketRetreat, !(t.IsInGenesis() || i == 0))
   411  	}
   412  
   413  	if common.IsVote1ForkBlock(header.Number) {
   414  		ApplyVote1HardFork(headerState, header.Number, parent.Time.Uint64())
   415  	}
   416  
   417  	hash, err := headerState.UpdateTickets(header.Number, parent.Time.Uint64())
   418  	if err != nil {
   419  		return nil, errors.New("UpdateTickets failed: " + err.Error())
   420  	}
   421  
   422  	snap.SetTicketNumber(int(headerState.TotalNumberOfTickets()))
   423  	snapBytes := snap.Bytes()
   424  
   425  	if isInMining {
   426  		header.MixDigest = hash
   427  		header.Extra = header.Extra[:extraVanity]
   428  		header.Extra = append(header.Extra, snapBytes...)
   429  		header.Extra = append(header.Extra, make([]byte, extraSeal)...)
   430  	} else {
   431  		if header.MixDigest != hash {
   432  			return nil, fmt.Errorf("MixDigest mismatch, have:%v, want:%v", header.MixDigest, hash)
   433  		}
   434  		if common.IsHeaderSnapCheckingEnabled(header.Number) {
   435  			if !bytes.Equal(getSnapData(header.Extra), snapBytes) {
   436  				return nil, fmt.Errorf("snapBytes in Extra mismatch")
   437  			}
   438  		}
   439  	}
   440  
   441  	headerState.AddBalance(header.Coinbase, common.SystemAssetID, CalcRewards(header.Number))
   442  	header.Root = headerState.IntermediateRoot(chain.Config().IsEIP158(header.Number))
   443  	return types.NewBlock(header, txs, nil, receipts), nil
   444  }
   445  
   446  // Seal generates a new sealing request for the given input block and pushes
   447  // the result into the given channel.
   448  //
   449  // Note, the method returns immediately and will send the result async. More
   450  // than one result may also be returned depending on the consensus algorothm.
   451  func (dt *DaTong) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
   452  	header := block.Header()
   453  	number := header.Number.Uint64()
   454  	if number == 0 {
   455  		return errUnknownBlock
   456  	}
   457  	dt.lock.RLock()
   458  	signer, signFn := dt.signer, dt.signFn
   459  	dt.lock.RUnlock()
   460  
   461  	if signer != header.Coinbase {
   462  		return errors.New("Mismatched Signer and Coinbase")
   463  	}
   464  
   465  	// delay time decide block time
   466  	delay, errc := dt.calcDelayTime(chain, header)
   467  	if errc != nil {
   468  		return errc
   469  	}
   470  
   471  	sighash, err := signFn(accounts.Account{Address: header.Coinbase}, sigHash(header).Bytes())
   472  	if err != nil {
   473  		return err
   474  	}
   475  	copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
   476  
   477  	go func() {
   478  		select {
   479  		case <-stop:
   480  			return
   481  		case <-time.After(delay):
   482  		}
   483  
   484  		select {
   485  		case results <- block.WithSeal(header):
   486  		default:
   487  			log.Warn("Sealing result is not read by miner", "sealhash", dt.SealHash(header))
   488  		}
   489  	}()
   490  
   491  	return nil
   492  }
   493  
   494  // SealHash returns the hash of a block prior to it being sealed.
   495  func (dt *DaTong) SealHash(header *types.Header) (hash common.Hash) {
   496  	hasher := sha3.NewKeccak256()
   497  	rlp.Encode(hasher, []interface{}{
   498  		header.ParentHash,
   499  		header.UncleHash,
   500  		header.Coinbase,
   501  		header.Root,
   502  		header.TxHash,
   503  		header.ReceiptHash,
   504  		header.Bloom,
   505  		header.Difficulty,
   506  		header.Number,
   507  		header.GasLimit,
   508  		header.GasUsed,
   509  		header.Extra[:extraVanity],
   510  		header.MixDigest,
   511  		header.Nonce,
   512  	})
   513  	hasher.Sum(hash[:0])
   514  	return hash
   515  }
   516  
   517  // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty
   518  // that a new block should have.
   519  func (dt *DaTong) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
   520  	return nil
   521  }
   522  
   523  // APIs returns the RPC APIs this consensus engine provides.
   524  func (dt *DaTong) APIs(chain consensus.ChainReader) []rpc.API {
   525  	return []rpc.API{{
   526  		Namespace: "fsn",
   527  		Version:   "1.0",
   528  		Service:   &API{chain: chain},
   529  		Public:    false,
   530  	}}
   531  }
   532  
   533  // Close terminates any background threads maintained by the consensus engine.
   534  func (dt *DaTong) Close() error {
   535  	return nil
   536  }
   537  
   538  func (dt *DaTong) getAllTickets(chain consensus.ChainReader, header *types.Header) (common.TicketsDataSlice, error) {
   539  	if ts := state.GetCachedTickets(header.MixDigest); ts != nil {
   540  		return ts, nil
   541  	}
   542  	statedb, err := state.New(header.Root, header.MixDigest, dt.stateCache)
   543  	if err == nil {
   544  		return statedb.AllTickets()
   545  	} else if header.Number.Uint64() == 0 {
   546  		return nil, err
   547  	}
   548  
   549  	// get tickets from past state
   550  	var tickets common.TicketsDataSlice
   551  	parent := header
   552  	parents := []*types.Header{parent}
   553  	for {
   554  		if parent = chain.GetHeader(parent.ParentHash, parent.Number.Uint64()-1); parent == nil {
   555  			return nil, fmt.Errorf("Can not find parent, number=%v, hash=%v", parent.Number.Uint64()-1, parent.ParentHash.String())
   556  		}
   557  		statedb, err = state.New(parent.Root, parent.MixDigest, dt.stateCache)
   558  		if err == nil {
   559  			if tickets, err = statedb.AllTickets(); err != nil {
   560  				return nil, err
   561  			}
   562  			break
   563  		} else if parent.Number.Uint64() == 0 {
   564  			return nil, err
   565  		}
   566  		parents = append(parents, parent)
   567  	}
   568  	log.Info("getAllTickets find tickets from past state", "current", header.Number, "past", parent.Number)
   569  	defer func(bstart time.Time) {
   570  		common.DebugInfo("getAllTickets from past state spend time", "duration", common.PrettyDuration(time.Since(bstart)))
   571  	}(time.Now())
   572  
   573  	// deduct the current tickets
   574  	getFuncType := func(l *types.Log) uint8 {
   575  		switch l.Address {
   576  		case common.FSNCallAddress:
   577  			if len(l.Topics) > 0 {
   578  				topic := l.Topics[0]
   579  				return topic[common.HashLength-1]
   580  			}
   581  		}
   582  		return 0xff
   583  	}
   584  	processBuyTicketLog := func(l *types.Log) error {
   585  		maps := make(map[string]interface{})
   586  		err := json.Unmarshal(l.Data, &maps)
   587  		if err != nil {
   588  			return err
   589  		}
   590  
   591  		if _, hasError := maps["Error"]; hasError {
   592  			return nil
   593  		}
   594  
   595  		idstr, idok := maps["TicketID"].(string)
   596  		ownerstr, ownerok := maps["TicketOwner"].(string)
   597  		datastr, dataok := maps["Base"].(string)
   598  		if !idok || !ownerok || !dataok {
   599  			return errors.New("buy ticket log has wrong data")
   600  		}
   601  
   602  		data, err := base64.StdEncoding.DecodeString(datastr)
   603  		if err != nil {
   604  			return err
   605  		}
   606  
   607  		buyTicketParam := common.BuyTicketParam{}
   608  		rlp.DecodeBytes(data, &buyTicketParam)
   609  
   610  		ticket := &common.Ticket{
   611  			Owner: common.HexToAddress(ownerstr),
   612  			TicketBody: common.TicketBody{
   613  				ID:         common.HexToHash(idstr),
   614  				Height:     l.BlockNumber,
   615  				StartTime:  buyTicketParam.Start,
   616  				ExpireTime: buyTicketParam.End,
   617  			},
   618  		}
   619  		tickets, err = tickets.AddTicket(ticket)
   620  		return err
   621  	}
   622  	processReportLog := func(l *types.Log) error {
   623  		maps := make(map[string]interface{})
   624  		err := json.Unmarshal(l.Data, &maps)
   625  		if err != nil {
   626  			return err
   627  		}
   628  
   629  		if _, hasError := maps["Error"]; hasError {
   630  			return nil
   631  		}
   632  
   633  		ids, idsok := maps["DeleteTickets"].(string)
   634  		if !idsok {
   635  			return fmt.Errorf("report log has wrong data")
   636  		}
   637  
   638  		bs, err := hexutil.Decode(ids)
   639  		if err != nil {
   640  			return fmt.Errorf("decode hex data error: %v", err)
   641  		}
   642  		delTickets := []common.Hash{}
   643  		if err := rlp.DecodeBytes(bs, &delTickets); err != nil {
   644  			return fmt.Errorf("decode report log error: %v", err)
   645  		}
   646  
   647  		for _, id := range delTickets {
   648  			tickets, err = tickets.RemoveTicket(id)
   649  			if err != nil {
   650  				return err
   651  			}
   652  		}
   653  
   654  		return nil
   655  	}
   656  	processLog := func(l *types.Log) error {
   657  		funcType := getFuncType(l)
   658  		switch funcType {
   659  		case common.BuyTicketFunc:
   660  			if err := processBuyTicketLog(l); err != nil {
   661  				return err
   662  			}
   663  		case common.ReportIllegalFunc:
   664  			if err := processReportLog(l); err != nil {
   665  				return err
   666  			}
   667  		}
   668  		return nil
   669  	}
   670  	processSnap := func(h *types.Header) error {
   671  		snap, err := NewSnapshotFromHeader(h)
   672  		if err != nil {
   673  			return err
   674  		}
   675  		tickets, err = tickets.RemoveTicket(snap.Selected)
   676  		if err != nil {
   677  			return err
   678  		}
   679  		for _, id := range snap.Retreat {
   680  			tickets, err = tickets.RemoveTicket(id)
   681  			if err != nil {
   682  				return err
   683  			}
   684  		}
   685  		return nil
   686  	}
   687  
   688  	for i := len(parents) - 1; i >= 0; i-- {
   689  		hash := parents[i].Hash()
   690  		if number := rawdb.ReadHeaderNumber(dt.db, hash); number != nil {
   691  			receipts := rawdb.ReadReceipts(dt.db, hash, *number)
   692  			for _, receipt := range receipts {
   693  				for _, log := range receipt.Logs {
   694  					if err := processLog(log); err != nil {
   695  						return nil, err
   696  					}
   697  				}
   698  			}
   699  		}
   700  		if err := processSnap(parents[i]); err != nil {
   701  			return nil, err
   702  		}
   703  	}
   704  
   705  	tickets, err = tickets.ClearExpiredTickets(header.Time.Uint64())
   706  	if err != nil {
   707  		return nil, err
   708  	}
   709  	if err := state.AddCachedTickets(header.MixDigest, tickets); err != nil {
   710  		return nil, err
   711  	}
   712  	return tickets, nil
   713  }
   714  
   715  func sigHash(header *types.Header) (hash common.Hash) {
   716  	hasher := sha3.NewKeccak256()
   717  	rlp.Encode(hasher, []interface{}{
   718  		header.ParentHash,
   719  		header.UncleHash,
   720  		header.Coinbase,
   721  		header.Root,
   722  		header.TxHash,
   723  		header.ReceiptHash,
   724  		header.Bloom,
   725  		header.Difficulty,
   726  		header.Number,
   727  		header.GasLimit,
   728  		header.GasUsed,
   729  		header.Time,
   730  		header.Extra[:len(header.Extra)-extraSeal],
   731  		header.MixDigest,
   732  		header.Nonce,
   733  	})
   734  	hasher.Sum(hash[:0])
   735  	return hash
   736  }
   737  
   738  func getSnapDataByHeader(header *types.Header) []byte {
   739  	return getSnapData(header.Extra)
   740  }
   741  
   742  func getSnapData(data []byte) []byte {
   743  	extraSuffix := len(data) - extraSeal
   744  	if extraSuffix < extraVanity {
   745  		return []byte{}
   746  	}
   747  	return data[extraVanity:extraSuffix]
   748  }
   749  
   750  func CalcRewards(height *big.Int) *big.Int {
   751  	var i int64
   752  	div2 := big.NewInt(2)
   753  	// initial reward 2.5
   754  	var reward = new(big.Int).Mul(big.NewInt(25), big.NewInt(100000000000000000))
   755  	// every 4915200 blocks divide reward by 2
   756  	segment := new(big.Int).Div(height, new(big.Int).SetUint64(4915200))
   757  	for i = 0; i < segment.Int64(); i++ {
   758  		reward = new(big.Int).Div(reward, div2)
   759  	}
   760  	return reward
   761  }
   762  
   763  // get rid of header.Extra[0:extraVanity] of user custom data
   764  func posHash(header *types.Header) (hash common.Hash) {
   765  	hasher := sha3.NewKeccak256()
   766  	switch common.GetPoSHashVersion(header.Number) {
   767  	case common.PosV1:
   768  		rlp.Encode(hasher, []interface{}{
   769  			header.ParentHash,
   770  			header.UncleHash,
   771  			header.Coinbase,
   772  			header.Root,
   773  			header.TxHash,
   774  			header.ReceiptHash,
   775  			header.Bloom,
   776  			header.Difficulty,
   777  			header.Number,
   778  			header.GasLimit,
   779  			header.GasUsed,
   780  			header.Time,
   781  			header.Extra[extraVanity : len(header.Extra)-extraSeal],
   782  			header.MixDigest,
   783  			header.Nonce,
   784  		})
   785  	case common.PosV2:
   786  		rlp.Encode(hasher, []interface{}{
   787  			header.UncleHash,
   788  			header.Coinbase,
   789  			header.Difficulty,
   790  			header.Number,
   791  			(header.Time.Uint64() >> 5) << 5,
   792  			header.Extra[extraVanity : len(header.Extra)-extraSeal],
   793  			header.MixDigest,
   794  			header.Nonce,
   795  		})
   796  	case common.PosV3:
   797  		rlp.Encode(hasher, []interface{}{
   798  			header.UncleHash,
   799  			header.Coinbase,
   800  			header.Difficulty,
   801  			header.Number,
   802  			(header.Time.Uint64() >> 5) << 5,
   803  			header.Extra[extraVanity : len(header.Extra)-extraSeal],
   804  			header.Nonce,
   805  		})
   806  	}
   807  	hasher.Sum(hash[:0])
   808  	return hash
   809  }
   810  
   811  type DisInfoWithIndex struct {
   812  	index int
   813  	info  *DisInfo
   814  }
   815  
   816  func calcDisInfo(ind int, tickets common.TicketsData, parent *types.Header, ch chan *DisInfoWithIndex) {
   817  	posHash := posHash(parent)
   818  	owner := tickets.Owner
   819  
   820  	var minTicket common.TicketBody
   821  	var minDist *big.Int
   822  	for _, t := range tickets.Tickets {
   823  		w := new(big.Int).SetUint64(parent.Number.Uint64() - t.Height + 1)
   824  		w2 := new(big.Int).Mul(w, w)
   825  
   826  		id := new(big.Int).SetBytes(crypto.Keccak256(posHash[:], t.ID[:], []byte(owner.Hex())))
   827  		id2 := new(big.Int).Mul(id, id)
   828  		s := new(big.Int).Add(w2, id2)
   829  
   830  		if minDist == nil || s.Cmp(minDist) < 0 {
   831  			minTicket = t
   832  			minDist = s
   833  		}
   834  	}
   835  	ticket := &common.Ticket{
   836  		Owner:      owner,
   837  		TicketBody: minTicket,
   838  	}
   839  	result := &DisInfoWithIndex{index: ind, info: &DisInfo{tk: ticket, res: minDist}}
   840  	ch <- result
   841  }
   842  
   843  func (dt *DaTong) calcBlockDifficulty(chain consensus.ChainReader, header *types.Header, parent *types.Header) (*big.Int, *common.Ticket, uint64, common.TicketPtrSlice, error) {
   844  	if header.GetSelectedTicket() != nil {
   845  		return header.Difficulty, header.GetSelectedTicket(), header.Nonce.Uint64(), header.GetRetreatTickets(), nil
   846  	}
   847  	parentTickets, err := dt.getAllTickets(chain, parent)
   848  	if err != nil {
   849  		return nil, nil, 0, nil, err
   850  	}
   851  	haveTicket := false
   852  	for _, v := range parentTickets {
   853  		if v.Owner == header.Coinbase {
   854  			haveTicket = true
   855  			break
   856  		}
   857  	}
   858  	if !haveTicket {
   859  		return nil, nil, 0, nil, ErrNoTicket
   860  	}
   861  	ticketsTotalAmount, numberOfticketOwners := parentTickets.NumberOfTicketsAndOwners()
   862  
   863  	// calc balance before selected ticket from stored tickets list
   864  	var (
   865  		selected *common.Ticket
   866  		retreat  common.TicketPtrSlice
   867  	)
   868  
   869  	// make consensus by tickets sequence(selectedTime) with: parentHash, weigth, ticketID, coinbase
   870  	ch := make(chan *DisInfoWithIndex, numberOfticketOwners)
   871  	list := make(DistanceSlice, numberOfticketOwners)
   872  	for k, v := range parentTickets {
   873  		go calcDisInfo(k, v, parent, ch)
   874  	}
   875  	for i := 0; i < int(numberOfticketOwners); i++ {
   876  		v := <-ch
   877  		list[v.index] = v.info
   878  	}
   879  	close(ch)
   880  	sort.Sort(list)
   881  	selectedTime := uint64(0)
   882  	for i, t := range list {
   883  		owner := t.tk.Owner
   884  		if owner == header.Coinbase {
   885  			selected = t.tk
   886  			break
   887  		} else {
   888  			selectedTime++
   889  			if i < maxNumberOfDeletedTickets {
   890  				retreat = append(retreat, t.tk) // one miner one selected ticket
   891  			}
   892  		}
   893  	}
   894  	if selected == nil {
   895  		return nil, nil, 0, nil, errors.New("myself tickets not selected in maxBlockTime")
   896  	}
   897  
   898  	// cacl difficulty
   899  	difficulty := new(big.Int).SetUint64(ticketsTotalAmount - selectedTime)
   900  	if selectedTime > 0 {
   901  		// base10 = base * 10 (base > 1)
   902  		base10 := int64(16)
   903  		// exponent = max(selectedTime, 50)
   904  		exponent := int64(selectedTime)
   905  		if exponent > 50 {
   906  			exponent = 50
   907  		}
   908  		// difficulty = ticketsTotal * pow(10, exponent) / pow(base10, exponent)
   909  		difficulty = new(big.Int).Div(
   910  			new(big.Int).Mul(difficulty, cmath.BigPow(10, exponent)),
   911  			cmath.BigPow(base10, exponent))
   912  		if difficulty.Cmp(common.Big1) < 0 {
   913  			difficulty = common.Big1
   914  		}
   915  	}
   916  	adjust := new(big.Int).SetUint64(numberOfticketOwners - selectedTime)
   917  	difficulty = new(big.Int).Add(difficulty, adjust)
   918  
   919  	header.SetSelectedTicket(selected)
   920  	header.SetRetreatTickets(retreat)
   921  
   922  	return difficulty, selected, selectedTime, retreat, nil
   923  }
   924  
   925  // PreProcess update state if needed from various block info
   926  // used with some PoS Systems
   927  func (c *DaTong) PreProcess(chain consensus.ChainReader, header *types.Header, statedb *state.StateDB) error {
   928  	return nil
   929  }
   930  
   931  func (dt *DaTong) calcDelayTime(chain consensus.ChainReader, header *types.Header) (time.Duration, error) {
   932  	list := header.Nonce.Uint64()
   933  	if list > 0 {
   934  		return time.Unix(header.Time.Int64(), 0).Sub(time.Now()), nil
   935  	}
   936  
   937  	// delayTime = ParentTime + (15 - 2) - time.Now
   938  	parent := chain.GetHeaderByNumber(header.Number.Uint64() - 1)
   939  	endTime := new(big.Int).Add(header.Time, new(big.Int).SetUint64(list*uint64(delayTimeModifier)+dt.config.Period-2))
   940  	delayTime := time.Unix(endTime.Int64(), 0).Sub(time.Now())
   941  
   942  	// delay maximum
   943  	if (new(big.Int).Sub(endTime, header.Time)).Uint64() > maxBlockTime {
   944  		endTime = new(big.Int).Add(header.Time, new(big.Int).SetUint64(maxBlockTime+dt.config.Period-2+list))
   945  		delayTime = time.Unix(endTime.Int64(), 0).Sub(time.Now())
   946  	}
   947  	if header.Number.Uint64() > (adjustIntervalBlocks + 1) {
   948  		// adjust = ( ( parent - gparent ) / 2 - (dt.config.Period) ) / dt.config.Period
   949  		gparent := chain.GetHeaderByNumber(header.Number.Uint64() - 1 - adjustIntervalBlocks)
   950  		adjust := ((time.Unix(parent.Time.Int64(), 0).Sub(time.Unix(gparent.Time.Int64(), 0)) / adjustIntervalBlocks) -
   951  			time.Duration(int64(dt.config.Period))*time.Second) /
   952  			time.Duration(int64(adjustIntervalBlocks))
   953  
   954  		stampSecond := time.Duration(2) * time.Second
   955  		if adjust > stampSecond {
   956  			adjust = stampSecond
   957  		} else if adjust < -stampSecond {
   958  			adjust = -stampSecond
   959  		}
   960  		delayTime -= adjust
   961  	}
   962  	return delayTime, nil
   963  }
   964  
   965  // check ticket info
   966  func (dt *DaTong) checkTicketInfo(header *types.Header, ticket *common.Ticket) error {
   967  	// check height
   968  	if ticket.BlockHeight().Cmp(header.Number) >= 0 {
   969  		return errors.New("checkTicketInfo ticket height mismatch")
   970  	}
   971  	// check start and expire time
   972  	if ticket.ExpireTime <= ticket.StartTime ||
   973  		ticket.ExpireTime < (ticket.StartTime+30*24*3600) ||
   974  		ticket.ExpireTime < header.Time.Uint64() {
   975  		return errors.New("checkTicketInfo ticket ExpireTime mismatch")
   976  	}
   977  	return nil
   978  }
   979  
   980  // check block time
   981  func (dt *DaTong) checkBlockTime(chain consensus.ChainReader, header *types.Header, parent *types.Header) error {
   982  	list := header.Nonce.Uint64()
   983  	if list <= 0 { // No.1 pass, check others
   984  		return nil
   985  	}
   986  	recvTime := header.Time.Int64() - parent.Time.Int64()
   987  	maxDelaySeconds := int64(maxBlockTime + dt.config.Period)
   988  	if recvTime < maxDelaySeconds {
   989  		expectTime := int64(dt.config.Period + list*delayTimeModifier)
   990  		if recvTime < expectTime {
   991  			return fmt.Errorf("block time mismatch: order: %v, receive: %v, expect: %v.", list, recvTime, expectTime)
   992  		}
   993  	}
   994  	return nil
   995  }
   996  
   997  func (dt *DaTong) SetStateCache(stateCache state.Database) {
   998  	dt.stateCache = stateCache
   999  }
  1000  
  1001  func (dt *DaTong) getSelectedAndRetreatedTickets(chain consensus.ChainReader, header *types.Header, parent *types.Header) (*common.Ticket, common.TicketPtrSlice, error) {
  1002  	parentTickets, err := dt.getAllTickets(chain, parent)
  1003  	if err != nil {
  1004  		return nil, nil, err
  1005  	}
  1006  	snap, err := NewSnapshotFromHeader(header)
  1007  	if err != nil {
  1008  		return nil, nil, err
  1009  	}
  1010  	selectedTicket, err := parentTickets.Get(snap.Selected)
  1011  	if err != nil {
  1012  		return nil, nil, err
  1013  	}
  1014  	retreat := make(common.TicketPtrSlice, len(snap.Retreat))
  1015  	for i, tid := range snap.Retreat {
  1016  		ticket, err := parentTickets.Get(tid)
  1017  		if err != nil {
  1018  			return nil, nil, err
  1019  		}
  1020  		retreat[i] = ticket
  1021  	}
  1022  	return selectedTicket, retreat, nil
  1023  }