github.com/klaytn/klaytn@v1.12.1/blockchain/headerchain.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from core/headerchain.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package blockchain
    22  
    23  import (
    24  	crand "crypto/rand"
    25  	"errors"
    26  	"fmt"
    27  	"math"
    28  	"math/big"
    29  	mrand "math/rand"
    30  	"sync/atomic"
    31  	"time"
    32  
    33  	"github.com/klaytn/klaytn/blockchain/state"
    34  	"github.com/klaytn/klaytn/blockchain/types"
    35  	"github.com/klaytn/klaytn/common"
    36  	"github.com/klaytn/klaytn/consensus"
    37  	"github.com/klaytn/klaytn/params"
    38  	"github.com/klaytn/klaytn/storage/database"
    39  )
    40  
    41  // HeaderChain implements the basic block header chain logic that is shared by
    42  // blockchain.BlockChain and light.LightChain. It is not usable in itself, only as
    43  // a part of either structure.
    44  // It is not thread safe either, the encapsulating chain structures should do
    45  // the necessary mutex locking/unlocking.
    46  type HeaderChain struct {
    47  	config *params.ChainConfig
    48  
    49  	chainDB       database.DBManager
    50  	genesisHeader *types.Header
    51  
    52  	currentHeader     atomic.Value
    53  	currentHeaderHash common.Hash
    54  
    55  	procInterrupt func() bool
    56  
    57  	rand   *mrand.Rand
    58  	engine consensus.Engine
    59  }
    60  
    61  // NewHeaderChain creates a new HeaderChain structure.
    62  //
    63  //	getValidator should return the parent's validator
    64  //	procInterrupt points to the parent's interrupt semaphore
    65  //	wg points to the parent's shutdown wait group
    66  func NewHeaderChain(chainDB database.DBManager, config *params.ChainConfig, engine consensus.Engine, procInterrupt func() bool) (*HeaderChain, error) {
    67  	// Seed a fast but crypto originating random generator
    68  	seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	hc := &HeaderChain{
    74  		config:        config,
    75  		chainDB:       chainDB,
    76  		procInterrupt: procInterrupt,
    77  		rand:          mrand.New(mrand.NewSource(seed.Int64())),
    78  		engine:        engine,
    79  	}
    80  
    81  	hc.genesisHeader = hc.GetHeaderByNumber(0)
    82  	if hc.genesisHeader == nil {
    83  		return nil, ErrNoGenesis
    84  	}
    85  
    86  	hc.currentHeader.Store(hc.genesisHeader)
    87  	if head := chainDB.ReadHeadBlockHash(); head != (common.Hash{}) {
    88  		if chead := hc.GetHeaderByHash(head); chead != nil {
    89  			hc.currentHeader.Store(chead)
    90  		} else if head := chainDB.ReadHeadBlockBackupHash(); head != (common.Hash{}) {
    91  			if chead := hc.GetHeaderByHash(head); chead != nil {
    92  				hc.currentHeader.Store(chead)
    93  			}
    94  		}
    95  	}
    96  	hc.currentHeaderHash = hc.CurrentHeader().Hash()
    97  
    98  	return hc, nil
    99  }
   100  
   101  // GetBlockNumber retrieves the block number belonging to the given hash
   102  // from the cache or database
   103  func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 {
   104  	return hc.chainDB.ReadHeaderNumber(hash)
   105  }
   106  
   107  // WriteHeader writes a header into the local chain, given that its parent is
   108  // already known. If the total blockscore of the newly inserted header becomes
   109  // greater than the current known TD, the canonical chain is re-routed.
   110  //
   111  // Note: This method is not concurrent-safe with inserting blocks simultaneously
   112  // into the chain, as side effects caused by reorganisations cannot be emulated
   113  // without the real blocks. Hence, writing headers directly should only be done
   114  // in two scenarios: pure-header mode of operation (light clients), or properly
   115  // separated header/block phases (non-archive clients).
   116  func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, err error) {
   117  	// Cache some values to prevent constant recalculation
   118  	var (
   119  		hash   = header.Hash()
   120  		number = header.Number.Uint64()
   121  	)
   122  	// Calculate the total blockscore of the header
   123  	ptd := hc.GetTd(header.ParentHash, number-1)
   124  	if ptd == nil {
   125  		logger.Error("unknown ancestor (WriteHeader)", "num", number,
   126  			"hash", hash, "parentHash", header.ParentHash)
   127  		return NonStatTy, consensus.ErrUnknownAncestor
   128  	}
   129  	localTd := hc.GetTd(hc.currentHeaderHash, hc.CurrentHeader().Number.Uint64())
   130  	externTd := new(big.Int).Add(header.BlockScore, ptd)
   131  
   132  	// Irrelevant of the canonical status, write the td and header to the database
   133  	hc.WriteTd(hash, number, externTd)
   134  	hc.chainDB.WriteHeader(header)
   135  
   136  	// TODO-Klaytn-Issue264 If we are using istanbul BFT, then we always have a canonical chain.
   137  	//         Later we may be able to refine below code.
   138  
   139  	// If the total blockscore is higher than our known, add it to the canonical chain
   140  	// Second clause in the if statement reduces the vulnerability to selfish mining.
   141  	// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
   142  	if externTd.Cmp(localTd) > 0 || (externTd.Cmp(localTd) == 0 && mrand.Float64() < 0.5) {
   143  		// Delete any canonical number assignments above the new head
   144  		for i := number + 1; ; i++ {
   145  			hash := hc.chainDB.ReadCanonicalHash(i)
   146  			if hash == (common.Hash{}) {
   147  				break
   148  			}
   149  			hc.chainDB.DeleteCanonicalHash(i)
   150  		}
   151  		// Overwrite any stale canonical number assignments
   152  		var (
   153  			headHash   = header.ParentHash
   154  			headNumber = header.Number.Uint64() - 1
   155  			headHeader = hc.GetHeader(headHash, headNumber)
   156  		)
   157  		for hc.chainDB.ReadCanonicalHash(headNumber) != headHash {
   158  			hc.chainDB.WriteCanonicalHash(headHash, headNumber)
   159  
   160  			headHash = headHeader.ParentHash
   161  			headNumber = headHeader.Number.Uint64() - 1
   162  			headHeader = hc.GetHeader(headHash, headNumber)
   163  		}
   164  		// Extend the canonical chain with the new header
   165  		hc.chainDB.WriteCanonicalHash(hash, number)
   166  		hc.chainDB.WriteHeadHeaderHash(hash)
   167  
   168  		hc.currentHeaderHash = hash
   169  		hc.currentHeader.Store(types.CopyHeader(header))
   170  
   171  		status = CanonStatTy
   172  	} else {
   173  		status = SideStatTy
   174  	}
   175  	return
   176  }
   177  
   178  // WhCallback is a callback function for inserting individual headers.
   179  // A callback is used for two reasons: first, in a LightChain, status should be
   180  // processed and light chain events sent, while in a BlockChain this is not
   181  // necessary since chain events are sent after inserting blocks. Second, the
   182  // header writes should be protected by the parent chain mutex individually.
   183  type WhCallback func(*types.Header) error
   184  
   185  func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int) (int, error) {
   186  	// Do a sanity check that the provided chain is actually ordered and linked
   187  	for i := 1; i < len(chain); i++ {
   188  		if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() {
   189  			// Chain broke ancestry, log a messge (programming error) and skip insertion
   190  			logger.Error("Non contiguous header insert", "number", chain[i].Number, "hash", chain[i].Hash(),
   191  				"parent", chain[i].ParentHash, "prevnumber", chain[i-1].Number, "prevhash", chain[i-1].Hash())
   192  
   193  			return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, chain[i-1].Number,
   194  				chain[i-1].Hash().Bytes()[:4], i, chain[i].Number, chain[i].Hash().Bytes()[:4], chain[i].ParentHash[:4])
   195  		}
   196  	}
   197  
   198  	// Generate the list of seal verification requests, and start the parallel verifier
   199  	seals := make([]bool, len(chain))
   200  	for i := 0; i < len(seals)/checkFreq; i++ {
   201  		index := i*checkFreq + hc.rand.Intn(checkFreq)
   202  		if index >= len(seals) {
   203  			index = len(seals) - 1
   204  		}
   205  		seals[index] = true
   206  	}
   207  	seals[len(seals)-1] = true // Last should always be verified to avoid junk
   208  
   209  	var (
   210  		abort   chan<- struct{}
   211  		results <-chan error
   212  	)
   213  	if hc.engine.CanVerifyHeadersConcurrently() {
   214  		abort, results = hc.engine.VerifyHeaders(hc, chain, seals)
   215  	} else {
   216  		abort, results = hc.engine.PreprocessHeaderVerification(chain)
   217  	}
   218  	defer close(abort)
   219  
   220  	// Iterate over the headers and ensure they all check out
   221  	for i, header := range chain {
   222  		// If the chain is terminating, stop processing blocks
   223  		if hc.procInterrupt() {
   224  			logger.Debug("Premature abort during headers verification")
   225  			return 0, errors.New("aborted")
   226  		}
   227  		// If the header is a banned one, straight out abort
   228  		if BadHashes[header.Hash()] {
   229  			return i, ErrBlacklistedHash
   230  		}
   231  		// Otherwise wait for headers checks and ensure they pass
   232  		if err := <-results; err != nil {
   233  			return i, err
   234  		}
   235  	}
   236  
   237  	return 0, nil
   238  }
   239  
   240  // InsertHeaderChain attempts to insert the given header chain in to the local
   241  // chain, possibly creating a reorg. If an error is returned, it will return the
   242  // index number of the failing header as well an error describing what went wrong.
   243  //
   244  // The verify parameter can be used to fine tune whether nonce verification
   245  // should be done or not. The reason behind the optional check is because some
   246  // of the header retrieval mechanisms already need to verfy nonces, as well as
   247  // because nonces can be verified sparsely, not needing to check each.
   248  func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, writeHeader WhCallback, start time.Time) (int, error) {
   249  	// Collect some import statistics to report on
   250  	stats := struct{ processed, ignored int }{}
   251  	// All headers passed verification, import them into the database
   252  	for i, header := range chain {
   253  		// Short circuit insertion if shutting down
   254  		if hc.procInterrupt() {
   255  			logger.Debug("Premature abort during headers import")
   256  			return i, errors.New("aborted")
   257  		}
   258  		// If the header's already known, skip it, otherwise store
   259  		if hc.HasHeader(header.Hash(), header.Number.Uint64()) {
   260  			stats.ignored++
   261  			continue
   262  		}
   263  		if !hc.engine.CanVerifyHeadersConcurrently() {
   264  			if err := hc.engine.VerifyHeader(hc, header, true); err != nil {
   265  				return i, err
   266  			}
   267  		}
   268  		if err := writeHeader(header); err != nil {
   269  			return i, err
   270  		}
   271  		stats.processed++
   272  	}
   273  	// Report some public statistics so the user has a clue what's going on
   274  	last := chain[len(chain)-1]
   275  	logger.Info("Imported new block headers", "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)),
   276  		"number", last.Number, "hash", last.Hash(), "ignored", stats.ignored)
   277  
   278  	return 0, nil
   279  }
   280  
   281  // GetBlockHashesFromHash retrieves a number of block hashes starting at a given
   282  // hash, fetching towards the genesis block.
   283  func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash {
   284  	// Get the origin header from which to fetch
   285  	header := hc.GetHeaderByHash(hash)
   286  	if header == nil {
   287  		return nil
   288  	}
   289  	// Iterate the headers until enough is collected or the genesis reached
   290  	chain := make([]common.Hash, 0, max)
   291  	for i := uint64(0); i < max; i++ {
   292  		next := header.ParentHash
   293  		if header = hc.GetHeader(next, header.Number.Uint64()-1); header == nil {
   294  			break
   295  		}
   296  		chain = append(chain, next)
   297  		if header.Number.Sign() == 0 {
   298  			break
   299  		}
   300  	}
   301  	return chain
   302  }
   303  
   304  // GetTd retrieves a block's total blockscore in the canonical chain from the
   305  // database by hash and number, caching it if found.
   306  func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int {
   307  	return hc.chainDB.ReadTd(hash, number)
   308  }
   309  
   310  // GetTdByHash retrieves a block's total blockscore in the canonical chain from the
   311  // database by hash, caching it if found.
   312  func (hc *HeaderChain) GetTdByHash(hash common.Hash) *big.Int {
   313  	number := hc.GetBlockNumber(hash)
   314  	if number == nil {
   315  		return nil
   316  	}
   317  	return hc.GetTd(hash, *number)
   318  }
   319  
   320  // WriteTd stores a block's total blockscore into the database, also caching it
   321  // along the way.
   322  func (hc *HeaderChain) WriteTd(hash common.Hash, number uint64, td *big.Int) {
   323  	hc.chainDB.WriteTd(hash, number, td)
   324  }
   325  
   326  // GetHeader retrieves a block header from the database by hash and number,
   327  // caching it if found.
   328  func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header {
   329  	return hc.chainDB.ReadHeader(hash, number)
   330  }
   331  
   332  // GetHeaderByHash retrieves a block header from the database by hash, caching it if
   333  // found.
   334  func (hc *HeaderChain) GetHeaderByHash(hash common.Hash) *types.Header {
   335  	number := hc.GetBlockNumber(hash)
   336  	if number == nil {
   337  		return nil
   338  	}
   339  	return hc.GetHeader(hash, *number)
   340  }
   341  
   342  // HasHeader checks if a block header is present in the database or not.
   343  func (hc *HeaderChain) HasHeader(hash common.Hash, number uint64) bool {
   344  	return hc.chainDB.HasHeader(hash, number)
   345  }
   346  
   347  // GetHeaderByNumber retrieves a block header from the database by number,
   348  // caching it (associated with its hash) if found.
   349  func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header {
   350  	hash := hc.chainDB.ReadCanonicalHash(number)
   351  	if hash == (common.Hash{}) {
   352  		return nil
   353  	}
   354  	return hc.GetHeader(hash, number)
   355  }
   356  
   357  // CurrentHeader retrieves the current head header of the canonical chain. The
   358  // header is retrieved from the HeaderChain's internal cache.
   359  func (hc *HeaderChain) CurrentHeader() *types.Header {
   360  	return hc.currentHeader.Load().(*types.Header)
   361  }
   362  
   363  // CurrentBlock is added because HeaderChain is sometimes used as
   364  // type consensus.ChainReader and consensus.ChainReader interface has CurrentBlock.
   365  // However CurrentBlock is not supported in HeaderChain so this function just panics.
   366  func (hc *HeaderChain) CurrentBlock() *types.Block {
   367  	panic("CurrentBlock not supported for HeaderChain")
   368  }
   369  
   370  // SetCurrentHeader sets the current head header of the canonical chain.
   371  func (hc *HeaderChain) SetCurrentHeader(head *types.Header) {
   372  	hc.chainDB.WriteHeadHeaderHash(head.Hash())
   373  
   374  	hc.currentHeader.Store(head)
   375  	hc.currentHeaderHash = head.Hash()
   376  }
   377  
   378  type (
   379  	// UpdateHeadBlocksCallback is a callback function that is called by SetHead
   380  	// before head header is updated. The method will return the actual block it
   381  	// updated the head to (missing state) and a flag if setHead should continue
   382  	// rewinding till that forcefully (exceeded ancient limits)
   383  	UpdateHeadBlocksCallback func(*types.Header) (uint64, error)
   384  
   385  	// DeleteBlockContentCallback is a callback function that is called by SetHead
   386  	// before each header is deleted.
   387  	DeleteBlockContentCallback func(common.Hash, uint64)
   388  )
   389  
   390  func (hc *HeaderChain) SetHead(head uint64, updateFn UpdateHeadBlocksCallback, delFn DeleteBlockContentCallback) error {
   391  	var parentHash common.Hash
   392  	for hdr := hc.CurrentHeader(); hdr != nil && hdr.Number.Uint64() > head; hdr = hc.CurrentHeader() {
   393  		hash, num := hdr.Hash(), hdr.Number.Uint64()
   394  
   395  		// Rewind block chain to new head.
   396  		parent := hc.GetHeader(hdr.ParentHash, num-1)
   397  		if parent == nil {
   398  			parent = hc.genesisHeader
   399  		}
   400  		parentHash = parent.Hash()
   401  
   402  		// Notably, since Klaytn has the possibility for setting the head to a low
   403  		// height which is even lower than ancient head.
   404  		// In order to ensure that the head is always no higher than the data in
   405  		// the database (ancient store or active store), we need to update head
   406  		// first then remove the relative data from the database.
   407  		//
   408  		// Update head first(head fast block, head full block) before deleting the data.
   409  		if updateFn != nil {
   410  			latestBlkNum, err := updateFn(parent)
   411  			if err != nil {
   412  				return err
   413  			}
   414  			if latestBlkNum < head {
   415  				// Discrepancy of loop iteration occurs. blockchain sets the
   416  				// current block number to `latestBlkNum`. Remove further blocks accordingly
   417  				head = latestBlkNum
   418  			}
   419  		}
   420  		// Update head header then.
   421  		hc.chainDB.WriteHeadHeaderHash(parentHash)
   422  
   423  		// Remove the related data from the database on all sidechains
   424  		if delFn != nil {
   425  			delFn(hash, num)
   426  		}
   427  
   428  		// Rewind header chain to new head.
   429  		hc.chainDB.DeleteHeader(hash, num)
   430  		hc.chainDB.DeleteTd(hash, num)
   431  		hc.chainDB.DeleteCanonicalHash(num)
   432  
   433  		hc.currentHeader.Store(parent)
   434  		hc.currentHeaderHash = parentHash
   435  	}
   436  
   437  	// Clear out any stale content from the caches
   438  	hc.chainDB.ClearHeaderChainCache()
   439  	return nil
   440  }
   441  
   442  // SetGenesis sets a new genesis block header for the chain
   443  func (hc *HeaderChain) SetGenesis(head *types.Header) {
   444  	hc.genesisHeader = head
   445  }
   446  
   447  // Config retrieves the header chain's chain configuration.
   448  func (hc *HeaderChain) Config() *params.ChainConfig { return hc.config }
   449  
   450  // Engine retrieves the header chain's consensus engine.
   451  func (hc *HeaderChain) Engine() consensus.Engine { return hc.engine }
   452  
   453  // GetBlock implements consensus.ChainReader, and returns nil for every input as
   454  // a header chain does not have blocks available for retrieval.
   455  func (hc *HeaderChain) GetBlock(hash common.Hash, number uint64) *types.Block {
   456  	return nil
   457  }
   458  
   459  func (hc *HeaderChain) State() (*state.StateDB, error) {
   460  	return nil, errors.New("HeaderChain does not support State() method")
   461  }
   462  
   463  func (hc *HeaderChain) StateAt(root common.Hash) (*state.StateDB, error) {
   464  	return nil, errors.New("HeaderChain does not support StateAt() method")
   465  }