hermez-node/db/historydb/historydb.go
db/historydb/historydb.goRaw
1package historydb
2
3import (
4 "database/sql"
5 "errors"
6 "fmt"
7 "math/big"
8
9 ethCommon "github.com/ethereum/go-ethereum/common"
10 "github.com/hermeznetwork/hermez-node/common"
11 "github.com/hermeznetwork/hermez-node/db"
12 "github.com/hermeznetwork/hermez-node/log"
13 "github.com/iden3/go-iden3-crypto/babyjub"
14 "github.com/jmoiron/sqlx"
15
16 //nolint:errcheck // driver for postgres DB
17 _ "github.com/lib/pq"
18 "github.com/russross/meddler"
19)
20
21// TODO(Edu): Document here how HistoryDB is kept consistent
22
23// HistoryDB persist the historic of the rollup
24type HistoryDB struct {
25 db *sqlx.DB
26}
27
28// BlockData contains the information of a Block
29type BlockData struct {
30 Block *common.Block
31 // Rollup
32 // L1UserTxs that were submitted in the block
33 L1UserTxs []common.L1Tx
34 Batches []BatchData
35 RegisteredTokens []common.Token
36 RollupVars *common.RollupVars
37 // Auction
38 Bids []common.Bid
39 Coordinators []common.Coordinator
40 AuctionVars *common.AuctionVars
41 WithdrawDelayerVars *common.WithdrawDelayerVars
42 // TODO: enable when common.WithdrawalDelayerVars is Merged from Synchronizer PR
43 // WithdrawalDelayerVars *common.WithdrawalDelayerVars
44}
45
46// BatchData contains the information of a Batch
47type BatchData struct {
48 // L1UserTxs that were forged in the batch
49 L1Batch bool // TODO: Remove once Batch.ForgeL1TxsNum is a pointer
50 L1UserTxs []common.L1Tx
51 L1CoordinatorTxs []common.L1Tx
52 L2Txs []common.L2Tx
53 CreatedAccounts []common.Account
54 ExitTree []common.ExitInfo
55 Batch *common.Batch
56}
57
58// NewBatchData creates an empty BatchData with the slices initialized.
59func NewBatchData() *BatchData {
60 return &BatchData{
61 L1Batch: false,
62 L1UserTxs: make([]common.L1Tx, 0),
63 L1CoordinatorTxs: make([]common.L1Tx, 0),
64 L2Txs: make([]common.L2Tx, 0),
65 CreatedAccounts: make([]common.Account, 0),
66 ExitTree: make([]common.ExitInfo, 0),
67 Batch: &common.Batch{},
68 }
69}
70
71// NewHistoryDB initialize the DB
72func NewHistoryDB(db *sqlx.DB) *HistoryDB {
73 return &HistoryDB{db: db}
74}
75
76// AddBlock insert a block into the DB
77func (hdb *HistoryDB) AddBlock(block *common.Block) error { return hdb.addBlock(hdb.db, block) }
78func (hdb *HistoryDB) addBlock(d meddler.DB, block *common.Block) error {
79 return meddler.Insert(d, "block", block)
80}
81
82// AddBlocks inserts blocks into the DB
83func (hdb *HistoryDB) AddBlocks(blocks []common.Block) error {
84 return hdb.addBlocks(hdb.db, blocks)
85}
86
87func (hdb *HistoryDB) addBlocks(d meddler.DB, blocks []common.Block) error {
88 return db.BulkInsert(
89 d,
90 `INSERT INTO block (
91 eth_block_num,
92 timestamp,
93 hash
94 ) VALUES %s;`,
95 blocks[:],
96 )
97}
98
99// GetBlock retrieve a block from the DB, given a block number
100func (hdb *HistoryDB) GetBlock(blockNum int64) (*common.Block, error) {
101 block := &common.Block{}
102 err := meddler.QueryRow(
103 hdb.db, block,
104 "SELECT * FROM block WHERE eth_block_num = $1;", blockNum,
105 )
106 return block, err
107}
108
109// GetBlocks retrieve blocks from the DB, given a range of block numbers defined by from and to
110func (hdb *HistoryDB) GetBlocks(from, to int64) ([]common.Block, error) {
111 var blocks []*common.Block
112 err := meddler.QueryAll(
113 hdb.db, &blocks,
114 "SELECT * FROM block WHERE $1 <= eth_block_num AND eth_block_num < $2;",
115 from, to,
116 )
117 return db.SlicePtrsToSlice(blocks).([]common.Block), err
118}
119
120// GetLastBlock retrieve the block with the highest block number from the DB
121func (hdb *HistoryDB) GetLastBlock() (*common.Block, error) {
122 block := &common.Block{}
123 err := meddler.QueryRow(
124 hdb.db, block, "SELECT * FROM block ORDER BY eth_block_num DESC LIMIT 1;",
125 )
126 return block, err
127}
128
129// AddBatch insert a Batch into the DB
130func (hdb *HistoryDB) AddBatch(batch *common.Batch) error { return hdb.addBatch(hdb.db, batch) }
131func (hdb *HistoryDB) addBatch(d meddler.DB, batch *common.Batch) error {
132 return meddler.Insert(d, "batch", batch)
133}
134
135// AddBatches insert Bids into the DB
136func (hdb *HistoryDB) AddBatches(batches []common.Batch) error {
137 return hdb.addBatches(hdb.db, batches)
138}
139func (hdb *HistoryDB) addBatches(d meddler.DB, batches []common.Batch) error {
140 // TODO: Calculate and insert total_fees_usd
141 return db.BulkInsert(
142 d,
143 `INSERT INTO batch (
144 batch_num,
145 eth_block_num,
146 forger_addr,
147 fees_collected,
148 state_root,
149 num_accounts,
150 exit_root,
151 forge_l1_txs_num,
152 slot_num
153 ) VALUES %s;`,
154 batches[:],
155 )
156}
157
158// GetBatches retrieve batches from the DB, given a range of batch numbers defined by from and to
159func (hdb *HistoryDB) GetBatches(from, to common.BatchNum) ([]common.Batch, error) {
160 var batches []*common.Batch
161 err := meddler.QueryAll(
162 hdb.db, &batches,
163 "SELECT * FROM batch WHERE $1 <= batch_num AND batch_num < $2;",
164 from, to,
165 )
166 return db.SlicePtrsToSlice(batches).([]common.Batch), err
167}
168
169// GetLastBatchNum returns the BatchNum of the latest forged batch
170func (hdb *HistoryDB) GetLastBatchNum() (common.BatchNum, error) {
171 row := hdb.db.QueryRow("SELECT batch_num FROM batch ORDER BY batch_num DESC LIMIT 1;")
172 var batchNum common.BatchNum
173 return batchNum, row.Scan(&batchNum)
174}
175
176// GetLastL1TxsNum returns the greatest ForgeL1TxsNum in the DB. If there's no
177// batch in the DB (nil, nil) is returned.
178func (hdb *HistoryDB) GetLastL1TxsNum() (*int64, error) {
179 row := hdb.db.QueryRow("SELECT MAX(forge_l1_txs_num) FROM batch;")
180 lastL1TxsNum := new(int64)
181 return lastL1TxsNum, row.Scan(&lastL1TxsNum)
182}
183
184// Reorg deletes all the information that was added into the DB after the
185// lastValidBlock. If lastValidBlock is negative, all block information is
186// deleted.
187func (hdb *HistoryDB) Reorg(lastValidBlock int64) error {
188 var err error
189 if lastValidBlock < 0 {
190 _, err = hdb.db.Exec("DELETE FROM block;")
191 } else {
192 _, err = hdb.db.Exec("DELETE FROM block WHERE eth_block_num > $1;", lastValidBlock)
193 }
194 return err
195}
196
197// SyncPoD stores all the data that can be changed / added on a block in the PoD SC
198func (hdb *HistoryDB) SyncPoD(
199 blockNum uint64,
200 bids []common.Bid,
201 coordinators []common.Coordinator,
202 vars *common.AuctionVars,
203) error {
204 return nil
205}
206
207// AddBids insert Bids into the DB
208func (hdb *HistoryDB) AddBids(bids []common.Bid) error { return hdb.addBids(hdb.db, bids) }
209func (hdb *HistoryDB) addBids(d meddler.DB, bids []common.Bid) error {
210 // TODO: check the coordinator info
211 return db.BulkInsert(
212 d,
213 "INSERT INTO bid (slot_num, bid_value, eth_block_num, bidder_addr) VALUES %s;",
214 bids[:],
215 )
216}
217
218// GetBids return the bids
219func (hdb *HistoryDB) GetBids() ([]common.Bid, error) {
220 var bids []*common.Bid
221 err := meddler.QueryAll(
222 hdb.db, &bids,
223 "SELECT * FROM bid;",
224 )
225 return db.SlicePtrsToSlice(bids).([]common.Bid), err
226}
227
228// AddCoordinators insert Coordinators into the DB
229func (hdb *HistoryDB) AddCoordinators(coordinators []common.Coordinator) error {
230 return hdb.addCoordinators(hdb.db, coordinators)
231}
232func (hdb *HistoryDB) addCoordinators(d meddler.DB, coordinators []common.Coordinator) error {
233 return db.BulkInsert(
234 d,
235 "INSERT INTO coordinator (bidder_addr, forger_addr, eth_block_num, url) VALUES %s;",
236 coordinators[:],
237 )
238}
239
240// AddExitTree insert Exit tree into the DB
241func (hdb *HistoryDB) AddExitTree(exitTree []common.ExitInfo) error {
242 return hdb.addExitTree(hdb.db, exitTree)
243}
244func (hdb *HistoryDB) addExitTree(d meddler.DB, exitTree []common.ExitInfo) error {
245 return db.BulkInsert(
246 d,
247 "INSERT INTO exit_tree (batch_num, account_idx, merkle_proof, balance, "+
248 "instant_withdrawn, delayed_withdraw_request, delayed_withdrawn) VALUES %s;",
249 exitTree[:],
250 )
251}
252
253// AddToken insert a token into the DB
254func (hdb *HistoryDB) AddToken(token *common.Token) error {
255 return meddler.Insert(hdb.db, "token", token)
256}
257
258// AddTokens insert tokens into the DB
259func (hdb *HistoryDB) AddTokens(tokens []common.Token) error { return hdb.addTokens(hdb.db, tokens) }
260func (hdb *HistoryDB) addTokens(d meddler.DB, tokens []common.Token) error {
261 return db.BulkInsert(
262 d,
263 `INSERT INTO token (
264 token_id,
265 eth_block_num,
266 eth_addr,
267 name,
268 symbol,
269 decimals
270 ) VALUES %s;`,
271 tokens[:],
272 )
273}
274
275// UpdateTokenValue updates the USD value of a token
276func (hdb *HistoryDB) UpdateTokenValue(tokenSymbol string, value float64) error {
277 _, err := hdb.db.Exec(
278 "UPDATE token SET usd = $1 WHERE symbol = $2;",
279 value, tokenSymbol,
280 )
281 return err
282}
283
284// GetTokens returns a list of tokens from the DB
285func (hdb *HistoryDB) GetTokens() ([]TokenRead, error) {
286 var tokens []*TokenRead
287 err := meddler.QueryAll(
288 hdb.db, &tokens,
289 "SELECT * FROM token ORDER BY token_id;",
290 )
291 return db.SlicePtrsToSlice(tokens).([]TokenRead), err
292}
293
294// GetTokenSymbols returns all the token symbols from the DB
295func (hdb *HistoryDB) GetTokenSymbols() ([]string, error) {
296 var tokenSymbols []string
297 rows, err := hdb.db.Query("SELECT symbol FROM token;")
298 if err != nil {
299 return nil, err
300 }
301 sym := new(string)
302 for rows.Next() {
303 err = rows.Scan(sym)
304 if err != nil {
305 return nil, err
306 }
307 tokenSymbols = append(tokenSymbols, *sym)
308 }
309 return tokenSymbols, nil
310}
311
312// AddAccounts insert accounts into the DB
313func (hdb *HistoryDB) AddAccounts(accounts []common.Account) error {
314 return hdb.addAccounts(hdb.db, accounts)
315}
316func (hdb *HistoryDB) addAccounts(d meddler.DB, accounts []common.Account) error {
317 return db.BulkInsert(
318 d,
319 `INSERT INTO account (
320 idx,
321 token_id,
322 batch_num,
323 bjj,
324 eth_addr
325 ) VALUES %s;`,
326 accounts[:],
327 )
328}
329
330// GetAccounts returns a list of accounts from the DB
331func (hdb *HistoryDB) GetAccounts() ([]common.Account, error) {
332 var accs []*common.Account
333 err := meddler.QueryAll(
334 hdb.db, &accs,
335 "SELECT * FROM account ORDER BY idx;",
336 )
337 return db.SlicePtrsToSlice(accs).([]common.Account), err
338}
339
340// AddL1Txs inserts L1 txs to the DB. USD and LoadAmountUSD will be set automatically before storing the tx.
341// If the tx is originated by a coordinator, BatchNum must be provided. If it's originated by a user,
342// BatchNum should be null, and the value will be setted by a trigger when a batch forges the tx.
343func (hdb *HistoryDB) AddL1Txs(l1txs []common.L1Tx) error { return hdb.addL1Txs(hdb.db, l1txs) }
344
345// addL1Txs inserts L1 txs to the DB. USD and LoadAmountUSD will be set automatically before storing the tx.
346// If the tx is originated by a coordinator, BatchNum must be provided. If it's originated by a user,
347// BatchNum should be null, and the value will be setted by a trigger when a batch forges the tx.
348func (hdb *HistoryDB) addL1Txs(d meddler.DB, l1txs []common.L1Tx) error {
349 txs := []txWrite{}
350 for i := 0; i < len(l1txs); i++ {
351 af := new(big.Float).SetInt(l1txs[i].Amount)
352 amountFloat, _ := af.Float64()
353 laf := new(big.Float).SetInt(l1txs[i].LoadAmount)
354 loadAmountFloat, _ := laf.Float64()
355 txs = append(txs, txWrite{
356 // Generic
357 IsL1: true,
358 TxID: l1txs[i].TxID,
359 Type: l1txs[i].Type,
360 Position: l1txs[i].Position,
361 FromIdx: &l1txs[i].FromIdx,
362 ToIdx: l1txs[i].ToIdx,
363 Amount: l1txs[i].Amount,
364 AmountFloat: amountFloat,
365 TokenID: l1txs[i].TokenID,
366 BatchNum: l1txs[i].BatchNum,
367 EthBlockNum: l1txs[i].EthBlockNum,
368 // L1
369 ToForgeL1TxsNum: l1txs[i].ToForgeL1TxsNum,
370 UserOrigin: &l1txs[i].UserOrigin,
371 FromEthAddr: &l1txs[i].FromEthAddr,
372 FromBJJ: l1txs[i].FromBJJ,
373 LoadAmount: l1txs[i].LoadAmount,
374 LoadAmountFloat: &loadAmountFloat,
375 })
376 }
377 return hdb.addTxs(d, txs)
378}
379
380// AddL2Txs inserts L2 txs to the DB. TokenID, USD and FeeUSD will be set automatically before storing the tx.
381func (hdb *HistoryDB) AddL2Txs(l2txs []common.L2Tx) error { return hdb.addL2Txs(hdb.db, l2txs) }
382
383// addL2Txs inserts L2 txs to the DB. TokenID, USD and FeeUSD will be set automatically before storing the tx.
384func (hdb *HistoryDB) addL2Txs(d meddler.DB, l2txs []common.L2Tx) error {
385 txs := []txWrite{}
386 for i := 0; i < len(l2txs); i++ {
387 f := new(big.Float).SetInt(l2txs[i].Amount)
388 amountFloat, _ := f.Float64()
389 txs = append(txs, txWrite{
390 // Generic
391 IsL1: false,
392 TxID: l2txs[i].TxID,
393 Type: l2txs[i].Type,
394 Position: l2txs[i].Position,
395 FromIdx: &l2txs[i].FromIdx,
396 ToIdx: l2txs[i].ToIdx,
397 Amount: l2txs[i].Amount,
398 AmountFloat: amountFloat,
399 BatchNum: &l2txs[i].BatchNum,
400 EthBlockNum: l2txs[i].EthBlockNum,
401 // L2
402 Fee: &l2txs[i].Fee,
403 Nonce: &l2txs[i].Nonce,
404 })
405 }
406 return hdb.addTxs(d, txs)
407}
408
409func (hdb *HistoryDB) addTxs(d meddler.DB, txs []txWrite) error {
410 return db.BulkInsert(
411 d,
412 `INSERT INTO tx (
413 is_l1,
414 id,
415 type,
416 position,
417 from_idx,
418 to_idx,
419 amount,
420 amount_f,
421 token_id,
422 batch_num,
423 eth_block_num,
424 to_forge_l1_txs_num,
425 user_origin,
426 from_eth_addr,
427 from_bjj,
428 load_amount,
429 load_amount_f,
430 fee,
431 nonce
432 ) VALUES %s;`,
433 txs[:],
434 )
435}
436
437// // GetTxs returns a list of txs from the DB
438// func (hdb *HistoryDB) GetTxs() ([]common.Tx, error) {
439// var txs []*common.Tx
440// err := meddler.QueryAll(
441// hdb.db, &txs,
442// `SELECT * FROM tx
443// ORDER BY (batch_num, position) ASC`,
444// )
445// return db.SlicePtrsToSlice(txs).([]common.Tx), err
446// }
447
448// GetHistoryTxs returns a list of txs from the DB using the HistoryTx struct
449func (hdb *HistoryDB) GetHistoryTxs(
450 ethAddr *ethCommon.Address, bjj *babyjub.PublicKey,
451 tokenID, idx, batchNum *uint, txType *common.TxType,
452 offset, limit *uint, last bool,
453) ([]HistoryTx, int, error) {
454 if ethAddr != nil && bjj != nil {
455 return nil, 0, errors.New("ethAddr and bjj are incompatible")
456 }
457 var query string
458 var args []interface{}
459 queryStr := `SELECT tx.is_l1, tx.id, tx.type, tx.position, tx.from_idx, tx.to_idx,
460 tx.amount, tx.token_id, tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num,
461 tx.user_origin, tx.from_eth_addr, tx.from_bjj, tx.load_amount, tx.fee, tx.nonce,
462 token.token_id, token.eth_block_num AS token_block,
463 token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
464 token.usd_update, block.timestamp, count(*) OVER() AS total_items
465 FROM tx
466 INNER JOIN token ON tx.token_id = token.token_id
467 INNER JOIN block ON tx.eth_block_num = block.eth_block_num `
468 // Apply filters
469 nextIsAnd := false
470 // ethAddr filter
471 if ethAddr != nil {
472 queryStr = `WITH acc AS
473 (select idx from account where eth_addr = ?) ` + queryStr
474 queryStr += ", acc WHERE (tx.from_idx IN(acc.idx) OR tx.to_idx IN(acc.idx)) "
475 nextIsAnd = true
476 args = append(args, ethAddr)
477 } else if bjj != nil { // bjj filter
478 queryStr = `WITH acc AS
479 (select idx from account where bjj = ?) ` + queryStr
480 queryStr += ", acc WHERE (tx.from_idx IN(acc.idx) OR tx.to_idx IN(acc.idx)) "
481 nextIsAnd = true
482 args = append(args, bjj)
483 }
484 // tokenID filter
485 if tokenID != nil {
486 if nextIsAnd {
487 queryStr += "AND "
488 } else {
489 queryStr += "WHERE "
490 }
491 queryStr += "tx.token_id = ? "
492 args = append(args, tokenID)
493 nextIsAnd = true
494 }
495 // idx filter
496 if idx != nil {
497 if nextIsAnd {
498 queryStr += "AND "
499 } else {
500 queryStr += "WHERE "
501 }
502 queryStr += "(tx.from_idx = ? OR tx.to_idx = ?) "
503 args = append(args, idx, idx)
504 nextIsAnd = true
505 }
506 // batchNum filter
507 if batchNum != nil {
508 if nextIsAnd {
509 queryStr += "AND "
510 } else {
511 queryStr += "WHERE "
512 }
513 queryStr += "tx.batch_num = ? "
514 args = append(args, batchNum)
515 nextIsAnd = true
516 }
517 // txType filter
518 if txType != nil {
519 if nextIsAnd {
520 queryStr += "AND "
521 } else {
522 queryStr += "WHERE "
523 }
524 queryStr += "tx.type = ? "
525 args = append(args, txType)
526 // nextIsAnd = true
527 }
528 // pagination
529 if last {
530 queryStr += "ORDER BY (batch_num, position) DESC NULLS FIRST "
531 } else {
532 queryStr += "ORDER BY (batch_num, position) ASC NULLS LAST "
533 queryStr += fmt.Sprintf("OFFSET %d ", *offset)
534 }
535 queryStr += fmt.Sprintf("LIMIT %d;", *limit)
536 query = hdb.db.Rebind(queryStr)
537 // log.Debug(query)
538 txsPtrs := []*HistoryTx{}
539 if err := meddler.QueryAll(hdb.db, &txsPtrs, query, args...); err != nil {
540 return nil, 0, err
541 }
542 txs := db.SlicePtrsToSlice(txsPtrs).([]HistoryTx)
543 if len(txs) == 0 {
544 return nil, 0, sql.ErrNoRows
545 } else if last {
546 tmp := []HistoryTx{}
547 for i := len(txs) - 1; i >= 0; i-- {
548 tmp = append(tmp, txs[i])
549 }
550 txs = tmp
551 }
552 return txs, txs[0].TotalItems, nil
553}
554
555// // GetTx returns a tx from the DB
556// func (hdb *HistoryDB) GetTx(txID common.TxID) (*common.Tx, error) {
557// tx := new(common.Tx)
558// return tx, meddler.QueryRow(
559// hdb.db, tx,
560// "SELECT * FROM tx WHERE id = $1;",
561// txID,
562// )
563// }
564
565// // GetL1UserTxs gets L1 User Txs to be forged in a batch that will create an account
566// // TODO: This is currently not used. Figure out if it should be used somewhere or removed.
567// func (hdb *HistoryDB) GetL1UserTxs(toForgeL1TxsNum int64) ([]*common.Tx, error) {
568// var txs []*common.Tx
569// err := meddler.QueryAll(
570// hdb.db, &txs,
571// "SELECT * FROM tx WHERE to_forge_l1_txs_num = $1 AND is_l1 = TRUE AND user_origin = TRUE;",
572// toForgeL1TxsNum,
573// )
574// return txs, err
575// }
576
577// TODO: Think about chaning all the queries that return a last value, to queries that return the next valid value.
578
579// GetLastTxsPosition for a given to_forge_l1_txs_num
580func (hdb *HistoryDB) GetLastTxsPosition(toForgeL1TxsNum int64) (int, error) {
581 row := hdb.db.QueryRow("SELECT MAX(position) FROM tx WHERE to_forge_l1_txs_num = $1;", toForgeL1TxsNum)
582 var lastL1TxsPosition int
583 return lastL1TxsPosition, row.Scan(&lastL1TxsPosition)
584}
585
586// AddBlockSCData stores all the information of a block retrieved by the Synchronizer
587func (hdb *HistoryDB) AddBlockSCData(blockData *BlockData) (err error) {
588 txn, err := hdb.db.Begin()
589 if err != nil {
590 return err
591 }
592 defer func() {
593 if err != nil {
594 errRollback := txn.Rollback()
595 if errRollback != nil {
596 log.Errorw("Rollback", "err", errRollback)
597 }
598 }
599 }()
600
601 // Add block
602 err = hdb.addBlock(txn, blockData.Block)
603 if err != nil {
604 return err
605 }
606
607 // Add Coordinators
608 if len(blockData.Coordinators) > 0 {
609 err = hdb.addCoordinators(txn, blockData.Coordinators)
610 if err != nil {
611 return err
612 }
613 }
614
615 // Add Bids
616 if len(blockData.Bids) > 0 {
617 err = hdb.addBids(txn, blockData.Bids)
618 if err != nil {
619 return err
620 }
621 }
622
623 // Add Tokens
624 if len(blockData.RegisteredTokens) > 0 {
625 err = hdb.addTokens(txn, blockData.RegisteredTokens)
626 if err != nil {
627 return err
628 }
629 }
630
631 // Add l1 Txs
632 if len(blockData.L1UserTxs) > 0 {
633 err = hdb.addL1Txs(txn, blockData.L1UserTxs)
634 if err != nil {
635 return err
636 }
637 }
638
639 // Add Batches
640 for _, batch := range blockData.Batches {
641 // Add Batch: this will trigger an update on the DB
642 // that will set the batch num of forged L1 txs in this batch
643 err = hdb.addBatch(txn, batch.Batch)
644 if err != nil {
645 return err
646 }
647
648 // Add unforged l1 Txs
649 if batch.L1Batch {
650 if len(batch.L1CoordinatorTxs) > 0 {
651 err = hdb.addL1Txs(txn, batch.L1CoordinatorTxs)
652 if err != nil {
653 return err
654 }
655 }
656 }
657
658 // Add l2 Txs
659 if len(batch.L2Txs) > 0 {
660 err = hdb.addL2Txs(txn, batch.L2Txs)
661 if err != nil {
662 return err
663 }
664 }
665
666 // Add accounts
667 if len(batch.CreatedAccounts) > 0 {
668 err = hdb.addAccounts(txn, batch.CreatedAccounts)
669 if err != nil {
670 return err
671 }
672 }
673
674 // Add exit tree
675 if len(batch.ExitTree) > 0 {
676 err = hdb.addExitTree(txn, batch.ExitTree)
677 if err != nil {
678 return err
679 }
680 }
681
682 // TODO: INSERT CONTRACTS VARS
683 }
684
685 return txn.Commit()
686}