aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGustav Simonsson <gustav.simonsson@gmail.com>2015-04-21 00:14:57 +0800
committerGustav Simonsson <gustav.simonsson@gmail.com>2015-04-21 11:23:10 +0800
commitb448390889685fc87f221c152b16b82849f7797f (patch)
tree99ab2230d8c2b744bf2201368bce0f2045aab944
parent805345d13594b41e5dd2e4fed471c58c3775be9e (diff)
downloaddexon-b448390889685fc87f221c152b16b82849f7797f.tar
dexon-b448390889685fc87f221c152b16b82849f7797f.tar.gz
dexon-b448390889685fc87f221c152b16b82849f7797f.tar.bz2
dexon-b448390889685fc87f221c152b16b82849f7797f.tar.lz
dexon-b448390889685fc87f221c152b16b82849f7797f.tar.xz
dexon-b448390889685fc87f221c152b16b82849f7797f.tar.zst
dexon-b448390889685fc87f221c152b16b82849f7797f.zip
Further fixes to block test wrapper
* Move go test wrapper for block tests from cmd/geth to tests * Fix logic for when tests are valid or not, by adding correct validations for expected valid/invalid blocks * Change block insertion helper to work on single blocks * Add one test case for each file in BlockTests and comment out the tests which are currently failing * Add Skip call in all block tests in lieu of performance fixes around ethash cache which are needed before it will be fast enough to start / stop the node between each test
-rw-r--r--cmd/geth/block_go_test.go80
-rw-r--r--cmd/geth/blocktest.go6
-rw-r--r--tests/block_test.go126
-rw-r--r--tests/block_test_util.go103
4 files changed, 185 insertions, 130 deletions
diff --git a/cmd/geth/block_go_test.go b/cmd/geth/block_go_test.go
deleted file mode 100644
index 1980e4798..000000000
--- a/cmd/geth/block_go_test.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package main
-
-import (
- "path"
- "testing"
-
- "github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/tests"
-)
-
-// TODO: refactor test setup & execution to better align with vm and tx tests
-// TODO: refactor to avoid duplication with cmd/geth/blocktest.go
-func TestBcValidBlockTests(t *testing.T) {
- runBlockTestsInFile("../../tests/files/BlockTests/bcValidBlockTest.json", t)
-}
-
-/*
-func TestBcUncleTests(t *testing.T) {
- runBlockTestsInFile("../../tests/files/BlockTests/bcUncleTest.json", t)
-}
-*/
-
-func runBlockTestsInFile(filepath string, t *testing.T) {
- bt, err := tests.LoadBlockTests(filepath)
- if err != nil {
- t.Fatal(err)
- }
- for name, test := range bt {
- runTest(name, test, t)
- }
-}
-
-func runTest(name string, test *tests.BlockTest, t *testing.T) {
- t.Log("Running test: ", name)
- cfg := testEthConfig()
- ethereum, err := eth.New(cfg)
- if err != nil {
- t.Fatalf("%v", err)
- }
-
- err = ethereum.Start()
- if err != nil {
- t.Fatalf("%v", err)
- }
-
- // import the genesis block
- ethereum.ResetWithGenesisBlock(test.Genesis)
-
- // import pre accounts
- statedb, err := test.InsertPreState(ethereum.StateDb())
- if err != nil {
- t.Fatalf("InsertPreState: %v", err)
- }
-
- // insert the test blocks, which will execute all transactions
- if err := test.InsertBlocks(ethereum.ChainManager()); err != nil {
- t.Fatalf("Block Test load error: %v %T", err, err)
- }
-
- if err := test.ValidatePostState(statedb); err != nil {
- t.Fatal("post state validation failed: %v", err)
- }
- t.Log("Test passed: ", name)
-}
-
-func testEthConfig() *eth.Config {
- ks := crypto.NewKeyStorePassphrase(path.Join(common.DefaultDataDir(), "keys"))
-
- return &eth.Config{
- DataDir: common.DefaultDataDir(),
- LogLevel: 5,
- Etherbase: "primary",
- AccountManager: accounts.NewManager(ks),
- NewDB: func(path string) (common.Database, error) { return ethdb.NewMemDatabase() },
- }
-}
diff --git a/cmd/geth/blocktest.go b/cmd/geth/blocktest.go
index 792981ec0..343a0bf28 100644
--- a/cmd/geth/blocktest.go
+++ b/cmd/geth/blocktest.go
@@ -109,10 +109,10 @@ func runOneBlockTest(ctx *cli.Context, test *tests.BlockTest) (*eth.Ethereum, er
return ethereum, fmt.Errorf("InsertPreState: %v", err)
}
- // insert the test blocks, which will execute all transactions
- if err := test.InsertBlocks(ethereum.ChainManager()); err != nil {
- return ethereum, fmt.Errorf("Block Test load error: %v %T", err, err)
+ if err := test.TryBlocksInsert(ethereum.ChainManager()); err != nil {
+ return ethereum, fmt.Errorf("Block Test load error: %v", err)
}
+
fmt.Println("chain loaded")
if err := test.ValidatePostState(statedb); err != nil {
return ethereum, fmt.Errorf("post state validation failed: %v", err)
diff --git a/tests/block_test.go b/tests/block_test.go
new file mode 100644
index 000000000..bffaf50da
--- /dev/null
+++ b/tests/block_test.go
@@ -0,0 +1,126 @@
+package tests
+
+import (
+ "path"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/accounts"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/ethdb"
+)
+
+// TODO: refactor test setup & execution to better align with vm and tx tests
+func TestBcValidBlockTests(t *testing.T) {
+ t.Skip("Skipped in lieu of performance fixes.")
+ runBlockTestsInFile("files/BlockTests/bcValidBlockTest.json", []string{}, t)
+}
+
+func TestBcUncleTests(t *testing.T) {
+ t.Skip("Skipped in lieu of performance fixes.")
+ runBlockTestsInFile("files/BlockTests/bcUncleTest.json", []string{}, t)
+}
+
+func TestBcUncleHeaderValidityTests(t *testing.T) {
+ t.Skip("Skipped in lieu of performance fixes.")
+ runBlockTestsInFile("files/BlockTests/bcUncleHeaderValiditiy.json", []string{}, t)
+}
+
+func TestBcInvalidHeaderTests(t *testing.T) {
+ t.Skip("Skipped in lieu of performance fixes.")
+ snafus := []string{
+ "wrongUncleHash", // TODO: why does this fail?
+ }
+ runBlockTestsInFile("files/BlockTests/bcInvalidHeaderTest.json", snafus, t)
+}
+
+func TestBcInvalidRLPTests(t *testing.T) {
+ t.Skip("Skipped in lieu of performance fixes.")
+ snafus := []string{
+ // TODO: why does these fail?
+ "TRANSCT__ZeroByteAtTheEnd",
+ "TRANSCT__RandomByteAtTheEnd",
+ "BLOCK__ZeroByteAtTheEnd",
+ "BLOCK__RandomByteAtTheEnd",
+ }
+ runBlockTestsInFile("files/BlockTests/bcInvalidRLPTest.json", snafus, t)
+}
+
+func TestBcJSAPITests(t *testing.T) {
+ t.Skip("Skipped in lieu of performance fixes.")
+ runBlockTestsInFile("files/BlockTests/bcJS_API_Test.json", []string{}, t)
+}
+
+func TestBcRPCAPITests(t *testing.T) {
+ t.Skip("Skipped in lieu of performance fixes.")
+ runBlockTestsInFile("files/BlockTests/bcRPC_API_Test.json", []string{}, t)
+}
+
+func TestBcForkBlockTests(t *testing.T) {
+ t.Skip("Skipped in lieu of performance fixes.")
+ runBlockTestsInFile("files/BlockTests/bcForkBlockTest.json", []string{}, t)
+}
+
+func runBlockTestsInFile(filepath string, snafus []string, t *testing.T) {
+ bt, err := LoadBlockTests(filepath)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ notWorking := make(map[string]bool, 100)
+ for _, name := range snafus {
+ notWorking[name] = true
+ }
+
+ for name, test := range bt {
+ if !notWorking[name] {
+ runBlockTest(name, test, t)
+ }
+ }
+}
+
+func runBlockTest(name string, test *BlockTest, t *testing.T) {
+ t.Log("Running test: ", name)
+ cfg := testEthConfig()
+ ethereum, err := eth.New(cfg)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+
+ err = ethereum.Start()
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+
+ // import the genesis block
+ ethereum.ResetWithGenesisBlock(test.Genesis)
+
+ // import pre accounts
+ statedb, err := test.InsertPreState(ethereum.StateDb())
+ if err != nil {
+ t.Fatalf("InsertPreState: %v", err)
+ }
+
+ err = test.TryBlocksInsert(ethereum.ChainManager())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if err = test.ValidatePostState(statedb); err != nil {
+ t.Fatal("post state validation failed: %v", err)
+ }
+ t.Log("Test passed: ", name)
+}
+
+func testEthConfig() *eth.Config {
+ ks := crypto.NewKeyStorePassphrase(path.Join(common.DefaultDataDir(), "keys"))
+
+ return &eth.Config{
+ DataDir: common.DefaultDataDir(),
+ LogLevel: 5,
+ Etherbase: "primary",
+ AccountManager: accounts.NewManager(ks),
+ NewDB: func(path string) (common.Database, error) { return ethdb.NewMemDatabase() },
+ }
+}
diff --git a/tests/block_test_util.go b/tests/block_test_util.go
index 5c42ae18c..ed2a9fca2 100644
--- a/tests/block_test_util.go
+++ b/tests/block_test_util.go
@@ -19,6 +19,13 @@ import (
)
// Block Test JSON Format
+type BlockTest struct {
+ Genesis *types.Block
+
+ Json *btJSON
+ preAccounts map[string]btAccount
+}
+
type btJSON struct {
Blocks []btBlock
GenesisBlockHeader btHeader
@@ -26,6 +33,13 @@ type btJSON struct {
PostState map[string]btAccount
}
+type btBlock struct {
+ BlockHeader *btHeader
+ Rlp string
+ Transactions []btTransaction
+ UncleHeaders []*btHeader
+}
+
type btAccount struct {
Balance string
Code string
@@ -65,20 +79,6 @@ type btTransaction struct {
Value string
}
-type btBlock struct {
- BlockHeader *btHeader
- Rlp string
- Transactions []btTransaction
- UncleHeaders []*btHeader
-}
-
-type BlockTest struct {
- Genesis *types.Block
-
- json *btJSON
- preAccounts map[string]btAccount
-}
-
// LoadBlockTests loads a block test JSON file.
func LoadBlockTests(file string) (map[string]*BlockTest, error) {
bt := make(map[string]*btJSON)
@@ -125,13 +125,43 @@ func (t *BlockTest) InsertPreState(db common.Database) (*state.StateDB, error) {
return statedb, nil
}
-// InsertBlocks loads the test's blocks into the given chain.
-func (t *BlockTest) InsertBlocks(chain *core.ChainManager) error {
- blocks, err := t.convertBlocks()
- if err != nil {
- return err
+/* See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II
+
+ Whether a block is valid or not is a bit subtle, it's defined by presence of
+ blockHeader, transactions and uncleHeaders fields. If they are missing, the block is
+ invalid and we must verify that we do not accept it.
+
+ Since some tests mix valid and invalid blocks we need to check this for every block.
+
+ If a block is invalid it does not necessarily fail the test, if it's invalidness is
+ expected we are expected to ignore it and continue processing and then validate the
+ post state.
+*/
+func (t *BlockTest) TryBlocksInsert(chainManager *core.ChainManager) error {
+ // insert the test blocks, which will execute all transactions
+ for _, b := range t.Json.Blocks {
+ cb, err := mustConvertBlock(b)
+ if err != nil {
+ if b.BlockHeader == nil {
+ continue // OK - block is supposed to be invalid, continue with next block
+ } else {
+ return fmt.Errorf("Block RLP decoding failed when expected to succeed: ", err)
+ }
+ }
+ // RLP decoding worked, try to insert into chain:
+ err = chainManager.InsertChain(types.Blocks{cb})
+ if err != nil {
+ if b.BlockHeader == nil {
+ continue // OK - block is supposed to be invalid, continue with next block
+ } else {
+ return fmt.Errorf("Block insertion into chain failed: ", err)
+ }
+ }
+ if b.BlockHeader == nil {
+ return fmt.Errorf("Block insertion should have failed")
+ }
}
- return chain.InsertChain(blocks)
+ return nil
}
func (t *BlockTest) ValidatePostState(statedb *state.StateDB) error {
@@ -159,21 +189,6 @@ func (t *BlockTest) ValidatePostState(statedb *state.StateDB) error {
return nil
}
-func (t *BlockTest) convertBlocks() (blocks []*types.Block, err error) {
- // the conversion handles errors by catching panics.
- // you might consider this ugly, but the alternative (passing errors)
- // would be much harder to read.
- defer func() {
- if recovered := recover(); recovered != nil {
- buf := make([]byte, 64<<10)
- buf = buf[:runtime.Stack(buf, false)]
- err = fmt.Errorf("%v\n%s", recovered, buf)
- }
- }()
- blocks = mustConvertBlocks(t.json.Blocks)
- return blocks, nil
-}
-
func convertTest(in *btJSON) (out *BlockTest, err error) {
// the conversion handles errors by catching panics.
// you might consider this ugly, but the alternative (passing errors)
@@ -185,7 +200,7 @@ func convertTest(in *btJSON) (out *BlockTest, err error) {
err = fmt.Errorf("%v\n%s", recovered, buf)
}
}()
- out = &BlockTest{preAccounts: in.Pre, json: in}
+ out = &BlockTest{preAccounts: in.Pre, Json: in}
out.Genesis = mustConvertGenesis(in.GenesisBlockHeader)
return out, err
}
@@ -221,17 +236,11 @@ func mustConvertHeader(in btHeader) *types.Header {
return header
}
-func mustConvertBlocks(testBlocks []btBlock) []*types.Block {
- var out []*types.Block
- for i, inb := range testBlocks {
- var b types.Block
- r := bytes.NewReader(mustConvertBytes(inb.Rlp))
- if err := rlp.Decode(r, &b); err != nil {
- panic(fmt.Errorf("invalid block %d: %q\nerror: %v", i, inb.Rlp, err))
- }
- out = append(out, &b)
- }
- return out
+func mustConvertBlock(testBlock btBlock) (*types.Block, error) {
+ var b types.Block
+ r := bytes.NewReader(mustConvertBytes(testBlock.Rlp))
+ err := rlp.Decode(r, &b)
+ return &b, err
}
func mustConvertBytes(in string) []byte {