hermez-node/coordinator/coordinator_test.go
coordinator/coordinator_test.goRaw
1package coordinator
2
3import (
4 "io/ioutil"
5 "math/big"
6 "os"
7 "testing"
8 "time"
9
10 ethCommon "github.com/ethereum/go-ethereum/common"
11 "github.com/hermeznetwork/hermez-node/batchbuilder"
12 dbUtils "github.com/hermeznetwork/hermez-node/db"
13 "github.com/hermeznetwork/hermez-node/db/historydb"
14 "github.com/hermeznetwork/hermez-node/db/l2db"
15 "github.com/hermeznetwork/hermez-node/db/statedb"
16 "github.com/hermeznetwork/hermez-node/log"
17 "github.com/hermeznetwork/hermez-node/test"
18 "github.com/hermeznetwork/hermez-node/txselector"
19 "github.com/stretchr/testify/assert"
20 "github.com/stretchr/testify/require"
21)
22
23func newTestModules(t *testing.T) (*txselector.TxSelector, *batchbuilder.BatchBuilder) { // FUTURE once Synchronizer is ready, should return it also
24 nLevels := 32
25
26 synchDBPath, err := ioutil.TempDir("", "tmpSynchDB")
27 require.Nil(t, err)
28 defer assert.Nil(t, os.RemoveAll(synchDBPath))
29 synchSdb, err := statedb.NewStateDB(synchDBPath, statedb.TypeSynchronizer, nLevels)
30 assert.Nil(t, err)
31
32 // txselDBPath, err := ioutil.TempDir("", "tmpTxSelDB")
33 // require.Nil(t, err)
34 // bbDBPath, err := ioutil.TempDir("", "tmpBBDB")
35 // require.Nil(t, err)
36 // txselSdb, err := statedb.NewLocalStateDB(txselDBPath, synchSdb, statedb.TypeTxSelector, nLevels)
37 // assert.Nil(t, err)
38 // bbSdb, err := statedb.NewLocalStateDB(bbDBPath, synchSdb, statedb.TypeBatchBuilder, nLevels)
39 // assert.Nil(t, err)
40
41 pass := os.Getenv("POSTGRES_PASS")
42 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
43 require.Nil(t, err)
44 l2DB := l2db.NewL2DB(db, 10, 100, 24*time.Hour)
45
46 txselDir, err := ioutil.TempDir("", "tmpTxSelDB")
47 require.Nil(t, err)
48 defer assert.Nil(t, os.RemoveAll(txselDir))
49 txsel, err := txselector.NewTxSelector(txselDir, synchSdb, l2DB, 10, 10, 10)
50 assert.Nil(t, err)
51
52 bbDir, err := ioutil.TempDir("", "tmpBatchBuilderDB")
53 require.Nil(t, err)
54 defer assert.Nil(t, os.RemoveAll(bbDir))
55 bb, err := batchbuilder.NewBatchBuilder(bbDir, synchSdb, nil, 0, uint64(nLevels))
56 assert.Nil(t, err)
57
58 // l1Txs, coordinatorL1Txs, poolL2Txs := test.GenerateTestTxsFromSet(t, test.SetTest0)
59
60 return txsel, bb
61}
62
63// CoordNode is an example of a Node that handles the goroutines for the coordinator
64type CoordNode struct {
65 c *Coordinator
66 stopForge chan bool
67 stopGetProofCallForge chan bool
68 stopForgeCallConfirm chan bool
69}
70
71func NewCoordNode(c *Coordinator) *CoordNode {
72 return &CoordNode{
73 c: c,
74 }
75}
76
77func (cn *CoordNode) Start() {
78 log.Debugw("Starting CoordNode...")
79 cn.stopForge = make(chan bool)
80 cn.stopGetProofCallForge = make(chan bool)
81 cn.stopForgeCallConfirm = make(chan bool)
82 queueSize := 8
83 batchCh0 := make(chan *BatchInfo, queueSize)
84 batchCh1 := make(chan *BatchInfo, queueSize)
85
86 go func() {
87 for {
88 select {
89 case <-cn.stopForge:
90 return
91 default:
92 if forge, err := cn.c.ForgeLoopFn(batchCh0, cn.stopForge); err == ErrStop {
93 return
94 } else if err != nil {
95 log.Errorw("CoordNode ForgeLoopFn", "error", err)
96 time.Sleep(200 * time.Millisecond) // Avoid overflowing log with errors
97 } else if !forge {
98 time.Sleep(200 * time.Millisecond)
99 }
100 }
101 }
102 }()
103 go func() {
104 for {
105 select {
106 case <-cn.stopGetProofCallForge:
107 return
108 default:
109 if err := cn.c.GetProofCallForgeLoopFn(
110 batchCh0, batchCh1, cn.stopGetProofCallForge); err == ErrStop {
111 return
112 } else if err != nil {
113 log.Errorw("CoordNode GetProofCallForgeLoopFn", "error", err)
114 }
115 }
116 }
117 }()
118 go func() {
119 for {
120 select {
121 case <-cn.stopForgeCallConfirm:
122 return
123 default:
124 if err := cn.c.ForgeCallConfirmLoopFn(
125 batchCh1, cn.stopForgeCallConfirm); err == ErrStop {
126 return
127 } else if err != nil {
128 log.Errorw("CoordNode ForgeCallConfirmLoopFn", "error", err)
129 }
130 }
131 }
132 }()
133}
134
135func (cn *CoordNode) Stop() {
136 log.Debugw("Stopping CoordNode...")
137 cn.stopForge <- true
138 cn.stopGetProofCallForge <- true
139 cn.stopForgeCallConfirm <- true
140}
141
142type timer struct {
143 time int64
144}
145
146func (t *timer) Time() int64 {
147 currentTime := t.time
148 t.time++
149 return currentTime
150}
151
152func waitForSlot(t *testing.T, c *test.Client, slot int64) {
153 for {
154 blockNum, err := c.EthCurrentBlock()
155 require.Nil(t, err)
156 nextBlockSlot, err := c.AuctionGetSlotNumber(blockNum + 1)
157 require.Nil(t, err)
158 if nextBlockSlot == slot {
159 break
160 }
161 c.CtlMineBlock()
162 }
163}
164
165func TestCoordinator(t *testing.T) {
166 txsel, bb := newTestModules(t)
167
168 conf := Config{}
169 hdb := &historydb.HistoryDB{}
170 serverProofs := []ServerProofInterface{&ServerProofMock{}, &ServerProofMock{}}
171
172 var timer timer
173 ethClientSetup := test.NewClientSetupExample()
174 bidder := ethCommon.HexToAddress("0x6b175474e89094c44da98b954eedeac495271d0f")
175 forger := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
176 ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
177
178 // Bid for slot 2 and 4
179 _, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
180 require.Nil(t, err)
181 _, err = ethClient.AuctionBidSimple(2, big.NewInt(9999))
182 require.Nil(t, err)
183 _, err = ethClient.AuctionBidSimple(4, big.NewInt(9999))
184 require.Nil(t, err)
185
186 c := NewCoordinator(conf, hdb, txsel, bb, serverProofs, ethClient)
187 cn := NewCoordNode(c)
188 cn.Start()
189 time.Sleep(1 * time.Second)
190
191 // simulate forgeSequence time
192 waitForSlot(t, ethClient, 2)
193 log.Info("simulate entering in forge time")
194 time.Sleep(1 * time.Second)
195
196 // simulate going out from forgeSequence
197 waitForSlot(t, ethClient, 3)
198 log.Info("simulate going out from forge time")
199 time.Sleep(1 * time.Second)
200
201 // simulate entering forgeSequence time again
202 waitForSlot(t, ethClient, 4)
203 log.Info("simulate entering in forge time again")
204 time.Sleep(2 * time.Second)
205
206 // simulate stopping forgerLoop by channel
207 log.Info("simulate stopping forgerLoop by closing coordinator stopch")
208 cn.Stop()
209 time.Sleep(1 * time.Second)
210}