hermez-node/db/l2db/l2db_test.go
db/l2db/l2db_test.goRaw
1package l2db
2
3import (
4 "os"
5 "testing"
6 "time"
7
8 "github.com/hermeznetwork/hermez-node/common"
9 dbUtils "github.com/hermeznetwork/hermez-node/db"
10 "github.com/hermeznetwork/hermez-node/db/historydb"
11 "github.com/hermeznetwork/hermez-node/log"
12 "github.com/hermeznetwork/hermez-node/test"
13 "github.com/jmoiron/sqlx"
14 "github.com/stretchr/testify/assert"
15)
16
17var l2DB *L2DB
18var tokens []common.Token
19
20func TestMain(m *testing.M) {
21 // init DB
22 pass := os.Getenv("POSTGRES_PASS")
23 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
24 if err != nil {
25 panic(err)
26 }
27 l2DB = NewL2DB(db, 10, 100, 24*time.Hour)
28 tokens, err = prepareHistoryDB(db)
29 if err != nil {
30 panic(err)
31 }
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, error) {
42 historyDB := historydb.NewHistoryDB(db)
43 const fromBlock int64 = 1
44 const toBlock int64 = 5
45 // Clean historyDB
46 if err := historyDB.Reorg(-1); err != nil {
47 panic(err)
48 }
49 // Store blocks to historyDB
50 blocks := test.GenBlocks(fromBlock, toBlock)
51 if err := historyDB.AddBlocks(blocks); err != nil {
52 panic(err)
53 }
54 // Store tokens to historyDB
55 const nTokens = 5
56 tokens := test.GenTokens(nTokens, blocks)
57 return tokens, historyDB.AddTokens(tokens)
58}
59
60func TestAddTxTest(t *testing.T) {
61 // Gen poolTxs
62 const nInserts = 20
63 test.CleanL2DB(l2DB.DB())
64 txs := test.GenPoolTxs(nInserts, tokens)
65 for _, tx := range txs {
66 err := l2DB.AddTxTest(tx)
67 assert.NoError(t, err)
68 fetchedTx, err := l2DB.GetTx(tx.TxID)
69 assert.NoError(t, err)
70 assertTx(t, tx, fetchedTx)
71 }
72}
73
74func assertTx(t *testing.T, expected, actual *common.PoolL2Tx) {
75 assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
76 expected.Timestamp = actual.Timestamp
77 if expected.AbsoluteFeeUpdate != nil {
78 assert.Equal(t, expected.AbsoluteFeeUpdate.Unix(), actual.AbsoluteFeeUpdate.Unix())
79 expected.AbsoluteFeeUpdate = actual.AbsoluteFeeUpdate
80 } else {
81 assert.Equal(t, expected.AbsoluteFeeUpdate, actual.AbsoluteFeeUpdate)
82 }
83 test.AssertUSD(t, expected.AbsoluteFee, actual.AbsoluteFee)
84 assert.Equal(t, expected, actual)
85}
86
87func BenchmarkAddTxTest(b *testing.B) {
88 const nInserts = 20
89 test.CleanL2DB(l2DB.DB())
90 txs := test.GenPoolTxs(nInserts, tokens)
91 now := time.Now()
92 for _, tx := range txs {
93 _ = l2DB.AddTxTest(tx)
94 }
95 elapsedTime := time.Since(now)
96 log.Info("Time to insert 2048 txs:", elapsedTime)
97}
98
99func TestGetPending(t *testing.T) {
100 const nInserts = 20
101 test.CleanL2DB(l2DB.DB())
102 txs := test.GenPoolTxs(nInserts, tokens)
103 var pendingTxs []*common.PoolL2Tx
104 for _, tx := range txs {
105 err := l2DB.AddTxTest(tx)
106 assert.NoError(t, err)
107 if tx.State == common.PoolL2TxStatePending && tx.AbsoluteFee != nil {
108 pendingTxs = append(pendingTxs, tx)
109 }
110 }
111 fetchedTxs, err := l2DB.GetPendingTxs()
112 assert.NoError(t, err)
113 assert.Equal(t, len(pendingTxs), len(fetchedTxs))
114 for i, fetchedTx := range fetchedTxs {
115 assertTx(t, pendingTxs[i], fetchedTx)
116 }
117}
118
119func TestStartForging(t *testing.T) {
120 // Generate txs
121 const nInserts = 60
122 const fakeBatchNum common.BatchNum = 33
123 test.CleanL2DB(l2DB.DB())
124 txs := test.GenPoolTxs(nInserts, tokens)
125 var startForgingTxIDs []common.TxID
126 randomizer := 0
127 // Add txs to DB
128 for _, tx := range txs {
129 err := l2DB.AddTxTest(tx)
130 assert.NoError(t, err)
131 if tx.State == common.PoolL2TxStatePending && randomizer%2 == 0 {
132 randomizer++
133 startForgingTxIDs = append(startForgingTxIDs, tx.TxID)
134 }
135 }
136 // Start forging txs
137 err := l2DB.StartForging(startForgingTxIDs, fakeBatchNum)
138 assert.NoError(t, err)
139 // Fetch txs and check that they've been updated correctly
140 for _, id := range startForgingTxIDs {
141 fetchedTx, err := l2DB.GetTx(id)
142 assert.NoError(t, err)
143 assert.Equal(t, common.PoolL2TxStateForging, fetchedTx.State)
144 assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
145 }
146}
147
148func TestDoneForging(t *testing.T) {
149 // Generate txs
150 const nInserts = 60
151 const fakeBatchNum common.BatchNum = 33
152 test.CleanL2DB(l2DB.DB())
153 txs := test.GenPoolTxs(nInserts, tokens)
154 var doneForgingTxIDs []common.TxID
155 randomizer := 0
156 // Add txs to DB
157 for _, tx := range txs {
158 err := l2DB.AddTxTest(tx)
159 assert.NoError(t, err)
160 if tx.State == common.PoolL2TxStateForging && randomizer%2 == 0 {
161 randomizer++
162 doneForgingTxIDs = append(doneForgingTxIDs, tx.TxID)
163 }
164 }
165 // Start forging txs
166 err := l2DB.DoneForging(doneForgingTxIDs, fakeBatchNum)
167 assert.NoError(t, err)
168 // Fetch txs and check that they've been updated correctly
169 for _, id := range doneForgingTxIDs {
170 fetchedTx, err := l2DB.GetTx(id)
171 assert.NoError(t, err)
172 assert.Equal(t, common.PoolL2TxStateForged, fetchedTx.State)
173 assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
174 }
175}
176
177func TestInvalidate(t *testing.T) {
178 // Generate txs
179 const nInserts = 60
180 const fakeBatchNum common.BatchNum = 33
181 test.CleanL2DB(l2DB.DB())
182 txs := test.GenPoolTxs(nInserts, tokens)
183 var invalidTxIDs []common.TxID
184 randomizer := 0
185 // Add txs to DB
186 for _, tx := range txs {
187 err := l2DB.AddTxTest(tx)
188 assert.NoError(t, err)
189 if tx.State != common.PoolL2TxStateInvalid && randomizer%2 == 0 {
190 randomizer++
191 invalidTxIDs = append(invalidTxIDs, tx.TxID)
192 }
193 }
194 // Start forging txs
195 err := l2DB.InvalidateTxs(invalidTxIDs, fakeBatchNum)
196 assert.NoError(t, err)
197 // Fetch txs and check that they've been updated correctly
198 for _, id := range invalidTxIDs {
199 fetchedTx, err := l2DB.GetTx(id)
200 assert.NoError(t, err)
201 assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
202 assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
203 }
204}
205
206func TestCheckNonces(t *testing.T) {
207 // Generate txs
208 const nInserts = 60
209 const fakeBatchNum common.BatchNum = 33
210 test.CleanL2DB(l2DB.DB())
211 txs := test.GenPoolTxs(nInserts, tokens)
212 var invalidTxIDs []common.TxID
213 // Generate accounts
214 const nAccoutns = 2
215 const currentNonce = 2
216 accs := []common.Account{}
217 for i := 0; i < nAccoutns; i++ {
218 accs = append(accs, common.Account{
219 Idx: common.Idx(i),
220 Nonce: currentNonce,
221 })
222 }
223 // Add txs to DB
224 for i := 0; i < len(txs); i++ {
225 if txs[i].State != common.PoolL2TxStateInvalid {
226 if i%2 == 0 { // Ensure transaction will be marked as invalid due to old nonce
227 txs[i].Nonce = accs[i%len(accs)].Nonce
228 txs[i].FromIdx = accs[i%len(accs)].Idx
229 invalidTxIDs = append(invalidTxIDs, txs[i].TxID)
230 } else { // Ensure transaction will NOT be marked as invalid due to old nonce
231 txs[i].Nonce = currentNonce + 1
232 }
233 }
234 err := l2DB.AddTxTest(txs[i])
235 assert.NoError(t, err)
236 }
237 // Start forging txs
238 err := l2DB.InvalidateTxs(invalidTxIDs, fakeBatchNum)
239 assert.NoError(t, err)
240 // Fetch txs and check that they've been updated correctly
241 for _, id := range invalidTxIDs {
242 fetchedTx, err := l2DB.GetTx(id)
243 assert.NoError(t, err)
244 assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
245 assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
246 }
247}
248
249func TestReorg(t *testing.T) {
250 // Generate txs
251 const nInserts = 20
252 const lastValidBatch common.BatchNum = 20
253 const reorgBatch common.BatchNum = lastValidBatch + 1
254 test.CleanL2DB(l2DB.DB())
255 txs := test.GenPoolTxs(nInserts, tokens)
256 // Add txs to the DB
257 reorgedTxIDs := []common.TxID{}
258 nonReorgedTxIDs := []common.TxID{}
259 for i := 0; i < len(txs); i++ {
260 txs[i].BatchNum = new(common.BatchNum)
261 if txs[i].State == common.PoolL2TxStateForged || txs[i].State == common.PoolL2TxStateInvalid {
262 *txs[i].BatchNum = reorgBatch
263 reorgedTxIDs = append(reorgedTxIDs, txs[i].TxID)
264 } else {
265 *txs[i].BatchNum = lastValidBatch
266 nonReorgedTxIDs = append(nonReorgedTxIDs, txs[i].TxID)
267 }
268 err := l2DB.AddTxTest(txs[i])
269 assert.NoError(t, err)
270 }
271 err := l2DB.Reorg(lastValidBatch)
272 assert.NoError(t, err)
273 for _, id := range reorgedTxIDs {
274 tx, err := l2DB.GetTx(id)
275 assert.NoError(t, err)
276 assert.Nil(t, tx.BatchNum)
277 assert.Equal(t, common.PoolL2TxStatePending, tx.State)
278 }
279 for _, id := range nonReorgedTxIDs {
280 tx, err := l2DB.GetTx(id)
281 assert.NoError(t, err)
282 assert.Equal(t, lastValidBatch, *tx.BatchNum)
283 }
284}
285
286func TestPurge(t *testing.T) {
287 // Generate txs
288 nInserts := l2DB.maxTxs + 20
289 test.CleanL2DB(l2DB.DB())
290 txs := test.GenPoolTxs(int(nInserts), tokens)
291 deletedIDs := []common.TxID{}
292 keepedIDs := []common.TxID{}
293 const toDeleteBatchNum common.BatchNum = 30
294 safeBatchNum := toDeleteBatchNum + l2DB.safetyPeriod + 1
295 // Add txs to the DB
296 for i := 0; i < int(l2DB.maxTxs); i++ {
297 txs[i].BatchNum = new(common.BatchNum)
298 if i%1 == 0 { // keep tx
299 *txs[i].BatchNum = safeBatchNum
300 keepedIDs = append(keepedIDs, txs[i].TxID)
301 } else if i%2 == 0 { // delete after safety period
302 *txs[i].BatchNum = toDeleteBatchNum
303 if i%3 == 0 {
304 txs[i].State = common.PoolL2TxStateForged
305 } else {
306 txs[i].State = common.PoolL2TxStateInvalid
307 }
308 deletedIDs = append(deletedIDs, txs[i].TxID)
309 }
310 err := l2DB.AddTxTest(txs[i])
311 assert.NoError(t, err)
312 }
313 for i := int(l2DB.maxTxs); i < len(txs); i++ {
314 // Delete after TTL
315 txs[i].Timestamp = time.Unix(time.Now().UTC().Unix()-int64(l2DB.ttl.Seconds()+float64(4*time.Second)), 0)
316 deletedIDs = append(deletedIDs, txs[i].TxID)
317 err := l2DB.AddTxTest(txs[i])
318 assert.NoError(t, err)
319 }
320 // Purge txs
321 err := l2DB.Purge(safeBatchNum - 1)
322 assert.NoError(t, err)
323 // Check results
324 for _, id := range deletedIDs {
325 tx, err := l2DB.GetTx(id)
326 if err == nil {
327 log.Debug(tx)
328 }
329 assert.Error(t, err)
330 }
331 for _, id := range keepedIDs {
332 _, err := l2DB.GetTx(id)
333 assert.NoError(t, err)
334 }
335}
336
337func TestAuth(t *testing.T) {
338 test.CleanL2DB(l2DB.DB())
339 const nAuths = 5
340 // Generate authorizations
341 auths := test.GenAuths(nAuths)
342 for i := 0; i < len(auths); i++ {
343 // Add to the DB
344 err := l2DB.AddAccountCreationAuth(auths[i])
345 assert.NoError(t, err)
346 // Fetch from DB
347 auth, err := l2DB.GetAccountCreationAuth(&auths[i].EthAddr)
348 assert.NoError(t, err)
349 // Check fetched vs generated
350 assert.Equal(t, auths[i].EthAddr, auth.EthAddr)
351 assert.Equal(t, auths[i].BJJ, auth.BJJ)
352 assert.Equal(t, auths[i].Signature, auth.Signature)
353 assert.Equal(t, auths[i].Timestamp.Unix(), auths[i].Timestamp.Unix())
354 }
355}