From 84a4f761f332b4aecc36c748bc4c9a4ce1c114e2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 4 Mar 2015 10:49:56 +0100 Subject: uncle validation --- core/block_processor.go | 60 +++++++++++++++++++++++++++++++------------------ core/chain_makers.go | 2 +- core/chain_manager.go | 12 +++++----- core/filter.go | 2 +- 4 files changed, 46 insertions(+), 30 deletions(-) (limited to 'core') diff --git a/core/block_processor.go b/core/block_processor.go index a6632fca7..c2799dc48 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -176,10 +176,15 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big state := state.New(parent.Root(), sm.db) // Block validation - if err = sm.ValidateBlock(block, parent); err != nil { + if err = sm.ValidateHeader(block.Header(), parent.Header()); err != nil { return } + // There can be at most two uncles + if len(block.Uncles()) > 2 { + return nil, ValidationError("Block can only contain one uncle (contained %v)", len(block.Uncles())) + } + receipts, err := sm.TransitionState(state, parent, block, false) if err != nil { return @@ -238,46 +243,41 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big // Validates the current block. Returns an error if the block was invalid, // an uncle or anything that isn't on the current block chain. // Validation validates easy over difficult (dagger takes longer time = difficult) -func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error { - if len(block.Header().Extra) > 1024 { - return fmt.Errorf("Block extra data too long (%d)", len(block.Header().Extra)) +func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header) error { + if len(block.Extra) > 1024 { + return fmt.Errorf("Block extra data too long (%d)", len(block.Extra)) } expd := CalcDifficulty(block, parent) - if expd.Cmp(block.Header().Difficulty) != 0 { - return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd) + if expd.Cmp(block.Difficulty) != 0 { + return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) } //expl := CalcGasLimit(parent, block) //if expl.Cmp(block.Header().GasLimit) != 0 { // block.gasLimit - parent.gasLimit <= parent.gasLimit / 1024 - a := new(big.Int).Sub(block.Header().GasLimit, parent.Header().GasLimit) - b := new(big.Int).Div(parent.Header().GasLimit, big.NewInt(1024)) + a := new(big.Int).Sub(block.GasLimit, parent.GasLimit) + b := new(big.Int).Div(parent.GasLimit, big.NewInt(1024)) if a.Cmp(b) > 0 { - return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.Header().GasLimit, a, b) - } - - // There can be at most one uncle - if len(block.Uncles()) > 1 { - return ValidationError("Block can only contain one uncle (contained %v)", len(block.Uncles())) + return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b) } - if block.Time() < parent.Time() { - return ValidationError("Block timestamp not after prev block (%v - %v)", block.Header().Time, parent.Header().Time) + if block.Time < parent.Time { + return ValidationError("Block timestamp not after prev block (%v - %v)", block.Time, parent.Time) } - if block.Time() > time.Now().Unix() { + if int64(block.Time) > time.Now().Unix() { return BlockFutureErr } - if new(big.Int).Sub(block.Number(), parent.Number()).Cmp(big.NewInt(1)) != 0 { + if new(big.Int).Sub(block.Number, parent.Number).Cmp(big.NewInt(1)) != 0 { return BlockNumberErr } // Verify the nonce of the block. Return an error if it's not valid - if !sm.Pow.Verify(block) { - return ValidationError("Block's nonce is invalid (= %x)", block.Header().Nonce) + if !sm.Pow.Verify(types.NewBlockWithHeader(block)) { + return ValidationError("Block's nonce is invalid (= %x)", block.Nonce) } return nil @@ -287,23 +287,39 @@ func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, paren reward := new(big.Int).Set(BlockReward) ancestors := set.New() + uncles := set.New() + ancestorHeaders := make(map[string]*types.Header) for _, ancestor := range sm.bc.GetAncestors(block, 7) { - ancestors.Add(string(ancestor.Hash())) + hash := string(ancestor.Hash()) + ancestorHeaders[hash] = ancestor.Header() + ancestors.Add(hash) + // Include ancestors uncles in the uncle set. Uncles must be unique. + for _, uncle := range ancestor.Uncles() { + uncles.Add(string(uncle.Hash())) + } } - uncles := set.New() uncles.Add(string(block.Hash())) for _, uncle := range block.Uncles() { if uncles.Has(string(uncle.Hash())) { // Error not unique return UncleError("Uncle not unique") } + uncles.Add(string(uncle.Hash())) + if ancestors.Has(string(uncle.Hash())) { + return UncleError("Uncle is ancestor") + } + if !ancestors.Has(string(uncle.ParentHash)) { return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4])) } + if err := sm.ValidateHeader(uncle, ancestorHeaders[string(uncle.ParentHash)]); err != nil { + return ValidationError(fmt.Sprintf("%v", err)) + } + if !sm.Pow.Verify(types.NewBlockWithHeader(uncle)) { return ValidationError("Uncle's nonce is invalid (= %x)", uncle.Nonce) } diff --git a/core/chain_makers.go b/core/chain_makers.go index 3248975e1..fad9ac97b 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -61,7 +61,7 @@ func newBlockFromParent(addr []byte, parent *types.Block) *types.Block { block.SetReceipts(nil) header := block.Header() - header.Difficulty = CalcDifficulty(block, parent) + header.Difficulty = CalcDifficulty(block.Header(), parent.Header()) header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1) header.Time = parent.Header().Time + 10 header.GasLimit = CalcGasLimit(parent, block) diff --git a/core/chain_manager.go b/core/chain_manager.go index 6212fb842..f2382cf8d 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -28,16 +28,16 @@ type StateQuery interface { GetAccount(addr []byte) *state.StateObject } -func CalcDifficulty(block, parent *types.Block) *big.Int { +func CalcDifficulty(block, parent *types.Header) *big.Int { diff := new(big.Int) //adjust := new(big.Int).Rsh(parent.Difficulty(), 10) //if block.Time() >= parent.Time()+8 { - adjust := new(big.Int).Div(parent.Difficulty(), big.NewInt(2048)) - if (block.Time() - parent.Time()) < 8 { - diff.Add(parent.Difficulty(), adjust) + adjust := new(big.Int).Div(parent.Difficulty, big.NewInt(2048)) + if (block.Time - parent.Time) < 8 { + diff.Add(parent.Difficulty, adjust) } else { - diff.Sub(parent.Difficulty(), adjust) + diff.Sub(parent.Difficulty, adjust) } return diff @@ -206,7 +206,7 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block { parent := bc.currentBlock if parent != nil { header := block.Header() - header.Difficulty = CalcDifficulty(block, parent) + header.Difficulty = CalcDifficulty(block.Header(), parent.Header()) header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1) header.GasLimit = CalcGasLimit(parent, block) diff --git a/core/filter.go b/core/filter.go index c61c9e998..d58aa8d7c 100644 --- a/core/filter.go +++ b/core/filter.go @@ -147,7 +147,7 @@ func (self *Filter) FilterLogs(logs state.Logs) state.Logs { // Filter the logs for interesting stuff Logs: for _, log := range logs { - if !includes(self.address, log.Address()) { + if len(self.address) > 0 && !includes(self.address, log.Address()) { continue } -- cgit v1.2.3