mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 03:16:45 +01:00
Feature/merge history l2 tables (#156)
* WIP rebase * Combine both SQL DBs * API and DB refactor
This commit is contained in:
@@ -6,16 +6,13 @@ import (
|
||||
"fmt"
|
||||
|
||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/log"
|
||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
//nolint:errcheck // driver for postgres DB
|
||||
_ "github.com/lib/pq"
|
||||
migrate "github.com/rubenv/sql-migrate"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
@@ -57,28 +54,8 @@ type BatchData struct {
|
||||
}
|
||||
|
||||
// NewHistoryDB initialize the DB
|
||||
func NewHistoryDB(port int, host, user, password, dbname string) (*HistoryDB, error) {
|
||||
// Connect to DB
|
||||
psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)
|
||||
hdb, err := sqlx.Connect("postgres", psqlconn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Init meddler
|
||||
db.InitMeddler()
|
||||
meddler.Default = meddler.PostgreSQL
|
||||
|
||||
// Run DB migrations
|
||||
migrations := &migrate.PackrMigrationSource{
|
||||
Box: packr.New("history-migrations", "./migrations"),
|
||||
}
|
||||
nMigrations, err := migrate.Exec(hdb.DB, "postgres", migrations, migrate.Up)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debug("HistoryDB applied ", nMigrations, " migrations for ", dbname, " database")
|
||||
|
||||
return &HistoryDB{hdb}, nil
|
||||
func NewHistoryDB(db *sqlx.DB) *HistoryDB {
|
||||
return &HistoryDB{db: db}
|
||||
}
|
||||
|
||||
// AddBlock insert a block into the DB
|
||||
@@ -328,8 +305,14 @@ func (hdb *HistoryDB) GetAccounts() ([]*common.Account, error) {
|
||||
return accs, err
|
||||
}
|
||||
|
||||
// AddL1Txs inserts L1 txs to the DB
|
||||
// AddL1Txs inserts L1 txs to the DB. USD and LoadAmountUSD will be set automatically before storing the tx.
|
||||
// If the tx is originated by a coordinator, BatchNum must be provided. If it's originated by a user,
|
||||
// BatchNum should be null, and the value will be setted by a trigger when a batch forges the tx.
|
||||
func (hdb *HistoryDB) AddL1Txs(l1txs []common.L1Tx) error { return hdb.addL1Txs(hdb.db, l1txs) }
|
||||
|
||||
// addL1Txs inserts L1 txs to the DB. USD and LoadAmountUSD will be set automatically before storing the tx.
|
||||
// If the tx is originated by a coordinator, BatchNum must be provided. If it's originated by a user,
|
||||
// BatchNum should be null, and the value will be setted by a trigger when a batch forges the tx.
|
||||
func (hdb *HistoryDB) addL1Txs(d meddler.DB, l1txs []common.L1Tx) error {
|
||||
txs := []common.Tx{}
|
||||
for _, tx := range l1txs {
|
||||
@@ -338,8 +321,10 @@ func (hdb *HistoryDB) addL1Txs(d meddler.DB, l1txs []common.L1Tx) error {
|
||||
return hdb.addTxs(d, txs)
|
||||
}
|
||||
|
||||
// AddL2Txs inserts L2 txs to the DB
|
||||
// AddL2Txs inserts L2 txs to the DB. USD and FeeUSD will be set automatically before storing the tx.
|
||||
func (hdb *HistoryDB) AddL2Txs(l2txs []common.L2Tx) error { return hdb.addL2Txs(hdb.db, l2txs) }
|
||||
|
||||
// addL2Txs inserts L2 txs to the DB. USD and FeeUSD will be set automatically before storing the tx.
|
||||
func (hdb *HistoryDB) addL2Txs(d meddler.DB, l2txs []common.L2Tx) error {
|
||||
txs := []common.Tx{}
|
||||
for _, tx := range l2txs {
|
||||
@@ -348,8 +333,6 @@ func (hdb *HistoryDB) addL2Txs(d meddler.DB, l2txs []common.L2Tx) error {
|
||||
return hdb.addTxs(d, txs)
|
||||
}
|
||||
|
||||
// AddTxs insert L1 txs into the DB
|
||||
func (hdb *HistoryDB) AddTxs(txs []common.Tx) error { return hdb.addTxs(hdb.db, txs) }
|
||||
func (hdb *HistoryDB) addTxs(d meddler.DB, txs []common.Tx) error {
|
||||
return db.BulkInsert(
|
||||
d,
|
||||
@@ -381,16 +364,6 @@ func (hdb *HistoryDB) addTxs(d meddler.DB, txs []common.Tx) error {
|
||||
)
|
||||
}
|
||||
|
||||
// SetBatchNumL1UserTxs sets the batchNum in all the L1UserTxs with toForgeL1TxsNum.
|
||||
func (hdb *HistoryDB) SetBatchNumL1UserTxs(toForgeL1TxsNum, batchNum int64) error {
|
||||
return hdb.setBatchNumL1UserTxs(hdb.db, toForgeL1TxsNum, batchNum)
|
||||
}
|
||||
func (hdb *HistoryDB) setBatchNumL1UserTxs(d meddler.DB, toForgeL1TxsNum, batchNum int64) error {
|
||||
_, err := d.Exec("UPDATE tx SET batch_num = $1 WHERE to_forge_l1_txs_num = $2 AND is_l1 = TRUE AND user_origin = TRUE;",
|
||||
batchNum, toForgeL1TxsNum)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetTxs returns a list of txs from the DB
|
||||
func (hdb *HistoryDB) GetTxs() ([]*common.Tx, error) {
|
||||
var txs []*common.Tx
|
||||
@@ -413,8 +386,10 @@ func (hdb *HistoryDB) GetHistoryTxs(
|
||||
}
|
||||
var query string
|
||||
var args []interface{}
|
||||
queryStr := `SELECT tx.*, tx.amount_f * token.usd AS current_usd,
|
||||
token.symbol, token.usd_update, block.timestamp, count(*) OVER() AS total_items FROM tx
|
||||
queryStr := `SELECT tx.*, token.token_id, token.eth_block_num AS token_block,
|
||||
token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
|
||||
token.usd_update, block.timestamp, count(*) OVER() AS total_items
|
||||
FROM tx
|
||||
INNER JOIN token ON tx.token_id = token.token_id
|
||||
INNER JOIN block ON tx.eth_block_num = block.eth_block_num `
|
||||
// Apply filters
|
||||
@@ -513,17 +488,17 @@ func (hdb *HistoryDB) GetTx(txID common.TxID) (*common.Tx, error) {
|
||||
)
|
||||
}
|
||||
|
||||
// GetL1UserTxs gets L1 User Txs to be forged in a batch that will create an account
|
||||
// TODO: This is currently not used. Figure out if it should be used somewhere or removed.
|
||||
func (hdb *HistoryDB) GetL1UserTxs(toForgeL1TxsNum int64) ([]*common.Tx, error) {
|
||||
var txs []*common.Tx
|
||||
err := meddler.QueryAll(
|
||||
hdb.db, &txs,
|
||||
"SELECT * FROM tx WHERE to_forge_l1_txs_num = $1 AND is_l1 = TRUE AND user_origin = TRUE;",
|
||||
toForgeL1TxsNum,
|
||||
)
|
||||
return txs, err
|
||||
}
|
||||
// // GetL1UserTxs gets L1 User Txs to be forged in a batch that will create an account
|
||||
// // TODO: This is currently not used. Figure out if it should be used somewhere or removed.
|
||||
// func (hdb *HistoryDB) GetL1UserTxs(toForgeL1TxsNum int64) ([]*common.Tx, error) {
|
||||
// var txs []*common.Tx
|
||||
// err := meddler.QueryAll(
|
||||
// hdb.db, &txs,
|
||||
// "SELECT * FROM tx WHERE to_forge_l1_txs_num = $1 AND is_l1 = TRUE AND user_origin = TRUE;",
|
||||
// toForgeL1TxsNum,
|
||||
// )
|
||||
// return txs, err
|
||||
// }
|
||||
|
||||
// TODO: Think about chaning all the queries that return a last value, to queries that return the next valid value.
|
||||
|
||||
@@ -586,11 +561,15 @@ func (hdb *HistoryDB) AddBlockSCData(blockData *BlockData) (err error) {
|
||||
|
||||
// Add Batches
|
||||
for _, batch := range blockData.Batches {
|
||||
// Add Batch: this will trigger an update on the DB
|
||||
// that will set the batch num of forged L1 txs in this batch
|
||||
err = hdb.addBatch(txn, batch.Batch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add unforged l1 Txs
|
||||
if batch.L1Batch {
|
||||
err = hdb.setBatchNumL1UserTxs(txn, batch.Batch.ForgeL1TxsNum, int64(batch.Batch.BatchNum))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(batch.L1CoordinatorTxs) > 0 {
|
||||
err = hdb.addL1Txs(txn, batch.L1CoordinatorTxs)
|
||||
if err != nil {
|
||||
@@ -623,19 +602,8 @@ func (hdb *HistoryDB) AddBlockSCData(blockData *BlockData) (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Add Batch
|
||||
err = hdb.addBatch(txn, batch.Batch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: INSERT CONTRACTS VARS
|
||||
}
|
||||
|
||||
return txn.Commit()
|
||||
}
|
||||
|
||||
// Close frees the resources used by HistoryDB
|
||||
func (hdb *HistoryDB) Close() error {
|
||||
return hdb.db.Close()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package historydb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"testing"
|
||||
@@ -9,6 +8,8 @@ import (
|
||||
|
||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
dbUtils "github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/log"
|
||||
"github.com/hermeznetwork/hermez-node/test"
|
||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -26,17 +27,20 @@ var historyDB *HistoryDB
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// init DB
|
||||
var err error
|
||||
pass := os.Getenv("POSTGRES_PASS")
|
||||
historyDB, err = NewHistoryDB(5432, "localhost", "hermez", pass, "history")
|
||||
db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
historyDB = NewHistoryDB(db)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Run tests
|
||||
result := m.Run()
|
||||
// Close DB
|
||||
if err := historyDB.Close(); err != nil {
|
||||
fmt.Println("Error closing the history DB:", err)
|
||||
if err := db.Close(); err != nil {
|
||||
log.Error("Error closing the history DB:", err)
|
||||
}
|
||||
os.Exit(result)
|
||||
}
|
||||
@@ -145,15 +149,6 @@ func TestTokens(t *testing.T) {
|
||||
tokens := test.GenTokens(nTokens, blocks)
|
||||
err := historyDB.AddTokens(tokens)
|
||||
assert.NoError(t, err)
|
||||
// Update price of generated tokens without price
|
||||
for i := 0; i < len(tokens); i++ {
|
||||
if tokens[i].USD == 0 {
|
||||
value := 3.33 + float64(i)
|
||||
tokens[i].USD = value
|
||||
err := historyDB.UpdateTokenValue(tokens[i].TokenID, value)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
// Fetch tokens
|
||||
fetchedTokens, err := historyDB.GetTokens()
|
||||
assert.NoError(t, err)
|
||||
@@ -166,7 +161,11 @@ func TestTokens(t *testing.T) {
|
||||
assert.Equal(t, tokens[i].Name, token.Name)
|
||||
assert.Equal(t, tokens[i].Symbol, token.Symbol)
|
||||
assert.Equal(t, tokens[i].USD, token.USD)
|
||||
assert.Greater(t, int64(1*time.Second), int64(time.Since(token.USDUpdate)))
|
||||
if token.USDUpdate != nil {
|
||||
assert.Greater(t, int64(1*time.Second), int64(time.Since(*token.USDUpdate)))
|
||||
} else {
|
||||
assert.Equal(t, tokens[i].USDUpdate, token.USDUpdate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,12 +204,8 @@ func TestTxs(t *testing.T) {
|
||||
// Prepare blocks in the DB
|
||||
blocks := setTestBlocks(fromBlock, toBlock)
|
||||
// Generate fake tokens
|
||||
const nTokens = 5
|
||||
const tokenValue = 1.23456
|
||||
const nTokens = 500
|
||||
tokens := test.GenTokens(nTokens, blocks)
|
||||
for i := 0; i < len(tokens); i++ {
|
||||
tokens[i].USD = tokenValue
|
||||
}
|
||||
err := historyDB.AddTokens(tokens)
|
||||
assert.NoError(t, err)
|
||||
// Generate fake batches
|
||||
@@ -224,60 +219,17 @@ func TestTxs(t *testing.T) {
|
||||
err = historyDB.AddAccounts(accs)
|
||||
assert.NoError(t, err)
|
||||
// Generate fake L1 txs
|
||||
const nL1s = 30
|
||||
const nL1s = 64
|
||||
_, l1txs := test.GenL1Txs(0, nL1s, 0, nil, accs, tokens, blocks, batches)
|
||||
err = historyDB.AddL1Txs(l1txs)
|
||||
assert.NoError(t, err)
|
||||
// Generate fake L2 txs
|
||||
const nL2s = 20
|
||||
const nL2s = 2048 - nL1s
|
||||
_, l2txs := test.GenL2Txs(0, nL2s, 0, nil, accs, tokens, blocks, batches)
|
||||
err = historyDB.AddL2Txs(l2txs)
|
||||
assert.NoError(t, err)
|
||||
// Compare fetched txs vs generated txs.
|
||||
for i := 0; i < len(l1txs); i++ {
|
||||
tx := l1txs[i].Tx()
|
||||
fetchedTx, err := historyDB.GetTx(tx.TxID)
|
||||
assert.NoError(t, err)
|
||||
tx.USD = tokenValue * tx.AmountFloat
|
||||
if fetchedTx.USD > tx.USD {
|
||||
assert.Less(t, 0.999, tx.USD/fetchedTx.USD)
|
||||
} else {
|
||||
assert.Less(t, 0.999, fetchedTx.USD/tx.USD)
|
||||
}
|
||||
tx.LoadAmountUSD = tokenValue * tx.LoadAmountFloat
|
||||
if fetchedTx.LoadAmountUSD > tx.LoadAmountUSD {
|
||||
assert.Less(t, 0.999, tx.LoadAmountUSD/fetchedTx.LoadAmountUSD)
|
||||
} else {
|
||||
assert.Less(t, 0.999, fetchedTx.LoadAmountUSD/tx.LoadAmountUSD)
|
||||
}
|
||||
tx.LoadAmountUSD = 0
|
||||
tx.USD = 0
|
||||
fetchedTx.LoadAmountUSD = 0
|
||||
fetchedTx.USD = 0
|
||||
assert.Equal(t, tx, fetchedTx)
|
||||
}
|
||||
for i := 0; i < len(l2txs); i++ {
|
||||
tx := l2txs[i].Tx()
|
||||
fetchedTx, err := historyDB.GetTx(tx.TxID)
|
||||
assert.NoError(t, err)
|
||||
tx.USD = tokenValue * tx.AmountFloat
|
||||
if fetchedTx.USD > tx.USD {
|
||||
assert.Less(t, 0.999, tx.USD/fetchedTx.USD)
|
||||
} else {
|
||||
assert.Less(t, 0.999, fetchedTx.USD/tx.USD)
|
||||
}
|
||||
tx.FeeUSD = tx.USD * tx.Fee.Percentage()
|
||||
if fetchedTx.FeeUSD > tx.FeeUSD {
|
||||
assert.Less(t, 0.999, tx.FeeUSD/fetchedTx.FeeUSD)
|
||||
} else if fetchedTx.FeeUSD < tx.FeeUSD {
|
||||
assert.Less(t, 0.999, fetchedTx.FeeUSD/tx.FeeUSD)
|
||||
}
|
||||
tx.FeeUSD = 0
|
||||
tx.USD = 0
|
||||
fetchedTx.FeeUSD = 0
|
||||
fetchedTx.USD = 0
|
||||
assert.Equal(t, tx, fetchedTx)
|
||||
}
|
||||
fetchAndAssertTxs(t, l1txs, l2txs)
|
||||
// Test trigger: L1 integrity
|
||||
// from_eth_addr can't be null
|
||||
l1txs[0].FromEthAddr = ethCommon.Address{}
|
||||
@@ -304,23 +256,75 @@ func TestTxs(t *testing.T) {
|
||||
l2txs[0].Nonce = 0
|
||||
err = historyDB.AddL2Txs(l2txs)
|
||||
assert.Error(t, err)
|
||||
// Test trigger: forge L1 txs
|
||||
// add next batch to DB
|
||||
batchNum, toForgeL1TxsNum := test.GetNextToForgeNumAndBatch(batches)
|
||||
batch := batches[0]
|
||||
batch.BatchNum = batchNum
|
||||
batch.ForgeL1TxsNum = toForgeL1TxsNum
|
||||
assert.NoError(t, historyDB.AddBatch(&batch)) // This should update nL1s / 2 rows
|
||||
// Set batch num in txs that should have been marked as forged in the DB
|
||||
for i := 0; i < len(l1txs); i++ {
|
||||
fetchedTx, err := historyDB.GetTx(l1txs[i].TxID)
|
||||
assert.NoError(t, err)
|
||||
if l1txs[i].ToForgeL1TxsNum == toForgeL1TxsNum {
|
||||
assert.Equal(t, batchNum, *fetchedTx.BatchNum)
|
||||
} else {
|
||||
if fetchedTx.BatchNum != nil {
|
||||
assert.NotEqual(t, batchNum, *fetchedTx.BatchNum)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test helper functions for Synchronizer
|
||||
txs, err := historyDB.GetL1UserTxs(2)
|
||||
// GetLastTxsPosition
|
||||
expectedPosition := -1
|
||||
var choosenToForgeL1TxsNum int64 = -1
|
||||
for _, tx := range l1txs {
|
||||
if choosenToForgeL1TxsNum == -1 && tx.ToForgeL1TxsNum > 0 {
|
||||
choosenToForgeL1TxsNum = tx.ToForgeL1TxsNum
|
||||
expectedPosition = tx.Position
|
||||
} else if choosenToForgeL1TxsNum == tx.ToForgeL1TxsNum && expectedPosition < tx.Position {
|
||||
expectedPosition = tx.Position
|
||||
}
|
||||
}
|
||||
position, err := historyDB.GetLastTxsPosition(choosenToForgeL1TxsNum)
|
||||
assert.NoError(t, err)
|
||||
assert.NotZero(t, len(txs))
|
||||
position, err := historyDB.GetLastTxsPosition(2)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 22, position)
|
||||
// Test Update L1 TX Batch_num
|
||||
assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
|
||||
txs[0].BatchNum = common.BatchNum(1)
|
||||
// err = historyDB.UpdateTxsBatchNum(txs)
|
||||
err = historyDB.SetBatchNumL1UserTxs(2, 1)
|
||||
assert.NoError(t, err)
|
||||
txs, err = historyDB.GetL1UserTxs(2)
|
||||
assert.NoError(t, err)
|
||||
assert.NotZero(t, len(txs))
|
||||
assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
|
||||
assert.Equal(t, expectedPosition, position)
|
||||
|
||||
// GetL1UserTxs: not needed? tests were broken
|
||||
// txs, err := historyDB.GetL1UserTxs(2)
|
||||
// assert.NoError(t, err)
|
||||
// assert.NotZero(t, len(txs))
|
||||
// assert.NoError(t, err)
|
||||
// assert.Equal(t, 22, position)
|
||||
// // Test Update L1 TX Batch_num
|
||||
// assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
|
||||
// txs[0].BatchNum = common.BatchNum(1)
|
||||
// txs, err = historyDB.GetL1UserTxs(2)
|
||||
// assert.NoError(t, err)
|
||||
// assert.NotZero(t, len(txs))
|
||||
// assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
|
||||
}
|
||||
|
||||
func fetchAndAssertTxs(t *testing.T, l1txs []common.L1Tx, l2txs []common.L2Tx) {
|
||||
for i := 0; i < len(l1txs); i++ {
|
||||
tx := l1txs[i].Tx()
|
||||
fetchedTx, err := historyDB.GetTx(tx.TxID)
|
||||
assert.NoError(t, err)
|
||||
test.AssertUSD(t, tx.USD, fetchedTx.USD)
|
||||
test.AssertUSD(t, tx.LoadAmountUSD, fetchedTx.LoadAmountUSD)
|
||||
assert.Equal(t, tx, fetchedTx)
|
||||
}
|
||||
for i := 0; i < len(l2txs); i++ {
|
||||
tx := l2txs[i].Tx()
|
||||
fetchedTx, err := historyDB.GetTx(tx.TxID)
|
||||
tx.TokenID = fetchedTx.TokenID
|
||||
assert.NoError(t, err)
|
||||
test.AssertUSD(t, fetchedTx.USD, tx.USD)
|
||||
test.AssertUSD(t, fetchedTx.FeeUSD, tx.FeeUSD)
|
||||
assert.Equal(t, tx, fetchedTx)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExitTree(t *testing.T) {
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
-- +migrate Up
|
||||
CREATE TABLE block (
|
||||
eth_block_num BIGINT PRIMARY KEY,
|
||||
timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
|
||||
hash BYTEA NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE coordinator (
|
||||
forger_addr BYTEA NOT NULL,
|
||||
eth_block_num BIGINT NOT NULL REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
withdraw_addr BYTEA NOT NULL,
|
||||
url VARCHAR(200) NOT NULL,
|
||||
PRIMARY KEY (forger_addr, eth_block_num)
|
||||
);
|
||||
|
||||
CREATE TABLE batch (
|
||||
batch_num BIGINT PRIMARY KEY,
|
||||
eth_block_num BIGINT REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
forger_addr BYTEA NOT NULL, -- fake foreign key for coordinator
|
||||
fees_collected BYTEA NOT NULL,
|
||||
state_root BYTEA NOT NULL,
|
||||
num_accounts BIGINT NOT NULL,
|
||||
exit_root BYTEA NOT NULL,
|
||||
forge_l1_txs_num BIGINT,
|
||||
slot_num BIGINT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE exit_tree (
|
||||
batch_num BIGINT REFERENCES batch (batch_num) ON DELETE CASCADE,
|
||||
account_idx BIGINT,
|
||||
merkle_proof BYTEA NOT NULL,
|
||||
balance BYTEA NOT NULL,
|
||||
instant_withdrawn BIGINT REFERENCES batch (batch_num) ON DELETE SET NULL,
|
||||
delayed_withdraw_request BIGINT REFERENCES batch (batch_num) ON DELETE SET NULL,
|
||||
delayed_withdrawn BIGINT REFERENCES batch (batch_num) ON DELETE SET NULL,
|
||||
PRIMARY KEY (batch_num, account_idx)
|
||||
);
|
||||
|
||||
CREATE TABLE bid (
|
||||
slot_num BIGINT NOT NULL,
|
||||
bid_value BYTEA NOT NULL,
|
||||
eth_block_num BIGINT NOT NULL REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
forger_addr BYTEA NOT NULL, -- fake foreign key for coordinator
|
||||
PRIMARY KEY (slot_num, bid_value)
|
||||
);
|
||||
|
||||
CREATE TABLE token (
|
||||
token_id INT PRIMARY KEY,
|
||||
eth_block_num BIGINT NOT NULL REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
eth_addr BYTEA UNIQUE NOT NULL,
|
||||
name VARCHAR(20) NOT NULL,
|
||||
symbol VARCHAR(10) NOT NULL,
|
||||
decimals INT NOT NULL,
|
||||
usd NUMERIC,
|
||||
usd_update TIMESTAMP
|
||||
);
|
||||
|
||||
-- +migrate StatementBegin
|
||||
CREATE FUNCTION set_token_usd_update()
|
||||
RETURNS TRIGGER
|
||||
AS
|
||||
$BODY$
|
||||
BEGIN
|
||||
IF NEW."usd" IS NOT NULL AND NEW."usd_update" IS NULL THEN
|
||||
NEW."usd_update" = timezone('utc', now());
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$BODY$
|
||||
LANGUAGE plpgsql;
|
||||
-- +migrate StatementEnd
|
||||
CREATE TRIGGER trigger_token_usd_update BEFORE UPDATE OR INSERT ON token
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_token_usd_update();
|
||||
|
||||
CREATE TABLE tx (
|
||||
-- Generic TX
|
||||
is_l1 BOOLEAN NOT NULL,
|
||||
id BYTEA PRIMARY KEY,
|
||||
type VARCHAR(40) NOT NULL,
|
||||
position INT NOT NULL,
|
||||
from_idx BIGINT NOT NULL,
|
||||
to_idx BIGINT NOT NULL,
|
||||
amount BYTEA NOT NULL,
|
||||
amount_f NUMERIC NOT NULL,
|
||||
token_id INT NOT NULL REFERENCES token (token_id),
|
||||
amount_usd NUMERIC, -- Value of the amount in USD at the moment the tx was inserted in the DB
|
||||
batch_num BIGINT REFERENCES batch (batch_num) ON DELETE SET NULL, -- Can be NULL in the case of L1 txs that are on the queue but not forged yet.
|
||||
eth_block_num BIGINT NOT NULL REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
-- L1
|
||||
to_forge_l1_txs_num BIGINT,
|
||||
user_origin BOOLEAN,
|
||||
from_eth_addr BYTEA,
|
||||
from_bjj BYTEA,
|
||||
load_amount BYTEA,
|
||||
load_amount_f NUMERIC,
|
||||
load_amount_usd NUMERIC,
|
||||
-- L2
|
||||
fee INT,
|
||||
fee_usd NUMERIC,
|
||||
nonce BIGINT
|
||||
);
|
||||
|
||||
CREATE INDEX tx_order ON tx (batch_num, position);
|
||||
|
||||
-- +migrate StatementBegin
|
||||
CREATE FUNCTION set_tx()
|
||||
RETURNS TRIGGER
|
||||
AS
|
||||
$BODY$
|
||||
DECLARE token_value NUMERIC := (SELECT usd FROM token WHERE token_id = NEW.token_id);
|
||||
BEGIN
|
||||
-- Validate L1/L2 constrains
|
||||
IF NEW.is_l1 AND (( -- L1 mandatory fields
|
||||
NEW.user_origin IS NULL OR
|
||||
NEW.from_eth_addr IS NULL OR
|
||||
NEW.from_bjj IS NULL OR
|
||||
NEW.load_amount IS NULL OR
|
||||
NEW.load_amount_f IS NULL
|
||||
) OR (NOT NEW.user_origin AND NEW.batch_num IS NULL)) THEN -- If is Coordinator L1, must include batch_num
|
||||
RAISE EXCEPTION 'Invalid L1 tx.';
|
||||
ELSIF NOT NEW.is_l1 THEN
|
||||
IF NEW.fee IS NULL THEN
|
||||
NEW.fee = (SELECT 0);
|
||||
END IF;
|
||||
IF NEW.batch_num IS NULL OR NEW.nonce IS NULL THEN
|
||||
RAISE EXCEPTION 'Invalid L2 tx.';
|
||||
END IF;
|
||||
END IF;
|
||||
-- If is L2, add token_id
|
||||
IF NEW.token_id IS NULL THEN
|
||||
NEW."token_id" = (SELECT token_id FROM account WHERE idx = NEW."from_idx");
|
||||
END IF;
|
||||
-- Set value_usd
|
||||
NEW."amount_usd" = (SELECT token_value * NEW.amount_f);
|
||||
NEW."load_amount_usd" = (SELECT token_value * NEW.load_amount_f);
|
||||
IF NOT NEW.is_l1 THEN
|
||||
NEW."fee_usd" = (SELECT token_value * NEW.amount_f * CASE
|
||||
WHEN NEW.fee = 0 THEN 0
|
||||
WHEN NEW.fee >= 1 AND NEW.fee <= 32 THEN POWER(10,-24+(NEW.fee::float/2))
|
||||
WHEN NEW.fee >= 33 AND NEW.fee <= 223 THEN POWER(10,-8+(0.041666666666667*(NEW.fee::float-32)))
|
||||
WHEN NEW.fee >= 224 AND NEW.fee <= 255 THEN POWER(10,NEW.fee-224) END);
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$BODY$
|
||||
LANGUAGE plpgsql;
|
||||
-- +migrate StatementEnd
|
||||
CREATE TRIGGER trigger_set_tx BEFORE INSERT ON tx
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_tx();
|
||||
|
||||
-- +migrate StatementBegin
|
||||
CREATE FUNCTION forge_l1_user_txs()
|
||||
RETURNS TRIGGER
|
||||
AS
|
||||
$BODY$
|
||||
BEGIN
|
||||
IF NEW.forge_l1_txs_num IS NOT NULL THEN
|
||||
UPDATE tx
|
||||
SET batch_num = NEW.batch_num
|
||||
WHERE user_origin AND NEW.forge_l1_txs_num = to_forge_l1_txs_num;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$BODY$
|
||||
LANGUAGE plpgsql;
|
||||
-- +migrate StatementEnd
|
||||
CREATE TRIGGER trigger_forge_l1_txs AFTER INSERT ON batch
|
||||
FOR EACH ROW EXECUTE PROCEDURE forge_l1_user_txs();
|
||||
|
||||
CREATE TABLE account (
|
||||
idx BIGINT PRIMARY KEY,
|
||||
token_id INT NOT NULL REFERENCES token (token_id) ON DELETE CASCADE,
|
||||
batch_num BIGINT NOT NULL REFERENCES batch (batch_num) ON DELETE CASCADE,
|
||||
bjj BYTEA NOT NULL,
|
||||
eth_addr BYTEA NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE rollup_vars (
|
||||
eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
forge_l1_timeout BYTEA NOT NULL,
|
||||
fee_l1_user_tx BYTEA NOT NULL,
|
||||
fee_add_token BYTEA NOT NULL,
|
||||
tokens_hez BYTEA NOT NULL,
|
||||
governance BYTEA NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE consensus_vars (
|
||||
eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
slot_deadline INT NOT NULL,
|
||||
close_auction_slots INT NOT NULL,
|
||||
open_auction_slots INT NOT NULL,
|
||||
min_bid_slots VARCHAR(200) NOT NULL,
|
||||
outbidding INT NOT NULL,
|
||||
donation_address BYTEA NOT NULL,
|
||||
governance_address BYTEA NOT NULL,
|
||||
allocation_ratio VARCHAR(200)
|
||||
);
|
||||
|
||||
-- +migrate Down
|
||||
DROP TABLE consensus_vars;
|
||||
DROP TABLE rollup_vars;
|
||||
DROP TABLE account;
|
||||
DROP TABLE tx;
|
||||
DROP TABLE token;
|
||||
DROP TABLE bid;
|
||||
DROP TABLE exit_tree;
|
||||
DROP TABLE batch;
|
||||
DROP TABLE coordinator;
|
||||
DROP TABLE block;
|
||||
@@ -13,34 +13,38 @@ import (
|
||||
// required by the API, and extracted by joining block and token tables
|
||||
type HistoryTx struct {
|
||||
// Generic
|
||||
IsL1 bool `meddler:"is_l1"`
|
||||
TxID common.TxID `meddler:"id"`
|
||||
Type common.TxType `meddler:"type"`
|
||||
Position int `meddler:"position"`
|
||||
FromIdx common.Idx `meddler:"from_idx"`
|
||||
ToIdx common.Idx `meddler:"to_idx"`
|
||||
Amount *big.Int `meddler:"amount,bigint"`
|
||||
AmountFloat float64 `meddler:"amount_f"`
|
||||
TokenID common.TokenID `meddler:"token_id"`
|
||||
USD float64 `meddler:"amount_usd,zeroisnull"`
|
||||
BatchNum common.BatchNum `meddler:"batch_num,zeroisnull"` // batchNum in which this tx was forged. If the tx is L2, this must be != 0
|
||||
EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
|
||||
IsL1 bool `meddler:"is_l1"`
|
||||
TxID common.TxID `meddler:"id"`
|
||||
Type common.TxType `meddler:"type"`
|
||||
Position int `meddler:"position"`
|
||||
FromIdx common.Idx `meddler:"from_idx"`
|
||||
ToIdx common.Idx `meddler:"to_idx"`
|
||||
Amount *big.Int `meddler:"amount,bigint"`
|
||||
AmountFloat float64 `meddler:"amount_f"`
|
||||
HistoricUSD *float64 `meddler:"amount_usd"`
|
||||
BatchNum *common.BatchNum `meddler:"batch_num"` // batchNum in which this tx was forged. If the tx is L2, this must be != 0
|
||||
EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
|
||||
// L1
|
||||
ToForgeL1TxsNum int64 `meddler:"to_forge_l1_txs_num"` // toForgeL1TxsNum in which the tx was forged / will be forged
|
||||
UserOrigin bool `meddler:"user_origin"` // true if the tx was originated by a user, false if it was aoriginated by a coordinator. Note that this differ from the spec for implementation simplification purpposes
|
||||
FromEthAddr ethCommon.Address `meddler:"from_eth_addr"`
|
||||
FromBJJ *babyjub.PublicKey `meddler:"from_bjj"`
|
||||
LoadAmount *big.Int `meddler:"load_amount,bigintnull"`
|
||||
LoadAmountFloat float64 `meddler:"load_amount_f"`
|
||||
LoadAmountUSD float64 `meddler:"load_amount_usd,zeroisnull"`
|
||||
ToForgeL1TxsNum int64 `meddler:"to_forge_l1_txs_num"` // toForgeL1TxsNum in which the tx was forged / will be forged
|
||||
UserOrigin bool `meddler:"user_origin"` // true if the tx was originated by a user, false if it was aoriginated by a coordinator. Note that this differ from the spec for implementation simplification purpposes
|
||||
FromEthAddr ethCommon.Address `meddler:"from_eth_addr"`
|
||||
FromBJJ *babyjub.PublicKey `meddler:"from_bjj"`
|
||||
LoadAmount *big.Int `meddler:"load_amount,bigintnull"`
|
||||
LoadAmountFloat *float64 `meddler:"load_amount_f"`
|
||||
HistoricLoadAmountUSD *float64 `meddler:"load_amount_usd"`
|
||||
// L2
|
||||
Fee common.FeeSelector `meddler:"fee,zeroisnull"`
|
||||
FeeUSD float64 `meddler:"fee_usd,zeroisnull"`
|
||||
Nonce common.Nonce `meddler:"nonce,zeroisnull"`
|
||||
Fee *common.FeeSelector `meddler:"fee"`
|
||||
HistoricFeeUSD *float64 `meddler:"fee_usd"`
|
||||
Nonce *common.Nonce `meddler:"nonce"`
|
||||
// API extras
|
||||
Timestamp time.Time `meddler:"timestamp,utctime"`
|
||||
TokenSymbol string `meddler:"symbol"`
|
||||
CurrentUSD float64 `meddler:"current_usd"`
|
||||
USDUpdate time.Time `meddler:"usd_update,utctime"`
|
||||
TotalItems int `meddler:"total_items"`
|
||||
Timestamp time.Time `meddler:"timestamp,utctime"`
|
||||
TotalItems int `meddler:"total_items"`
|
||||
TokenID common.TokenID `meddler:"token_id"`
|
||||
TokenEthBlockNum int64 `meddler:"token_block"`
|
||||
TokenEthAddr ethCommon.Address `meddler:"eth_addr"`
|
||||
TokenName string `meddler:"name"`
|
||||
TokenSymbol string `meddler:"symbol"`
|
||||
TokenDecimals uint64 `meddler:"decimals"`
|
||||
TokenUSD *float64 `meddler:"usd"`
|
||||
TokenUSDUpdate *time.Time `meddler:"usd_update"`
|
||||
}
|
||||
|
||||
144
db/l2db/l2db.go
144
db/l2db/l2db.go
@@ -1,19 +1,16 @@
|
||||
package l2db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
"github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/log"
|
||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
//nolint:errcheck // driver for postgres DB
|
||||
_ "github.com/lib/pq"
|
||||
migrate "github.com/rubenv/sql-migrate"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
@@ -29,40 +26,15 @@ type L2DB struct {
|
||||
}
|
||||
|
||||
// NewL2DB creates a L2DB.
|
||||
// To create it, it's needed postgres configuration, safety period expressed in batches,
|
||||
// To create it, it's needed db connection, safety period expressed in batches,
|
||||
// maxTxs that the DB should have and TTL (time to live) for pending txs.
|
||||
func NewL2DB(
|
||||
port int, host, user, password, dbname string,
|
||||
safetyPeriod common.BatchNum,
|
||||
maxTxs uint32,
|
||||
TTL time.Duration,
|
||||
) (*L2DB, error) {
|
||||
// init meddler
|
||||
db.InitMeddler()
|
||||
meddler.Default = meddler.PostgreSQL
|
||||
// Stablish DB connection
|
||||
psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)
|
||||
db, err := sqlx.Connect("postgres", psqlconn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Run DB migrations
|
||||
migrations := &migrate.PackrMigrationSource{
|
||||
Box: packr.New("l2db-migrations", "./migrations"),
|
||||
}
|
||||
nMigrations, err := migrate.Exec(db.DB, "postgres", migrations, migrate.Up)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debug("L2DB applied ", nMigrations, " migrations for ", dbname, " database")
|
||||
|
||||
func NewL2DB(db *sqlx.DB, safetyPeriod common.BatchNum, maxTxs uint32, TTL time.Duration) *L2DB {
|
||||
return &L2DB{
|
||||
db: db,
|
||||
safetyPeriod: safetyPeriod,
|
||||
ttl: TTL,
|
||||
maxTxs: maxTxs,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// DB returns a pointer to the L2DB.db. This method should be used only for
|
||||
@@ -86,27 +58,82 @@ func (l2db *L2DB) GetAccountCreationAuth(addr ethCommon.Address) (*common.Accoun
|
||||
)
|
||||
}
|
||||
|
||||
// AddTx inserts a tx into the L2DB
|
||||
func (l2db *L2DB) AddTx(tx *common.PoolL2Tx) error {
|
||||
return meddler.Insert(l2db.db, "tx_pool", tx)
|
||||
// AddTxTest inserts a tx into the L2DB. This is useful for test purposes,
|
||||
// but in production txs will only be inserted through the API (method TBD)
|
||||
func (l2db *L2DB) AddTxTest(tx *common.PoolL2Tx) error {
|
||||
type withouUSD struct {
|
||||
TxID common.TxID `meddler:"tx_id"`
|
||||
FromIdx common.Idx `meddler:"from_idx"`
|
||||
ToIdx common.Idx `meddler:"to_idx"`
|
||||
ToEthAddr ethCommon.Address `meddler:"to_eth_addr"`
|
||||
ToBJJ *babyjub.PublicKey `meddler:"to_bjj"`
|
||||
TokenID common.TokenID `meddler:"token_id"`
|
||||
Amount *big.Int `meddler:"amount,bigint"`
|
||||
AmountFloat float64 `meddler:"amount_f"`
|
||||
Fee common.FeeSelector `meddler:"fee"`
|
||||
Nonce common.Nonce `meddler:"nonce"`
|
||||
State common.PoolL2TxState `meddler:"state"`
|
||||
Signature *babyjub.Signature `meddler:"signature"`
|
||||
Timestamp time.Time `meddler:"timestamp,utctime"`
|
||||
BatchNum common.BatchNum `meddler:"batch_num,zeroisnull"`
|
||||
RqFromIdx common.Idx `meddler:"rq_from_idx,zeroisnull"`
|
||||
RqToIdx common.Idx `meddler:"rq_to_idx,zeroisnull"`
|
||||
RqToEthAddr ethCommon.Address `meddler:"rq_to_eth_addr"`
|
||||
RqToBJJ *babyjub.PublicKey `meddler:"rq_to_bjj"`
|
||||
RqTokenID common.TokenID `meddler:"rq_token_id,zeroisnull"`
|
||||
RqAmount *big.Int `meddler:"rq_amount,bigintnull"`
|
||||
RqFee common.FeeSelector `meddler:"rq_fee,zeroisnull"`
|
||||
RqNonce uint64 `meddler:"rq_nonce,zeroisnull"`
|
||||
Type common.TxType `meddler:"tx_type"`
|
||||
}
|
||||
return meddler.Insert(l2db.db, "tx_pool", &withouUSD{
|
||||
TxID: tx.TxID,
|
||||
FromIdx: tx.FromIdx,
|
||||
ToIdx: tx.ToIdx,
|
||||
ToEthAddr: tx.ToEthAddr,
|
||||
ToBJJ: tx.ToBJJ,
|
||||
TokenID: tx.TokenID,
|
||||
Amount: tx.Amount,
|
||||
AmountFloat: tx.AmountFloat,
|
||||
Fee: tx.Fee,
|
||||
Nonce: tx.Nonce,
|
||||
State: tx.State,
|
||||
Signature: tx.Signature,
|
||||
Timestamp: tx.Timestamp,
|
||||
BatchNum: tx.BatchNum,
|
||||
RqFromIdx: tx.RqFromIdx,
|
||||
RqToIdx: tx.RqToIdx,
|
||||
RqToEthAddr: tx.RqToEthAddr,
|
||||
RqToBJJ: tx.RqToBJJ,
|
||||
RqTokenID: tx.RqTokenID,
|
||||
RqAmount: tx.RqAmount,
|
||||
RqFee: tx.RqFee,
|
||||
RqNonce: tx.RqNonce,
|
||||
Type: tx.Type,
|
||||
})
|
||||
}
|
||||
|
||||
// selectPoolTx select part of queries to get common.PoolL2Tx
|
||||
const selectPoolTx = `SELECT tx_pool.*, token.usd * tx_pool.amount_f AS value_usd,
|
||||
fee_percentage(tx_pool.fee::NUMERIC) * token.usd * tx_pool.amount_f AS fee_usd, token.usd_update,
|
||||
token.symbol AS token_symbol FROM tx_pool INNER JOIN token ON tx_pool.token_id = token.token_id `
|
||||
|
||||
// GetTx return the specified Tx
|
||||
func (l2db *L2DB) GetTx(txID common.TxID) (*common.PoolL2Tx, error) {
|
||||
tx := new(common.PoolL2Tx)
|
||||
return tx, meddler.QueryRow(
|
||||
l2db.db, tx,
|
||||
"SELECT * FROM tx_pool WHERE tx_id = $1;",
|
||||
selectPoolTx+"WHERE tx_id = $1;",
|
||||
txID,
|
||||
)
|
||||
}
|
||||
|
||||
// GetPendingTxs return all the pending txs of the L2DB
|
||||
// GetPendingTxs return all the pending txs of the L2DB, that have a non NULL AbsoluteFee
|
||||
func (l2db *L2DB) GetPendingTxs() ([]*common.PoolL2Tx, error) {
|
||||
var txs []*common.PoolL2Tx
|
||||
err := meddler.QueryAll(
|
||||
l2db.db, &txs,
|
||||
"SELECT * FROM tx_pool WHERE state = $1",
|
||||
selectPoolTx+"WHERE state = $1 AND token.usd IS NOT NULL",
|
||||
common.PoolL2TxStatePending,
|
||||
)
|
||||
return txs, err
|
||||
@@ -202,40 +229,6 @@ func (l2db *L2DB) CheckNonces(updatedAccounts []common.Account, batchNum common.
|
||||
return txn.Commit()
|
||||
}
|
||||
|
||||
// UpdateTxValue updates the absolute fee and value of txs given a token list that include their price in USD
|
||||
func (l2db *L2DB) UpdateTxValue(tokens []common.Token) (err error) {
|
||||
// WARNING: this is very slow and should be optimized
|
||||
txn, err := l2db.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
// Rollback the transaction if there was an error.
|
||||
if err != nil {
|
||||
err = txn.Rollback()
|
||||
}
|
||||
}()
|
||||
now := time.Now()
|
||||
for i := 0; i < len(tokens); i++ {
|
||||
_, err = txn.Exec(
|
||||
`UPDATE tx_pool
|
||||
SET usd_update = $1, value_usd = amount_f * $2, fee_usd = $2 * amount_f * CASE
|
||||
WHEN fee = 0 THEN 0
|
||||
WHEN fee >= 1 AND fee <= 32 THEN POWER(10,-24+(fee::float/2))
|
||||
WHEN fee >= 33 AND fee <= 223 THEN POWER(10,-8+(0.041666666666667*(fee::float-32)))
|
||||
WHEN fee >= 224 AND fee <= 255 THEN POWER(10,fee-224) END
|
||||
WHERE token_id = $3;`,
|
||||
now,
|
||||
tokens[i].USD,
|
||||
tokens[i].TokenID,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return txn.Commit()
|
||||
}
|
||||
|
||||
// Reorg updates the state of txs that were updated in a batch that has been discarted due to a blockchain reorg.
|
||||
// The state of the affected txs can change form Forged -> Pending or from Invalid -> Pending
|
||||
func (l2db *L2DB) Reorg(lastValidBatch common.BatchNum) error {
|
||||
@@ -286,8 +279,3 @@ func (l2db *L2DB) Purge(currentBatchNum common.BatchNum) (err error) {
|
||||
}
|
||||
return txn.Commit()
|
||||
}
|
||||
|
||||
// Close frees the resources used by the L2DB
|
||||
func (l2db *L2DB) Close() error {
|
||||
return l2db.db.Close()
|
||||
}
|
||||
|
||||
@@ -1,79 +1,110 @@
|
||||
package l2db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
dbUtils "github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
"github.com/hermeznetwork/hermez-node/log"
|
||||
"github.com/hermeznetwork/hermez-node/test"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var l2DB *L2DB
|
||||
var tokens []common.Token
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// init DB
|
||||
var err error
|
||||
pass := os.Getenv("POSTGRES_PASS")
|
||||
l2DB, err = NewL2DB(5432, "localhost", "hermez", pass, "l2", 10, 100, 24*time.Hour)
|
||||
db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
l2DB = NewL2DB(db, 10, 100, 24*time.Hour)
|
||||
tokens, err = prepareHistoryDB(db)
|
||||
if err != nil {
|
||||
log.Error("L2DB migration failed: " + err.Error())
|
||||
panic(err)
|
||||
} else {
|
||||
log.Debug("L2DB migration succed")
|
||||
}
|
||||
// Run tests
|
||||
result := m.Run()
|
||||
// Close DB
|
||||
if err := l2DB.Close(); err != nil {
|
||||
fmt.Println("Error closing the history DB:", err)
|
||||
if err := db.Close(); err != nil {
|
||||
log.Error("Error closing the history DB:", err)
|
||||
}
|
||||
os.Exit(result)
|
||||
}
|
||||
|
||||
func TestAddTx(t *testing.T) {
|
||||
func prepareHistoryDB(db *sqlx.DB) ([]common.Token, error) {
|
||||
historyDB := historydb.NewHistoryDB(db)
|
||||
const fromBlock int64 = 1
|
||||
const toBlock int64 = 5
|
||||
// Clean historyDB
|
||||
if err := historyDB.Reorg(-1); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Store blocks to historyDB
|
||||
blocks := test.GenBlocks(fromBlock, toBlock)
|
||||
if err := historyDB.AddBlocks(blocks); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Store tokens to historyDB
|
||||
const nTokens = 5
|
||||
tokens := test.GenTokens(nTokens, blocks)
|
||||
return tokens, historyDB.AddTokens(tokens)
|
||||
}
|
||||
|
||||
func TestAddTxTest(t *testing.T) {
|
||||
// Gen poolTxs
|
||||
const nInserts = 20
|
||||
test.CleanL2DB(l2DB.DB())
|
||||
txs := test.GenPoolTxs(nInserts)
|
||||
txs := test.GenPoolTxs(nInserts, tokens)
|
||||
for _, tx := range txs {
|
||||
err := l2DB.AddTx(tx)
|
||||
err := l2DB.AddTxTest(tx)
|
||||
assert.NoError(t, err)
|
||||
fetchedTx, err := l2DB.GetTx(tx.TxID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tx.Timestamp.Unix(), fetchedTx.Timestamp.Unix())
|
||||
tx.Timestamp = fetchedTx.Timestamp
|
||||
assert.Equal(t, tx.AbsoluteFeeUpdate.Unix(), fetchedTx.AbsoluteFeeUpdate.Unix())
|
||||
tx.Timestamp = fetchedTx.Timestamp
|
||||
tx.AbsoluteFeeUpdate = fetchedTx.AbsoluteFeeUpdate
|
||||
assert.Equal(t, tx, fetchedTx)
|
||||
assertTx(t, tx, fetchedTx)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAddTx(b *testing.B) {
|
||||
func assertTx(t *testing.T, expected, actual *common.PoolL2Tx) {
|
||||
assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
|
||||
expected.Timestamp = actual.Timestamp
|
||||
if expected.AbsoluteFeeUpdate != nil {
|
||||
assert.Equal(t, expected.AbsoluteFeeUpdate.Unix(), actual.AbsoluteFeeUpdate.Unix())
|
||||
expected.AbsoluteFeeUpdate = actual.AbsoluteFeeUpdate
|
||||
} else {
|
||||
assert.Equal(t, expected.AbsoluteFeeUpdate, actual.AbsoluteFeeUpdate)
|
||||
}
|
||||
test.AssertUSD(t, expected.AbsoluteFee, actual.AbsoluteFee)
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func BenchmarkAddTxTest(b *testing.B) {
|
||||
const nInserts = 20
|
||||
test.CleanL2DB(l2DB.DB())
|
||||
txs := test.GenPoolTxs(nInserts)
|
||||
txs := test.GenPoolTxs(nInserts, tokens)
|
||||
now := time.Now()
|
||||
for _, tx := range txs {
|
||||
_ = l2DB.AddTx(tx)
|
||||
_ = l2DB.AddTxTest(tx)
|
||||
}
|
||||
elapsedTime := time.Since(now)
|
||||
fmt.Println("Time to insert 2048 txs:", elapsedTime)
|
||||
log.Info("Time to insert 2048 txs:", elapsedTime)
|
||||
}
|
||||
|
||||
func TestGetPending(t *testing.T) {
|
||||
const nInserts = 20
|
||||
test.CleanL2DB(l2DB.DB())
|
||||
txs := test.GenPoolTxs(nInserts)
|
||||
txs := test.GenPoolTxs(nInserts, tokens)
|
||||
var pendingTxs []*common.PoolL2Tx
|
||||
for _, tx := range txs {
|
||||
err := l2DB.AddTx(tx)
|
||||
err := l2DB.AddTxTest(tx)
|
||||
assert.NoError(t, err)
|
||||
if tx.State == common.PoolL2TxStatePending {
|
||||
if tx.State == common.PoolL2TxStatePending && tx.AbsoluteFee != nil {
|
||||
pendingTxs = append(pendingTxs, tx)
|
||||
}
|
||||
}
|
||||
@@ -81,11 +112,7 @@ func TestGetPending(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(pendingTxs), len(fetchedTxs))
|
||||
for i, fetchedTx := range fetchedTxs {
|
||||
assert.Equal(t, pendingTxs[i].Timestamp.Unix(), fetchedTx.Timestamp.Unix())
|
||||
pendingTxs[i].Timestamp = fetchedTx.Timestamp
|
||||
assert.Equal(t, pendingTxs[i].AbsoluteFeeUpdate.Unix(), fetchedTx.AbsoluteFeeUpdate.Unix())
|
||||
pendingTxs[i].AbsoluteFeeUpdate = fetchedTx.AbsoluteFeeUpdate
|
||||
assert.Equal(t, pendingTxs[i], fetchedTx)
|
||||
assertTx(t, pendingTxs[i], fetchedTx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,12 +121,12 @@ func TestStartForging(t *testing.T) {
|
||||
const nInserts = 60
|
||||
const fakeBatchNum common.BatchNum = 33
|
||||
test.CleanL2DB(l2DB.DB())
|
||||
txs := test.GenPoolTxs(nInserts)
|
||||
txs := test.GenPoolTxs(nInserts, tokens)
|
||||
var startForgingTxIDs []common.TxID
|
||||
randomizer := 0
|
||||
// Add txs to DB
|
||||
for _, tx := range txs {
|
||||
err := l2DB.AddTx(tx)
|
||||
err := l2DB.AddTxTest(tx)
|
||||
assert.NoError(t, err)
|
||||
if tx.State == common.PoolL2TxStatePending && randomizer%2 == 0 {
|
||||
randomizer++
|
||||
@@ -123,12 +150,12 @@ func TestDoneForging(t *testing.T) {
|
||||
const nInserts = 60
|
||||
const fakeBatchNum common.BatchNum = 33
|
||||
test.CleanL2DB(l2DB.DB())
|
||||
txs := test.GenPoolTxs(nInserts)
|
||||
txs := test.GenPoolTxs(nInserts, tokens)
|
||||
var doneForgingTxIDs []common.TxID
|
||||
randomizer := 0
|
||||
// Add txs to DB
|
||||
for _, tx := range txs {
|
||||
err := l2DB.AddTx(tx)
|
||||
err := l2DB.AddTxTest(tx)
|
||||
assert.NoError(t, err)
|
||||
if tx.State == common.PoolL2TxStateForging && randomizer%2 == 0 {
|
||||
randomizer++
|
||||
@@ -152,12 +179,12 @@ func TestInvalidate(t *testing.T) {
|
||||
const nInserts = 60
|
||||
const fakeBatchNum common.BatchNum = 33
|
||||
test.CleanL2DB(l2DB.DB())
|
||||
txs := test.GenPoolTxs(nInserts)
|
||||
txs := test.GenPoolTxs(nInserts, tokens)
|
||||
var invalidTxIDs []common.TxID
|
||||
randomizer := 0
|
||||
// Add txs to DB
|
||||
for _, tx := range txs {
|
||||
err := l2DB.AddTx(tx)
|
||||
err := l2DB.AddTxTest(tx)
|
||||
assert.NoError(t, err)
|
||||
if tx.State != common.PoolL2TxStateInvalid && randomizer%2 == 0 {
|
||||
randomizer++
|
||||
@@ -181,7 +208,7 @@ func TestCheckNonces(t *testing.T) {
|
||||
const nInserts = 60
|
||||
const fakeBatchNum common.BatchNum = 33
|
||||
test.CleanL2DB(l2DB.DB())
|
||||
txs := test.GenPoolTxs(nInserts)
|
||||
txs := test.GenPoolTxs(nInserts, tokens)
|
||||
var invalidTxIDs []common.TxID
|
||||
// Generate accounts
|
||||
const nAccoutns = 2
|
||||
@@ -204,7 +231,7 @@ func TestCheckNonces(t *testing.T) {
|
||||
txs[i].Nonce = currentNonce + 1
|
||||
}
|
||||
}
|
||||
err := l2DB.AddTx(txs[i])
|
||||
err := l2DB.AddTxTest(txs[i])
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
// Start forging txs
|
||||
@@ -219,69 +246,13 @@ func TestCheckNonces(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateTxValue(t *testing.T) {
|
||||
// Generate txs
|
||||
const nInserts = 255 // Force all possible fee selector values
|
||||
test.CleanL2DB(l2DB.DB())
|
||||
txs := test.GenPoolTxs(nInserts)
|
||||
// Generate tokens
|
||||
const nTokens = 2
|
||||
tokens := []common.Token{}
|
||||
for i := 0; i < nTokens; i++ {
|
||||
tokens = append(tokens, common.Token{
|
||||
TokenID: common.TokenID(i),
|
||||
USD: float64(i) * 1.3,
|
||||
})
|
||||
}
|
||||
// Add txs to DB
|
||||
for i := 0; i < len(txs); i++ {
|
||||
// Set Token
|
||||
token := tokens[i%len(tokens)]
|
||||
txs[i].TokenID = token.TokenID
|
||||
// Insert to DB
|
||||
err := l2DB.AddTx(txs[i])
|
||||
assert.NoError(t, err)
|
||||
// Set USD values (for comparing results when fetching from DB)
|
||||
txs[i].USD = txs[i].AmountFloat * token.USD
|
||||
if txs[i].Fee == 0 {
|
||||
txs[i].AbsoluteFee = 0
|
||||
} else if txs[i].Fee <= 32 {
|
||||
txs[i].AbsoluteFee = txs[i].USD * math.Pow(10, -24+(float64(txs[i].Fee)/2))
|
||||
} else if txs[i].Fee <= 223 {
|
||||
txs[i].AbsoluteFee = txs[i].USD * math.Pow(10, -8+(0.041666666666667*(float64(txs[i].Fee)-32)))
|
||||
} else {
|
||||
txs[i].AbsoluteFee = txs[i].USD * math.Pow(10, float64(txs[i].Fee)-224)
|
||||
}
|
||||
}
|
||||
// Update token value
|
||||
err := l2DB.UpdateTxValue(tokens)
|
||||
assert.NoError(t, err)
|
||||
// Fetch txs and check that they've been updated correctly
|
||||
for _, tx := range txs {
|
||||
fetchedTx, err := l2DB.GetTx(tx.TxID)
|
||||
assert.NoError(t, err)
|
||||
if fetchedTx.USD > tx.USD {
|
||||
assert.Less(t, 0.999, tx.USD/fetchedTx.USD)
|
||||
} else if fetchedTx.USD < tx.USD {
|
||||
assert.Less(t, 0.999, fetchedTx.USD/tx.USD)
|
||||
}
|
||||
if fetchedTx.AbsoluteFee > tx.AbsoluteFee {
|
||||
assert.Less(t, 0.999, tx.AbsoluteFee/fetchedTx.AbsoluteFee)
|
||||
} else if fetchedTx.AbsoluteFee < tx.AbsoluteFee {
|
||||
assert.Less(t, 0.999, fetchedTx.AbsoluteFee/tx.AbsoluteFee)
|
||||
}
|
||||
// Time is set in the DB, so it cannot be compared exactly
|
||||
assert.Greater(t, float64(15*time.Second), time.Since(fetchedTx.AbsoluteFeeUpdate).Seconds())
|
||||
}
|
||||
}
|
||||
|
||||
func TestReorg(t *testing.T) {
|
||||
// Generate txs
|
||||
const nInserts = 20
|
||||
const lastValidBatch common.BatchNum = 20
|
||||
const reorgBatch common.BatchNum = lastValidBatch + 1
|
||||
test.CleanL2DB(l2DB.DB())
|
||||
txs := test.GenPoolTxs(nInserts)
|
||||
txs := test.GenPoolTxs(nInserts, tokens)
|
||||
// Add txs to the DB
|
||||
reorgedTxIDs := []common.TxID{}
|
||||
nonReorgedTxIDs := []common.TxID{}
|
||||
@@ -293,7 +264,7 @@ func TestReorg(t *testing.T) {
|
||||
txs[i].BatchNum = lastValidBatch
|
||||
nonReorgedTxIDs = append(nonReorgedTxIDs, txs[i].TxID)
|
||||
}
|
||||
err := l2DB.AddTx(txs[i])
|
||||
err := l2DB.AddTxTest(txs[i])
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
err := l2DB.Reorg(lastValidBatch)
|
||||
@@ -316,7 +287,7 @@ func TestPurge(t *testing.T) {
|
||||
// Generate txs
|
||||
nInserts := l2DB.maxTxs + 20
|
||||
test.CleanL2DB(l2DB.DB())
|
||||
txs := test.GenPoolTxs(int(nInserts))
|
||||
txs := test.GenPoolTxs(int(nInserts), tokens)
|
||||
deletedIDs := []common.TxID{}
|
||||
keepedIDs := []common.TxID{}
|
||||
const toDeleteBatchNum common.BatchNum = 30
|
||||
@@ -335,14 +306,14 @@ func TestPurge(t *testing.T) {
|
||||
}
|
||||
deletedIDs = append(deletedIDs, txs[i].TxID)
|
||||
}
|
||||
err := l2DB.AddTx(txs[i])
|
||||
err := l2DB.AddTxTest(txs[i])
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
for i := int(l2DB.maxTxs); i < len(txs); i++ {
|
||||
// Delete after TTL
|
||||
txs[i].Timestamp = time.Unix(time.Now().UTC().Unix()-int64(l2DB.ttl.Seconds()+float64(4*time.Second)), 0)
|
||||
deletedIDs = append(deletedIDs, txs[i].TxID)
|
||||
err := l2DB.AddTx(txs[i])
|
||||
err := l2DB.AddTxTest(txs[i])
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
// Purge txs
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
-- +migrate Up
|
||||
CREATE TABLE tx_pool (
|
||||
tx_id BYTEA PRIMARY KEY,
|
||||
from_idx BIGINT NOT NULL,
|
||||
to_idx BIGINT NOT NULL,
|
||||
to_eth_addr BYTEA NOT NULL,
|
||||
to_bjj BYTEA NOT NULL,
|
||||
token_id INT NOT NULL,
|
||||
amount BYTEA NOT NULL,
|
||||
amount_f NUMERIC NOT NULL,
|
||||
value_usd NUMERIC,
|
||||
fee SMALLINT NOT NULL,
|
||||
nonce BIGINT NOT NULL,
|
||||
state CHAR(4) NOT NULL,
|
||||
signature BYTEA NOT NULL,
|
||||
timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
|
||||
batch_num BIGINT,
|
||||
rq_from_idx BIGINT,
|
||||
rq_to_idx BIGINT,
|
||||
rq_to_eth_addr BYTEA,
|
||||
rq_to_bjj BYTEA,
|
||||
rq_token_id INT,
|
||||
rq_amount BYTEA,
|
||||
rq_fee SMALLINT,
|
||||
rq_nonce BIGINT,
|
||||
fee_usd NUMERIC,
|
||||
usd_update TIMESTAMP WITHOUT TIME ZONE,
|
||||
tx_type VARCHAR(40) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE account_creation_auth (
|
||||
eth_addr BYTEA PRIMARY KEY,
|
||||
bjj BYTEA NOT NULL,
|
||||
signature BYTEA NOT NULL,
|
||||
timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL
|
||||
);
|
||||
|
||||
-- +migrate Down
|
||||
DROP TABLE account_creation_auth;
|
||||
DROP TABLE tx_pool;
|
||||
515
db/migrations/0001.sql
Normal file
515
db/migrations/0001.sql
Normal file
@@ -0,0 +1,515 @@
|
||||
-- +migrate Up
|
||||
|
||||
-- History
|
||||
CREATE TABLE block (
|
||||
eth_block_num BIGINT PRIMARY KEY,
|
||||
timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
|
||||
hash BYTEA NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE coordinator (
|
||||
forger_addr BYTEA NOT NULL,
|
||||
eth_block_num BIGINT NOT NULL REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
withdraw_addr BYTEA NOT NULL,
|
||||
url VARCHAR(200) NOT NULL,
|
||||
PRIMARY KEY (forger_addr, eth_block_num)
|
||||
);
|
||||
|
||||
CREATE TABLE batch (
|
||||
batch_num BIGINT PRIMARY KEY,
|
||||
eth_block_num BIGINT REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
forger_addr BYTEA NOT NULL, -- fake foreign key for coordinator
|
||||
fees_collected BYTEA NOT NULL,
|
||||
state_root BYTEA NOT NULL,
|
||||
num_accounts BIGINT NOT NULL,
|
||||
exit_root BYTEA NOT NULL,
|
||||
forge_l1_txs_num BIGINT,
|
||||
slot_num BIGINT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE exit_tree (
|
||||
batch_num BIGINT REFERENCES batch (batch_num) ON DELETE CASCADE,
|
||||
account_idx BIGINT,
|
||||
merkle_proof BYTEA NOT NULL,
|
||||
balance BYTEA NOT NULL,
|
||||
instant_withdrawn BIGINT REFERENCES batch (batch_num) ON DELETE SET NULL,
|
||||
delayed_withdraw_request BIGINT REFERENCES batch (batch_num) ON DELETE SET NULL,
|
||||
delayed_withdrawn BIGINT REFERENCES batch (batch_num) ON DELETE SET NULL,
|
||||
PRIMARY KEY (batch_num, account_idx)
|
||||
);
|
||||
|
||||
CREATE TABLE bid (
|
||||
slot_num BIGINT NOT NULL,
|
||||
bid_value BYTEA NOT NULL,
|
||||
eth_block_num BIGINT NOT NULL REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
forger_addr BYTEA NOT NULL, -- fake foreign key for coordinator
|
||||
PRIMARY KEY (slot_num, bid_value)
|
||||
);
|
||||
|
||||
CREATE TABLE token (
|
||||
token_id INT PRIMARY KEY,
|
||||
eth_block_num BIGINT NOT NULL REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
eth_addr BYTEA UNIQUE NOT NULL,
|
||||
name VARCHAR(20) NOT NULL,
|
||||
symbol VARCHAR(10) NOT NULL,
|
||||
decimals INT NOT NULL,
|
||||
usd NUMERIC,
|
||||
usd_update TIMESTAMP
|
||||
);
|
||||
|
||||
-- +migrate StatementBegin
|
||||
CREATE FUNCTION set_token_usd_update()
|
||||
RETURNS TRIGGER
|
||||
AS
|
||||
$BODY$
|
||||
BEGIN
|
||||
IF NEW."usd" IS NOT NULL AND NEW."usd_update" IS NULL THEN
|
||||
NEW."usd_update" = timezone('utc', now());
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$BODY$
|
||||
LANGUAGE plpgsql;
|
||||
-- +migrate StatementEnd
|
||||
CREATE TRIGGER trigger_token_usd_update BEFORE UPDATE OR INSERT ON token
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_token_usd_update();
|
||||
|
||||
CREATE TABLE tx (
|
||||
-- Generic TX
|
||||
is_l1 BOOLEAN NOT NULL,
|
||||
id BYTEA PRIMARY KEY,
|
||||
type VARCHAR(40) NOT NULL,
|
||||
position INT NOT NULL,
|
||||
from_idx BIGINT NOT NULL,
|
||||
to_idx BIGINT NOT NULL,
|
||||
amount BYTEA NOT NULL,
|
||||
amount_f NUMERIC NOT NULL,
|
||||
token_id INT NOT NULL REFERENCES token (token_id),
|
||||
amount_usd NUMERIC, -- Value of the amount in USD at the moment the tx was inserted in the DB
|
||||
batch_num BIGINT REFERENCES batch (batch_num) ON DELETE SET NULL, -- Can be NULL in the case of L1 txs that are on the queue but not forged yet.
|
||||
eth_block_num BIGINT NOT NULL REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
-- L1
|
||||
to_forge_l1_txs_num BIGINT,
|
||||
user_origin BOOLEAN,
|
||||
from_eth_addr BYTEA,
|
||||
from_bjj BYTEA,
|
||||
load_amount BYTEA,
|
||||
load_amount_f NUMERIC,
|
||||
load_amount_usd NUMERIC,
|
||||
-- L2
|
||||
fee INT,
|
||||
fee_usd NUMERIC,
|
||||
nonce BIGINT
|
||||
);
|
||||
|
||||
CREATE INDEX tx_order ON tx (batch_num, position);
|
||||
|
||||
-- +migrate StatementBegin
|
||||
CREATE FUNCTION fee_percentage(NUMERIC)
|
||||
RETURNS NUMERIC
|
||||
AS
|
||||
$BODY$
|
||||
DECLARE perc NUMERIC;
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN $1 = 0 THEN 0
|
||||
WHEN $1 = 1 THEN 3.162278e-24
|
||||
WHEN $1 = 2 THEN 1.000000e-23
|
||||
WHEN $1 = 3 THEN 3.162278e-23
|
||||
WHEN $1 = 4 THEN 1.000000e-22
|
||||
WHEN $1 = 5 THEN 3.162278e-22
|
||||
WHEN $1 = 6 THEN 1.000000e-21
|
||||
WHEN $1 = 7 THEN 3.162278e-21
|
||||
WHEN $1 = 8 THEN 1.000000e-20
|
||||
WHEN $1 = 9 THEN 3.162278e-20
|
||||
WHEN $1 = 10 THEN 1.000000e-19
|
||||
WHEN $1 = 11 THEN 3.162278e-19
|
||||
WHEN $1 = 12 THEN 1.000000e-18
|
||||
WHEN $1 = 13 THEN 3.162278e-18
|
||||
WHEN $1 = 14 THEN 1.000000e-17
|
||||
WHEN $1 = 15 THEN 3.162278e-17
|
||||
WHEN $1 = 16 THEN 1.000000e-16
|
||||
WHEN $1 = 17 THEN 3.162278e-16
|
||||
WHEN $1 = 18 THEN 1.000000e-15
|
||||
WHEN $1 = 19 THEN 3.162278e-15
|
||||
WHEN $1 = 20 THEN 1.000000e-14
|
||||
WHEN $1 = 21 THEN 3.162278e-14
|
||||
WHEN $1 = 22 THEN 1.000000e-13
|
||||
WHEN $1 = 23 THEN 3.162278e-13
|
||||
WHEN $1 = 24 THEN 1.000000e-12
|
||||
WHEN $1 = 25 THEN 3.162278e-12
|
||||
WHEN $1 = 26 THEN 1.000000e-11
|
||||
WHEN $1 = 27 THEN 3.162278e-11
|
||||
WHEN $1 = 28 THEN 1.000000e-10
|
||||
WHEN $1 = 29 THEN 3.162278e-10
|
||||
WHEN $1 = 30 THEN 1.000000e-09
|
||||
WHEN $1 = 31 THEN 3.162278e-09
|
||||
WHEN $1 = 32 THEN 1.000000e-08
|
||||
WHEN $1 = 33 THEN 1.100694e-08
|
||||
WHEN $1 = 34 THEN 1.211528e-08
|
||||
WHEN $1 = 35 THEN 1.333521e-08
|
||||
WHEN $1 = 36 THEN 1.467799e-08
|
||||
WHEN $1 = 37 THEN 1.615598e-08
|
||||
WHEN $1 = 38 THEN 1.778279e-08
|
||||
WHEN $1 = 39 THEN 1.957342e-08
|
||||
WHEN $1 = 40 THEN 2.154435e-08
|
||||
WHEN $1 = 41 THEN 2.371374e-08
|
||||
WHEN $1 = 42 THEN 2.610157e-08
|
||||
WHEN $1 = 43 THEN 2.872985e-08
|
||||
WHEN $1 = 44 THEN 3.162278e-08
|
||||
WHEN $1 = 45 THEN 3.480701e-08
|
||||
WHEN $1 = 46 THEN 3.831187e-08
|
||||
WHEN $1 = 47 THEN 4.216965e-08
|
||||
WHEN $1 = 48 THEN 4.641589e-08
|
||||
WHEN $1 = 49 THEN 5.108970e-08
|
||||
WHEN $1 = 50 THEN 5.623413e-08
|
||||
WHEN $1 = 51 THEN 6.189658e-08
|
||||
WHEN $1 = 52 THEN 6.812921e-08
|
||||
WHEN $1 = 53 THEN 7.498942e-08
|
||||
WHEN $1 = 54 THEN 8.254042e-08
|
||||
WHEN $1 = 55 THEN 9.085176e-08
|
||||
WHEN $1 = 56 THEN 1.000000e-07
|
||||
WHEN $1 = 57 THEN 1.100694e-07
|
||||
WHEN $1 = 58 THEN 1.211528e-07
|
||||
WHEN $1 = 59 THEN 1.333521e-07
|
||||
WHEN $1 = 60 THEN 1.467799e-07
|
||||
WHEN $1 = 61 THEN 1.615598e-07
|
||||
WHEN $1 = 62 THEN 1.778279e-07
|
||||
WHEN $1 = 63 THEN 1.957342e-07
|
||||
WHEN $1 = 64 THEN 2.154435e-07
|
||||
WHEN $1 = 65 THEN 2.371374e-07
|
||||
WHEN $1 = 66 THEN 2.610157e-07
|
||||
WHEN $1 = 67 THEN 2.872985e-07
|
||||
WHEN $1 = 68 THEN 3.162278e-07
|
||||
WHEN $1 = 69 THEN 3.480701e-07
|
||||
WHEN $1 = 70 THEN 3.831187e-07
|
||||
WHEN $1 = 71 THEN 4.216965e-07
|
||||
WHEN $1 = 72 THEN 4.641589e-07
|
||||
WHEN $1 = 73 THEN 5.108970e-07
|
||||
WHEN $1 = 74 THEN 5.623413e-07
|
||||
WHEN $1 = 75 THEN 6.189658e-07
|
||||
WHEN $1 = 76 THEN 6.812921e-07
|
||||
WHEN $1 = 77 THEN 7.498942e-07
|
||||
WHEN $1 = 78 THEN 8.254042e-07
|
||||
WHEN $1 = 79 THEN 9.085176e-07
|
||||
WHEN $1 = 80 THEN 1.000000e-06
|
||||
WHEN $1 = 81 THEN 1.100694e-06
|
||||
WHEN $1 = 82 THEN 1.211528e-06
|
||||
WHEN $1 = 83 THEN 1.333521e-06
|
||||
WHEN $1 = 84 THEN 1.467799e-06
|
||||
WHEN $1 = 85 THEN 1.615598e-06
|
||||
WHEN $1 = 86 THEN 1.778279e-06
|
||||
WHEN $1 = 87 THEN 1.957342e-06
|
||||
WHEN $1 = 88 THEN 2.154435e-06
|
||||
WHEN $1 = 89 THEN 2.371374e-06
|
||||
WHEN $1 = 90 THEN 2.610157e-06
|
||||
WHEN $1 = 91 THEN 2.872985e-06
|
||||
WHEN $1 = 92 THEN 3.162278e-06
|
||||
WHEN $1 = 93 THEN 3.480701e-06
|
||||
WHEN $1 = 94 THEN 3.831187e-06
|
||||
WHEN $1 = 95 THEN 4.216965e-06
|
||||
WHEN $1 = 96 THEN 4.641589e-06
|
||||
WHEN $1 = 97 THEN 5.108970e-06
|
||||
WHEN $1 = 98 THEN 5.623413e-06
|
||||
WHEN $1 = 99 THEN 6.189658e-06
|
||||
WHEN $1 = 100 THEN 6.812921e-06
|
||||
WHEN $1 = 101 THEN 7.498942e-06
|
||||
WHEN $1 = 102 THEN 8.254042e-06
|
||||
WHEN $1 = 103 THEN 9.085176e-06
|
||||
WHEN $1 = 104 THEN 1.000000e-05
|
||||
WHEN $1 = 105 THEN 1.100694e-05
|
||||
WHEN $1 = 106 THEN 1.211528e-05
|
||||
WHEN $1 = 107 THEN 1.333521e-05
|
||||
WHEN $1 = 108 THEN 1.467799e-05
|
||||
WHEN $1 = 109 THEN 1.615598e-05
|
||||
WHEN $1 = 110 THEN 1.778279e-05
|
||||
WHEN $1 = 111 THEN 1.957342e-05
|
||||
WHEN $1 = 112 THEN 2.154435e-05
|
||||
WHEN $1 = 113 THEN 2.371374e-05
|
||||
WHEN $1 = 114 THEN 2.610157e-05
|
||||
WHEN $1 = 115 THEN 2.872985e-05
|
||||
WHEN $1 = 116 THEN 3.162278e-05
|
||||
WHEN $1 = 117 THEN 3.480701e-05
|
||||
WHEN $1 = 118 THEN 3.831187e-05
|
||||
WHEN $1 = 119 THEN 4.216965e-05
|
||||
WHEN $1 = 120 THEN 4.641589e-05
|
||||
WHEN $1 = 121 THEN 5.108970e-05
|
||||
WHEN $1 = 122 THEN 5.623413e-05
|
||||
WHEN $1 = 123 THEN 6.189658e-05
|
||||
WHEN $1 = 124 THEN 6.812921e-05
|
||||
WHEN $1 = 125 THEN 7.498942e-05
|
||||
WHEN $1 = 126 THEN 8.254042e-05
|
||||
WHEN $1 = 127 THEN 9.085176e-05
|
||||
WHEN $1 = 128 THEN 1.000000e-04
|
||||
WHEN $1 = 129 THEN 1.100694e-04
|
||||
WHEN $1 = 130 THEN 1.211528e-04
|
||||
WHEN $1 = 131 THEN 1.333521e-04
|
||||
WHEN $1 = 132 THEN 1.467799e-04
|
||||
WHEN $1 = 133 THEN 1.615598e-04
|
||||
WHEN $1 = 134 THEN 1.778279e-04
|
||||
WHEN $1 = 135 THEN 1.957342e-04
|
||||
WHEN $1 = 136 THEN 2.154435e-04
|
||||
WHEN $1 = 137 THEN 2.371374e-04
|
||||
WHEN $1 = 138 THEN 2.610157e-04
|
||||
WHEN $1 = 139 THEN 2.872985e-04
|
||||
WHEN $1 = 140 THEN 3.162278e-04
|
||||
WHEN $1 = 141 THEN 3.480701e-04
|
||||
WHEN $1 = 142 THEN 3.831187e-04
|
||||
WHEN $1 = 143 THEN 4.216965e-04
|
||||
WHEN $1 = 144 THEN 4.641589e-04
|
||||
WHEN $1 = 145 THEN 5.108970e-04
|
||||
WHEN $1 = 146 THEN 5.623413e-04
|
||||
WHEN $1 = 147 THEN 6.189658e-04
|
||||
WHEN $1 = 148 THEN 6.812921e-04
|
||||
WHEN $1 = 149 THEN 7.498942e-04
|
||||
WHEN $1 = 150 THEN 8.254042e-04
|
||||
WHEN $1 = 151 THEN 9.085176e-04
|
||||
WHEN $1 = 152 THEN 1.000000e-03
|
||||
WHEN $1 = 153 THEN 1.100694e-03
|
||||
WHEN $1 = 154 THEN 1.211528e-03
|
||||
WHEN $1 = 155 THEN 1.333521e-03
|
||||
WHEN $1 = 156 THEN 1.467799e-03
|
||||
WHEN $1 = 157 THEN 1.615598e-03
|
||||
WHEN $1 = 158 THEN 1.778279e-03
|
||||
WHEN $1 = 159 THEN 1.957342e-03
|
||||
WHEN $1 = 160 THEN 2.154435e-03
|
||||
WHEN $1 = 161 THEN 2.371374e-03
|
||||
WHEN $1 = 162 THEN 2.610157e-03
|
||||
WHEN $1 = 163 THEN 2.872985e-03
|
||||
WHEN $1 = 164 THEN 3.162278e-03
|
||||
WHEN $1 = 165 THEN 3.480701e-03
|
||||
WHEN $1 = 166 THEN 3.831187e-03
|
||||
WHEN $1 = 167 THEN 4.216965e-03
|
||||
WHEN $1 = 168 THEN 4.641589e-03
|
||||
WHEN $1 = 169 THEN 5.108970e-03
|
||||
WHEN $1 = 170 THEN 5.623413e-03
|
||||
WHEN $1 = 171 THEN 6.189658e-03
|
||||
WHEN $1 = 172 THEN 6.812921e-03
|
||||
WHEN $1 = 173 THEN 7.498942e-03
|
||||
WHEN $1 = 174 THEN 8.254042e-03
|
||||
WHEN $1 = 175 THEN 9.085176e-03
|
||||
WHEN $1 = 176 THEN 1.000000e-02
|
||||
WHEN $1 = 177 THEN 1.100694e-02
|
||||
WHEN $1 = 178 THEN 1.211528e-02
|
||||
WHEN $1 = 179 THEN 1.333521e-02
|
||||
WHEN $1 = 180 THEN 1.467799e-02
|
||||
WHEN $1 = 181 THEN 1.615598e-02
|
||||
WHEN $1 = 182 THEN 1.778279e-02
|
||||
WHEN $1 = 183 THEN 1.957342e-02
|
||||
WHEN $1 = 184 THEN 2.154435e-02
|
||||
WHEN $1 = 185 THEN 2.371374e-02
|
||||
WHEN $1 = 186 THEN 2.610157e-02
|
||||
WHEN $1 = 187 THEN 2.872985e-02
|
||||
WHEN $1 = 188 THEN 3.162278e-02
|
||||
WHEN $1 = 189 THEN 3.480701e-02
|
||||
WHEN $1 = 190 THEN 3.831187e-02
|
||||
WHEN $1 = 191 THEN 4.216965e-02
|
||||
WHEN $1 = 192 THEN 4.641589e-02
|
||||
WHEN $1 = 193 THEN 5.108970e-02
|
||||
WHEN $1 = 194 THEN 5.623413e-02
|
||||
WHEN $1 = 195 THEN 6.189658e-02
|
||||
WHEN $1 = 196 THEN 6.812921e-02
|
||||
WHEN $1 = 197 THEN 7.498942e-02
|
||||
WHEN $1 = 198 THEN 8.254042e-02
|
||||
WHEN $1 = 199 THEN 9.085176e-02
|
||||
WHEN $1 = 200 THEN 1.000000e-01
|
||||
WHEN $1 = 201 THEN 1.100694e-01
|
||||
WHEN $1 = 202 THEN 1.211528e-01
|
||||
WHEN $1 = 203 THEN 1.333521e-01
|
||||
WHEN $1 = 204 THEN 1.467799e-01
|
||||
WHEN $1 = 205 THEN 1.615598e-01
|
||||
WHEN $1 = 206 THEN 1.778279e-01
|
||||
WHEN $1 = 207 THEN 1.957342e-01
|
||||
WHEN $1 = 208 THEN 2.154435e-01
|
||||
WHEN $1 = 209 THEN 2.371374e-01
|
||||
WHEN $1 = 210 THEN 2.610157e-01
|
||||
WHEN $1 = 211 THEN 2.872985e-01
|
||||
WHEN $1 = 212 THEN 3.162278e-01
|
||||
WHEN $1 = 213 THEN 3.480701e-01
|
||||
WHEN $1 = 214 THEN 3.831187e-01
|
||||
WHEN $1 = 215 THEN 4.216965e-01
|
||||
WHEN $1 = 216 THEN 4.641589e-01
|
||||
WHEN $1 = 217 THEN 5.108970e-01
|
||||
WHEN $1 = 218 THEN 5.623413e-01
|
||||
WHEN $1 = 219 THEN 6.189658e-01
|
||||
WHEN $1 = 220 THEN 6.812921e-01
|
||||
WHEN $1 = 221 THEN 7.498942e-01
|
||||
WHEN $1 = 222 THEN 8.254042e-01
|
||||
WHEN $1 = 223 THEN 9.085176e-01
|
||||
WHEN $1 = 224 THEN 1.000000e+00
|
||||
WHEN $1 = 225 THEN 1.000000e+01
|
||||
WHEN $1 = 226 THEN 1.000000e+02
|
||||
WHEN $1 = 227 THEN 1.000000e+03
|
||||
WHEN $1 = 228 THEN 1.000000e+04
|
||||
WHEN $1 = 229 THEN 1.000000e+05
|
||||
WHEN $1 = 230 THEN 1.000000e+06
|
||||
WHEN $1 = 231 THEN 1.000000e+07
|
||||
WHEN $1 = 232 THEN 1.000000e+08
|
||||
WHEN $1 = 233 THEN 1.000000e+09
|
||||
WHEN $1 = 234 THEN 1.000000e+10
|
||||
WHEN $1 = 235 THEN 1.000000e+11
|
||||
WHEN $1 = 236 THEN 1.000000e+12
|
||||
WHEN $1 = 237 THEN 1.000000e+13
|
||||
WHEN $1 = 238 THEN 1.000000e+14
|
||||
WHEN $1 = 239 THEN 1.000000e+15
|
||||
WHEN $1 = 240 THEN 1.000000e+16
|
||||
WHEN $1 = 241 THEN 1.000000e+17
|
||||
WHEN $1 = 242 THEN 1.000000e+18
|
||||
WHEN $1 = 243 THEN 1.000000e+19
|
||||
WHEN $1 = 244 THEN 1.000000e+20
|
||||
WHEN $1 = 245 THEN 1.000000e+21
|
||||
WHEN $1 = 246 THEN 1.000000e+22
|
||||
WHEN $1 = 247 THEN 1.000000e+23
|
||||
WHEN $1 = 248 THEN 1.000000e+24
|
||||
WHEN $1 = 249 THEN 1.000000e+25
|
||||
WHEN $1 = 250 THEN 1.000000e+26
|
||||
WHEN $1 = 251 THEN 1.000000e+27
|
||||
WHEN $1 = 252 THEN 1.000000e+28
|
||||
WHEN $1 = 253 THEN 1.000000e+29
|
||||
WHEN $1 = 254 THEN 1.000000e+30
|
||||
WHEN $1 = 255 THEN 1.000000e+31
|
||||
END INTO perc;
|
||||
RETURN perc;
|
||||
END;
|
||||
$BODY$
|
||||
LANGUAGE plpgsql;
|
||||
-- +migrate StatementEnd
|
||||
|
||||
-- +migrate StatementBegin
|
||||
CREATE FUNCTION set_tx()
|
||||
RETURNS TRIGGER
|
||||
AS
|
||||
$BODY$
|
||||
DECLARE token_value NUMERIC;
|
||||
BEGIN
|
||||
-- Validate L1/L2 constrains
|
||||
IF NEW.is_l1 AND (( -- L1 mandatory fields
|
||||
NEW.user_origin IS NULL OR
|
||||
NEW.from_eth_addr IS NULL OR
|
||||
NEW.from_bjj IS NULL OR
|
||||
NEW.load_amount IS NULL OR
|
||||
NEW.load_amount_f IS NULL
|
||||
) OR (NOT NEW.user_origin AND NEW.batch_num IS NULL)) THEN -- If is Coordinator L1, must include batch_num
|
||||
RAISE EXCEPTION 'Invalid L1 tx.';
|
||||
ELSIF NOT NEW.is_l1 THEN
|
||||
IF NEW.fee IS NULL THEN
|
||||
NEW.fee = (SELECT 0);
|
||||
END IF;
|
||||
IF NEW.batch_num IS NULL OR NEW.nonce IS NULL THEN
|
||||
RAISE EXCEPTION 'Invalid L2 tx.';
|
||||
END IF;
|
||||
END IF;
|
||||
-- If is L2, add token_id
|
||||
IF NOT NEW.is_l1 THEN
|
||||
NEW."token_id" = (SELECT token_id FROM account WHERE idx = NEW."from_idx");
|
||||
END IF;
|
||||
-- Set value_usd
|
||||
token_value = (SELECT usd / POWER(10, decimals) FROM token WHERE token_id = NEW.token_id);
|
||||
NEW."amount_usd" = (SELECT token_value * NEW.amount_f);
|
||||
NEW."load_amount_usd" = (SELECT token_value * NEW.load_amount_f);
|
||||
IF NOT NEW.is_l1 THEN
|
||||
NEW."fee_usd" = (SELECT NEW."amount_usd" * fee_percentage(NEW.fee::NUMERIC));
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$BODY$
|
||||
LANGUAGE plpgsql;
|
||||
-- +migrate StatementEnd
|
||||
CREATE TRIGGER trigger_set_tx BEFORE INSERT ON tx
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_tx();
|
||||
|
||||
-- +migrate StatementBegin
|
||||
CREATE FUNCTION forge_l1_user_txs()
|
||||
RETURNS TRIGGER
|
||||
AS
|
||||
$BODY$
|
||||
BEGIN
|
||||
IF NEW.forge_l1_txs_num IS NOT NULL THEN
|
||||
UPDATE tx
|
||||
SET batch_num = NEW.batch_num
|
||||
WHERE user_origin AND NEW.forge_l1_txs_num = to_forge_l1_txs_num;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$BODY$
|
||||
LANGUAGE plpgsql;
|
||||
-- +migrate StatementEnd
|
||||
CREATE TRIGGER trigger_forge_l1_txs AFTER INSERT ON batch
|
||||
FOR EACH ROW EXECUTE PROCEDURE forge_l1_user_txs();
|
||||
|
||||
CREATE TABLE account (
|
||||
idx BIGINT PRIMARY KEY,
|
||||
token_id INT NOT NULL REFERENCES token (token_id) ON DELETE CASCADE,
|
||||
batch_num BIGINT NOT NULL REFERENCES batch (batch_num) ON DELETE CASCADE,
|
||||
bjj BYTEA NOT NULL,
|
||||
eth_addr BYTEA NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE rollup_vars (
|
||||
eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
forge_l1_timeout BYTEA NOT NULL,
|
||||
fee_l1_user_tx BYTEA NOT NULL,
|
||||
fee_add_token BYTEA NOT NULL,
|
||||
tokens_hez BYTEA NOT NULL,
|
||||
governance BYTEA NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE consensus_vars (
|
||||
eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||
slot_deadline INT NOT NULL,
|
||||
close_auction_slots INT NOT NULL,
|
||||
open_auction_slots INT NOT NULL,
|
||||
min_bid_slots VARCHAR(200) NOT NULL,
|
||||
outbidding INT NOT NULL,
|
||||
donation_address BYTEA NOT NULL,
|
||||
governance_address BYTEA NOT NULL,
|
||||
allocation_ratio VARCHAR(200)
|
||||
);
|
||||
|
||||
-- L2
|
||||
CREATE TABLE tx_pool (
|
||||
tx_id BYTEA PRIMARY KEY,
|
||||
from_idx BIGINT NOT NULL,
|
||||
to_idx BIGINT NOT NULL,
|
||||
to_eth_addr BYTEA NOT NULL,
|
||||
to_bjj BYTEA NOT NULL,
|
||||
token_id INT NOT NULL REFERENCES token (token_id) ON DELETE CASCADE,
|
||||
amount BYTEA NOT NULL,
|
||||
amount_f NUMERIC NOT NULL,
|
||||
fee SMALLINT NOT NULL,
|
||||
nonce BIGINT NOT NULL,
|
||||
state CHAR(4) NOT NULL,
|
||||
signature BYTEA NOT NULL,
|
||||
timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
|
||||
batch_num BIGINT,
|
||||
rq_from_idx BIGINT,
|
||||
rq_to_idx BIGINT,
|
||||
rq_to_eth_addr BYTEA,
|
||||
rq_to_bjj BYTEA,
|
||||
rq_token_id INT,
|
||||
rq_amount BYTEA,
|
||||
rq_fee SMALLINT,
|
||||
rq_nonce BIGINT,
|
||||
tx_type VARCHAR(40) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE account_creation_auth (
|
||||
eth_addr BYTEA PRIMARY KEY,
|
||||
bjj BYTEA NOT NULL,
|
||||
signature BYTEA NOT NULL,
|
||||
timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL
|
||||
);
|
||||
|
||||
-- +migrate Down
|
||||
DROP TABLE account_creation_auth;
|
||||
DROP TABLE tx_pool;
|
||||
DROP TABLE consensus_vars;
|
||||
DROP TABLE rollup_vars;
|
||||
DROP TABLE account;
|
||||
DROP TABLE tx;
|
||||
DROP TABLE token;
|
||||
DROP TABLE bid;
|
||||
DROP TABLE exit_tree;
|
||||
DROP TABLE batch;
|
||||
DROP TABLE coordinator;
|
||||
DROP TABLE block;
|
||||
@@ -27,7 +27,7 @@ func TestProcessTxs(t *testing.T) {
|
||||
instructions, err := parser.Parse()
|
||||
assert.Nil(t, err)
|
||||
|
||||
l1Txs, coordinatorL1Txs, poolL2Txs := test.GenerateTestTxs(t, instructions)
|
||||
l1Txs, coordinatorL1Txs, poolL2Txs, _ := test.GenerateTestTxs(t, instructions)
|
||||
assert.Equal(t, 29, len(l1Txs[0]))
|
||||
assert.Equal(t, 0, len(coordinatorL1Txs[0]))
|
||||
assert.Equal(t, 21, len(poolL2Txs[0]))
|
||||
@@ -57,7 +57,7 @@ func TestProcessTxsBatchByBatch(t *testing.T) {
|
||||
instructions, err := parser.Parse()
|
||||
assert.Nil(t, err)
|
||||
|
||||
l1Txs, coordinatorL1Txs, poolL2Txs := test.GenerateTestTxs(t, instructions)
|
||||
l1Txs, coordinatorL1Txs, poolL2Txs, _ := test.GenerateTestTxs(t, instructions)
|
||||
assert.Equal(t, 29, len(l1Txs[0]))
|
||||
assert.Equal(t, 0, len(coordinatorL1Txs[0]))
|
||||
assert.Equal(t, 21, len(poolL2Txs[0]))
|
||||
@@ -108,7 +108,7 @@ func TestZKInputsGeneration(t *testing.T) {
|
||||
instructions, err := parser.Parse()
|
||||
assert.Nil(t, err)
|
||||
|
||||
l1Txs, coordinatorL1Txs, poolL2Txs := test.GenerateTestTxs(t, instructions)
|
||||
l1Txs, coordinatorL1Txs, poolL2Txs, _ := test.GenerateTestTxs(t, instructions)
|
||||
assert.Equal(t, 29, len(l1Txs[0]))
|
||||
assert.Equal(t, 0, len(coordinatorL1Txs[0]))
|
||||
assert.Equal(t, 21, len(poolL2Txs[0]))
|
||||
|
||||
38
db/utils.go
38
db/utils.go
@@ -7,11 +7,45 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/hermeznetwork/hermez-node/log"
|
||||
"github.com/jmoiron/sqlx"
|
||||
migrate "github.com/rubenv/sql-migrate"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
// InitMeddler registers tags to be used to read/write from SQL DBs using meddler
|
||||
func InitMeddler() {
|
||||
// InitSQLDB runs migrations and registers meddlers
|
||||
func InitSQLDB(port int, host, user, password, name string) (*sqlx.DB, error) {
|
||||
// Init meddler
|
||||
initMeddler()
|
||||
meddler.Default = meddler.PostgreSQL
|
||||
// Stablish connection
|
||||
psqlconn := fmt.Sprintf(
|
||||
"host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
|
||||
host,
|
||||
port,
|
||||
user,
|
||||
password,
|
||||
name,
|
||||
)
|
||||
db, err := sqlx.Connect("postgres", psqlconn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Run DB migrations
|
||||
migrations := &migrate.PackrMigrationSource{
|
||||
Box: packr.New("hermez-db-migrations", "./migrations"),
|
||||
}
|
||||
nMigrations, err := migrate.Exec(db.DB, "postgres", migrations, migrate.Up)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Info("successfully runt ", nMigrations, " migrations")
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// initMeddler registers tags to be used to read/write from SQL DBs using meddler
|
||||
func initMeddler() {
|
||||
meddler.Register("bigint", BigIntMeddler{})
|
||||
meddler.Register("bigintnull", BigIntNullMeddler{})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user