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
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 float32) 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}