hermez-node/db/l2db/l2db_test.go
db/l2db/l2db_test.goRaw
1package l2db
2
3import (
4 "math/big"
5 "os"
6 "testing"
7 "time"
8
9 "github.com/hermeznetwork/hermez-node/common"
10 dbUtils "github.com/hermeznetwork/hermez-node/db"
11 "github.com/hermeznetwork/hermez-node/db/historydb"
12 "github.com/hermeznetwork/hermez-node/log"
13 "github.com/hermeznetwork/hermez-node/test"
14 "github.com/jmoiron/sqlx"
15 "github.com/stretchr/testify/assert"
16)
17
18var l2DB *L2DB
19var tokens []common.Token
20var tokensUSD []historydb.TokenWithUSD
21
22func TestMain(m *testing.M) {
23 // init DB
24 pass := os.Getenv("POSTGRES_PASS")
25 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
26 if err != nil {
27 panic(err)
28 }
29 l2DB = NewL2DB(db, 10, 100, 24*time.Hour)
30 test.WipeDB(l2DB.DB())
31 tokens, tokensUSD = prepareHistoryDB(db)
32 // Run tests
33 result := m.Run()
34 // Close DB
35 if err := db.Close(); err != nil {
36 log.Error("Error closing the history DB:", err)
37 }
38 os.Exit(result)
39}
40
41func prepareHistoryDB(db *sqlx.DB) ([]common.Token, []historydb.TokenWithUSD) {
42 historyDB := historydb.NewHistoryDB(db)
43 const fromBlock int64 = 1
44 const toBlock int64 = 5
45 // Store blocks to historyDB
46 blocks := test.GenBlocks(fromBlock, toBlock)
47 if err := historyDB.AddBlocks(blocks); err != nil {
48 panic(err)
49 }
50 // Store tokens to historyDB
51 const nTokens = 5
52 tokens, ethToken := test.GenTokens(nTokens, blocks)
53 if err := historyDB.AddTokens(tokens); err != nil {
54 panic(err)
55 }
56 tokens = append([]common.Token{ethToken}, tokens...)
57 readTokens := []historydb.TokenWithUSD{}
58 for i, token := range tokens {
59 readToken := historydb.TokenWithUSD{
60 TokenID: token.TokenID,
61 EthBlockNum: token.EthBlockNum,
62 EthAddr: token.EthAddr,
63 Name: token.Name,
64 Symbol: token.Symbol,
65 Decimals: token.Decimals,
66 }
67 if i%2 != 0 {
68 value := float64(i) * 5.4321
69 if err := historyDB.UpdateTokenValue(token.Symbol, value); err != nil {
70 panic(err)
71 }
72 now := time.Now().UTC()
73 readToken.USDUpdate = &now
74 readToken.USD = &value
75 }
76 readTokens = append(readTokens, readToken)
77 }
78 return tokens, readTokens
79}
80
81func TestAddTxTest(t *testing.T) {
82 // Gen poolTxs
83 const nInserts = 20
84 test.WipeDB(l2DB.DB())
85 txs := test.GenPoolTxs(nInserts, tokens)
86 for _, tx := range txs {
87 // TODO: UPDATE with til
88 err := l2DB.AddTxTest(tx)
89 assert.NoError(t, err)
90 fetchedTx, err := l2DB.GetTx(tx.TxID)
91 assert.NoError(t, err)
92 // assertReadTx(t, commonToRead(tx, tokens), fetchedTx)
93 assertTx(t, tx, fetchedTx)
94 nameZone, offset := fetchedTx.Timestamp.Zone()
95 assert.Equal(t, "UTC", nameZone)
96 assert.Equal(t, 0, offset)
97 }
98}
99
100func assertTx(t *testing.T, expected, actual *common.PoolL2Tx) {
101 // Check that timestamp has been set within the last 3 seconds
102 assert.Less(t, time.Now().UTC().Unix()-3, actual.Timestamp.Unix())
103 assert.GreaterOrEqual(t, time.Now().UTC().Unix(), actual.Timestamp.Unix())
104 expected.Timestamp = actual.Timestamp
105 // Check absolute fee
106 // find token
107 token := historydb.TokenWithUSD{}
108 for _, tkn := range tokensUSD {
109 if expected.TokenID == tkn.TokenID {
110 token = tkn
111 break
112 }
113 }
114 // If the token has value in USD setted
115 if token.USDUpdate != nil {
116 assert.Equal(t, token.USDUpdate.Unix(), actual.AbsoluteFeeUpdate.Unix())
117 expected.AbsoluteFeeUpdate = actual.AbsoluteFeeUpdate
118 // Set expected fee
119 f := new(big.Float).SetInt(expected.Amount)
120 amountF, _ := f.Float64()
121 expected.AbsoluteFee = *token.USD * amountF * expected.Fee.Percentage()
122 test.AssertUSD(t, &expected.AbsoluteFee, &actual.AbsoluteFee)
123 }
124 assert.Equal(t, expected, actual)
125}
126
127// NO UPDATE: benchmarks will be done after impl is finished
128// func BenchmarkAddTxTest(b *testing.B) {
129// const nInserts = 20
130// test.WipeDB(l2DB.DB())
131// txs := test.GenPoolTxs(nInserts, tokens)
132// now := time.Now()
133// for _, tx := range txs {
134// _ = l2DB.AddTxTest(tx)
135// }
136// elapsedTime := time.Since(now)
137// log.Info("Time to insert 2048 txs:", elapsedTime)
138// }
139
140func TestGetPending(t *testing.T) {
141 const nInserts = 20
142 test.WipeDB(l2DB.DB())
143 // TODO: UPDATE with til
144 txs := test.GenPoolTxs(nInserts, tokens)
145 var pendingTxs []*common.PoolL2Tx
146 for _, tx := range txs {
147 err := l2DB.AddTxTest(tx)
148 assert.NoError(t, err)
149 if tx.State == common.PoolL2TxStatePending {
150 pendingTxs = append(pendingTxs, tx)
151 }
152 }
153 fetchedTxs, err := l2DB.GetPendingTxs()
154 assert.NoError(t, err)
155 assert.Equal(t, len(pendingTxs), len(fetchedTxs))
156 for i := range fetchedTxs {
157 assertTx(t, pendingTxs[i], &fetchedTxs[i])
158 }
159}
160
161/*
162 TODO: update with til
163func TestStartForging(t *testing.T) {
164 // Generate txs
165 const nInserts = 60
166 const fakeBatchNum common.BatchNum = 33
167 test.WipeDB(l2DB.DB())
168 txs := test.GenPoolTxs(nInserts, tokens)
169 var startForgingTxIDs []common.TxID
170 randomizer := 0
171 // Add txs to DB
172 for _, tx := range txs {
173 err := l2DB.AddTxTest(tx)
174 assert.NoError(t, err)
175 if tx.State == common.PoolL2TxStatePending && randomizer%2 == 0 {
176 randomizer++
177 startForgingTxIDs = append(startForgingTxIDs, tx.TxID)
178 }
179 }
180 // Start forging txs
181 err := l2DB.StartForging(startForgingTxIDs, fakeBatchNum)
182 assert.NoError(t, err)
183 // Fetch txs and check that they've been updated correctly
184 for _, id := range startForgingTxIDs {
185 fetchedTx, err := l2DB.GetTx(id)
186 assert.NoError(t, err)
187 assert.Equal(t, common.PoolL2TxStateForging, fetchedTx.State)
188 assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
189 }
190}
191*/
192
193/*
194 TODO: update with til
195func TestDoneForging(t *testing.T) {
196 // Generate txs
197 const nInserts = 60
198 const fakeBatchNum common.BatchNum = 33
199 test.WipeDB(l2DB.DB())
200 txs := test.GenPoolTxs(nInserts, tokens)
201 var doneForgingTxIDs []common.TxID
202 randomizer := 0
203 // Add txs to DB
204 for _, tx := range txs {
205 err := l2DB.AddTxTest(tx)
206 assert.NoError(t, err)
207 if tx.State == common.PoolL2TxStateForging && randomizer%2 == 0 {
208 randomizer++
209 doneForgingTxIDs = append(doneForgingTxIDs, tx.TxID)
210 }
211 }
212 // Start forging txs
213 err := l2DB.DoneForging(doneForgingTxIDs, fakeBatchNum)
214 assert.NoError(t, err)
215 // Fetch txs and check that they've been updated correctly
216 for _, id := range doneForgingTxIDs {
217 fetchedTx, err := l2DB.GetTx(id)
218 assert.NoError(t, err)
219 assert.Equal(t, common.PoolL2TxStateForged, fetchedTx.State)
220 assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
221 }
222}
223*/
224
225/*
226 TODO: update with til
227func TestInvalidate(t *testing.T) {
228 // Generate txs
229 const nInserts = 60
230 const fakeBatchNum common.BatchNum = 33
231 test.WipeDB(l2DB.DB())
232 txs := test.GenPoolTxs(nInserts, tokens)
233 var invalidTxIDs []common.TxID
234 randomizer := 0
235 // Add txs to DB
236 for _, tx := range txs {
237 err := l2DB.AddTxTest(tx)
238 assert.NoError(t, err)
239 if tx.State != common.PoolL2TxStateInvalid && randomizer%2 == 0 {
240 randomizer++
241 invalidTxIDs = append(invalidTxIDs, tx.TxID)
242 }
243 }
244 // Start forging txs
245 err := l2DB.InvalidateTxs(invalidTxIDs, fakeBatchNum)
246 assert.NoError(t, err)
247 // Fetch txs and check that they've been updated correctly
248 for _, id := range invalidTxIDs {
249 fetchedTx, err := l2DB.GetTx(id)
250 assert.NoError(t, err)
251 assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
252 assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
253 }
254}
255*/
256
257/*
258
259 TODO: update with til
260
261
262func TestCheckNonces(t *testing.T) {
263 // Generate txs
264 const nInserts = 60
265 const fakeBatchNum common.BatchNum = 33
266 test.WipeDB(l2DB.DB())
267 txs := test.GenPoolTxs(nInserts, tokens)
268 var invalidTxIDs []common.TxID
269 // Generate accounts
270 const nAccoutns = 2
271 const currentNonce = 2
272 accs := []common.Account{}
273 for i := 0; i < nAccoutns; i++ {
274 accs = append(accs, common.Account{
275 Idx: common.Idx(i),
276 Nonce: currentNonce,
277 })
278 }
279 // Add txs to DB
280 for i := 0; i < len(txs); i++ {
281 if txs[i].State != common.PoolL2TxStateInvalid {
282 if i%2 == 0 { // Ensure transaction will be marked as invalid due to old nonce
283 txs[i].Nonce = accs[i%len(accs)].Nonce
284 txs[i].FromIdx = accs[i%len(accs)].Idx
285 invalidTxIDs = append(invalidTxIDs, txs[i].TxID)
286 } else { // Ensure transaction will NOT be marked as invalid due to old nonce
287 txs[i].Nonce = currentNonce + 1
288 }
289 }
290 err := l2DB.AddTxTest(txs[i])
291 assert.NoError(t, err)
292 }
293 // Start forging txs
294 err := l2DB.InvalidateTxs(invalidTxIDs, fakeBatchNum)
295 assert.NoError(t, err)
296 // Fetch txs and check that they've been updated correctly
297 for _, id := range invalidTxIDs {
298 fetchedTx, err := l2DB.GetTx(id)
299 assert.NoError(t, err)
300 assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
301 assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
302 }
303}
304*/
305
306func TestReorg(t *testing.T) {
307 // Generate txs
308 const nInserts = 20
309 const lastValidBatch common.BatchNum = 20
310 const reorgBatch common.BatchNum = lastValidBatch + 1
311 test.WipeDB(l2DB.DB())
312 // TODO: update with til
313 txs := test.GenPoolTxs(nInserts, tokens)
314 // Add txs to the DB
315 reorgedTxIDs := []common.TxID{}
316 nonReorgedTxIDs := []common.TxID{}
317 for i := 0; i < len(txs); i++ {
318 err := l2DB.AddTxTest(txs[i])
319 assert.NoError(t, err)
320 var batchNum common.BatchNum
321 if txs[i].State == common.PoolL2TxStateForged || txs[i].State == common.PoolL2TxStateInvalid {
322 reorgedTxIDs = append(reorgedTxIDs, txs[i].TxID)
323 batchNum = reorgBatch
324 } else {
325 nonReorgedTxIDs = append(nonReorgedTxIDs, txs[i].TxID)
326 batchNum = lastValidBatch
327 }
328 _, err = l2DB.db.Exec(
329 "UPDATE tx_pool SET batch_num = $1 WHERE tx_id = $2;",
330 batchNum, txs[i].TxID,
331 )
332 assert.NoError(t, err)
333 }
334 err := l2DB.Reorg(lastValidBatch)
335 assert.NoError(t, err)
336 for _, id := range reorgedTxIDs {
337 tx, err := l2DB.GetTxAPI(id)
338 assert.NoError(t, err)
339 assert.Nil(t, tx.BatchNum)
340 assert.Equal(t, common.PoolL2TxStatePending, tx.State)
341 }
342 for _, id := range nonReorgedTxIDs {
343 fetchedTx, err := l2DB.GetTxAPI(id)
344 assert.NoError(t, err)
345 assert.Equal(t, lastValidBatch, *fetchedTx.BatchNum)
346 }
347}
348
349func TestPurge(t *testing.T) {
350 /*
351
352 TODO: update with til
353
354 WARNING: this should be fixed once transaktio is ready
355 // Generate txs
356 nInserts := l2DB.maxTxs + 20
357 test.WipeDB(l2DB.DB())
358 txs := test.GenPoolTxs(int(nInserts), tokens)
359 deletedIDs := []common.TxID{}
360 keepedIDs := []common.TxID{}
361 const toDeleteBatchNum common.BatchNum = 30
362 safeBatchNum := toDeleteBatchNum + l2DB.safetyPeriod + 1
363 // Add txs to the DB
364 for i := 0; i < int(l2DB.maxTxs); i++ {
365 var batchNum common.BatchNum
366 if i%2 == 0 { // keep tx
367 batchNum = safeBatchNum
368 keepedIDs = append(keepedIDs, txs[i].TxID)
369 } else { // delete after safety period
370 batchNum = toDeleteBatchNum
371 if i%3 == 0 {
372 txs[i].State = common.PoolL2TxStateForged
373 } else {
374 txs[i].State = common.PoolL2TxStateInvalid
375 }
376 deletedIDs = append(deletedIDs, txs[i].TxID)
377 }
378 err := l2DB.AddTxTest(txs[i])
379 assert.NoError(t, err)
380 // Set batchNum
381 _, err = l2DB.db.Exec(
382 "UPDATE tx_pool SET batch_num = $1 WHERE tx_id = $2;",
383 batchNum, txs[i].TxID,
384 )
385 assert.NoError(t, err)
386 }
387 for i := int(l2DB.maxTxs); i < len(txs); i++ {
388 // Delete after TTL
389 deletedIDs = append(deletedIDs, txs[i].TxID)
390 err := l2DB.AddTxTest(txs[i])
391 assert.NoError(t, err)
392 // Set timestamp
393 deleteTimestamp := time.Unix(time.Now().UTC().Unix()-int64(l2DB.ttl.Seconds()+float64(4*time.Second)), 0)
394 _, err = l2DB.db.Exec(
395 "UPDATE tx_pool SET timestamp = $1 WHERE tx_id = $2;",
396 deleteTimestamp, txs[i].TxID,
397 )
398 assert.NoError(t, err)
399 }
400 // Purge txs
401 err := l2DB.Purge(safeBatchNum)
402 assert.NoError(t, err)
403 // Check results
404 for _, id := range deletedIDs {
405 tx, err := l2DB.GetTx(id)
406 if err == nil {
407 log.Debug(tx)
408 }
409 assert.Error(t, err)
410 }
411 for _, id := range keepedIDs {
412 _, err := l2DB.GetTx(id)
413 assert.NoError(t, err)
414 }
415 */
416}
417
418func TestAuth(t *testing.T) {
419 test.WipeDB(l2DB.DB())
420 const nAuths = 5
421 // Generate authorizations
422 auths := test.GenAuths(nAuths)
423 for i := 0; i < len(auths); i++ {
424 // Add to the DB
425 err := l2DB.AddAccountCreationAuth(auths[i])
426 assert.NoError(t, err)
427 // Fetch from DB
428 auth, err := l2DB.GetAccountCreationAuth(auths[i].EthAddr)
429 assert.NoError(t, err)
430 // Check fetched vs generated
431 assert.Equal(t, auths[i].EthAddr, auth.EthAddr)
432 assert.Equal(t, auths[i].BJJ, auth.BJJ)
433 assert.Equal(t, auths[i].Signature, auth.Signature)
434 assert.Equal(t, auths[i].Timestamp.Unix(), auths[i].Timestamp.Unix())
435 nameZone, offset := auths[i].Timestamp.Zone()
436 assert.Equal(t, "UTC", nameZone)
437 assert.Equal(t, 0, offset)
438 }
439}