main.go 5.32 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// 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"
26

27
	"github.com/ethereum/go-ethereum/accounts"
28
	"github.com/ethereum/go-ethereum/common"
29
	"github.com/ethereum/go-ethereum/core"
30 31 32
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/eth"
	"github.com/ethereum/go-ethereum/ethdb"
33
	"github.com/ethereum/go-ethereum/logger/glog"
34
	"github.com/ethereum/go-ethereum/node"
35
	"github.com/ethereum/go-ethereum/params"
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
	"github.com/ethereum/go-ethereum/tests"
	"github.com/ethereum/go-ethereum/whisper"
)

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")
)

func main() {
	flag.Parse()

51 52 53 54
	// Enable logging errors, we really do want to see those
	glog.SetV(2)
	glog.SetToStderr(true)

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
	// 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...")

	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
97
	stack, err := node.New(&node.Config{
98 99 100 101 102 103 104
		IPCPath:     node.DefaultIPCEndpoint(),
		HTTPHost:    common.DefaultHTTPHost,
		HTTPPort:    common.DefaultHTTPPort,
		HTTPModules: []string{"admin", "db", "eth", "debug", "miner", "net", "shh", "txpool", "personal", "web3"},
		WSHost:      common.DefaultWSHost,
		WSPort:      common.DefaultWSPort,
		WSModules:   []string{"admin", "db", "eth", "debug", "miner", "net", "shh", "txpool", "personal", "web3"},
105 106
		NoDiscovery: true,
	})
107 108 109 110
	if err != nil {
		return nil, err
	}
	// Create the keystore and inject an unlocked account if requested
111
	accman := accounts.NewPlaintextManager(keydir)
112 113 114 115 116
	if len(privkey) > 0 {
		key, err := crypto.HexToECDSA(privkey)
		if err != nil {
			return nil, err
		}
117 118
		a, err := accman.ImportECDSA(key, "")
		if err != nil {
119 120
			return nil, err
		}
Felix Lange's avatar
Felix Lange committed
121
		if err := accman.Unlock(a, ""); err != nil {
122 123 124 125 126
			return nil, err
		}
	}
	// Initialize and register the Ethereum protocol
	db, _ := ethdb.NewMemDatabase()
127
	if _, err := test.InsertPreState(db); err != nil {
128 129 130 131 132
		return nil, err
	}
	ethConf := &eth.Config{
		TestGenesisState: db,
		TestGenesisBlock: test.Genesis,
133
		ChainConfig:      &core.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock},
134 135
		AccountManager:   accman,
	}
136
	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil {
137 138 139
		return nil, err
	}
	// Initialize and register the Whisper protocol
140
	if err := stack.Register(func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil {
141 142 143 144 145 146 147 148
		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 {
149
	var ethereum *eth.Ethereum
150
	stack.Service(&ethereum)
151
	blockchain := ethereum.BlockChain()
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170

	// 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
}