Commit 1e806c4c authored by Péter Szilágyi's avatar Péter Szilágyi

cmd, common, core, eth, node, rpc, tests, whisper, xeth: use protocol stacks

parent 8a44451e
...@@ -34,6 +34,7 @@ import ( ...@@ -34,6 +34,7 @@ import (
"github.com/ethereum/go-ethereum/common/registrar" "github.com/ethereum/go-ethereum/common/registrar"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
re "github.com/ethereum/go-ethereum/jsre" re "github.com/ethereum/go-ethereum/jsre"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/rpc/api" "github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
...@@ -77,7 +78,7 @@ func (r dumbterm) AppendHistory(string) {} ...@@ -77,7 +78,7 @@ func (r dumbterm) AppendHistory(string) {}
type jsre struct { type jsre struct {
re *re.JSRE re *re.JSRE
ethereum *eth.Ethereum stack *node.Node
xeth *xeth.XEth xeth *xeth.XEth
wait chan *big.Int wait chan *big.Int
ps1 string ps1 string
...@@ -176,18 +177,18 @@ func newLightweightJSRE(docRoot string, client comms.EthereumClient, datadir str ...@@ -176,18 +177,18 @@ func newLightweightJSRE(docRoot string, client comms.EthereumClient, datadir str
return js return js
} }
func newJSRE(ethereum *eth.Ethereum, docRoot, corsDomain string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre { func newJSRE(stack *node.Node, docRoot, corsDomain string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre {
js := &jsre{ethereum: ethereum, ps1: "> "} js := &jsre{stack: stack, ps1: "> "}
// set default cors domain used by startRpc from CLI flag // set default cors domain used by startRpc from CLI flag
js.corsDomain = corsDomain js.corsDomain = corsDomain
if f == nil { if f == nil {
f = js f = js
} }
js.xeth = xeth.New(ethereum, f) js.xeth = xeth.New(stack, f)
js.wait = js.xeth.UpdateState() js.wait = js.xeth.UpdateState()
js.client = client js.client = client
if clt, ok := js.client.(*comms.InProcClient); ok { if clt, ok := js.client.(*comms.InProcClient); ok {
if offeredApis, err := api.ParseApiString(shared.AllApis, codec.JSON, js.xeth, ethereum); err == nil { if offeredApis, err := api.ParseApiString(shared.AllApis, codec.JSON, js.xeth, stack); err == nil {
clt.Initialize(api.Merge(offeredApis...)) clt.Initialize(api.Merge(offeredApis...))
} }
} }
...@@ -202,14 +203,14 @@ func newJSRE(ethereum *eth.Ethereum, docRoot, corsDomain string, client comms.Et ...@@ -202,14 +203,14 @@ func newJSRE(ethereum *eth.Ethereum, docRoot, corsDomain string, client comms.Et
js.prompter = dumbterm{bufio.NewReader(os.Stdin)} js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
} else { } else {
lr := liner.NewLiner() lr := liner.NewLiner()
js.withHistory(ethereum.DataDir, func(hist *os.File) { lr.ReadHistory(hist) }) js.withHistory(stack.DataDir(), func(hist *os.File) { lr.ReadHistory(hist) })
lr.SetCtrlCAborts(true) lr.SetCtrlCAborts(true)
js.loadAutoCompletion() js.loadAutoCompletion()
lr.SetWordCompleter(apiWordCompleter) lr.SetWordCompleter(apiWordCompleter)
lr.SetTabCompletionStyle(liner.TabPrints) lr.SetTabCompletionStyle(liner.TabPrints)
js.prompter = lr js.prompter = lr
js.atexit = func() { js.atexit = func() {
js.withHistory(ethereum.DataDir, func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) }) js.withHistory(stack.DataDir(), func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) })
lr.Close() lr.Close()
close(js.wait) close(js.wait)
} }
...@@ -276,7 +277,7 @@ func (js *jsre) apiBindings(f xeth.Frontend) error { ...@@ -276,7 +277,7 @@ func (js *jsre) apiBindings(f xeth.Frontend) error {
apiNames = append(apiNames, a) apiNames = append(apiNames, a)
} }
apiImpl, err := api.ParseApiString(strings.Join(apiNames, ","), codec.JSON, js.xeth, js.ethereum) apiImpl, err := api.ParseApiString(strings.Join(apiNames, ","), codec.JSON, js.xeth, js.stack)
if err != nil { if err != nil {
utils.Fatalf("Unable to determine supported api's: %v", err) utils.Fatalf("Unable to determine supported api's: %v", err)
} }
...@@ -342,8 +343,14 @@ func (self *jsre) AskPassword() (string, bool) { ...@@ -342,8 +343,14 @@ func (self *jsre) AskPassword() (string, bool) {
} }
func (self *jsre) ConfirmTransaction(tx string) bool { func (self *jsre) ConfirmTransaction(tx string) bool {
if self.ethereum.NatSpec { // Retrieve the Ethereum instance from the node
notice := natspec.GetNotice(self.xeth, tx, self.ethereum.HTTPClient()) var ethereum *eth.Ethereum
if _, err := self.stack.SingletonService(&ethereum); err != nil {
return false
}
// If natspec is enabled, ask for permission
if ethereum.NatSpec {
notice := natspec.GetNotice(self.xeth, tx, ethereum.HTTPClient())
fmt.Println(notice) fmt.Println(notice)
answer, _ := self.Prompt("Confirm Transaction [y/n]") answer, _ := self.Prompt("Confirm Transaction [y/n]")
return strings.HasPrefix(strings.Trim(answer, " "), "y") return strings.HasPrefix(strings.Trim(answer, " "), "y")
...@@ -359,7 +366,11 @@ func (self *jsre) UnlockAccount(addr []byte) bool { ...@@ -359,7 +366,11 @@ func (self *jsre) UnlockAccount(addr []byte) bool {
return false return false
} }
// TODO: allow retry // TODO: allow retry
if err := self.ethereum.AccountManager().Unlock(common.BytesToAddress(addr), pass); err != nil { var ethereum *eth.Ethereum
if _, err := self.stack.SingletonService(&ethereum); err != nil {
return false
}
if err := ethereum.AccountManager().Unlock(common.BytesToAddress(addr), pass); err != nil {
return false return false
} else { } else {
fmt.Println("Account is now unlocked for this session.") fmt.Println("Account is now unlocked for this session.")
......
...@@ -38,6 +38,7 @@ import ( ...@@ -38,6 +38,7 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/comms" "github.com/ethereum/go-ethereum/rpc/comms"
) )
...@@ -66,7 +67,10 @@ type testjethre struct { ...@@ -66,7 +67,10 @@ type testjethre struct {
} }
func (self *testjethre) UnlockAccount(acc []byte) bool { func (self *testjethre) UnlockAccount(acc []byte) bool {
err := self.ethereum.AccountManager().Unlock(common.BytesToAddress(acc), "") var ethereum *eth.Ethereum
self.stack.SingletonService(&ethereum)
err := ethereum.AccountManager().Unlock(common.BytesToAddress(acc), "")
if err != nil { if err != nil {
panic("unable to unlock") panic("unable to unlock")
} }
...@@ -74,67 +78,74 @@ func (self *testjethre) UnlockAccount(acc []byte) bool { ...@@ -74,67 +78,74 @@ func (self *testjethre) UnlockAccount(acc []byte) bool {
} }
func (self *testjethre) ConfirmTransaction(tx string) bool { func (self *testjethre) ConfirmTransaction(tx string) bool {
if self.ethereum.NatSpec { var ethereum *eth.Ethereum
self.stack.SingletonService(&ethereum)
if ethereum.NatSpec {
self.lastConfirm = natspec.GetNotice(self.xeth, tx, self.client) self.lastConfirm = natspec.GetNotice(self.xeth, tx, self.client)
} }
return true return true
} }
func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) { func testJEthRE(t *testing.T) (string, *testjethre, *node.Node) {
return testREPL(t, nil) return testREPL(t, nil)
} }
func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *eth.Ethereum) { func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *node.Node) {
tmp, err := ioutil.TempDir("", "geth-test") tmp, err := ioutil.TempDir("", "geth-test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Create a networkless protocol stack
stack, err := node.New(&node.Config{PrivateKey: testNodeKey, Name: "test", NoDiscovery: true})
if err != nil {
t.Fatalf("failed to create node: %v", err)
}
// Initialize and register the Ethereum protocol
keystore := crypto.NewKeyStorePlain(filepath.Join(tmp, "keystore"))
accman := accounts.NewManager(keystore)
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
core.WriteGenesisBlockForTesting(db, core.GenesisAccount{common.HexToAddress(testAddress), common.String2Big(testBalance)}) core.WriteGenesisBlockForTesting(db, core.GenesisAccount{common.HexToAddress(testAddress), common.String2Big(testBalance)})
ks := crypto.NewKeyStorePlain(filepath.Join(tmp, "keystore"))
am := accounts.NewManager(ks) ethConf := &eth.Config{
conf := &eth.Config{ TestGenesisState: db,
NodeKey: testNodeKey, AccountManager: accman,
DataDir: tmp, DocRoot: "/",
AccountManager: am, SolcPath: testSolcPath,
MaxPeers: 0, PowTest: true,
Name: "test",
DocRoot: "/",
SolcPath: testSolcPath,
PowTest: true,
NewDB: func(path string) (ethdb.Database, error) { return db, nil },
} }
if config != nil { if config != nil {
config(conf) config(ethConf)
} }
ethereum, err := eth.New(conf) if err := stack.Register("ethereum", func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil {
if err != nil { t.Fatalf("failed to register ethereum protocol: %v", err)
t.Fatal("%v", err)
} }
// Initialize all the keys for testing
keyb, err := crypto.HexToECDSA(testKey) keyb, err := crypto.HexToECDSA(testKey)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
key := crypto.NewKeyFromECDSA(keyb) key := crypto.NewKeyFromECDSA(keyb)
err = ks.StoreKey(key, "") if err := keystore.StoreKey(key, ""); err != nil {
if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := accman.Unlock(key.Address, ""); err != nil {
err = am.Unlock(key.Address, "")
if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Start the node and assemble the REPL tester
if err := stack.Start(); err != nil {
t.Fatalf("failed to start test stack: %v", err)
}
var ethereum *eth.Ethereum
stack.SingletonService(&ethereum)
assetPath := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext") assetPath := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext")
client := comms.NewInProcClient(codec.JSON) client := comms.NewInProcClient(codec.JSON)
tf := &testjethre{client: ethereum.HTTPClient()} tf := &testjethre{client: ethereum.HTTPClient()}
repl := newJSRE(ethereum, assetPath, "", client, false, tf) repl := newJSRE(stack, assetPath, "", client, false, tf)
tf.jsre = repl tf.jsre = repl
return tmp, tf, ethereum return tmp, tf, stack
} }
func TestNodeInfo(t *testing.T) { func TestNodeInfo(t *testing.T) {
...@@ -151,11 +162,8 @@ func TestNodeInfo(t *testing.T) { ...@@ -151,11 +162,8 @@ func TestNodeInfo(t *testing.T) {
} }
func TestAccounts(t *testing.T) { func TestAccounts(t *testing.T) {
tmp, repl, ethereum := testJEthRE(t) tmp, repl, node := testJEthRE(t)
if err := ethereum.Start(); err != nil { defer node.Stop()
t.Fatalf("error starting ethereum: %v", err)
}
defer ethereum.Stop()
defer os.RemoveAll(tmp) defer os.RemoveAll(tmp)
checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`) checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`)
...@@ -174,11 +182,8 @@ func TestAccounts(t *testing.T) { ...@@ -174,11 +182,8 @@ func TestAccounts(t *testing.T) {
} }
func TestBlockChain(t *testing.T) { func TestBlockChain(t *testing.T) {
tmp, repl, ethereum := testJEthRE(t) tmp, repl, node := testJEthRE(t)
if err := ethereum.Start(); err != nil { defer node.Stop()
t.Fatalf("error starting ethereum: %v", err)
}
defer ethereum.Stop()
defer os.RemoveAll(tmp) defer os.RemoveAll(tmp)
// get current block dump before export/import. // get current block dump before export/import.
val, err := repl.re.Run("JSON.stringify(debug.dumpBlock(eth.blockNumber))") val, err := repl.re.Run("JSON.stringify(debug.dumpBlock(eth.blockNumber))")
...@@ -196,6 +201,8 @@ func TestBlockChain(t *testing.T) { ...@@ -196,6 +201,8 @@ func TestBlockChain(t *testing.T) {
tmpfile := filepath.Join(extmp, "export.chain") tmpfile := filepath.Join(extmp, "export.chain")
tmpfileq := strconv.Quote(tmpfile) tmpfileq := strconv.Quote(tmpfile)
var ethereum *eth.Ethereum
node.SingletonService(&ethereum)
ethereum.BlockChain().Reset() ethereum.BlockChain().Reset()
checkEvalJSON(t, repl, `admin.exportChain(`+tmpfileq+`)`, `true`) checkEvalJSON(t, repl, `admin.exportChain(`+tmpfileq+`)`, `true`)
...@@ -209,22 +216,15 @@ func TestBlockChain(t *testing.T) { ...@@ -209,22 +216,15 @@ func TestBlockChain(t *testing.T) {
} }
func TestMining(t *testing.T) { func TestMining(t *testing.T) {
tmp, repl, ethereum := testJEthRE(t) tmp, repl, node := testJEthRE(t)
if err := ethereum.Start(); err != nil { defer node.Stop()
t.Fatalf("error starting ethereum: %v", err)
}
defer ethereum.Stop()
defer os.RemoveAll(tmp) defer os.RemoveAll(tmp)
checkEvalJSON(t, repl, `eth.mining`, `false`) checkEvalJSON(t, repl, `eth.mining`, `false`)
} }
func TestRPC(t *testing.T) { func TestRPC(t *testing.T) {
tmp, repl, ethereum := testJEthRE(t) tmp, repl, node := testJEthRE(t)
if err := ethereum.Start(); err != nil { defer node.Stop()
t.Errorf("error starting ethereum: %v", err)
return
}
defer ethereum.Stop()
defer os.RemoveAll(tmp) defer os.RemoveAll(tmp)
checkEvalJSON(t, repl, `admin.startRPC("127.0.0.1", 5004, "*", "web3,eth,net")`, `true`) checkEvalJSON(t, repl, `admin.startRPC("127.0.0.1", 5004, "*", "web3,eth,net")`, `true`)
...@@ -234,12 +234,8 @@ func TestCheckTestAccountBalance(t *testing.T) { ...@@ -234,12 +234,8 @@ func TestCheckTestAccountBalance(t *testing.T) {
t.Skip() // i don't think it tests the correct behaviour here. it's actually testing t.Skip() // i don't think it tests the correct behaviour here. it's actually testing
// internals which shouldn't be tested. This now fails because of a change in the core // internals which shouldn't be tested. This now fails because of a change in the core
// and i have no means to fix this, sorry - @obscuren // and i have no means to fix this, sorry - @obscuren
tmp, repl, ethereum := testJEthRE(t) tmp, repl, node := testJEthRE(t)
if err := ethereum.Start(); err != nil { defer node.Stop()
t.Errorf("error starting ethereum: %v", err)
return
}
defer ethereum.Stop()
defer os.RemoveAll(tmp) defer os.RemoveAll(tmp)
repl.re.Run(`primary = "` + testAddress + `"`) repl.re.Run(`primary = "` + testAddress + `"`)
...@@ -247,12 +243,8 @@ func TestCheckTestAccountBalance(t *testing.T) { ...@@ -247,12 +243,8 @@ func TestCheckTestAccountBalance(t *testing.T) {
} }
func TestSignature(t *testing.T) { func TestSignature(t *testing.T) {
tmp, repl, ethereum := testJEthRE(t) tmp, repl, node := testJEthRE(t)
if err := ethereum.Start(); err != nil { defer node.Stop()
t.Errorf("error starting ethereum: %v", err)
return
}
defer ethereum.Stop()
defer os.RemoveAll(tmp) defer os.RemoveAll(tmp)
val, err := repl.re.Run(`eth.sign("` + testAddress + `", "` + testHash + `")`) val, err := repl.re.Run(`eth.sign("` + testAddress + `", "` + testHash + `")`)
...@@ -443,7 +435,10 @@ multiply7 = Multiply7.at(contractaddress); ...@@ -443,7 +435,10 @@ multiply7 = Multiply7.at(contractaddress);
} }
func pendingTransactions(repl *testjethre, t *testing.T) (txc int64, err error) { func pendingTransactions(repl *testjethre, t *testing.T) (txc int64, err error) {
txs := repl.ethereum.TxPool().GetTransactions() var ethereum *eth.Ethereum
repl.stack.SingletonService(&ethereum)
txs := ethereum.TxPool().GetTransactions()
return int64(len(txs)), nil return int64(len(txs)), nil
} }
...@@ -468,12 +463,15 @@ func processTxs(repl *testjethre, t *testing.T, expTxc int) bool { ...@@ -468,12 +463,15 @@ func processTxs(repl *testjethre, t *testing.T, expTxc int) bool {
t.Errorf("incorrect number of pending transactions, expected %v, got %v", expTxc, txc) t.Errorf("incorrect number of pending transactions, expected %v, got %v", expTxc, txc)
return false return false
} }
err = repl.ethereum.StartMining(runtime.NumCPU(), "") var ethereum *eth.Ethereum
repl.stack.SingletonService(&ethereum)
err = ethereum.StartMining(runtime.NumCPU(), "")
if err != nil { if err != nil {
t.Errorf("unexpected error mining: %v", err) t.Errorf("unexpected error mining: %v", err)
return false return false
} }
defer repl.ethereum.StopMining() defer ethereum.StopMining()
timer := time.NewTimer(100 * time.Second) timer := time.NewTimer(100 * time.Second)
height := new(big.Int).Add(repl.xeth.CurrentBlock().Number(), big.NewInt(1)) height := new(big.Int).Add(repl.xeth.CurrentBlock().Number(), big.NewInt(1))
......
This diff is collapsed.
...@@ -45,11 +45,6 @@ var ( ...@@ -45,11 +45,6 @@ var (
testKey = flag.String("key", defaultTestKey, "Private key of a test account to inject") testKey = flag.String("key", defaultTestKey, "Private key of a test account to inject")
) )
var (
ethereumServiceId = "ethereum"
whisperServiceId = "whisper"
)
func main() { func main() {
flag.Parse() flag.Parse()
...@@ -131,11 +126,11 @@ func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node ...@@ -131,11 +126,11 @@ func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node
TestGenesisBlock: test.Genesis, TestGenesisBlock: test.Genesis,
AccountManager: accman, AccountManager: accman,
} }
if err := stack.Register(ethereumServiceId, func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil { if err := stack.Register("ethereum", func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil {
return nil, err return nil, err
} }
// Initialize and register the Whisper protocol // Initialize and register the Whisper protocol
if err := stack.Register(whisperServiceId, func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil { if err := stack.Register("whisper", func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil {
return nil, err return nil, err
} }
return stack, nil return stack, nil
...@@ -144,7 +139,9 @@ func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node ...@@ -144,7 +139,9 @@ func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node
// RunTest executes the specified test against an already pre-configured protocol // RunTest executes the specified test against an already pre-configured protocol
// stack to ensure basic checks pass before running RPC tests. // stack to ensure basic checks pass before running RPC tests.
func RunTest(stack *node.Node, test *tests.BlockTest) error { func RunTest(stack *node.Node, test *tests.BlockTest) error {
blockchain := stack.Service(ethereumServiceId).(*eth.Ethereum).BlockChain() var ethereum *eth.Ethereum
stack.SingletonService(&ethereum)
blockchain := ethereum.BlockChain()
// Process the blocks and verify the imported headers // Process the blocks and verify the imported headers
blocks, err := test.TryBlocksInsert(blockchain) blocks, err := test.TryBlocksInsert(blockchain)
......
// 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 utils
import "github.com/ethereum/go-ethereum/p2p/discover"
// FrontierBootNodes are the enode URLs of the P2P bootstrap nodes running on
// the Frontier network.
var FrontierBootNodes = []*discover.Node{
// ETH/DEV Go Bootnodes
discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"), // IE
discover.MustParseNode("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"), // BR
discover.MustParseNode("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"), // SG
// ETH/DEV Cpp Bootnodes
discover.MustParseNode("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"),
}
// TestNetBootNodes are the enode URLs of the P2P bootstrap nodes running on the
// Morden test network.
var TestNetBootNodes = []*discover.Node{
// ETH/DEV Go Bootnodes
discover.MustParseNode("enode://e4533109cc9bd7604e4ff6c095f7a1d807e15b38e9bfeb05d3b7c423ba86af0a9e89abbf40bd9dde4250fef114cd09270fa4e224cbeef8b7bf05a51e8260d6b8@94.242.229.4:40404"),
discover.MustParseNode("enode://8c336ee6f03e99613ad21274f269479bf4413fb294d697ef15ab897598afb931f56beb8e97af530aee20ce2bcba5776f4a312bc168545de4d43736992c814592@94.242.229.203:30303"),
// ETH/DEV Cpp Bootnodes
}
...@@ -29,9 +29,9 @@ import ( ...@@ -29,9 +29,9 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/peterh/liner" "github.com/peterh/liner"
) )
...@@ -110,10 +110,9 @@ func Fatalf(format string, args ...interface{}) { ...@@ -110,10 +110,9 @@ func Fatalf(format string, args ...interface{}) {
os.Exit(1) os.Exit(1)
} }
func StartEthereum(ethereum *eth.Ethereum) { func StartNode(stack *node.Node) {
glog.V(logger.Info).Infoln("Starting", ethereum.Name()) if err := stack.Start(); err != nil {
if err := ethereum.Start(); err != nil { Fatalf("Error starting protocol stack: %v", err)
Fatalf("Error starting Ethereum: %v", err)
} }
go func() { go func() {
sigc := make(chan os.Signal, 1) sigc := make(chan os.Signal, 1)
...@@ -121,7 +120,7 @@ func StartEthereum(ethereum *eth.Ethereum) { ...@@ -121,7 +120,7 @@ func StartEthereum(ethereum *eth.Ethereum) {
defer signal.Stop(sigc) defer signal.Stop(sigc)
<-sigc <-sigc
glog.V(logger.Info).Infoln("Got interrupt, shutting down...") glog.V(logger.Info).Infoln("Got interrupt, shutting down...")
go ethereum.Stop() go stack.Stop()
logger.Flush() logger.Flush()
for i := 10; i > 0; i-- { for i := 10; i > 0; i-- {
<-sigc <-sigc
......
This diff is collapsed.
...@@ -34,6 +34,8 @@ import ( ...@@ -34,6 +34,8 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/node"
xe "github.com/ethereum/go-ethereum/xeth" xe "github.com/ethereum/go-ethereum/xeth"
) )
...@@ -146,13 +148,11 @@ func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) { ...@@ -146,13 +148,11 @@ func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
} }
// only use minimalistic stack with no networking // only use minimalistic stack with no networking
return eth.New(&eth.Config{ return eth.New(&node.ServiceContext{EventMux: new(event.TypeMux)}, &eth.Config{
DataDir: tmp,
AccountManager: am, AccountManager: am,
Etherbase: common.HexToAddress(testAddress), Etherbase: common.HexToAddress(testAddress),
MaxPeers: 0,
PowTest: true, PowTest: true,
NewDB: func(path string) (ethdb.Database, error) { return db, nil }, TestGenesisState: db,
GpoMinGasPrice: common.Big1, GpoMinGasPrice: common.Big1,
GpobaseCorrectionFactor: 1, GpobaseCorrectionFactor: 1,
GpoMaxGasPrice: common.Big1, GpoMaxGasPrice: common.Big1,
...@@ -166,7 +166,7 @@ func testInit(t *testing.T) (self *testFrontend) { ...@@ -166,7 +166,7 @@ func testInit(t *testing.T) (self *testFrontend) {
t.Errorf("error creating ethereum: %v", err) t.Errorf("error creating ethereum: %v", err)
return return
} }
err = ethereum.Start() err = ethereum.Start(nil)
if err != nil { if err != nil {
t.Errorf("error starting ethereum: %v", err) t.Errorf("error starting ethereum: %v", err)
return return
...@@ -174,7 +174,7 @@ func testInit(t *testing.T) (self *testFrontend) { ...@@ -174,7 +174,7 @@ func testInit(t *testing.T) (self *testFrontend) {
// mock frontend // mock frontend
self = &testFrontend{t: t, ethereum: ethereum} self = &testFrontend{t: t, ethereum: ethereum}
self.xeth = xe.New(ethereum, self) self.xeth = xe.New(nil, self)
self.wait = self.xeth.UpdateState() self.wait = self.xeth.UpdateState()
addr, _ := self.ethereum.Etherbase() addr, _ := self.ethereum.Etherbase()
......
...@@ -24,13 +24,13 @@ import ( ...@@ -24,13 +24,13 @@ import (
) )
const ( const (
hashLength = 32 HashLength = 32
addressLength = 20 AddressLength = 20
) )
type ( type (
Hash [hashLength]byte Hash [HashLength]byte
Address [addressLength]byte Address [AddressLength]byte
) )
func BytesToHash(b []byte) Hash { func BytesToHash(b []byte) Hash {
...@@ -53,10 +53,10 @@ func (h Hash) Hex() string { return "0x" + Bytes2Hex(h[:]) } ...@@ -53,10 +53,10 @@ func (h Hash) Hex() string { return "0x" + Bytes2Hex(h[:]) }
// Sets the hash to the value of b. If b is larger than len(h) it will panic // Sets the hash to the value of b. If b is larger than len(h) it will panic
func (h *Hash) SetBytes(b []byte) { func (h *Hash) SetBytes(b []byte) {
if len(b) > len(h) { if len(b) > len(h) {
b = b[len(b)-hashLength:] b = b[len(b)-HashLength:]
} }
copy(h[hashLength-len(b):], b) copy(h[HashLength-len(b):], b)
} }
// Set string `s` to h. If s is larger than len(h) it will panic // Set string `s` to h. If s is larger than len(h) it will panic
...@@ -92,6 +92,18 @@ func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) } ...@@ -92,6 +92,18 @@ func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) }
func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }
func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) } func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) }
// IsHexAddress verifies whether a string can represent a valid hex-encoded
// Ethereum address or not.
func IsHexAddress(s string) bool {
if len(s) == 2+2*AddressLength && IsHex(s[2:]) {
return true
}
if len(s) == 2*AddressLength && IsHex(s) {
return true
}
return false
}
// Get the string representation of the underlying address // Get the string representation of the underlying address
func (a Address) Str() string { return string(a[:]) } func (a Address) Str() string { return string(a[:]) }
func (a Address) Bytes() []byte { return a[:] } func (a Address) Bytes() []byte { return a[:] }
...@@ -102,9 +114,9 @@ func (a Address) Hex() string { return "0x" + Bytes2Hex(a[:]) } ...@@ -102,9 +114,9 @@ func (a Address) Hex() string { return "0x" + Bytes2Hex(a[:]) }
// Sets the address to the value of b. If b is larger than len(a) it will panic // Sets the address to the value of b. If b is larger than len(a) it will panic
func (a *Address) SetBytes(b []byte) { func (a *Address) SetBytes(b []byte) {
if len(b) > len(a) { if len(b) > len(a) {
b = b[len(b)-addressLength:] b = b[len(b)-AddressLength:]
} }
copy(a[addressLength-len(b):], b) copy(a[AddressLength-len(b):], b)
} }
// Set string `s` to a. If s is larger than len(a) it will panic // Set string `s` to a. If s is larger than len(a) it will panic
......
...@@ -34,7 +34,7 @@ func proc() (Validator, *BlockChain) { ...@@ -34,7 +34,7 @@ func proc() (Validator, *BlockChain) {
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
var mux event.TypeMux var mux event.TypeMux
WriteTestNetGenesisBlock(db, 0) WriteTestNetGenesisBlock(db)
blockchain, err := NewBlockChain(db, thePow(), &mux) blockchain, err := NewBlockChain(db, thePow(), &mux)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
......
...@@ -149,11 +149,7 @@ func NewBlockChain(chainDb ethdb.Database, pow pow.PoW, mux *event.TypeMux) (*Bl ...@@ -149,11 +149,7 @@ func NewBlockChain(chainDb ethdb.Database, pow pow.PoW, mux *event.TypeMux) (*Bl
bc.genesisBlock = bc.GetBlockByNumber(0) bc.genesisBlock = bc.GetBlockByNumber(0)
if bc.genesisBlock == nil { if bc.genesisBlock == nil {
reader, err := NewDefaultGenesisReader() bc.genesisBlock, err = WriteDefaultGenesisBlock(chainDb)
if err != nil {
return nil, err
}
bc.genesisBlock, err = WriteGenesisBlock(chainDb, reader)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -51,7 +51,7 @@ func thePow() pow.PoW { ...@@ -51,7 +51,7 @@ func thePow() pow.PoW {
func theBlockChain(db ethdb.Database, t *testing.T) *BlockChain { func theBlockChain(db ethdb.Database, t *testing.T) *BlockChain {
var eventMux event.TypeMux var eventMux event.TypeMux
WriteTestNetGenesisBlock(db, 0) WriteTestNetGenesisBlock(db)
blockchain, err := NewBlockChain(db, thePow(), &eventMux) blockchain, err := NewBlockChain(db, thePow(), &eventMux)
if err != nil { if err != nil {
t.Error("failed creating blockchain:", err) t.Error("failed creating blockchain:", err)
...@@ -506,7 +506,7 @@ func testReorgShort(t *testing.T, full bool) { ...@@ -506,7 +506,7 @@ func testReorgShort(t *testing.T, full bool) {
func testReorg(t *testing.T, first, second []int, td int64, full bool) { func testReorg(t *testing.T, first, second []int, td int64, full bool) {
// Create a pristine block chain // Create a pristine block chain
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
genesis, _ := WriteTestNetGenesisBlock(db, 0) genesis, _ := WriteTestNetGenesisBlock(db)
bc := chm(genesis, db) bc := chm(genesis, db)
// Insert an easy and a difficult chain afterwards // Insert an easy and a difficult chain afterwards
...@@ -553,7 +553,7 @@ func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) } ...@@ -553,7 +553,7 @@ func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) }
func testBadHashes(t *testing.T, full bool) { func testBadHashes(t *testing.T, full bool) {
// Create a pristine block chain // Create a pristine block chain
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
genesis, _ := WriteTestNetGenesisBlock(db, 0) genesis, _ := WriteTestNetGenesisBlock(db)
bc := chm(genesis, db) bc := chm(genesis, db)
// Create a chain, ban a hash and try to import // Create a chain, ban a hash and try to import
...@@ -580,7 +580,7 @@ func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) } ...@@ -580,7 +580,7 @@ func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) }
func testReorgBadHashes(t *testing.T, full bool) { func testReorgBadHashes(t *testing.T, full bool) {
// Create a pristine block chain // Create a pristine block chain
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
genesis, _ := WriteTestNetGenesisBlock(db, 0) genesis, _ := WriteTestNetGenesisBlock(db)
bc := chm(genesis, db) bc := chm(genesis, db)
// Create a chain, import and ban aferwards // Create a chain, import and ban aferwards
......
...@@ -220,7 +220,7 @@ func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) { ...@@ -220,7 +220,7 @@ func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) {
evmux := &event.TypeMux{} evmux := &event.TypeMux{}
// Initialize a fresh chain with only a genesis block // Initialize a fresh chain with only a genesis block
genesis, _ := WriteTestNetGenesisBlock(db, 0) genesis, _ := WriteTestNetGenesisBlock(db)
blockchain, _ := NewBlockChain(db, FakePow{}, evmux) blockchain, _ := NewBlockChain(db, FakePow{}, evmux)
// Create and inject the requested chain // Create and inject the requested chain
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
package core package core
import ( import (
"compress/gzip"
"encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
...@@ -158,46 +160,80 @@ func WriteGenesisBlockForTesting(db ethdb.Database, accounts ...GenesisAccount) ...@@ -158,46 +160,80 @@ func WriteGenesisBlockForTesting(db ethdb.Database, accounts ...GenesisAccount)
return block return block
} }
func WriteTestNetGenesisBlock(chainDb ethdb.Database, nonce uint64) (*types.Block, error) { // WriteDefaultGenesisBlock assembles the official Ethereum genesis block and
testGenesis := fmt.Sprintf(`{ // writes it - along with all associated state - into a chain database.
"nonce": "0x%x", func WriteDefaultGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
"difficulty": "0x20000", return WriteGenesisBlock(chainDb, strings.NewReader(DefaultGenesisBlock()))
"mixhash": "0x00000000000000000000000000000000000000647572616c65787365646c6578",
"coinbase": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x2FEFD8",
"alloc": {
"0000000000000000000000000000000000000001": { "balance": "1" },
"0000000000000000000000000000000000000002": { "balance": "1" },
"0000000000000000000000000000000000000003": { "balance": "1" },
"0000000000000000000000000000000000000004": { "balance": "1" },
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
}
}`, types.EncodeNonce(nonce))
return WriteGenesisBlock(chainDb, strings.NewReader(testGenesis))
} }
func WriteOlympicGenesisBlock(chainDb ethdb.Database, nonce uint64) (*types.Block, error) { // WriteTestNetGenesisBlock assembles the Morden test network genesis block and
testGenesis := fmt.Sprintf(`{ // writes it - along with all associated state - into a chain database.
"nonce":"0x%x", func WriteTestNetGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
"gasLimit":"0x%x", return WriteGenesisBlock(chainDb, strings.NewReader(TestNetGenesisBlock()))
"difficulty":"0x%x", }
"alloc": {
"0000000000000000000000000000000000000001": {"balance": "1"}, // WriteOlympicGenesisBlock assembles the Olympic genesis block and writes it
"0000000000000000000000000000000000000002": {"balance": "1"}, // along with all associated state into a chain database.
"0000000000000000000000000000000000000003": {"balance": "1"}, func WriteOlympicGenesisBlock(db ethdb.Database) (*types.Block, error) {
"0000000000000000000000000000000000000004": {"balance": "1"}, return WriteGenesisBlock(db, strings.NewReader(OlympicGenesisBlock()))
"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, }
"e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
"b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, // DefaultGenesisBlock assembles a JSON string representing the default Ethereum
"6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, // genesis block.
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, func DefaultGenesisBlock() string {
"2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, reader, err := gzip.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultGenesisBlock)))
"e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, if err != nil {
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"} panic(fmt.Sprintf("failed to access default genesis: %v", err))
}
blob, err := ioutil.ReadAll(reader)
if err != nil {
panic(fmt.Sprintf("failed to load default genesis: %v", err))
} }
}`, types.EncodeNonce(nonce), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes()) return string(blob)
return WriteGenesisBlock(chainDb, strings.NewReader(testGenesis)) }
// OlympicGenesisBlock assembles a JSON string representing the Olympic genesis
// block.
func OlympicGenesisBlock() string {
return fmt.Sprintf(`{
"nonce":"0x%x",
"gasLimit":"0x%x",
"difficulty":"0x%x",
"alloc": {
"0000000000000000000000000000000000000001": {"balance": "1"},
"0000000000000000000000000000000000000002": {"balance": "1"},
"0000000000000000000000000000000000000003": {"balance": "1"},
"0000000000000000000000000000000000000004": {"balance": "1"},
"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
"e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
"b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
"6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
"2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
"e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}
}
}`, types.EncodeNonce(42), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes())
}
// TestNetGenesisBlock assembles a JSON string representing the Morden test net
// genenis block.
func TestNetGenesisBlock() string {
return fmt.Sprintf(`{
"nonce": "0x%x",
"difficulty": "0x20000",
"mixhash": "0x00000000000000000000000000000000000000647572616c65787365646c6578",
"coinbase": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x2FEFD8",
"alloc": {
"0000000000000000000000000000000000000001": { "balance": "1" },
"0000000000000000000000000000000000000002": { "balance": "1" },
"0000000000000000000000000000000000000003": { "balance": "1" },
"0000000000000000000000000000000000000004": { "balance": "1" },
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
}
}`, types.EncodeNonce(0x6d6f7264656e))
} }
This diff is collapsed.
...@@ -21,6 +21,7 @@ import ( ...@@ -21,6 +21,7 @@ import (
"errors" "errors"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"sync" "sync"
"syscall" "syscall"
...@@ -40,14 +41,17 @@ var ( ...@@ -40,14 +41,17 @@ var (
// Node represents a P2P node into which arbitrary services might be registered. // Node represents a P2P node into which arbitrary services might be registered.
type Node struct { type Node struct {
datadir string // Path to the currently used data directory datadir string // Path to the currently used data directory
config *p2p.Server // Configuration of the underlying P2P networking layer eventmux *event.TypeMux // Event multiplexer used between the services of a stack
stack map[string]ServiceConstructor // Protocol stack registered into this node
emux *event.TypeMux // Event multiplexer used between the services of a stack
running *p2p.Server // Currently running P2P networking layer serverConfig *p2p.Server // Configuration of the underlying P2P networking layer
services map[string]Service // Currently running services server *p2p.Server // Currently running P2P networking layer
serviceIndex map[string]ServiceConstructor // Set of services currently registered in the node
serviceOrder []string // Service construction order to handle dependencies
services map[string]Service // Currently running services
stop chan struct{} // Channel to wait for termination notifications
lock sync.RWMutex lock sync.RWMutex
} }
...@@ -66,7 +70,7 @@ func New(conf *Config) (*Node, error) { ...@@ -66,7 +70,7 @@ func New(conf *Config) (*Node, error) {
} }
return &Node{ return &Node{
datadir: conf.DataDir, datadir: conf.DataDir,
config: &p2p.Server{ serverConfig: &p2p.Server{
PrivateKey: conf.NodeKey(), PrivateKey: conf.NodeKey(),
Name: conf.Name, Name: conf.Name,
Discovery: !conf.NoDiscovery, Discovery: !conf.NoDiscovery,
...@@ -81,8 +85,9 @@ func New(conf *Config) (*Node, error) { ...@@ -81,8 +85,9 @@ func New(conf *Config) (*Node, error) {
MaxPeers: conf.MaxPeers, MaxPeers: conf.MaxPeers,
MaxPendingPeers: conf.MaxPendingPeers, MaxPendingPeers: conf.MaxPendingPeers,
}, },
stack: make(map[string]ServiceConstructor), serviceIndex: make(map[string]ServiceConstructor),
emux: new(event.TypeMux), serviceOrder: []string{},
eventmux: new(event.TypeMux),
}, nil }, nil
} }
...@@ -92,14 +97,15 @@ func (n *Node) Register(id string, constructor ServiceConstructor) error { ...@@ -92,14 +97,15 @@ func (n *Node) Register(id string, constructor ServiceConstructor) error {
defer n.lock.Unlock() defer n.lock.Unlock()
// Short circuit if the node is running or if the id is taken // Short circuit if the node is running or if the id is taken
if n.running != nil { if n.server != nil {
return ErrNodeRunning return ErrNodeRunning
} }
if _, ok := n.stack[id]; ok { if _, ok := n.serviceIndex[id]; ok {
return ErrServiceRegistered return ErrServiceRegistered
} }
// Otherwise register the service and return // Otherwise register the service and return
n.stack[id] = constructor n.serviceOrder = append(n.serviceOrder, id)
n.serviceIndex[id] = constructor
return nil return nil
} }
...@@ -111,14 +117,20 @@ func (n *Node) Unregister(id string) error { ...@@ -111,14 +117,20 @@ func (n *Node) Unregister(id string) error {
defer n.lock.Unlock() defer n.lock.Unlock()
// Short circuit if the node is running, or if the service is unknown // Short circuit if the node is running, or if the service is unknown
if n.running != nil { if n.server != nil {
return ErrNodeRunning return ErrNodeRunning
} }
if _, ok := n.stack[id]; !ok { if _, ok := n.serviceIndex[id]; !ok {
return ErrServiceUnknown return ErrServiceUnknown
} }
// Otherwise drop the service and return // Otherwise drop the service and return
delete(n.stack, id) delete(n.serviceIndex, id)
for i, service := range n.serviceOrder {
if service == id {
n.serviceOrder = append(n.serviceOrder[:i], n.serviceOrder[i+1:]...)
break
}
}
return nil return nil
} }
...@@ -128,19 +140,27 @@ func (n *Node) Start() error { ...@@ -128,19 +140,27 @@ func (n *Node) Start() error {
defer n.lock.Unlock() defer n.lock.Unlock()
// Short circuit if the node's already running // Short circuit if the node's already running
if n.running != nil { if n.server != nil {
return ErrNodeRunning return ErrNodeRunning
} }
// Otherwise copy and specialize the P2P configuration // Otherwise copy and specialize the P2P configuration
running := new(p2p.Server) running := new(p2p.Server)
*running = *n.config *running = *n.serverConfig
ctx := &ServiceContext{
dataDir: n.datadir,
EventMux: n.emux,
}
services := make(map[string]Service) services := make(map[string]Service)
for id, constructor := range n.stack { for _, id := range n.serviceOrder {
constructor := n.serviceIndex[id]
// Create a new context for the particular service
ctx := &ServiceContext{
datadir: n.datadir,
services: make(map[string]Service),
EventMux: n.eventmux,
}
for id, s := range services { // copy needed for threaded access
ctx.services[id] = s
}
// Construct and save the service
service, err := constructor(ctx) service, err := constructor(ctx)
if err != nil { if err != nil {
return err return err
...@@ -161,10 +181,12 @@ func (n *Node) Start() error { ...@@ -161,10 +181,12 @@ func (n *Node) Start() error {
started := []string{} started := []string{}
for id, service := range services { for id, service := range services {
// Start the next service, stopping all previous upon failure // Start the next service, stopping all previous upon failure
if err := service.Start(); err != nil { if err := service.Start(running); err != nil {
for _, id := range started { for _, id := range started {
services[id].Stop() services[id].Stop()
} }
running.Stop()
return err return err
} }
// Mark the service started for potential cleanup // Mark the service started for potential cleanup
...@@ -172,7 +194,8 @@ func (n *Node) Start() error { ...@@ -172,7 +194,8 @@ func (n *Node) Start() error {
} }
// Finish initializing the startup // Finish initializing the startup
n.services = services n.services = services
n.running = running n.server = running
n.stop = make(chan struct{})
return nil return nil
} }
...@@ -184,7 +207,7 @@ func (n *Node) Stop() error { ...@@ -184,7 +207,7 @@ func (n *Node) Stop() error {
defer n.lock.Unlock() defer n.lock.Unlock()
// Short circuit if the node's not running // Short circuit if the node's not running
if n.running == nil { if n.server == nil {
return ErrNodeStopped return ErrNodeStopped
} }
// Otherwise terminate all the services and the P2P server too // Otherwise terminate all the services and the P2P server too
...@@ -196,10 +219,11 @@ func (n *Node) Stop() error { ...@@ -196,10 +219,11 @@ func (n *Node) Stop() error {
failure.Services[id] = err failure.Services[id] = err
} }
} }
n.running.Stop() n.server.Stop()
n.services = nil n.services = nil
n.running = nil n.server = nil
close(n.stop)
if len(failure.Services) > 0 { if len(failure.Services) > 0 {
return failure return failure
...@@ -207,6 +231,19 @@ func (n *Node) Stop() error { ...@@ -207,6 +231,19 @@ func (n *Node) Stop() error {
return nil return nil
} }
// Wait blocks the thread until the node is stopped. If the node is not running
// at the time of invocation, the method immediately returns.
func (n *Node) Wait() {
n.lock.RLock()
if n.server == nil {
return
}
stop := n.stop
n.lock.RUnlock()
<-stop
}
// Restart terminates a running node and boots up a new one in its place. If the // Restart terminates a running node and boots up a new one in its place. If the
// node isn't running, an error is returned. // node isn't running, an error is returned.
func (n *Node) Restart() error { func (n *Node) Restart() error {
...@@ -226,20 +263,45 @@ func (n *Node) Server() *p2p.Server { ...@@ -226,20 +263,45 @@ func (n *Node) Server() *p2p.Server {
n.lock.RLock() n.lock.RLock()
defer n.lock.RUnlock() defer n.lock.RUnlock()
return n.running return n.server
} }
// Service retrieves a currently running services registered under a given id. // Service retrieves a currently running service registered under a given id.
func (n *Node) Service(id string) Service { func (n *Node) Service(id string) Service {
n.lock.RLock() n.lock.RLock()
defer n.lock.RUnlock() defer n.lock.RUnlock()
if n.services == nil { // Short circuit if the node's not running
if n.server == nil {
return nil return nil
} }
return n.services[id] return n.services[id]
} }
// SingletonService retrieves a currently running service using a specific type
// implementing the Service interface. This is a utility function for scenarios
// where it is known that only one instance of a given service type is running,
// allowing to access services without needing to know their specific id with
// which they were registered. Note, this method uses reflection, so do not run
// in a tight loop.
func (n *Node) SingletonService(service interface{}) (string, error) {
n.lock.RLock()
defer n.lock.RUnlock()
// Short circuit if the node's not running
if n.server == nil {
return "", ErrServiceUnknown
}
// Otherwise try to find the service to return
for id, running := range n.services {
if reflect.TypeOf(running) == reflect.ValueOf(service).Elem().Type() {
reflect.ValueOf(service).Elem().Set(reflect.ValueOf(running))
return id, nil
}
}
return "", ErrServiceUnknown
}
// DataDir retrieves the current datadir used by the protocol stack. // DataDir retrieves the current datadir used by the protocol stack.
func (n *Node) DataDir() string { func (n *Node) DataDir() string {
return n.datadir return n.datadir
...@@ -248,5 +310,5 @@ func (n *Node) DataDir() string { ...@@ -248,5 +310,5 @@ func (n *Node) DataDir() string {
// EventMux retrieves the event multiplexer used by all the network services in // EventMux retrieves the event multiplexer used by all the network services in
// the current protocol stack. // the current protocol stack.
func (n *Node) EventMux() *event.TypeMux { func (n *Node) EventMux() *event.TypeMux {
return n.emux return n.eventmux
} }
...@@ -35,8 +35,8 @@ import ( ...@@ -35,8 +35,8 @@ import (
type SampleService struct{} type SampleService struct{}
func (s *SampleService) Protocols() []p2p.Protocol { return nil } func (s *SampleService) Protocols() []p2p.Protocol { return nil }
func (s *SampleService) Start() error { fmt.Println("Sample service starting..."); return nil } func (s *SampleService) Start(*p2p.Server) error { fmt.Println("Service starting..."); return nil }
func (s *SampleService) Stop() error { fmt.Println("Sample service stopping..."); return nil } func (s *SampleService) Stop() error { fmt.Println("Service stopping..."); return nil }
func ExampleUsage() { func ExampleUsage() {
// Create a network node to run protocols with the default values. The below list // Create a network node to run protocols with the default values. The below list
...@@ -80,8 +80,8 @@ func ExampleUsage() { ...@@ -80,8 +80,8 @@ func ExampleUsage() {
log.Fatalf("Failed to stop the protocol stack: %v", err) log.Fatalf("Failed to stop the protocol stack: %v", err)
} }
// Output: // Output:
// Sample service starting... // Service starting...
// Sample service stopping... // Service stopping...
// Sample service starting... // Service starting...
// Sample service stopping... // Service stopping...
} }
...@@ -102,7 +102,7 @@ func TestNodeUsedDataDir(t *testing.T) { ...@@ -102,7 +102,7 @@ func TestNodeUsedDataDir(t *testing.T) {
type NoopService struct{} type NoopService struct{}
func (s *NoopService) Protocols() []p2p.Protocol { return nil } func (s *NoopService) Protocols() []p2p.Protocol { return nil }
func (s *NoopService) Start() error { return nil } func (s *NoopService) Start(*p2p.Server) error { return nil }
func (s *NoopService) Stop() error { return nil } func (s *NoopService) Stop() error { return nil }
func NewNoopService(*ServiceContext) (Service, error) { return new(NoopService), nil } func NewNoopService(*ServiceContext) (Service, error) { return new(NoopService), nil }
...@@ -148,7 +148,7 @@ type InstrumentedService struct { ...@@ -148,7 +148,7 @@ type InstrumentedService struct {
stop error stop error
protocolsHook func() protocolsHook func()
startHook func() startHook func(*p2p.Server)
stopHook func() stopHook func()
} }
...@@ -159,9 +159,9 @@ func (s *InstrumentedService) Protocols() []p2p.Protocol { ...@@ -159,9 +159,9 @@ func (s *InstrumentedService) Protocols() []p2p.Protocol {
return s.protocols return s.protocols
} }
func (s *InstrumentedService) Start() error { func (s *InstrumentedService) Start(server *p2p.Server) error {
if s.startHook != nil { if s.startHook != nil {
s.startHook() s.startHook(server)
} }
return s.start return s.start
} }
...@@ -189,7 +189,7 @@ func TestServiceLifeCycle(t *testing.T) { ...@@ -189,7 +189,7 @@ func TestServiceLifeCycle(t *testing.T) {
id := id // Closure for the constructor id := id // Closure for the constructor
constructor := func(*ServiceContext) (Service, error) { constructor := func(*ServiceContext) (Service, error) {
return &InstrumentedService{ return &InstrumentedService{
startHook: func() { started[id] = true }, startHook: func(*p2p.Server) { started[id] = true },
stopHook: func() { stopped[id] = true }, stopHook: func() { stopped[id] = true },
}, nil }, nil
} }
...@@ -241,7 +241,7 @@ func TestServiceRestarts(t *testing.T) { ...@@ -241,7 +241,7 @@ func TestServiceRestarts(t *testing.T) {
running = false running = false
return &InstrumentedService{ return &InstrumentedService{
startHook: func() { startHook: func(*p2p.Server) {
if running { if running {
panic("already running") panic("already running")
} }
...@@ -288,7 +288,7 @@ func TestServiceConstructionAbortion(t *testing.T) { ...@@ -288,7 +288,7 @@ func TestServiceConstructionAbortion(t *testing.T) {
id := id // Closure for the constructor id := id // Closure for the constructor
constructor := func(*ServiceContext) (Service, error) { constructor := func(*ServiceContext) (Service, error) {
return &InstrumentedService{ return &InstrumentedService{
startHook: func() { started[id] = true }, startHook: func(*p2p.Server) { started[id] = true },
}, nil }, nil
} }
if err := stack.Register(id, constructor); err != nil { if err := stack.Register(id, constructor); err != nil {
...@@ -334,7 +334,7 @@ func TestServiceStartupAbortion(t *testing.T) { ...@@ -334,7 +334,7 @@ func TestServiceStartupAbortion(t *testing.T) {
id := id // Closure for the constructor id := id // Closure for the constructor
constructor := func(*ServiceContext) (Service, error) { constructor := func(*ServiceContext) (Service, error) {
return &InstrumentedService{ return &InstrumentedService{
startHook: func() { started[id] = true }, startHook: func(*p2p.Server) { started[id] = true },
stopHook: func() { stopped[id] = true }, stopHook: func() { stopped[id] = true },
}, nil }, nil
} }
...@@ -384,7 +384,7 @@ func TestServiceTerminationGuarantee(t *testing.T) { ...@@ -384,7 +384,7 @@ func TestServiceTerminationGuarantee(t *testing.T) {
id := id // Closure for the constructor id := id // Closure for the constructor
constructor := func(*ServiceContext) (Service, error) { constructor := func(*ServiceContext) (Service, error) {
return &InstrumentedService{ return &InstrumentedService{
startHook: func() { started[id] = true }, startHook: func(*p2p.Server) { started[id] = true },
stopHook: func() { stopped[id] = true }, stopHook: func() { stopped[id] = true },
}, nil }, nil
} }
...@@ -438,6 +438,42 @@ func TestServiceTerminationGuarantee(t *testing.T) { ...@@ -438,6 +438,42 @@ func TestServiceTerminationGuarantee(t *testing.T) {
} }
} }
// TestSingletonServiceRetrieval tests that singleton services can be retrieved.
func TestSingletonServiceRetrieval(t *testing.T) {
// Create a simple stack and register two service types
stack, err := New(testNodeConfig)
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
if err := stack.Register("noop", func(*ServiceContext) (Service, error) { return new(NoopService), nil }); err != nil {
t.Fatalf("noop service registration failed: %v", err)
}
if err := stack.Register("instrumented", func(*ServiceContext) (Service, error) { return new(InstrumentedService), nil }); err != nil {
t.Fatalf("instrumented service registration failed: %v", err)
}
// Make sure none of the services can be retrieved until started
var noopServ *NoopService
if id, err := stack.SingletonService(&noopServ); id != "" || err != ErrServiceUnknown {
t.Fatalf("noop service retrieval mismatch: have %v/%v, want %v/%v", id, err, "", ErrServiceUnknown)
}
var instServ *InstrumentedService
if id, err := stack.SingletonService(&instServ); id != "" || err != ErrServiceUnknown {
t.Fatalf("instrumented service retrieval mismatch: have %v/%v, want %v/%v", id, err, "", ErrServiceUnknown)
}
// Start the stack and ensure everything is retrievable now
if err := stack.Start(); err != nil {
t.Fatalf("failed to start stack: %v", err)
}
defer stack.Stop()
if id, err := stack.SingletonService(&noopServ); id != "noop" || err != nil {
t.Fatalf("noop service retrieval mismatch: have %v/%v, want %v/%v", id, err, "noop", nil)
}
if id, err := stack.SingletonService(&instServ); id != "instrumented" || err != nil {
t.Fatalf("instrumented service retrieval mismatch: have %v/%v, want %v/%v", id, err, "instrumented", nil)
}
}
// Tests that all protocols defined by individual services get launched. // Tests that all protocols defined by individual services get launched.
func TestProtocolGather(t *testing.T) { func TestProtocolGather(t *testing.T) {
stack, err := New(testNodeConfig) stack, err := New(testNodeConfig)
......
...@@ -18,6 +18,7 @@ package node ...@@ -18,6 +18,7 @@ package node
import ( import (
"path/filepath" "path/filepath"
"reflect"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
...@@ -28,18 +29,39 @@ import ( ...@@ -28,18 +29,39 @@ import (
// the protocol stack, that is passed to all constructors to be optionally used; // the protocol stack, that is passed to all constructors to be optionally used;
// as well as utility methods to operate on the service environment. // as well as utility methods to operate on the service environment.
type ServiceContext struct { type ServiceContext struct {
dataDir string // Data directory for protocol persistence datadir string // Data directory for protocol persistence
EventMux *event.TypeMux // Event multiplexer used for decoupled notifications services map[string]Service // Index of the already constructed services
EventMux *event.TypeMux // Event multiplexer used for decoupled notifications
} }
// Database opens an existing database with the given name (or creates one if no // Database opens an existing database with the given name (or creates one if no
// previous can be found) from within the node's data directory. If the node is // previous can be found) from within the node's data directory. If the node is
// an ephemeral one, a memory database is returned. // an ephemeral one, a memory database is returned.
func (ctx *ServiceContext) Database(name string, cache int) (ethdb.Database, error) { func (ctx *ServiceContext) Database(name string, cache int) (ethdb.Database, error) {
if ctx.dataDir == "" { if ctx.datadir == "" {
return ethdb.NewMemDatabase() return ethdb.NewMemDatabase()
} }
return ethdb.NewLDBDatabase(filepath.Join(ctx.dataDir, name), cache) return ethdb.NewLDBDatabase(filepath.Join(ctx.datadir, name), cache)
}
// Service retrieves an already constructed service registered under a given id.
func (ctx *ServiceContext) Service(id string) Service {
return ctx.services[id]
}
// SingletonService retrieves an already constructed service using a specific type
// implementing the Service interface. This is a utility function for scenarios
// where it is known that only one instance of a given service type is running,
// allowing to access services without needing to know their specific id with
// which they were registered.
func (ctx *ServiceContext) SingletonService(service interface{}) (string, error) {
for id, running := range ctx.services {
if reflect.TypeOf(running) == reflect.ValueOf(service).Elem().Type() {
reflect.ValueOf(service).Elem().Set(reflect.ValueOf(running))
return id, nil
}
}
return "", ErrServiceUnknown
} }
// ServiceConstructor is the function signature of the constructors needed to be // ServiceConstructor is the function signature of the constructors needed to be
...@@ -58,8 +80,9 @@ type Service interface { ...@@ -58,8 +80,9 @@ type Service interface {
// Protocol retrieves the P2P protocols the service wishes to start. // Protocol retrieves the P2P protocols the service wishes to start.
Protocols() []p2p.Protocol Protocols() []p2p.Protocol
// Start spawns any goroutines required by the service. // Start is called after all services have been constructed and the networking
Start() error // layer was also initialized to spawn any goroutines required by the service.
Start(server *p2p.Server) error
// Stop terminates all goroutines belonging to the service, blocking until they // Stop terminates all goroutines belonging to the service, blocking until they
// are all terminated. // are all terminated.
......
...@@ -17,14 +17,16 @@ ...@@ -17,14 +17,16 @@
package node package node
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
) )
// Tests that service context methods work properly. // Tests that databases are correctly created persistent or ephemeral based on
func TestServiceContext(t *testing.T) { // the configured service context.
func TestContextDatabases(t *testing.T) {
// Create a temporary folder and ensure no database is contained within // Create a temporary folder and ensure no database is contained within
dir, err := ioutil.TempDir("", "") dir, err := ioutil.TempDir("", "")
if err != nil { if err != nil {
...@@ -36,7 +38,7 @@ func TestServiceContext(t *testing.T) { ...@@ -36,7 +38,7 @@ func TestServiceContext(t *testing.T) {
t.Fatalf("non-created database already exists") t.Fatalf("non-created database already exists")
} }
// Request the opening/creation of a database and ensure it persists to disk // Request the opening/creation of a database and ensure it persists to disk
ctx := &ServiceContext{dataDir: dir} ctx := &ServiceContext{datadir: dir}
db, err := ctx.Database("persistent", 0) db, err := ctx.Database("persistent", 0)
if err != nil { if err != nil {
t.Fatalf("failed to open persistent database: %v", err) t.Fatalf("failed to open persistent database: %v", err)
...@@ -47,7 +49,7 @@ func TestServiceContext(t *testing.T) { ...@@ -47,7 +49,7 @@ func TestServiceContext(t *testing.T) {
t.Fatalf("persistent database doesn't exists: %v", err) t.Fatalf("persistent database doesn't exists: %v", err)
} }
// Request th opening/creation of an ephemeral database and ensure it's not persisted // Request th opening/creation of an ephemeral database and ensure it's not persisted
ctx = &ServiceContext{dataDir: ""} ctx = &ServiceContext{datadir: ""}
db, err = ctx.Database("ephemeral", 0) db, err = ctx.Database("ephemeral", 0)
if err != nil { if err != nil {
t.Fatalf("failed to open ephemeral database: %v", err) t.Fatalf("failed to open ephemeral database: %v", err)
...@@ -58,3 +60,47 @@ func TestServiceContext(t *testing.T) { ...@@ -58,3 +60,47 @@ func TestServiceContext(t *testing.T) {
t.Fatalf("ephemeral database exists") t.Fatalf("ephemeral database exists")
} }
} }
// Tests that already constructed services can be retrieves by later ones.
func TestContextServices(t *testing.T) {
stack, err := New(testNodeConfig)
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
// Define a set of services, constructed before/after a verifier
formers := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"}
latters := []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}
verifier := func(ctx *ServiceContext) (Service, error) {
for i, id := range formers {
if ctx.Service(id) == nil {
return nil, fmt.Errorf("former %d: service not found", i)
}
}
for i, id := range latters {
if ctx.Service(id) != nil {
return nil, fmt.Errorf("latters %d: service found", i)
}
}
return new(NoopService), nil
}
// Register the collection of services
for i, id := range formers {
if err := stack.Register(id, NewNoopService); err != nil {
t.Fatalf("former #%d: failed to register service: %v", i, err)
}
}
if err := stack.Register("verifier", verifier); err != nil {
t.Fatalf("failed to register service verifier: %v", err)
}
for i, id := range latters {
if err := stack.Register(id, NewNoopService); err != nil {
t.Fatalf("latter #%d: failed to register service: %v", i, err)
}
}
// Start the protocol stack and ensure services are constructed in order
if err := stack.Start(); err != nil {
t.Fatalf("failed to start stack: %v", err)
}
defer stack.Stop()
}
...@@ -32,6 +32,8 @@ import ( ...@@ -32,6 +32,8 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/comms" "github.com/ethereum/go-ethereum/rpc/comms"
...@@ -80,19 +82,24 @@ type adminhandler func(*adminApi, *shared.Request) (interface{}, error) ...@@ -80,19 +82,24 @@ type adminhandler func(*adminApi, *shared.Request) (interface{}, error)
// admin api provider // admin api provider
type adminApi struct { type adminApi struct {
xeth *xeth.XEth xeth *xeth.XEth
stack *node.Node
ethereum *eth.Ethereum ethereum *eth.Ethereum
codec codec.Codec codec codec.Codec
coder codec.ApiCoder coder codec.ApiCoder
} }
// create a new admin api instance // create a new admin api instance
func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, codec codec.Codec) *adminApi { func NewAdminApi(xeth *xeth.XEth, stack *node.Node, codec codec.Codec) *adminApi {
return &adminApi{ api := &adminApi{
xeth: xeth, xeth: xeth,
ethereum: ethereum, stack: stack,
codec: codec, codec: codec,
coder: codec.New(nil), coder: codec.New(nil),
} }
if stack != nil {
stack.SingletonService(&api.ethereum)
}
return api
} }
// collection with supported methods // collection with supported methods
...@@ -128,24 +135,24 @@ func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) { ...@@ -128,24 +135,24 @@ func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) {
if err := self.coder.Decode(req.Params, &args); err != nil { if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error()) return nil, shared.NewDecodeParamError(err.Error())
} }
node, err := discover.ParseNode(args.Url)
err := self.ethereum.AddPeer(args.Url) if err != nil {
if err == nil { return nil, fmt.Errorf("invalid node URL: %v", err)
return true, nil
} }
return false, err self.stack.Server().AddPeer(node)
return true, nil
} }
func (self *adminApi) Peers(req *shared.Request) (interface{}, error) { func (self *adminApi) Peers(req *shared.Request) (interface{}, error) {
return self.ethereum.Network().PeersInfo(), nil return self.stack.Server().PeersInfo(), nil
} }
func (self *adminApi) NodeInfo(req *shared.Request) (interface{}, error) { func (self *adminApi) NodeInfo(req *shared.Request) (interface{}, error) {
return self.ethereum.Network().NodeInfo(), nil return self.stack.Server().NodeInfo(), nil
} }
func (self *adminApi) DataDir(req *shared.Request) (interface{}, error) { func (self *adminApi) DataDir(req *shared.Request) (interface{}, error) {
return self.ethereum.DataDir, nil return self.stack.DataDir(), nil
} }
func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool {
...@@ -253,7 +260,7 @@ func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) { ...@@ -253,7 +260,7 @@ func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) {
CorsDomain: args.CorsDomain, CorsDomain: args.CorsDomain,
} }
apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.ethereum) apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.stack)
if err != nil { if err != nil {
return false, err return false, err
} }
......
...@@ -93,7 +93,7 @@ func TestCompileSolidity(t *testing.T) { ...@@ -93,7 +93,7 @@ func TestCompileSolidity(t *testing.T) {
expSource := source expSource := source
eth := &eth.Ethereum{} eth := &eth.Ethereum{}
xeth := xeth.NewTest(eth, nil) xeth := xeth.NewTest(nil, nil)
api := NewEthApi(xeth, eth, codec.JSON) api := NewEthApi(xeth, eth, codec.JSON)
var rpcRequest shared.Request var rpcRequest shared.Request
......
...@@ -22,6 +22,7 @@ import ( ...@@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/rpc/shared"
"github.com/ethereum/go-ethereum/xeth" "github.com/ethereum/go-ethereum/xeth"
...@@ -154,7 +155,7 @@ var ( ...@@ -154,7 +155,7 @@ var (
) )
// Parse a comma separated API string to individual api's // Parse a comma separated API string to individual api's
func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.Ethereum) ([]shared.EthereumApi, error) { func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, stack *node.Node) ([]shared.EthereumApi, error) {
if len(strings.TrimSpace(apistr)) == 0 { if len(strings.TrimSpace(apistr)) == 0 {
return nil, fmt.Errorf("Empty apistr provided") return nil, fmt.Errorf("Empty apistr provided")
} }
...@@ -162,10 +163,16 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth. ...@@ -162,10 +163,16 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.
names := strings.Split(apistr, ",") names := strings.Split(apistr, ",")
apis := make([]shared.EthereumApi, len(names)) apis := make([]shared.EthereumApi, len(names))
var eth *eth.Ethereum
if stack != nil {
if _, err := stack.SingletonService(&eth); err != nil {
return nil, err
}
}
for i, name := range names { for i, name := range names {
switch strings.ToLower(strings.TrimSpace(name)) { switch strings.ToLower(strings.TrimSpace(name)) {
case shared.AdminApiName: case shared.AdminApiName:
apis[i] = NewAdminApi(xeth, eth, codec) apis[i] = NewAdminApi(xeth, stack, codec)
case shared.DebugApiName: case shared.DebugApiName:
apis[i] = NewDebugApi(xeth, eth, codec) apis[i] = NewDebugApi(xeth, eth, codec)
case shared.DbApiName: case shared.DbApiName:
...@@ -188,7 +195,6 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth. ...@@ -188,7 +195,6 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.
return nil, fmt.Errorf("Unknown API '%s'", name) return nil, fmt.Errorf("Unknown API '%s'", name)
} }
} }
return apis, nil return apis, nil
} }
......
...@@ -36,7 +36,9 @@ import ( ...@@ -36,7 +36,9 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
...@@ -165,15 +167,6 @@ func runBlockTest(test *BlockTest) error { ...@@ -165,15 +167,6 @@ func runBlockTest(test *BlockTest) error {
ks := crypto.NewKeyStorePassphrase(filepath.Join(common.DefaultDataDir(), "keystore"), crypto.StandardScryptN, crypto.StandardScryptP) ks := crypto.NewKeyStorePassphrase(filepath.Join(common.DefaultDataDir(), "keystore"), crypto.StandardScryptN, crypto.StandardScryptP)
am := accounts.NewManager(ks) am := accounts.NewManager(ks)
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
cfg := &eth.Config{
DataDir: common.DefaultDataDir(),
Verbosity: 5,
Etherbase: common.Address{},
AccountManager: am,
NewDB: func(path string) (ethdb.Database, error) { return db, nil },
}
cfg.GenesisBlock = test.Genesis
// import pre accounts & construct test genesis block & state root // import pre accounts & construct test genesis block & state root
_, err := test.InsertPreState(db, am) _, err := test.InsertPreState(db, am)
...@@ -181,16 +174,16 @@ func runBlockTest(test *BlockTest) error { ...@@ -181,16 +174,16 @@ func runBlockTest(test *BlockTest) error {
return fmt.Errorf("InsertPreState: %v", err) return fmt.Errorf("InsertPreState: %v", err)
} }
ethereum, err := eth.New(cfg) cfg := &eth.Config{
if err != nil { TestGenesisState: db,
return err TestGenesisBlock: test.Genesis,
Etherbase: common.Address{},
AccountManager: am,
} }
ethereum, err := eth.New(&node.ServiceContext{EventMux: new(event.TypeMux)}, cfg)
err = ethereum.Start()
if err != nil { if err != nil {
return err return err
} }
cm := ethereum.BlockChain() cm := ethereum.BlockChain()
validBlocks, err := test.TryBlocksInsert(cm) validBlocks, err := test.TryBlocksInsert(cm)
if err != nil { if err != nil {
......
...@@ -37,7 +37,7 @@ func startTestPeer() *testPeer { ...@@ -37,7 +37,7 @@ func startTestPeer() *testPeer {
// Create a whisper client and connect with it to the tester peer // Create a whisper client and connect with it to the tester peer
client := New() client := New()
client.Start() client.Start(nil)
termed := make(chan struct{}) termed := make(chan struct{})
go func() { go func() {
......
...@@ -98,9 +98,9 @@ func New() *Whisper { ...@@ -98,9 +98,9 @@ func New() *Whisper {
return whisper return whisper
} }
// Protocol returns the whisper sub-protocol handler for this particular client. // Protocols returns the whisper sub-protocols ran by this particular client.
func (self *Whisper) Protocol() p2p.Protocol { func (self *Whisper) Protocols() []p2p.Protocol {
return self.protocol return []p2p.Protocol{self.protocol}
} }
// Version returns the whisper sub-protocols version number. // Version returns the whisper sub-protocols version number.
...@@ -156,14 +156,20 @@ func (self *Whisper) Send(envelope *Envelope) error { ...@@ -156,14 +156,20 @@ func (self *Whisper) Send(envelope *Envelope) error {
return self.add(envelope) return self.add(envelope)
} }
func (self *Whisper) Start() { // Start implements node.Service, starting the background data propagation thread
// of the Whisper protocol.
func (self *Whisper) Start(*p2p.Server) error {
glog.V(logger.Info).Infoln("Whisper started") glog.V(logger.Info).Infoln("Whisper started")
go self.update() go self.update()
return nil
} }
func (self *Whisper) Stop() { // Stop implements node.Service, stopping the background data propagation thread
// of the Whisper protocol.
func (self *Whisper) Stop() error {
close(self.quit) close(self.quit)
glog.V(logger.Info).Infoln("Whisper stopped") glog.V(logger.Info).Infoln("Whisper stopped")
return nil
} }
// Messages retrieves all the currently pooled messages matching a filter id. // Messages retrieves all the currently pooled messages matching a filter id.
......
...@@ -33,7 +33,7 @@ func startTestCluster(n int) []*Whisper { ...@@ -33,7 +33,7 @@ func startTestCluster(n int) []*Whisper {
whispers := make([]*Whisper, n) whispers := make([]*Whisper, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
whispers[i] = New() whispers[i] = New()
whispers[i].Start() whispers[i].Start(nil)
} }
// Wire all the peers to the root one // Wire all the peers to the root one
for i := 1; i < n; i++ { for i := 1; i < n; i++ {
......
...@@ -19,6 +19,7 @@ package xeth ...@@ -19,6 +19,7 @@ package xeth
import ( import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/eth"
) )
type State struct { type State struct {
...@@ -45,8 +46,7 @@ func (self *State) SafeGet(addr string) *Object { ...@@ -45,8 +46,7 @@ func (self *State) SafeGet(addr string) *Object {
func (self *State) safeGet(addr string) *state.StateObject { func (self *State) safeGet(addr string) *state.StateObject {
object := self.state.GetStateObject(common.HexToAddress(addr)) object := self.state.GetStateObject(common.HexToAddress(addr))
if object == nil { if object == nil {
object = state.NewStateObject(common.HexToAddress(addr), self.xeth.backend.ChainDb()) object = state.NewStateObject(common.HexToAddress(addr), self.xeth.backend.Service("eth").(*eth.Ethereum).ChainDb())
} }
return object return object
} }
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment