github.com/codingfuture/orig-energi3@v0.8.4/core/blockchain_insert.go (about)

     1  // Copyright 2018 The Energi Core Authors
     2  // Copyright 2018 The go-ethereum Authors
     3  // This file is part of the Energi Core library.
     4  //
     5  // The Energi Core library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The Energi Core library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the Energi Core library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package core
    19  
    20  import (
    21  	"time"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/common/mclock"
    25  	"github.com/ethereum/go-ethereum/core/types"
    26  	"github.com/ethereum/go-ethereum/log"
    27  )
    28  
    29  // insertStats tracks and reports on block insertion.
    30  type insertStats struct {
    31  	queued, processed, ignored int
    32  	usedGas                    uint64
    33  	lastIndex                  int
    34  	startTime                  mclock.AbsTime
    35  }
    36  
    37  // statsReportLimit is the time limit during import and export after which we
    38  // always print out progress. This avoids the user wondering what's going on.
    39  const statsReportLimit = 8 * time.Second
    40  
    41  // report prints statistics if some number of blocks have been processed
    42  // or more than a few seconds have passed since the last message.
    43  func (st *insertStats) report(chain []*types.Block, index int, cache common.StorageSize) {
    44  	// Fetch the timings for the batch
    45  	var (
    46  		now     = mclock.Now()
    47  		elapsed = time.Duration(now) - time.Duration(st.startTime)
    48  	)
    49  	// If we're at the last block of the batch or report period reached, log
    50  	if index == len(chain)-1 || elapsed >= statsReportLimit {
    51  		// Count the number of transactions in this segment
    52  		var txs int
    53  		for _, block := range chain[st.lastIndex : index+1] {
    54  			txs += len(block.Transactions())
    55  		}
    56  		end := chain[index]
    57  
    58  		// Assemble the log context and send it to the logger
    59  		context := []interface{}{
    60  			"blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000,
    61  			"elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed),
    62  			"number", end.Number(), "hash", end.Hash(),
    63  		}
    64  		if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute {
    65  			context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)
    66  		}
    67  		context = append(context, []interface{}{"cache", cache}...)
    68  
    69  		if st.queued > 0 {
    70  			context = append(context, []interface{}{"queued", st.queued}...)
    71  		}
    72  		if st.ignored > 0 {
    73  			context = append(context, []interface{}{"ignored", st.ignored}...)
    74  		}
    75  		log.Info("Imported new chain segment", context...)
    76  
    77  		// Bump the stats reported to the next section
    78  		*st = insertStats{startTime: now, lastIndex: index + 1}
    79  	}
    80  }
    81  
    82  // insertIterator is a helper to assist during chain import.
    83  type insertIterator struct {
    84  	chain     types.Blocks
    85  	results   <-chan error
    86  	ready     chan<- bool
    87  	index     int
    88  	validator Validator
    89  }
    90  
    91  // newInsertIterator creates a new iterator based on the given blocks, which are
    92  // assumed to be a contiguous chain.
    93  func newInsertIterator(chain types.Blocks, results <-chan error, ready chan<- bool, validator Validator) *insertIterator {
    94  	return &insertIterator{
    95  		chain:     chain,
    96  		results:   results,
    97  		ready:     ready,
    98  		index:     -1,
    99  		validator: validator,
   100  	}
   101  }
   102  
   103  // next returns the next block in the iterator, along with any potential validation
   104  // error for that block. When the end is reached, it will return (nil, nil).
   105  func (it *insertIterator) next() (*types.Block, error) {
   106  	if it.index+1 >= len(it.chain) {
   107  		it.index = len(it.chain)
   108  		return nil, nil
   109  	}
   110  	it.index++
   111  	if it.ready != nil {
   112  		it.ready <- true
   113  	}
   114  	if err := <-it.results; err != nil {
   115  		return it.chain[it.index], err
   116  	}
   117  	return it.chain[it.index], it.validator.ValidateBody(it.chain[it.index])
   118  }
   119  
   120  // previous returns the previous block was being processed, or nil
   121  func (it *insertIterator) previous() *types.Block {
   122  	if it.index < 1 {
   123  		return nil
   124  	}
   125  	return it.chain[it.index-1]
   126  }
   127  
   128  // first returns the first block in the it.
   129  func (it *insertIterator) first() *types.Block {
   130  	return it.chain[0]
   131  }
   132  
   133  // remaining returns the number of remaining blocks.
   134  func (it *insertIterator) remaining() int {
   135  	return len(it.chain) - it.index
   136  }
   137  
   138  // processed returns the number of processed blocks.
   139  func (it *insertIterator) processed() int {
   140  	return it.index + 1
   141  }