Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Further fixes to block test wrapper #765

Merged
merged 1 commit into from
Apr 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 0 additions & 80 deletions cmd/geth/block_go_test.go

This file was deleted.

6 changes: 3 additions & 3 deletions cmd/geth/blocktest.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
126 changes: 126 additions & 0 deletions tests/block_test.go
Original file line number Diff line number Diff line change
@@ -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() },
}
}
103 changes: 56 additions & 47 deletions tests/block_test_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,27 @@ import (
)

// Block Test JSON Format
type BlockTest struct {
Genesis *types.Block

Json *btJSON
preAccounts map[string]btAccount
}

type btJSON struct {
Blocks []btBlock
GenesisBlockHeader btHeader
Pre map[string]btAccount
PostState map[string]btAccount
}

type btBlock struct {
BlockHeader *btHeader
Rlp string
Transactions []btTransaction
UncleHeaders []*btHeader
}

type btAccount struct {
Balance string
Code string
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand All @@ -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
}
Expand Down Expand Up @@ -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 {
Expand Down