hermez-node/db/l2db/l2db.go
db/l2db/l2db.goRaw
1package l2db
2
3import (
4 "fmt"
5 "strconv"
6 "time"
7
8 eth "github.com/ethereum/go-ethereum/common"
9 "github.com/gobuffalo/packr/v2"
10 "github.com/hermeznetwork/hermez-node/common"
11 "github.com/hermeznetwork/hermez-node/db"
12 "github.com/jmoiron/sqlx"
13
14 //nolint:errcheck // driver for postgres DB
15 _ "github.com/lib/pq"
16 migrate "github.com/rubenv/sql-migrate"
17 "github.com/russross/meddler"
18)
19
20// L2DB stores L2 txs and authorization registers received by the coordinator and keeps them until they are no longer relevant
21// due to them being forged or invalid after a safety period
22type L2DB struct {
23 db *sqlx.DB
24 safetyPeriod uint16
25 ttl time.Duration
26 maxTxs uint32
27}
28
29// NewL2DB creates a L2DB.
30// More info on how to set dbDialect and dbArgs here: http://gorm.io/docs/connecting_to_the_database.html
31// safetyPeriod is the amount of blockchain blocks that must be waited before deleting anything (to avoid reorg problems).
32// maxTxs indicates the desired maximum amount of txs stored on the L2DB.
33// TTL indicates the maximum amount of time that a tx can be in the L2DB
34// (to prevent tx that won't ever be forged to stay there, will be used if maxTxs is exceeded).
35// autoPurgePeriod will be used as delay between calls to Purge. If the value is 0, it will be disabled.
36func NewL2DB(
37 port int, host, user, password, dbname string,
38 safetyPeriod uint16,
39 maxTxs uint32,
40 TTL time.Duration,
41) (*L2DB, error) {
42 // init meddler
43 db.InitMeddler()
44 meddler.Default = meddler.PostgreSQL
45 // Stablish DB connection
46 psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)
47 db, err := sqlx.Connect("postgres", psqlconn)
48 if err != nil {
49 return nil, err
50 }
51
52 // Run DB migrations
53 migrations := &migrate.PackrMigrationSource{
54 Box: packr.New("history-migrations", "./migrations"),
55 }
56 if _, err := migrate.Exec(db.DB, "postgres", migrations, migrate.Up); err != nil {
57 return nil, err
58 }
59
60 return &L2DB{
61 db: db,
62 safetyPeriod: safetyPeriod,
63 ttl: TTL,
64 maxTxs: maxTxs,
65 }, nil
66}
67
68// DB returns a pointer to the L2DB.db. This method should be used only for
69// internal testing purposes.
70func (l2db *L2DB) DB() *sqlx.DB {
71 return l2db.db
72}
73
74// AddTx inserts a tx into the L2DB
75func (l2db *L2DB) AddTx(tx *common.PoolL2Tx) error {
76 return meddler.Insert(l2db.db, "tx_pool", tx)
77}
78
79// AddAccountCreationAuth inserts an account creation authorization into the DB
80func (l2db *L2DB) AddAccountCreationAuth(auth *common.AccountCreationAuth) error {
81 // TODO: impl
82 return nil
83}
84
85// GetTx return the specified Tx
86func (l2db *L2DB) GetTx(txID common.TxID) (*common.PoolL2Tx, error) {
87 tx := new(common.PoolL2Tx)
88 return tx, meddler.QueryRow(
89 l2db.db, tx,
90 "SELECT * FROM tx_pool WHERE tx_id = $1;",
91 txID,
92 )
93}
94
95// GetPendingTxs return all the pending txs of the L2DB
96func (l2db *L2DB) GetPendingTxs() ([]*common.PoolL2Tx, error) {
97 var txs []*common.PoolL2Tx
98 err := meddler.QueryAll(
99 l2db.db, &txs,
100 "SELECT * FROM tx_pool WHERE state = $1",
101 common.PoolL2TxStatePending,
102 )
103 return txs, err
104}
105
106// GetAccountCreationAuth return the authorization to make registers of an Ethereum address
107func (l2db *L2DB) GetAccountCreationAuth(ethAddr eth.Address) (*common.AccountCreationAuth, error) {
108 // TODO: impl
109 return nil, nil
110}
111
112// StartForging updates the state of the transactions that will begin the forging process.
113// The state of the txs referenced by txIDs will be changed from Pending -> Forging
114func (l2db *L2DB) StartForging(txIDs []common.TxID, batchNum common.BatchNum) error {
115 query, args, err := sqlx.In(
116 `UPDATE tx_pool
117 SET state = ?, batch_num = ?
118 WHERE state = ? AND tx_id IN (?);`,
119 string(common.PoolL2TxStateForging),
120 strconv.Itoa(int(batchNum)),
121 string(common.PoolL2TxStatePending),
122 txIDs,
123 )
124 if err != nil {
125 return err
126 }
127 query = l2db.db.Rebind(query)
128 _, err = l2db.db.Exec(query, args...)
129 return err
130}
131
132// DoneForging updates the state of the transactions that have been forged
133// so the state of the txs referenced by txIDs will be changed from Forging -> Forged
134func (l2db *L2DB) DoneForging(txIDs []common.TxID) error {
135 // TODO: impl
136 return nil
137}
138
139// InvalidateTxs updates the state of the transactions that are invalid.
140// The state of the txs referenced by txIDs will be changed from * -> Invalid
141func (l2db *L2DB) InvalidateTxs(txIDs []common.TxID) error {
142 return nil
143}
144
145// CheckNonces invalidate txs with nonces that are smaller than their respective accounts nonces.
146// The state of the affected txs will be changed from Pending -> Invalid
147func (l2db *L2DB) CheckNonces(updatedAccounts []common.Account) error {
148 // TODO: impl
149 return nil
150}
151
152// GetTxsByAbsoluteFeeUpdate return the txs that have an AbsoluteFee updated before olderThan
153func (l2db *L2DB) GetTxsByAbsoluteFeeUpdate(olderThan time.Time) ([]*common.PoolL2Tx, error) {
154 // TODO: impl
155 return nil, nil
156}
157
158// UpdateTxs update existing txs from the pool (TxID must exist)
159func (l2db *L2DB) UpdateTxs(txs []*common.PoolL2Tx) error {
160 // TODO: impl
161 return nil
162}
163
164// Reorg updates the state of txs that were updated in a batch that has been discarted due to a blockchain reorg.
165// The state of the affected txs can change form Forged -> Pending or from Invalid -> Pending
166func (l2db *L2DB) Reorg(lastValidBatch common.BatchNum) error {
167 // TODO: impl
168 return nil
169}
170
171// Purge deletes transactions that have been forged or marked as invalid for longer than the safety period
172// it also deletes txs that has been in the L2DB for longer than the ttl if maxTxs has been exceeded
173func (l2db *L2DB) Purge() error {
174 // TODO: impl
175 return nil
176}
177
178// Close frees the resources used by the L2DB
179func (l2db *L2DB) Close() error {
180 return l2db.db.Close()
181}