浏览代码

cmd: drop blocktest command, create gethrpctest program

Péter Szilágyi 10 年之前
父节点
当前提交
8a44451edf
共有 3 个文件被更改,包括 182 次插入168 次删除
  1. 0 135
      cmd/geth/blocktestcmd.go
  2. 182 0
      cmd/gethrpctest/main.go
  3. 0 33
      node/utils.go

+ 0 - 135
cmd/geth/blocktestcmd.go

@@ -1,135 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of go-ethereum.
-//
-// go-ethereum is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// go-ethereum is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"fmt"
-	"os"
-
-	"github.com/codegangsta/cli"
-	"github.com/ethereum/go-ethereum/cmd/utils"
-	"github.com/ethereum/go-ethereum/eth"
-	"github.com/ethereum/go-ethereum/ethdb"
-	"github.com/ethereum/go-ethereum/tests"
-)
-
-var blocktestCommand = cli.Command{
-	Action: runBlockTest,
-	Name:   "blocktest",
-	Usage:  `loads a block test file`,
-	Description: `
-The first argument should be a block test file.
-The second argument is the name of a block test from the file.
-
-The block test will be loaded into an in-memory database.
-If loading succeeds, the RPC server is started. Clients will
-be able to interact with the chain defined by the test.
-`,
-}
-
-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" ] ]`)
-	}
-	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)
-	}
-	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)
-	db, _ := ethdb.NewMemDatabase()
-	cfg.NewDB = func(path string) (ethdb.Database, error) { return db, nil }
-	cfg.MaxPeers = 0 // disable network
-	cfg.Shh = false  // disable whisper
-	cfg.NAT = nil    // disable port mapping
-	ethereum, err := eth.New(cfg)
-	if err != nil {
-		return nil, err
-	}
-
-	// import the genesis block
-	ethereum.ResetWithGenesisBlock(test.Genesis)
-	// import pre accounts
-	_, err = test.InsertPreState(db, cfg.AccountManager)
-	if err != nil {
-		return ethereum, fmt.Errorf("InsertPreState: %v", err)
-	}
-
-	cm := ethereum.BlockChain()
-	validBlocks, err := test.TryBlocksInsert(cm)
-	if err != nil {
-		return ethereum, fmt.Errorf("Block Test load error: %v", err)
-	}
-	newDB, err := cm.State()
-	if err != nil {
-		return ethereum, fmt.Errorf("Block Test get state error: %v", err)
-	}
-	if err := test.ValidatePostState(newDB); err != nil {
-		return ethereum, fmt.Errorf("post state validation failed: %v", err)
-	}
-	return ethereum, test.ValidateImportedHeaders(cm, validBlocks)
-}

+ 182 - 0
cmd/gethrpctest/main.go

@@ -0,0 +1,182 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of go-ethereum.
+//
+// go-ethereum is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// go-ethereum is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+
+// gethrpctest is a command to run the external RPC tests.
+package main
+
+import (
+	"flag"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/signal"
+
+	"github.com/ethereum/go-ethereum/accounts"
+	"github.com/ethereum/go-ethereum/crypto"
+	"github.com/ethereum/go-ethereum/eth"
+	"github.com/ethereum/go-ethereum/ethdb"
+	"github.com/ethereum/go-ethereum/node"
+	"github.com/ethereum/go-ethereum/rpc/api"
+	"github.com/ethereum/go-ethereum/rpc/codec"
+	"github.com/ethereum/go-ethereum/rpc/comms"
+	"github.com/ethereum/go-ethereum/tests"
+	"github.com/ethereum/go-ethereum/whisper"
+	"github.com/ethereum/go-ethereum/xeth"
+)
+
+const defaultTestKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
+
+var (
+	testFile = flag.String("json", "", "Path to the .json test file to load")
+	testName = flag.String("test", "", "Name of the test from the .json file to run")
+	testKey  = flag.String("key", defaultTestKey, "Private key of a test account to inject")
+)
+
+var (
+	ethereumServiceId = "ethereum"
+	whisperServiceId  = "whisper"
+)
+
+func main() {
+	flag.Parse()
+
+	// Load the test suite to run the RPC against
+	tests, err := tests.LoadBlockTests(*testFile)
+	if err != nil {
+		log.Fatalf("Failed to load test suite: %v", err)
+	}
+	test, found := tests[*testName]
+	if !found {
+		log.Fatalf("Requested test (%s) not found within suite", *testName)
+	}
+	// Create the protocol stack to run the test with
+	keydir, err := ioutil.TempDir("", "")
+	if err != nil {
+		log.Fatalf("Failed to create temporary keystore directory: %v", err)
+	}
+	defer os.RemoveAll(keydir)
+
+	stack, err := MakeSystemNode(keydir, *testKey, test)
+	if err != nil {
+		log.Fatalf("Failed to assemble test stack: %v", err)
+	}
+	if err := stack.Start(); err != nil {
+		log.Fatalf("Failed to start test node: %v", err)
+	}
+	defer stack.Stop()
+
+	log.Println("Test node started...")
+
+	// Make sure the tests contained within the suite pass
+	if err := RunTest(stack, test); err != nil {
+		log.Fatalf("Failed to run the pre-configured test: %v", err)
+	}
+	log.Println("Initial test suite passed...")
+
+	// Start the RPC interface and wait until terminated
+	if err := StartRPC(stack); err != nil {
+		log.Fatalf("Failed to start RPC instarface: %v", err)
+	}
+	log.Println("RPC Interface started, accepting requests...")
+
+	quit := make(chan os.Signal, 1)
+	signal.Notify(quit, os.Interrupt)
+	<-quit
+}
+
+// MakeSystemNode configures a protocol stack for the RPC tests based on a given
+// keystore path and initial pre-state.
+func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node.Node, error) {
+	// Create a networkless protocol stack
+	stack, err := node.New(&node.Config{NoDiscovery: true})
+	if err != nil {
+		return nil, err
+	}
+	// Create the keystore and inject an unlocked account if requested
+	keystore := crypto.NewKeyStorePassphrase(keydir, crypto.StandardScryptN, crypto.StandardScryptP)
+	accman := accounts.NewManager(keystore)
+
+	if len(privkey) > 0 {
+		key, err := crypto.HexToECDSA(privkey)
+		if err != nil {
+			return nil, err
+		}
+		if err := keystore.StoreKey(crypto.NewKeyFromECDSA(key), ""); err != nil {
+			return nil, err
+		}
+		if err := accman.Unlock(crypto.NewKeyFromECDSA(key).Address, ""); err != nil {
+			return nil, err
+		}
+	}
+	// Initialize and register the Ethereum protocol
+	db, _ := ethdb.NewMemDatabase()
+	if _, err := test.InsertPreState(db, accman); err != nil {
+		return nil, err
+	}
+	ethConf := &eth.Config{
+		TestGenesisState: db,
+		TestGenesisBlock: test.Genesis,
+		AccountManager:   accman,
+	}
+	if err := stack.Register(ethereumServiceId, func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil {
+		return nil, err
+	}
+	// Initialize and register the Whisper protocol
+	if err := stack.Register(whisperServiceId, func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil {
+		return nil, err
+	}
+	return stack, nil
+}
+
+// RunTest executes the specified test against an already pre-configured protocol
+// stack to ensure basic checks pass before running RPC tests.
+func RunTest(stack *node.Node, test *tests.BlockTest) error {
+	blockchain := stack.Service(ethereumServiceId).(*eth.Ethereum).BlockChain()
+
+	// Process the blocks and verify the imported headers
+	blocks, err := test.TryBlocksInsert(blockchain)
+	if err != nil {
+		return err
+	}
+	if err := test.ValidateImportedHeaders(blockchain, blocks); err != nil {
+		return err
+	}
+	// Retrieve the assembled state and validate it
+	stateDb, err := blockchain.State()
+	if err != nil {
+		return err
+	}
+	if err := test.ValidatePostState(stateDb); err != nil {
+		return err
+	}
+	return nil
+}
+
+// StartRPC initializes an RPC interface to the given protocol stack.
+func StartRPC(stack *node.Node) error {
+	config := comms.HttpConfig{
+		ListenAddress: "127.0.0.1",
+		ListenPort:    8545,
+	}
+	xeth := xeth.New(stack, nil)
+	codec := codec.JSON
+
+	apis, err := api.ParseApiString(comms.DefaultHttpRpcApis, codec, xeth, stack)
+	if err != nil {
+		return err
+	}
+	return comms.StartHttp(config, codec, api.Merge(apis...))
+}

+ 0 - 33
node/utils.go

@@ -1,33 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package node
-
-import (
-	"path/filepath"
-
-	"github.com/ethereum/go-ethereum/ethdb"
-)
-
-// openDatabase opens an existing database with the given name from within the
-// specified data directory, creating one if none exists. If the data directory
-// is empty, an ephemeral memory database is returned.
-func openDatabase(dataDir string, name string, cache int) (ethdb.Database, error) {
-	if dataDir == "" {
-		return ethdb.NewMemDatabase()
-	}
-	return ethdb.NewLDBDatabase(filepath.Join(dataDir, name), cache)
-}