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 if txs[i].State == common.PoolL2TxStateForged || txs[i].State == common.PoolL2TxStateInvalid {
261 txs[i].BatchNum = reorgBatch
262 reorgedTxIDs = append(reorgedTxIDs, txs[i].TxID)
263 } else {
264 txs[i].BatchNum = lastValidBatch
265 nonReorgedTxIDs = append(nonReorgedTxIDs, txs[i].TxID)
266 }
267 err := l2DB.AddTxTest(txs[i])
268 assert.NoError(t, err)
269 }
270 err := l2DB.Reorg(lastValidBatch)
271 assert.NoError(t, err)
272 var nullBatchNum common.BatchNum
273 for _, id := range reorgedTxIDs {
274 tx, err := l2DB.GetTx(id)
275 assert.NoError(t, err)
276 assert.Equal(t, nullBatchNum, 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 if i%1 == 0 { // keep tx
298 txs[i].BatchNum = safeBatchNum
299 keepedIDs = append(keepedIDs, txs[i].TxID)
300 } else if i%2 == 0 { // delete after safety period
301 txs[i].BatchNum = toDeleteBatchNum
302 if i%3 == 0 {
303 txs[i].State = common.PoolL2TxStateForged
304 } else {
305 txs[i].State = common.PoolL2TxStateInvalid
306 }
307 deletedIDs = append(deletedIDs, txs[i].TxID)
308 }
309 err := l2DB.AddTxTest(txs[i])
310 assert.NoError(t, err)
311 }
312 for i := int(l2DB.maxTxs); i < len(txs); i++ {
313 // Delete after TTL
314 txs[i].Timestamp = time.Unix(time.Now().UTC().Unix()-int64(l2DB.ttl.Seconds()+float64(4*time.Second)), 0)
315 deletedIDs = append(deletedIDs, txs[i].TxID)
316 err := l2DB.AddTxTest(txs[i])
317 assert.NoError(t, err)
318 }
319 // Purge txs
320 err := l2DB.Purge(safeBatchNum - 1)
321 assert.NoError(t, err)
322 // Check results
323 for _, id := range deletedIDs {
324 tx, err := l2DB.GetTx(id)
325 if err == nil {
326 log.Debug(tx)
327 }
328 assert.Error(t, err)
329 }
330 for _, id := range keepedIDs {
331 _, err := l2DB.GetTx(id)
332 assert.NoError(t, err)
333 }
334}
335
336func TestAuth(t *testing.T) {
337 test.CleanL2DB(l2DB.DB())
338 const nAuths = 5
339 // Generate authorizations
340 auths := test.GenAuths(nAuths)
341 for i := 0; i < len(auths); i++ {
342 // Add to the DB
343 err := l2DB.AddAccountCreationAuth(auths[i])
344 assert.NoError(t, err)
345 // Fetch from DB
346 auth, err := l2DB.GetAccountCreationAuth(auths[i].EthAddr)
347 assert.NoError(t, err)
348 // Check fetched vs generated
349 assert.Equal(t, auths[i].EthAddr, auth.EthAddr)
350 assert.Equal(t, auths[i].BJJ, auth.BJJ)
351 assert.Equal(t, auths[i].Signature, auth.Signature)
352 assert.Equal(t, auths[i].Timestamp.Unix(), auths[i].Timestamp.Unix())
353 }
354}