// ValidateHeader validates the given header and, depending on the pow arg, // checks the proof of work of the given header. Returns an error if the // validation failed. func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow bool) error { // Short circuit if the parent is missing. if parent == nil { return ParentError(header.ParentHash) } // Short circuit if the header's already known or its parent missing if v.bc.HasHeader(header.Hash()) { return nil } return ValidateHeader(v.Pow, header, parent, checkPow, false) }
// WriteHeader serializes a block header into the database. func WriteHeader(db ethdb.Database, header *types.Header) error { data, err := rlp.EncodeToBytes(header) if err != nil { return err } key := append(append(blockPrefix, header.Hash().Bytes()...), headerSuffix...) if err := db.Put(key, data); err != nil { glog.Fatalf("failed to store header into database: %v", err) return err } glog.V(logger.Debug).Infof("stored header #%v [%x…]", header.Number, header.Hash().Bytes()[:4]) return nil }
func (self *worker) commitUncle(work *Work, uncle *types.Header) error { hash := uncle.Hash() if work.uncles.Has(hash) { return core.UncleError("Uncle not unique") } if !work.ancestors.Has(uncle.ParentHash) { return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4])) } if work.family.Has(hash) { return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", hash)) } work.uncles.Add(uncle.Hash()) return nil }
// Validates a header. Returns an error if the header is invalid. // // See YP section 4.3.4. "Block Header Validity" func ValidateHeader(pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error { if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 { return fmt.Errorf("Header extra data too long (%d)", len(header.Extra)) } if uncle { if header.Time.Cmp(common.MaxBig) == 1 { return BlockTSTooBigErr } } else { if header.Time.Cmp(big.NewInt(time.Now().Unix())) == 1 { return BlockFutureErr } } if header.Time.Cmp(parent.Time) != 1 { return BlockEqualTSErr } expd := CalcDifficulty(header.Time.Uint64(), parent.Time.Uint64(), parent.Number, parent.Difficulty) if expd.Cmp(header.Difficulty) != 0 { return fmt.Errorf("Difficulty check failed for header %v, %v", header.Difficulty, expd) } a := new(big.Int).Set(parent.GasLimit) a = a.Sub(a, header.GasLimit) a.Abs(a) b := new(big.Int).Set(parent.GasLimit) b = b.Div(b, params.GasLimitBoundDivisor) if !(a.Cmp(b) < 0) || (header.GasLimit.Cmp(params.MinGasLimit) == -1) { return fmt.Errorf("GasLimit check failed for header %v (%v > %v)", header.GasLimit, a, b) } num := new(big.Int).Set(parent.Number) num.Sub(header.Number, num) if num.Cmp(big.NewInt(1)) != 0 { return BlockNumberErr } if checkPow { // Verify the nonce of the header. Return an error if it's not valid if !pow.Verify(types.NewBlockWithHeader(header)) { return &BlockNonceErr{header.Number, header.Hash(), header.Nonce.Uint64()} } } 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 }