| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 |
- // Copyright 2015 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 (
- "fmt"
- "math/big"
- "time"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/logger/glog"
- "github.com/ethereum/go-ethereum/params"
- "github.com/ethereum/go-ethereum/pow"
- "gopkg.in/fatih/set.v0"
- )
- var (
- ExpDiffPeriod = big.NewInt(100000)
- big10 = big.NewInt(10)
- bigMinus99 = big.NewInt(-99)
- )
- // BlockValidator is responsible for validating block headers, uncles and
- // processed state.
- //
- // BlockValidator implements Validator.
- type BlockValidator struct {
- config *ChainConfig // Chain configuration options
- bc *BlockChain // Canonical block chain
- Pow pow.PoW // Proof of work used for validating
- }
- // NewBlockValidator returns a new block validator which is safe for re-use
- func NewBlockValidator(config *ChainConfig, blockchain *BlockChain, pow pow.PoW) *BlockValidator {
- validator := &BlockValidator{
- config: config,
- Pow: pow,
- bc: blockchain,
- }
- return validator
- }
- // ValidateBlock validates the given block's header and uncles and verifies the
- // the block header's transaction and uncle roots.
- //
- // ValidateBlock does not validate the header's pow. The pow work validated
- // separately so we can process them in parallel.
- //
- // ValidateBlock also validates and makes sure that any previous state (or present)
- // state that might or might not be present is checked to make sure that fast
- // sync has done it's job proper. This prevents the block validator form accepting
- // false positives where a header is present but the state is not.
- func (v *BlockValidator) ValidateBlock(block *types.Block) error {
- if v.bc.HasBlock(block.Hash()) {
- if _, err := state.New(block.Root(), v.bc.chainDb); err == nil {
- return &KnownBlockError{block.Number(), block.Hash()}
- }
- }
- parent := v.bc.GetBlock(block.ParentHash())
- if parent == nil {
- return ParentError(block.ParentHash())
- }
- if _, err := state.New(parent.Root(), v.bc.chainDb); err != nil {
- return ParentError(block.ParentHash())
- }
- header := block.Header()
- // validate the block header
- if err := ValidateHeader(v.config, v.Pow, header, parent.Header(), false, false); err != nil {
- return err
- }
- // verify the uncles are correctly rewarded
- if err := v.VerifyUncles(block, parent); err != nil {
- return err
- }
- // Verify UncleHash before running other uncle validations
- unclesSha := types.CalcUncleHash(block.Uncles())
- if unclesSha != header.UncleHash {
- return fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha)
- }
- // The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]]))
- // can be used by light clients to make sure they've received the correct Txs
- txSha := types.DeriveSha(block.Transactions())
- if txSha != header.TxHash {
- return fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha)
- }
- return nil
- }
- // ValidateState validates the various changes that happen after a state
- // transition, such as amount of used gas, the receipt roots and the state root
- // itself. ValidateState returns a database batch if the validation was a success
- // otherwise nil and an error is returned.
- func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas *big.Int) (err error) {
- header := block.Header()
- if block.GasUsed().Cmp(usedGas) != 0 {
- return ValidationError(fmt.Sprintf("gas used error (%v / %v)", block.GasUsed(), usedGas))
- }
- // Validate the received block's bloom with the one derived from the generated receipts.
- // For valid blocks this should always validate to true.
- rbloom := types.CreateBloom(receipts)
- if rbloom != header.Bloom {
- return fmt.Errorf("unable to replicate block's bloom=%x vs calculated bloom=%x", header.Bloom, rbloom)
- }
- // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
- receiptSha := types.DeriveSha(receipts)
- if receiptSha != header.ReceiptHash {
- return fmt.Errorf("invalid receipt root hash. received=%x calculated=%x", header.ReceiptHash, receiptSha)
- }
- // Validate the state root against the received state root and throw
- // an error if they don't match.
- if root := statedb.IntermediateRoot(); header.Root != root {
- return fmt.Errorf("invalid merkle root: header=%x computed=%x", header.Root, root)
- }
- return nil
- }
- // VerifyUncles verifies the given block's uncles and applies the Ethereum
- // consensus rules to the various block headers included; it will return an
- // error if any of the included uncle headers were invalid. It returns an error
- // if the validation failed.
- func (v *BlockValidator) VerifyUncles(block, parent *types.Block) error {
- // validate that there at most 2 uncles included in this block
- if len(block.Uncles()) > 2 {
- return ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(block.Uncles()))
- }
- uncles := set.New()
- ancestors := make(map[common.Hash]*types.Block)
- for _, ancestor := range v.bc.GetBlocksFromHash(block.ParentHash(), 7) {
- ancestors[ancestor.Hash()] = ancestor
- // Include ancestors uncles in the uncle set. Uncles must be unique.
- for _, uncle := range ancestor.Uncles() {
- uncles.Add(uncle.Hash())
- }
- }
- ancestors[block.Hash()] = block
- uncles.Add(block.Hash())
- for i, uncle := range block.Uncles() {
- hash := uncle.Hash()
- if uncles.Has(hash) {
- // Error not unique
- return UncleError("uncle[%d](%x) not unique", i, hash[:4])
- }
- uncles.Add(hash)
- if ancestors[hash] != nil {
- branch := fmt.Sprintf(" O - %x\n |\n", block.Hash())
- for h := range ancestors {
- branch += fmt.Sprintf(" O - %x\n |\n", h)
- }
- glog.Infoln(branch)
- return UncleError("uncle[%d](%x) is ancestor", i, hash[:4])
- }
- if ancestors[uncle.ParentHash] == nil || uncle.ParentHash == parent.Hash() {
- return UncleError("uncle[%d](%x)'s parent is not ancestor (%x)", i, hash[:4], uncle.ParentHash[0:4])
- }
- if err := ValidateHeader(v.config, v.Pow, uncle, ancestors[uncle.ParentHash].Header(), true, true); err != nil {
- return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err))
- }
- }
- return nil
- }
- // 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.config, v.Pow, header, parent, checkPow, false)
- }
- // Validates a header. Returns an error if the header is invalid.
- //
- // See YP section 4.3.4. "Block Header Validity"
- func ValidateHeader(config *ChainConfig, 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(config, 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
- }
- // CalcDifficulty is the difficulty adjustment algorithm. It returns
- // the difficulty that a new block should have when created at time
- // given the parent block's time and difficulty.
- func CalcDifficulty(config *ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
- if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) {
- return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff)
- } else {
- return calcDifficultyFrontier(time, parentTime, parentNumber, parentDiff)
- }
- }
- func calcDifficultyHomestead(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
- // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.mediawiki
- // algorithm:
- // diff = (parent_diff +
- // (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
- // ) + 2^(periodCount - 2)
- bigTime := new(big.Int).SetUint64(time)
- bigParentTime := new(big.Int).SetUint64(parentTime)
- // holds intermediate values to make the algo easier to read & audit
- x := new(big.Int)
- y := new(big.Int)
- // 1 - (block_timestamp -parent_timestamp) // 10
- x.Sub(bigTime, bigParentTime)
- x.Div(x, big10)
- x.Sub(common.Big1, x)
- // max(1 - (block_timestamp - parent_timestamp) // 10, -99)))
- if x.Cmp(bigMinus99) < 0 {
- x.Set(bigMinus99)
- }
- // (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
- y.Div(parentDiff, params.DifficultyBoundDivisor)
- x.Mul(y, x)
- x.Add(parentDiff, x)
- // minimum difficulty can ever be (before exponential factor)
- if x.Cmp(params.MinimumDifficulty) < 0 {
- x = params.MinimumDifficulty
- }
- // for the exponential factor
- periodCount := new(big.Int).Add(parentNumber, common.Big1)
- periodCount.Div(periodCount, ExpDiffPeriod)
- // the exponential factor, commonly referred to as "the bomb"
- // diff = diff + 2^(periodCount - 2)
- if periodCount.Cmp(common.Big1) > 0 {
- y.Sub(periodCount, common.Big2)
- y.Exp(common.Big2, y, nil)
- x.Add(x, y)
- }
- return x
- }
- func calcDifficultyFrontier(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
- diff := new(big.Int)
- adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor)
- bigTime := new(big.Int)
- bigParentTime := new(big.Int)
- bigTime.SetUint64(time)
- bigParentTime.SetUint64(parentTime)
- if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 {
- diff.Add(parentDiff, adjust)
- } else {
- diff.Sub(parentDiff, adjust)
- }
- if diff.Cmp(params.MinimumDifficulty) < 0 {
- diff = params.MinimumDifficulty
- }
- periodCount := new(big.Int).Add(parentNumber, common.Big1)
- periodCount.Div(periodCount, ExpDiffPeriod)
- if periodCount.Cmp(common.Big1) > 0 {
- // diff = diff + 2^(periodCount - 2)
- expDiff := periodCount.Sub(periodCount, common.Big2)
- expDiff.Exp(common.Big2, expDiff, nil)
- diff.Add(diff, expDiff)
- diff = common.BigMax(diff, params.MinimumDifficulty)
- }
- return diff
- }
- // CalcGasLimit computes the gas limit of the next block after parent.
- // The result may be modified by the caller.
- // This is miner strategy, not consensus protocol.
- func CalcGasLimit(parent *types.Block) *big.Int {
- // contrib = (parentGasUsed * 3 / 2) / 1024
- contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3))
- contrib = contrib.Div(contrib, big.NewInt(2))
- contrib = contrib.Div(contrib, params.GasLimitBoundDivisor)
- // decay = parentGasLimit / 1024 -1
- decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor)
- decay.Sub(decay, big.NewInt(1))
- /*
- strategy: gasLimit of block-to-mine is set based on parent's
- gasUsed value. if parentGasUsed > parentGasLimit * (2/3) then we
- increase it, otherwise lower it (or leave it unchanged if it's right
- at that usage) the amount increased/decreased depends on how far away
- from parentGasLimit * (2/3) parentGasUsed is.
- */
- gl := new(big.Int).Sub(parent.GasLimit(), decay)
- gl = gl.Add(gl, contrib)
- gl.Set(common.BigMax(gl, params.MinGasLimit))
- // however, if we're now below the target (TargetGasLimit) we increase the
- // limit as much as we can (parentGasLimit / 1024 -1)
- if gl.Cmp(params.TargetGasLimit) < 0 {
- gl.Add(parent.GasLimit(), decay)
- gl.Set(common.BigMin(gl, params.TargetGasLimit))
- }
- return gl
- }
|