aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/block_processor_test.go7
-rw-r--r--core/blocks.go1
-rw-r--r--core/chain_makers.go2
-rw-r--r--core/chain_manager.go30
-rw-r--r--core/chain_manager_test.go102
-rw-r--r--core/error.go17
-rw-r--r--core/genesis.go4
-rw-r--r--core/transaction_pool.go2
-rw-r--r--core/transaction_pool_test.go23
9 files changed, 159 insertions, 29 deletions
diff --git a/core/block_processor_test.go b/core/block_processor_test.go
index b52c3d3f8..97b80038d 100644
--- a/core/block_processor_test.go
+++ b/core/block_processor_test.go
@@ -1,6 +1,7 @@
package core
import (
+ "fmt"
"math/big"
"testing"
@@ -16,7 +17,11 @@ func proc() (*BlockProcessor, *ChainManager) {
db, _ := ethdb.NewMemDatabase()
var mux event.TypeMux
- chainMan := NewChainManager(db, db, thePow(), &mux)
+ genesis := GenesisBlock(0, db)
+ chainMan, err := NewChainManager(genesis, db, db, thePow(), &mux)
+ if err != nil {
+ fmt.Println(err)
+ }
return NewBlockProcessor(db, db, ezp.New(), chainMan, &mux), chainMan
}
diff --git a/core/blocks.go b/core/blocks.go
index 83727ff62..f0d39e1e1 100644
--- a/core/blocks.go
+++ b/core/blocks.go
@@ -7,4 +7,5 @@ var BadHashes = map[common.Hash]bool{
common.HexToHash("f269c503aed286caaa0d114d6a5320e70abbc2febe37953207e76a2873f2ba79"): true,
common.HexToHash("38f5bbbffd74804820ffa4bab0cd540e9de229725afb98c1a7e57936f4a714bc"): true,
common.HexToHash("7064455b364775a16afbdecd75370e912c6e2879f202eda85b9beae547fff3ac"): true,
+ common.HexToHash("5b7c80070a6eff35f3eb3181edb023465c776d40af2885571e1bc4689f3a44d8"): true,
}
diff --git a/core/chain_makers.go b/core/chain_makers.go
index 3039e52da..4e685f599 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -108,7 +108,7 @@ func makeChain(bman *BlockProcessor, parent *types.Block, max int, db common.Dat
// Create a new chain manager starting from given block
// Effectively a fork factory
func newChainManager(block *types.Block, eventMux *event.TypeMux, db common.Database) *ChainManager {
- genesis := GenesisBlock(db)
+ genesis := GenesisBlock(0, db)
bc := &ChainManager{blockDb: db, stateDb: db, genesisBlock: genesis, eventMux: eventMux, pow: FakePow{}}
bc.txState = state.ManageState(state.New(genesis.Root(), db))
bc.futureBlocks = NewBlockCache(1000)
diff --git a/core/chain_manager.go b/core/chain_manager.go
index a00fd288d..e87253304 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -109,16 +109,22 @@ type ChainManager struct {
pow pow.PoW
}
-func NewChainManager(blockDb, stateDb common.Database, pow pow.PoW, mux *event.TypeMux) *ChainManager {
+func NewChainManager(genesis *types.Block, blockDb, stateDb common.Database, pow pow.PoW, mux *event.TypeMux) (*ChainManager, error) {
bc := &ChainManager{
- blockDb: blockDb,
- stateDb: stateDb,
- genesisBlock: GenesisBlock(stateDb),
- eventMux: mux,
- quit: make(chan struct{}),
- cache: NewBlockCache(blockCacheLimit),
- pow: pow,
+ blockDb: blockDb,
+ stateDb: stateDb,
+ eventMux: mux,
+ quit: make(chan struct{}),
+ cache: NewBlockCache(blockCacheLimit),
+ pow: pow,
}
+
+ // Check the genesis block given to the chain manager. If the genesis block mismatches block number 0
+ // throw an error. If no block or the same block's found continue.
+ if g := bc.GetBlockByNumber(0); g != nil && g.Hash() != genesis.Hash() {
+ return nil, fmt.Errorf("Genesis mismatch. Maybe different nonce (%d vs %d)? %x / %x", g.Nonce(), genesis.Nonce(), g.Hash().Bytes()[:4], genesis.Hash().Bytes()[:4])
+ }
+ bc.genesisBlock = genesis
bc.setLastState()
// Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain
@@ -144,7 +150,7 @@ func NewChainManager(blockDb, stateDb common.Database, pow pow.PoW, mux *event.T
go bc.update()
- return bc
+ return bc, nil
}
func (bc *ChainManager) SetHead(head *types.Block) {
@@ -562,12 +568,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()}
}
}
diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go
index 560e85f77..c56a3b3e1 100644
--- a/core/chain_manager_test.go
+++ b/core/chain_manager_test.go
@@ -3,6 +3,7 @@ package core
import (
"fmt"
"math/big"
+ "math/rand"
"os"
"path/filepath"
"runtime"
@@ -28,6 +29,21 @@ func thePow() pow.PoW {
return pow
}
+func theChainManager(db common.Database, t *testing.T) *ChainManager {
+ var eventMux event.TypeMux
+ genesis := GenesisBlock(0, db)
+ chainMan, err := NewChainManager(genesis, db, db, thePow(), &eventMux)
+ if err != nil {
+ t.Error("failed creating chainmanager:", err)
+ t.FailNow()
+ return nil
+ }
+ blockMan := NewBlockProcessor(db, db, nil, chainMan, &eventMux)
+ chainMan.SetProcessor(blockMan)
+
+ return chainMan
+}
+
// Test fork of length N starting from block i
func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big.Int)) {
// switch databases to process the new chain
@@ -265,10 +281,7 @@ func TestChainInsertions(t *testing.T) {
t.FailNow()
}
- var eventMux event.TypeMux
- chainMan := NewChainManager(db, db, thePow(), &eventMux)
- blockMan := NewBlockProcessor(db, db, nil, chainMan, &eventMux)
- chainMan.SetProcessor(blockMan)
+ chainMan := theChainManager(db, t)
const max = 2
done := make(chan bool, max)
@@ -310,10 +323,9 @@ func TestChainMultipleInsertions(t *testing.T) {
t.FailNow()
}
}
- var eventMux event.TypeMux
- chainMan := NewChainManager(db, db, thePow(), &eventMux)
- blockMan := NewBlockProcessor(db, db, nil, chainMan, &eventMux)
- chainMan.SetProcessor(blockMan)
+
+ chainMan := theChainManager(db, t)
+
done := make(chan bool, max)
for i, chain := range chains {
// XXX the go routine would otherwise reference the same (chain[3]) variable and fail
@@ -338,8 +350,7 @@ func TestGetAncestors(t *testing.T) {
t.Skip() // travil fails.
db, _ := ethdb.NewMemDatabase()
- var eventMux event.TypeMux
- chainMan := NewChainManager(db, db, thePow(), &eventMux)
+ chainMan := theChainManager(db, t)
chain, err := loadChain("valid1", t)
if err != nil {
fmt.Println(err)
@@ -390,7 +401,7 @@ func chm(genesis *types.Block, db common.Database) *ChainManager {
func TestReorgLongest(t *testing.T) {
t.Skip("skipped while cache is removed")
db, _ := ethdb.NewMemDatabase()
- genesis := GenesisBlock(db)
+ genesis := GenesisBlock(0, db)
bc := chm(genesis, db)
chain1 := makeChainWithDiff(genesis, []int{1, 2, 4}, 10)
@@ -410,7 +421,7 @@ func TestReorgLongest(t *testing.T) {
func TestReorgShortest(t *testing.T) {
t.Skip("skipped while cache is removed")
db, _ := ethdb.NewMemDatabase()
- genesis := GenesisBlock(db)
+ genesis := GenesisBlock(0, db)
bc := chm(genesis, db)
chain1 := makeChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
@@ -426,3 +437,70 @@ func TestReorgShortest(t *testing.T) {
}
}
}
+
+func TestInsertNonceError(t *testing.T) {
+ for i := 1; i < 25 && !t.Failed(); i++ {
+ db, _ := ethdb.NewMemDatabase()
+ genesis := GenesisBlock(0, 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())
+ }
+ }
+ }
+}
+
+func TestGenesisMismatch(t *testing.T) {
+ db, _ := ethdb.NewMemDatabase()
+ var mux event.TypeMux
+ genesis := GenesisBlock(0, db)
+ _, err := NewChainManager(genesis, db, db, thePow(), &mux)
+ if err != nil {
+ t.Error(err)
+ }
+ genesis = GenesisBlock(1, db)
+ _, err = NewChainManager(genesis, db, db, thePow(), &mux)
+ if err == nil {
+ t.Error("expected genesis mismatch error")
+ }
+}
+
+// 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) {
+}
diff --git a/core/error.go b/core/error.go
index 2bdad364f..3f3c350df 100644
--- a/core/error.go
+++ b/core/error.go
@@ -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
}
diff --git a/core/genesis.go b/core/genesis.go
index a9b7339f3..dd894e0b0 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -19,8 +19,8 @@ var ZeroHash256 = make([]byte, 32)
var ZeroHash160 = make([]byte, 20)
var ZeroHash512 = make([]byte, 64)
-func GenesisBlock(db common.Database) *types.Block {
- genesis := types.NewBlock(common.Hash{}, common.Address{}, common.Hash{}, params.GenesisDifficulty, 42, nil)
+func GenesisBlock(nonce uint64, db common.Database) *types.Block {
+ genesis := types.NewBlock(common.Hash{}, common.Address{}, common.Hash{}, params.GenesisDifficulty, nonce, nil)
genesis.Header().Number = common.Big0
genesis.Header().GasLimit = params.GenesisGasLimit
genesis.Header().GasUsed = common.Big0
diff --git a/core/transaction_pool.go b/core/transaction_pool.go
index 27dc1b0d1..77744f8f7 100644
--- a/core/transaction_pool.go
+++ b/core/transaction_pool.go
@@ -331,7 +331,7 @@ func (pool *TxPool) checkQueue() {
// current account nonce.
sort.Sort(addq)
for _, e := range addq {
- if e.AccountNonce > curnonce+1 {
+ if e.AccountNonce > curnonce {
break
}
delete(txs, e.hash)
diff --git a/core/transaction_pool_test.go b/core/transaction_pool_test.go
index ac297d266..b8bf78f00 100644
--- a/core/transaction_pool_test.go
+++ b/core/transaction_pool_test.go
@@ -201,3 +201,26 @@ func TestTransactionDoubleNonce(t *testing.T) {
t.Error("expected 2 pending txs. Got", len(pool.pending))
}
}
+
+func TestMissingNonce(t *testing.T) {
+ pool, key := setupTxPool()
+ addr := crypto.PubkeyToAddress(key.PublicKey)
+ pool.currentState().AddBalance(addr, big.NewInt(100000000000000))
+ tx := transaction()
+ tx.AccountNonce = 1
+ tx.GasLimit = big.NewInt(100000)
+ tx.SignECDSA(key)
+
+ err := pool.add(tx)
+ if err != nil {
+ t.Error("didn't expect error", err)
+ }
+
+ if len(pool.pending) != 0 {
+ t.Error("expected 0 pending transactions, got", len(pool.pending))
+ }
+
+ if len(pool.queue[addr]) != 1 {
+ t.Error("expected 1 queued transaction, got", len(pool.queue[addr]))
+ }
+}