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