WriteHeader writes a header into the local chain, given that its parent is already known. If the total difficulty of the newly inserted header becomes greater than the current known TD, the canonical chain is re-routed.

Note: This method is not concurrent-safe with inserting blocks simultaneously into the chain, as side effects caused by reorganisations cannot be emulated without the real blocks. Hence, writing headers directly should only be done in two scenarios: pure-header mode of operation (light clients), or properly separated header/block phases (non-archive clients).

WriteHeader is referenced in 1 repository


func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, err error) {
	// Cache some values to prevent constant recalculation
	var (
		hash   = header.Hash()
		number = header.Number.Uint64()
	// Calculate the total difficulty of the header
	ptd := hc.GetTd(header.ParentHash)
	if ptd == nil {
		return NonStatTy, ParentError(header.ParentHash)
	localTd := hc.GetTd(hc.currentHeaderHash)
	externTd := new(big.Int).Add(header.Difficulty, ptd)

	// Irrelevant of the canonical status, write the td and header to the database
	if err := hc.WriteTd(hash, externTd); err != nil {
		glog.Fatalf("failed to write header total difficulty: %v", err)
	if err := WriteHeader(hc.chainDb, header); err != nil {
		glog.Fatalf("failed to write header contents: %v", err)

	// If the total difficulty is higher than our known, add it to the canonical chain
	// Second clause in the if statement reduces the vulnerability to selfish mining.
	// Please refer to
	if externTd.Cmp(localTd) > 0 || (externTd.Cmp(localTd) == 0 && mrand.Float64() < 0.5) {
		// Delete any canonical number assignments above the new head
		for i := number + 1; GetCanonicalHash(hc.chainDb, i) != (common.Hash{}); i++ {
			DeleteCanonicalHash(hc.chainDb, i)
		// Overwrite any stale canonical number assignments
		var (
			headHash   = header.ParentHash
			headHeader = hc.GetHeader(headHash)
			headNumber = headHeader.Number.Uint64()
		for GetCanonicalHash(hc.chainDb, headNumber) != headHash {
			WriteCanonicalHash(hc.chainDb, headHash, headNumber)

			headHash = headHeader.ParentHash
			headHeader = hc.GetHeader(headHash)
			headNumber = headHeader.Number.Uint64()

		// Extend the canonical chain with the new header
		if err := WriteCanonicalHash(hc.chainDb, hash, number); err != nil {
			glog.Fatalf("failed to insert header number: %v", err)
		if err := WriteHeadHeaderHash(hc.chainDb, hash); err != nil {
			glog.Fatalf("failed to insert head header hash: %v", err)

		hc.currentHeaderHash, hc.currentHeader = hash, types.CopyHeader(header)

		status = CanonStatTy
	} else {
		status = SideStatTy
	hc.headerCache.Add(hash, header)