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:
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Postgres
|
- name: Postgres
|
||||||
run: docker run --rm --name hermez-db-test -p 5432:5432 -e POSTGRES_DB=history -e POSTGRES_USER=hermez -e POSTGRES_PASSWORD="${{ secrets.POSTGRES_PASS }}" -d postgres && sleep 2s && docker exec hermez-db-test psql -a history -U hermez -c "CREATE DATABASE l2;"
|
run: docker run --rm --name hermez-db-test -p 5432:5432 -e POSTGRES_DB=hermez -e POSTGRES_USER=hermez -e POSTGRES_PASSWORD="${{ secrets.POSTGRES_PASS }}" -d postgres
|
||||||
- name: Test
|
- name: Test
|
||||||
env:
|
env:
|
||||||
POSTGRES_PASS: ${{ secrets.POSTGRES_PASS }}
|
POSTGRES_PASS: ${{ secrets.POSTGRES_PASS }}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Go implementation of the Hermez node.
|
|||||||
- First run a docker instance of the PostgresSQL (where `yourpasswordhere` should be your password)
|
- First run a docker instance of the PostgresSQL (where `yourpasswordhere` should be your password)
|
||||||
|
|
||||||
```
|
```
|
||||||
POSTGRES_PASS=yourpasswordhere; sudo docker run --rm --name hermez-db-test -p 5432:5432 -e POSTGRES_DB=history -e POSTGRES_USER=hermez -e POSTGRES_PASSWORD="$POSTGRES_PASS" -d postgres && sleep 2s && sudo docker exec hermez-db-test psql -a history -U hermez -c "CREATE DATABASE l2;"
|
POSTGRES_PASS=yourpasswordhere; sudo docker run --rm --name hermez-db-test -p 5432:5432 -e POSTGRES_DB=hermez -e POSTGRES_USER=hermez -e POSTGRES_PASSWORD="$POSTGRES_PASS" -d postgres
|
||||||
```
|
```
|
||||||
|
|
||||||
- Then, run the tests with the password as env var
|
- Then, run the tests with the password as env var
|
||||||
|
|||||||
12
api/api.go
12
api/api.go
@@ -2,7 +2,6 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||||
@@ -11,8 +10,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var h *historydb.HistoryDB
|
var h *historydb.HistoryDB
|
||||||
var s *statedb.StateDB // Not 100% sure if this is needed
|
|
||||||
var l2 *l2db.L2DB
|
// var s *statedb.StateDB // Not 100% sure if this is needed
|
||||||
|
// var l2 *l2db.L2DB
|
||||||
|
|
||||||
// SetAPIEndpoints sets the endpoints and the appropriate handlers, but doesn't start the server
|
// SetAPIEndpoints sets the endpoints and the appropriate handlers, but doesn't start the server
|
||||||
func SetAPIEndpoints(
|
func SetAPIEndpoints(
|
||||||
@@ -32,11 +32,9 @@ func SetAPIEndpoints(
|
|||||||
}
|
}
|
||||||
|
|
||||||
h = hdb
|
h = hdb
|
||||||
s = sdb
|
// s = sdb
|
||||||
l2 = l2db
|
// l2 = l2db
|
||||||
|
|
||||||
// tmp
|
|
||||||
fmt.Println(h, s, l2)
|
|
||||||
// Add coordinator endpoints
|
// Add coordinator endpoints
|
||||||
if coordinatorEndpoints {
|
if coordinatorEndpoints {
|
||||||
// Account
|
// Account
|
||||||
|
|||||||
152
api/api_test.go
152
api/api_test.go
@@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -19,13 +20,14 @@ import (
|
|||||||
swagger "github.com/getkin/kin-openapi/openapi3filter"
|
swagger "github.com/getkin/kin-openapi/openapi3filter"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/hermeznetwork/hermez-node/common"
|
"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/db/historydb"
|
||||||
"github.com/hermeznetwork/hermez-node/db/l2db"
|
"github.com/hermeznetwork/hermez-node/db/l2db"
|
||||||
"github.com/hermeznetwork/hermez-node/db/statedb"
|
"github.com/hermeznetwork/hermez-node/db/statedb"
|
||||||
"github.com/hermeznetwork/hermez-node/log"
|
"github.com/hermeznetwork/hermez-node/log"
|
||||||
"github.com/hermeznetwork/hermez-node/test"
|
"github.com/hermeznetwork/hermez-node/test"
|
||||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||||
"github.com/jinzhu/copier"
|
"github.com/mitchellh/copystructure"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -77,16 +79,18 @@ func TestMain(m *testing.M) {
|
|||||||
// Init swagger
|
// Init swagger
|
||||||
router := swagger.NewRouter().WithSwaggerFromFile("./swagger.yml")
|
router := swagger.NewRouter().WithSwaggerFromFile("./swagger.yml")
|
||||||
// Init DBs
|
// Init DBs
|
||||||
|
// HistoryDB
|
||||||
pass := os.Getenv("POSTGRES_PASS")
|
pass := os.Getenv("POSTGRES_PASS")
|
||||||
hdb, err := historydb.NewHistoryDB(5432, "localhost", "hermez", pass, "history")
|
db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
// Reset DB
|
hdb := historydb.NewHistoryDB(db)
|
||||||
err = hdb.Reorg(-1)
|
err = hdb.Reorg(-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
// StateDB
|
||||||
dir, err := ioutil.TempDir("", "tmpdb")
|
dir, err := ioutil.TempDir("", "tmpdb")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -95,11 +99,10 @@ func TestMain(m *testing.M) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
l2db, err := l2db.NewL2DB(5432, "localhost", "hermez", pass, "l2", 10, 512, 24*time.Hour)
|
// L2DB
|
||||||
if err != nil {
|
l2DB := l2db.NewL2DB(db, 10, 100, 24*time.Hour)
|
||||||
panic(err)
|
test.CleanL2DB(l2DB.DB())
|
||||||
}
|
|
||||||
test.CleanL2DB(l2db.DB())
|
|
||||||
// Init API
|
// Init API
|
||||||
api := gin.Default()
|
api := gin.Default()
|
||||||
if err := SetAPIEndpoints(
|
if err := SetAPIEndpoints(
|
||||||
@@ -108,7 +111,7 @@ func TestMain(m *testing.M) {
|
|||||||
api,
|
api,
|
||||||
hdb,
|
hdb,
|
||||||
sdb,
|
sdb,
|
||||||
l2db,
|
l2DB,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -120,6 +123,7 @@ func TestMain(m *testing.M) {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Populate DBs
|
// Populate DBs
|
||||||
// Clean DB
|
// Clean DB
|
||||||
err = h.Reorg(0)
|
err = h.Reorg(0)
|
||||||
@@ -203,40 +207,67 @@ func TestMain(m *testing.M) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// find token
|
// find token
|
||||||
token := common.Token{}
|
var token common.Token
|
||||||
for i := 0; i < len(tokens); i++ {
|
if genericTx.IsL1 {
|
||||||
if tokens[i].TokenID == genericTx.TokenID {
|
tokenID := genericTx.TokenID
|
||||||
token = tokens[i]
|
found := false
|
||||||
break
|
for i := 0; i < len(tokens); i++ {
|
||||||
|
if tokens[i].TokenID == tokenID {
|
||||||
|
token = tokens[i]
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
panic("Token not found")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
token = test.GetToken(genericTx.FromIdx, accs, tokens)
|
||||||
|
}
|
||||||
|
var usd, loadUSD, feeUSD *float64
|
||||||
|
if token.USD != nil {
|
||||||
|
noDecimalsUSD := *token.USD / math.Pow(10, float64(token.Decimals))
|
||||||
|
usd = new(float64)
|
||||||
|
*usd = noDecimalsUSD * genericTx.AmountFloat
|
||||||
|
if genericTx.IsL1 {
|
||||||
|
loadUSD = new(float64)
|
||||||
|
*loadUSD = noDecimalsUSD * *genericTx.LoadAmountFloat
|
||||||
|
} else {
|
||||||
|
feeUSD = new(float64)
|
||||||
|
*feeUSD = *usd * genericTx.Fee.Percentage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
historyTxs = append(historyTxs, &historydb.HistoryTx{
|
historyTxs = append(historyTxs, &historydb.HistoryTx{
|
||||||
IsL1: genericTx.IsL1,
|
IsL1: genericTx.IsL1,
|
||||||
TxID: genericTx.TxID,
|
TxID: genericTx.TxID,
|
||||||
Type: genericTx.Type,
|
Type: genericTx.Type,
|
||||||
Position: genericTx.Position,
|
Position: genericTx.Position,
|
||||||
FromIdx: genericTx.FromIdx,
|
FromIdx: genericTx.FromIdx,
|
||||||
ToIdx: genericTx.ToIdx,
|
ToIdx: genericTx.ToIdx,
|
||||||
Amount: genericTx.Amount,
|
Amount: genericTx.Amount,
|
||||||
AmountFloat: genericTx.AmountFloat,
|
AmountFloat: genericTx.AmountFloat,
|
||||||
TokenID: genericTx.TokenID,
|
HistoricUSD: usd,
|
||||||
USD: token.USD * genericTx.AmountFloat,
|
BatchNum: genericTx.BatchNum,
|
||||||
BatchNum: genericTx.BatchNum,
|
EthBlockNum: genericTx.EthBlockNum,
|
||||||
EthBlockNum: genericTx.EthBlockNum,
|
ToForgeL1TxsNum: genericTx.ToForgeL1TxsNum,
|
||||||
ToForgeL1TxsNum: genericTx.ToForgeL1TxsNum,
|
UserOrigin: genericTx.UserOrigin,
|
||||||
UserOrigin: genericTx.UserOrigin,
|
FromEthAddr: genericTx.FromEthAddr,
|
||||||
FromEthAddr: genericTx.FromEthAddr,
|
FromBJJ: genericTx.FromBJJ,
|
||||||
FromBJJ: genericTx.FromBJJ,
|
LoadAmount: genericTx.LoadAmount,
|
||||||
LoadAmount: genericTx.LoadAmount,
|
LoadAmountFloat: genericTx.LoadAmountFloat,
|
||||||
LoadAmountFloat: genericTx.LoadAmountFloat,
|
HistoricLoadAmountUSD: loadUSD,
|
||||||
LoadAmountUSD: token.USD * genericTx.LoadAmountFloat,
|
Fee: genericTx.Fee,
|
||||||
Fee: genericTx.Fee,
|
HistoricFeeUSD: feeUSD,
|
||||||
FeeUSD: genericTx.Fee.Percentage() * token.USD * genericTx.AmountFloat,
|
Nonce: genericTx.Nonce,
|
||||||
Nonce: genericTx.Nonce,
|
Timestamp: timestamp,
|
||||||
Timestamp: timestamp,
|
TokenID: token.TokenID,
|
||||||
TokenSymbol: token.Symbol,
|
TokenEthBlockNum: token.EthBlockNum,
|
||||||
CurrentUSD: token.USD * genericTx.AmountFloat,
|
TokenEthAddr: token.EthAddr,
|
||||||
USDUpdate: token.USDUpdate,
|
TokenName: token.Name,
|
||||||
|
TokenSymbol: token.Symbol,
|
||||||
|
TokenDecimals: token.Decimals,
|
||||||
|
TokenUSD: token.USD,
|
||||||
|
TokenUSDUpdate: token.USDUpdate,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return historyTxAPIs(historyTxsToAPI(historyTxs))
|
return historyTxAPIs(historyTxsToAPI(historyTxs))
|
||||||
@@ -265,10 +296,7 @@ func TestMain(m *testing.M) {
|
|||||||
if err := server.Shutdown(context.Background()); err != nil {
|
if err := server.Shutdown(context.Background()); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if err := h.Close(); err != nil {
|
if err := db.Close(); err != nil {
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if err := l2.Close(); err != nil {
|
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
os.Exit(result)
|
os.Exit(result)
|
||||||
@@ -279,11 +307,11 @@ func TestGetHistoryTxs(t *testing.T) {
|
|||||||
fetchedTxs := historyTxAPIs{}
|
fetchedTxs := historyTxAPIs{}
|
||||||
appendIter := func(intr interface{}) {
|
appendIter := func(intr interface{}) {
|
||||||
for i := 0; i < len(intr.(*historyTxsAPI).Txs); i++ {
|
for i := 0; i < len(intr.(*historyTxsAPI).Txs); i++ {
|
||||||
tmp := &historyTxAPI{}
|
tmp, err := copystructure.Copy(intr.(*historyTxsAPI).Txs[i])
|
||||||
if err := copier.Copy(tmp, &intr.(*historyTxsAPI).Txs[i]); err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
fetchedTxs = append(fetchedTxs, *tmp)
|
fetchedTxs = append(fetchedTxs, tmp.(historyTxAPI))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Get all (no filters)
|
// Get all (no filters)
|
||||||
@@ -315,7 +343,7 @@ func TestGetHistoryTxs(t *testing.T) {
|
|||||||
// Get by tokenID
|
// Get by tokenID
|
||||||
fetchedTxs = historyTxAPIs{}
|
fetchedTxs = historyTxAPIs{}
|
||||||
limit = 5
|
limit = 5
|
||||||
tokenID := tc.allTxs[0].TokenID
|
tokenID := tc.allTxs[0].Token.TokenID
|
||||||
path = fmt.Sprintf(
|
path = fmt.Sprintf(
|
||||||
"%s?tokenId=%d&limit=%d&offset=",
|
"%s?tokenId=%d&limit=%d&offset=",
|
||||||
endpoint, tokenID, limit,
|
endpoint, tokenID, limit,
|
||||||
@@ -324,7 +352,7 @@ func TestGetHistoryTxs(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
tokenIDTxs := historyTxAPIs{}
|
tokenIDTxs := historyTxAPIs{}
|
||||||
for i := 0; i < len(tc.allTxs); i++ {
|
for i := 0; i < len(tc.allTxs); i++ {
|
||||||
if tc.allTxs[i].TokenID == tokenID {
|
if tc.allTxs[i].Token.TokenID == tokenID {
|
||||||
tokenIDTxs = append(tokenIDTxs, tc.allTxs[i])
|
tokenIDTxs = append(tokenIDTxs, tc.allTxs[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -407,7 +435,7 @@ func TestGetHistoryTxs(t *testing.T) {
|
|||||||
mixedTxs := historyTxAPIs{}
|
mixedTxs := historyTxAPIs{}
|
||||||
for i := 0; i < len(tc.allTxs); i++ {
|
for i := 0; i < len(tc.allTxs); i++ {
|
||||||
if tc.allTxs[i].BatchNum != nil {
|
if tc.allTxs[i].BatchNum != nil {
|
||||||
if *tc.allTxs[i].BatchNum == *batchNum && tc.allTxs[i].TokenID == tokenID {
|
if *tc.allTxs[i].BatchNum == *batchNum && tc.allTxs[i].Token.TokenID == tokenID {
|
||||||
mixedTxs = append(mixedTxs, tc.allTxs[i])
|
mixedTxs = append(mixedTxs, tc.allTxs[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -420,11 +448,11 @@ func TestGetHistoryTxs(t *testing.T) {
|
|||||||
appendIterRev := func(intr interface{}) {
|
appendIterRev := func(intr interface{}) {
|
||||||
tmpAll := historyTxAPIs{}
|
tmpAll := historyTxAPIs{}
|
||||||
for i := 0; i < len(intr.(*historyTxsAPI).Txs); i++ {
|
for i := 0; i < len(intr.(*historyTxsAPI).Txs); i++ {
|
||||||
tmpItem := &historyTxAPI{}
|
tmp, err := copystructure.Copy(intr.(*historyTxsAPI).Txs[i])
|
||||||
if err := copier.Copy(tmpItem, &intr.(*historyTxsAPI).Txs[i]); err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
tmpAll = append(tmpAll, *tmpItem)
|
tmpAll = append(tmpAll, tmp.(historyTxAPI))
|
||||||
}
|
}
|
||||||
fetchedTxs = append(tmpAll, fetchedTxs...)
|
fetchedTxs = append(tmpAll, fetchedTxs...)
|
||||||
}
|
}
|
||||||
@@ -455,15 +483,17 @@ func assertHistoryTxAPIs(t *testing.T, expected, actual historyTxAPIs) {
|
|||||||
for i := 0; i < len(actual); i++ { //nolint len(actual) won't change within the loop
|
for i := 0; i < len(actual); i++ { //nolint len(actual) won't change within the loop
|
||||||
assert.Equal(t, expected[i].Timestamp.Unix(), actual[i].Timestamp.Unix())
|
assert.Equal(t, expected[i].Timestamp.Unix(), actual[i].Timestamp.Unix())
|
||||||
expected[i].Timestamp = actual[i].Timestamp
|
expected[i].Timestamp = actual[i].Timestamp
|
||||||
assert.Equal(t, expected[i].USDUpdate.Unix(), actual[i].USDUpdate.Unix())
|
if expected[i].Token.USDUpdate == nil {
|
||||||
expected[i].USDUpdate = actual[i].USDUpdate
|
assert.Equal(t, expected[i].Token.USDUpdate, actual[i].Token.USDUpdate)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, expected[i].Token.USDUpdate.Unix(), actual[i].Token.USDUpdate.Unix())
|
||||||
|
expected[i].Token.USDUpdate = actual[i].Token.USDUpdate
|
||||||
|
}
|
||||||
|
test.AssertUSD(t, expected[i].HistoricUSD, actual[i].HistoricUSD)
|
||||||
if expected[i].L2Info != nil {
|
if expected[i].L2Info != nil {
|
||||||
if expected[i].L2Info.FeeUSD > actual[i].L2Info.FeeUSD {
|
test.AssertUSD(t, expected[i].L2Info.HistoricFeeUSD, actual[i].L2Info.HistoricFeeUSD)
|
||||||
assert.Less(t, 0.999, actual[i].L2Info.FeeUSD/expected[i].L2Info.FeeUSD)
|
} else {
|
||||||
} else if expected[i].L2Info.FeeUSD < actual[i].L2Info.FeeUSD {
|
test.AssertUSD(t, expected[i].L1Info.HistoricLoadAmountUSD, actual[i].L1Info.HistoricLoadAmountUSD)
|
||||||
assert.Less(t, 0.999, expected[i].L2Info.FeeUSD/actual[i].L2Info.FeeUSD)
|
|
||||||
}
|
|
||||||
expected[i].L2Info.FeeUSD = actual[i].L2Info.FeeUSD
|
|
||||||
}
|
}
|
||||||
assert.Equal(t, expected[i], actual[i])
|
assert.Equal(t, expected[i], actual[i])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/hermeznetwork/hermez-node/common"
|
"github.com/hermeznetwork/hermez-node/common"
|
||||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||||
@@ -37,19 +38,19 @@ func (htx *historyTxsAPI) GetPagination() pagination { return htx.Pagination }
|
|||||||
func (htx *historyTxsAPI) Len() int { return len(htx.Txs) }
|
func (htx *historyTxsAPI) Len() int { return len(htx.Txs) }
|
||||||
|
|
||||||
type l1Info struct {
|
type l1Info struct {
|
||||||
ToForgeL1TxsNum int64 `json:"toForgeL1TransactionsNum"`
|
ToForgeL1TxsNum int64 `json:"toForgeL1TransactionsNum"`
|
||||||
UserOrigin bool `json:"userOrigin"`
|
UserOrigin bool `json:"userOrigin"`
|
||||||
FromEthAddr string `json:"fromEthereumAddress"`
|
FromEthAddr string `json:"fromHezEthereumAddress"`
|
||||||
FromBJJ string `json:"fromBJJ"`
|
FromBJJ string `json:"fromBJJ"`
|
||||||
LoadAmount string `json:"loadAmount"`
|
LoadAmount string `json:"loadAmount"`
|
||||||
LoadAmountUSD float64 `json:"loadAmountUSD"`
|
HistoricLoadAmountUSD *float64 `json:"historicLoadAmountUSD"`
|
||||||
EthBlockNum int64 `json:"ethereumBlockNum"`
|
EthBlockNum int64 `json:"ethereumBlockNum"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type l2Info struct {
|
type l2Info struct {
|
||||||
Fee common.FeeSelector `json:"fee"`
|
Fee common.FeeSelector `json:"fee"`
|
||||||
FeeUSD float64 `json:"feeUSD"`
|
HistoricFeeUSD *float64 `json:"historicFeeUSD"`
|
||||||
Nonce common.Nonce `json:"nonce"`
|
Nonce common.Nonce `json:"nonce"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type historyTxAPI struct {
|
type historyTxAPI struct {
|
||||||
@@ -61,14 +62,11 @@ type historyTxAPI struct {
|
|||||||
ToIdx string `json:"toAccountIndex"`
|
ToIdx string `json:"toAccountIndex"`
|
||||||
Amount string `json:"amount"`
|
Amount string `json:"amount"`
|
||||||
BatchNum *common.BatchNum `json:"batchNum"`
|
BatchNum *common.BatchNum `json:"batchNum"`
|
||||||
TokenID common.TokenID `json:"tokenId"`
|
HistoricUSD *float64 `json:"historicUSD"`
|
||||||
TokenSymbol string `json:"tokenSymbol"`
|
|
||||||
USD float64 `json:"historicUSD"`
|
|
||||||
Timestamp time.Time `json:"timestamp"`
|
Timestamp time.Time `json:"timestamp"`
|
||||||
CurrentUSD float64 `json:"currentUSD"`
|
|
||||||
USDUpdate time.Time `json:"fiatUpdate"`
|
|
||||||
L1Info *l1Info `json:"L1Info"`
|
L1Info *l1Info `json:"L1Info"`
|
||||||
L2Info *l2Info `json:"L2Info"`
|
L2Info *l2Info `json:"L2Info"`
|
||||||
|
Token common.Token `json:"token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func historyTxsToAPI(dbTxs []*historydb.HistoryTx) []historyTxAPI {
|
func historyTxsToAPI(dbTxs []*historydb.HistoryTx) []historyTxAPI {
|
||||||
@@ -78,40 +76,42 @@ func historyTxsToAPI(dbTxs []*historydb.HistoryTx) []historyTxAPI {
|
|||||||
TxID: dbTxs[i].TxID,
|
TxID: dbTxs[i].TxID,
|
||||||
Type: dbTxs[i].Type,
|
Type: dbTxs[i].Type,
|
||||||
Position: dbTxs[i].Position,
|
Position: dbTxs[i].Position,
|
||||||
FromIdx: "hez:" + dbTxs[i].TokenSymbol + ":" + strconv.Itoa(int(dbTxs[i].FromIdx)),
|
FromIdx: idxToHez(dbTxs[i].FromIdx, dbTxs[i].TokenSymbol),
|
||||||
ToIdx: "hez:" + dbTxs[i].TokenSymbol + ":" + strconv.Itoa(int(dbTxs[i].ToIdx)),
|
ToIdx: idxToHez(dbTxs[i].ToIdx, dbTxs[i].TokenSymbol),
|
||||||
Amount: dbTxs[i].Amount.String(),
|
Amount: dbTxs[i].Amount.String(),
|
||||||
TokenID: dbTxs[i].TokenID,
|
HistoricUSD: dbTxs[i].HistoricUSD,
|
||||||
USD: dbTxs[i].USD,
|
BatchNum: dbTxs[i].BatchNum,
|
||||||
BatchNum: nil,
|
|
||||||
Timestamp: dbTxs[i].Timestamp,
|
Timestamp: dbTxs[i].Timestamp,
|
||||||
TokenSymbol: dbTxs[i].TokenSymbol,
|
Token: common.Token{
|
||||||
CurrentUSD: dbTxs[i].CurrentUSD,
|
TokenID: dbTxs[i].TokenID,
|
||||||
USDUpdate: dbTxs[i].USDUpdate,
|
EthBlockNum: dbTxs[i].TokenEthBlockNum,
|
||||||
L1Info: nil,
|
EthAddr: dbTxs[i].TokenEthAddr,
|
||||||
L2Info: nil,
|
Name: dbTxs[i].TokenName,
|
||||||
}
|
Symbol: dbTxs[i].TokenSymbol,
|
||||||
bn := dbTxs[i].BatchNum
|
Decimals: dbTxs[i].TokenDecimals,
|
||||||
if dbTxs[i].BatchNum != 0 {
|
USD: dbTxs[i].TokenUSD,
|
||||||
apiTx.BatchNum = &bn
|
USDUpdate: dbTxs[i].TokenUSDUpdate,
|
||||||
|
},
|
||||||
|
L1Info: nil,
|
||||||
|
L2Info: nil,
|
||||||
}
|
}
|
||||||
if dbTxs[i].IsL1 {
|
if dbTxs[i].IsL1 {
|
||||||
apiTx.IsL1 = "L1"
|
apiTx.IsL1 = "L1"
|
||||||
apiTx.L1Info = &l1Info{
|
apiTx.L1Info = &l1Info{
|
||||||
ToForgeL1TxsNum: dbTxs[i].ToForgeL1TxsNum,
|
ToForgeL1TxsNum: dbTxs[i].ToForgeL1TxsNum,
|
||||||
UserOrigin: dbTxs[i].UserOrigin,
|
UserOrigin: dbTxs[i].UserOrigin,
|
||||||
FromEthAddr: "hez:" + dbTxs[i].FromEthAddr.String(),
|
FromEthAddr: ethAddrToHez(dbTxs[i].FromEthAddr),
|
||||||
FromBJJ: bjjToString(dbTxs[i].FromBJJ),
|
FromBJJ: bjjToString(dbTxs[i].FromBJJ),
|
||||||
LoadAmount: dbTxs[i].LoadAmount.String(),
|
LoadAmount: dbTxs[i].LoadAmount.String(),
|
||||||
LoadAmountUSD: dbTxs[i].LoadAmountUSD,
|
HistoricLoadAmountUSD: dbTxs[i].HistoricLoadAmountUSD,
|
||||||
EthBlockNum: dbTxs[i].EthBlockNum,
|
EthBlockNum: dbTxs[i].EthBlockNum,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
apiTx.IsL1 = "L2"
|
apiTx.IsL1 = "L2"
|
||||||
apiTx.L2Info = &l2Info{
|
apiTx.L2Info = &l2Info{
|
||||||
Fee: dbTxs[i].Fee,
|
Fee: *dbTxs[i].Fee,
|
||||||
FeeUSD: dbTxs[i].FeeUSD,
|
HistoricFeeUSD: dbTxs[i].HistoricFeeUSD,
|
||||||
Nonce: dbTxs[i].Nonce,
|
Nonce: *dbTxs[i].Nonce,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
apiTxs = append(apiTxs, apiTx)
|
apiTxs = append(apiTxs, apiTx)
|
||||||
@@ -128,3 +128,11 @@ func bjjToString(bjj *babyjub.PublicKey) string {
|
|||||||
bjjSum := append(pkComp[:], sum)
|
bjjSum := append(pkComp[:], sum)
|
||||||
return "hez:" + base64.RawURLEncoding.EncodeToString(bjjSum)
|
return "hez:" + base64.RawURLEncoding.EncodeToString(bjjSum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ethAddrToHez(addr ethCommon.Address) string {
|
||||||
|
return "hez:" + addr.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func idxToHez(idx common.Idx, tokenSymbol string) string {
|
||||||
|
return "hez:" + tokenSymbol + ":" + strconv.Itoa(int(idx))
|
||||||
|
}
|
||||||
|
|||||||
296
api/swagger.yml
296
api/swagger.yml
@@ -96,7 +96,7 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/Error500'
|
$ref: '#/components/schemas/Error500'
|
||||||
'/account-creation-authorization/{hermezEthereumAddress}':
|
'/account-creation-authorization/{hezEthereumAddress}':
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- Account
|
- Account
|
||||||
@@ -105,12 +105,12 @@ paths:
|
|||||||
True if the coordinator has the required authorization to perform an account creation with the given Ethereum address on behalf of the Ethereum address holder.
|
True if the coordinator has the required authorization to perform an account creation with the given Ethereum address on behalf of the Ethereum address holder.
|
||||||
operationId: getAccountCreationAuthorization
|
operationId: getAccountCreationAuthorization
|
||||||
parameters:
|
parameters:
|
||||||
- name: hermezEthereumAddress
|
- name: hezEthereumAddress
|
||||||
in: path
|
in: path
|
||||||
description: Ethereum address.
|
description: Ethereum address.
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/HermezEthereumAddress'
|
$ref: '#/components/schemas/HezEthereumAddress'
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Successful operation.
|
description: Successful operation.
|
||||||
@@ -144,15 +144,15 @@ paths:
|
|||||||
description: Get accounts balances and other associated information.
|
description: Get accounts balances and other associated information.
|
||||||
operationId: getAccounts
|
operationId: getAccounts
|
||||||
parameters:
|
parameters:
|
||||||
- name: hermezEthereumAddress
|
- name: hezEthereumAddress
|
||||||
in: query
|
in: query
|
||||||
description: Only get accounts associated to an Ethereum address. Incompatible with the query `BJJ`.
|
description: Only get accounts associated to an Ethereum address. Incompatible with the query `BJJ`.
|
||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/HermezEthereumAddress'
|
$ref: '#/components/schemas/HezEthereumAddress'
|
||||||
- name: BJJ
|
- name: BJJ
|
||||||
in: query
|
in: query
|
||||||
description: Only get accounts associated to a BabyJubJub public key. Incompatible with the query `hermezEthereumAddress`.
|
description: Only get accounts associated to a BabyJubJub public key. Incompatible with the query `hezEthereumAddress`.
|
||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/BJJ'
|
$ref: '#/components/schemas/BJJ'
|
||||||
@@ -258,21 +258,21 @@ paths:
|
|||||||
description: Get exit information. This information is required to perform a withdraw.
|
description: Get exit information. This information is required to perform a withdraw.
|
||||||
operationId: getExits
|
operationId: getExits
|
||||||
parameters:
|
parameters:
|
||||||
- name: hermezEthereumAddress
|
- name: hezEthereumAddress
|
||||||
in: query
|
in: query
|
||||||
description: Get exits associated to a Ethereum address. Incompatible with query `BJJ` and `accountIndex`.
|
description: Get exits associated to a Ethereum address. Incompatible with query `BJJ` and `accountIndex`.
|
||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/HermezEthereumAddress'
|
$ref: '#/components/schemas/HezEthereumAddress'
|
||||||
- name: BJJ
|
- name: BJJ
|
||||||
in: query
|
in: query
|
||||||
description: Get exits associated to a BabyJubJub public key. Incompatible with query `hermezEthereumAddress` and `accountIndex`.
|
description: Get exits associated to a BabyJubJub public key. Incompatible with query `hezEthereumAddress` and `accountIndex`.
|
||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/BJJ'
|
$ref: '#/components/schemas/BJJ'
|
||||||
- name: accountIndex
|
- name: accountIndex
|
||||||
in: query
|
in: query
|
||||||
description: Get exits associated to a specific account. Incompatible with queries `hermezEthereumAddress` and `BJJ`.
|
description: Get exits associated to a specific account. Incompatible with queries `hezEthereumAddress` and `BJJ`.
|
||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/AccountIndex'
|
$ref: '#/components/schemas/AccountIndex'
|
||||||
@@ -388,7 +388,7 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/PoolL2Transaction'
|
$ref: '#/components/schemas/PostPoolL2Transaction'
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Successful operation.
|
description: Successful operation.
|
||||||
@@ -468,22 +468,22 @@ paths:
|
|||||||
description: Only get transactions of specific token
|
description: Only get transactions of specific token
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/TokenId'
|
$ref: '#/components/schemas/TokenId'
|
||||||
- name: hermezEthereumAddress
|
- name: hezEthereumAddress
|
||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
description: Only get transactions sent from or to an account associated to an Ethereum address Incompatible with the queries `BJJ` and `accountIndex`.
|
description: Only get transactions sent from or to an account associated to an Ethereum address Incompatible with the queries `BJJ` and `accountIndex`.
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/HermezEthereumAddress'
|
$ref: '#/components/schemas/HezEthereumAddress'
|
||||||
- name: BJJ
|
- name: BJJ
|
||||||
in: query
|
in: query
|
||||||
description: Only get transactions associated to a BabyJubJub public key. Incompatible with the queries `hermezEthereumAddress` and `accountIndex`.
|
description: Only get transactions associated to a BabyJubJub public key. Incompatible with the queries `hezEthereumAddress` and `accountIndex`.
|
||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/BJJ'
|
$ref: '#/components/schemas/BJJ'
|
||||||
- name: accountIndex
|
- name: accountIndex
|
||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
description: Only get transactions sent from or to a specific account. Incompatible with the queries `tokenId`, `hermezEthereumAddress` and `BJJ`.
|
description: Only get transactions sent from or to a specific account. Incompatible with the queries `tokenId`, `hezEthereumAddress` and `BJJ`.
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/AccountIndex'
|
$ref: '#/components/schemas/AccountIndex'
|
||||||
- name: batchNum
|
- name: batchNum
|
||||||
@@ -1228,6 +1228,101 @@ paths:
|
|||||||
$ref: '#/components/schemas/Error500'
|
$ref: '#/components/schemas/Error500'
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
|
PostPoolL2Transaction:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
$ref: '#/components/schemas/TransactionId'
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/TransactionType'
|
||||||
|
tokenId:
|
||||||
|
$ref: '#/components/schemas/TokenId'
|
||||||
|
fromAccountIndex:
|
||||||
|
$ref: '#/components/schemas/AccountIndex'
|
||||||
|
toAccountIndex:
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/components/schemas/AccountIndex'
|
||||||
|
- example: "hez:DAI:672"
|
||||||
|
toHezEthereumAddress:
|
||||||
|
$ref: '#/components/schemas/HezEthereumAddress'
|
||||||
|
toBjj:
|
||||||
|
$ref: '#/components/schemas/BJJ'
|
||||||
|
amount:
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/components/schemas/BigInt'
|
||||||
|
- description: Amount of tokens to be sent.
|
||||||
|
example: "63"
|
||||||
|
fee:
|
||||||
|
$ref: '#/components/schemas/FeeSelector'
|
||||||
|
nonce:
|
||||||
|
$ref: '#/components/schemas/Nonce'
|
||||||
|
signature:
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/components/schemas/Signature'
|
||||||
|
- description: Signature of the transaction. More info [here](https://idocs.hermez.io/#/spec/zkrollup/README?id=l2a-idl2).
|
||||||
|
- example: "72024a43f546b0e1d9d5d7c4c30c259102a9726363adcc4ec7b6aea686bcb5116f485c5542d27c4092ae0ceaf38e3bb44417639bd2070a58ba1aa1aab9d92c03"
|
||||||
|
requestFromAccountIndex:
|
||||||
|
type: string
|
||||||
|
description: References the `fromAccountIndex` of the requested transaction.
|
||||||
|
example: null
|
||||||
|
nullable: true
|
||||||
|
requestToAccountIndex:
|
||||||
|
type: string
|
||||||
|
description: References the `toAccountIndex` of the requested transaction.
|
||||||
|
example: null
|
||||||
|
nullable: true
|
||||||
|
requestToHezEthereumAddress:
|
||||||
|
type: string
|
||||||
|
description: References the `toHezEthereumAddress` of the requested transaction.
|
||||||
|
pattern: "^hez:0x[a-fA-F0-9]{40}$"
|
||||||
|
example: null
|
||||||
|
nullable: true
|
||||||
|
requestToBJJ:
|
||||||
|
type: string
|
||||||
|
description: References the `toBJJ` of the requested transaction.
|
||||||
|
pattern: "^hez:[A-Za-z0-9_-]{44}$"
|
||||||
|
example: null
|
||||||
|
nullable: true
|
||||||
|
requestTokenId:
|
||||||
|
type: integer
|
||||||
|
description: References the `tokenId` of the requested transaction.
|
||||||
|
example: null
|
||||||
|
nullable: true
|
||||||
|
requestAmount:
|
||||||
|
type: string
|
||||||
|
description: References the `amount` of the requested transaction.
|
||||||
|
example: null
|
||||||
|
nullable: true
|
||||||
|
requestFee:
|
||||||
|
type: integer
|
||||||
|
description: References the `fee` of the requested transaction.
|
||||||
|
example: null
|
||||||
|
nullable: true
|
||||||
|
requestNonce:
|
||||||
|
type: integer
|
||||||
|
description: References the `nonce` of the requested transaction.
|
||||||
|
example: null
|
||||||
|
nullable: true
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- type
|
||||||
|
- tokenId
|
||||||
|
- fromAccountIndex
|
||||||
|
- toHezAccountIndex
|
||||||
|
- toHezEthereumAddress
|
||||||
|
- toBjj
|
||||||
|
- amount
|
||||||
|
- fee
|
||||||
|
- nonce
|
||||||
|
- signature
|
||||||
|
- requestFromAccountIndex
|
||||||
|
- requestToAccountIndex
|
||||||
|
- requestToHezEthereumAddress
|
||||||
|
- requestToBJJ
|
||||||
|
- requestTokenId
|
||||||
|
- requestAmount
|
||||||
|
- requestFee
|
||||||
|
- requestNonce
|
||||||
PoolL2Transaction:
|
PoolL2Transaction:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@@ -1241,20 +1336,10 @@ components:
|
|||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/AccountIndex'
|
- $ref: '#/components/schemas/AccountIndex'
|
||||||
- example: "hez:DAI:672"
|
- example: "hez:DAI:672"
|
||||||
toEthereumAddress:
|
toHezEthereumAddress:
|
||||||
$ref: '#/components/schemas/HermezEthereumAddress'
|
$ref: '#/components/schemas/HezEthereumAddress'
|
||||||
toBjj:
|
toBjj:
|
||||||
$ref: '#/components/schemas/BJJ'
|
$ref: '#/components/schemas/BJJ'
|
||||||
tokenId:
|
|
||||||
$ref: '#/components/schemas/TokenId'
|
|
||||||
USD:
|
|
||||||
type: number
|
|
||||||
description: Value of the token in USD.
|
|
||||||
example: 4.53
|
|
||||||
fiatUpdate:
|
|
||||||
type: string
|
|
||||||
format: date-time
|
|
||||||
description: Timestamp of the moment the `USD` value was updated.
|
|
||||||
amount:
|
amount:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/BigInt'
|
- $ref: '#/components/schemas/BigInt'
|
||||||
@@ -1262,10 +1347,6 @@ components:
|
|||||||
example: "63"
|
example: "63"
|
||||||
fee:
|
fee:
|
||||||
$ref: '#/components/schemas/FeeSelector'
|
$ref: '#/components/schemas/FeeSelector'
|
||||||
feeUSD:
|
|
||||||
type: number
|
|
||||||
description: Fee in USD.
|
|
||||||
example: 0.75
|
|
||||||
nonce:
|
nonce:
|
||||||
$ref: '#/components/schemas/Nonce'
|
$ref: '#/components/schemas/Nonce'
|
||||||
state:
|
state:
|
||||||
@@ -1294,9 +1375,9 @@ components:
|
|||||||
- $ref: '#/components/schemas/AccountIndex'
|
- $ref: '#/components/schemas/AccountIndex'
|
||||||
- nullable: true
|
- nullable: true
|
||||||
- example: "hez:DAI:33"
|
- example: "hez:DAI:33"
|
||||||
requestToEthereumAddress:
|
requestToHezEthereumAddress:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/HermezEthereumAddress'
|
- $ref: '#/components/schemas/HezEthereumAddress'
|
||||||
- nullable: true
|
- nullable: true
|
||||||
- example: "hez:0xbb942cfcd25ad4d90a62358b0dd84f33b3982699"
|
- example: "hez:0xbb942cfcd25ad4d90a62358b0dd84f33b3982699"
|
||||||
requestToBJJ:
|
requestToBJJ:
|
||||||
@@ -1325,12 +1406,12 @@ components:
|
|||||||
- $ref: '#/components/schemas/Nonce'
|
- $ref: '#/components/schemas/Nonce'
|
||||||
- nullable: true
|
- nullable: true
|
||||||
- example: 6
|
- example: 6
|
||||||
tokenSymbol:
|
token:
|
||||||
$ref: '#/components/schemas/TokenSymbol'
|
$ref: '#/components/schemas/Token'
|
||||||
required:
|
required:
|
||||||
- fromAccountIndex
|
- fromAccountIndex
|
||||||
- toAccountIndex
|
- toHezAccountIndex
|
||||||
- toEthereumAddress
|
- toHezEthereumAddress
|
||||||
- toBjj
|
- toBjj
|
||||||
- tokenId
|
- tokenId
|
||||||
- amount
|
- amount
|
||||||
@@ -1346,14 +1427,14 @@ components:
|
|||||||
description: "Address of an Etherum account."
|
description: "Address of an Etherum account."
|
||||||
pattern: "^0x[a-fA-F0-9]{40}$"
|
pattern: "^0x[a-fA-F0-9]{40}$"
|
||||||
example: "0xaa942cfcd25ad4d90a62358b0dd84f33b398262a"
|
example: "0xaa942cfcd25ad4d90a62358b0dd84f33b398262a"
|
||||||
HermezEthereumAddress:
|
HezEthereumAddress:
|
||||||
type: string
|
type: string
|
||||||
description: "Address of an Etherum account linked to the Hermez network."
|
description: "Address of an Etherum account linked to the Hermez network."
|
||||||
pattern: "^hez:0x[a-fA-F0-9]{40}$"
|
pattern: "^hez:0x[a-fA-F0-9]{40}$"
|
||||||
example: "hez:0xaa942cfcd25ad4d90a62358b0dd84f33b398262a"
|
example: "hez:0xaa942cfcd25ad4d90a62358b0dd84f33b398262a"
|
||||||
BJJ:
|
BJJ:
|
||||||
type: string
|
type: string
|
||||||
description: "BabyJubJub public key, encoded as base64, which result in 33 bytes (last byte used as checksum)."
|
description: "BabyJubJub public key, encoded as base64 URL (RFC 4648), which result in 33 bytes. The padding byte is replaced by a sum of the encoded bytes."
|
||||||
pattern: "^hez:[A-Za-z0-9_-]{44}$"
|
pattern: "^hez:[A-Za-z0-9_-]{44}$"
|
||||||
example: "hez:rR7LXKal-av7I56Y0dEBCVmwc9zpoLY5ERhy5w7G-xwe"
|
example: "hez:rR7LXKal-av7I56Y0dEBCVmwc9zpoLY5ERhy5w7G-xwe"
|
||||||
AccountIndex:
|
AccountIndex:
|
||||||
@@ -1429,8 +1510,8 @@ components:
|
|||||||
timestamp:
|
timestamp:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
ethereumAddress:
|
hezEthereumAddress:
|
||||||
$ref: '#/components/schemas/HermezEthereumAddress'
|
$ref: '#/components/schemas/HezEthereumAddress'
|
||||||
bjj:
|
bjj:
|
||||||
$ref: '#/components/schemas/BJJ'
|
$ref: '#/components/schemas/BJJ'
|
||||||
signature:
|
signature:
|
||||||
@@ -1475,26 +1556,17 @@ components:
|
|||||||
maximum: 4294967295
|
maximum: 4294967295
|
||||||
example: 5432
|
example: 5432
|
||||||
nullable: true
|
nullable: true
|
||||||
tokenId:
|
|
||||||
$ref: '#/components/schemas/TokenId'
|
|
||||||
tokenSymbol:
|
|
||||||
$ref: '#/components/schemas/TokenSymbol'
|
|
||||||
historicUSD:
|
historicUSD:
|
||||||
type: number
|
type: number
|
||||||
description: Value in USD at the moment the transaction was forged.
|
description: Value in USD at the moment the transaction was forged.
|
||||||
example: 49.7
|
example: 49.7
|
||||||
currentUSD:
|
nullable: true
|
||||||
type: number
|
|
||||||
description: Value in USD at the current token/USD conversion.
|
|
||||||
example: 50.01
|
|
||||||
fiatUpdate:
|
|
||||||
type: string
|
|
||||||
format: date-time
|
|
||||||
description: Timestamp of the moment the `currentUSD` value was updated.
|
|
||||||
timestamp:
|
timestamp:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
description: In the case of L1 indicates the moment where the transaction was added in the smart contract. For L2 indicates when the transaction was forged.
|
description: In the case of L1 indicates the moment where the transaction was added in the smart contract. For L2 indicates when the transaction was forged.
|
||||||
|
token:
|
||||||
|
$ref: '#/components/schemas/Token'
|
||||||
L1Info:
|
L1Info:
|
||||||
type: object
|
type: object
|
||||||
description: Additional information that only applies to L1 transactions.
|
description: Additional information that only applies to L1 transactions.
|
||||||
@@ -1505,8 +1577,8 @@ components:
|
|||||||
userOrigin:
|
userOrigin:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: True if the transaction was sent by a user. False if it was sent by a coordinator.
|
description: True if the transaction was sent by a user. False if it was sent by a coordinator.
|
||||||
fromEthereumAddress:
|
fromHezEthereumAddress:
|
||||||
$ref: '#/components/schemas/HermezEthereumAddress'
|
$ref: '#/components/schemas/HezEthereumAddress'
|
||||||
fromBJJ:
|
fromBJJ:
|
||||||
$ref: '#/components/schemas/BJJ'
|
$ref: '#/components/schemas/BJJ'
|
||||||
loadAmount:
|
loadAmount:
|
||||||
@@ -1514,10 +1586,11 @@ components:
|
|||||||
- $ref: '#/components/schemas/BigInt'
|
- $ref: '#/components/schemas/BigInt'
|
||||||
- description: Tokens transfered from L1 to L2.
|
- description: Tokens transfered from L1 to L2.
|
||||||
- example: "49"
|
- example: "49"
|
||||||
loadAmountUSD:
|
historicLoadAmountUSD:
|
||||||
type: number
|
type: number
|
||||||
description: Load amount in USD, at the moment the transaction was made.
|
description: Load amount in USD, at the moment the transaction was made.
|
||||||
example: 3.897
|
example: 3.897
|
||||||
|
nullable: true
|
||||||
ethereumBlockNum:
|
ethereumBlockNum:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthBlockNum'
|
- $ref: '#/components/schemas/EthBlockNum'
|
||||||
@@ -1526,10 +1599,10 @@ components:
|
|||||||
required:
|
required:
|
||||||
- toForgeL1TransactionsNum
|
- toForgeL1TransactionsNum
|
||||||
- userOrigin
|
- userOrigin
|
||||||
- fromEthereumAddress
|
- fromHezEthereumAddress
|
||||||
- fromBJJ
|
- fromBJJ
|
||||||
- loadAmount
|
- loadAmount
|
||||||
- loadAmountUSD
|
- historicLoadAmountUSD
|
||||||
- ethereumBlockNum
|
- ethereumBlockNum
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
L2Info:
|
L2Info:
|
||||||
@@ -1539,16 +1612,17 @@ components:
|
|||||||
properties:
|
properties:
|
||||||
fee:
|
fee:
|
||||||
$ref: '#/components/schemas/FeeSelector'
|
$ref: '#/components/schemas/FeeSelector'
|
||||||
feeUSD:
|
historicFeeUSD:
|
||||||
type: number
|
type: number
|
||||||
description: Fee in USD, at the moment the transaction was forged.
|
description: Fee in USD, at the moment the transaction was forged.
|
||||||
example: 263.89
|
example: 263.89
|
||||||
|
nullable: true
|
||||||
nonce:
|
nonce:
|
||||||
$ref: '#/components/schemas/Nonce'
|
$ref: '#/components/schemas/Nonce'
|
||||||
example: null
|
example: null
|
||||||
required:
|
required:
|
||||||
- fee
|
- fee
|
||||||
- feeUSD
|
- historicFeeUSD
|
||||||
- nonce
|
- nonce
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
required:
|
required:
|
||||||
@@ -1560,12 +1634,9 @@ components:
|
|||||||
- toAccountIndex
|
- toAccountIndex
|
||||||
- amount
|
- amount
|
||||||
- batchNum
|
- batchNum
|
||||||
- tokenId
|
|
||||||
- tokenSymbol
|
|
||||||
- historicUSD
|
- historicUSD
|
||||||
- currentUSD
|
|
||||||
- fiatUpdate
|
|
||||||
- timestamp
|
- timestamp
|
||||||
|
- token
|
||||||
- L1Info
|
- L1Info
|
||||||
- L2Info
|
- L2Info
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
@@ -1618,10 +1689,8 @@ components:
|
|||||||
items:
|
items:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
tokenId:
|
token:
|
||||||
$ref: '#/components/schemas/TokenId'
|
$ref: '#/components/schemas/Token'
|
||||||
tokenSymbol:
|
|
||||||
$ref: '#/components/schemas/TokenSymbol'
|
|
||||||
amount:
|
amount:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/BigInt'
|
- $ref: '#/components/schemas/BigInt'
|
||||||
@@ -1635,13 +1704,21 @@ components:
|
|||||||
$ref: '#/components/schemas/BatchNum'
|
$ref: '#/components/schemas/BatchNum'
|
||||||
ethereumBlockNum:
|
ethereumBlockNum:
|
||||||
$ref: '#/components/schemas/EthBlockNum'
|
$ref: '#/components/schemas/EthBlockNum'
|
||||||
|
ethereumBlockHash:
|
||||||
|
type: string
|
||||||
|
description: hash of the Ethereum block in which the batch was forged
|
||||||
|
example: "0xfe88c94d860f01a17f961bf4bdfb6e0c6cd10d3fda5cc861e805ca1240c58553"
|
||||||
|
timestamp:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
description: Time in which the batch was forged.
|
||||||
forgerAddr:
|
forgerAddr:
|
||||||
$ref: '#/components/schemas/EthereumAddress'
|
$ref: '#/components/schemas/EthereumAddress'
|
||||||
collectedFees:
|
collectedFees:
|
||||||
$ref: '#/components/schemas/CollectedFees'
|
$ref: '#/components/schemas/CollectedFees'
|
||||||
totalCollectedFeesUSD:
|
historicTotalCollectedFeesUSD:
|
||||||
type: number
|
type: number
|
||||||
description: Sum of the all the fees collected, in USD.
|
description: Sum of the all the fees collected, in USD, at the moment the batch was forged.
|
||||||
example: 23.3
|
example: 23.3
|
||||||
stateRoot:
|
stateRoot:
|
||||||
allOf:
|
allOf:
|
||||||
@@ -1668,35 +1745,8 @@ components:
|
|||||||
type: object
|
type: object
|
||||||
description: Group of transactions forged in a coordinator and sent and validated in Ethereum.
|
description: Group of transactions forged in a coordinator and sent and validated in Ethereum.
|
||||||
properties:
|
properties:
|
||||||
batchNum:
|
batch:
|
||||||
$ref: '#/components/schemas/BatchNum'
|
$ref: '#/components/schemas/Batch'
|
||||||
forgerAddr:
|
|
||||||
$ref: '#/components/schemas/EthereumAddress'
|
|
||||||
collectedFees:
|
|
||||||
$ref: '#/components/schemas/CollectedFees'
|
|
||||||
ethereumBlockNum:
|
|
||||||
$ref: '#/components/schemas/EthBlockNum'
|
|
||||||
stateRoot:
|
|
||||||
allOf:
|
|
||||||
- $ref: '#/components/schemas/Hash'
|
|
||||||
- description: Root of the accounts Merkle Tree.
|
|
||||||
- example: "2734657026572a8708d883"
|
|
||||||
numAccounts:
|
|
||||||
type: integer
|
|
||||||
description: Number of registered accounts in this batch.
|
|
||||||
exitRoot:
|
|
||||||
allOf:
|
|
||||||
- $ref: '#/components/schemas/Hash'
|
|
||||||
- description: Root of the exit Merkle Tree associated to this batch.
|
|
||||||
- example: "2734657026572a8708d883"
|
|
||||||
forgeL1TransactionsNum:
|
|
||||||
allOf:
|
|
||||||
- $ref: '#/components/schemas/ToForgeL1TransactionsNum'
|
|
||||||
- description: Identifier that corresponds to the group of L1 transactions forged in the current batch.
|
|
||||||
- nullable: true
|
|
||||||
- example: 9
|
|
||||||
slotNum:
|
|
||||||
$ref: '#/components/schemas/SlotNum'
|
|
||||||
transactions:
|
transactions:
|
||||||
type: array
|
type: array
|
||||||
description: List of forged transactions in the batch
|
description: List of forged transactions in the batch
|
||||||
@@ -1752,6 +1802,8 @@ components:
|
|||||||
properties:
|
properties:
|
||||||
forgerAddr:
|
forgerAddr:
|
||||||
$ref: '#/components/schemas/EthereumAddress'
|
$ref: '#/components/schemas/EthereumAddress'
|
||||||
|
slotNum:
|
||||||
|
$ref: '#/components/schemas/SlotNum'
|
||||||
withdrawAddr:
|
withdrawAddr:
|
||||||
$ref: '#/components/schemas/EthereumAddress'
|
$ref: '#/components/schemas/EthereumAddress'
|
||||||
URL:
|
URL:
|
||||||
@@ -1814,7 +1866,7 @@ components:
|
|||||||
decimals:
|
decimals:
|
||||||
type: integer
|
type: integer
|
||||||
description: Number of decimals of the token.
|
description: Number of decimals of the token.
|
||||||
example: 5
|
example: 18
|
||||||
ethereumBlockNum:
|
ethereumBlockNum:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthBlockNum'
|
- $ref: '#/components/schemas/EthBlockNum'
|
||||||
@@ -1823,11 +1875,23 @@ components:
|
|||||||
USD:
|
USD:
|
||||||
type: number
|
type: number
|
||||||
description: Value of the token in USD.
|
description: Value of the token in USD.
|
||||||
example: 4.53
|
example: 1.01
|
||||||
|
nullable: true
|
||||||
fiatUpdate:
|
fiatUpdate:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
description: Timestamp of the moment the `USD` value was updated.
|
description: Timestamp of the moment the `USD` value was updated.
|
||||||
|
nullable: true
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- ethereumAddress
|
||||||
|
- name
|
||||||
|
- symbol
|
||||||
|
- decimals
|
||||||
|
- ethereumBlockNum
|
||||||
|
- USD
|
||||||
|
- fiatUpdate
|
||||||
|
additionalProperties: false
|
||||||
Tokens:
|
Tokens:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@@ -1855,8 +1919,6 @@ components:
|
|||||||
example: "0x347089321de8971320489793a823470918fffeab"
|
example: "0x347089321de8971320489793a823470918fffeab"
|
||||||
balance:
|
balance:
|
||||||
$ref: '#/components/schemas/BigInt'
|
$ref: '#/components/schemas/BigInt'
|
||||||
nullifier:
|
|
||||||
$ref: '#/components/schemas/BigInt'
|
|
||||||
instantWithdrawn:
|
instantWithdrawn:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthBlockNum'
|
- $ref: '#/components/schemas/EthBlockNum'
|
||||||
@@ -1872,6 +1934,8 @@ components:
|
|||||||
- $ref: '#/components/schemas/EthBlockNum'
|
- $ref: '#/components/schemas/EthBlockNum'
|
||||||
- description: Block in which the exit balance was delayed withdrawn after a delay withdraw request. Null indicates that a delay withdraw hasn't been performed.
|
- description: Block in which the exit balance was delayed withdrawn after a delay withdraw request. Null indicates that a delay withdraw hasn't been performed.
|
||||||
- example: null
|
- example: null
|
||||||
|
token:
|
||||||
|
$ref: '#/components/schemas/Token'
|
||||||
Exits:
|
Exits:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@@ -1888,24 +1952,16 @@ components:
|
|||||||
properties:
|
properties:
|
||||||
accountIndex:
|
accountIndex:
|
||||||
$ref: '#/components/schemas/AccountIndex'
|
$ref: '#/components/schemas/AccountIndex'
|
||||||
tokenId:
|
|
||||||
$ref: '#/components/schemas/TokenId'
|
|
||||||
tokenSymbol:
|
|
||||||
$ref: '#/components/schemas/TokenSymbol'
|
|
||||||
tokenName:
|
|
||||||
$ref: '#/components/schemas/TokenName'
|
|
||||||
nonce:
|
nonce:
|
||||||
$ref: '#/components/schemas/Nonce'
|
$ref: '#/components/schemas/Nonce'
|
||||||
balance:
|
balance:
|
||||||
$ref: '#/components/schemas/BigInt'
|
$ref: '#/components/schemas/BigInt'
|
||||||
balanceUSD:
|
|
||||||
type: integer
|
|
||||||
description: Balance of the account in USD
|
|
||||||
example: 1304
|
|
||||||
bjj:
|
bjj:
|
||||||
$ref: '#/components/schemas/BJJ'
|
$ref: '#/components/schemas/BJJ'
|
||||||
ethereumAddress:
|
hezEthereumAddress:
|
||||||
$ref: '#/components/schemas/HermezEthereumAddress'
|
$ref: '#/components/schemas/HezEthereumAddress'
|
||||||
|
token:
|
||||||
|
$ref: '#/components/schemas/Token'
|
||||||
Accounts:
|
Accounts:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@@ -2053,6 +2109,7 @@ components:
|
|||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthereumAddress'
|
- $ref: '#/components/schemas/EthereumAddress'
|
||||||
- description: Ethereum address of the boot coordinator.
|
- description: Ethereum address of the boot coordinator.
|
||||||
|
- example: "0x997dc4262BCDbf85190C01c996b4C06a461d2430"
|
||||||
slotDeadline:
|
slotDeadline:
|
||||||
type: integer
|
type: integer
|
||||||
description: Number of blocks at the end of a slot in which any coordinator can forge if the winner has not forged one before.
|
description: Number of blocks at the end of a slot in which any coordinator can forge if the winner has not forged one before.
|
||||||
@@ -2078,6 +2135,7 @@ components:
|
|||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthereumAddress'
|
- $ref: '#/components/schemas/EthereumAddress'
|
||||||
- description: Ethereum address where the donations will go to.
|
- description: Ethereum address where the donations will go to.
|
||||||
|
- example: "0x887dc4262BCDbf85190C01c996b4C06a461d2430"
|
||||||
allocationRatio:
|
allocationRatio:
|
||||||
type: array
|
type: array
|
||||||
description: Percentage in which fees will be splitted between donations, governance and burning. The sum of the tree values should be 100.
|
description: Percentage in which fees will be splitted between donations, governance and burning. The sum of the tree values should be 100.
|
||||||
@@ -2092,22 +2150,27 @@ components:
|
|||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthereumAddress'
|
- $ref: '#/components/schemas/EthereumAddress'
|
||||||
- description: Ethereum address of the rollup smart contract.
|
- description: Ethereum address of the rollup smart contract.
|
||||||
|
- example: "0x777dc4262BCDbf85190C01c996b4C06a461d2430"
|
||||||
governanceAddress:
|
governanceAddress:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthereumAddress'
|
- $ref: '#/components/schemas/EthereumAddress'
|
||||||
- description: Ethereum address of the governance mechanism.
|
- description: Ethereum address of the governance mechanism.
|
||||||
|
- example: "0x667dc4262BCDbf85190C01c996b4C06a461d2430"
|
||||||
whitheHackerGroupAddress:
|
whitheHackerGroupAddress:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthereumAddress'
|
- $ref: '#/components/schemas/EthereumAddress'
|
||||||
- description: Ethereum Address that can claim the funds in an emergency when the maximum emergency mode time is exceeded.
|
- description: Ethereum Address that can claim the funds in an emergency when the maximum emergency mode time is exceeded.
|
||||||
|
- example: "0x557dc4262BCDbf85190C01c996b4C06a461d2430"
|
||||||
keeperAddress:
|
keeperAddress:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthereumAddress'
|
- $ref: '#/components/schemas/EthereumAddress'
|
||||||
- description: Ethereum Address that can enable emergency mode and modify the delay to make a withdrawal.
|
- description: Ethereum Address that can enable emergency mode and modify the delay to make a withdrawal.
|
||||||
|
- example: "0x557dc4262BCDbf85190C01c996b4C06a461d2430"
|
||||||
withdrawalDelay:
|
withdrawalDelay:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthBlockNum'
|
- $ref: '#/components/schemas/EthBlockNum'
|
||||||
- description: The time that anyone needs to wait until a withdrawal of the funds is allowed, in Ethereum blocks.
|
- description: The time that anyone needs to wait until a withdrawal of the funds is allowed, in Ethereum blocks.
|
||||||
|
- example: 539573849
|
||||||
emergencyModeStartingTime:
|
emergencyModeStartingTime:
|
||||||
type: integer
|
type: integer
|
||||||
description: Ethereum block in which the emergency mode will be activated.
|
description: Ethereum block in which the emergency mode will be activated.
|
||||||
@@ -2140,6 +2203,7 @@ components:
|
|||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthereumAddress'
|
- $ref: '#/components/schemas/EthereumAddress'
|
||||||
- description: Ethereum address of the HEZ token.
|
- description: Ethereum address of the HEZ token.
|
||||||
|
- example: "0x444dc4262BCDbf85190C01c996b4C06a461d2430"
|
||||||
maxTxVerifiers:
|
maxTxVerifiers:
|
||||||
type: integer
|
type: integer
|
||||||
description: Maximum transactions of the verifiers.
|
description: Maximum transactions of the verifiers.
|
||||||
@@ -2214,10 +2278,12 @@ components:
|
|||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthereumAddress'
|
- $ref: '#/components/schemas/EthereumAddress'
|
||||||
- description: Ethereum address of the HEZ token.
|
- description: Ethereum address of the HEZ token.
|
||||||
|
- example: "0x333dc4262BCDbf85190C01c996b4C06a461d2430"
|
||||||
rollupAddress:
|
rollupAddress:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthereumAddress'
|
- $ref: '#/components/schemas/EthereumAddress'
|
||||||
- description: Ethereum address of the rollup smart contract.
|
- description: Ethereum address of the rollup smart contract.
|
||||||
|
- example: "0x222dc4262BCDbf85190C01c996b4C06a461d2430"
|
||||||
genesisBlockNum:
|
genesisBlockNum:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/EthBlockNum'
|
- $ref: '#/components/schemas/EthBlockNum'
|
||||||
|
|||||||
@@ -6,16 +6,13 @@ Port = 5432
|
|||||||
Host = "localhost"
|
Host = "localhost"
|
||||||
User = "hermez"
|
User = "hermez"
|
||||||
Password = "yourpasswordhere"
|
Password = "yourpasswordhere"
|
||||||
|
Name = "hermez"
|
||||||
|
|
||||||
[L2DB]
|
[L2DB]
|
||||||
Name = "l2"
|
|
||||||
SafetyPeriod = 10
|
SafetyPeriod = 10
|
||||||
MaxTxs = 512
|
MaxTxs = 512
|
||||||
TTL = "24h"
|
TTL = "24h"
|
||||||
|
|
||||||
[HistoryDB]
|
|
||||||
Name = "history"
|
|
||||||
|
|
||||||
[Web3]
|
[Web3]
|
||||||
URL = "XXX"
|
URL = "XXX"
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ type L1Tx struct {
|
|||||||
LoadAmount *big.Int
|
LoadAmount *big.Int
|
||||||
EthBlockNum int64 // Ethereum Block Number in which this L1Tx was added to the queue
|
EthBlockNum int64 // Ethereum Block Number in which this L1Tx was added to the queue
|
||||||
Type TxType
|
Type TxType
|
||||||
BatchNum BatchNum
|
BatchNum *BatchNum
|
||||||
|
USD *float64
|
||||||
|
LoadAmountUSD *float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tx returns a *Tx from the L1Tx
|
// Tx returns a *Tx from the L1Tx
|
||||||
@@ -52,11 +54,13 @@ func (tx *L1Tx) Tx() *Tx {
|
|||||||
FromBJJ: tx.FromBJJ,
|
FromBJJ: tx.FromBJJ,
|
||||||
LoadAmount: tx.LoadAmount,
|
LoadAmount: tx.LoadAmount,
|
||||||
EthBlockNum: tx.EthBlockNum,
|
EthBlockNum: tx.EthBlockNum,
|
||||||
|
USD: tx.USD,
|
||||||
|
LoadAmountUSD: tx.LoadAmountUSD,
|
||||||
}
|
}
|
||||||
if tx.LoadAmount != nil {
|
if tx.LoadAmount != nil {
|
||||||
lf := new(big.Float).SetInt(tx.LoadAmount)
|
lf := new(big.Float).SetInt(tx.LoadAmount)
|
||||||
loadAmountFloat, _ := lf.Float64()
|
loadAmountFloat, _ := lf.Float64()
|
||||||
genericTx.LoadAmountFloat = loadAmountFloat
|
genericTx.LoadAmountFloat = &loadAmountFloat
|
||||||
}
|
}
|
||||||
return genericTx
|
return genericTx
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ type L2Tx struct {
|
|||||||
FromIdx Idx
|
FromIdx Idx
|
||||||
ToIdx Idx
|
ToIdx Idx
|
||||||
Amount *big.Int
|
Amount *big.Int
|
||||||
|
USD *float64
|
||||||
Fee FeeSelector
|
Fee FeeSelector
|
||||||
|
FeeUSD *float64
|
||||||
Nonce Nonce
|
Nonce Nonce
|
||||||
Type TxType
|
Type TxType
|
||||||
EthBlockNum int64 // Ethereum Block Number in which this L2Tx was added to the queue
|
EthBlockNum int64 // Ethereum Block Number in which this L2Tx was added to the queue
|
||||||
@@ -23,6 +25,12 @@ type L2Tx struct {
|
|||||||
func (tx *L2Tx) Tx() *Tx {
|
func (tx *L2Tx) Tx() *Tx {
|
||||||
f := new(big.Float).SetInt(tx.Amount)
|
f := new(big.Float).SetInt(tx.Amount)
|
||||||
amountFloat, _ := f.Float64()
|
amountFloat, _ := f.Float64()
|
||||||
|
batchNum := new(BatchNum)
|
||||||
|
*batchNum = tx.BatchNum
|
||||||
|
fee := new(FeeSelector)
|
||||||
|
*fee = tx.Fee
|
||||||
|
nonce := new(Nonce)
|
||||||
|
*nonce = tx.Nonce
|
||||||
return &Tx{
|
return &Tx{
|
||||||
IsL1: false,
|
IsL1: false,
|
||||||
TxID: tx.TxID,
|
TxID: tx.TxID,
|
||||||
@@ -31,11 +39,13 @@ func (tx *L2Tx) Tx() *Tx {
|
|||||||
FromIdx: tx.FromIdx,
|
FromIdx: tx.FromIdx,
|
||||||
ToIdx: tx.ToIdx,
|
ToIdx: tx.ToIdx,
|
||||||
Amount: tx.Amount,
|
Amount: tx.Amount,
|
||||||
|
USD: tx.USD,
|
||||||
AmountFloat: amountFloat,
|
AmountFloat: amountFloat,
|
||||||
BatchNum: tx.BatchNum,
|
BatchNum: batchNum,
|
||||||
EthBlockNum: tx.EthBlockNum,
|
EthBlockNum: tx.EthBlockNum,
|
||||||
Fee: tx.Fee,
|
Fee: fee,
|
||||||
Nonce: tx.Nonce,
|
FeeUSD: tx.FeeUSD,
|
||||||
|
Nonce: nonce,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type PoolL2Tx struct {
|
|||||||
TokenID TokenID `meddler:"token_id"`
|
TokenID TokenID `meddler:"token_id"`
|
||||||
Amount *big.Int `meddler:"amount,bigint"` // TODO: change to float16
|
Amount *big.Int `meddler:"amount,bigint"` // TODO: change to float16
|
||||||
AmountFloat float64 `meddler:"amount_f"` // TODO: change to float16
|
AmountFloat float64 `meddler:"amount_f"` // TODO: change to float16
|
||||||
USD float64 `meddler:"value_usd"` // TODO: change to float16
|
USD *float64 `meddler:"value_usd"` // TODO: change to float16
|
||||||
Fee FeeSelector `meddler:"fee"`
|
Fee FeeSelector `meddler:"fee"`
|
||||||
Nonce Nonce `meddler:"nonce"` // effective 40 bits used
|
Nonce Nonce `meddler:"nonce"` // effective 40 bits used
|
||||||
State PoolL2TxState `meddler:"state"`
|
State PoolL2TxState `meddler:"state"`
|
||||||
@@ -37,11 +37,12 @@ type PoolL2Tx struct {
|
|||||||
RqAmount *big.Int `meddler:"rq_amount,bigintnull"` // TODO: change to float16
|
RqAmount *big.Int `meddler:"rq_amount,bigintnull"` // TODO: change to float16
|
||||||
RqFee FeeSelector `meddler:"rq_fee,zeroisnull"`
|
RqFee FeeSelector `meddler:"rq_fee,zeroisnull"`
|
||||||
RqNonce uint64 `meddler:"rq_nonce,zeroisnull"` // effective 48 bits used
|
RqNonce uint64 `meddler:"rq_nonce,zeroisnull"` // effective 48 bits used
|
||||||
AbsoluteFee float64 `meddler:"fee_usd,zeroisnull"`
|
AbsoluteFee *float64 `meddler:"fee_usd"`
|
||||||
AbsoluteFeeUpdate time.Time `meddler:"usd_update,utctimez"`
|
AbsoluteFeeUpdate *time.Time `meddler:"usd_update,utctime"`
|
||||||
Type TxType `meddler:"tx_type"`
|
Type TxType `meddler:"tx_type"`
|
||||||
// Extra metadata, may be uninitialized
|
// Extra metadata, may be uninitialized
|
||||||
RqTxCompressedData []byte `meddler:"-"` // 253 bits, optional for atomic txs
|
RqTxCompressedData []byte `meddler:"-"` // 253 bits, optional for atomic txs
|
||||||
|
TokenSymbol string `meddler:"token_symbol"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TxCompressedData spec:
|
// TxCompressedData spec:
|
||||||
@@ -186,8 +187,8 @@ func (tx *PoolL2Tx) Tx() *Tx {
|
|||||||
FromIdx: tx.FromIdx,
|
FromIdx: tx.FromIdx,
|
||||||
ToIdx: tx.ToIdx,
|
ToIdx: tx.ToIdx,
|
||||||
Amount: tx.Amount,
|
Amount: tx.Amount,
|
||||||
Nonce: tx.Nonce,
|
Nonce: &tx.Nonce,
|
||||||
Fee: tx.Fee,
|
Fee: &tx.Fee,
|
||||||
Type: tx.Type,
|
Type: tx.Type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ const tokenIDBytesLen = 4
|
|||||||
|
|
||||||
// Token is a struct that represents an Ethereum token that is supported in Hermez network
|
// Token is a struct that represents an Ethereum token that is supported in Hermez network
|
||||||
type Token struct {
|
type Token struct {
|
||||||
TokenID TokenID `meddler:"token_id"`
|
TokenID TokenID `json:"id" meddler:"token_id"`
|
||||||
EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum block number in which this token was registered
|
EthBlockNum int64 `json:"ethereumBlockNum" meddler:"eth_block_num"` // Ethereum block number in which this token was registered
|
||||||
EthAddr ethCommon.Address `meddler:"eth_addr"`
|
EthAddr ethCommon.Address `json:"ethereumAddress" meddler:"eth_addr"`
|
||||||
Name string `meddler:"name"`
|
Name string `json:"name" meddler:"name"`
|
||||||
Symbol string `meddler:"symbol"`
|
Symbol string `json:"symbol" meddler:"symbol"`
|
||||||
Decimals uint64 `meddler:"decimals"`
|
Decimals uint64 `json:"decimals" meddler:"decimals"`
|
||||||
USD float64 `meddler:"usd,zeroisnull"`
|
USD *float64 `json:"USD" meddler:"usd"`
|
||||||
USDUpdate time.Time `meddler:"usd_update,utctimez"`
|
USDUpdate *time.Time `json:"fiatUpdate" meddler:"usd_update,utctime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenInfo provides the price of the token in USD
|
// TokenInfo provides the price of the token in USD
|
||||||
|
|||||||
34
common/tx.go
34
common/tx.go
@@ -41,30 +41,30 @@ const (
|
|||||||
// Tx is a struct used by the TxSelector & BatchBuilder as a generic type generated from L1Tx & PoolL2Tx
|
// Tx is a struct used by the TxSelector & BatchBuilder as a generic type generated from L1Tx & PoolL2Tx
|
||||||
type Tx struct {
|
type Tx struct {
|
||||||
// Generic
|
// Generic
|
||||||
IsL1 bool `meddler:"is_l1"`
|
IsL1 bool `meddler:"is_l1"`
|
||||||
TxID TxID `meddler:"id"`
|
TxID TxID `meddler:"id"`
|
||||||
Type TxType `meddler:"type"`
|
Type TxType `meddler:"type"`
|
||||||
Position int `meddler:"position"`
|
Position int `meddler:"position"`
|
||||||
FromIdx Idx `meddler:"from_idx"`
|
FromIdx Idx `meddler:"from_idx"`
|
||||||
ToIdx Idx `meddler:"to_idx"`
|
ToIdx Idx `meddler:"to_idx"`
|
||||||
Amount *big.Int `meddler:"amount,bigint"`
|
Amount *big.Int `meddler:"amount,bigint"`
|
||||||
AmountFloat float64 `meddler:"amount_f"`
|
AmountFloat float64 `meddler:"amount_f"`
|
||||||
TokenID TokenID `meddler:"token_id"`
|
TokenID TokenID `meddler:"token_id"`
|
||||||
USD float64 `meddler:"amount_usd,zeroisnull"`
|
USD *float64 `meddler:"amount_usd"`
|
||||||
BatchNum BatchNum `meddler:"batch_num,zeroisnull"` // batchNum in which this tx was forged. If the tx is L2, this must be != 0
|
BatchNum *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
|
EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
|
||||||
// L1
|
// L1
|
||||||
ToForgeL1TxsNum int64 `meddler:"to_forge_l1_txs_num"` // toForgeL1TxsNum in which the tx was forged / will be forged
|
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
|
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"`
|
FromEthAddr ethCommon.Address `meddler:"from_eth_addr"`
|
||||||
FromBJJ *babyjub.PublicKey `meddler:"from_bjj"`
|
FromBJJ *babyjub.PublicKey `meddler:"from_bjj"`
|
||||||
LoadAmount *big.Int `meddler:"load_amount,bigintnull"`
|
LoadAmount *big.Int `meddler:"load_amount,bigintnull"`
|
||||||
LoadAmountFloat float64 `meddler:"load_amount_f"`
|
LoadAmountFloat *float64 `meddler:"load_amount_f"`
|
||||||
LoadAmountUSD float64 `meddler:"load_amount_usd,zeroisnull"`
|
LoadAmountUSD *float64 `meddler:"load_amount_usd"`
|
||||||
// L2
|
// L2
|
||||||
Fee FeeSelector `meddler:"fee,zeroisnull"`
|
Fee *FeeSelector `meddler:"fee"`
|
||||||
FeeUSD float64 `meddler:"fee_usd,zeroisnull"`
|
FeeUSD *float64 `meddler:"fee_usd"`
|
||||||
Nonce Nonce `meddler:"nonce,zeroisnull"`
|
Nonce *Nonce `meddler:"nonce"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// L1Tx returns a *L1Tx from the Tx
|
// L1Tx returns a *L1Tx from the Tx
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ type Coordinator struct {
|
|||||||
ForgerAddress ethCommon.Address `validate:"required"`
|
ForgerAddress ethCommon.Address `validate:"required"`
|
||||||
ForgeLoopInterval Duration `validate:"required"`
|
ForgeLoopInterval Duration `validate:"required"`
|
||||||
L2DB struct {
|
L2DB struct {
|
||||||
Name string `validate:"required"`
|
|
||||||
SafetyPeriod common.BatchNum `validate:"required"`
|
SafetyPeriod common.BatchNum `validate:"required"`
|
||||||
MaxTxs uint32 `validate:"required"`
|
MaxTxs uint32 `validate:"required"`
|
||||||
TTL Duration `validate:"required"`
|
TTL Duration `validate:"required"`
|
||||||
@@ -60,9 +59,7 @@ type Node struct {
|
|||||||
Host string `validate:"required"`
|
Host string `validate:"required"`
|
||||||
User string `validate:"required"`
|
User string `validate:"required"`
|
||||||
Password string `validate:"required"`
|
Password string `validate:"required"`
|
||||||
} `validate:"required"`
|
Name string `validate:"required"`
|
||||||
HistoryDB struct {
|
|
||||||
Name string `validate:"required"`
|
|
||||||
} `validate:"required"`
|
} `validate:"required"`
|
||||||
Web3 struct {
|
Web3 struct {
|
||||||
URL string `validate:"required"`
|
URL string `validate:"required"`
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hermeznetwork/hermez-node/batchbuilder"
|
"github.com/hermeznetwork/hermez-node/batchbuilder"
|
||||||
|
dbUtils "github.com/hermeznetwork/hermez-node/db"
|
||||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||||
"github.com/hermeznetwork/hermez-node/db/l2db"
|
"github.com/hermeznetwork/hermez-node/db/l2db"
|
||||||
"github.com/hermeznetwork/hermez-node/db/statedb"
|
"github.com/hermeznetwork/hermez-node/db/statedb"
|
||||||
@@ -26,8 +27,9 @@ func newTestModules(t *testing.T) (*txselector.TxSelector, *batchbuilder.BatchBu
|
|||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
pass := os.Getenv("POSTGRES_PASS")
|
pass := os.Getenv("POSTGRES_PASS")
|
||||||
l2DB, err := l2db.NewL2DB(5432, "localhost", "hermez", pass, "l2", 10, 512, 24*time.Hour)
|
db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
l2DB := l2db.NewL2DB(db, 10, 100, 24*time.Hour)
|
||||||
|
|
||||||
txselDir, err := ioutil.TempDir("", "tmpTxSelDB")
|
txselDir, err := ioutil.TempDir("", "tmpTxSelDB")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|||||||
@@ -6,16 +6,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/gobuffalo/packr/v2"
|
|
||||||
"github.com/hermeznetwork/hermez-node/common"
|
"github.com/hermeznetwork/hermez-node/common"
|
||||||
"github.com/hermeznetwork/hermez-node/db"
|
"github.com/hermeznetwork/hermez-node/db"
|
||||||
"github.com/hermeznetwork/hermez-node/log"
|
|
||||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
//nolint:errcheck // driver for postgres DB
|
//nolint:errcheck // driver for postgres DB
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
migrate "github.com/rubenv/sql-migrate"
|
|
||||||
"github.com/russross/meddler"
|
"github.com/russross/meddler"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -57,28 +54,8 @@ type BatchData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewHistoryDB initialize the DB
|
// NewHistoryDB initialize the DB
|
||||||
func NewHistoryDB(port int, host, user, password, dbname string) (*HistoryDB, error) {
|
func NewHistoryDB(db *sqlx.DB) *HistoryDB {
|
||||||
// Connect to DB
|
return &HistoryDB{db: 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddBlock insert a block into the DB
|
// AddBlock insert a block into the DB
|
||||||
@@ -328,8 +305,14 @@ func (hdb *HistoryDB) GetAccounts() ([]*common.Account, error) {
|
|||||||
return accs, err
|
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) }
|
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 {
|
func (hdb *HistoryDB) addL1Txs(d meddler.DB, l1txs []common.L1Tx) error {
|
||||||
txs := []common.Tx{}
|
txs := []common.Tx{}
|
||||||
for _, tx := range l1txs {
|
for _, tx := range l1txs {
|
||||||
@@ -338,8 +321,10 @@ func (hdb *HistoryDB) addL1Txs(d meddler.DB, l1txs []common.L1Tx) error {
|
|||||||
return hdb.addTxs(d, txs)
|
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) }
|
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 {
|
func (hdb *HistoryDB) addL2Txs(d meddler.DB, l2txs []common.L2Tx) error {
|
||||||
txs := []common.Tx{}
|
txs := []common.Tx{}
|
||||||
for _, tx := range l2txs {
|
for _, tx := range l2txs {
|
||||||
@@ -348,8 +333,6 @@ func (hdb *HistoryDB) addL2Txs(d meddler.DB, l2txs []common.L2Tx) error {
|
|||||||
return hdb.addTxs(d, txs)
|
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 {
|
func (hdb *HistoryDB) addTxs(d meddler.DB, txs []common.Tx) error {
|
||||||
return db.BulkInsert(
|
return db.BulkInsert(
|
||||||
d,
|
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
|
// GetTxs returns a list of txs from the DB
|
||||||
func (hdb *HistoryDB) GetTxs() ([]*common.Tx, error) {
|
func (hdb *HistoryDB) GetTxs() ([]*common.Tx, error) {
|
||||||
var txs []*common.Tx
|
var txs []*common.Tx
|
||||||
@@ -413,8 +386,10 @@ func (hdb *HistoryDB) GetHistoryTxs(
|
|||||||
}
|
}
|
||||||
var query string
|
var query string
|
||||||
var args []interface{}
|
var args []interface{}
|
||||||
queryStr := `SELECT tx.*, tx.amount_f * token.usd AS current_usd,
|
queryStr := `SELECT tx.*, token.token_id, token.eth_block_num AS token_block,
|
||||||
token.symbol, token.usd_update, block.timestamp, count(*) OVER() AS total_items FROM tx
|
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 token ON tx.token_id = token.token_id
|
||||||
INNER JOIN block ON tx.eth_block_num = block.eth_block_num `
|
INNER JOIN block ON tx.eth_block_num = block.eth_block_num `
|
||||||
// Apply filters
|
// 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
|
// // 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.
|
// // 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) {
|
// func (hdb *HistoryDB) GetL1UserTxs(toForgeL1TxsNum int64) ([]*common.Tx, error) {
|
||||||
var txs []*common.Tx
|
// var txs []*common.Tx
|
||||||
err := meddler.QueryAll(
|
// err := meddler.QueryAll(
|
||||||
hdb.db, &txs,
|
// hdb.db, &txs,
|
||||||
"SELECT * FROM tx WHERE to_forge_l1_txs_num = $1 AND is_l1 = TRUE AND user_origin = TRUE;",
|
// "SELECT * FROM tx WHERE to_forge_l1_txs_num = $1 AND is_l1 = TRUE AND user_origin = TRUE;",
|
||||||
toForgeL1TxsNum,
|
// toForgeL1TxsNum,
|
||||||
)
|
// )
|
||||||
return txs, err
|
// return txs, err
|
||||||
}
|
// }
|
||||||
|
|
||||||
// TODO: Think about chaning all the queries that return a last value, to queries that return the next valid value.
|
// 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
|
// Add Batches
|
||||||
for _, batch := range blockData.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 {
|
if batch.L1Batch {
|
||||||
err = hdb.setBatchNumL1UserTxs(txn, batch.Batch.ForgeL1TxsNum, int64(batch.Batch.BatchNum))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(batch.L1CoordinatorTxs) > 0 {
|
if len(batch.L1CoordinatorTxs) > 0 {
|
||||||
err = hdb.addL1Txs(txn, batch.L1CoordinatorTxs)
|
err = hdb.addL1Txs(txn, batch.L1CoordinatorTxs)
|
||||||
if err != nil {
|
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
|
// TODO: INSERT CONTRACTS VARS
|
||||||
}
|
}
|
||||||
|
|
||||||
return txn.Commit()
|
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
|
package historydb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -9,6 +8,8 @@ import (
|
|||||||
|
|
||||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/hermeznetwork/hermez-node/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/hermeznetwork/hermez-node/test"
|
||||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -26,17 +27,20 @@ var historyDB *HistoryDB
|
|||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
// init DB
|
// init DB
|
||||||
var err error
|
|
||||||
pass := os.Getenv("POSTGRES_PASS")
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
// Run tests
|
// Run tests
|
||||||
result := m.Run()
|
result := m.Run()
|
||||||
// Close DB
|
// Close DB
|
||||||
if err := historyDB.Close(); err != nil {
|
if err := db.Close(); err != nil {
|
||||||
fmt.Println("Error closing the history DB:", err)
|
log.Error("Error closing the history DB:", err)
|
||||||
}
|
}
|
||||||
os.Exit(result)
|
os.Exit(result)
|
||||||
}
|
}
|
||||||
@@ -145,15 +149,6 @@ func TestTokens(t *testing.T) {
|
|||||||
tokens := test.GenTokens(nTokens, blocks)
|
tokens := test.GenTokens(nTokens, blocks)
|
||||||
err := historyDB.AddTokens(tokens)
|
err := historyDB.AddTokens(tokens)
|
||||||
assert.NoError(t, err)
|
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
|
// Fetch tokens
|
||||||
fetchedTokens, err := historyDB.GetTokens()
|
fetchedTokens, err := historyDB.GetTokens()
|
||||||
assert.NoError(t, err)
|
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].Name, token.Name)
|
||||||
assert.Equal(t, tokens[i].Symbol, token.Symbol)
|
assert.Equal(t, tokens[i].Symbol, token.Symbol)
|
||||||
assert.Equal(t, tokens[i].USD, token.USD)
|
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
|
// Prepare blocks in the DB
|
||||||
blocks := setTestBlocks(fromBlock, toBlock)
|
blocks := setTestBlocks(fromBlock, toBlock)
|
||||||
// Generate fake tokens
|
// Generate fake tokens
|
||||||
const nTokens = 5
|
const nTokens = 500
|
||||||
const tokenValue = 1.23456
|
|
||||||
tokens := test.GenTokens(nTokens, blocks)
|
tokens := test.GenTokens(nTokens, blocks)
|
||||||
for i := 0; i < len(tokens); i++ {
|
|
||||||
tokens[i].USD = tokenValue
|
|
||||||
}
|
|
||||||
err := historyDB.AddTokens(tokens)
|
err := historyDB.AddTokens(tokens)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// Generate fake batches
|
// Generate fake batches
|
||||||
@@ -224,60 +219,17 @@ func TestTxs(t *testing.T) {
|
|||||||
err = historyDB.AddAccounts(accs)
|
err = historyDB.AddAccounts(accs)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// Generate fake L1 txs
|
// Generate fake L1 txs
|
||||||
const nL1s = 30
|
const nL1s = 64
|
||||||
_, l1txs := test.GenL1Txs(0, nL1s, 0, nil, accs, tokens, blocks, batches)
|
_, l1txs := test.GenL1Txs(0, nL1s, 0, nil, accs, tokens, blocks, batches)
|
||||||
err = historyDB.AddL1Txs(l1txs)
|
err = historyDB.AddL1Txs(l1txs)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// Generate fake L2 txs
|
// Generate fake L2 txs
|
||||||
const nL2s = 20
|
const nL2s = 2048 - nL1s
|
||||||
_, l2txs := test.GenL2Txs(0, nL2s, 0, nil, accs, tokens, blocks, batches)
|
_, l2txs := test.GenL2Txs(0, nL2s, 0, nil, accs, tokens, blocks, batches)
|
||||||
err = historyDB.AddL2Txs(l2txs)
|
err = historyDB.AddL2Txs(l2txs)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// Compare fetched txs vs generated txs.
|
// Compare fetched txs vs generated txs.
|
||||||
for i := 0; i < len(l1txs); i++ {
|
fetchAndAssertTxs(t, l1txs, l2txs)
|
||||||
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)
|
|
||||||
}
|
|
||||||
// Test trigger: L1 integrity
|
// Test trigger: L1 integrity
|
||||||
// from_eth_addr can't be null
|
// from_eth_addr can't be null
|
||||||
l1txs[0].FromEthAddr = ethCommon.Address{}
|
l1txs[0].FromEthAddr = ethCommon.Address{}
|
||||||
@@ -304,23 +256,75 @@ func TestTxs(t *testing.T) {
|
|||||||
l2txs[0].Nonce = 0
|
l2txs[0].Nonce = 0
|
||||||
err = historyDB.AddL2Txs(l2txs)
|
err = historyDB.AddL2Txs(l2txs)
|
||||||
assert.Error(t, err)
|
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
|
// 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.NoError(t, err)
|
||||||
assert.NotZero(t, len(txs))
|
assert.Equal(t, expectedPosition, position)
|
||||||
position, err := historyDB.GetLastTxsPosition(2)
|
|
||||||
assert.NoError(t, err)
|
// GetL1UserTxs: not needed? tests were broken
|
||||||
assert.Equal(t, 22, position)
|
// txs, err := historyDB.GetL1UserTxs(2)
|
||||||
// Test Update L1 TX Batch_num
|
// assert.NoError(t, err)
|
||||||
assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
|
// assert.NotZero(t, len(txs))
|
||||||
txs[0].BatchNum = common.BatchNum(1)
|
// assert.NoError(t, err)
|
||||||
// err = historyDB.UpdateTxsBatchNum(txs)
|
// assert.Equal(t, 22, position)
|
||||||
err = historyDB.SetBatchNumL1UserTxs(2, 1)
|
// // Test Update L1 TX Batch_num
|
||||||
assert.NoError(t, err)
|
// assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
|
||||||
txs, err = historyDB.GetL1UserTxs(2)
|
// txs[0].BatchNum = common.BatchNum(1)
|
||||||
assert.NoError(t, err)
|
// txs, err = historyDB.GetL1UserTxs(2)
|
||||||
assert.NotZero(t, len(txs))
|
// assert.NoError(t, err)
|
||||||
assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
|
// 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) {
|
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
|
// required by the API, and extracted by joining block and token tables
|
||||||
type HistoryTx struct {
|
type HistoryTx struct {
|
||||||
// Generic
|
// Generic
|
||||||
IsL1 bool `meddler:"is_l1"`
|
IsL1 bool `meddler:"is_l1"`
|
||||||
TxID common.TxID `meddler:"id"`
|
TxID common.TxID `meddler:"id"`
|
||||||
Type common.TxType `meddler:"type"`
|
Type common.TxType `meddler:"type"`
|
||||||
Position int `meddler:"position"`
|
Position int `meddler:"position"`
|
||||||
FromIdx common.Idx `meddler:"from_idx"`
|
FromIdx common.Idx `meddler:"from_idx"`
|
||||||
ToIdx common.Idx `meddler:"to_idx"`
|
ToIdx common.Idx `meddler:"to_idx"`
|
||||||
Amount *big.Int `meddler:"amount,bigint"`
|
Amount *big.Int `meddler:"amount,bigint"`
|
||||||
AmountFloat float64 `meddler:"amount_f"`
|
AmountFloat float64 `meddler:"amount_f"`
|
||||||
TokenID common.TokenID `meddler:"token_id"`
|
HistoricUSD *float64 `meddler:"amount_usd"`
|
||||||
USD float64 `meddler:"amount_usd,zeroisnull"`
|
BatchNum *common.BatchNum `meddler:"batch_num"` // batchNum in which this tx was forged. If the tx is L2, this must be != 0
|
||||||
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
|
||||||
EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
|
|
||||||
// L1
|
// L1
|
||||||
ToForgeL1TxsNum int64 `meddler:"to_forge_l1_txs_num"` // toForgeL1TxsNum in which the tx was forged / will be forged
|
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
|
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"`
|
FromEthAddr ethCommon.Address `meddler:"from_eth_addr"`
|
||||||
FromBJJ *babyjub.PublicKey `meddler:"from_bjj"`
|
FromBJJ *babyjub.PublicKey `meddler:"from_bjj"`
|
||||||
LoadAmount *big.Int `meddler:"load_amount,bigintnull"`
|
LoadAmount *big.Int `meddler:"load_amount,bigintnull"`
|
||||||
LoadAmountFloat float64 `meddler:"load_amount_f"`
|
LoadAmountFloat *float64 `meddler:"load_amount_f"`
|
||||||
LoadAmountUSD float64 `meddler:"load_amount_usd,zeroisnull"`
|
HistoricLoadAmountUSD *float64 `meddler:"load_amount_usd"`
|
||||||
// L2
|
// L2
|
||||||
Fee common.FeeSelector `meddler:"fee,zeroisnull"`
|
Fee *common.FeeSelector `meddler:"fee"`
|
||||||
FeeUSD float64 `meddler:"fee_usd,zeroisnull"`
|
HistoricFeeUSD *float64 `meddler:"fee_usd"`
|
||||||
Nonce common.Nonce `meddler:"nonce,zeroisnull"`
|
Nonce *common.Nonce `meddler:"nonce"`
|
||||||
// API extras
|
// API extras
|
||||||
Timestamp time.Time `meddler:"timestamp,utctime"`
|
Timestamp time.Time `meddler:"timestamp,utctime"`
|
||||||
TokenSymbol string `meddler:"symbol"`
|
TotalItems int `meddler:"total_items"`
|
||||||
CurrentUSD float64 `meddler:"current_usd"`
|
TokenID common.TokenID `meddler:"token_id"`
|
||||||
USDUpdate time.Time `meddler:"usd_update,utctime"`
|
TokenEthBlockNum int64 `meddler:"token_block"`
|
||||||
TotalItems int `meddler:"total_items"`
|
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
|
package l2db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/gobuffalo/packr/v2"
|
|
||||||
"github.com/hermeznetwork/hermez-node/common"
|
"github.com/hermeznetwork/hermez-node/common"
|
||||||
"github.com/hermeznetwork/hermez-node/db"
|
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||||
"github.com/hermeznetwork/hermez-node/log"
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
//nolint:errcheck // driver for postgres DB
|
//nolint:errcheck // driver for postgres DB
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
migrate "github.com/rubenv/sql-migrate"
|
|
||||||
"github.com/russross/meddler"
|
"github.com/russross/meddler"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,40 +26,15 @@ type L2DB struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewL2DB creates a L2DB.
|
// 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.
|
// maxTxs that the DB should have and TTL (time to live) for pending txs.
|
||||||
func NewL2DB(
|
func NewL2DB(db *sqlx.DB, safetyPeriod common.BatchNum, maxTxs uint32, TTL time.Duration) *L2DB {
|
||||||
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")
|
|
||||||
|
|
||||||
return &L2DB{
|
return &L2DB{
|
||||||
db: db,
|
db: db,
|
||||||
safetyPeriod: safetyPeriod,
|
safetyPeriod: safetyPeriod,
|
||||||
ttl: TTL,
|
ttl: TTL,
|
||||||
maxTxs: maxTxs,
|
maxTxs: maxTxs,
|
||||||
}, nil
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DB returns a pointer to the L2DB.db. This method should be used only for
|
// 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
|
// AddTxTest inserts a tx into the L2DB. This is useful for test purposes,
|
||||||
func (l2db *L2DB) AddTx(tx *common.PoolL2Tx) error {
|
// but in production txs will only be inserted through the API (method TBD)
|
||||||
return meddler.Insert(l2db.db, "tx_pool", tx)
|
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
|
// GetTx return the specified Tx
|
||||||
func (l2db *L2DB) GetTx(txID common.TxID) (*common.PoolL2Tx, error) {
|
func (l2db *L2DB) GetTx(txID common.TxID) (*common.PoolL2Tx, error) {
|
||||||
tx := new(common.PoolL2Tx)
|
tx := new(common.PoolL2Tx)
|
||||||
return tx, meddler.QueryRow(
|
return tx, meddler.QueryRow(
|
||||||
l2db.db, tx,
|
l2db.db, tx,
|
||||||
"SELECT * FROM tx_pool WHERE tx_id = $1;",
|
selectPoolTx+"WHERE tx_id = $1;",
|
||||||
txID,
|
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) {
|
func (l2db *L2DB) GetPendingTxs() ([]*common.PoolL2Tx, error) {
|
||||||
var txs []*common.PoolL2Tx
|
var txs []*common.PoolL2Tx
|
||||||
err := meddler.QueryAll(
|
err := meddler.QueryAll(
|
||||||
l2db.db, &txs,
|
l2db.db, &txs,
|
||||||
"SELECT * FROM tx_pool WHERE state = $1",
|
selectPoolTx+"WHERE state = $1 AND token.usd IS NOT NULL",
|
||||||
common.PoolL2TxStatePending,
|
common.PoolL2TxStatePending,
|
||||||
)
|
)
|
||||||
return txs, err
|
return txs, err
|
||||||
@@ -202,40 +229,6 @@ func (l2db *L2DB) CheckNonces(updatedAccounts []common.Account, batchNum common.
|
|||||||
return txn.Commit()
|
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.
|
// 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
|
// The state of the affected txs can change form Forged -> Pending or from Invalid -> Pending
|
||||||
func (l2db *L2DB) Reorg(lastValidBatch common.BatchNum) error {
|
func (l2db *L2DB) Reorg(lastValidBatch common.BatchNum) error {
|
||||||
@@ -286,8 +279,3 @@ func (l2db *L2DB) Purge(currentBatchNum common.BatchNum) (err error) {
|
|||||||
}
|
}
|
||||||
return txn.Commit()
|
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
|
package l2db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hermeznetwork/hermez-node/common"
|
"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/log"
|
||||||
"github.com/hermeznetwork/hermez-node/test"
|
"github.com/hermeznetwork/hermez-node/test"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
var l2DB *L2DB
|
var l2DB *L2DB
|
||||||
|
var tokens []common.Token
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
// init DB
|
// init DB
|
||||||
var err error
|
|
||||||
pass := os.Getenv("POSTGRES_PASS")
|
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 {
|
if err != nil {
|
||||||
log.Error("L2DB migration failed: " + err.Error())
|
|
||||||
panic(err)
|
panic(err)
|
||||||
} else {
|
|
||||||
log.Debug("L2DB migration succed")
|
|
||||||
}
|
}
|
||||||
// Run tests
|
// Run tests
|
||||||
result := m.Run()
|
result := m.Run()
|
||||||
// Close DB
|
// Close DB
|
||||||
if err := l2DB.Close(); err != nil {
|
if err := db.Close(); err != nil {
|
||||||
fmt.Println("Error closing the history DB:", err)
|
log.Error("Error closing the history DB:", err)
|
||||||
}
|
}
|
||||||
os.Exit(result)
|
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
|
const nInserts = 20
|
||||||
test.CleanL2DB(l2DB.DB())
|
test.CleanL2DB(l2DB.DB())
|
||||||
txs := test.GenPoolTxs(nInserts)
|
txs := test.GenPoolTxs(nInserts, tokens)
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
err := l2DB.AddTx(tx)
|
err := l2DB.AddTxTest(tx)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
fetchedTx, err := l2DB.GetTx(tx.TxID)
|
fetchedTx, err := l2DB.GetTx(tx.TxID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, tx.Timestamp.Unix(), fetchedTx.Timestamp.Unix())
|
assertTx(t, tx, fetchedTx)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
const nInserts = 20
|
||||||
test.CleanL2DB(l2DB.DB())
|
test.CleanL2DB(l2DB.DB())
|
||||||
txs := test.GenPoolTxs(nInserts)
|
txs := test.GenPoolTxs(nInserts, tokens)
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
_ = l2DB.AddTx(tx)
|
_ = l2DB.AddTxTest(tx)
|
||||||
}
|
}
|
||||||
elapsedTime := time.Since(now)
|
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) {
|
func TestGetPending(t *testing.T) {
|
||||||
const nInserts = 20
|
const nInserts = 20
|
||||||
test.CleanL2DB(l2DB.DB())
|
test.CleanL2DB(l2DB.DB())
|
||||||
txs := test.GenPoolTxs(nInserts)
|
txs := test.GenPoolTxs(nInserts, tokens)
|
||||||
var pendingTxs []*common.PoolL2Tx
|
var pendingTxs []*common.PoolL2Tx
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
err := l2DB.AddTx(tx)
|
err := l2DB.AddTxTest(tx)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if tx.State == common.PoolL2TxStatePending {
|
if tx.State == common.PoolL2TxStatePending && tx.AbsoluteFee != nil {
|
||||||
pendingTxs = append(pendingTxs, tx)
|
pendingTxs = append(pendingTxs, tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,11 +112,7 @@ func TestGetPending(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, len(pendingTxs), len(fetchedTxs))
|
assert.Equal(t, len(pendingTxs), len(fetchedTxs))
|
||||||
for i, fetchedTx := range fetchedTxs {
|
for i, fetchedTx := range fetchedTxs {
|
||||||
assert.Equal(t, pendingTxs[i].Timestamp.Unix(), fetchedTx.Timestamp.Unix())
|
assertTx(t, pendingTxs[i], fetchedTx)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,12 +121,12 @@ func TestStartForging(t *testing.T) {
|
|||||||
const nInserts = 60
|
const nInserts = 60
|
||||||
const fakeBatchNum common.BatchNum = 33
|
const fakeBatchNum common.BatchNum = 33
|
||||||
test.CleanL2DB(l2DB.DB())
|
test.CleanL2DB(l2DB.DB())
|
||||||
txs := test.GenPoolTxs(nInserts)
|
txs := test.GenPoolTxs(nInserts, tokens)
|
||||||
var startForgingTxIDs []common.TxID
|
var startForgingTxIDs []common.TxID
|
||||||
randomizer := 0
|
randomizer := 0
|
||||||
// Add txs to DB
|
// Add txs to DB
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
err := l2DB.AddTx(tx)
|
err := l2DB.AddTxTest(tx)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if tx.State == common.PoolL2TxStatePending && randomizer%2 == 0 {
|
if tx.State == common.PoolL2TxStatePending && randomizer%2 == 0 {
|
||||||
randomizer++
|
randomizer++
|
||||||
@@ -123,12 +150,12 @@ func TestDoneForging(t *testing.T) {
|
|||||||
const nInserts = 60
|
const nInserts = 60
|
||||||
const fakeBatchNum common.BatchNum = 33
|
const fakeBatchNum common.BatchNum = 33
|
||||||
test.CleanL2DB(l2DB.DB())
|
test.CleanL2DB(l2DB.DB())
|
||||||
txs := test.GenPoolTxs(nInserts)
|
txs := test.GenPoolTxs(nInserts, tokens)
|
||||||
var doneForgingTxIDs []common.TxID
|
var doneForgingTxIDs []common.TxID
|
||||||
randomizer := 0
|
randomizer := 0
|
||||||
// Add txs to DB
|
// Add txs to DB
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
err := l2DB.AddTx(tx)
|
err := l2DB.AddTxTest(tx)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if tx.State == common.PoolL2TxStateForging && randomizer%2 == 0 {
|
if tx.State == common.PoolL2TxStateForging && randomizer%2 == 0 {
|
||||||
randomizer++
|
randomizer++
|
||||||
@@ -152,12 +179,12 @@ func TestInvalidate(t *testing.T) {
|
|||||||
const nInserts = 60
|
const nInserts = 60
|
||||||
const fakeBatchNum common.BatchNum = 33
|
const fakeBatchNum common.BatchNum = 33
|
||||||
test.CleanL2DB(l2DB.DB())
|
test.CleanL2DB(l2DB.DB())
|
||||||
txs := test.GenPoolTxs(nInserts)
|
txs := test.GenPoolTxs(nInserts, tokens)
|
||||||
var invalidTxIDs []common.TxID
|
var invalidTxIDs []common.TxID
|
||||||
randomizer := 0
|
randomizer := 0
|
||||||
// Add txs to DB
|
// Add txs to DB
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
err := l2DB.AddTx(tx)
|
err := l2DB.AddTxTest(tx)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if tx.State != common.PoolL2TxStateInvalid && randomizer%2 == 0 {
|
if tx.State != common.PoolL2TxStateInvalid && randomizer%2 == 0 {
|
||||||
randomizer++
|
randomizer++
|
||||||
@@ -181,7 +208,7 @@ func TestCheckNonces(t *testing.T) {
|
|||||||
const nInserts = 60
|
const nInserts = 60
|
||||||
const fakeBatchNum common.BatchNum = 33
|
const fakeBatchNum common.BatchNum = 33
|
||||||
test.CleanL2DB(l2DB.DB())
|
test.CleanL2DB(l2DB.DB())
|
||||||
txs := test.GenPoolTxs(nInserts)
|
txs := test.GenPoolTxs(nInserts, tokens)
|
||||||
var invalidTxIDs []common.TxID
|
var invalidTxIDs []common.TxID
|
||||||
// Generate accounts
|
// Generate accounts
|
||||||
const nAccoutns = 2
|
const nAccoutns = 2
|
||||||
@@ -204,7 +231,7 @@ func TestCheckNonces(t *testing.T) {
|
|||||||
txs[i].Nonce = currentNonce + 1
|
txs[i].Nonce = currentNonce + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err := l2DB.AddTx(txs[i])
|
err := l2DB.AddTxTest(txs[i])
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
// Start forging txs
|
// 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) {
|
func TestReorg(t *testing.T) {
|
||||||
// Generate txs
|
// Generate txs
|
||||||
const nInserts = 20
|
const nInserts = 20
|
||||||
const lastValidBatch common.BatchNum = 20
|
const lastValidBatch common.BatchNum = 20
|
||||||
const reorgBatch common.BatchNum = lastValidBatch + 1
|
const reorgBatch common.BatchNum = lastValidBatch + 1
|
||||||
test.CleanL2DB(l2DB.DB())
|
test.CleanL2DB(l2DB.DB())
|
||||||
txs := test.GenPoolTxs(nInserts)
|
txs := test.GenPoolTxs(nInserts, tokens)
|
||||||
// Add txs to the DB
|
// Add txs to the DB
|
||||||
reorgedTxIDs := []common.TxID{}
|
reorgedTxIDs := []common.TxID{}
|
||||||
nonReorgedTxIDs := []common.TxID{}
|
nonReorgedTxIDs := []common.TxID{}
|
||||||
@@ -293,7 +264,7 @@ func TestReorg(t *testing.T) {
|
|||||||
txs[i].BatchNum = lastValidBatch
|
txs[i].BatchNum = lastValidBatch
|
||||||
nonReorgedTxIDs = append(nonReorgedTxIDs, txs[i].TxID)
|
nonReorgedTxIDs = append(nonReorgedTxIDs, txs[i].TxID)
|
||||||
}
|
}
|
||||||
err := l2DB.AddTx(txs[i])
|
err := l2DB.AddTxTest(txs[i])
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
err := l2DB.Reorg(lastValidBatch)
|
err := l2DB.Reorg(lastValidBatch)
|
||||||
@@ -316,7 +287,7 @@ func TestPurge(t *testing.T) {
|
|||||||
// Generate txs
|
// Generate txs
|
||||||
nInserts := l2DB.maxTxs + 20
|
nInserts := l2DB.maxTxs + 20
|
||||||
test.CleanL2DB(l2DB.DB())
|
test.CleanL2DB(l2DB.DB())
|
||||||
txs := test.GenPoolTxs(int(nInserts))
|
txs := test.GenPoolTxs(int(nInserts), tokens)
|
||||||
deletedIDs := []common.TxID{}
|
deletedIDs := []common.TxID{}
|
||||||
keepedIDs := []common.TxID{}
|
keepedIDs := []common.TxID{}
|
||||||
const toDeleteBatchNum common.BatchNum = 30
|
const toDeleteBatchNum common.BatchNum = 30
|
||||||
@@ -335,14 +306,14 @@ func TestPurge(t *testing.T) {
|
|||||||
}
|
}
|
||||||
deletedIDs = append(deletedIDs, txs[i].TxID)
|
deletedIDs = append(deletedIDs, txs[i].TxID)
|
||||||
}
|
}
|
||||||
err := l2DB.AddTx(txs[i])
|
err := l2DB.AddTxTest(txs[i])
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
for i := int(l2DB.maxTxs); i < len(txs); i++ {
|
for i := int(l2DB.maxTxs); i < len(txs); i++ {
|
||||||
// Delete after TTL
|
// Delete after TTL
|
||||||
txs[i].Timestamp = time.Unix(time.Now().UTC().Unix()-int64(l2DB.ttl.Seconds()+float64(4*time.Second)), 0)
|
txs[i].Timestamp = time.Unix(time.Now().UTC().Unix()-int64(l2DB.ttl.Seconds()+float64(4*time.Second)), 0)
|
||||||
deletedIDs = append(deletedIDs, txs[i].TxID)
|
deletedIDs = append(deletedIDs, txs[i].TxID)
|
||||||
err := l2DB.AddTx(txs[i])
|
err := l2DB.AddTxTest(txs[i])
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
// Purge txs
|
// 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()
|
instructions, err := parser.Parse()
|
||||||
assert.Nil(t, err)
|
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, 29, len(l1Txs[0]))
|
||||||
assert.Equal(t, 0, len(coordinatorL1Txs[0]))
|
assert.Equal(t, 0, len(coordinatorL1Txs[0]))
|
||||||
assert.Equal(t, 21, len(poolL2Txs[0]))
|
assert.Equal(t, 21, len(poolL2Txs[0]))
|
||||||
@@ -57,7 +57,7 @@ func TestProcessTxsBatchByBatch(t *testing.T) {
|
|||||||
instructions, err := parser.Parse()
|
instructions, err := parser.Parse()
|
||||||
assert.Nil(t, err)
|
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, 29, len(l1Txs[0]))
|
||||||
assert.Equal(t, 0, len(coordinatorL1Txs[0]))
|
assert.Equal(t, 0, len(coordinatorL1Txs[0]))
|
||||||
assert.Equal(t, 21, len(poolL2Txs[0]))
|
assert.Equal(t, 21, len(poolL2Txs[0]))
|
||||||
@@ -108,7 +108,7 @@ func TestZKInputsGeneration(t *testing.T) {
|
|||||||
instructions, err := parser.Parse()
|
instructions, err := parser.Parse()
|
||||||
assert.Nil(t, err)
|
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, 29, len(l1Txs[0]))
|
||||||
assert.Equal(t, 0, len(coordinatorL1Txs[0]))
|
assert.Equal(t, 0, len(coordinatorL1Txs[0]))
|
||||||
assert.Equal(t, 21, len(poolL2Txs[0]))
|
assert.Equal(t, 21, len(poolL2Txs[0]))
|
||||||
|
|||||||
38
db/utils.go
38
db/utils.go
@@ -7,11 +7,45 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"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"
|
"github.com/russross/meddler"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InitMeddler registers tags to be used to read/write from SQL DBs using meddler
|
// InitSQLDB runs migrations and registers meddlers
|
||||||
func InitMeddler() {
|
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("bigint", BigIntMeddler{})
|
||||||
meddler.Register("bigintnull", BigIntNullMeddler{})
|
meddler.Register("bigintnull", BigIntNullMeddler{})
|
||||||
}
|
}
|
||||||
|
|||||||
26
node/node.go
26
node/node.go
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/hermeznetwork/hermez-node/batchbuilder"
|
"github.com/hermeznetwork/hermez-node/batchbuilder"
|
||||||
"github.com/hermeznetwork/hermez-node/config"
|
"github.com/hermeznetwork/hermez-node/config"
|
||||||
"github.com/hermeznetwork/hermez-node/coordinator"
|
"github.com/hermeznetwork/hermez-node/coordinator"
|
||||||
|
dbUtils "github.com/hermeznetwork/hermez-node/db"
|
||||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||||
"github.com/hermeznetwork/hermez-node/db/l2db"
|
"github.com/hermeznetwork/hermez-node/db/l2db"
|
||||||
"github.com/hermeznetwork/hermez-node/db/statedb"
|
"github.com/hermeznetwork/hermez-node/db/statedb"
|
||||||
@@ -14,6 +15,7 @@ import (
|
|||||||
"github.com/hermeznetwork/hermez-node/log"
|
"github.com/hermeznetwork/hermez-node/log"
|
||||||
"github.com/hermeznetwork/hermez-node/synchronizer"
|
"github.com/hermeznetwork/hermez-node/synchronizer"
|
||||||
"github.com/hermeznetwork/hermez-node/txselector"
|
"github.com/hermeznetwork/hermez-node/txselector"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Mode sets the working mode of the node (synchronizer or coordinator)
|
// Mode sets the working mode of the node (synchronizer or coordinator)
|
||||||
@@ -49,23 +51,27 @@ type Node struct {
|
|||||||
stoppedSync chan bool
|
stoppedSync chan bool
|
||||||
|
|
||||||
// General
|
// General
|
||||||
cfg *config.Node
|
cfg *config.Node
|
||||||
mode Mode
|
mode Mode
|
||||||
|
sqlConn *sqlx.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNode creates a Node
|
// NewNode creates a Node
|
||||||
func NewNode(mode Mode, cfg *config.Node, coordCfg *config.Coordinator) (*Node, error) {
|
func NewNode(mode Mode, cfg *config.Node, coordCfg *config.Coordinator) (*Node, error) {
|
||||||
historyDB, err := historydb.NewHistoryDB(
|
// Stablish DB connection
|
||||||
|
db, err := dbUtils.InitSQLDB(
|
||||||
cfg.PostgreSQL.Port,
|
cfg.PostgreSQL.Port,
|
||||||
cfg.PostgreSQL.Host,
|
cfg.PostgreSQL.Host,
|
||||||
cfg.PostgreSQL.User,
|
cfg.PostgreSQL.User,
|
||||||
cfg.PostgreSQL.Password,
|
cfg.PostgreSQL.Password,
|
||||||
cfg.HistoryDB.Name,
|
cfg.PostgreSQL.Name,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
historyDB := historydb.NewHistoryDB(db)
|
||||||
|
|
||||||
stateDB, err := statedb.NewStateDB(cfg.StateDB.Path, true, 32)
|
stateDB, err := statedb.NewStateDB(cfg.StateDB.Path, true, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -81,19 +87,12 @@ func NewNode(mode Mode, cfg *config.Node, coordCfg *config.Coordinator) (*Node,
|
|||||||
|
|
||||||
var coord *coordinator.Coordinator
|
var coord *coordinator.Coordinator
|
||||||
if mode == ModeCoordinator {
|
if mode == ModeCoordinator {
|
||||||
l2DB, err := l2db.NewL2DB(
|
l2DB := l2db.NewL2DB(
|
||||||
cfg.PostgreSQL.Port,
|
db,
|
||||||
cfg.PostgreSQL.Host,
|
|
||||||
cfg.PostgreSQL.User,
|
|
||||||
cfg.PostgreSQL.Password,
|
|
||||||
coordCfg.L2DB.Name,
|
|
||||||
coordCfg.L2DB.SafetyPeriod,
|
coordCfg.L2DB.SafetyPeriod,
|
||||||
coordCfg.L2DB.MaxTxs,
|
coordCfg.L2DB.MaxTxs,
|
||||||
coordCfg.L2DB.TTL.Duration,
|
coordCfg.L2DB.TTL.Duration,
|
||||||
)
|
)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// TODO: Get (maxL1UserTxs, maxL1OperatorTxs, maxTxs) from the smart contract
|
// TODO: Get (maxL1UserTxs, maxL1OperatorTxs, maxTxs) from the smart contract
|
||||||
txSelector, err := txselector.NewTxSelector(coordCfg.TxSelector.Path, stateDB, l2DB, 10, 10, 10)
|
txSelector, err := txselector.NewTxSelector(coordCfg.TxSelector.Path, stateDB, l2DB, 10, 10, 10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -129,6 +128,7 @@ func NewNode(mode Mode, cfg *config.Node, coordCfg *config.Coordinator) (*Node,
|
|||||||
sync: sync,
|
sync: sync,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
mode: mode,
|
mode: mode,
|
||||||
|
sqlConn: db,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -397,7 +397,9 @@ func (s *Synchronizer) rollupSync(blockNum int64) (*rollupData, error) {
|
|||||||
l1CoordinatorTx.TxID = common.TxID(common.Hash([]byte("0x01" + strconv.FormatInt(int64(nextForgeL1TxsNum), 10) + strconv.FormatInt(int64(l1CoordinatorTx.Position), 10) + "00")))
|
l1CoordinatorTx.TxID = common.TxID(common.Hash([]byte("0x01" + strconv.FormatInt(int64(nextForgeL1TxsNum), 10) + strconv.FormatInt(int64(l1CoordinatorTx.Position), 10) + "00")))
|
||||||
l1CoordinatorTx.UserOrigin = false
|
l1CoordinatorTx.UserOrigin = false
|
||||||
l1CoordinatorTx.EthBlockNum = blockNum
|
l1CoordinatorTx.EthBlockNum = blockNum
|
||||||
l1CoordinatorTx.BatchNum = common.BatchNum(fbEvent.BatchNum)
|
bn := new(common.BatchNum)
|
||||||
|
*bn = common.BatchNum(fbEvent.BatchNum)
|
||||||
|
l1CoordinatorTx.BatchNum = bn
|
||||||
|
|
||||||
batchData.l1CoordinatorTxs = append(batchData.l1CoordinatorTxs, l1CoordinatorTx)
|
batchData.l1CoordinatorTxs = append(batchData.l1CoordinatorTxs, l1CoordinatorTx)
|
||||||
|
|
||||||
@@ -571,7 +573,6 @@ func getL1UserTx(l1UserTxEvents []eth.RollupEventL1UserTx, blockNum int64) []*co
|
|||||||
eL1UserTx.L1Tx.Position = eL1UserTx.Position
|
eL1UserTx.L1Tx.Position = eL1UserTx.Position
|
||||||
eL1UserTx.L1Tx.UserOrigin = true
|
eL1UserTx.L1Tx.UserOrigin = true
|
||||||
eL1UserTx.L1Tx.EthBlockNum = blockNum
|
eL1UserTx.L1Tx.EthBlockNum = blockNum
|
||||||
eL1UserTx.L1Tx.BatchNum = 0
|
|
||||||
|
|
||||||
l1Txs = append(l1Txs, &eL1UserTx.L1Tx)
|
l1Txs = append(l1Txs, &eL1UserTx.L1Tx)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package synchronizer
|
package synchronizer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
|
dbUtils "github.com/hermeznetwork/hermez-node/db"
|
||||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||||
"github.com/hermeznetwork/hermez-node/db/statedb"
|
"github.com/hermeznetwork/hermez-node/db/statedb"
|
||||||
"github.com/hermeznetwork/hermez-node/eth"
|
"github.com/hermeznetwork/hermez-node/eth"
|
||||||
@@ -24,8 +24,9 @@ func Test(t *testing.T) {
|
|||||||
|
|
||||||
// Init History DB
|
// Init History DB
|
||||||
pass := os.Getenv("POSTGRES_PASS")
|
pass := os.Getenv("POSTGRES_PASS")
|
||||||
historyDB, err := historydb.NewHistoryDB(5432, "localhost", "hermez", pass, "history")
|
db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
historyDB := historydb.NewHistoryDB(db)
|
||||||
err = historyDB.Reorg(0)
|
err = historyDB.Reorg(0)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -65,9 +66,4 @@ func Test(t *testing.T) {
|
|||||||
err = s.Sync()
|
err = s.Sync()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Close History DB
|
|
||||||
if err := historyDB.Close(); err != nil {
|
|
||||||
fmt.Println("Error closing the history DB:", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
23
test/dbUtils.go
Normal file
23
test/dbUtils.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AssertUSD asserts pointers to float64, and checks that they are equal
|
||||||
|
// with a tolerance of 0.01%. After that, the actual value is setted to the expected value
|
||||||
|
// in order to be able to perform further assertions using the standar assert functions.
|
||||||
|
func AssertUSD(t *testing.T, expected, actual *float64) {
|
||||||
|
if actual == nil {
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if *expected < *actual {
|
||||||
|
assert.InEpsilon(t, *actual, *expected, 0.0001)
|
||||||
|
} else if *expected > *actual {
|
||||||
|
assert.InEpsilon(t, *expected, *actual, 0.0001)
|
||||||
|
}
|
||||||
|
*expected = *actual
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package test
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@@ -43,8 +44,10 @@ func GenTokens(nTokens int, blocks []common.Block) []common.Token {
|
|||||||
EthAddr: ethCommon.BigToAddress(big.NewInt(int64(i))),
|
EthAddr: ethCommon.BigToAddress(big.NewInt(int64(i))),
|
||||||
}
|
}
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
token.USD = 3
|
usd := 3.0
|
||||||
token.USDUpdate = time.Now()
|
token.USD = &usd
|
||||||
|
now := time.Now()
|
||||||
|
token.USDUpdate = &now
|
||||||
}
|
}
|
||||||
tokens = append(tokens, token)
|
tokens = append(tokens, token)
|
||||||
}
|
}
|
||||||
@@ -122,72 +125,118 @@ func GenL1Txs(
|
|||||||
}
|
}
|
||||||
userTxs := []common.L1Tx{}
|
userTxs := []common.L1Tx{}
|
||||||
othersTxs := []common.L1Tx{}
|
othersTxs := []common.L1Tx{}
|
||||||
|
_, nextTxsNum := GetNextToForgeNumAndBatch(batches)
|
||||||
for i := 0; i < totalTxs; i++ {
|
for i := 0; i < totalTxs; i++ {
|
||||||
var tx common.L1Tx
|
token := tokens[i%len(tokens)]
|
||||||
if batches[i%len(batches)].ForgeL1TxsNum != 0 {
|
var usd *float64
|
||||||
tx = common.L1Tx{
|
var lUSD *float64
|
||||||
TxID: common.TxID(common.Hash([]byte("L1_" + strconv.Itoa(fromIdx+i)))),
|
amount := big.NewInt(int64(i + 1))
|
||||||
ToForgeL1TxsNum: batches[i%len(batches)].ForgeL1TxsNum,
|
if token.USD != nil {
|
||||||
Position: i,
|
//nolint:gomnd
|
||||||
UserOrigin: i%2 == 0,
|
noDecimalsUSD := *token.USD / math.Pow(10, float64(token.Decimals))
|
||||||
TokenID: tokens[i%len(tokens)].TokenID,
|
f := new(big.Float).SetInt(amount)
|
||||||
Amount: big.NewInt(int64(i + 1)),
|
af, _ := f.Float64()
|
||||||
LoadAmount: big.NewInt(int64(i + 1)),
|
usd = new(float64)
|
||||||
EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
|
*usd = noDecimalsUSD * af
|
||||||
Type: randomTxType(i),
|
lUSD = new(float64)
|
||||||
}
|
*lUSD = noDecimalsUSD * af
|
||||||
if i%4 == 0 {
|
|
||||||
tx.BatchNum = batches[i%len(batches)].BatchNum
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
if i < nUserTxs {
|
tx := common.L1Tx{
|
||||||
var from, to *common.Account
|
TxID: common.TxID(common.Hash([]byte("L1_" + strconv.Itoa(fromIdx+i)))),
|
||||||
var err error
|
Position: i,
|
||||||
if i%2 == 0 {
|
UserOrigin: i%2 == 0,
|
||||||
from, err = randomAccount(i, true, userAddr, accounts)
|
TokenID: token.TokenID,
|
||||||
if err != nil {
|
Amount: amount,
|
||||||
panic(err)
|
USD: usd,
|
||||||
}
|
LoadAmount: amount,
|
||||||
to, err = randomAccount(i, false, userAddr, accounts)
|
LoadAmountUSD: lUSD,
|
||||||
if err != nil {
|
EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
|
||||||
panic(err)
|
Type: randomTxType(i),
|
||||||
}
|
}
|
||||||
} else {
|
if batches[i%len(batches)].ForgeL1TxsNum != 0 {
|
||||||
from, err = randomAccount(i, false, userAddr, accounts)
|
// Add already forged txs
|
||||||
if err != nil {
|
tx.BatchNum = &batches[i%len(batches)].BatchNum
|
||||||
panic(err)
|
setFromToAndAppend(tx, i, nUserTxs, userAddr, accounts, &userTxs, &othersTxs)
|
||||||
}
|
|
||||||
to, err = randomAccount(i, true, userAddr, accounts)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tx.FromIdx = from.Idx
|
|
||||||
tx.FromEthAddr = from.EthAddr
|
|
||||||
tx.FromBJJ = from.PublicKey
|
|
||||||
tx.ToIdx = to.Idx
|
|
||||||
userTxs = append(userTxs, tx)
|
|
||||||
} else {
|
} else {
|
||||||
from, err := randomAccount(i, false, userAddr, accounts)
|
// Add unforged txs
|
||||||
if err != nil {
|
tx.ToForgeL1TxsNum = nextTxsNum
|
||||||
panic(err)
|
tx.UserOrigin = true
|
||||||
}
|
setFromToAndAppend(tx, i, nUserTxs, userAddr, accounts, &userTxs, &othersTxs)
|
||||||
to, err := randomAccount(i, false, userAddr, accounts)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
tx.FromIdx = from.Idx
|
|
||||||
tx.FromEthAddr = from.EthAddr
|
|
||||||
tx.FromBJJ = from.PublicKey
|
|
||||||
tx.ToIdx = to.Idx
|
|
||||||
othersTxs = append(othersTxs, tx)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return userTxs, othersTxs
|
return userTxs, othersTxs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNextToForgeNumAndBatch returns the next BatchNum and ForgeL1TxsNum to be added
|
||||||
|
func GetNextToForgeNumAndBatch(batches []common.Batch) (common.BatchNum, int64) {
|
||||||
|
batchNum := batches[len(batches)-1].BatchNum + 1
|
||||||
|
var toForgeL1TxsNum int64
|
||||||
|
found := false
|
||||||
|
for i := len(batches) - 1; i >= 0; i-- {
|
||||||
|
if batches[i].ForgeL1TxsNum != 0 {
|
||||||
|
toForgeL1TxsNum = batches[i].ForgeL1TxsNum + 1
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
panic("toForgeL1TxsNum not found")
|
||||||
|
}
|
||||||
|
return batchNum, toForgeL1TxsNum
|
||||||
|
}
|
||||||
|
|
||||||
|
func setFromToAndAppend(
|
||||||
|
tx common.L1Tx,
|
||||||
|
i, nUserTxs int,
|
||||||
|
userAddr *ethCommon.Address,
|
||||||
|
accounts []common.Account,
|
||||||
|
userTxs *[]common.L1Tx,
|
||||||
|
othersTxs *[]common.L1Tx,
|
||||||
|
) {
|
||||||
|
if i < nUserTxs {
|
||||||
|
var from, to *common.Account
|
||||||
|
var err error
|
||||||
|
if i%2 == 0 {
|
||||||
|
from, err = randomAccount(i, true, userAddr, accounts)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
to, err = randomAccount(i, false, userAddr, accounts)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
from, err = randomAccount(i, false, userAddr, accounts)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
to, err = randomAccount(i, true, userAddr, accounts)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tx.FromIdx = from.Idx
|
||||||
|
tx.FromEthAddr = from.EthAddr
|
||||||
|
tx.FromBJJ = from.PublicKey
|
||||||
|
tx.ToIdx = to.Idx
|
||||||
|
*userTxs = append(*userTxs, tx)
|
||||||
|
} else {
|
||||||
|
from, err := randomAccount(i, false, userAddr, accounts)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
to, err := randomAccount(i, false, userAddr, accounts)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
tx.FromIdx = from.Idx
|
||||||
|
tx.FromEthAddr = from.EthAddr
|
||||||
|
tx.FromBJJ = from.PublicKey
|
||||||
|
tx.ToIdx = to.Idx
|
||||||
|
*othersTxs = append(*othersTxs, tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GenL2Txs generates L2 txs. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
|
// GenL2Txs generates L2 txs. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
|
||||||
func GenL2Txs(
|
func GenL2Txs(
|
||||||
fromIdx int,
|
fromIdx int,
|
||||||
@@ -204,14 +253,14 @@ func GenL2Txs(
|
|||||||
userTxs := []common.L2Tx{}
|
userTxs := []common.L2Tx{}
|
||||||
othersTxs := []common.L2Tx{}
|
othersTxs := []common.L2Tx{}
|
||||||
for i := 0; i < totalTxs; i++ {
|
for i := 0; i < totalTxs; i++ {
|
||||||
|
amount := big.NewInt(int64(i + 1))
|
||||||
|
fee := common.FeeSelector(i % 256) //nolint:gomnd
|
||||||
tx := common.L2Tx{
|
tx := common.L2Tx{
|
||||||
TxID: common.TxID(common.Hash([]byte("L2_" + strconv.Itoa(fromIdx+i)))),
|
TxID: common.TxID(common.Hash([]byte("L2_" + strconv.Itoa(fromIdx+i)))),
|
||||||
BatchNum: batches[i%len(batches)].BatchNum,
|
BatchNum: batches[i%len(batches)].BatchNum,
|
||||||
Position: i,
|
Position: i,
|
||||||
//nolint:gomnd
|
Amount: amount,
|
||||||
Amount: big.NewInt(int64(i + 1)),
|
Fee: fee,
|
||||||
//nolint:gomnd
|
|
||||||
Fee: common.FeeSelector(i % 256),
|
|
||||||
Nonce: common.Nonce(i + 1),
|
Nonce: common.Nonce(i + 1),
|
||||||
EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
|
EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
|
||||||
Type: randomTxType(i),
|
Type: randomTxType(i),
|
||||||
@@ -240,7 +289,6 @@ func GenL2Txs(
|
|||||||
}
|
}
|
||||||
tx.FromIdx = from.Idx
|
tx.FromIdx = from.Idx
|
||||||
tx.ToIdx = to.Idx
|
tx.ToIdx = to.Idx
|
||||||
userTxs = append(userTxs, tx)
|
|
||||||
} else {
|
} else {
|
||||||
from, err := randomAccount(i, false, userAddr, accounts)
|
from, err := randomAccount(i, false, userAddr, accounts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -252,12 +300,55 @@ func GenL2Txs(
|
|||||||
}
|
}
|
||||||
tx.FromIdx = from.Idx
|
tx.FromIdx = from.Idx
|
||||||
tx.ToIdx = to.Idx
|
tx.ToIdx = to.Idx
|
||||||
|
}
|
||||||
|
|
||||||
|
var usd *float64
|
||||||
|
var fUSD *float64
|
||||||
|
token := GetToken(tx.FromIdx, accounts, tokens)
|
||||||
|
if token.USD != nil {
|
||||||
|
//nolint:gomnd
|
||||||
|
noDecimalsUSD := *token.USD / math.Pow(10, float64(token.Decimals))
|
||||||
|
f := new(big.Float).SetInt(amount)
|
||||||
|
af, _ := f.Float64()
|
||||||
|
usd = new(float64)
|
||||||
|
fUSD = new(float64)
|
||||||
|
*usd = noDecimalsUSD * af
|
||||||
|
*fUSD = *usd * fee.Percentage()
|
||||||
|
}
|
||||||
|
tx.USD = usd
|
||||||
|
tx.FeeUSD = fUSD
|
||||||
|
if i < nUserTxs {
|
||||||
|
userTxs = append(userTxs, tx)
|
||||||
|
} else {
|
||||||
othersTxs = append(othersTxs, tx)
|
othersTxs = append(othersTxs, tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return userTxs, othersTxs
|
return userTxs, othersTxs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetToken returns the Token associated to an Idx given a list of tokens and accounts.
|
||||||
|
// It panics when not found, intended for testing only.
|
||||||
|
func GetToken(idx common.Idx, accs []common.Account, tokens []common.Token) common.Token {
|
||||||
|
var id common.TokenID
|
||||||
|
found := false
|
||||||
|
for _, acc := range accs {
|
||||||
|
if acc.Idx == idx {
|
||||||
|
found = true
|
||||||
|
id = acc.TokenID
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
panic("tokenID not found")
|
||||||
|
}
|
||||||
|
for i := 0; i < len(tokens); i++ {
|
||||||
|
if tokens[i].TokenID == id {
|
||||||
|
return tokens[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("token not found")
|
||||||
|
}
|
||||||
|
|
||||||
// GenCoordinators generates coordinators. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
|
// GenCoordinators generates coordinators. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
|
||||||
func GenCoordinators(nCoords int, blocks []common.Block) []common.Coordinator {
|
func GenCoordinators(nCoords int, blocks []common.Block) []common.Coordinator {
|
||||||
coords := []common.Coordinator{}
|
coords := []common.Coordinator{}
|
||||||
|
|||||||
44
test/l2db.go
44
test/l2db.go
@@ -24,7 +24,7 @@ func CleanL2DB(db *sqlx.DB) {
|
|||||||
// GenPoolTxs generates L2 pool txs.
|
// GenPoolTxs generates L2 pool txs.
|
||||||
// WARNING: This tx doesn't follow the protocol (signature, txID, ...)
|
// WARNING: This tx doesn't follow the protocol (signature, txID, ...)
|
||||||
// it's just to test getting/setting from/to the DB.
|
// it's just to test getting/setting from/to the DB.
|
||||||
func GenPoolTxs(n int) []*common.PoolL2Tx {
|
func GenPoolTxs(n int, tokens []common.Token) []*common.PoolL2Tx {
|
||||||
txs := make([]*common.PoolL2Tx, 0, n)
|
txs := make([]*common.PoolL2Tx, 0, n)
|
||||||
privK := babyjub.NewRandPrivKey()
|
privK := babyjub.NewRandPrivKey()
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
@@ -44,21 +44,33 @@ func GenPoolTxs(n int) []*common.PoolL2Tx {
|
|||||||
}
|
}
|
||||||
f := new(big.Float).SetInt(big.NewInt(int64(i)))
|
f := new(big.Float).SetInt(big.NewInt(int64(i)))
|
||||||
amountF, _ := f.Float64()
|
amountF, _ := f.Float64()
|
||||||
|
var usd, absFee *float64
|
||||||
|
fee := common.FeeSelector(i % 255) //nolint:gomnd
|
||||||
|
token := tokens[i%len(tokens)]
|
||||||
|
if token.USD != nil {
|
||||||
|
usd = new(float64)
|
||||||
|
absFee = new(float64)
|
||||||
|
*usd = *token.USD * amountF
|
||||||
|
*absFee = fee.Percentage() * *usd
|
||||||
|
}
|
||||||
tx := &common.PoolL2Tx{
|
tx := &common.PoolL2Tx{
|
||||||
TxID: common.TxID(common.Hash([]byte(strconv.Itoa(i)))),
|
TxID: common.TxID(common.Hash([]byte(strconv.Itoa(i)))),
|
||||||
FromIdx: common.Idx(i),
|
FromIdx: common.Idx(i),
|
||||||
ToIdx: common.Idx(i + 1),
|
ToIdx: common.Idx(i + 1),
|
||||||
ToEthAddr: ethCommon.BigToAddress(big.NewInt(int64(i))),
|
ToEthAddr: ethCommon.BigToAddress(big.NewInt(int64(i))),
|
||||||
ToBJJ: privK.Public(),
|
ToBJJ: privK.Public(),
|
||||||
TokenID: common.TokenID(i),
|
TokenID: token.TokenID,
|
||||||
Amount: big.NewInt(int64(i)),
|
Amount: big.NewInt(int64(i)),
|
||||||
AmountFloat: amountF,
|
AmountFloat: amountF,
|
||||||
//nolint:gomnd
|
USD: usd,
|
||||||
Fee: common.FeeSelector(i % 255),
|
Fee: fee,
|
||||||
Nonce: common.Nonce(i),
|
Nonce: common.Nonce(i),
|
||||||
State: state,
|
State: state,
|
||||||
Signature: privK.SignPoseidon(big.NewInt(int64(i))),
|
Signature: privK.SignPoseidon(big.NewInt(int64(i))),
|
||||||
Timestamp: time.Now().UTC(),
|
Timestamp: time.Now().UTC(),
|
||||||
|
TokenSymbol: token.Symbol,
|
||||||
|
AbsoluteFee: absFee,
|
||||||
|
AbsoluteFeeUpdate: token.USDUpdate,
|
||||||
}
|
}
|
||||||
if i%2 == 0 { // Optional parameters: rq
|
if i%2 == 0 { // Optional parameters: rq
|
||||||
tx.RqFromIdx = common.Idx(i)
|
tx.RqFromIdx = common.Idx(i)
|
||||||
@@ -72,8 +84,6 @@ func GenPoolTxs(n int) []*common.PoolL2Tx {
|
|||||||
}
|
}
|
||||||
if i%3 == 0 { // Optional parameters: things that get updated "a posteriori"
|
if i%3 == 0 { // Optional parameters: things that get updated "a posteriori"
|
||||||
tx.BatchNum = 489
|
tx.BatchNum = 489
|
||||||
tx.AbsoluteFee = 39.12345
|
|
||||||
tx.AbsoluteFeeUpdate = time.Now().UTC()
|
|
||||||
}
|
}
|
||||||
txs = append(txs, tx)
|
txs = append(txs, tx)
|
||||||
}
|
}
|
||||||
|
|||||||
27
test/txs.go
27
test/txs.go
@@ -52,7 +52,7 @@ func GenerateKeys(t *testing.T, accNames []string) map[string]*Account {
|
|||||||
|
|
||||||
// GenerateTestTxs generates L1Tx & PoolL2Tx in a deterministic way for the
|
// GenerateTestTxs generates L1Tx & PoolL2Tx in a deterministic way for the
|
||||||
// given Instructions.
|
// given Instructions.
|
||||||
func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]*common.L1Tx, [][]*common.L1Tx, [][]*common.PoolL2Tx) {
|
func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]*common.L1Tx, [][]*common.L1Tx, [][]*common.PoolL2Tx, []common.Token) {
|
||||||
accounts := GenerateKeys(t, instructions.Accounts)
|
accounts := GenerateKeys(t, instructions.Accounts)
|
||||||
l1CreatedAccounts := make(map[string]*Account)
|
l1CreatedAccounts := make(map[string]*Account)
|
||||||
|
|
||||||
@@ -148,13 +148,32 @@ func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]*common.L1Tx,
|
|||||||
l1Txs = append(l1Txs, batchL1Txs)
|
l1Txs = append(l1Txs, batchL1Txs)
|
||||||
coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)
|
coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)
|
||||||
poolL2Txs = append(poolL2Txs, batchPoolL2Txs)
|
poolL2Txs = append(poolL2Txs, batchPoolL2Txs)
|
||||||
|
tokens := []common.Token{}
|
||||||
return l1Txs, coordinatorL1Txs, poolL2Txs
|
for i := 0; i < len(poolL2Txs); i++ {
|
||||||
|
for j := 0; j < len(poolL2Txs[i]); j++ {
|
||||||
|
id := poolL2Txs[i][j].TokenID
|
||||||
|
found := false
|
||||||
|
for k := 0; k < len(tokens); k++ {
|
||||||
|
if tokens[k].TokenID == id {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
tokens = append(tokens, common.Token{
|
||||||
|
TokenID: id,
|
||||||
|
EthBlockNum: 1,
|
||||||
|
EthAddr: ethCommon.BigToAddress(big.NewInt(int64(i*10000 + j))),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l1Txs, coordinatorL1Txs, poolL2Txs, tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateTestTxsFromSet reurns the L1 & L2 transactions for a given Set of
|
// GenerateTestTxsFromSet reurns the L1 & L2 transactions for a given Set of
|
||||||
// Instructions code
|
// Instructions code
|
||||||
func GenerateTestTxsFromSet(t *testing.T, set string) ([][]*common.L1Tx, [][]*common.L1Tx, [][]*common.PoolL2Tx) {
|
func GenerateTestTxsFromSet(t *testing.T, set string) ([][]*common.L1Tx, [][]*common.L1Tx, [][]*common.PoolL2Tx, []common.Token) {
|
||||||
parser := NewParser(strings.NewReader(set))
|
parser := NewParser(strings.NewReader(set))
|
||||||
instructions, err := parser.Parse()
|
instructions, err := parser.Parse()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func TestGenerateTestL2Txs(t *testing.T) {
|
|||||||
instructions, err := parser.Parse()
|
instructions, err := parser.Parse()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
l1txs, coordinatorL1txs, l2txs := GenerateTestTxs(t, instructions)
|
l1txs, coordinatorL1txs, l2txs, _ := GenerateTestTxs(t, instructions)
|
||||||
assert.Equal(t, 2, len(l1txs))
|
assert.Equal(t, 2, len(l1txs))
|
||||||
assert.Equal(t, 3, len(l1txs[0]))
|
assert.Equal(t, 3, len(l1txs[0]))
|
||||||
assert.Equal(t, 1, len(coordinatorL1txs[0]))
|
assert.Equal(t, 1, len(coordinatorL1txs[0]))
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ func (t txs) Swap(i, j int) {
|
|||||||
t[i], t[j] = t[j], t[i]
|
t[i], t[j] = t[j], t[i]
|
||||||
}
|
}
|
||||||
func (t txs) Less(i, j int) bool {
|
func (t txs) Less(i, j int) bool {
|
||||||
return t[i].AbsoluteFee > t[j].AbsoluteFee
|
return *t[i].AbsoluteFee > *t[j].AbsoluteFee
|
||||||
}
|
}
|
||||||
|
|
||||||
// TxSelector implements all the functionalities to select the txs for the next batch
|
// TxSelector implements all the functionalities to select the txs for the next batch
|
||||||
|
|||||||
@@ -7,17 +7,21 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hermeznetwork/hermez-node/common"
|
"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/db/l2db"
|
"github.com/hermeznetwork/hermez-node/db/l2db"
|
||||||
"github.com/hermeznetwork/hermez-node/db/statedb"
|
"github.com/hermeznetwork/hermez-node/db/statedb"
|
||||||
"github.com/hermeznetwork/hermez-node/test"
|
"github.com/hermeznetwork/hermez-node/test"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initTest(t *testing.T, testSet string) *TxSelector {
|
func initTest(t *testing.T, testSet string) *TxSelector {
|
||||||
pass := os.Getenv("POSTGRES_PASS")
|
pass := os.Getenv("POSTGRES_PASS")
|
||||||
l2DB, err := l2db.NewL2DB(5432, "localhost", "hermez", pass, "l2", 10, 512, 24*time.Hour)
|
db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
l2DB := l2db.NewL2DB(db, 10, 100, 24*time.Hour)
|
||||||
|
|
||||||
dir, err := ioutil.TempDir("", "tmpdb")
|
dir, err := ioutil.TempDir("", "tmpdb")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
@@ -33,18 +37,29 @@ func initTest(t *testing.T, testSet string) *TxSelector {
|
|||||||
}
|
}
|
||||||
func addL2Txs(t *testing.T, txsel *TxSelector, poolL2Txs []*common.PoolL2Tx) {
|
func addL2Txs(t *testing.T, txsel *TxSelector, poolL2Txs []*common.PoolL2Tx) {
|
||||||
for i := 0; i < len(poolL2Txs); i++ {
|
for i := 0; i < len(poolL2Txs); i++ {
|
||||||
err := txsel.l2db.AddTx(poolL2Txs[i])
|
err := txsel.l2db.AddTxTest(poolL2Txs[i])
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addTokens(t *testing.T, tokens []common.Token, db *sqlx.DB) {
|
||||||
|
hdb := historydb.NewHistoryDB(db)
|
||||||
|
assert.NoError(t, hdb.Reorg(-1))
|
||||||
|
assert.NoError(t, hdb.AddBlock(&common.Block{
|
||||||
|
EthBlockNum: 1,
|
||||||
|
}))
|
||||||
|
assert.NoError(t, hdb.AddTokens(tokens))
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetL2TxSelection(t *testing.T) {
|
func TestGetL2TxSelection(t *testing.T) {
|
||||||
txsel := initTest(t, test.SetTest0)
|
txsel := initTest(t, test.SetTest0)
|
||||||
test.CleanL2DB(txsel.l2db.DB())
|
test.CleanL2DB(txsel.l2db.DB())
|
||||||
|
|
||||||
// generate test transactions
|
// generate test transactions
|
||||||
l1Txs, _, poolL2Txs := test.GenerateTestTxsFromSet(t, test.SetTest0)
|
l1Txs, _, poolL2Txs, tokens := test.GenerateTestTxsFromSet(t, test.SetTest0)
|
||||||
|
|
||||||
|
// add tokens to HistoryDB to avoid breaking FK constrains
|
||||||
|
addTokens(t, tokens, txsel.l2db.DB())
|
||||||
// add the first batch of transactions to the TxSelector
|
// add the first batch of transactions to the TxSelector
|
||||||
addL2Txs(t, txsel, poolL2Txs[0])
|
addL2Txs(t, txsel, poolL2Txs[0])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user