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 limit := uint(10)
149 // Fetch tokens6
150 fetchedTokens, _, err := historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
151 assert.NoError(t, err)
152 // Compare fetched tokens vs generated tokens
153 // All the tokens should have USDUpdate setted by the DB trigger
154 for i, token := range fetchedTokens {
155 assert.Equal(t, tokens[i].TokenID, token.TokenID)
156 assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
157 assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
158 assert.Equal(t, tokens[i].Name, token.Name)
159 assert.Equal(t, tokens[i].Symbol, token.Symbol)
160 assert.Nil(t, token.USD)
161 assert.Nil(t, token.USDUpdate)
162 }
163}
164
165func TestAccounts(t *testing.T) {
166 const fromBlock int64 = 1
167 const toBlock int64 = 5
168 // Prepare blocks in the DB
169 blocks := setTestBlocks(fromBlock, toBlock)
170 // Generate fake tokens
171 const nTokens = 5
172 tokens := test.GenTokens(nTokens, blocks)
173 err := historyDB.AddTokens(tokens)
174 assert.NoError(t, err)
175 // Generate fake batches
176 const nBatches = 10
177 batches := test.GenBatches(nBatches, blocks)
178 err = historyDB.AddBatches(batches)
179 assert.NoError(t, err)
180 // Generate fake accounts
181 const nAccounts = 3
182 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
183 err = historyDB.AddAccounts(accs)
184 assert.NoError(t, err)
185 // Fetch accounts
186 fetchedAccs, err := historyDB.GetAccounts()
187 assert.NoError(t, err)
188 // Compare fetched accounts vs generated accounts
189 for i, acc := range fetchedAccs {
190 accs[i].Balance = nil
191 assert.Equal(t, accs[i], acc)
192 }
193}
194
195func TestTxs(t *testing.T) {
196 const fromBlock int64 = 1
197 const toBlock int64 = 5
198 // Prepare blocks in the DB
199 blocks := setTestBlocks(fromBlock, toBlock)
200 // Generate fake tokens
201 const nTokens = 500
202 tokens := test.GenTokens(nTokens, blocks)
203 err := historyDB.AddTokens(tokens)
204 assert.NoError(t, err)
205 // Generate fake batches
206 const nBatches = 10
207 batches := test.GenBatches(nBatches, blocks)
208 err = historyDB.AddBatches(batches)
209 assert.NoError(t, err)
210 // Generate fake accounts
211 const nAccounts = 3
212 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
213 err = historyDB.AddAccounts(accs)
214 assert.NoError(t, err)
215
216 /*
217 Uncomment once the transaction generation is fixed
218 !! test that batches that forge user L1s !!
219 !! Missing tests to check that historic USD is not set if USDUpdate is too old (24h) !!
220
221 // Generate fake L1 txs
222 const nL1s = 64
223 _, l1txs := test.GenL1Txs(256, nL1s, 0, nil, accs, tokens, blocks, batches)
224 err = historyDB.AddL1Txs(l1txs)
225 assert.NoError(t, err)
226 // Generate fake L2 txs
227 const nL2s = 2048 - nL1s
228 _, l2txs := test.GenL2Txs(256, nL2s, 0, nil, accs, tokens, blocks, batches)
229 err = historyDB.AddL2Txs(l2txs)
230 assert.NoError(t, err)
231 // Compare fetched txs vs generated txs.
232 fetchAndAssertTxs(t, l1txs, l2txs)
233 // Test trigger: L1 integrity
234 // from_eth_addr can't be null
235 l1txs[0].FromEthAddr = ethCommon.Address{}
236 err = historyDB.AddL1Txs(l1txs)
237 assert.Error(t, err)
238 l1txs[0].FromEthAddr = ethCommon.BigToAddress(big.NewInt(int64(5)))
239 // from_bjj can't be null
240 l1txs[0].FromBJJ = nil
241 err = historyDB.AddL1Txs(l1txs)
242 assert.Error(t, err)
243 privK := babyjub.NewRandPrivKey()
244 l1txs[0].FromBJJ = privK.Public()
245 // load_amount can't be null
246 l1txs[0].LoadAmount = nil
247 err = historyDB.AddL1Txs(l1txs)
248 assert.Error(t, err)
249 // Test trigger: L2 integrity
250 // batch_num can't be null
251 l2txs[0].BatchNum = 0
252 err = historyDB.AddL2Txs(l2txs)
253 assert.Error(t, err)
254 l2txs[0].BatchNum = 1
255 // nonce can't be null
256 l2txs[0].Nonce = 0
257 err = historyDB.AddL2Txs(l2txs)
258 assert.Error(t, err)
259 // Test trigger: forge L1 txs
260 // add next batch to DB
261 batchNum, toForgeL1TxsNum := test.GetNextToForgeNumAndBatch(batches)
262 batch := batches[0]
263 batch.BatchNum = batchNum
264 batch.ForgeL1TxsNum = toForgeL1TxsNum
265 assert.NoError(t, historyDB.AddBatch(&batch)) // This should update nL1s / 2 rows
266 // Set batch num in txs that should have been marked as forged in the DB
267 for i := 0; i < len(l1txs); i++ {
268 fetchedTx, err := historyDB.GetTx(l1txs[i].TxID)
269 assert.NoError(t, err)
270 if l1txs[i].ToForgeL1TxsNum == toForgeL1TxsNum {
271 assert.Equal(t, batchNum, *fetchedTx.BatchNum)
272 } else {
273 if fetchedTx.BatchNum != nil {
274 assert.NotEqual(t, batchNum, *fetchedTx.BatchNum)
275 }
276 }
277 }
278
279 // Test helper functions for Synchronizer
280 // GetLastTxsPosition
281 expectedPosition := -1
282 var choosenToForgeL1TxsNum int64 = -1
283 for _, tx := range l1txs {
284 if choosenToForgeL1TxsNum == -1 && tx.ToForgeL1TxsNum > 0 {
285 choosenToForgeL1TxsNum = tx.ToForgeL1TxsNum
286 expectedPosition = tx.Position
287 } else if choosenToForgeL1TxsNum == tx.ToForgeL1TxsNum && expectedPosition < tx.Position {
288 expectedPosition = tx.Position
289 }
290 }
291 position, err := historyDB.GetLastTxsPosition(choosenToForgeL1TxsNum)
292 assert.NoError(t, err)
293 assert.Equal(t, expectedPosition, position)
294
295 // GetL1UserTxs: not needed? tests were broken
296 // txs, err := historyDB.GetL1UserTxs(2)
297 // assert.NoError(t, err)
298 // assert.NotZero(t, len(txs))
299 // assert.NoError(t, err)
300 // assert.Equal(t, 22, position)
301 // // Test Update L1 TX Batch_num
302 // assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
303 // txs[0].BatchNum = common.BatchNum(1)
304 // txs, err = historyDB.GetL1UserTxs(2)
305 // assert.NoError(t, err)
306 // assert.NotZero(t, len(txs))
307 // assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
308 */
309}
310
311/*
312func fetchAndAssertTxs(t *testing.T, l1txs []common.L1Tx, l2txs []common.L2Tx) {
313 for i := 0; i < len(l1txs); i++ {
314 tx := l1txs[i].Tx()
315 fmt.Println("ASDF", i, tx.TxID)
316 fetchedTx, err := historyDB.GetTx(tx.TxID)
317 require.NoError(t, err)
318 test.AssertUSD(t, tx.USD, fetchedTx.USD)
319 test.AssertUSD(t, tx.LoadAmountUSD, fetchedTx.LoadAmountUSD)
320 assert.Equal(t, tx, fetchedTx)
321 }
322 for i := 0; i < len(l2txs); i++ {
323 tx := l2txs[i].Tx()
324 fetchedTx, err := historyDB.GetTx(tx.TxID)
325 tx.TokenID = fetchedTx.TokenID
326 assert.NoError(t, err)
327 test.AssertUSD(t, fetchedTx.USD, tx.USD)
328 test.AssertUSD(t, fetchedTx.FeeUSD, tx.FeeUSD)
329 assert.Equal(t, tx, fetchedTx)
330 }
331}
332*/
333
334func TestExitTree(t *testing.T) {
335 nBatches := 17
336 blocks := setTestBlocks(0, 10)
337 batches := test.GenBatches(nBatches, blocks)
338 err := historyDB.AddBatches(batches)
339 const nTokens = 50
340 tokens := test.GenTokens(nTokens, blocks)
341 assert.NoError(t, historyDB.AddTokens(tokens))
342 assert.NoError(t, err)
343 const nAccounts = 3
344 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
345 assert.NoError(t, historyDB.AddAccounts(accs))
346 exitTree := test.GenExitTree(nBatches, batches, accs)
347 err = historyDB.AddExitTree(exitTree)
348 assert.NoError(t, err)
349}
350
351// setTestBlocks WARNING: this will delete the blocks and recreate them
352func setTestBlocks(from, to int64) []common.Block {
353 if err := cleanHistoryDB(); err != nil {
354 panic(err)
355 }
356 blocks := test.GenBlocks(from, to)
357 if err := historyDB.AddBlocks(blocks); err != nil {
358 panic(err)
359 }
360 return blocks
361}
362
363func cleanHistoryDB() error {
364 return historyDB.Reorg(-1)
365}