hermez-node/db/historydb/historydb_test.go
db/historydb/historydb_test.goRaw
1package historydb
2
3import (
4 "os"
5 "testing"
6
7 "github.com/hermeznetwork/hermez-node/common"
8 dbUtils "github.com/hermeznetwork/hermez-node/db"
9 "github.com/hermeznetwork/hermez-node/log"
10 "github.com/hermeznetwork/hermez-node/test"
11 "github.com/stretchr/testify/assert"
12)
13
14var historyDB *HistoryDB
15
16// In order to run the test you need to run a Posgres DB with
17// a database named "history" that is accessible by
18// user: "hermez"
19// pass: set it using the env var POSTGRES_PASS
20// This can be achieved by running: POSTGRES_PASS=your_strong_pass && sudo docker run --rm --name hermez-db-test -p 5432:5432 -e POSTGRES_DB=history -e POSTGRES_USER=hermez -e POSTGRES_PASSWORD=$POSTGRES_PASS -d postgres && sleep 2s && sudo docker exec -it hermez-db-test psql -a history -U hermez -c "CREATE DATABASE l2;"
21// After running the test you can stop the container by running: sudo docker kill hermez-db-test
22// If you already did that for the L2DB you don't have to do it again
23
24func TestMain(m *testing.M) {
25 // init DB
26 pass := os.Getenv("POSTGRES_PASS")
27 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
28 if err != nil {
29 panic(err)
30 }
31 historyDB = NewHistoryDB(db)
32 if err != nil {
33 panic(err)
34 }
35 // Run tests
36 result := m.Run()
37 // Close DB
38 if err := db.Close(); err != nil {
39 log.Error("Error closing the history DB:", err)
40 }
41 os.Exit(result)
42}
43
44func TestBlocks(t *testing.T) {
45 var fromBlock, toBlock int64
46 fromBlock = 1
47 toBlock = 5
48 // Delete peviously created rows (clean previous test execs)
49 assert.NoError(t, historyDB.Reorg(fromBlock-1))
50 // Generate fake blocks
51 blocks := test.GenBlocks(fromBlock, toBlock)
52 // Insert blocks into DB
53 for i := 0; i < len(blocks); i++ {
54 err := historyDB.AddBlock(&blocks[i])
55 assert.NoError(t, err)
56 }
57 // Get all blocks from DB
58 fetchedBlocks, err := historyDB.GetBlocks(fromBlock, toBlock)
59 assert.Equal(t, len(blocks), len(fetchedBlocks))
60 // Compare generated vs getted blocks
61 assert.NoError(t, err)
62 for i := range fetchedBlocks {
63 assertEqualBlock(t, &blocks[i], &fetchedBlocks[i])
64 }
65 // Get blocks from the DB one by one
66 for i := fromBlock; i < toBlock; i++ {
67 fetchedBlock, err := historyDB.GetBlock(i)
68 assert.NoError(t, err)
69 assertEqualBlock(t, &blocks[i-1], fetchedBlock)
70 }
71 // Get last block
72 lastBlock, err := historyDB.GetLastBlock()
73 assert.NoError(t, err)
74 assertEqualBlock(t, &blocks[len(blocks)-1], lastBlock)
75}
76
77func assertEqualBlock(t *testing.T, expected *common.Block, actual *common.Block) {
78 assert.Equal(t, expected.EthBlockNum, actual.EthBlockNum)
79 assert.Equal(t, expected.Hash, actual.Hash)
80 assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
81}
82
83func TestBatches(t *testing.T) {
84 const fromBlock int64 = 1
85 const toBlock int64 = 3
86 // Prepare blocks in the DB
87 blocks := setTestBlocks(fromBlock, toBlock)
88 // Generate fake batches
89 const nBatches = 9
90 batches := test.GenBatches(nBatches, blocks)
91 // Test GetLastL1TxsNum with no batches
92 fetchedLastL1TxsNum, err := historyDB.GetLastL1TxsNum()
93 assert.NoError(t, err)
94 assert.Nil(t, fetchedLastL1TxsNum)
95 // Add batches to the DB
96 err = historyDB.AddBatches(batches)
97 assert.NoError(t, err)
98 // Get batches from the DB
99 fetchedBatches, err := historyDB.GetBatches(0, common.BatchNum(nBatches))
100 assert.NoError(t, err)
101 for i, fetchedBatch := range fetchedBatches {
102 assert.Equal(t, batches[i], fetchedBatch)
103 }
104 // Test GetLastBatchNum
105 fetchedLastBatchNum, err := historyDB.GetLastBatchNum()
106 assert.NoError(t, err)
107 assert.Equal(t, batches[len(batches)-1].BatchNum, fetchedLastBatchNum)
108 // Test GetLastL1TxsNum
109 fetchedLastL1TxsNum, err = historyDB.GetLastL1TxsNum()
110 assert.NoError(t, err)
111 assert.Equal(t, *batches[nBatches-1].ForgeL1TxsNum, *fetchedLastL1TxsNum)
112}
113
114func TestBids(t *testing.T) {
115 const fromBlock int64 = 1
116 const toBlock int64 = 5
117 // Prepare blocks in the DB
118 blocks := setTestBlocks(fromBlock, toBlock)
119 // Generate fake coordinators
120 const nCoords = 5
121 coords := test.GenCoordinators(nCoords, blocks)
122 err := historyDB.AddCoordinators(coords)
123 assert.NoError(t, err)
124 // Generate fake bids
125 const nBids = 20
126 bids := test.GenBids(nBids, blocks, coords)
127 err = historyDB.AddBids(bids)
128 assert.NoError(t, err)
129 // Fetch bids
130 fetchedBids, err := historyDB.GetBids()
131 assert.NoError(t, err)
132 // Compare fetched bids vs generated bids
133 for i, bid := range fetchedBids {
134 assert.Equal(t, bids[i], bid)
135 }
136}
137
138func TestTokens(t *testing.T) {
139 const fromBlock int64 = 1
140 const toBlock int64 = 5
141 // Prepare blocks in the DB
142 blocks := setTestBlocks(fromBlock, toBlock)
143 // Generate fake tokens
144 const nTokens = 5
145 tokens := test.GenTokens(nTokens, blocks)
146 err := historyDB.AddTokens(tokens)
147 assert.NoError(t, err)
148 // Fetch tokens
149 fetchedTokens, err := historyDB.GetTokens()
150 assert.NoError(t, err)
151 // Compare fetched tokens vs generated tokens
152 // All the tokens should have USDUpdate setted by the DB trigger
153 for i, token := range fetchedTokens {
154 assert.Equal(t, tokens[i].TokenID, token.TokenID)
155 assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
156 assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
157 assert.Equal(t, tokens[i].Name, token.Name)
158 assert.Equal(t, tokens[i].Symbol, token.Symbol)
159 assert.Nil(t, token.USD)
160 assert.Nil(t, token.USDUpdate)
161 }
162}
163
164func TestAccounts(t *testing.T) {
165 const fromBlock int64 = 1
166 const toBlock int64 = 5
167 // Prepare blocks in the DB
168 blocks := setTestBlocks(fromBlock, toBlock)
169 // Generate fake tokens
170 const nTokens = 5
171 tokens := test.GenTokens(nTokens, blocks)
172 err := historyDB.AddTokens(tokens)
173 assert.NoError(t, err)
174 // Generate fake batches
175 const nBatches = 10
176 batches := test.GenBatches(nBatches, blocks)
177 err = historyDB.AddBatches(batches)
178 assert.NoError(t, err)
179 // Generate fake accounts
180 const nAccounts = 3
181 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
182 err = historyDB.AddAccounts(accs)
183 assert.NoError(t, err)
184 // Fetch accounts
185 fetchedAccs, err := historyDB.GetAccounts()
186 assert.NoError(t, err)
187 // Compare fetched accounts vs generated accounts
188 for i, acc := range fetchedAccs {
189 assert.Equal(t, accs[i], acc)
190 }
191}
192
193func TestTxs(t *testing.T) {
194 const fromBlock int64 = 1
195 const toBlock int64 = 5
196 // Prepare blocks in the DB
197 blocks := setTestBlocks(fromBlock, toBlock)
198 // Generate fake tokens
199 const nTokens = 500
200 tokens := test.GenTokens(nTokens, blocks)
201 err := historyDB.AddTokens(tokens)
202 assert.NoError(t, err)
203 // Generate fake batches
204 const nBatches = 10
205 batches := test.GenBatches(nBatches, blocks)
206 err = historyDB.AddBatches(batches)
207 assert.NoError(t, err)
208 // Generate fake accounts
209 const nAccounts = 3
210 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
211 err = historyDB.AddAccounts(accs)
212 assert.NoError(t, err)
213
214 /*
215 Uncomment once the transaction generation is fixed
216 !! test that batches that forge user L1s !!
217 !! Missing tests to check that historic USD is not set if USDUpdate is too old (24h) !!
218
219 // Generate fake L1 txs
220 const nL1s = 64
221 _, l1txs := test.GenL1Txs(256, nL1s, 0, nil, accs, tokens, blocks, batches)
222 err = historyDB.AddL1Txs(l1txs)
223 assert.NoError(t, err)
224 // Generate fake L2 txs
225 const nL2s = 2048 - nL1s
226 _, l2txs := test.GenL2Txs(256, nL2s, 0, nil, accs, tokens, blocks, batches)
227 err = historyDB.AddL2Txs(l2txs)
228 assert.NoError(t, err)
229 // Compare fetched txs vs generated txs.
230 fetchAndAssertTxs(t, l1txs, l2txs)
231 // Test trigger: L1 integrity
232 // from_eth_addr can't be null
233 l1txs[0].FromEthAddr = ethCommon.Address{}
234 err = historyDB.AddL1Txs(l1txs)
235 assert.Error(t, err)
236 l1txs[0].FromEthAddr = ethCommon.BigToAddress(big.NewInt(int64(5)))
237 // from_bjj can't be null
238 l1txs[0].FromBJJ = nil
239 err = historyDB.AddL1Txs(l1txs)
240 assert.Error(t, err)
241 privK := babyjub.NewRandPrivKey()
242 l1txs[0].FromBJJ = privK.Public()
243 // load_amount can't be null
244 l1txs[0].LoadAmount = nil
245 err = historyDB.AddL1Txs(l1txs)
246 assert.Error(t, err)
247 // Test trigger: L2 integrity
248 // batch_num can't be null
249 l2txs[0].BatchNum = 0
250 err = historyDB.AddL2Txs(l2txs)
251 assert.Error(t, err)
252 l2txs[0].BatchNum = 1
253 // nonce can't be null
254 l2txs[0].Nonce = 0
255 err = historyDB.AddL2Txs(l2txs)
256 assert.Error(t, err)
257 // Test trigger: forge L1 txs
258 // add next batch to DB
259 batchNum, toForgeL1TxsNum := test.GetNextToForgeNumAndBatch(batches)
260 batch := batches[0]
261 batch.BatchNum = batchNum
262 batch.ForgeL1TxsNum = toForgeL1TxsNum
263 assert.NoError(t, historyDB.AddBatch(&batch)) // This should update nL1s / 2 rows
264 // Set batch num in txs that should have been marked as forged in the DB
265 for i := 0; i < len(l1txs); i++ {
266 fetchedTx, err := historyDB.GetTx(l1txs[i].TxID)
267 assert.NoError(t, err)
268 if l1txs[i].ToForgeL1TxsNum == toForgeL1TxsNum {
269 assert.Equal(t, batchNum, *fetchedTx.BatchNum)
270 } else {
271 if fetchedTx.BatchNum != nil {
272 assert.NotEqual(t, batchNum, *fetchedTx.BatchNum)
273 }
274 }
275 }
276
277 // Test helper functions for Synchronizer
278 // GetLastTxsPosition
279 expectedPosition := -1
280 var choosenToForgeL1TxsNum int64 = -1
281 for _, tx := range l1txs {
282 if choosenToForgeL1TxsNum == -1 && tx.ToForgeL1TxsNum > 0 {
283 choosenToForgeL1TxsNum = tx.ToForgeL1TxsNum
284 expectedPosition = tx.Position
285 } else if choosenToForgeL1TxsNum == tx.ToForgeL1TxsNum && expectedPosition < tx.Position {
286 expectedPosition = tx.Position
287 }
288 }
289 position, err := historyDB.GetLastTxsPosition(choosenToForgeL1TxsNum)
290 assert.NoError(t, err)
291 assert.Equal(t, expectedPosition, position)
292
293 // GetL1UserTxs: not needed? tests were broken
294 // txs, err := historyDB.GetL1UserTxs(2)
295 // assert.NoError(t, err)
296 // assert.NotZero(t, len(txs))
297 // assert.NoError(t, err)
298 // assert.Equal(t, 22, position)
299 // // Test Update L1 TX Batch_num
300 // assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
301 // txs[0].BatchNum = common.BatchNum(1)
302 // txs, err = historyDB.GetL1UserTxs(2)
303 // assert.NoError(t, err)
304 // assert.NotZero(t, len(txs))
305 // assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
306 */
307}
308
309/*
310func fetchAndAssertTxs(t *testing.T, l1txs []common.L1Tx, l2txs []common.L2Tx) {
311 for i := 0; i < len(l1txs); i++ {
312 tx := l1txs[i].Tx()
313 fmt.Println("ASDF", i, tx.TxID)
314 fetchedTx, err := historyDB.GetTx(tx.TxID)
315 require.NoError(t, err)
316 test.AssertUSD(t, tx.USD, fetchedTx.USD)
317 test.AssertUSD(t, tx.LoadAmountUSD, fetchedTx.LoadAmountUSD)
318 assert.Equal(t, tx, fetchedTx)
319 }
320 for i := 0; i < len(l2txs); i++ {
321 tx := l2txs[i].Tx()
322 fetchedTx, err := historyDB.GetTx(tx.TxID)
323 tx.TokenID = fetchedTx.TokenID
324 assert.NoError(t, err)
325 test.AssertUSD(t, fetchedTx.USD, tx.USD)
326 test.AssertUSD(t, fetchedTx.FeeUSD, tx.FeeUSD)
327 assert.Equal(t, tx, fetchedTx)
328 }
329}
330*/
331
332func TestExitTree(t *testing.T) {
333 nBatches := 17
334 blocks := setTestBlocks(0, 10)
335 batches := test.GenBatches(nBatches, blocks)
336 err := historyDB.AddBatches(batches)
337 const nTokens = 50
338 tokens := test.GenTokens(nTokens, blocks)
339 assert.NoError(t, historyDB.AddTokens(tokens))
340 assert.NoError(t, err)
341 const nAccounts = 3
342 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
343 assert.NoError(t, historyDB.AddAccounts(accs))
344 exitTree := test.GenExitTree(nBatches, batches, accs)
345 err = historyDB.AddExitTree(exitTree)
346 assert.NoError(t, err)
347}
348
349// setTestBlocks WARNING: this will delete the blocks and recreate them
350func setTestBlocks(from, to int64) []common.Block {
351 if err := cleanHistoryDB(); err != nil {
352 panic(err)
353 }
354 blocks := test.GenBlocks(from, to)
355 if err := historyDB.AddBlocks(blocks); err != nil {
356 panic(err)
357 }
358 return blocks
359}
360
361func cleanHistoryDB() error {
362 return historyDB.Reorg(-1)
363}