hermez-node/node/node.go
node/node.goRaw
1package node
2
3import (
4 "context"
5 "time"
6
7 "github.com/ethereum/go-ethereum/ethclient"
8 "github.com/hermeznetwork/hermez-node/batchbuilder"
9 "github.com/hermeznetwork/hermez-node/config"
10 "github.com/hermeznetwork/hermez-node/coordinator"
11 dbUtils "github.com/hermeznetwork/hermez-node/db"
12 "github.com/hermeznetwork/hermez-node/db/historydb"
13 "github.com/hermeznetwork/hermez-node/db/l2db"
14 "github.com/hermeznetwork/hermez-node/db/statedb"
15 "github.com/hermeznetwork/hermez-node/eth"
16 "github.com/hermeznetwork/hermez-node/log"
17 "github.com/hermeznetwork/hermez-node/synchronizer"
18 "github.com/hermeznetwork/hermez-node/txselector"
19 "github.com/jmoiron/sqlx"
20)
21
22// Mode sets the working mode of the node (synchronizer or coordinator)
23type Mode string
24
25const (
26 // ModeCoordinator defines the mode of the HermezNode as Coordinator, which
27 // means that the node is set to forge (which also will be synchronizing with
28 // the L1 blockchain state)
29 ModeCoordinator Mode = "coordinator"
30
31 // ModeSynchronizer defines the mode of the HermezNode as Synchronizer, which
32 // means that the node is set to only synchronize with the L1 blockchain state
33 // and will not forge
34 ModeSynchronizer Mode = "synchronizer"
35)
36
37// Node is the Hermez Node
38type Node struct {
39 // Coordinator
40 coord *coordinator.Coordinator
41 coordCfg *config.Coordinator
42 stopForge chan bool
43 stopGetProofCallForge chan bool
44 stopForgeCallConfirm chan bool
45 stoppedForge chan bool
46 stoppedGetProofCallForge chan bool
47 stoppedForgeCallConfirm chan bool
48
49 // Synchronizer
50 sync *synchronizer.Synchronizer
51 stopSync chan bool
52 stoppedSync chan bool
53
54 // General
55 cfg *config.Node
56 mode Mode
57 sqlConn *sqlx.DB
58}
59
60// NewNode creates a Node
61func NewNode(mode Mode, cfg *config.Node, coordCfg *config.Coordinator) (*Node, error) {
62 // Stablish DB connection
63 db, err := dbUtils.InitSQLDB(
64 cfg.PostgreSQL.Port,
65 cfg.PostgreSQL.Host,
66 cfg.PostgreSQL.User,
67 cfg.PostgreSQL.Password,
68 cfg.PostgreSQL.Name,
69 )
70 if err != nil {
71 return nil, err
72 }
73
74 historyDB := historydb.NewHistoryDB(db)
75
76 stateDB, err := statedb.NewStateDB(cfg.StateDB.Path, statedb.TypeSynchronizer, 32)
77 if err != nil {
78 return nil, err
79 }
80
81 ethClient, err := ethclient.Dial(cfg.Web3.URL)
82 if err != nil {
83 return nil, err
84 }
85 client := eth.NewClient(ethClient, nil, nil, nil)
86
87 sync, err := synchronizer.NewSynchronizer(client, historyDB, stateDB)
88 if err != nil {
89 return nil, err
90 }
91
92 var coord *coordinator.Coordinator
93 if mode == ModeCoordinator {
94 l2DB := l2db.NewL2DB(
95 db,
96 coordCfg.L2DB.SafetyPeriod,
97 coordCfg.L2DB.MaxTxs,
98 coordCfg.L2DB.TTL.Duration,
99 )
100 // TODO: Get (maxL1UserTxs, maxL1OperatorTxs, maxTxs) from the smart contract
101 txSelector, err := txselector.NewTxSelector(coordCfg.TxSelector.Path, stateDB, l2DB, 10, 10, 10)
102 if err != nil {
103 return nil, err
104 }
105 // TODO: Get (configCircuits []ConfigCircuit, batchNum common.BatchNum, nLevels uint64) from smart contract
106 nLevels := uint64(32) //nolint:gomnd
107 batchBuilder, err := batchbuilder.NewBatchBuilder(coordCfg.BatchBuilder.Path, stateDB, nil, 0, nLevels)
108 if err != nil {
109 return nil, err
110 }
111 if err != nil {
112 return nil, err
113 }
114 serverProofs := make([]coordinator.ServerProofInterface, len(coordCfg.ServerProofs))
115 for i, serverProofCfg := range coordCfg.ServerProofs {
116 serverProofs[i] = coordinator.NewServerProof(serverProofCfg.URL)
117 }
118 coord = coordinator.NewCoordinator(
119 coordinator.Config{
120 ForgerAddress: coordCfg.ForgerAddress,
121 },
122 historyDB,
123 txSelector,
124 batchBuilder,
125 serverProofs,
126 client,
127 )
128 }
129 return &Node{
130 coord: coord,
131 coordCfg: coordCfg,
132 sync: sync,
133 cfg: cfg,
134 mode: mode,
135 sqlConn: db,
136 }, nil
137}
138
139// StartCoordinator starts the coordinator
140func (n *Node) StartCoordinator() {
141 log.Info("Starting Coordinator...")
142
143 n.stopForge = make(chan bool)
144 n.stopGetProofCallForge = make(chan bool)
145 n.stopForgeCallConfirm = make(chan bool)
146
147 n.stoppedForge = make(chan bool)
148 n.stoppedGetProofCallForge = make(chan bool)
149 n.stoppedForgeCallConfirm = make(chan bool)
150
151 queueSize := 1
152 batchCh0 := make(chan *coordinator.BatchInfo, queueSize)
153 batchCh1 := make(chan *coordinator.BatchInfo, queueSize)
154
155 go func() {
156 defer func() { n.stoppedForge <- true }()
157 for {
158 select {
159 case <-n.stopForge:
160 return
161 default:
162 if forge, err := n.coord.ForgeLoopFn(batchCh0, n.stopForge); err == coordinator.ErrStop {
163 return
164 } else if err != nil {
165 log.Errorw("Coordinator.ForgeLoopFn", "error", err)
166 } else if !forge {
167 time.Sleep(n.coordCfg.ForgeLoopInterval.Duration)
168 }
169 }
170 }
171 }()
172 go func() {
173 defer func() { n.stoppedGetProofCallForge <- true }()
174 for {
175 select {
176 case <-n.stopGetProofCallForge:
177 return
178 default:
179 if err := n.coord.GetProofCallForgeLoopFn(
180 batchCh0, batchCh1, n.stopGetProofCallForge); err == coordinator.ErrStop {
181 return
182 } else if err != nil {
183 log.Errorw("Coordinator.GetProofCallForgeLoopFn", "error", err)
184 }
185 }
186 }
187 }()
188 go func() {
189 defer func() { n.stoppedForgeCallConfirm <- true }()
190 for {
191 select {
192 case <-n.stopForgeCallConfirm:
193 return
194 default:
195 if err := n.coord.ForgeCallConfirmLoopFn(
196 batchCh1, n.stopForgeCallConfirm); err == coordinator.ErrStop {
197 return
198 } else if err != nil {
199 log.Errorw("Coordinator.ForgeCallConfirmLoopFn", "error", err)
200 }
201 }
202 }
203 }()
204}
205
206// StopCoordinator stops the coordinator
207func (n *Node) StopCoordinator() {
208 log.Info("Stopping Coordinator...")
209 n.stopForge <- true
210 n.stopGetProofCallForge <- true
211 n.stopForgeCallConfirm <- true
212 <-n.stoppedForge
213 <-n.stoppedGetProofCallForge
214 <-n.stoppedForgeCallConfirm
215}
216
217// StartSynchronizer starts the synchronizer
218func (n *Node) StartSynchronizer() {
219 log.Info("Starting Synchronizer...")
220 n.stopSync = make(chan bool)
221 n.stoppedSync = make(chan bool)
222 go func() {
223 defer func() { n.stoppedSync <- true }()
224 for {
225 select {
226 case <-n.stopSync:
227 log.Info("Coordinator stopped")
228 return
229 case <-time.After(n.cfg.Synchronizer.SyncLoopInterval.Duration):
230 if err := n.sync.Sync(context.TODO()); err != nil {
231 log.Errorw("Synchronizer.Sync", "error", err)
232 }
233 }
234 }
235 }()
236}
237
238// StopSynchronizer stops the synchronizer
239func (n *Node) StopSynchronizer() {
240 log.Info("Stopping Synchronizer...")
241 n.stopSync <- true
242 <-n.stoppedSync
243}
244
245// Start the node
246func (n *Node) Start() {
247 log.Infow("Starting node...", "mode", n.mode)
248 if n.mode == ModeCoordinator {
249 n.StartCoordinator()
250 }
251 n.StartSynchronizer()
252}
253
254// Stop the node
255func (n *Node) Stop() {
256 log.Infow("Stopping node...")
257 if n.mode == ModeCoordinator {
258 n.StopCoordinator()
259 }
260 n.StopSynchronizer()
261}