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