tendermint/node/node.go

266 lines
7.0 KiB
Go
Raw Normal View History

package node
2014-07-08 00:02:04 -07:00
import (
2015-04-27 07:25:11 -07:00
"fmt"
2015-04-23 14:59:12 -07:00
"math/rand"
"net"
2015-04-10 02:12:17 -07:00
"net/http"
2014-07-08 15:33:26 -07:00
"os"
"strconv"
"strings"
2015-05-06 10:50:57 -07:00
"time"
2014-07-08 15:33:26 -07:00
2015-04-01 17:30:16 -07:00
bc "github.com/tendermint/tendermint/blockchain"
. "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/consensus"
dbm "github.com/tendermint/tendermint/db"
"github.com/tendermint/tendermint/events"
2015-04-01 17:30:16 -07:00
mempl "github.com/tendermint/tendermint/mempool"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/rpc"
"github.com/tendermint/tendermint/rpc/core"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
2014-07-08 00:02:04 -07:00
)
2015-04-27 07:25:11 -07:00
import _ "net/http/pprof"
func init() {
go func() {
fmt.Println(http.ListenAndServe("0.0.0.0:6060", nil))
}()
}
2014-07-09 18:33:44 -07:00
type Node struct {
2014-10-22 17:20:44 -07:00
sw *p2p.Switch
evsw *events.EventSwitch
2014-10-22 17:20:44 -07:00
book *p2p.AddrBook
blockStore *bc.BlockStore
2014-10-22 17:20:44 -07:00
pexReactor *p2p.PEXReactor
bcReactor *bc.BlockchainReactor
mempoolReactor *mempl.MempoolReactor
2015-01-11 14:27:46 -08:00
consensusState *consensus.ConsensusState
2014-10-22 17:20:44 -07:00
consensusReactor *consensus.ConsensusReactor
privValidator *sm.PrivValidator
2014-07-09 18:33:44 -07:00
}
2014-07-08 00:02:04 -07:00
2014-07-09 18:33:44 -07:00
func NewNode() *Node {
2014-10-22 17:20:44 -07:00
// Get BlockStore
blockStoreDB := dbm.GetDB("blockstore")
blockStore := bc.NewBlockStore(blockStoreDB)
2014-10-22 17:20:44 -07:00
// Get State
stateDB := dbm.GetDB("state")
state := sm.LoadState(stateDB)
2014-10-22 17:20:44 -07:00
if state == nil {
state = sm.MakeGenesisStateFromFile(stateDB, config.App().GetString("genesis_file"))
2014-10-25 14:27:53 -07:00
state.Save()
2014-10-22 17:20:44 -07:00
}
// Get PrivValidator
var privValidator *sm.PrivValidator
privValidatorFile := config.App().GetString("priv_validator_file")
if _, err := os.Stat(privValidatorFile); err == nil {
privValidator = sm.LoadPrivValidator(privValidatorFile)
log.Info("Loaded PrivValidator",
"file", privValidatorFile, "privValidator", privValidator)
} else {
privValidator = sm.GenPrivValidator()
privValidator.SetFile(privValidatorFile)
privValidator.Save()
log.Info("Generated PrivValidator", "file", privValidatorFile)
}
eventSwitch := new(events.EventSwitch)
eventSwitch.Start()
2014-10-22 17:20:44 -07:00
// Get PEXReactor
book := p2p.NewAddrBook(config.App().GetString("addrbook_file"))
2014-10-22 17:20:44 -07:00
pexReactor := p2p.NewPEXReactor(book)
// Get BlockchainReactor
bcReactor := bc.NewBlockchainReactor(state, blockStore, config.App().GetBool("fast_sync"))
2014-10-22 17:20:44 -07:00
// Get MempoolReactor
mempool := mempl.NewMempool(state.Copy())
mempoolReactor := mempl.NewMempoolReactor(mempool)
2014-10-22 17:20:44 -07:00
// Get ConsensusReactor
2015-01-11 14:27:46 -08:00
consensusState := consensus.NewConsensusState(state, blockStore, mempoolReactor)
consensusReactor := consensus.NewConsensusReactor(consensusState, blockStore)
if privValidator != nil {
consensusReactor.SetPrivValidator(privValidator)
}
2014-10-22 17:20:44 -07:00
// so the consensus reactor won't do anything until we're synced
if config.App().GetBool("fast_sync") {
consensusReactor.SetSyncing(true)
}
sw := p2p.NewSwitch()
sw.AddReactor("PEX", pexReactor)
sw.AddReactor("MEMPOOL", mempoolReactor)
sw.AddReactor("BLOCKCHAIN", bcReactor)
sw.AddReactor("CONSENSUS", consensusReactor)
2014-07-08 00:02:04 -07:00
// add the event switch to all services
// they should all satisfy events.Eventable
2015-04-15 23:40:27 -07:00
SetFireable(eventSwitch, pexReactor, bcReactor, mempoolReactor, consensusReactor)
2014-07-10 22:14:23 -07:00
return &Node{
2014-10-22 17:20:44 -07:00
sw: sw,
evsw: eventSwitch,
2014-10-22 17:20:44 -07:00
book: book,
2015-01-06 15:51:41 -08:00
blockStore: blockStore,
pexReactor: pexReactor,
bcReactor: bcReactor,
2014-10-22 17:20:44 -07:00
mempoolReactor: mempoolReactor,
2015-01-11 14:27:46 -08:00
consensusState: consensusState,
2014-10-22 17:20:44 -07:00
consensusReactor: consensusReactor,
privValidator: privValidator,
2014-07-09 18:33:44 -07:00
}
}
// Call Start() after adding the listeners.
2014-07-09 18:33:44 -07:00
func (n *Node) Start() {
2014-11-27 04:04:07 -08:00
log.Info("Starting Node")
2014-07-09 18:33:44 -07:00
n.book.Start()
nodeInfo := makeNodeInfo(n.sw)
n.sw.SetNodeInfo(nodeInfo)
n.sw.Start()
2014-07-09 18:33:44 -07:00
}
func (n *Node) Stop() {
2014-11-27 04:04:07 -08:00
log.Info("Stopping Node")
// TODO: gracefully disconnect from peers.
n.sw.Stop()
n.book.Stop()
}
// Add the event switch to reactors, mempool, etc.
2015-04-15 23:40:27 -07:00
func SetFireable(evsw *events.EventSwitch, eventables ...events.Eventable) {
for _, e := range eventables {
2015-04-15 23:40:27 -07:00
e.SetFireable(evsw)
}
}
// Add a Listener to accept inbound peer connections.
// Add listeners before starting the Node.
// The first listener is the primary listener (in NodeInfo)
2014-07-10 22:14:23 -07:00
func (n *Node) AddListener(l p2p.Listener) {
2014-12-29 18:09:06 -08:00
log.Info(Fmt("Added %v", l))
2015-04-01 14:52:25 -07:00
n.sw.AddListener(l)
n.book.AddOurAddress(l.ExternalAddress())
2014-07-09 18:33:44 -07:00
}
2014-07-08 00:02:04 -07:00
2015-05-06 10:50:57 -07:00
// NOTE: Blocking
func (n *Node) DialSeed() {
2015-05-06 10:50:57 -07:00
// permute the list, dial them in random order.
seeds := strings.Split(config.App().GetString("seeds"), ",")
2015-04-23 14:59:12 -07:00
perm := rand.Perm(len(seeds))
for i := 0; i < len(perm); i++ {
2015-05-06 10:50:57 -07:00
go func(i int) {
time.Sleep(time.Duration(rand.Int63n(3000)) * time.Millisecond)
j := perm[i]
addr := p2p.NewNetAddressString(seeds[j])
n.dialSeed(addr)
}(i)
2015-04-23 14:59:12 -07:00
}
}
func (n *Node) dialSeed(addr *p2p.NetAddress) {
peer, err := n.sw.DialPeerWithAddress(addr)
if err != nil {
log.Error("Error dialing seed", "error", err)
//n.book.MarkAttempt(addr)
return
} else {
log.Info("Connected to seed", "peer", peer)
n.book.AddAddress(addr, addr)
}
}
2015-03-30 15:55:05 -07:00
func (n *Node) StartRPC() {
2015-03-29 18:06:55 -07:00
core.SetBlockStore(n.blockStore)
core.SetConsensusState(n.consensusState)
core.SetConsensusReactor(n.consensusReactor)
2015-03-29 18:06:55 -07:00
core.SetMempoolReactor(n.mempoolReactor)
core.SetSwitch(n.sw)
2015-05-12 19:03:05 -07:00
core.SetPrivValidator(n.privValidator)
2015-04-10 02:12:17 -07:00
listenAddr := config.App().GetString("rpc_laddr")
2015-04-10 02:12:17 -07:00
mux := http.NewServeMux()
rpc.RegisterEventsHandler(mux, n.evsw)
rpc.RegisterRPCFuncs(mux, core.Routes)
2015-04-23 18:33:20 -07:00
rpc.StartHTTPServer(listenAddr, mux)
}
func (n *Node) Switch() *p2p.Switch {
return n.sw
}
func (n *Node) ConsensusState() *consensus.ConsensusState {
return n.consensusState
}
func (n *Node) MempoolReactor() *mempl.MempoolReactor {
return n.mempoolReactor
}
2015-04-17 13:18:50 -07:00
func (n *Node) EventSwitch() *events.EventSwitch {
return n.evsw
}
func makeNodeInfo(sw *p2p.Switch) *types.NodeInfo {
nodeInfo := &types.NodeInfo{
Network: config.App().GetString("network"),
Moniker: config.App().GetString("moniker"),
2015-05-12 19:03:05 -07:00
Version: config.App().GetString("version"),
}
if !sw.IsListening() {
return nodeInfo
}
p2pListener := sw.Listeners()[0]
p2pHost := p2pListener.ExternalAddress().IP.String()
p2pPort := p2pListener.ExternalAddress().Port
rpcListenAddr := config.App().GetString("rpc_laddr")
_, rpcPortStr, _ := net.SplitHostPort(rpcListenAddr)
rpcPort, err := strconv.Atoi(rpcPortStr)
if err != nil {
panic(Fmt("Expected numeric RPC.ListenAddr port but got %v", rpcPortStr))
}
// We assume that the rpcListener has the same ExternalAddress.
// This is probably true because both P2P and RPC listeners use UPnP.
nodeInfo.Host = p2pHost
nodeInfo.P2PPort = p2pPort
nodeInfo.RPCPort = uint16(rpcPort)
return nodeInfo
}
2015-04-01 14:52:25 -07:00
//------------------------------------------------------------------------------
func RunNode() {
2014-07-12 14:52:31 -07:00
// Create & start node
2014-07-09 18:33:44 -07:00
n := NewNode()
l := p2p.NewDefaultListener("tcp", config.App().GetString("node_laddr"), false)
2014-07-10 22:14:23 -07:00
n.AddListener(l)
n.Start()
2014-07-09 18:33:44 -07:00
2014-10-22 17:20:44 -07:00
// If seedNode is provided by config, dial out.
if len(config.App().GetStringSlice("seeds")) != 0 {
n.DialSeed()
2014-07-09 18:33:44 -07:00
}
2014-07-08 15:33:26 -07:00
2014-11-27 04:04:07 -08:00
// Run the RPC server.
if config.App().GetString("rpc_laddr") != "" {
2015-03-30 15:55:05 -07:00
n.StartRPC()
2014-11-27 04:04:07 -08:00
}
// Sleep forever and then...
2015-04-08 11:35:17 -07:00
TrapSignal(func() {
n.Stop()
})
2014-07-08 15:33:26 -07:00
}