core: fix the nonce check one more time

The block nonce verification was effectively disabled by a typo.
This time, there is an actual test for it.
pull/1198/head
Felix Lange 10 years ago
parent 43ceb0f5c7
commit 0b493910d3
  1. 6
      core/chain_manager.go
  2. 53
      core/chain_manager_test.go
  3. 17
      core/error.go

@ -551,12 +551,12 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
bstart := time.Now()
// Wait for block i's nonce to be verified before processing
// its state transition.
for nonceChecked[i] {
for !nonceChecked[i] {
r := <-nonceDone
nonceChecked[r.i] = true
if !r.valid {
block := chain[i]
return i, ValidationError("Block (#%v / %x) nonce is invalid (= %x)", block.Number(), block.Hash(), block.Nonce)
block := chain[r.i]
return r.i, &BlockNonceErr{Hash: block.Hash(), Number: block.Number(), Nonce: block.Nonce()}
}
}

@ -3,6 +3,7 @@ package core
import (
"fmt"
"math/big"
"math/rand"
"os"
"path/filepath"
"runtime"
@ -426,3 +427,55 @@ func TestReorgShortest(t *testing.T) {
}
}
}
func TestInsertNonceError(t *testing.T) {
for i := 1; i < 25 && !t.Failed(); i++ {
db, _ := ethdb.NewMemDatabase()
genesis := GenesisBlock(db)
bc := chm(genesis, db)
bc.processor = NewBlockProcessor(db, db, bc.pow, bc, bc.eventMux)
blocks := makeChain(bc.processor.(*BlockProcessor), bc.currentBlock, i, db, 0)
fail := rand.Int() % len(blocks)
failblock := blocks[fail]
bc.pow = failpow{failblock.NumberU64()}
n, err := bc.InsertChain(blocks)
// Check that the returned error indicates the nonce failure.
if n != fail {
t.Errorf("(i=%d) wrong failed block index: got %d, want %d", i, n, fail)
}
if !IsBlockNonceErr(err) {
t.Fatalf("(i=%d) got %q, want a nonce error", i, err)
}
nerr := err.(*BlockNonceErr)
if nerr.Number.Cmp(failblock.Number()) != 0 {
t.Errorf("(i=%d) wrong block number in error, got %v, want %v", i, nerr.Number, failblock.Number())
}
if nerr.Hash != failblock.Hash() {
t.Errorf("(i=%d) wrong block hash in error, got %v, want %v", i, nerr.Hash, failblock.Hash())
}
// Check that all no blocks after the failing block have been inserted.
for _, block := range blocks[fail:] {
if bc.HasBlock(block.Hash()) {
t.Errorf("(i=%d) invalid block %d present in chain", i, block.NumberU64())
}
}
}
}
// failpow returns false from Verify for a certain block number.
type failpow struct{ num uint64 }
func (pow failpow) Search(pow.Block, <-chan struct{}) (nonce uint64, mixHash []byte) {
return 0, nil
}
func (pow failpow) Verify(b pow.Block) bool {
return b.NumberU64() != pow.num
}
func (pow failpow) GetHashrate() int64 {
return 0
}
func (pow failpow) Turbo(bool) {
}

@ -90,6 +90,23 @@ func IsNonceErr(err error) bool {
return ok
}
// BlockNonceErr indicates that a block's nonce is invalid.
type BlockNonceErr struct {
Number *big.Int
Hash common.Hash
Nonce uint64
}
func (err *BlockNonceErr) Error() string {
return fmt.Sprintf("block %d (%v) nonce is invalid (got %d)", err.Number, err.Hash, err.Nonce)
}
// IsBlockNonceErr returns true for invalid block nonce errors.
func IsBlockNonceErr(err error) bool {
_, ok := err.(*BlockNonceErr)
return ok
}
type InvalidTxErr struct {
Message string
}

Loading…
Cancel
Save