hermez-node/db/historydb/historydb.go
db/historydb/historydb.goRaw
1package historydb
2
3import (
4 "fmt"
5
6 "github.com/gobuffalo/packr/v2"
7 "github.com/hermeznetwork/hermez-node/common"
8 "github.com/hermeznetwork/hermez-node/db"
9 "github.com/jmoiron/sqlx"
10
11 //nolint:errcheck // driver for postgres DB
12 _ "github.com/lib/pq"
13 migrate "github.com/rubenv/sql-migrate"
14 "github.com/russross/meddler"
15)
16
17// HistoryDB persist the historic of the rollup
18type HistoryDB struct {
19 db *sqlx.DB
20}
21
22// NewHistoryDB initialize the DB
23func NewHistoryDB(port int, host, user, password, dbname string) (*HistoryDB, error) {
24 // Connect to DB
25 psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)
26 hdb, err := sqlx.Connect("postgres", psqlconn)
27 if err != nil {
28 return nil, err
29 }
30 // Init meddler
31 db.InitMeddler()
32 meddler.Default = meddler.PostgreSQL
33
34 // Run DB migrations
35 migrations := &migrate.PackrMigrationSource{
36 Box: packr.New("history-migrations", "./migrations"),
37 }
38 if _, err := migrate.Exec(hdb.DB, "postgres", migrations, migrate.Up); err != nil {
39 return nil, err
40 }
41
42 return &HistoryDB{hdb}, nil
43}
44
45// AddBlock insert a block into the DB
46func (hdb *HistoryDB) AddBlock(block *common.Block) error {
47 return meddler.Insert(hdb.db, "block", block)
48}
49
50// AddBlocks inserts blocks into the DB
51func (hdb *HistoryDB) AddBlocks(blocks []common.Block) error {
52 return db.BulkInsert(
53 hdb.db,
54 `INSERT INTO block (
55 eth_block_num,
56 timestamp,
57 hash
58 ) VALUES %s;`,
59 blocks[:],
60 )
61}
62
63// GetBlock retrieve a block from the DB, given a block number
64func (hdb *HistoryDB) GetBlock(blockNum int64) (*common.Block, error) {
65 block := &common.Block{}
66 err := meddler.QueryRow(
67 hdb.db, block,
68 "SELECT * FROM block WHERE eth_block_num = $1;", blockNum,
69 )
70 return block, err
71}
72
73// GetBlocks retrieve blocks from the DB, given a range of block numbers defined by from and to
74func (hdb *HistoryDB) GetBlocks(from, to int64) ([]*common.Block, error) {
75 var blocks []*common.Block
76 err := meddler.QueryAll(
77 hdb.db, &blocks,
78 "SELECT * FROM block WHERE $1 <= eth_block_num AND eth_block_num < $2",
79 from, to,
80 )
81 return blocks, err
82}
83
84// GetLastBlock retrieve the block with the highest block number from the DB
85func (hdb *HistoryDB) GetLastBlock() (*common.Block, error) {
86 block := &common.Block{}
87 err := meddler.QueryRow(
88 hdb.db, block, "SELECT * FROM block ORDER BY eth_block_num DESC LIMIT 1;",
89 )
90 return block, err
91}
92
93// AddBatches insert Bids into the DB
94func (hdb *HistoryDB) AddBatches(batches []common.Batch) error {
95 return db.BulkInsert(
96 hdb.db,
97 `INSERT INTO batch (
98 batch_num,
99 eth_block_num,
100 forger_addr,
101 fees_collected,
102 state_root,
103 num_accounts,
104 exit_root,
105 forge_l1_txs_num,
106 slot_num
107 ) VALUES %s;`,
108 batches[:],
109 )
110}
111
112// GetBatches retrieve batches from the DB, given a range of batch numbers defined by from and to
113func (hdb *HistoryDB) GetBatches(from, to common.BatchNum) ([]*common.Batch, error) {
114 var batches []*common.Batch
115 err := meddler.QueryAll(
116 hdb.db, &batches,
117 "SELECT * FROM batch WHERE $1 <= batch_num AND batch_num < $2",
118 from, to,
119 )
120 return batches, err
121}
122
123// GetLastBatchNum returns the BatchNum of the latest forged batch
124func (hdb *HistoryDB) GetLastBatchNum() (common.BatchNum, error) {
125 row := hdb.db.QueryRow("SELECT batch_num FROM batch ORDER BY batch_num DESC LIMIT 1;")
126 var batchNum common.BatchNum
127 return batchNum, row.Scan(&batchNum)
128}
129
130// GetLastL1TxsNum returns the greatest ForgeL1TxsNum in the DB. If there's no
131// batch in the DB (nil, nil) is returned.
132func (hdb *HistoryDB) GetLastL1TxsNum() (*uint32, error) {
133 row := hdb.db.QueryRow("SELECT MAX(forge_l1_txs_num) FROM batch;")
134 lastL1TxsNum := new(uint32)
135 return lastL1TxsNum, row.Scan(&lastL1TxsNum)
136}
137
138// Reorg deletes all the information that was added into the DB after the lastValidBlock
139func (hdb *HistoryDB) Reorg(lastValidBlock int64) error {
140 _, err := hdb.db.Exec("DELETE FROM block WHERE eth_block_num > $1;", lastValidBlock)
141 return err
142}
143
144// SyncRollup stores all the data that can be changed / added on a block in the Rollup SC
145func (hdb *HistoryDB) SyncRollup(
146 blockNum uint64,
147 l1txs []common.L1Tx,
148 l2txs []common.L2Tx,
149 registeredAccounts []common.Account,
150 exitTree common.ExitInfo,
151 withdrawals common.ExitInfo,
152 registeredTokens []common.Token,
153 batches []common.Batch,
154 vars *common.RollupVars,
155) error {
156 // TODO: make all in a single DB commit
157 if err := hdb.AddBatches(batches); err != nil {
158 return err
159 }
160 return nil
161}
162
163// SyncPoD stores all the data that can be changed / added on a block in the PoD SC
164func (hdb *HistoryDB) SyncPoD(
165 blockNum uint64,
166 bids []common.Bid,
167 coordinators []common.Coordinator,
168 vars *common.AuctionVars,
169) error {
170 return nil
171}
172
173// addBids insert Bids into the DB
174func (hdb *HistoryDB) addBids(bids []common.Bid) error {
175 // TODO: check the coordinator info
176 return db.BulkInsert(
177 hdb.db,
178 "INSERT INTO bid (slot_num, forger_addr, bid_value, eth_block_num) VALUES %s",
179 bids[:],
180 )
181}
182
183// GetBids return the bids
184func (hdb *HistoryDB) GetBids() ([]*common.Bid, error) {
185 var bids []*common.Bid
186 err := meddler.QueryAll(
187 hdb.db, &bids,
188 "SELECT * FROM bid;",
189 )
190 return bids, err
191}
192
193// AddToken insert a token into the DB
194func (hdb *HistoryDB) AddToken(token *common.Token) error {
195 return meddler.Insert(hdb.db, "token", token)
196}
197
198// AddTokens insert tokens into the DB
199func (hdb *HistoryDB) AddTokens(tokens []common.Token) error {
200 return db.BulkInsert(
201 hdb.db,
202 `INSERT INTO token (
203 token_id,
204 eth_block_num,
205 eth_addr,
206 name,
207 symbol,
208 decimals,
209 usd,
210 usd_update
211 ) VALUES %s;`,
212 tokens[:],
213 )
214}
215
216// UpdateTokenValue updates the USD value of a token
217func (hdb *HistoryDB) UpdateTokenValue(tokenID common.TokenID, value float32) error {
218 _, err := hdb.db.Exec(
219 "UPDATE token SET usd = $1 WHERE token_id = $2;",
220 value, tokenID,
221 )
222 return err
223}
224
225// GetTokens returns a list of tokens from the DB
226func (hdb *HistoryDB) GetTokens() ([]*common.Token, error) {
227 var tokens []*common.Token
228 err := meddler.QueryAll(
229 hdb.db, &tokens,
230 "SELECT * FROM token ORDER BY token_id;",
231 )
232 return tokens, err
233}
234
235// AddAccounts insert accounts into the DB
236func (hdb *HistoryDB) AddAccounts(accounts []common.Account) error {
237 return db.BulkInsert(
238 hdb.db,
239 `INSERT INTO account (
240 idx,
241 token_id,
242 batch_num,
243 bjj,
244 eth_addr
245 ) VALUES %s;`,
246 accounts[:],
247 )
248}
249
250// GetAccounts returns a list of accounts from the DB
251func (hdb *HistoryDB) GetAccounts() ([]*common.Account, error) {
252 var accs []*common.Account
253 err := meddler.QueryAll(
254 hdb.db, &accs,
255 "SELECT * FROM account ORDER BY idx;",
256 )
257 return accs, err
258}
259
260// AddL1Txs inserts L1 txs to the DB
261func (hdb *HistoryDB) AddL1Txs(l1txs []common.L1Tx) error {
262 txs := []common.Tx{}
263 for _, tx := range l1txs {
264 txs = append(txs, *tx.Tx())
265 }
266 return hdb.AddTxs(txs)
267}
268
269// AddL2Txs inserts L2 txs to the DB
270func (hdb *HistoryDB) AddL2Txs(l2txs []common.L2Tx) error {
271 txs := []common.Tx{}
272 for _, tx := range l2txs {
273 txs = append(txs, *tx.Tx())
274 }
275 return hdb.AddTxs(txs)
276}
277
278// AddTxs insert L1 txs into the DB
279func (hdb *HistoryDB) AddTxs(txs []common.Tx) error {
280 return db.BulkInsert(
281 hdb.db,
282 `INSERT INTO tx (
283 is_l1,
284 id,
285 type,
286 position,
287 from_idx,
288 to_idx,
289 amount,
290 amount_f,
291 token_id,
292 amount_usd,
293 batch_num,
294 eth_block_num,
295 to_forge_l1_txs_num,
296 user_origin,
297 from_eth_addr,
298 from_bjj,
299 load_amount,
300 load_amount_f,
301 load_amount_usd,
302 fee,
303 fee_usd,
304 nonce
305 ) VALUES %s;`,
306 txs[:],
307 )
308}
309
310// GetTxs returns a list of txs from the DB
311func (hdb *HistoryDB) GetTxs() ([]*common.Tx, error) {
312 var txs []*common.Tx
313 err := meddler.QueryAll(
314 hdb.db, &txs,
315 `SELECT * FROM tx
316 ORDER BY (batch_num, position) ASC`,
317 )
318 return txs, err
319}
320
321// GetTx returns a tx from the DB
322func (hdb *HistoryDB) GetTx(txID common.TxID) (*common.Tx, error) {
323 tx := new(common.Tx)
324 return tx, meddler.QueryRow(
325 hdb.db, tx,
326 "SELECT * FROM tx WHERE id = $1;",
327 txID,
328 )
329}
330
331// Close frees the resources used by HistoryDB
332func (hdb *HistoryDB) Close() error {
333 return hdb.db.Close()
334}