aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2016-07-08 23:48:17 +0800
committerPéter Szilágyi <peterke@gmail.com>2016-07-15 21:52:55 +0800
commita87089fd2dc08a69a4a4f1ef93db9a2871d819a3 (patch)
treeb1634faefc24ee8b80b9ad9c06ac8df7f409558b /core
parent1e24c2e4f428c85c2f83272af2696469cb8f5bed (diff)
downloadgo-tangerine-a87089fd2dc08a69a4a4f1ef93db9a2871d819a3.tar
go-tangerine-a87089fd2dc08a69a4a4f1ef93db9a2871d819a3.tar.gz
go-tangerine-a87089fd2dc08a69a4a4f1ef93db9a2871d819a3.tar.bz2
go-tangerine-a87089fd2dc08a69a4a4f1ef93db9a2871d819a3.tar.lz
go-tangerine-a87089fd2dc08a69a4a4f1ef93db9a2871d819a3.tar.xz
go-tangerine-a87089fd2dc08a69a4a4f1ef93db9a2871d819a3.tar.zst
go-tangerine-a87089fd2dc08a69a4a4f1ef93db9a2871d819a3.zip
cmd, core, miner: add extradata validation to consensus rules
Diffstat (limited to 'core')
-rw-r--r--core/block_validator.go21
-rw-r--r--core/block_validator_test.go105
-rw-r--r--core/config.go5
3 files changed, 129 insertions, 2 deletions
diff --git a/core/block_validator.go b/core/block_validator.go
index c3f959324..73d581328 100644
--- a/core/block_validator.go
+++ b/core/block_validator.go
@@ -17,6 +17,7 @@
package core
import (
+ "bytes"
"fmt"
"math/big"
"time"
@@ -247,6 +248,26 @@ func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, pare
return &BlockNonceErr{header.Number, header.Hash(), header.Nonce.Uint64()}
}
}
+ // DAO hard-fork extension to the header validity: a) if the node is no-fork,
+ // do not accept blocks in the [fork, fork+10) range with the fork specific
+ // extra-data set; b) if the node is pro-fork, require blocks in the specific
+ // range to have the unique extra-data set.
+ if daoBlock := config.DAOForkBlock; daoBlock != nil {
+ // Check whether the block is among the fork extra-override range
+ limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
+ if daoBlock.Cmp(header.Number) <= 0 && header.Number.Cmp(limit) < 0 {
+ // Depending whether we support or oppose the fork, verrift the extra-data contents
+ if config.DAOForkSupport {
+ if bytes.Compare(header.Extra, params.DAOForkBlockExtra) != 0 {
+ return ValidationError("DAO pro-fork bad block extra-data: 0x%x", header.Extra)
+ }
+ } else {
+ if bytes.Compare(header.Extra, params.DAOForkBlockExtra) == 0 {
+ return ValidationError("DAO no-fork bad block extra-data: 0x%x", header.Extra)
+ }
+ }
+ }
+ }
return nil
}
diff --git a/core/block_validator_test.go b/core/block_validator_test.go
index c6daf9e7f..5320c3f8d 100644
--- a/core/block_validator_test.go
+++ b/core/block_validator_test.go
@@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow/ezp"
)
@@ -92,3 +93,107 @@ func TestPutReceipt(t *testing.T) {
t.Error("expected to get 1 receipt, got none.")
}
}
+
+// Tests that DAO-fork enabled clients can properly filter out fork-commencing
+// blocks based on their extradata fields.
+func TestDAOForkRangeExtradata(t *testing.T) {
+ forkBlock := big.NewInt(32)
+
+ // Generate a common prefix for both pro-forkers and non-forkers
+ db, _ := ethdb.NewMemDatabase()
+ genesis := WriteGenesisBlockForTesting(db)
+ prefix, _ := GenerateChain(genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
+
+ // Create the concurrent, conflicting two nodes
+ proDb, _ := ethdb.NewMemDatabase()
+ WriteGenesisBlockForTesting(proDb)
+ proBc, _ := NewBlockChain(proDb, &ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}, new(FakePow), new(event.TypeMux))
+
+ conDb, _ := ethdb.NewMemDatabase()
+ WriteGenesisBlockForTesting(conDb)
+ conBc, _ := NewBlockChain(conDb, &ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}, new(FakePow), new(event.TypeMux))
+
+ if _, err := proBc.InsertChain(prefix); err != nil {
+ t.Fatalf("pro-fork: failed to import chain prefix: %v", err)
+ }
+ if _, err := conBc.InsertChain(prefix); err != nil {
+ t.Fatalf("con-fork: failed to import chain prefix: %v", err)
+ }
+ // Try to expand both pro-fork and non-fork chains iteratively with other camp's blocks
+ for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ {
+ // Create a pro-fork block, and try to feed into the no-fork chain
+ db, _ = ethdb.NewMemDatabase()
+ WriteGenesisBlockForTesting(db)
+ bc, _ := NewBlockChain(db, &ChainConfig{HomesteadBlock: big.NewInt(0)}, new(FakePow), new(event.TypeMux))
+
+ blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
+ for j := 0; j < len(blocks)/2; j++ {
+ blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
+ }
+ if _, err := bc.InsertChain(blocks); err != nil {
+ t.Fatalf("failed to import contra-fork chain for expansion: %v", err)
+ }
+ blocks, _ = GenerateChain(conBc.CurrentBlock(), db, 1, func(i int, gen *BlockGen) { gen.SetExtra(params.DAOForkBlockExtra) })
+ if _, err := conBc.InsertChain(blocks); err == nil {
+ t.Fatalf("contra-fork chain accepted pro-fork block: %v", blocks[0])
+ }
+ // Create a proper no-fork block for the contra-forker
+ blocks, _ = GenerateChain(conBc.CurrentBlock(), db, 1, func(i int, gen *BlockGen) {})
+ if _, err := conBc.InsertChain(blocks); err != nil {
+ t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err)
+ }
+ // Create a no-fork block, and try to feed into the pro-fork chain
+ db, _ = ethdb.NewMemDatabase()
+ WriteGenesisBlockForTesting(db)
+ bc, _ = NewBlockChain(db, &ChainConfig{HomesteadBlock: big.NewInt(0)}, new(FakePow), new(event.TypeMux))
+
+ blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
+ for j := 0; j < len(blocks)/2; j++ {
+ blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
+ }
+ if _, err := bc.InsertChain(blocks); err != nil {
+ t.Fatalf("failed to import pro-fork chain for expansion: %v", err)
+ }
+ blocks, _ = GenerateChain(proBc.CurrentBlock(), db, 1, func(i int, gen *BlockGen) {})
+ if _, err := proBc.InsertChain(blocks); err == nil {
+ t.Fatalf("pro-fork chain accepted contra-fork block: %v", blocks[0])
+ }
+ // Create a proper pro-fork block for the pro-forker
+ blocks, _ = GenerateChain(proBc.CurrentBlock(), db, 1, func(i int, gen *BlockGen) { gen.SetExtra(params.DAOForkBlockExtra) })
+ if _, err := proBc.InsertChain(blocks); err != nil {
+ t.Fatalf("pro-fork chain didn't accepted pro-fork block: %v", err)
+ }
+ }
+ // Verify that contra-forkers accept pro-fork extra-datas after forking finishes
+ db, _ = ethdb.NewMemDatabase()
+ WriteGenesisBlockForTesting(db)
+ bc, _ := NewBlockChain(db, &ChainConfig{HomesteadBlock: big.NewInt(0)}, new(FakePow), new(event.TypeMux))
+
+ blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
+ for j := 0; j < len(blocks)/2; j++ {
+ blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
+ }
+ if _, err := bc.InsertChain(blocks); err != nil {
+ t.Fatalf("failed to import contra-fork chain for expansion: %v", err)
+ }
+ blocks, _ = GenerateChain(conBc.CurrentBlock(), db, 1, func(i int, gen *BlockGen) { gen.SetExtra(params.DAOForkBlockExtra) })
+ if _, err := conBc.InsertChain(blocks); err != nil {
+ t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err)
+ }
+ // Verify that pro-forkers accept contra-fork extra-datas after forking finishes
+ db, _ = ethdb.NewMemDatabase()
+ WriteGenesisBlockForTesting(db)
+ bc, _ = NewBlockChain(db, &ChainConfig{HomesteadBlock: big.NewInt(0)}, new(FakePow), new(event.TypeMux))
+
+ blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
+ for j := 0; j < len(blocks)/2; j++ {
+ blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
+ }
+ if _, err := bc.InsertChain(blocks); err != nil {
+ t.Fatalf("failed to import pro-fork chain for expansion: %v", err)
+ }
+ blocks, _ = GenerateChain(proBc.CurrentBlock(), db, 1, func(i int, gen *BlockGen) {})
+ if _, err := proBc.InsertChain(blocks); err != nil {
+ t.Fatalf("pro-fork chain didn't accept contra-fork block post-fork: %v", err)
+ }
+}
diff --git a/core/config.go b/core/config.go
index d04b00e9c..c0d065a57 100644
--- a/core/config.go
+++ b/core/config.go
@@ -31,8 +31,9 @@ var ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general conf
// that any network, identified by its genesis block, can have its own
// set of configuration options.
type ChainConfig struct {
- HomesteadBlock *big.Int `json:"homesteadBlock"` // homestead switch block (0 = already homestead)
- DAOForkBlock *big.Int `json:"daoForkBlock"` // TheDAO hard-fork block (nil = no fork)
+ HomesteadBlock *big.Int `json:"homesteadBlock"` // Homestead switch block (nil = no fork, 0 = already homestead)
+ DAOForkBlock *big.Int `json:"daoForkBlock"` // TheDAO hard-fork switch block (nil = no fork)
+ DAOForkSupport bool `json:"daoForkSupport"` // Whether the nodes supports or opposes the DAO hard-fork
VmConfig vm.Config `json:"-"`
}