// 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). func (self *BlockChain) writeHeader(header *types.Header) error { self.wg.Add(1) defer self.wg.Done() // Calculate the total difficulty of the header ptd := self.GetTd(header.ParentHash) if ptd == nil { return ParentError(header.ParentHash) } localTd := self.GetTd(self.currentHeader.Hash()) externTd := new(big.Int).Add(header.Difficulty, ptd) // Make sure no inconsistent state is leaked during insertion self.mu.Lock() defer self.mu.Unlock() // 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 http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf if externTd.Cmp(localTd) > 0 || (externTd.Cmp(localTd) == 0 && mrand.Float64() < 0.5) { // Delete any canonical number assignments above the new head for i := header.Number.Uint64() + 1; GetCanonicalHash(self.chainDb, i) != (common.Hash{}); i++ { DeleteCanonicalHash(self.chainDb, i) } // Overwrite any stale canonical number assignments head := self.GetHeader(header.ParentHash) for GetCanonicalHash(self.chainDb, head.Number.Uint64()) != head.Hash() { WriteCanonicalHash(self.chainDb, head.Hash(), head.Number.Uint64()) head = self.GetHeader(head.ParentHash) } // Extend the canonical chain with the new header if err := WriteCanonicalHash(self.chainDb, header.Hash(), header.Number.Uint64()); err != nil { glog.Fatalf("failed to insert header number: %v", err) } if err := WriteHeadHeaderHash(self.chainDb, header.Hash()); err != nil { glog.Fatalf("failed to insert head header hash: %v", err) } self.currentHeader = types.CopyHeader(header) } // Irrelevant of the canonical status, write the header itself to the database if err := WriteTd(self.chainDb, header.Hash(), externTd); err != nil { glog.Fatalf("failed to write header total difficulty: %v", err) } if err := WriteHeader(self.chainDb, header); err != nil { glog.Fatalf("filed to write header contents: %v", err) } return nil }
// 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). func (self *BlockChain) writeHeader(header *types.Header) error { self.wg.Add(1) defer self.wg.Done() // Calculate the total difficulty of the header ptd := self.GetTd(header.ParentHash) if ptd == nil { return ParentError(header.ParentHash) } td := new(big.Int).Add(header.Difficulty, ptd) // Make sure no inconsistent state is leaked during insertion self.mu.Lock() defer self.mu.Unlock() // If the total difficulty is higher than our known, add it to the canonical chain if td.Cmp(self.GetTd(self.currentHeader.Hash())) > 0 { // Delete any canonical number assignments above the new head for i := header.Number.Uint64() + 1; GetCanonicalHash(self.chainDb, i) != (common.Hash{}); i++ { DeleteCanonicalHash(self.chainDb, i) } // Overwrite any stale canonical number assignments head := self.GetHeader(header.ParentHash) for GetCanonicalHash(self.chainDb, head.Number.Uint64()) != head.Hash() { WriteCanonicalHash(self.chainDb, head.Hash(), head.Number.Uint64()) head = self.GetHeader(head.ParentHash) } // Extend the canonical chain with the new header if err := WriteCanonicalHash(self.chainDb, header.Hash(), header.Number.Uint64()); err != nil { glog.Fatalf("failed to insert header number: %v", err) } if err := WriteHeadHeaderHash(self.chainDb, header.Hash()); err != nil { glog.Fatalf("failed to insert head header hash: %v", err) } self.currentHeader = types.CopyHeader(header) } // Irrelevant of the canonical status, write the header itself to the database if err := WriteTd(self.chainDb, header.Hash(), td); err != nil { glog.Fatalf("failed to write header total difficulty: %v", err) } if err := WriteHeader(self.chainDb, header); err != nil { glog.Fatalf("filed to write header contents: %v", err) } return nil }
// 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). 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 http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf 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) return }