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// 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}