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// AddTx inserts a tx into the L2DB
69func (l2db *L2DB) AddTx(tx *common.PoolL2Tx) error {
70 return meddler.Insert(l2db.db, "tx_pool", tx)
71}
72
73// AddAccountCreationAuth inserts an account creation authorization into the DB
74func (l2db *L2DB) AddAccountCreationAuth(auth *common.AccountCreationAuth) error {
75 // TODO: impl
76 return nil
77}
78
79// GetTx return the specified Tx
80func (l2db *L2DB) GetTx(txID common.TxID) (*common.PoolL2Tx, error) {
81 tx := new(common.PoolL2Tx)
82 return tx, meddler.QueryRow(
83 l2db.db, tx,
84 "SELECT * FROM tx_pool WHERE tx_id = $1;",
85 txID,
86 )
87}
88
89// GetPendingTxs return all the pending txs of the L2DB
90func (l2db *L2DB) GetPendingTxs() ([]*common.PoolL2Tx, error) {
91 var txs []*common.PoolL2Tx
92 err := meddler.QueryAll(
93 l2db.db, &txs,
94 "SELECT * FROM tx_pool WHERE state = $1",
95 common.PoolL2TxStatePending,
96 )
97 return txs, err
98}
99
100// GetAccountCreationAuth return the authorization to make registers of an Ethereum address
101func (l2db *L2DB) GetAccountCreationAuth(ethAddr eth.Address) (*common.AccountCreationAuth, error) {
102 // TODO: impl
103 return nil, nil
104}
105
106// StartForging updates the state of the transactions that will begin the forging process.
107// The state of the txs referenced by txIDs will be changed from Pending -> Forging
108func (l2db *L2DB) StartForging(txIDs []common.TxID, batchNum common.BatchNum) error {
109 query, args, err := sqlx.In(
110 `UPDATE tx_pool
111 SET state = ?, batch_num = ?
112 WHERE state = ? AND tx_id IN (?);`,
113 string(common.PoolL2TxStateForging),
114 strconv.Itoa(int(batchNum)),
115 string(common.PoolL2TxStatePending),
116 txIDs,
117 )
118 if err != nil {
119 return err
120 }
121 query = l2db.db.Rebind(query)
122 _, err = l2db.db.Exec(query, args...)
123 return err
124}
125
126// DoneForging updates the state of the transactions that have been forged
127// so the state of the txs referenced by txIDs will be changed from Forging -> Forged
128func (l2db *L2DB) DoneForging(txIDs []common.TxID) error {
129 // TODO: impl
130 return nil
131}
132
133// InvalidateTxs updates the state of the transactions that are invalid.
134// The state of the txs referenced by txIDs will be changed from * -> Invalid
135func (l2db *L2DB) InvalidateTxs(txIDs []common.TxID) error {
136 return nil
137}
138
139// CheckNonces invalidate txs with nonces that are smaller than their respective accounts nonces.
140// The state of the affected txs will be changed from Pending -> Invalid
141func (l2db *L2DB) CheckNonces(updatedAccounts []common.Account) error {
142 // TODO: impl
143 return nil
144}
145
146// GetTxsByAbsoluteFeeUpdate return the txs that have an AbsoluteFee updated before olderThan
147func (l2db *L2DB) GetTxsByAbsoluteFeeUpdate(olderThan time.Time) ([]*common.PoolL2Tx, error) {
148 // TODO: impl
149 return nil, nil
150}
151
152// UpdateTxs update existing txs from the pool (TxID must exist)
153func (l2db *L2DB) UpdateTxs(txs []*common.PoolL2Tx) error {
154 // TODO: impl
155 return nil
156}
157
158// Reorg updates the state of txs that were updated in a batch that has been discarted due to a blockchain reorg.
159// The state of the affected txs can change form Forged -> Pending or from Invalid -> Pending
160func (l2db *L2DB) Reorg(lastValidBatch common.BatchNum) error {
161 // TODO: impl
162 return nil
163}
164
165// Purge deletes transactions that have been forged or marked as invalid for longer than the safety period
166// it also deletes txs that has been in the L2DB for longer than the ttl if maxTxs has been exceeded
167func (l2db *L2DB) Purge() error {
168 // TODO: impl
169 return nil
170}
171
172// Close frees the resources used by the L2DB
173func (l2db *L2DB) Close() error {
174 return l2db.db.Close()
175}