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
131func (hdb *HistoryDB) GetLastL1TxsNum() (uint32, error) {
132 row := hdb.db.QueryRow("SELECT MAX(forge_l1_txs_num) FROM batch;")
133 var lastL1TxsNum uint32
134 return lastL1TxsNum, row.Scan(&lastL1TxsNum)
135}
136
137// Reorg deletes all the information that was added into the DB after the lastValidBlock
138func (hdb *HistoryDB) Reorg(lastValidBlock int64) error {
139 _, err := hdb.db.Exec("DELETE FROM block WHERE eth_block_num > $1;", lastValidBlock)
140 return err
141}
142
143// SyncRollup stores all the data that can be changed / added on a block in the Rollup SC
144func (hdb *HistoryDB) SyncRollup(
145 blockNum uint64,
146 l1txs []common.L1Tx,
147 l2txs []common.L2Tx,
148 registeredAccounts []common.Account,
149 exitTree common.ExitInfo,
150 withdrawals common.ExitInfo,
151 registeredTokens []common.Token,
152 batches []common.Batch,
153 vars *common.RollupVars,
154) error {
155 // TODO: make all in a single DB commit
156 if err := hdb.AddBatches(batches); err != nil {
157 return err
158 }
159 return nil
160}
161
162// SyncPoD stores all the data that can be changed / added on a block in the PoD SC
163func (hdb *HistoryDB) SyncPoD(
164 blockNum uint64,
165 bids []common.Bid,
166 coordinators []common.Coordinator,
167 vars *common.AuctionVars,
168) error {
169 return nil
170}
171
172// addBids insert Bids into the DB
173func (hdb *HistoryDB) addBids(bids []common.Bid) error {
174 // TODO: check the coordinator info
175 return db.BulkInsert(
176 hdb.db,
177 "INSERT INTO bid (slot_num, forger_addr, bid_value, eth_block_num) VALUES %s",
178 bids[:],
179 )
180}
181
182// GetBids return the bids
183func (hdb *HistoryDB) GetBids() ([]*common.Bid, error) {
184 var bids []*common.Bid
185 err := meddler.QueryAll(
186 hdb.db, &bids,
187 "SELECT * FROM bid;",
188 )
189 return bids, err
190}
191
192// AddToken insert a token into the DB
193func (hdb *HistoryDB) AddToken(token *common.Token) error {
194 return meddler.Insert(hdb.db, "token", token)
195}
196
197// AddTokens insert tokens into the DB
198func (hdb *HistoryDB) AddTokens(tokens []common.Token) error {
199 return db.BulkInsert(
200 hdb.db,
201 `INSERT INTO token (
202 token_id,
203 eth_block_num,
204 eth_addr,
205 name,
206 symbol,
207 decimals,
208 usd,
209 usd_update
210 ) VALUES %s;`,
211 tokens[:],
212 )
213}
214
215// UpdateTokenValue updates the USD value of a token
216func (hdb *HistoryDB) UpdateTokenValue(tokenID common.TokenID, value float64) error {
217 _, err := hdb.db.Exec(
218 "UPDATE token SET usd = $1 WHERE token_id = $2;",
219 value, tokenID,
220 )
221 return err
222}
223
224// GetTokens returns a list of tokens from the DB
225func (hdb *HistoryDB) GetTokens() ([]*common.Token, error) {
226 var tokens []*common.Token
227 err := meddler.QueryAll(
228 hdb.db, &tokens,
229 "SELECT * FROM token ORDER BY token_id;",
230 )
231 return tokens, err
232}
233
234// AddAccounts insert accounts into the DB
235func (hdb *HistoryDB) AddAccounts(accounts []common.Account) error {
236 return db.BulkInsert(
237 hdb.db,
238 `INSERT INTO account (
239 idx,
240 token_id,
241 batch_num,
242 bjj,
243 eth_addr
244 ) VALUES %s;`,
245 accounts[:],
246 )
247}
248
249// GetAccounts returns a list of accounts from the DB
250func (hdb *HistoryDB) GetAccounts() ([]*common.Account, error) {
251 var accs []*common.Account
252 err := meddler.QueryAll(
253 hdb.db, &accs,
254 "SELECT * FROM account ORDER BY idx;",
255 )
256 return accs, err
257}
258
259// AddL1Txs inserts L1 txs to the DB
260func (hdb *HistoryDB) AddL1Txs(l1txs []common.L1Tx) error {
261 txs := []common.Tx{}
262 for _, tx := range l1txs {
263 txs = append(txs, *tx.Tx())
264 }
265 return hdb.AddTxs(txs)
266}
267
268// AddL2Txs inserts L2 txs to the DB
269func (hdb *HistoryDB) AddL2Txs(l2txs []common.L2Tx) error {
270 txs := []common.Tx{}
271 for _, tx := range l2txs {
272 txs = append(txs, *tx.Tx())
273 }
274 return hdb.AddTxs(txs)
275}
276
277// AddTxs insert L1 txs into the DB
278func (hdb *HistoryDB) AddTxs(txs []common.Tx) error {
279 return db.BulkInsert(
280 hdb.db,
281 `INSERT INTO tx (
282 is_l1,
283 id,
284 type,
285 position,
286 from_idx,
287 to_idx,
288 amount,
289 amount_f,
290 token_id,
291 amount_usd,
292 batch_num,
293 eth_block_num,
294 to_forge_l1_txs_num,
295 user_origin,
296 from_eth_addr,
297 from_bjj,
298 load_amount,
299 load_amount_f,
300 load_amount_usd,
301 fee,
302 fee_usd,
303 nonce
304 ) VALUES %s;`,
305 txs[:],
306 )
307}
308
309// GetTxs returns a list of txs from the DB
310func (hdb *HistoryDB) GetTxs() ([]*common.Tx, error) {
311 var txs []*common.Tx
312 err := meddler.QueryAll(
313 hdb.db, &txs,
314 `SELECT * FROM tx
315 ORDER BY (batch_num, position) ASC`,
316 )
317 return txs, err
318}
319
320// GetTx returns a tx from the DB
321func (hdb *HistoryDB) GetTx(txID common.TxID) (*common.Tx, error) {
322 tx := new(common.Tx)
323 return tx, meddler.QueryRow(
324 hdb.db, tx,
325 "SELECT * FROM tx WHERE id = $1;",
326 txID,
327 )
328}
329
330// Close frees the resources used by HistoryDB
331func (hdb *HistoryDB) Close() error {
332 return hdb.db.Close()
333}