aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/geth/blocktest.go89
-rw-r--r--tests/blocktest.go49
2 files changed, 105 insertions, 33 deletions
diff --git a/cmd/geth/blocktest.go b/cmd/geth/blocktest.go
index f0b6bb1a2..792981ec0 100644
--- a/cmd/geth/blocktest.go
+++ b/cmd/geth/blocktest.go
@@ -2,6 +2,7 @@ package main
import (
"fmt"
+ "os"
"github.com/codegangsta/cli"
"github.com/ethereum/go-ethereum/cmd/utils"
@@ -12,7 +13,7 @@ import (
)
var blocktestCmd = cli.Command{
- Action: runblocktest,
+ Action: runBlockTest,
Name: "blocktest",
Usage: `loads a block test file`,
Description: `
@@ -25,27 +26,78 @@ be able to interact with the chain defined by the test.
`,
}
-func runblocktest(ctx *cli.Context) {
- if len(ctx.Args()) != 3 {
- utils.Fatalf("Usage: ethereum blocktest <path-to-test-file> <test-name> {rpc, norpc}")
+func runBlockTest(ctx *cli.Context) {
+ var (
+ file, testname string
+ rpc bool
+ )
+ args := ctx.Args()
+ switch {
+ case len(args) == 1:
+ file = args[0]
+ case len(args) == 2:
+ file, testname = args[0], args[1]
+ case len(args) == 3:
+ file, testname = args[0], args[1]
+ rpc = true
+ default:
+ utils.Fatalf(`Usage: ethereum blocktest <path-to-test-file> [ <test-name> [ "rpc" ] ]`)
}
- file, testname, startrpc := ctx.Args()[0], ctx.Args()[1], ctx.Args()[2]
-
bt, err := tests.LoadBlockTests(file)
if err != nil {
utils.Fatalf("%v", err)
}
+
+ // run all tests if no test name is specified
+ if testname == "" {
+ ecode := 0
+ for name, test := range bt {
+ fmt.Printf("----------------- Running Block Test %q\n", name)
+ ethereum, err := runOneBlockTest(ctx, test)
+ if err != nil {
+ fmt.Println(err)
+ fmt.Println("FAIL")
+ ecode = 1
+ }
+ if ethereum != nil {
+ ethereum.Stop()
+ ethereum.WaitForShutdown()
+ }
+ }
+ os.Exit(ecode)
+ return
+ }
+ // otherwise, run the given test
test, ok := bt[testname]
if !ok {
utils.Fatalf("Test file does not contain test named %q", testname)
}
+ ethereum, err := runOneBlockTest(ctx, test)
+ if err != nil {
+ utils.Fatalf("%v", err)
+ }
+ defer ethereum.Stop()
+ if rpc {
+ fmt.Println("Block Test post state validated, starting RPC interface.")
+ startEth(ctx, ethereum)
+ utils.StartRPC(ethereum, ctx)
+ ethereum.WaitForShutdown()
+ }
+}
+func runOneBlockTest(ctx *cli.Context, test *tests.BlockTest) (*eth.Ethereum, error) {
cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx)
cfg.NewDB = func(path string) (common.Database, error) { return ethdb.NewMemDatabase() }
cfg.MaxPeers = 0 // disable network
+ cfg.Shh = false // disable whisper
+ cfg.NAT = nil // disable port mapping
+
ethereum, err := eth.New(cfg)
if err != nil {
- utils.Fatalf("%v", err)
+ return nil, err
+ }
+ if err := ethereum.Start(); err != nil {
+ return nil, err
}
// import the genesis block
@@ -54,27 +106,16 @@ func runblocktest(ctx *cli.Context) {
// import pre accounts
statedb, err := test.InsertPreState(ethereum.StateDb())
if err != nil {
- utils.Fatalf("could not insert genesis accounts: %v", err)
+ return ethereum, fmt.Errorf("InsertPreState: %v", err)
}
// insert the test blocks, which will execute all transactions
- chain := ethereum.ChainManager()
- if err := chain.InsertChain(test.Blocks); err != nil {
- utils.Fatalf("Block Test load error: %v %T", err, err)
- } else {
- fmt.Println("Block Test chain loaded")
+ if err := test.InsertBlocks(ethereum.ChainManager()); err != nil {
+ return ethereum, fmt.Errorf("Block Test load error: %v %T", err, err)
}
-
+ fmt.Println("chain loaded")
if err := test.ValidatePostState(statedb); err != nil {
- utils.Fatalf("post state validation failed: %v", err)
- }
- fmt.Println("Block Test post state validated, starting ethereum.")
-
- if startrpc == "rpc" {
- startEth(ctx, ethereum)
- utils.StartRPC(ethereum, ctx)
- ethereum.WaitForShutdown()
- } else {
- startEth(ctx, ethereum)
+ return ethereum, fmt.Errorf("post state validation failed: %v", err)
}
+ return ethereum, nil
}
diff --git a/tests/blocktest.go b/tests/blocktest.go
index 2d6b11944..37fd9e494 100644
--- a/tests/blocktest.go
+++ b/tests/blocktest.go
@@ -12,6 +12,7 @@ import (
"strings"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
@@ -73,8 +74,8 @@ type btBlock struct {
type BlockTest struct {
Genesis *types.Block
- Blocks []*types.Block
+ json *btJSON
preAccounts map[string]btAccount
}
@@ -88,7 +89,7 @@ func LoadBlockTests(file string) (map[string]*BlockTest, error) {
for name, in := range bt {
var err error
if out[name], err = convertTest(in); err != nil {
- return nil, fmt.Errorf("bad test %q: %v", err)
+ return out, fmt.Errorf("bad test %q: %v", name, err)
}
}
return out, nil
@@ -124,6 +125,15 @@ 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
+ }
+ return chain.InsertChain(blocks)
+}
+
func (t *BlockTest) ValidatePostState(statedb *state.StateDB) error {
for addrString, acct := range t.preAccounts {
// XXX: is is worth it checking for errors here?
@@ -149,6 +159,21 @@ 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)
@@ -160,9 +185,8 @@ func convertTest(in *btJSON) (out *BlockTest, err error) {
err = fmt.Errorf("%v\n%s", recovered, buf)
}
}()
- out = &BlockTest{preAccounts: in.Pre}
+ out = &BlockTest{preAccounts: in.Pre, json: in}
out.Genesis = mustConvertGenesis(in.GenesisBlockHeader)
- out.Blocks = mustConvertBlocks(in.Blocks)
return out, err
}
@@ -203,7 +227,7 @@ func mustConvertBlocks(testBlocks []btBlock) []*types.Block {
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", i, inb.Rlp))
+ panic(fmt.Errorf("invalid block %d: %q\nerror: %v", i, inb.Rlp, err))
}
out = append(out, &b)
}
@@ -293,11 +317,18 @@ func findLine(data []byte, offset int64) (line int) {
}
func unfuckCPPHexInts(s string) string {
- if s == "0x" { // no respect for the empty value :(
+ switch {
+ case s == "0x":
+ // no respect for the empty value :(
return "0x00"
- }
- if (len(s) % 2) != 0 { // motherfucking nibbles
+ case len(s) == 0:
+ return "0x00"
+ case len(s) == 1:
+ return "0x0" + s[:1]
+ case len(s)%2 != 0:
+ // motherfucking nibbles
return "0x0" + s[2:]
+ default:
+ return s
}
- return s
}