| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | // Copyright 2018 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package core | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common/mclock" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // insertStats tracks and reports on block insertion. | 
					
						
							|  |  |  | type insertStats struct { | 
					
						
							|  |  |  | 	queued, processed, ignored int | 
					
						
							|  |  |  | 	usedGas                    uint64 | 
					
						
							|  |  |  | 	lastIndex                  int | 
					
						
							|  |  |  | 	startTime                  mclock.AbsTime | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // statsReportLimit is the time limit during import and export after which we | 
					
						
							|  |  |  | // always print out progress. This avoids the user wondering what's going on. | 
					
						
							|  |  |  | const statsReportLimit = 8 * time.Second | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // report prints statistics if some number of blocks have been processed | 
					
						
							|  |  |  | // or more than a few seconds have passed since the last message. | 
					
						
							| 
									
										
										
										
											2019-02-05 12:49:59 +02:00
										 |  |  | func (st *insertStats) report(chain []*types.Block, index int, dirty common.StorageSize) { | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | 	// Fetch the timings for the batch | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		now     = mclock.Now() | 
					
						
							|  |  |  | 		elapsed = time.Duration(now) - time.Duration(st.startTime) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	// If we're at the last block of the batch or report period reached, log | 
					
						
							|  |  |  | 	if index == len(chain)-1 || elapsed >= statsReportLimit { | 
					
						
							|  |  |  | 		// Count the number of transactions in this segment | 
					
						
							|  |  |  | 		var txs int | 
					
						
							|  |  |  | 		for _, block := range chain[st.lastIndex : index+1] { | 
					
						
							|  |  |  | 			txs += len(block.Transactions()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		end := chain[index] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Assemble the log context and send it to the logger | 
					
						
							|  |  |  | 		context := []interface{}{ | 
					
						
							|  |  |  | 			"blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000, | 
					
						
							|  |  |  | 			"elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed), | 
					
						
							|  |  |  | 			"number", end.Number(), "hash", end.Hash(), | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-04-02 22:28:48 +02:00
										 |  |  | 		if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute { | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | 			context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-02-05 12:49:59 +02:00
										 |  |  | 		context = append(context, []interface{}{"dirty", dirty}...) | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if st.queued > 0 { | 
					
						
							|  |  |  | 			context = append(context, []interface{}{"queued", st.queued}...) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if st.ignored > 0 { | 
					
						
							|  |  |  | 			context = append(context, []interface{}{"ignored", st.ignored}...) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		log.Info("Imported new chain segment", context...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Bump the stats reported to the next section | 
					
						
							|  |  |  | 		*st = insertStats{startTime: now, lastIndex: index + 1} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // insertIterator is a helper to assist during chain import. | 
					
						
							|  |  |  | type insertIterator struct { | 
					
						
							| 
									
										
										
										
											2019-03-25 12:41:50 +02:00
										 |  |  | 	chain types.Blocks // Chain of blocks being iterated over | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	results <-chan error // Verification result sink from the consensus engine | 
					
						
							|  |  |  | 	errors  []error      // Header verification errors for the blocks | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	index     int       // Current offset of the iterator | 
					
						
							|  |  |  | 	validator Validator // Validator to run if verification succeeds | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newInsertIterator creates a new iterator based on the given blocks, which are | 
					
						
							|  |  |  | // assumed to be a contiguous chain. | 
					
						
							|  |  |  | func newInsertIterator(chain types.Blocks, results <-chan error, validator Validator) *insertIterator { | 
					
						
							|  |  |  | 	return &insertIterator{ | 
					
						
							|  |  |  | 		chain:     chain, | 
					
						
							|  |  |  | 		results:   results, | 
					
						
							| 
									
										
										
										
											2019-03-25 12:41:50 +02:00
										 |  |  | 		errors:    make([]error, 0, len(chain)), | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | 		index:     -1, | 
					
						
							|  |  |  | 		validator: validator, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // next returns the next block in the iterator, along with any potential validation | 
					
						
							|  |  |  | // error for that block. When the end is reached, it will return (nil, nil). | 
					
						
							|  |  |  | func (it *insertIterator) next() (*types.Block, error) { | 
					
						
							| 
									
										
										
										
											2019-03-25 12:41:50 +02:00
										 |  |  | 	// If we reached the end of the chain, abort | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | 	if it.index+1 >= len(it.chain) { | 
					
						
							|  |  |  | 		it.index = len(it.chain) | 
					
						
							|  |  |  | 		return nil, nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-03-25 12:41:50 +02:00
										 |  |  | 	// Advance the iterator and wait for verification result if not yet done | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | 	it.index++ | 
					
						
							| 
									
										
										
										
											2019-03-25 12:41:50 +02:00
										 |  |  | 	if len(it.errors) <= it.index { | 
					
						
							|  |  |  | 		it.errors = append(it.errors, <-it.results) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if it.errors[it.index] != nil { | 
					
						
							|  |  |  | 		return it.chain[it.index], it.errors[it.index] | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-03-25 12:41:50 +02:00
										 |  |  | 	// Block header valid, run body validation and return | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | 	return it.chain[it.index], it.validator.ValidateBody(it.chain[it.index]) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-25 12:41:50 +02:00
										 |  |  | // peek returns the next block in the iterator, along with any potential validation | 
					
						
							|  |  |  | // error for that block, but does **not** advance the iterator. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Both header and body validation errors (nil too) is cached into the iterator | 
					
						
							|  |  |  | // to avoid duplicating work on the following next() call. | 
					
						
							|  |  |  | func (it *insertIterator) peek() (*types.Block, error) { | 
					
						
							|  |  |  | 	// If we reached the end of the chain, abort | 
					
						
							|  |  |  | 	if it.index+1 >= len(it.chain) { | 
					
						
							|  |  |  | 		return nil, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Wait for verification result if not yet done | 
					
						
							|  |  |  | 	if len(it.errors) <= it.index+1 { | 
					
						
							|  |  |  | 		it.errors = append(it.errors, <-it.results) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if it.errors[it.index+1] != nil { | 
					
						
							|  |  |  | 		return it.chain[it.index+1], it.errors[it.index+1] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Block header valid, ignore body validation since we don't have a parent anyway | 
					
						
							|  |  |  | 	return it.chain[it.index+1], nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-13 12:31:35 +02:00
										 |  |  | // previous returns the previous header that was being processed, or nil. | 
					
						
							|  |  |  | func (it *insertIterator) previous() *types.Header { | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | 	if it.index < 1 { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-03-13 12:31:35 +02:00
										 |  |  | 	return it.chain[it.index-1].Header() | 
					
						
							| 
									
										
										
										
											2018-11-20 14:15:26 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // first returns the first block in the it. | 
					
						
							|  |  |  | func (it *insertIterator) first() *types.Block { | 
					
						
							|  |  |  | 	return it.chain[0] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // remaining returns the number of remaining blocks. | 
					
						
							|  |  |  | func (it *insertIterator) remaining() int { | 
					
						
							|  |  |  | 	return len(it.chain) - it.index | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // processed returns the number of processed blocks. | 
					
						
							|  |  |  | func (it *insertIterator) processed() int { | 
					
						
							|  |  |  | 	return it.index + 1 | 
					
						
							|  |  |  | } |