mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 03:16:45 +01:00
Refactor api txs
This commit is contained in:
@@ -651,15 +651,16 @@ func (hdb *HistoryDB) addTxs(d meddler.DB, txs []txWrite) error {
|
||||
// }
|
||||
|
||||
// GetHistoryTx returns a tx from the DB given a TxID
|
||||
func (hdb *HistoryDB) GetHistoryTx(txID common.TxID) (*HistoryTx, error) {
|
||||
tx := &HistoryTx{}
|
||||
func (hdb *HistoryDB) GetHistoryTx(txID common.TxID) (*TxAPI, error) {
|
||||
tx := &TxAPI{}
|
||||
err := meddler.QueryRow(
|
||||
hdb.db, tx, `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position,
|
||||
tx.from_idx, tx.to_idx, tx.amount, tx.token_id, tx.amount_usd,
|
||||
hez_idx(tx.from_idx, token.symbol) AS from_idx, tx.from_eth_addr, tx.from_bjj,
|
||||
hez_idx(tx.to_idx, token.symbol) AS to_idx, tx.to_eth_addr, tx.to_bjj,
|
||||
tx.amount, tx.token_id, tx.amount_usd,
|
||||
tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin,
|
||||
tx.from_eth_addr, tx.from_bjj, tx.load_amount,
|
||||
tx.load_amount_usd, tx.fee, tx.fee_usd, tx.nonce,
|
||||
token.token_id, token.eth_block_num AS token_block,
|
||||
tx.load_amount, tx.load_amount_usd, tx.fee, tx.fee_usd, tx.nonce,
|
||||
token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
|
||||
token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
|
||||
token.usd_update, block.timestamp
|
||||
FROM tx INNER JOIN token ON tx.token_id = token.token_id
|
||||
@@ -675,18 +676,19 @@ func (hdb *HistoryDB) GetHistoryTxs(
|
||||
ethAddr *ethCommon.Address, bjj *babyjub.PublicKey,
|
||||
tokenID *common.TokenID, idx *common.Idx, batchNum *uint, txType *common.TxType,
|
||||
fromItem, limit *uint, order string,
|
||||
) ([]HistoryTx, *db.Pagination, error) {
|
||||
) ([]TxAPI, *db.Pagination, error) {
|
||||
if ethAddr != nil && bjj != nil {
|
||||
return nil, nil, errors.New("ethAddr and bjj are incompatible")
|
||||
}
|
||||
var query string
|
||||
var args []interface{}
|
||||
queryStr := `SELECT tx.item_id, tx.is_l1, tx.id, tx.type, tx.position,
|
||||
tx.from_idx, tx.to_idx, tx.amount, tx.token_id, tx.amount_usd,
|
||||
hez_idx(tx.from_idx, token.symbol) AS from_idx, tx.from_eth_addr, tx.from_bjj,
|
||||
hez_idx(tx.to_idx, token.symbol) AS to_idx, tx.to_eth_addr, tx.to_bjj,
|
||||
tx.amount, tx.token_id, tx.amount_usd,
|
||||
tx.batch_num, tx.eth_block_num, tx.to_forge_l1_txs_num, tx.user_origin,
|
||||
tx.from_eth_addr, tx.from_bjj, tx.load_amount,
|
||||
tx.load_amount_usd, tx.fee, tx.fee_usd, tx.nonce,
|
||||
token.token_id, token.eth_block_num AS token_block,
|
||||
tx.load_amount, tx.load_amount_usd, tx.fee, tx.fee_usd, tx.nonce,
|
||||
token.token_id, token.item_id AS token_item_id, token.eth_block_num AS token_block,
|
||||
token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
|
||||
token.usd_update, block.timestamp, count(*) OVER() AS total_items,
|
||||
MIN(tx.item_id) OVER() AS first_item, MAX(tx.item_id) OVER() AS last_item
|
||||
@@ -783,11 +785,11 @@ func (hdb *HistoryDB) GetHistoryTxs(
|
||||
queryStr += fmt.Sprintf("LIMIT %d;", *limit)
|
||||
query = hdb.db.Rebind(queryStr)
|
||||
log.Debug(query)
|
||||
txsPtrs := []*HistoryTx{}
|
||||
txsPtrs := []*TxAPI{}
|
||||
if err := meddler.QueryAll(hdb.db, &txsPtrs, query, args...); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
txs := db.SlicePtrsToSlice(txsPtrs).([]HistoryTx)
|
||||
txs := db.SlicePtrsToSlice(txsPtrs).([]TxAPI)
|
||||
if len(txs) == 0 {
|
||||
return nil, nil, sql.ErrNoRows
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package historydb
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
@@ -11,29 +12,30 @@ import (
|
||||
"github.com/iden3/go-merkletree"
|
||||
)
|
||||
|
||||
// HistoryTx is a representation of a generic Tx with additional information
|
||||
// TxAPI is a representation of a generic Tx with additional information
|
||||
// required by the API, and extracted by joining block and token tables
|
||||
type HistoryTx struct {
|
||||
type TxAPI struct {
|
||||
// Generic
|
||||
IsL1 bool `meddler:"is_l1"`
|
||||
TxID common.TxID `meddler:"id"`
|
||||
ItemID int `meddler:"item_id"`
|
||||
Type common.TxType `meddler:"type"`
|
||||
Position int `meddler:"position"`
|
||||
FromIdx *common.Idx `meddler:"from_idx"`
|
||||
ToIdx common.Idx `meddler:"to_idx"`
|
||||
Amount *big.Int `meddler:"amount,bigint"`
|
||||
HistoricUSD *float64 `meddler:"amount_usd"`
|
||||
BatchNum *common.BatchNum `meddler:"batch_num"` // batchNum in which this tx was forged. If the tx is L2, this must be != 0
|
||||
EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
|
||||
IsL1 bool `meddler:"is_l1"`
|
||||
TxID common.TxID `meddler:"id"`
|
||||
ItemID int `meddler:"item_id"`
|
||||
Type common.TxType `meddler:"type"`
|
||||
Position int `meddler:"position"`
|
||||
FromIdx *apitypes.HezIdx `meddler:"from_idx"`
|
||||
FromEthAddr *apitypes.HezEthAddr `meddler:"from_eth_addr"`
|
||||
FromBJJ *apitypes.HezBJJ `meddler:"from_bjj"`
|
||||
ToIdx apitypes.HezIdx `meddler:"to_idx"`
|
||||
ToEthAddr *apitypes.HezEthAddr `meddler:"to_eth_addr"`
|
||||
ToBJJ *apitypes.HezBJJ `meddler:"to_bjj"`
|
||||
Amount apitypes.BigIntStr `meddler:"amount"`
|
||||
HistoricUSD *float64 `meddler:"amount_usd"`
|
||||
BatchNum *common.BatchNum `meddler:"batch_num"` // batchNum in which this tx was forged. If the tx is L2, this must be != 0
|
||||
EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
|
||||
// L1
|
||||
ToForgeL1TxsNum *int64 `meddler:"to_forge_l1_txs_num"` // toForgeL1TxsNum in which the tx was forged / will be forged
|
||||
UserOrigin *bool `meddler:"user_origin"` // true if the tx was originated by a user, false if it was aoriginated by a coordinator. Note that this differ from the spec for implementation simplification purpposes
|
||||
FromEthAddr *ethCommon.Address `meddler:"from_eth_addr"`
|
||||
FromBJJ *babyjub.PublicKey `meddler:"from_bjj"`
|
||||
LoadAmount *big.Int `meddler:"load_amount,bigintnull"`
|
||||
// LoadAmountFloat *float64 `meddler:"load_amount_f"`
|
||||
HistoricLoadAmountUSD *float64 `meddler:"load_amount_usd"`
|
||||
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
|
||||
LoadAmount *apitypes.BigIntStr `meddler:"load_amount"`
|
||||
HistoricLoadAmountUSD *float64 `meddler:"load_amount_usd"`
|
||||
// L2
|
||||
Fee *common.FeeSelector `meddler:"fee"`
|
||||
HistoricFeeUSD *float64 `meddler:"fee_usd"`
|
||||
@@ -44,6 +46,7 @@ type HistoryTx struct {
|
||||
FirstItem int `meddler:"first_item"`
|
||||
LastItem int `meddler:"last_item"`
|
||||
TokenID common.TokenID `meddler:"token_id"`
|
||||
TokenItemID int `meddler:"token_item_id"`
|
||||
TokenEthBlockNum int64 `meddler:"token_block"`
|
||||
TokenEthAddr ethCommon.Address `meddler:"eth_addr"`
|
||||
TokenName string `meddler:"name"`
|
||||
@@ -53,6 +56,58 @@ type HistoryTx struct {
|
||||
TokenUSDUpdate *time.Time `meddler:"usd_update"`
|
||||
}
|
||||
|
||||
// MarshalJSON is used to neast some of the fields of TxAPI
|
||||
// without the need of auxiliar structs
|
||||
func (tx TxAPI) MarshalJSON() ([]byte, error) {
|
||||
jsonTx := map[string]interface{}{
|
||||
"id": tx.TxID,
|
||||
"itemId": tx.ItemID,
|
||||
"type": tx.Type,
|
||||
"position": tx.Position,
|
||||
"fromAccountIndex": tx.FromIdx,
|
||||
"fromHezEthereumAddress": tx.FromEthAddr,
|
||||
"fromBJJ": tx.FromBJJ,
|
||||
"toAccountIndex": tx.ToIdx,
|
||||
"toHezEthereumAddress": tx.ToEthAddr,
|
||||
"toBJJ": tx.ToBJJ,
|
||||
"amount": tx.Amount,
|
||||
"batchNum": tx.BatchNum,
|
||||
"historicUSD": tx.HistoricUSD,
|
||||
"timestamp": tx.Timestamp,
|
||||
"L1Info": nil,
|
||||
"L2Info": nil,
|
||||
"token": map[string]interface{}{
|
||||
"id": tx.TokenID,
|
||||
"itemId": tx.TokenItemID,
|
||||
"ethereumBlockNum": tx.TokenEthBlockNum,
|
||||
"ethereumAddress": tx.TokenEthAddr,
|
||||
"name": tx.TokenName,
|
||||
"symbol": tx.TokenSymbol,
|
||||
"decimals": tx.TokenDecimals,
|
||||
"USD": tx.TokenUSD,
|
||||
"fiatUpdate": tx.TokenUSDUpdate,
|
||||
},
|
||||
}
|
||||
if tx.IsL1 {
|
||||
jsonTx["L1orL2"] = "L1"
|
||||
jsonTx["L1Info"] = map[string]interface{}{
|
||||
"toForgeL1TransactionsNum": tx.ToForgeL1TxsNum,
|
||||
"userOrigin": tx.UserOrigin,
|
||||
"loadAmount": tx.LoadAmount,
|
||||
"historicLoadAmountUSD": tx.HistoricLoadAmountUSD,
|
||||
"ethereumBlockNum": tx.EthBlockNum,
|
||||
}
|
||||
} else {
|
||||
jsonTx["L1orL2"] = "L2"
|
||||
jsonTx["L2Info"] = map[string]interface{}{
|
||||
"fee": tx.Fee,
|
||||
"historicFeeUSD": tx.HistoricFeeUSD,
|
||||
"nonce": tx.Nonce,
|
||||
}
|
||||
}
|
||||
return json.Marshal(jsonTx)
|
||||
}
|
||||
|
||||
// txWrite is an representatiion that merges common.L1Tx and common.L2Tx
|
||||
// in order to perform inserts into tx table
|
||||
type txWrite struct {
|
||||
|
||||
@@ -114,30 +114,41 @@ func (l2db *L2DB) AddTxTest(tx *common.PoolL2Tx) error {
|
||||
return meddler.Insert(l2db.db, "tx_pool", insertTx)
|
||||
}
|
||||
|
||||
// selectPoolTxRead select part of queries to get PoolL2TxRead
|
||||
const selectPoolTxRead = `SELECT tx_pool.tx_id, tx_pool.from_idx, tx_pool.to_idx, tx_pool.to_eth_addr,
|
||||
// selectPoolTxAPI select part of queries to get PoolL2TxRead
|
||||
const selectPoolTxAPI = `SELECT tx_pool.tx_id, hez_idx(tx_pool.from_idx, token.symbol) AS from_idx, tx_pool.from_eth_addr,
|
||||
tx_pool.from_bjj, hez_idx(tx_pool.to_idx, token.symbol) AS to_idx, tx_pool.to_eth_addr,
|
||||
tx_pool.to_bjj, tx_pool.token_id, tx_pool.amount, tx_pool.fee, tx_pool.nonce,
|
||||
tx_pool.state, tx_pool.signature, tx_pool.timestamp, tx_pool.batch_num, tx_pool.rq_from_idx,
|
||||
tx_pool.rq_to_idx, tx_pool.rq_to_eth_addr, tx_pool.rq_to_bjj, tx_pool.rq_token_id, tx_pool.rq_amount,
|
||||
tx_pool.state, tx_pool.signature, tx_pool.timestamp, tx_pool.batch_num, hez_idx(tx_pool.rq_from_idx, token.symbol) AS rq_from_idx,
|
||||
hez_idx(tx_pool.rq_to_idx, token.symbol) AS rq_to_idx, tx_pool.rq_to_eth_addr, tx_pool.rq_to_bjj, tx_pool.rq_token_id, tx_pool.rq_amount,
|
||||
tx_pool.rq_fee, tx_pool.rq_nonce, tx_pool.tx_type,
|
||||
token.eth_block_num, token.eth_addr, token.name, token.symbol, token.decimals, token.usd, token.usd_update
|
||||
token.item_id AS token_item_id, token.eth_block_num, token.eth_addr, token.name, token.symbol, token.decimals, token.usd, token.usd_update
|
||||
FROM tx_pool INNER JOIN token ON tx_pool.token_id = token.token_id `
|
||||
|
||||
// selectPoolTxCommon select part of queries to get common.PoolL2Tx
|
||||
const selectPoolTxCommon = `SELECT tx_pool.tx_id, tx_pool.from_idx, tx_pool.to_idx, tx_pool.to_eth_addr,
|
||||
const selectPoolTxCommon = `SELECT tx_pool.tx_id, from_idx, to_idx, tx_pool.to_eth_addr,
|
||||
tx_pool.to_bjj, tx_pool.token_id, tx_pool.amount, tx_pool.fee, tx_pool.nonce,
|
||||
tx_pool.state, tx_pool.signature, tx_pool.timestamp, tx_pool.rq_from_idx,
|
||||
tx_pool.rq_to_idx, tx_pool.rq_to_eth_addr, tx_pool.rq_to_bjj, tx_pool.rq_token_id, tx_pool.rq_amount,
|
||||
tx_pool.state, tx_pool.signature, tx_pool.timestamp, rq_from_idx,
|
||||
rq_to_idx, tx_pool.rq_to_eth_addr, tx_pool.rq_to_bjj, tx_pool.rq_token_id, tx_pool.rq_amount,
|
||||
tx_pool.rq_fee, tx_pool.rq_nonce, tx_pool.tx_type,
|
||||
fee_percentage(tx_pool.fee::NUMERIC) * token.usd * tx_pool.amount_f AS fee_usd, token.usd_update
|
||||
FROM tx_pool INNER JOIN token ON tx_pool.token_id = token.token_id `
|
||||
|
||||
// GetTx return the specified Tx
|
||||
func (l2db *L2DB) GetTx(txID common.TxID) (*PoolL2TxRead, error) {
|
||||
tx := new(PoolL2TxRead)
|
||||
// GetTx return the specified Tx in common.PoolL2Tx format
|
||||
func (l2db *L2DB) GetTx(txID common.TxID) (*common.PoolL2Tx, error) {
|
||||
tx := new(common.PoolL2Tx)
|
||||
return tx, meddler.QueryRow(
|
||||
l2db.db, tx,
|
||||
selectPoolTxRead+"WHERE tx_id = $1;",
|
||||
selectPoolTxCommon+"WHERE tx_id = $1;",
|
||||
txID,
|
||||
)
|
||||
}
|
||||
|
||||
// GetTxAPI return the specified Tx in PoolTxAPI format
|
||||
func (l2db *L2DB) GetTxAPI(txID common.TxID) (*PoolTxAPI, error) {
|
||||
tx := new(PoolTxAPI)
|
||||
return tx, meddler.QueryRow(
|
||||
l2db.db, tx,
|
||||
selectPoolTxAPI+"WHERE tx_id = $1;",
|
||||
txID,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
dbUtils "github.com/hermeznetwork/hermez-node/db"
|
||||
"github.com/hermeznetwork/hermez-node/db/historydb"
|
||||
@@ -94,81 +93,11 @@ func TestAddTxTest(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
fetchedTx, err := l2DB.GetTx(tx.TxID)
|
||||
assert.NoError(t, err)
|
||||
assertReadTx(t, commonToRead(tx, tokens), fetchedTx)
|
||||
// assertReadTx(t, commonToRead(tx, tokens), fetchedTx)
|
||||
assertTx(t, tx, fetchedTx)
|
||||
}
|
||||
}
|
||||
|
||||
func commonToRead(commonTx *common.PoolL2Tx, tokens []common.Token) *PoolL2TxRead {
|
||||
readTx := &PoolL2TxRead{
|
||||
TxID: commonTx.TxID,
|
||||
FromIdx: commonTx.FromIdx,
|
||||
ToBJJ: commonTx.ToBJJ,
|
||||
Amount: commonTx.Amount,
|
||||
Fee: commonTx.Fee,
|
||||
Nonce: commonTx.Nonce,
|
||||
State: commonTx.State,
|
||||
Signature: commonTx.Signature,
|
||||
RqToBJJ: commonTx.RqToBJJ,
|
||||
RqAmount: commonTx.RqAmount,
|
||||
Type: commonTx.Type,
|
||||
Timestamp: commonTx.Timestamp,
|
||||
TokenID: commonTx.TokenID,
|
||||
}
|
||||
// token related fields
|
||||
// find token
|
||||
token := historydb.TokenWithUSD{}
|
||||
for _, tkn := range tokensUSD {
|
||||
if tkn.TokenID == readTx.TokenID {
|
||||
token = tkn
|
||||
break
|
||||
}
|
||||
}
|
||||
// set token related fields
|
||||
readTx.TokenEthBlockNum = token.EthBlockNum
|
||||
readTx.TokenEthAddr = token.EthAddr
|
||||
readTx.TokenName = token.Name
|
||||
readTx.TokenSymbol = token.Symbol
|
||||
readTx.TokenDecimals = token.Decimals
|
||||
readTx.TokenUSD = token.USD
|
||||
readTx.TokenUSDUpdate = token.USDUpdate
|
||||
// nullable fields
|
||||
if commonTx.ToIdx != 0 {
|
||||
readTx.ToIdx = &commonTx.ToIdx
|
||||
}
|
||||
nilAddr := ethCommon.BigToAddress(big.NewInt(0))
|
||||
if commonTx.ToEthAddr != nilAddr {
|
||||
readTx.ToEthAddr = &commonTx.ToEthAddr
|
||||
}
|
||||
if commonTx.RqFromIdx != 0 {
|
||||
readTx.RqFromIdx = &commonTx.RqFromIdx
|
||||
}
|
||||
if commonTx.RqToIdx != 0 { // if true, all Rq... fields must be different to nil
|
||||
readTx.RqToIdx = &commonTx.RqToIdx
|
||||
readTx.RqTokenID = &commonTx.RqTokenID
|
||||
readTx.RqFee = &commonTx.RqFee
|
||||
readTx.RqNonce = &commonTx.RqNonce
|
||||
}
|
||||
if commonTx.RqToEthAddr != nilAddr {
|
||||
readTx.RqToEthAddr = &commonTx.RqToEthAddr
|
||||
}
|
||||
return readTx
|
||||
}
|
||||
|
||||
func assertReadTx(t *testing.T, expected, actual *PoolL2TxRead) {
|
||||
// Check that timestamp has been set within the last 3 seconds
|
||||
assert.Less(t, time.Now().UTC().Unix()-3, actual.Timestamp.Unix())
|
||||
assert.GreaterOrEqual(t, time.Now().UTC().Unix(), actual.Timestamp.Unix())
|
||||
expected.Timestamp = actual.Timestamp
|
||||
// Check token related stuff
|
||||
if expected.TokenUSDUpdate != nil {
|
||||
// Check that TokenUSDUpdate has been set within the last 3 seconds
|
||||
assert.Less(t, time.Now().UTC().Unix()-3, actual.TokenUSDUpdate.Unix())
|
||||
assert.GreaterOrEqual(t, time.Now().UTC().Unix(), actual.TokenUSDUpdate.Unix())
|
||||
expected.TokenUSDUpdate = actual.TokenUSDUpdate
|
||||
}
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func assertTx(t *testing.T, expected, actual *common.PoolL2Tx) {
|
||||
// Check that timestamp has been set within the last 3 seconds
|
||||
assert.Less(t, time.Now().UTC().Unix()-3, actual.Timestamp.Unix())
|
||||
@@ -400,13 +329,13 @@ func TestReorg(t *testing.T) {
|
||||
err := l2DB.Reorg(lastValidBatch)
|
||||
assert.NoError(t, err)
|
||||
for _, id := range reorgedTxIDs {
|
||||
tx, err := l2DB.GetTx(id)
|
||||
tx, err := l2DB.GetTxAPI(id)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, tx.BatchNum)
|
||||
assert.Equal(t, common.PoolL2TxStatePending, tx.State)
|
||||
}
|
||||
for _, id := range nonReorgedTxIDs {
|
||||
fetchedTx, err := l2DB.GetTx(id)
|
||||
fetchedTx, err := l2DB.GetTxAPI(id)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, lastValidBatch, *fetchedTx.BatchNum)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package l2db
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/hermeznetwork/hermez-node/apitypes"
|
||||
"github.com/hermeznetwork/hermez-node/common"
|
||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||
)
|
||||
@@ -34,24 +36,26 @@ type PoolL2TxWrite struct {
|
||||
Type common.TxType `meddler:"tx_type"`
|
||||
}
|
||||
|
||||
// PoolL2TxRead represents a L2 Tx pool with extra metadata used by the API
|
||||
type PoolL2TxRead struct {
|
||||
// PoolTxAPI represents a L2 Tx pool with extra metadata used by the API
|
||||
type PoolTxAPI 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"`
|
||||
Amount *big.Int `meddler:"amount,bigint"`
|
||||
FromIdx apitypes.HezIdx `meddler:"from_idx"`
|
||||
FromEthAddr *apitypes.HezEthAddr `meddler:"from_eth_addr"`
|
||||
FromBJJ *apitypes.HezBJJ `meddler:"from_bjj"`
|
||||
ToIdx *apitypes.HezIdx `meddler:"to_idx"`
|
||||
ToEthAddr *apitypes.HezEthAddr `meddler:"to_eth_addr"`
|
||||
ToBJJ *apitypes.HezBJJ `meddler:"to_bjj"`
|
||||
Amount apitypes.BigIntStr `meddler:"amount"`
|
||||
Fee common.FeeSelector `meddler:"fee"`
|
||||
Nonce common.Nonce `meddler:"nonce"`
|
||||
State common.PoolL2TxState `meddler:"state"`
|
||||
Signature babyjub.SignatureComp `meddler:"signature"`
|
||||
RqFromIdx *common.Idx `meddler:"rq_from_idx"`
|
||||
RqToIdx *common.Idx `meddler:"rq_to_idx"`
|
||||
RqToEthAddr *ethCommon.Address `meddler:"rq_to_eth_addr"`
|
||||
RqToBJJ *babyjub.PublicKey `meddler:"rq_to_bjj"`
|
||||
RqFromIdx *apitypes.HezIdx `meddler:"rq_from_idx"`
|
||||
RqToIdx *apitypes.HezIdx `meddler:"rq_to_idx"`
|
||||
RqToEthAddr *apitypes.HezEthAddr `meddler:"rq_to_eth_addr"`
|
||||
RqToBJJ *apitypes.HezBJJ `meddler:"rq_to_bjj"`
|
||||
RqTokenID *common.TokenID `meddler:"rq_token_id"`
|
||||
RqAmount *big.Int `meddler:"rq_amount,bigintnull"`
|
||||
RqAmount *apitypes.BigIntStr `meddler:"rq_amount"`
|
||||
RqFee *common.FeeSelector `meddler:"rq_fee"`
|
||||
RqNonce *common.Nonce `meddler:"rq_nonce"`
|
||||
Type common.TxType `meddler:"tx_type"`
|
||||
@@ -60,6 +64,7 @@ type PoolL2TxRead struct {
|
||||
Timestamp time.Time `meddler:"timestamp,utctime"`
|
||||
TotalItems int `meddler:"total_items"`
|
||||
TokenID common.TokenID `meddler:"token_id"`
|
||||
TokenItemID int `meddler:"token_item_id"`
|
||||
TokenEthBlockNum int64 `meddler:"eth_block_num"`
|
||||
TokenEthAddr ethCommon.Address `meddler:"eth_addr"`
|
||||
TokenName string `meddler:"name"`
|
||||
@@ -68,3 +73,44 @@ type PoolL2TxRead struct {
|
||||
TokenUSD *float64 `meddler:"usd"`
|
||||
TokenUSDUpdate *time.Time `meddler:"usd_update"`
|
||||
}
|
||||
|
||||
// MarshalJSON is used to neast some of the fields of PoolTxAPI
|
||||
// without the need of auxiliar structs
|
||||
func (tx PoolTxAPI) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(map[string]interface{}{
|
||||
"id": tx.TxID,
|
||||
"type": tx.Type,
|
||||
"fromAccountIndex": tx.FromIdx,
|
||||
"fromHezEthereumAddress": tx.FromEthAddr,
|
||||
"fromBJJ": tx.FromBJJ,
|
||||
"toAccountIndex": tx.ToIdx,
|
||||
"toHezEthereumAddress": tx.ToEthAddr,
|
||||
"toBjj": tx.ToBJJ,
|
||||
"amount": tx.Amount,
|
||||
"fee": tx.Fee,
|
||||
"nonce": tx.Nonce,
|
||||
"state": tx.State,
|
||||
"signature": tx.Signature,
|
||||
"timestamp": tx.Timestamp,
|
||||
"batchNum": tx.BatchNum,
|
||||
"requestFromAccountIndex": tx.RqFromIdx,
|
||||
"requestToAccountIndex": tx.RqToIdx,
|
||||
"requestToHezEthereumAddress": tx.RqToEthAddr,
|
||||
"requestToBJJ": tx.RqToBJJ,
|
||||
"requestTokenId": tx.RqTokenID,
|
||||
"requestAmount": tx.RqAmount,
|
||||
"requestFee": tx.RqFee,
|
||||
"requestNonce": tx.RqNonce,
|
||||
"token": map[string]interface{}{
|
||||
"id": tx.TokenID,
|
||||
"itemId": tx.TokenItemID,
|
||||
"ethereumBlockNum": tx.TokenEthBlockNum,
|
||||
"ethereumAddress": tx.TokenEthAddr,
|
||||
"name": tx.TokenName,
|
||||
"symbol": tx.TokenSymbol,
|
||||
"decimals": tx.TokenDecimals,
|
||||
"USD": tx.TokenUSD,
|
||||
"fiatUpdate": tx.TokenUSDUpdate,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -50,6 +50,22 @@ CREATE TABLE token (
|
||||
usd_update TIMESTAMP WITHOUT TIME ZONE
|
||||
);
|
||||
|
||||
|
||||
-- +migrate StatementBegin
|
||||
CREATE FUNCTION hez_idx(BIGINT, VARCHAR)
|
||||
RETURNS VARCHAR
|
||||
AS
|
||||
$BODY$
|
||||
BEGIN
|
||||
IF $1 = 1 THEN
|
||||
RETURN 'hez:EXIT:1';
|
||||
END IF;
|
||||
RETURN 'hez:' || $2 || ':' || $1;
|
||||
END;
|
||||
$BODY$
|
||||
LANGUAGE plpgsql;
|
||||
-- +migrate StatementEnd
|
||||
|
||||
CREATE TABLE account (
|
||||
idx BIGINT PRIMARY KEY,
|
||||
token_id INT NOT NULL REFERENCES token (token_id) ON DELETE CASCADE,
|
||||
@@ -96,7 +112,11 @@ CREATE TABLE tx (
|
||||
type VARCHAR(40) NOT NULL,
|
||||
position INT NOT NULL,
|
||||
from_idx BIGINT,
|
||||
from_eth_addr BYTEA,
|
||||
from_bjj BYTEA,
|
||||
to_idx BIGINT NOT NULL,
|
||||
to_eth_addr BYTEA,
|
||||
to_bjj BYTEA,
|
||||
amount BYTEA NOT NULL,
|
||||
amount_f NUMERIC NOT NULL,
|
||||
token_id INT NOT NULL REFERENCES token (token_id),
|
||||
@@ -106,8 +126,6 @@ CREATE TABLE tx (
|
||||
-- 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,
|
||||
@@ -398,28 +416,31 @@ DECLARE
|
||||
_usd_update TIMESTAMP;
|
||||
_tx_timestamp TIMESTAMP;
|
||||
BEGIN
|
||||
-- Validate L1/L2 constrains
|
||||
IF NEW.is_l1 AND (( -- L1 mandatory fields
|
||||
NEW.user_origin IS NULL OR
|
||||
IF NEW.is_l1 THEN
|
||||
-- Validate
|
||||
IF 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);
|
||||
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.';
|
||||
END IF;
|
||||
ELSE
|
||||
-- Validate
|
||||
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
|
||||
-- Set fee if it's null
|
||||
IF NEW.fee IS NULL THEN
|
||||
NEW.fee = (SELECT 0);
|
||||
END IF;
|
||||
-- Set token_id
|
||||
NEW."token_id" = (SELECT token_id FROM account WHERE idx = NEW."from_idx");
|
||||
-- Set from_{eth_addr,bjj}
|
||||
SELECT INTO NEW."from_eth_addr", NEW."from_bjj" eth_addr, bjj FROM account WHERE idx = NEW.from_idx;
|
||||
END IF;
|
||||
-- Set value_usd
|
||||
-- Set USD related
|
||||
SELECT INTO _value, _usd_update, _tx_timestamp
|
||||
usd / POWER(10, decimals), usd_update, timestamp FROM token INNER JOIN block on token.eth_block_num = block.eth_block_num WHERE token_id = NEW.token_id;
|
||||
IF _tx_timestamp - interval '24 hours' < _usd_update AND _tx_timestamp + interval '24 hours' > _usd_update THEN
|
||||
@@ -430,6 +451,10 @@ BEGIN
|
||||
NEW."load_amount_usd" = (SELECT _value * NEW.load_amount_f);
|
||||
END IF;
|
||||
END IF;
|
||||
-- Set to_{eth_addr,bjj}
|
||||
IF NEW.to_idx > 255 THEN
|
||||
SELECT INTO NEW."to_eth_addr", NEW."to_bjj" eth_addr, bjj FROM account WHERE idx = NEW.to_idx;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$BODY$
|
||||
@@ -487,6 +512,8 @@ CREATE TABLE consensus_vars (
|
||||
CREATE TABLE tx_pool (
|
||||
tx_id BYTEA PRIMARY KEY,
|
||||
from_idx BIGINT NOT NULL,
|
||||
from_eth_addr BYTEA,
|
||||
from_bjj BYTEA,
|
||||
to_idx BIGINT,
|
||||
to_eth_addr BYTEA,
|
||||
to_bjj BYTEA,
|
||||
@@ -510,6 +537,25 @@ CREATE TABLE tx_pool (
|
||||
tx_type VARCHAR(40) NOT NULL
|
||||
);
|
||||
|
||||
-- +migrate StatementBegin
|
||||
CREATE FUNCTION set_pool_tx()
|
||||
RETURNS TRIGGER
|
||||
AS
|
||||
$BODY$
|
||||
BEGIN
|
||||
SELECT INTO NEW."from_eth_addr", NEW."from_bjj" eth_addr, bjj FROM account WHERE idx = NEW."from_idx";
|
||||
-- Set to_{eth_addr,bjj}
|
||||
IF NEW.to_idx > 255 THEN
|
||||
SELECT INTO NEW."to_eth_addr", NEW."to_bjj" eth_addr, bjj FROM account WHERE idx = NEW."to_idx";
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$BODY$
|
||||
LANGUAGE plpgsql;
|
||||
-- +migrate StatementEnd
|
||||
CREATE TRIGGER trigger_set_pool_tx BEFORE INSERT ON tx_pool
|
||||
FOR EACH ROW EXECUTE PROCEDURE set_pool_tx();
|
||||
|
||||
CREATE TABLE account_creation_auth (
|
||||
eth_addr BYTEA PRIMARY KEY,
|
||||
bjj BYTEA NOT NULL,
|
||||
|
||||
Reference in New Issue
Block a user