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 err := l2DB.AddTxTest(tx)
88 assert.NoError(t, err)
89 fetchedTx, err := l2DB.GetTx(tx.TxID)
90 assert.NoError(t, err)
91 // assertReadTx(t, commonToRead(tx, tokens), fetchedTx)
92 assertTx(t, tx, fetchedTx)
93 }
94}
95
96func assertTx(t *testing.T, expected, actual *common.PoolL2Tx) {
97 // Check that timestamp has been set within the last 3 seconds
98 assert.Less(t, time.Now().UTC().Unix()-3, actual.Timestamp.Unix())
99 assert.GreaterOrEqual(t, time.Now().UTC().Unix(), actual.Timestamp.Unix())
100 expected.Timestamp = actual.Timestamp
101 // Check absolute fee
102 // find token
103 token := historydb.TokenWithUSD{}
104 for _, tkn := range tokensUSD {
105 if expected.TokenID == tkn.TokenID {
106 token = tkn
107 break
108 }
109 }
110 // If the token has value in USD setted
111 if token.USDUpdate != nil {
112 assert.Equal(t, token.USDUpdate.Unix(), actual.AbsoluteFeeUpdate.Unix())
113 expected.AbsoluteFeeUpdate = actual.AbsoluteFeeUpdate
114 // Set expected fee
115 f := new(big.Float).SetInt(expected.Amount)
116 amountF, _ := f.Float64()
117 expected.AbsoluteFee = *token.USD * amountF * expected.Fee.Percentage()
118 test.AssertUSD(t, &expected.AbsoluteFee, &actual.AbsoluteFee)
119 }
120 assert.Equal(t, expected, actual)
121}
122
123func BenchmarkAddTxTest(b *testing.B) {
124 const nInserts = 20
125 test.WipeDB(l2DB.DB())
126 txs := test.GenPoolTxs(nInserts, tokens)
127 now := time.Now()
128 for _, tx := range txs {
129 _ = l2DB.AddTxTest(tx)
130 }
131 elapsedTime := time.Since(now)
132 log.Info("Time to insert 2048 txs:", elapsedTime)
133}
134
135func TestGetPending(t *testing.T) {
136 const nInserts = 20
137 test.WipeDB(l2DB.DB())
138 txs := test.GenPoolTxs(nInserts, tokens)
139 var pendingTxs []*common.PoolL2Tx
140 for _, tx := range txs {
141 err := l2DB.AddTxTest(tx)
142 assert.NoError(t, err)
143 if tx.State == common.PoolL2TxStatePending {
144 pendingTxs = append(pendingTxs, tx)
145 }
146 }
147 fetchedTxs, err := l2DB.GetPendingTxs()
148 assert.NoError(t, err)
149 assert.Equal(t, len(pendingTxs), len(fetchedTxs))
150 for i := range fetchedTxs {
151 assertTx(t, pendingTxs[i], &fetchedTxs[i])
152 }
153}
154
155/*
156 WARNING: this should be fixed once transaktio is ready
157func TestStartForging(t *testing.T) {
158 // Generate txs
159 const nInserts = 60
160 const fakeBatchNum common.BatchNum = 33
161 test.WipeDB(l2DB.DB())
162 txs := test.GenPoolTxs(nInserts, tokens)
163 var startForgingTxIDs []common.TxID
164 randomizer := 0
165 // Add txs to DB
166 for _, tx := range txs {
167 err := l2DB.AddTxTest(tx)
168 assert.NoError(t, err)
169 if tx.State == common.PoolL2TxStatePending && randomizer%2 == 0 {
170 randomizer++
171 startForgingTxIDs = append(startForgingTxIDs, tx.TxID)
172 }
173 }
174 // Start forging txs
175 err := l2DB.StartForging(startForgingTxIDs, fakeBatchNum)
176 assert.NoError(t, err)
177 // Fetch txs and check that they've been updated correctly
178 for _, id := range startForgingTxIDs {
179 fetchedTx, err := l2DB.GetTx(id)
180 assert.NoError(t, err)
181 assert.Equal(t, common.PoolL2TxStateForging, fetchedTx.State)
182 assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
183 }
184}
185*/
186
187/*
188 WARNING: this should be fixed once transaktio is ready
189func TestDoneForging(t *testing.T) {
190 // Generate txs
191 const nInserts = 60
192 const fakeBatchNum common.BatchNum = 33
193 test.WipeDB(l2DB.DB())
194 txs := test.GenPoolTxs(nInserts, tokens)
195 var doneForgingTxIDs []common.TxID
196 randomizer := 0
197 // Add txs to DB
198 for _, tx := range txs {
199 err := l2DB.AddTxTest(tx)
200 assert.NoError(t, err)
201 if tx.State == common.PoolL2TxStateForging && randomizer%2 == 0 {
202 randomizer++
203 doneForgingTxIDs = append(doneForgingTxIDs, tx.TxID)
204 }
205 }
206 // Start forging txs
207 err := l2DB.DoneForging(doneForgingTxIDs, fakeBatchNum)
208 assert.NoError(t, err)
209 // Fetch txs and check that they've been updated correctly
210 for _, id := range doneForgingTxIDs {
211 fetchedTx, err := l2DB.GetTx(id)
212 assert.NoError(t, err)
213 assert.Equal(t, common.PoolL2TxStateForged, fetchedTx.State)
214 assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
215 }
216}
217*/
218
219/*
220 WARNING: this should be fixed once transaktio is ready
221func TestInvalidate(t *testing.T) {
222 // Generate txs
223 const nInserts = 60
224 const fakeBatchNum common.BatchNum = 33
225 test.WipeDB(l2DB.DB())
226 txs := test.GenPoolTxs(nInserts, tokens)
227 var invalidTxIDs []common.TxID
228 randomizer := 0
229 // Add txs to DB
230 for _, tx := range txs {
231 err := l2DB.AddTxTest(tx)
232 assert.NoError(t, err)
233 if tx.State != common.PoolL2TxStateInvalid && randomizer%2 == 0 {
234 randomizer++
235 invalidTxIDs = append(invalidTxIDs, tx.TxID)
236 }
237 }
238 // Start forging txs
239 err := l2DB.InvalidateTxs(invalidTxIDs, fakeBatchNum)
240 assert.NoError(t, err)
241 // Fetch txs and check that they've been updated correctly
242 for _, id := range invalidTxIDs {
243 fetchedTx, err := l2DB.GetTx(id)
244 assert.NoError(t, err)
245 assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
246 assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
247 }
248}
249*/
250
251/*
252 WARNING: this should be fixed once transaktio is ready
253func TestCheckNonces(t *testing.T) {
254 // Generate txs
255 const nInserts = 60
256 const fakeBatchNum common.BatchNum = 33
257 test.WipeDB(l2DB.DB())
258 txs := test.GenPoolTxs(nInserts, tokens)
259 var invalidTxIDs []common.TxID
260 // Generate accounts
261 const nAccoutns = 2
262 const currentNonce = 2
263 accs := []common.Account{}
264 for i := 0; i < nAccoutns; i++ {
265 accs = append(accs, common.Account{
266 Idx: common.Idx(i),
267 Nonce: currentNonce,
268 })
269 }
270 // Add txs to DB
271 for i := 0; i < len(txs); i++ {
272 if txs[i].State != common.PoolL2TxStateInvalid {
273 if i%2 == 0 { // Ensure transaction will be marked as invalid due to old nonce
274 txs[i].Nonce = accs[i%len(accs)].Nonce
275 txs[i].FromIdx = accs[i%len(accs)].Idx
276 invalidTxIDs = append(invalidTxIDs, txs[i].TxID)
277 } else { // Ensure transaction will NOT be marked as invalid due to old nonce
278 txs[i].Nonce = currentNonce + 1
279 }
280 }
281 err := l2DB.AddTxTest(txs[i])
282 assert.NoError(t, err)
283 }
284 // Start forging txs
285 err := l2DB.InvalidateTxs(invalidTxIDs, fakeBatchNum)
286 assert.NoError(t, err)
287 // Fetch txs and check that they've been updated correctly
288 for _, id := range invalidTxIDs {
289 fetchedTx, err := l2DB.GetTx(id)
290 assert.NoError(t, err)
291 assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
292 assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
293 }
294}
295*/
296
297func TestReorg(t *testing.T) {
298 // Generate txs
299 const nInserts = 20
300 const lastValidBatch common.BatchNum = 20
301 const reorgBatch common.BatchNum = lastValidBatch + 1
302 test.WipeDB(l2DB.DB())
303 txs := test.GenPoolTxs(nInserts, tokens)
304 // Add txs to the DB
305 reorgedTxIDs := []common.TxID{}
306 nonReorgedTxIDs := []common.TxID{}
307 for i := 0; i < len(txs); i++ {
308 err := l2DB.AddTxTest(txs[i])
309 assert.NoError(t, err)
310 var batchNum common.BatchNum
311 if txs[i].State == common.PoolL2TxStateForged || txs[i].State == common.PoolL2TxStateInvalid {
312 reorgedTxIDs = append(reorgedTxIDs, txs[i].TxID)
313 batchNum = reorgBatch
314 } else {
315 nonReorgedTxIDs = append(nonReorgedTxIDs, txs[i].TxID)
316 batchNum = lastValidBatch
317 }
318 _, err = l2DB.db.Exec(
319 "UPDATE tx_pool SET batch_num = $1 WHERE tx_id = $2;",
320 batchNum, txs[i].TxID,
321 )
322 assert.NoError(t, err)
323 }
324 err := l2DB.Reorg(lastValidBatch)
325 assert.NoError(t, err)
326 for _, id := range reorgedTxIDs {
327 tx, err := l2DB.GetTxAPI(id)
328 assert.NoError(t, err)
329 assert.Nil(t, tx.BatchNum)
330 assert.Equal(t, common.PoolL2TxStatePending, tx.State)
331 }
332 for _, id := range nonReorgedTxIDs {
333 fetchedTx, err := l2DB.GetTxAPI(id)
334 assert.NoError(t, err)
335 assert.Equal(t, lastValidBatch, *fetchedTx.BatchNum)
336 }
337}
338
339func TestPurge(t *testing.T) {
340 /*
341 WARNING: this should be fixed once transaktio is ready
342 // Generate txs
343 nInserts := l2DB.maxTxs + 20
344 test.WipeDB(l2DB.DB())
345 txs := test.GenPoolTxs(int(nInserts), tokens)
346 deletedIDs := []common.TxID{}
347 keepedIDs := []common.TxID{}
348 const toDeleteBatchNum common.BatchNum = 30
349 safeBatchNum := toDeleteBatchNum + l2DB.safetyPeriod + 1
350 // Add txs to the DB
351 for i := 0; i < int(l2DB.maxTxs); i++ {
352 var batchNum common.BatchNum
353 if i%2 == 0 { // keep tx
354 batchNum = safeBatchNum
355 keepedIDs = append(keepedIDs, txs[i].TxID)
356 } else { // delete after safety period
357 batchNum = toDeleteBatchNum
358 if i%3 == 0 {
359 txs[i].State = common.PoolL2TxStateForged
360 } else {
361 txs[i].State = common.PoolL2TxStateInvalid
362 }
363 deletedIDs = append(deletedIDs, txs[i].TxID)
364 }
365 err := l2DB.AddTxTest(txs[i])
366 assert.NoError(t, err)
367 // Set batchNum
368 _, err = l2DB.db.Exec(
369 "UPDATE tx_pool SET batch_num = $1 WHERE tx_id = $2;",
370 batchNum, txs[i].TxID,
371 )
372 assert.NoError(t, err)
373 }
374 for i := int(l2DB.maxTxs); i < len(txs); i++ {
375 // Delete after TTL
376 deletedIDs = append(deletedIDs, txs[i].TxID)
377 err := l2DB.AddTxTest(txs[i])
378 assert.NoError(t, err)
379 // Set timestamp
380 deleteTimestamp := time.Unix(time.Now().UTC().Unix()-int64(l2DB.ttl.Seconds()+float64(4*time.Second)), 0)
381 _, err = l2DB.db.Exec(
382 "UPDATE tx_pool SET timestamp = $1 WHERE tx_id = $2;",
383 deleteTimestamp, txs[i].TxID,
384 )
385 assert.NoError(t, err)
386 }
387 // Purge txs
388 err := l2DB.Purge(safeBatchNum)
389 assert.NoError(t, err)
390 // Check results
391 for _, id := range deletedIDs {
392 tx, err := l2DB.GetTx(id)
393 if err == nil {
394 log.Debug(tx)
395 }
396 assert.Error(t, err)
397 }
398 for _, id := range keepedIDs {
399 _, err := l2DB.GetTx(id)
400 assert.NoError(t, err)
401 }
402 */
403}
404
405func TestAuth(t *testing.T) {
406 test.WipeDB(l2DB.DB())
407 const nAuths = 5
408 // Generate authorizations
409 auths := test.GenAuths(nAuths)
410 for i := 0; i < len(auths); i++ {
411 // Add to the DB
412 err := l2DB.AddAccountCreationAuth(auths[i])
413 assert.NoError(t, err)
414 // Fetch from DB
415 auth, err := l2DB.GetAccountCreationAuth(auths[i].EthAddr)
416 assert.NoError(t, err)
417 // Check fetched vs generated
418 assert.Equal(t, auths[i].EthAddr, auth.EthAddr)
419 assert.Equal(t, auths[i].BJJ, auth.BJJ)
420 assert.Equal(t, auths[i].Signature, auth.Signature)
421 assert.Equal(t, auths[i].Timestamp.Unix(), auths[i].Timestamp.Unix())
422 }
423}