arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
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}