hermez-node/db/historydb/historydb_test.go
db/historydb/historydb_test.goRaw
1package historydb
2
3import (
4 "fmt"
5 "math/big"
6 "os"
7 "testing"
8 "time"
9
10 eth "github.com/ethereum/go-ethereum/common"
11 "github.com/hermeznetwork/hermez-node/common"
12 "github.com/hermeznetwork/hermez-node/db"
13 "github.com/stretchr/testify/assert"
14)
15
16var historyDB *HistoryDB
17
18// In order to run the test you need to run a Posgres DB with
19// a database named "history" that is accessible by
20// user: "hermez"
21// pass: set it using the env var POSTGRES_PASS
22// 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;"
23// After running the test you can stop the container by running: sudo docker kill hermez-db-test
24// If you already did that for the L2DB you don't have to do it again
25
26func TestMain(m *testing.M) {
27 // init DB
28 var err error
29 pass := os.Getenv("POSTGRES_PASS")
30 historyDB, err = NewHistoryDB(5432, "localhost", "hermez", pass, "history")
31 if err != nil {
32 panic(err)
33 }
34 // Run tests
35 result := m.Run()
36 // Close DB
37 if err := historyDB.Close(); err != nil {
38 fmt.Println("Error closing the history DB:", err)
39 }
40 os.Exit(result)
41}
42
43func TestBlocks(t *testing.T) {
44 var fromBlock, toBlock int64
45 fromBlock = 1
46 toBlock = 5
47 // Delete peviously created rows (clean previous test execs)
48 assert.NoError(t, historyDB.Reorg(fromBlock-1))
49 // Generate fake blocks
50 blocks := genBlocks(fromBlock, toBlock)
51 // Insert blocks into DB
52 for i := 0; i < len(blocks); i++ {
53 err := historyDB.AddBlock(&blocks[i])
54 assert.NoError(t, err)
55 }
56 // Get all blocks from DB
57 fetchedBlocks, err := historyDB.GetBlocks(fromBlock, toBlock)
58 assert.Equal(t, len(blocks), len(fetchedBlocks))
59 // Compare generated vs getted blocks
60 assert.NoError(t, err)
61 for i, fetchedBlock := range fetchedBlocks {
62 assertEqualBlock(t, &blocks[i], fetchedBlock)
63 }
64 // Get blocks from the DB one by one
65 for i := fromBlock; i < toBlock; i++ {
66 fetchedBlock, err := historyDB.GetBlock(i)
67 assert.NoError(t, err)
68 assertEqualBlock(t, &blocks[i-1], fetchedBlock)
69 }
70 // Get last block
71 lastBlock, err := historyDB.GetLastBlock()
72 assert.NoError(t, err)
73 assertEqualBlock(t, &blocks[len(blocks)-1], lastBlock)
74}
75
76func assertEqualBlock(t *testing.T, expected *common.Block, actual *common.Block) {
77 assert.Equal(t, expected.EthBlockNum, actual.EthBlockNum)
78 assert.Equal(t, expected.Hash, actual.Hash)
79 assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
80}
81
82func TestBatches(t *testing.T) {
83 const fromBlock int64 = 1
84 const toBlock int64 = 3
85 const nBatchesPerBlock = 3
86 // Prepare blocks in the DB
87 setTestBlocks(fromBlock, toBlock)
88 // Generate fake batches
89 var batches []common.Batch
90 collectedFees := make(map[common.TokenID]*big.Int)
91 for i := 0; i < 64; i++ {
92 collectedFees[common.TokenID(i)] = big.NewInt(int64(i))
93 }
94 for i := fromBlock; i < toBlock; i++ {
95 for j := 0; j < nBatchesPerBlock; j++ {
96 batch := common.Batch{
97 BatchNum: common.BatchNum(int(i-1)*nBatchesPerBlock + j),
98 EthBlockNum: int64(i),
99 ForgerAddr: eth.BigToAddress(big.NewInt(239457111187)),
100 CollectedFees: collectedFees,
101 StateRoot: common.Hash([]byte("duhdqlwiucgwqeiu")),
102 NumAccounts: j,
103 ExitRoot: common.Hash([]byte("tykertheuhtgenuer3iuw3b")),
104 SlotNum: common.SlotNum(j),
105 }
106 if j%2 == 0 {
107 batch.ForgeL1TxsNum = uint32(i)
108 }
109 batches = append(batches, batch)
110 }
111 }
112 // Add batches to the DB
113 err := historyDB.addBatches(batches)
114 assert.NoError(t, err)
115 // Get batches from the DB
116 fetchedBatches, err := historyDB.GetBatches(0, common.BatchNum(int(toBlock-fromBlock)*nBatchesPerBlock))
117 assert.NoError(t, err)
118 for i, fetchedBatch := range fetchedBatches {
119 assert.Equal(t, batches[i], *fetchedBatch)
120 }
121 // Test GetLastBatchNum
122 fetchedLastBatchNum, err := historyDB.GetLastBatchNum()
123 assert.NoError(t, err)
124 assert.Equal(t, batches[len(batches)-1].BatchNum, fetchedLastBatchNum)
125 // Test GetLastL1TxsNum
126 fetchedLastL1TxsNum, err := historyDB.GetLastL1TxsNum()
127 assert.NoError(t, err)
128 assert.Equal(t, batches[len(batches)-1-(int(toBlock-fromBlock+1)%nBatchesPerBlock)].ForgeL1TxsNum, fetchedLastL1TxsNum)
129}
130
131func TestBids(t *testing.T) {
132 const fromBlock int64 = 1
133 const toBlock int64 = 5
134 const bidsPerSlot = 5
135 // Prepare blocks in the DB
136 setTestBlocks(fromBlock, toBlock)
137 // Generate fake bids
138 bids := make([]common.Bid, 0, (toBlock-fromBlock)*bidsPerSlot)
139 for i := fromBlock; i < toBlock; i++ {
140 for j := 0; j < bidsPerSlot; j++ {
141 bids = append(bids, common.Bid{
142 SlotNum: common.SlotNum(i),
143 BidValue: big.NewInt(int64(j)),
144 EthBlockNum: i,
145 ForgerAddr: eth.BigToAddress(big.NewInt(int64(j))),
146 })
147 }
148 }
149 err := historyDB.addBids(bids)
150 assert.NoError(t, err)
151 // Fetch bids
152 var fetchedBids []*common.Bid
153 for i := fromBlock; i < toBlock; i++ {
154 fetchedBidsSlot, err := historyDB.GetBidsBySlot(common.SlotNum(i))
155 assert.NoError(t, err)
156 fetchedBids = append(fetchedBids, fetchedBidsSlot...)
157 }
158 // Compare fetched bids vs generated bids
159 for i, bid := range fetchedBids {
160 assert.Equal(t, bids[i], *bid)
161 }
162}
163
164// setTestBlocks WARNING: this will delete the blocks and recreate them
165func setTestBlocks(from, to int64) {
166 if from == 0 {
167 if err := historyDB.Reorg(from); err != nil {
168 panic(err)
169 }
170 } else {
171 if err := historyDB.Reorg(from - 1); err != nil {
172 panic(err)
173 }
174 }
175 blocks := genBlocks(from, to)
176 if err := addBlocks(blocks); err != nil {
177 panic(err)
178 }
179}
180
181func genBlocks(from, to int64) []common.Block {
182 var blocks []common.Block
183 for i := from; i < to; i++ {
184 blocks = append(blocks, common.Block{
185 EthBlockNum: i,
186 Timestamp: time.Now().Add(time.Second * 13).UTC(),
187 Hash: eth.BigToHash(big.NewInt(int64(i))),
188 })
189 }
190 return blocks
191}
192
193// addBlocks insert blocks into the DB. TODO: move method to test
194func addBlocks(blocks []common.Block) error {
195 return db.BulkInsert(
196 historyDB.db,
197 "INSERT INTO block (eth_block_num, timestamp, hash) VALUES %s",
198 blocks[:],
199 )
200}