OSDN Git Service

Main network and test network distinguish address prefix
[bytom/bytom.git] / node / node.go
1 package node
2
3 import (
4         "context"
5         "net/http"
6         _ "net/http/pprof"
7         "time"
8
9         log "github.com/sirupsen/logrus"
10         cmn "github.com/tendermint/tmlibs/common"
11         dbm "github.com/tendermint/tmlibs/db"
12         browser "github.com/toqueteos/webbrowser"
13
14         "github.com/bytom/accesstoken"
15         "github.com/bytom/account"
16         "github.com/bytom/api"
17         "github.com/bytom/asset"
18         "github.com/bytom/blockchain/pseudohsm"
19         "github.com/bytom/blockchain/txfeed"
20         cfg "github.com/bytom/config"
21         "github.com/bytom/consensus"
22         "github.com/bytom/crypto/ed25519/chainkd"
23         "github.com/bytom/database/leveldb"
24         "github.com/bytom/env"
25         "github.com/bytom/mining/cpuminer"
26         "github.com/bytom/mining/miningpool"
27         "github.com/bytom/netsync"
28         "github.com/bytom/protocol"
29         "github.com/bytom/protocol/bc"
30         "github.com/bytom/types"
31         w "github.com/bytom/wallet"
32 )
33
34 const (
35         webAddress               = "http://127.0.0.1:9888"
36         expireReservationsPeriod = time.Second
37         maxNewBlockChSize        = 1024
38 )
39
40 type Node struct {
41         cmn.BaseService
42
43         // config
44         config *cfg.Config
45
46         syncManager *netsync.SyncManager
47
48         evsw types.EventSwitch // pub/sub for services
49         //bcReactor    *bc.BlockchainReactor
50         wallet       *w.Wallet
51         accessTokens *accesstoken.CredentialStore
52         api          *api.API
53         chain        *protocol.Chain
54         txfeed       *txfeed.Tracker
55         cpuMiner     *cpuminer.CPUMiner
56         miningPool   *miningpool.MiningPool
57         miningEnable bool
58 }
59
60 func NewNode(config *cfg.Config) *Node {
61         ctx := context.Background()
62         if config.ChainID == "testnet" {
63                 consensus.ActiveNetParams = &consensus.TestNetParams
64         }
65         // Get store
66         txDB := dbm.NewDB("txdb", config.DBBackend, config.DBDir())
67         store := leveldb.NewStore(txDB)
68
69         tokenDB := dbm.NewDB("accesstoken", config.DBBackend, config.DBDir())
70         accessTokens := accesstoken.NewStore(tokenDB)
71
72         // Make event switch
73         eventSwitch := types.NewEventSwitch()
74         _, err := eventSwitch.Start()
75         if err != nil {
76                 cmn.Exit(cmn.Fmt("Failed to start switch: %v", err))
77         }
78
79         txPool := protocol.NewTxPool()
80         chain, err := protocol.NewChain(store, txPool)
81         if err != nil {
82                 cmn.Exit(cmn.Fmt("Failed to create chain structure: %v", err))
83         }
84
85         var accounts *account.Manager = nil
86         var assets *asset.Registry = nil
87         var wallet *w.Wallet = nil
88         var txFeed *txfeed.Tracker = nil
89
90         txFeedDB := dbm.NewDB("txfeeds", config.DBBackend, config.DBDir())
91         txFeed = txfeed.NewTracker(txFeedDB, chain)
92
93         if err = txFeed.Prepare(ctx); err != nil {
94                 log.WithField("error", err).Error("start txfeed")
95                 return nil
96         }
97
98         hsm, err := pseudohsm.New(config.KeysDir())
99         if err != nil {
100                 cmn.Exit(cmn.Fmt("initialize HSM failed: %v", err))
101         }
102
103         if !config.Wallet.Disable {
104                 walletDB := dbm.NewDB("wallet", config.DBBackend, config.DBDir())
105                 accounts = account.NewManager(walletDB, chain)
106                 assets = asset.NewRegistry(walletDB, chain)
107                 wallet, err = w.NewWallet(walletDB, accounts, assets, hsm, chain)
108                 if err != nil {
109                         log.WithField("error", err).Error("init NewWallet")
110                 }
111
112                 if err := initOrRecoverAccount(hsm, wallet); err != nil {
113                         log.WithField("error", err).Error("initialize or recover account")
114                 }
115
116                 // Clean up expired UTXO reservations periodically.
117                 go accounts.ExpireReservations(ctx, expireReservationsPeriod)
118         }
119         newBlockCh := make(chan *bc.Hash, maxNewBlockChSize)
120
121         syncManager, _ := netsync.NewSyncManager(config, chain, txPool, newBlockCh)
122
123         // run the profile server
124         profileHost := config.ProfListenAddress
125         if profileHost != "" {
126                 // Profiling bytomd programs.see (https://blog.golang.org/profiling-go-programs)
127                 // go tool pprof http://profileHose/debug/pprof/heap
128                 go func() {
129                         http.ListenAndServe(profileHost, nil)
130                 }()
131         }
132
133         node := &Node{
134                 config:       config,
135                 syncManager:  syncManager,
136                 evsw:         eventSwitch,
137                 accessTokens: accessTokens,
138                 wallet:       wallet,
139                 chain:        chain,
140                 txfeed:       txFeed,
141                 miningEnable: config.Mining,
142         }
143
144         node.cpuMiner = cpuminer.NewCPUMiner(chain, accounts, txPool, newBlockCh)
145         node.miningPool = miningpool.NewMiningPool(chain, accounts, txPool, newBlockCh)
146
147         node.BaseService = *cmn.NewBaseService(nil, "Node", node)
148
149         return node
150 }
151
152 func initOrRecoverAccount(hsm *pseudohsm.HSM, wallet *w.Wallet) error {
153         xpubs := hsm.ListKeys()
154
155         if len(xpubs) == 0 {
156                 xpub, err := hsm.XCreate("default", "123456")
157                 if err != nil {
158                         return err
159                 }
160
161                 wallet.AccountMgr.Create(nil, []chainkd.XPub{xpub.XPub}, 1, "default")
162                 return nil
163         }
164
165         accounts, err := wallet.AccountMgr.ListAccounts("")
166         if err != nil {
167                 return err
168         }
169
170         if len(accounts) > 0 {
171                 return nil
172         }
173
174         for i, xPub := range xpubs {
175                 if err := wallet.ImportAccountXpubKey(i, xPub, w.RecoveryIndex); err != nil {
176                         return err
177                 }
178         }
179         return nil
180 }
181
182 // Lanch web broser or not
183 func lanchWebBroser() {
184         log.Info("Launching System Browser with :", webAddress)
185         if err := browser.Open(webAddress); err != nil {
186                 log.Error(err.Error())
187                 return
188         }
189 }
190
191 func (n *Node) initAndstartApiServer() {
192         n.api = api.NewAPI(n.syncManager, n.wallet, n.txfeed, n.cpuMiner, n.miningPool, n.chain, n.config, n.accessTokens)
193
194         listenAddr := env.String("LISTEN", n.config.ApiAddress)
195         env.Parse()
196         n.api.StartServer(*listenAddr)
197 }
198
199 func (n *Node) OnStart() error {
200         if n.miningEnable {
201                 n.cpuMiner.Start()
202         }
203         n.syncManager.Start()
204         n.initAndstartApiServer()
205         if !n.config.Web.Closed {
206                 lanchWebBroser()
207         }
208
209         return nil
210 }
211
212 func (n *Node) OnStop() {
213         n.BaseService.OnStop()
214         if n.miningEnable {
215                 n.cpuMiner.Stop()
216         }
217         n.syncManager.Stop()
218         log.Info("Stopping Node")
219         // TODO: gracefully disconnect from peers.
220 }
221
222 func (n *Node) RunForever() {
223         // Sleep forever and then...
224         cmn.TrapSignal(func() {
225                 n.Stop()
226         })
227 }
228
229 func (n *Node) EventSwitch() types.EventSwitch {
230         return n.evsw
231 }
232
233 func (n *Node) SyncManager() *netsync.SyncManager {
234         return n.syncManager
235 }
236
237 func (n *Node) MiningPool() *miningpool.MiningPool {
238         return n.miningPool
239 }
240
241 //------------------------------------------------------------------------------