Merge branch 'develop' into release/1.4

This commit is contained in:
Jeffrey Wilcke 2016-05-09 22:04:40 +02:00
commit 8f96d66241
21 changed files with 239 additions and 100 deletions

View File

@ -13,7 +13,7 @@ GOBIN = build/bin
GO ?= latest GO ?= latest
geth: geth:
build/env.sh go install -v $(shell build/flags.sh) ./cmd/geth build/env.sh go build -i -v $(shell build/flags.sh) -o $(GOBIN)/geth ./cmd/geth
@echo "Done building." @echo "Done building."
@echo "Run \"$(GOBIN)/geth\" to launch geth." @echo "Run \"$(GOBIN)/geth\" to launch geth."
@ -103,7 +103,9 @@ evm:
@echo "Run \"$(GOBIN)/evm to start the evm." @echo "Run \"$(GOBIN)/evm to start the evm."
all: all:
build/env.sh go install -v $(shell build/flags.sh) ./... for cmd in `ls ./cmd/`; do \
build/env.sh go build -i -v $(shell build/flags.sh) -o $(GOBIN)/$$cmd ./cmd/$$cmd; \
done
test: all test: all
build/env.sh go test ./... build/env.sh go test ./...

26
build/win-ci-compile.bat Normal file
View File

@ -0,0 +1,26 @@
@echo off
if not exist .\build\win-ci-compile.bat (
echo This script must be run from the root of the repository.
exit /b
)
if not defined GOPATH (
echo GOPATH is not set.
exit /b
)
set GOPATH=%GOPATH%;%cd%\Godeps\_workspace
set GOBIN=%cd%\build\bin
rem set gitCommit when running from a Git checkout.
set goLinkFlags=""
if exist ".git\HEAD" (
where /q git
if not errorlevel 1 (
for /f %%h in ('git rev-parse HEAD') do (
set goLinkFlags="-X main.gitCommit=%%h"
)
)
)
@echo on
go install -v -ldflags %goLinkFlags% ./...

15
build/win-ci-test.bat Normal file
View File

@ -0,0 +1,15 @@
@echo off
if not exist .\build\win-ci-test.bat (
echo This script must be run from the root of the repository.
exit /b
)
if not defined GOPATH (
echo GOPATH is not set.
exit /b
)
set GOPATH=%GOPATH%;%cd%\Godeps\_workspace
set GOBIN=%cd%\build\bin
@echo on
go test ./...

View File

@ -73,15 +73,13 @@ func StartNode(stack *node.Node) {
<-sigc <-sigc
glog.V(logger.Info).Infoln("Got interrupt, shutting down...") glog.V(logger.Info).Infoln("Got interrupt, shutting down...")
go stack.Stop() go stack.Stop()
logger.Flush()
for i := 10; i > 0; i-- { for i := 10; i > 0; i-- {
<-sigc <-sigc
if i > 1 { if i > 1 {
glog.V(logger.Info).Infoln("Already shutting down, please be patient.") glog.V(logger.Info).Infof("Already shutting down, interrupt %d more times for panic.", i-1)
glog.V(logger.Info).Infoln("Interrupt", i-1, "more times to induce panic.")
} }
} }
glog.V(logger.Error).Infof("Force quitting: this might not end so well.") debug.Exit() // ensure trace and CPU profile data is flushed.
debug.LoudPanic("boom") debug.LoudPanic("boom")
}() }()
} }

View File

@ -0,0 +1,54 @@
// Copyright 2016 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/>.
// +build freebsd
package utils
import "syscall"
// This file is largely identical to fdlimit_unix.go,
// but Rlimit fields have type int64 on FreeBSD so it needs
// an extra conversion.
// raiseFdLimit tries to maximize the file descriptor allowance of this process
// to the maximum hard-limit allowed by the OS.
func raiseFdLimit(max uint64) error {
// Get the current limit
var limit syscall.Rlimit
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
return err
}
// Try to update the limit to the max allowance
limit.Cur = limit.Max
if limit.Cur > int64(max) {
limit.Cur = int64(max)
}
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
return err
}
return nil
}
// getFdLimit retrieves the number of file descriptors allowed to be opened by this
// process.
func getFdLimit() (int, error) {
var limit syscall.Rlimit
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
return 0, err
}
return int(limit.Cur), nil
}

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
// +build linux darwin // +build linux darwin netbsd openbsd solaris
package utils package utils

View File

@ -60,7 +60,6 @@ type stateFn func() (*state.StateDB, error)
// two states over time as they are received and processed. // two states over time as they are received and processed.
type TxPool struct { type TxPool struct {
config *ChainConfig config *ChainConfig
quit chan bool // Quitting channel
currentState stateFn // The state function which will allow us to do some pre checks currentState stateFn // The state function which will allow us to do some pre checks
pendingState *state.ManagedState pendingState *state.ManagedState
gasLimit func() *big.Int // The current gas limit function callback gasLimit func() *big.Int // The current gas limit function callback
@ -72,6 +71,8 @@ type TxPool struct {
pending map[common.Hash]*types.Transaction // processable transactions pending map[common.Hash]*types.Transaction // processable transactions
queue map[common.Address]map[common.Hash]*types.Transaction queue map[common.Address]map[common.Hash]*types.Transaction
wg sync.WaitGroup // for shutdown sync
homestead bool homestead bool
} }
@ -80,7 +81,6 @@ func NewTxPool(config *ChainConfig, eventMux *event.TypeMux, currentStateFn stat
config: config, config: config,
pending: make(map[common.Hash]*types.Transaction), pending: make(map[common.Hash]*types.Transaction),
queue: make(map[common.Address]map[common.Hash]*types.Transaction), queue: make(map[common.Address]map[common.Hash]*types.Transaction),
quit: make(chan bool),
eventMux: eventMux, eventMux: eventMux,
currentState: currentStateFn, currentState: currentStateFn,
gasLimit: gasLimitFn, gasLimit: gasLimitFn,
@ -90,12 +90,15 @@ func NewTxPool(config *ChainConfig, eventMux *event.TypeMux, currentStateFn stat
events: eventMux.Subscribe(ChainHeadEvent{}, GasPriceChanged{}, RemovedTransactionEvent{}), events: eventMux.Subscribe(ChainHeadEvent{}, GasPriceChanged{}, RemovedTransactionEvent{}),
} }
pool.wg.Add(1)
go pool.eventLoop() go pool.eventLoop()
return pool return pool
} }
func (pool *TxPool) eventLoop() { func (pool *TxPool) eventLoop() {
defer pool.wg.Done()
// Track chain events. When a chain events occurs (new chain canon block) // Track chain events. When a chain events occurs (new chain canon block)
// we need to know the new state. The new state will help us determine // we need to know the new state. The new state will help us determine
// the nonces in the managed state // the nonces in the managed state
@ -155,8 +158,8 @@ func (pool *TxPool) resetState() {
} }
func (pool *TxPool) Stop() { func (pool *TxPool) Stop() {
close(pool.quit)
pool.events.Unsubscribe() pool.events.Unsubscribe()
pool.wg.Wait()
glog.V(logger.Info).Infoln("Transaction pool stopped") glog.V(logger.Info).Infoln("Transaction pool stopped")
} }

View File

@ -1841,7 +1841,7 @@ func (s *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logger *vm.LogCon
} }
// Mutate the state if we haven't reached the tracing transaction yet // Mutate the state if we haven't reached the tracing transaction yet
if uint64(idx) < txIndex { if uint64(idx) < txIndex {
vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, parent.Header(), vm.Config{}) vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, block.Header(), vm.Config{})
_, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())) _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
if err != nil { if err != nil {
return nil, fmt.Errorf("mutation failed: %v", err) return nil, fmt.Errorf("mutation failed: %v", err)
@ -1849,7 +1849,7 @@ func (s *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logger *vm.LogCon
continue continue
} }
// Otherwise trace the transaction and return // Otherwise trace the transaction and return
vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, parent.Header(), vm.Config{Debug: true, Logger: *logger}) vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, block.Header(), vm.Config{Debug: true, Logger: *logger})
ret, gas, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())) ret, gas, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
if err != nil { if err != nil {
return nil, fmt.Errorf("tracing failed: %v", err) return nil, fmt.Errorf("tracing failed: %v", err)

View File

@ -416,6 +416,7 @@ func (s *Ethereum) Stop() error {
s.blockchain.Stop() s.blockchain.Stop()
s.protocolManager.Stop() s.protocolManager.Stop()
s.txPool.Stop() s.txPool.Stop()
s.miner.Stop()
s.eventMux.Stop() s.eventMux.Stop()
s.StopAutoDAG() s.StopAutoDAG()

View File

@ -77,11 +77,11 @@ type ProtocolManager struct {
newPeerCh chan *peer newPeerCh chan *peer
txsyncCh chan *txsync txsyncCh chan *txsync
quitSync chan struct{} quitSync chan struct{}
noMorePeers chan struct{}
// wait group is used for graceful shutdowns during downloading // wait group is used for graceful shutdowns during downloading
// and processing // and processing
wg sync.WaitGroup wg sync.WaitGroup
quit bool
} }
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
@ -101,7 +101,8 @@ func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int,
blockchain: blockchain, blockchain: blockchain,
chaindb: chaindb, chaindb: chaindb,
peers: newPeerSet(), peers: newPeerSet(),
newPeerCh: make(chan *peer, 1), newPeerCh: make(chan *peer),
noMorePeers: make(chan struct{}),
txsyncCh: make(chan *txsync), txsyncCh: make(chan *txsync),
quitSync: make(chan struct{}), quitSync: make(chan struct{}),
} }
@ -120,8 +121,14 @@ func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int,
Length: ProtocolLengths[i], Length: ProtocolLengths[i],
Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
peer := manager.newPeer(int(version), p, rw) peer := manager.newPeer(int(version), p, rw)
manager.newPeerCh <- peer select {
case manager.newPeerCh <- peer:
manager.wg.Add(1)
defer manager.wg.Done()
return manager.handle(peer) return manager.handle(peer)
case <-manager.quitSync:
return p2p.DiscQuitting
}
}, },
NodeInfo: func() interface{} { NodeInfo: func() interface{} {
return manager.NodeInfo() return manager.NodeInfo()
@ -187,16 +194,25 @@ func (pm *ProtocolManager) Start() {
} }
func (pm *ProtocolManager) Stop() { func (pm *ProtocolManager) Stop() {
// Showing a log message. During download / process this could actually
// take between 5 to 10 seconds and therefor feedback is required.
glog.V(logger.Info).Infoln("Stopping ethereum protocol handler...") glog.V(logger.Info).Infoln("Stopping ethereum protocol handler...")
pm.quit = true
pm.txSub.Unsubscribe() // quits txBroadcastLoop pm.txSub.Unsubscribe() // quits txBroadcastLoop
pm.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop pm.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop
close(pm.quitSync) // quits syncer, fetcher, txsyncLoop
// Wait for any process action // Quit the sync loop.
// After this send has completed, no new peers will be accepted.
pm.noMorePeers <- struct{}{}
// Quit fetcher, txsyncLoop.
close(pm.quitSync)
// Disconnect existing sessions.
// This also closes the gate for any new registrations on the peer set.
// sessions which are already established but not added to pm.peers yet
// will exit when they try to register.
pm.peers.Close()
// Wait for all peer handler goroutines and the loops to come down.
pm.wg.Wait() pm.wg.Wait()
glog.V(logger.Info).Infoln("Ethereum protocol handler stopped") glog.V(logger.Info).Infoln("Ethereum protocol handler stopped")

View File

@ -140,14 +140,14 @@ func newTestPeer(name string, version int, pm *ProtocolManager, shake bool) (*te
// Start the peer on a new thread // Start the peer on a new thread
errc := make(chan error, 1) errc := make(chan error, 1)
go func() { go func() {
pm.newPeerCh <- peer select {
case pm.newPeerCh <- peer:
errc <- pm.handle(peer) errc <- pm.handle(peer)
}() case <-pm.quitSync:
tp := &testPeer{ errc <- p2p.DiscQuitting
app: app,
net: net,
peer: peer,
} }
}()
tp := &testPeer{app: app, net: net, peer: peer}
// Execute any implicitly requested handshakes and return // Execute any implicitly requested handshakes and return
if shake { if shake {
td, head, genesis := pm.blockchain.Status() td, head, genesis := pm.blockchain.Status()

View File

@ -34,6 +34,7 @@ import (
) )
var ( var (
errClosed = errors.New("peer set is closed")
errAlreadyRegistered = errors.New("peer is already registered") errAlreadyRegistered = errors.New("peer is already registered")
errNotRegistered = errors.New("peer is not registered") errNotRegistered = errors.New("peer is not registered")
) )
@ -353,6 +354,7 @@ func (p *peer) String() string {
type peerSet struct { type peerSet struct {
peers map[string]*peer peers map[string]*peer
lock sync.RWMutex lock sync.RWMutex
closed bool
} }
// newPeerSet creates a new peer set to track the active participants. // newPeerSet creates a new peer set to track the active participants.
@ -368,6 +370,9 @@ func (ps *peerSet) Register(p *peer) error {
ps.lock.Lock() ps.lock.Lock()
defer ps.lock.Unlock() defer ps.lock.Unlock()
if ps.closed {
return errClosed
}
if _, ok := ps.peers[p.id]; ok { if _, ok := ps.peers[p.id]; ok {
return errAlreadyRegistered return errAlreadyRegistered
} }
@ -450,3 +455,15 @@ func (ps *peerSet) BestPeer() *peer {
} }
return bestPeer return bestPeer
} }
// Close disconnects all peers.
// No new peers can be registered after Close has returned.
func (ps *peerSet) Close() {
ps.lock.Lock()
defer ps.lock.Unlock()
for _, p := range ps.peers {
p.Disconnect(p2p.DiscQuitting)
}
ps.closed = true
}

View File

@ -148,7 +148,7 @@ func (pm *ProtocolManager) syncer() {
// Force a sync even if not enough peers are present // Force a sync even if not enough peers are present
go pm.synchronise(pm.peers.BestPeer()) go pm.synchronise(pm.peers.BestPeer())
case <-pm.quitSync: case <-pm.noMorePeers:
return return
} }
} }

View File

@ -51,7 +51,7 @@ type HandlerT struct {
traceFile string traceFile string
} }
// Verbosity sets the glog verbosity floor. // Verbosity sets the glog verbosity ceiling.
// The verbosity of individual packages and source files // The verbosity of individual packages and source files
// can be raised using Vmodule. // can be raised using Vmodule.
func (*HandlerT) Verbosity(level int) { func (*HandlerT) Verbosity(level int) {
@ -131,14 +131,14 @@ func (h *HandlerT) StopCPUProfile() error {
return nil return nil
} }
// Trace turns on tracing for nsec seconds and writes // GoTrace turns on tracing for nsec seconds and writes
// trace data to file. // trace data to file.
func (h *HandlerT) Trace(file string, nsec uint) error { func (h *HandlerT) GoTrace(file string, nsec uint) error {
if err := h.StartTrace(file); err != nil { if err := h.StartGoTrace(file); err != nil {
return err return err
} }
time.Sleep(time.Duration(nsec) * time.Second) time.Sleep(time.Duration(nsec) * time.Second)
h.StopTrace() h.StopGoTrace()
return nil return nil
} }

View File

@ -89,7 +89,7 @@ func Setup(ctx *cli.Context) error {
runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name) runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name)
Handler.SetBlockProfileRate(ctx.GlobalInt(blockprofilerateFlag.Name)) Handler.SetBlockProfileRate(ctx.GlobalInt(blockprofilerateFlag.Name))
if traceFile := ctx.GlobalString(traceFlag.Name); traceFile != "" { if traceFile := ctx.GlobalString(traceFlag.Name); traceFile != "" {
if err := Handler.StartTrace(traceFile); err != nil { if err := Handler.StartGoTrace(traceFile); err != nil {
return err return err
} }
} }
@ -114,5 +114,5 @@ func Setup(ctx *cli.Context) error {
// respective file. // respective file.
func Exit() { func Exit() {
Handler.StopCPUProfile() Handler.StopCPUProfile()
Handler.StopTrace() Handler.StopGoTrace()
} }

View File

@ -27,8 +27,8 @@ import (
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
) )
// StartTrace turns on tracing, writing to the given file. // StartGoTrace turns on tracing, writing to the given file.
func (h *HandlerT) StartTrace(file string) error { func (h *HandlerT) StartGoTrace(file string) error {
h.mu.Lock() h.mu.Lock()
defer h.mu.Unlock() defer h.mu.Unlock()
if h.traceW != nil { if h.traceW != nil {
@ -49,7 +49,7 @@ func (h *HandlerT) StartTrace(file string) error {
} }
// StopTrace stops an ongoing trace. // StopTrace stops an ongoing trace.
func (h *HandlerT) StopTrace() error { func (h *HandlerT) StopGoTrace() error {
h.mu.Lock() h.mu.Lock()
defer h.mu.Unlock() defer h.mu.Unlock()
trace.Stop() trace.Stop()

View File

@ -22,10 +22,10 @@ package debug
import "errors" import "errors"
func (*HandlerT) StartTrace(string) error { func (*HandlerT) StartGoTrace(string) error {
return errors.New("tracing is not supported on Go < 1.5") return errors.New("tracing is not supported on Go < 1.5")
} }
func (*HandlerT) StopTrace() error { func (*HandlerT) StopGoTrace() error {
return errors.New("tracing is not supported on Go < 1.5") return errors.New("tracing is not supported on Go < 1.5")
} }

View File

@ -366,18 +366,18 @@ web3._extend({
params: 0 params: 0
}), }),
new web3._extend.Method({ new web3._extend.Method({
name: 'trace', name: 'goTrace',
call: 'debug_trace', call: 'debug_goTrace',
params: 2 params: 2
}), }),
new web3._extend.Method({ new web3._extend.Method({
name: 'startTrace', name: 'startGoTrace',
call: 'debug_startTrace', call: 'debug_startGoTrace',
params: 1 params: 1
}), }),
new web3._extend.Method({ new web3._extend.Method({
name: 'stopTrace', name: 'stopGoTrace',
call: 'debug_stopTrace', call: 'debug_stopGoTrace',
params: 0 params: 0
}), }),
new web3._extend.Method({ new web3._extend.Method({

View File

@ -3911,7 +3911,12 @@ var outputSyncingFormatter = function(result) {
result.startingBlock = utils.toDecimal(result.startingBlock); result.startingBlock = utils.toDecimal(result.startingBlock);
result.currentBlock = utils.toDecimal(result.currentBlock); result.currentBlock = utils.toDecimal(result.currentBlock);
result.highestBlock = utils.toDecimal(result.highestBlock); result.highestBlock = utils.toDecimal(result.highestBlock);
if (result.knownStates !== undefined) {
result.knownStates = utils.toDecimal(result.knownStates);
}
if (result.pulledStates !== undefined) {
result.pulledStates = utils.toDecimal(result.pulledStates);
}
return result; return result;
}; };

View File

@ -94,10 +94,13 @@ type worker struct {
mu sync.Mutex mu sync.Mutex
// update loop
mux *event.TypeMux
events event.Subscription
wg sync.WaitGroup
agents map[Agent]struct{} agents map[Agent]struct{}
recv chan *Result recv chan *Result
mux *event.TypeMux
quit chan struct{}
pow pow.PoW pow pow.PoW
eth core.Backend eth core.Backend
@ -138,13 +141,14 @@ func newWorker(config *core.ChainConfig, coinbase common.Address, eth core.Backe
possibleUncles: make(map[common.Hash]*types.Block), possibleUncles: make(map[common.Hash]*types.Block),
coinbase: coinbase, coinbase: coinbase,
txQueue: make(map[common.Hash]*types.Transaction), txQueue: make(map[common.Hash]*types.Transaction),
quit: make(chan struct{}),
agents: make(map[Agent]struct{}), agents: make(map[Agent]struct{}),
fullValidation: false, fullValidation: false,
} }
worker.events = worker.mux.Subscribe(core.ChainHeadEvent{}, core.ChainSideEvent{}, core.TxPreEvent{})
worker.wg.Add(1)
go worker.update() go worker.update()
go worker.wait()
go worker.wait()
worker.commitNewWork() worker.commitNewWork()
return worker return worker
@ -184,9 +188,12 @@ func (self *worker) start() {
} }
func (self *worker) stop() { func (self *worker) stop() {
// Quit update.
self.events.Unsubscribe()
self.wg.Wait()
self.mu.Lock() self.mu.Lock()
defer self.mu.Unlock() defer self.mu.Unlock()
if atomic.LoadInt32(&self.mining) == 1 { if atomic.LoadInt32(&self.mining) == 1 {
// Stop all agents. // Stop all agents.
for agent := range self.agents { for agent := range self.agents {
@ -217,18 +224,8 @@ func (self *worker) unregister(agent Agent) {
} }
func (self *worker) update() { func (self *worker) update() {
eventSub := self.mux.Subscribe(core.ChainHeadEvent{}, core.ChainSideEvent{}, core.TxPreEvent{}) defer self.wg.Done()
defer eventSub.Unsubscribe() for event := range self.events.Chan() {
eventCh := eventSub.Chan()
for {
select {
case event, ok := <-eventCh:
if !ok {
// Event subscription closed, set the channel to nil to stop spinning
eventCh = nil
continue
}
// A real event arrived, process interesting content // A real event arrived, process interesting content
switch ev := event.Data.(type) { switch ev := event.Data.(type) {
case core.ChainHeadEvent: case core.ChainHeadEvent:
@ -245,9 +242,6 @@ func (self *worker) update() {
self.currentMu.Unlock() self.currentMu.Unlock()
} }
} }
case <-self.quit:
return
}
} }
} }

View File

@ -68,7 +68,11 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *rpc.HexNumber, cors *st
} }
if host == nil { if host == nil {
host = &api.node.httpHost h := common.DefaultHTTPHost
if api.node.httpHost != "" {
h = api.node.httpHost
}
host = &h
} }
if port == nil { if port == nil {
port = rpc.NewHexNumber(api.node.httpPort) port = rpc.NewHexNumber(api.node.httpPort)
@ -113,7 +117,11 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *rpc.HexNumber, allowedOr
} }
if host == nil { if host == nil {
host = &api.node.wsHost h := common.DefaultWSHost
if api.node.wsHost != "" {
h = api.node.wsHost
}
host = &h
} }
if port == nil { if port == nil {
port = rpc.NewHexNumber(api.node.wsPort) port = rpc.NewHexNumber(api.node.wsPort)