Avoid using pointers in common

This commit is contained in:
Arnau B
2020-10-07 18:43:48 +02:00
parent 5ec18f0378
commit 5097939b12
30 changed files with 673 additions and 564 deletions

View File

@@ -4,6 +4,7 @@ import (
"database/sql"
"errors"
"fmt"
"math/big"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/hermeznetwork/hermez-node/common"
@@ -136,6 +137,7 @@ func (hdb *HistoryDB) AddBatches(batches []common.Batch) error {
return hdb.addBatches(hdb.db, batches)
}
func (hdb *HistoryDB) addBatches(d meddler.DB, batches []common.Batch) error {
// TODO: Calculate and insert total_fees_usd
return db.BulkInsert(
d,
`INSERT INTO batch (
@@ -147,8 +149,7 @@ func (hdb *HistoryDB) addBatches(d meddler.DB, batches []common.Batch) error {
num_accounts,
exit_root,
forge_l1_txs_num,
slot_num,
total_fees_usd
slot_num
) VALUES %s;`,
batches[:],
)
@@ -265,9 +266,7 @@ func (hdb *HistoryDB) addTokens(d meddler.DB, tokens []common.Token) error {
eth_addr,
name,
symbol,
decimals,
usd,
usd_update
decimals
) VALUES %s;`,
tokens[:],
)
@@ -283,13 +282,13 @@ func (hdb *HistoryDB) UpdateTokenValue(tokenSymbol string, value float64) error
}
// GetTokens returns a list of tokens from the DB
func (hdb *HistoryDB) GetTokens() ([]common.Token, error) {
var tokens []*common.Token
func (hdb *HistoryDB) GetTokens() ([]TokenRead, error) {
var tokens []*TokenRead
err := meddler.QueryAll(
hdb.db, &tokens,
"SELECT * FROM token ORDER BY token_id;",
)
return db.SlicePtrsToSlice(tokens).([]common.Token), err
return db.SlicePtrsToSlice(tokens).([]TokenRead), err
}
// GetTokenSymbols returns all the token symbols from the DB
@@ -347,26 +346,67 @@ func (hdb *HistoryDB) AddL1Txs(l1txs []common.L1Tx) error { return hdb.addL1Txs(
// If the tx is originated by a coordinator, BatchNum must be provided. If it's originated by a user,
// BatchNum should be null, and the value will be setted by a trigger when a batch forges the tx.
func (hdb *HistoryDB) addL1Txs(d meddler.DB, l1txs []common.L1Tx) error {
txs := []common.Tx{}
for _, tx := range l1txs {
txs = append(txs, *(tx.Tx()))
txs := []txWrite{}
for i := 0; i < len(l1txs); i++ {
af := new(big.Float).SetInt(l1txs[i].Amount)
amountFloat, _ := af.Float64()
laf := new(big.Float).SetInt(l1txs[i].LoadAmount)
loadAmountFloat, _ := laf.Float64()
txs = append(txs, txWrite{
// Generic
IsL1: true,
TxID: l1txs[i].TxID,
Type: l1txs[i].Type,
Position: l1txs[i].Position,
FromIdx: &l1txs[i].FromIdx,
ToIdx: l1txs[i].ToIdx,
Amount: l1txs[i].Amount,
AmountFloat: amountFloat,
TokenID: l1txs[i].TokenID,
BatchNum: l1txs[i].BatchNum,
EthBlockNum: l1txs[i].EthBlockNum,
// L1
ToForgeL1TxsNum: l1txs[i].ToForgeL1TxsNum,
UserOrigin: &l1txs[i].UserOrigin,
FromEthAddr: &l1txs[i].FromEthAddr,
FromBJJ: l1txs[i].FromBJJ,
LoadAmount: l1txs[i].LoadAmount,
LoadAmountFloat: &loadAmountFloat,
})
}
return hdb.addTxs(d, txs)
}
// AddL2Txs inserts L2 txs to the DB. USD and FeeUSD will be set automatically before storing the tx.
// AddL2Txs inserts L2 txs to the DB. TokenID, USD and FeeUSD will be set automatically before storing the tx.
func (hdb *HistoryDB) AddL2Txs(l2txs []common.L2Tx) error { return hdb.addL2Txs(hdb.db, l2txs) }
// addL2Txs inserts L2 txs to the DB. USD and FeeUSD will be set automatically before storing the tx.
// addL2Txs inserts L2 txs to the DB. TokenID, USD and FeeUSD will be set automatically before storing the tx.
func (hdb *HistoryDB) addL2Txs(d meddler.DB, l2txs []common.L2Tx) error {
txs := []common.Tx{}
for _, tx := range l2txs {
txs = append(txs, *(tx.Tx()))
txs := []txWrite{}
for i := 0; i < len(l2txs); i++ {
f := new(big.Float).SetInt(l2txs[i].Amount)
amountFloat, _ := f.Float64()
txs = append(txs, txWrite{
// Generic
IsL1: false,
TxID: l2txs[i].TxID,
Type: l2txs[i].Type,
Position: l2txs[i].Position,
FromIdx: &l2txs[i].FromIdx,
ToIdx: l2txs[i].ToIdx,
Amount: l2txs[i].Amount,
AmountFloat: amountFloat,
BatchNum: &l2txs[i].BatchNum,
EthBlockNum: l2txs[i].EthBlockNum,
// L2
Fee: &l2txs[i].Fee,
Nonce: &l2txs[i].Nonce,
})
}
return hdb.addTxs(d, txs)
}
func (hdb *HistoryDB) addTxs(d meddler.DB, txs []common.Tx) error {
func (hdb *HistoryDB) addTxs(d meddler.DB, txs []txWrite) error {
return db.BulkInsert(
d,
`INSERT INTO tx (
@@ -379,7 +419,6 @@ func (hdb *HistoryDB) addTxs(d meddler.DB, txs []common.Tx) error {
amount,
amount_f,
token_id,
amount_usd,
batch_num,
eth_block_num,
to_forge_l1_txs_num,
@@ -388,25 +427,23 @@ func (hdb *HistoryDB) addTxs(d meddler.DB, txs []common.Tx) error {
from_bjj,
load_amount,
load_amount_f,
load_amount_usd,
fee,
fee_usd,
nonce
) VALUES %s;`,
txs[:],
)
}
// GetTxs returns a list of txs from the DB
func (hdb *HistoryDB) GetTxs() ([]common.Tx, error) {
var txs []*common.Tx
err := meddler.QueryAll(
hdb.db, &txs,
`SELECT * FROM tx
ORDER BY (batch_num, position) ASC`,
)
return db.SlicePtrsToSlice(txs).([]common.Tx), err
}
// // GetTxs returns a list of txs from the DB
// func (hdb *HistoryDB) GetTxs() ([]common.Tx, error) {
// var txs []*common.Tx
// err := meddler.QueryAll(
// hdb.db, &txs,
// `SELECT * FROM tx
// ORDER BY (batch_num, position) ASC`,
// )
// return db.SlicePtrsToSlice(txs).([]common.Tx), err
// }
// GetHistoryTxs returns a list of txs from the DB using the HistoryTx struct
func (hdb *HistoryDB) GetHistoryTxs(
@@ -419,7 +456,10 @@ func (hdb *HistoryDB) GetHistoryTxs(
}
var query string
var args []interface{}
queryStr := `SELECT tx.*, token.token_id, token.eth_block_num AS token_block,
queryStr := `SELECT tx.is_l1, tx.id, tx.type, tx.position, tx.from_idx, tx.to_idx,
tx.amount, tx.token_id, 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.fee, tx.nonce,
token.token_id, token.eth_block_num AS token_block,
token.eth_addr, token.name, token.symbol, token.decimals, token.usd,
token.usd_update, block.timestamp, count(*) OVER() AS total_items
FROM tx
@@ -512,15 +552,15 @@ func (hdb *HistoryDB) GetHistoryTxs(
return txs, txs[0].TotalItems, nil
}
// GetTx returns a tx from the DB
func (hdb *HistoryDB) GetTx(txID common.TxID) (*common.Tx, error) {
tx := new(common.Tx)
return tx, meddler.QueryRow(
hdb.db, tx,
"SELECT * FROM tx WHERE id = $1;",
txID,
)
}
// // GetTx returns a tx from the DB
// func (hdb *HistoryDB) GetTx(txID common.TxID) (*common.Tx, error) {
// tx := new(common.Tx)
// return tx, meddler.QueryRow(
// hdb.db, tx,
// "SELECT * FROM tx WHERE id = $1;",
// txID,
// )
// }
// // 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.

View File

@@ -3,7 +3,6 @@ package historydb
import (
"os"
"testing"
"time"
"github.com/hermeznetwork/hermez-node/common"
dbUtils "github.com/hermeznetwork/hermez-node/db"
@@ -157,12 +156,8 @@ func TestTokens(t *testing.T) {
assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
assert.Equal(t, tokens[i].Name, token.Name)
assert.Equal(t, tokens[i].Symbol, token.Symbol)
assert.Equal(t, tokens[i].USD, token.USD)
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)
}
assert.Nil(t, token.USD)
assert.Nil(t, token.USDUpdate)
}
}
@@ -218,6 +213,7 @@ func TestTxs(t *testing.T) {
/*
Uncomment once the transaction generation is fixed
!! Missing tests to check that historic USD is not set if USDUpdate is too old (24h) !!
// Generate fake L1 txs
const nL1s = 64

View File

@@ -20,18 +20,17 @@ type HistoryTx struct {
FromIdx *common.Idx `meddler:"from_idx"`
ToIdx common.Idx `meddler:"to_idx"`
Amount *big.Int `meddler:"amount,bigint"`
AmountFloat float64 `meddler:"amount_f"`
HistoricUSD *float64 `meddler:"amount_usd"`
BatchNum *common.BatchNum `meddler:"batch_num"` // batchNum in which this tx was forged. If the tx is L2, this must be != 0
EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
// L1
ToForgeL1TxsNum *int64 `meddler:"to_forge_l1_txs_num"` // toForgeL1TxsNum in which the tx was forged / will be forged
UserOrigin *bool `meddler:"user_origin"` // true if the tx was originated by a user, false if it was aoriginated by a coordinator. Note that this differ from the spec for implementation simplification purpposes
FromEthAddr *ethCommon.Address `meddler:"from_eth_addr"`
FromBJJ *babyjub.PublicKey `meddler:"from_bjj"`
LoadAmount *big.Int `meddler:"load_amount,bigintnull"`
LoadAmountFloat *float64 `meddler:"load_amount_f"`
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
FromEthAddr *ethCommon.Address `meddler:"from_eth_addr"`
FromBJJ *babyjub.PublicKey `meddler:"from_bjj"`
LoadAmount *big.Int `meddler:"load_amount,bigintnull"`
// LoadAmountFloat *float64 `meddler:"load_amount_f"`
HistoricLoadAmountUSD *float64 `meddler:"load_amount_usd"`
// L2
Fee *common.FeeSelector `meddler:"fee"`
HistoricFeeUSD *float64 `meddler:"fee_usd"`
@@ -48,3 +47,42 @@ type HistoryTx struct {
TokenUSD *float64 `meddler:"usd"`
TokenUSDUpdate *time.Time `meddler:"usd_update"`
}
// txWrite is an representatiion that merges common.L1Tx and common.L2Tx
// in order to perform inserts into tx table
type txWrite struct {
// Generic
IsL1 bool `meddler:"is_l1"`
TxID common.TxID `meddler:"id"`
Type common.TxType `meddler:"type"`
Position int `meddler:"position"`
FromIdx *common.Idx `meddler:"from_idx"`
ToIdx common.Idx `meddler:"to_idx"`
Amount *big.Int `meddler:"amount,bigint"`
AmountFloat float64 `meddler:"amount_f"`
TokenID common.TokenID `meddler:"token_id"`
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"`
// L2
Fee *common.FeeSelector `meddler:"fee"`
Nonce *common.Nonce `meddler:"nonce"`
}
// TokenRead add USD info to common.Token
type TokenRead struct {
TokenID common.TokenID `json:"id" meddler:"token_id"`
EthBlockNum int64 `json:"ethereumBlockNum" meddler:"eth_block_num"` // Ethereum block number in which this token was registered
EthAddr ethCommon.Address `json:"ethereumAddress" meddler:"eth_addr"`
Name string `json:"name" meddler:"name"`
Symbol string `json:"symbol" meddler:"symbol"`
Decimals uint64 `json:"decimals" meddler:"decimals"`
USD *float64 `json:"USD" meddler:"usd"`
USDUpdate *time.Time `json:"fiatUpdate" meddler:"usd_update,utctime"`
}

View File

@@ -1,7 +1,6 @@
package l2db
import (
"errors"
"math/big"
"time"
@@ -9,7 +8,6 @@ import (
"github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/db"
"github.com/hermeznetwork/hermez-node/log"
"github.com/iden3/go-iden3-crypto/babyjub"
"github.com/jmoiron/sqlx"
//nolint:errcheck // driver for postgres DB
@@ -52,10 +50,7 @@ func (l2db *L2DB) AddAccountCreationAuth(auth *common.AccountCreationAuth) error
}
// GetAccountCreationAuth returns an account creation authorization into the DB
func (l2db *L2DB) GetAccountCreationAuth(addr *ethCommon.Address) (*common.AccountCreationAuth, error) {
if addr == nil {
return nil, errors.New("addr cannot be nil")
}
func (l2db *L2DB) GetAccountCreationAuth(addr ethCommon.Address) (*common.AccountCreationAuth, error) {
auth := new(common.AccountCreationAuth)
return auth, meddler.QueryRow(
l2db.db, auth,
@@ -67,69 +62,71 @@ func (l2db *L2DB) GetAccountCreationAuth(addr *ethCommon.Address) (*common.Accou
// AddTxTest inserts a tx into the L2DB. This is useful for test purposes,
// but in production txs will only be inserted through the API (method TBD)
func (l2db *L2DB) AddTxTest(tx *common.PoolL2Tx) error {
type withouUSD struct {
TxID common.TxID `meddler:"tx_id"`
FromIdx common.Idx `meddler:"from_idx"`
ToIdx *common.Idx `meddler:"to_idx"`
ToEthAddr *ethCommon.Address `meddler:"to_eth_addr"`
ToBJJ *babyjub.PublicKey `meddler:"to_bjj"`
TokenID common.TokenID `meddler:"token_id"`
Amount *big.Int `meddler:"amount,bigint"`
AmountFloat float64 `meddler:"amount_f"`
Fee common.FeeSelector `meddler:"fee"`
Nonce common.Nonce `meddler:"nonce"`
State common.PoolL2TxState `meddler:"state"`
Signature *babyjub.Signature `meddler:"signature"`
Timestamp time.Time `meddler:"timestamp,utctime"`
BatchNum *common.BatchNum `meddler:"batch_num"`
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"`
RqTokenID *common.TokenID `meddler:"rq_token_id"`
RqAmount *big.Int `meddler:"rq_amount,bigintnull"`
RqFee *common.FeeSelector `meddler:"rq_fee"`
RqNonce *uint64 `meddler:"rq_nonce"`
Type common.TxType `meddler:"tx_type"`
// transform tx from *common.PoolL2Tx to PoolL2TxWrite
insertTx := &PoolL2TxWrite{
TxID: tx.TxID,
FromIdx: tx.FromIdx,
ToBJJ: tx.ToBJJ,
TokenID: tx.TokenID,
Amount: tx.Amount,
Fee: tx.Fee,
Nonce: tx.Nonce,
State: tx.State,
Signature: tx.Signature,
RqToBJJ: tx.RqToBJJ,
RqAmount: tx.RqAmount,
Type: 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,
})
if tx.ToIdx != 0 {
insertTx.ToIdx = &tx.ToIdx
}
nilAddr := ethCommon.BigToAddress(big.NewInt(0))
if tx.ToEthAddr != nilAddr {
insertTx.ToEthAddr = &tx.ToEthAddr
}
if tx.RqFromIdx != 0 {
insertTx.RqFromIdx = &tx.RqFromIdx
}
if tx.RqToIdx != 0 { // if true, all Rq... fields must be different to nil
insertTx.RqToIdx = &tx.RqToIdx
insertTx.RqTokenID = &tx.RqTokenID
insertTx.RqFee = &tx.RqFee
insertTx.RqNonce = &tx.RqNonce
}
if tx.RqToEthAddr != nilAddr {
insertTx.RqToEthAddr = &tx.RqToEthAddr
}
f := new(big.Float).SetInt(tx.Amount)
amountF, _ := f.Float64()
insertTx.AmountFloat = amountF
// insert tx
return meddler.Insert(l2db.db, "tx_pool", insertTx)
}
// selectPoolTx select part of queries to get common.PoolL2Tx
const selectPoolTx = `SELECT tx_pool.*, token.usd * tx_pool.amount_f AS value_usd,
// 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,
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.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
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,
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.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) (*common.PoolL2Tx, error) {
tx := new(common.PoolL2Tx)
func (l2db *L2DB) GetTx(txID common.TxID) (*PoolL2TxRead, error) {
tx := new(PoolL2TxRead)
return tx, meddler.QueryRow(
l2db.db, tx,
selectPoolTx+"WHERE tx_id = $1;",
selectPoolTxRead+"WHERE tx_id = $1;",
txID,
)
}
@@ -139,7 +136,7 @@ func (l2db *L2DB) GetPendingTxs() ([]common.PoolL2Tx, error) {
var txs []*common.PoolL2Tx
err := meddler.QueryAll(
l2db.db, &txs,
selectPoolTx+"WHERE state = $1 AND token.usd IS NOT NULL",
selectPoolTxCommon+"WHERE state = $1",
common.PoolL2TxStatePending,
)
return db.SlicePtrsToSlice(txs).([]common.PoolL2Tx), err

View File

@@ -1,10 +1,12 @@
package l2db
import (
"math/big"
"os"
"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"
@@ -16,6 +18,7 @@ import (
var l2DB *L2DB
var tokens []common.Token
var tokensUSD []historydb.TokenRead
func TestMain(m *testing.M) {
// init DB
@@ -25,7 +28,7 @@ func TestMain(m *testing.M) {
panic(err)
}
l2DB = NewL2DB(db, 10, 100, 24*time.Hour)
tokens, err = prepareHistoryDB(db)
tokens, tokensUSD = prepareHistoryDB(db)
if err != nil {
panic(err)
}
@@ -38,7 +41,7 @@ func TestMain(m *testing.M) {
os.Exit(result)
}
func prepareHistoryDB(db *sqlx.DB) ([]common.Token, error) {
func prepareHistoryDB(db *sqlx.DB) ([]common.Token, []historydb.TokenRead) {
historyDB := historydb.NewHistoryDB(db)
const fromBlock int64 = 1
const toBlock int64 = 5
@@ -54,7 +57,31 @@ func prepareHistoryDB(db *sqlx.DB) ([]common.Token, error) {
// Store tokens to historyDB
const nTokens = 5
tokens := test.GenTokens(nTokens, blocks)
return tokens, historyDB.AddTokens(tokens)
if err := historyDB.AddTokens(tokens); err != nil {
panic(err)
}
readTokens := []historydb.TokenRead{}
for i, token := range tokens {
readToken := historydb.TokenRead{
TokenID: token.TokenID,
EthBlockNum: token.EthBlockNum,
EthAddr: token.EthAddr,
Name: token.Name,
Symbol: token.Symbol,
Decimals: token.Decimals,
}
if i%2 != 0 {
value := float64(i) * 5.4321
if err := historyDB.UpdateTokenValue(token.Symbol, value); err != nil {
panic(err)
}
now := time.Now().UTC()
readToken.USDUpdate = &now
readToken.USD = &value
}
readTokens = append(readTokens, readToken)
}
return tokens, readTokens
}
func TestAddTxTest(t *testing.T) {
@@ -67,20 +94,105 @@ func TestAddTxTest(t *testing.T) {
assert.NoError(t, err)
fetchedTx, err := l2DB.GetTx(tx.TxID)
assert.NoError(t, err)
assertTx(t, tx, fetchedTx)
assertReadTx(t, commonToRead(tx, tokens), fetchedTx)
}
}
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)
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.TokenRead{}
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())
assert.GreaterOrEqual(t, time.Now().UTC().Unix(), actual.Timestamp.Unix())
expected.Timestamp = actual.Timestamp
// Check absolute fee
// find token
token := historydb.TokenRead{}
for _, tkn := range tokensUSD {
if expected.TokenID == tkn.TokenID {
token = tkn
break
}
}
// If the token has value in USD setted
if token.USDUpdate != nil {
assert.Equal(t, token.USDUpdate.Unix(), actual.AbsoluteFeeUpdate.Unix())
expected.AbsoluteFeeUpdate = actual.AbsoluteFeeUpdate
// Set expected fee
f := new(big.Float).SetInt(expected.Amount)
amountF, _ := f.Float64()
expected.AbsoluteFee = *token.USD * amountF * expected.Fee.Percentage()
test.AssertUSD(t, &expected.AbsoluteFee, &actual.AbsoluteFee)
}
test.AssertUSD(t, expected.AbsoluteFee, actual.AbsoluteFee)
assert.Equal(t, expected, actual)
}
@@ -104,7 +216,7 @@ func TestGetPending(t *testing.T) {
for _, tx := range txs {
err := l2DB.AddTxTest(tx)
assert.NoError(t, err)
if tx.State == common.PoolL2TxStatePending && tx.AbsoluteFee != nil {
if tx.State == common.PoolL2TxStatePending {
pendingTxs = append(pendingTxs, tx)
}
}
@@ -257,16 +369,21 @@ func TestReorg(t *testing.T) {
reorgedTxIDs := []common.TxID{}
nonReorgedTxIDs := []common.TxID{}
for i := 0; i < len(txs); i++ {
txs[i].BatchNum = new(common.BatchNum)
if txs[i].State == common.PoolL2TxStateForged || txs[i].State == common.PoolL2TxStateInvalid {
*txs[i].BatchNum = reorgBatch
reorgedTxIDs = append(reorgedTxIDs, txs[i].TxID)
} else {
*txs[i].BatchNum = lastValidBatch
nonReorgedTxIDs = append(nonReorgedTxIDs, txs[i].TxID)
}
err := l2DB.AddTxTest(txs[i])
assert.NoError(t, err)
var batchNum common.BatchNum
if txs[i].State == common.PoolL2TxStateForged || txs[i].State == common.PoolL2TxStateInvalid {
reorgedTxIDs = append(reorgedTxIDs, txs[i].TxID)
batchNum = reorgBatch
} else {
nonReorgedTxIDs = append(nonReorgedTxIDs, txs[i].TxID)
batchNum = lastValidBatch
}
_, err = l2DB.db.Exec(
"UPDATE tx_pool SET batch_num = $1 WHERE tx_id = $2;",
batchNum, txs[i].TxID,
)
assert.NoError(t, err)
}
err := l2DB.Reorg(lastValidBatch)
assert.NoError(t, err)
@@ -277,9 +394,9 @@ func TestReorg(t *testing.T) {
assert.Equal(t, common.PoolL2TxStatePending, tx.State)
}
for _, id := range nonReorgedTxIDs {
tx, err := l2DB.GetTx(id)
fetchedTx, err := l2DB.GetTx(id)
assert.NoError(t, err)
assert.Equal(t, lastValidBatch, *tx.BatchNum)
assert.Equal(t, lastValidBatch, *fetchedTx.BatchNum)
}
}
@@ -294,12 +411,12 @@ func TestPurge(t *testing.T) {
safeBatchNum := toDeleteBatchNum + l2DB.safetyPeriod + 1
// Add txs to the DB
for i := 0; i < int(l2DB.maxTxs); i++ {
txs[i].BatchNum = new(common.BatchNum)
if i%1 == 0 { // keep tx
*txs[i].BatchNum = safeBatchNum
var batchNum common.BatchNum
if i%2 == 0 { // keep tx
batchNum = safeBatchNum
keepedIDs = append(keepedIDs, txs[i].TxID)
} else if i%2 == 0 { // delete after safety period
*txs[i].BatchNum = toDeleteBatchNum
} else { // delete after safety period
batchNum = toDeleteBatchNum
if i%3 == 0 {
txs[i].State = common.PoolL2TxStateForged
} else {
@@ -309,16 +426,28 @@ func TestPurge(t *testing.T) {
}
err := l2DB.AddTxTest(txs[i])
assert.NoError(t, err)
// Set batchNum
_, err = l2DB.db.Exec(
"UPDATE tx_pool SET batch_num = $1 WHERE tx_id = $2;",
batchNum, txs[i].TxID,
)
assert.NoError(t, err)
}
for i := int(l2DB.maxTxs); i < len(txs); i++ {
// Delete after TTL
txs[i].Timestamp = time.Unix(time.Now().UTC().Unix()-int64(l2DB.ttl.Seconds()+float64(4*time.Second)), 0)
deletedIDs = append(deletedIDs, txs[i].TxID)
err := l2DB.AddTxTest(txs[i])
assert.NoError(t, err)
// Set timestamp
deleteTimestamp := time.Unix(time.Now().UTC().Unix()-int64(l2DB.ttl.Seconds()+float64(4*time.Second)), 0)
_, err = l2DB.db.Exec(
"UPDATE tx_pool SET timestamp = $1 WHERE tx_id = $2;",
deleteTimestamp, txs[i].TxID,
)
assert.NoError(t, err)
}
// Purge txs
err := l2DB.Purge(safeBatchNum - 1)
err := l2DB.Purge(safeBatchNum)
assert.NoError(t, err)
// Check results
for _, id := range deletedIDs {
@@ -344,7 +473,7 @@ func TestAuth(t *testing.T) {
err := l2DB.AddAccountCreationAuth(auths[i])
assert.NoError(t, err)
// Fetch from DB
auth, err := l2DB.GetAccountCreationAuth(&auths[i].EthAddr)
auth, err := l2DB.GetAccountCreationAuth(auths[i].EthAddr)
assert.NoError(t, err)
// Check fetched vs generated
assert.Equal(t, auths[i].EthAddr, auth.EthAddr)

70
db/l2db/views.go Normal file
View File

@@ -0,0 +1,70 @@
package l2db
import (
"math/big"
"time"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/hermeznetwork/hermez-node/common"
"github.com/iden3/go-iden3-crypto/babyjub"
)
// PoolL2TxWrite holds the necessary data to perform inserts in tx_pool
type PoolL2TxWrite 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"`
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"`
RqTokenID *common.TokenID `meddler:"rq_token_id"`
RqAmount *big.Int `meddler:"rq_amount,bigintnull"`
RqFee *common.FeeSelector `meddler:"rq_fee"`
RqNonce *uint64 `meddler:"rq_nonce"`
Type common.TxType `meddler:"tx_type"`
}
// PoolL2TxRead represents a L2 Tx pool with extra metadata used by the API
type PoolL2TxRead 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"`
Fee common.FeeSelector `meddler:"fee"`
Nonce common.Nonce `meddler:"nonce"`
State common.PoolL2TxState `meddler:"state"`
Signature *babyjub.Signature `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"`
RqTokenID *common.TokenID `meddler:"rq_token_id"`
RqAmount *big.Int `meddler:"rq_amount,bigintnull"`
RqFee *common.FeeSelector `meddler:"rq_fee"`
RqNonce *uint64 `meddler:"rq_nonce"`
Type common.TxType `meddler:"tx_type"`
// Extra read fileds
BatchNum *common.BatchNum `meddler:"batch_num"`
Timestamp time.Time `meddler:"timestamp,utctime"`
TotalItems int `meddler:"total_items"`
TokenID common.TokenID `meddler:"token_id"`
TokenEthBlockNum int64 `meddler:"eth_block_num"`
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"`
}

View File

@@ -55,7 +55,7 @@ CREATE TABLE token (
symbol VARCHAR(10) NOT NULL,
decimals INT NOT NULL,
usd NUMERIC,
usd_update TIMESTAMP
usd_update TIMESTAMP WITHOUT TIME ZONE
);
-- +migrate StatementBegin
@@ -381,7 +381,10 @@ CREATE FUNCTION set_tx()
RETURNS TRIGGER
AS
$BODY$
DECLARE token_value NUMERIC;
DECLARE
_value NUMERIC;
_usd_update TIMESTAMP;
_tx_timestamp TIMESTAMP;
BEGIN
-- Validate L1/L2 constrains
IF NEW.is_l1 AND (( -- L1 mandatory fields
@@ -405,11 +408,14 @@ BEGIN
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));
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
NEW."amount_usd" = (SELECT _value * NEW.amount_f);
NEW."load_amount_usd" = (SELECT _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;
END IF;
RETURN NEW;
END;
@@ -481,7 +487,7 @@ CREATE TABLE tx_pool (
nonce BIGINT NOT NULL,
state CHAR(4) NOT NULL,
signature BYTEA NOT NULL,
timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
timestamp TIMESTAMP WITHOUT TIME ZONE DEFAULT timezone('utc', now()),
batch_num BIGINT,
rq_from_idx BIGINT,
rq_to_idx BIGINT,
@@ -498,7 +504,7 @@ 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
timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT timezone('utc', now())
);
-- +migrate Down

View File

@@ -247,19 +247,13 @@ func (s *StateDB) Reset(batchNum common.BatchNum) error {
}
// GetAccount returns the account for the given Idx
func (s *StateDB) GetAccount(idx *common.Idx) (*common.Account, error) {
if idx == nil {
return nil, errors.New("idx cannot be nil")
}
func (s *StateDB) GetAccount(idx common.Idx) (*common.Account, error) {
return getAccountInTreeDB(s.db, idx)
}
// getAccountInTreeDB is abstracted from StateDB to be used from StateDB and
// from ExitTree. GetAccount returns the account for the given Idx
func getAccountInTreeDB(sto db.Storage, idx *common.Idx) (*common.Account, error) {
if idx == nil {
return nil, errors.New("idx cannot be nil")
}
func getAccountInTreeDB(sto db.Storage, idx common.Idx) (*common.Account, error) {
idxBytes, err := idx.Bytes()
if err != nil {
return nil, err
@@ -281,12 +275,12 @@ func getAccountInTreeDB(sto db.Storage, idx *common.Idx) (*common.Account, error
// StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
// MerkleTree, returning a CircomProcessorProof.
func (s *StateDB) CreateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
cpp, err := createAccountInTreeDB(s.db, s.mt, &idx, account)
cpp, err := createAccountInTreeDB(s.db, s.mt, idx, account)
if err != nil {
return cpp, err
}
// store idx by EthAddr & BJJ
err = s.setIdxByEthAddrBJJ(idx, &account.EthAddr, account.PublicKey)
err = s.setIdxByEthAddrBJJ(idx, account.EthAddr, account.PublicKey)
return cpp, err
}
@@ -294,10 +288,7 @@ func (s *StateDB) CreateAccount(idx common.Idx, account *common.Account) (*merkl
// from ExitTree. Creates a new Account in the StateDB for the given Idx. If
// StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
// MerkleTree, returning a CircomProcessorProof.
func createAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx *common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
if idx == nil {
return nil, errors.New("idx cannot be nil")
}
func createAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
// store at the DB the key: v, and value: leaf.Bytes()
v, err := account.HashValue()
if err != nil {
@@ -346,10 +337,7 @@ func createAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx *commo
// UpdateAccount updates the Account in the StateDB for the given Idx. If
// StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
// MerkleTree, returning a CircomProcessorProof.
func (s *StateDB) UpdateAccount(idx *common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
if idx == nil {
return nil, errors.New("idx cannot be nil")
}
func (s *StateDB) UpdateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
return updateAccountInTreeDB(s.db, s.mt, idx, account)
}
@@ -357,10 +345,7 @@ func (s *StateDB) UpdateAccount(idx *common.Idx, account *common.Account) (*merk
// from ExitTree. Updates the Account in the StateDB for the given Idx. If
// StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
// MerkleTree, returning a CircomProcessorProof.
func updateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx *common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
if idx == nil {
return nil, errors.New("idx cannot be nil")
}
func updateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
// store at the DB the key: v, and value: account.Bytes()
v, err := account.HashValue()
if err != nil {

View File

@@ -130,7 +130,7 @@ func TestStateDBWithoutMT(t *testing.T) {
// get non-existing account, expecting an error
unexistingAccount := common.Idx(1)
_, err = sdb.GetAccount(&unexistingAccount)
_, err = sdb.GetAccount(unexistingAccount)
assert.NotNil(t, err)
assert.Equal(t, db.ErrNotFound, err)
@@ -142,14 +142,14 @@ func TestStateDBWithoutMT(t *testing.T) {
for i := 0; i < len(accounts); i++ {
existingAccount := common.Idx(i)
accGetted, err := sdb.GetAccount(&existingAccount)
accGetted, err := sdb.GetAccount(existingAccount)
assert.Nil(t, err)
assert.Equal(t, accounts[i], accGetted)
}
// try already existing idx and get error
existingAccount := common.Idx(1)
_, err = sdb.GetAccount(&existingAccount) // check that exist
_, err = sdb.GetAccount(existingAccount) // check that exist
assert.Nil(t, err)
_, err = sdb.CreateAccount(common.Idx(1), accounts[1]) // check that can not be created twice
assert.NotNil(t, err)
@@ -159,7 +159,7 @@ func TestStateDBWithoutMT(t *testing.T) {
for i := 0; i < len(accounts); i++ {
accounts[i].Nonce = accounts[i].Nonce + 1
existingAccount = common.Idx(i)
_, err = sdb.UpdateAccount(&existingAccount, accounts[i])
_, err = sdb.UpdateAccount(existingAccount, accounts[i])
assert.Nil(t, err)
}
@@ -182,8 +182,7 @@ func TestStateDBWithMT(t *testing.T) {
}
// get non-existing account, expecting an error
accountIdx := common.Idx(1)
_, err = sdb.GetAccount(&accountIdx)
_, err = sdb.GetAccount(common.Idx(1))
assert.NotNil(t, err)
assert.Equal(t, db.ErrNotFound, err)
@@ -194,15 +193,13 @@ func TestStateDBWithMT(t *testing.T) {
}
for i := 0; i < len(accounts); i++ {
accountIdx = common.Idx(i)
accGetted, err := sdb.GetAccount(&accountIdx)
accGetted, err := sdb.GetAccount(common.Idx(i))
assert.Nil(t, err)
assert.Equal(t, accounts[i], accGetted)
}
// try already existing idx and get error
accountIdx = 1
_, err = sdb.GetAccount(&accountIdx) // check that exist
_, err = sdb.GetAccount(common.Idx(1)) // check that exist
assert.Nil(t, err)
_, err = sdb.CreateAccount(common.Idx(1), accounts[1]) // check that can not be created twice
assert.NotNil(t, err)
@@ -214,12 +211,10 @@ func TestStateDBWithMT(t *testing.T) {
// update accounts
for i := 0; i < len(accounts); i++ {
accounts[i].Nonce = accounts[i].Nonce + 1
accountIdx = common.Idx(i)
_, err = sdb.UpdateAccount(&accountIdx, accounts[i])
_, err = sdb.UpdateAccount(common.Idx(i), accounts[i])
assert.Nil(t, err)
}
accountIdx = 1
a, err := sdb.GetAccount(&accountIdx) // check that account value has been updated
a, err := sdb.GetAccount(common.Idx(1)) // check that account value has been updated
assert.Nil(t, err)
assert.Equal(t, accounts[1].Nonce, a.Nonce)
}

View File

@@ -230,11 +230,7 @@ func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx)
if s.zki != nil {
// Txs
// s.zki.TxCompressedData[s.i] = tx.TxCompressedData() // uncomment once L1Tx.TxCompressedData is ready
if tx.FromIdx != nil {
s.zki.FromIdx[s.i] = tx.FromIdx.BigInt()
} else {
s.zki.FromIdx[s.i] = big.NewInt(0)
}
s.zki.FromIdx[s.i] = tx.FromIdx.BigInt()
s.zki.ToIdx[s.i] = tx.ToIdx.BigInt()
s.zki.OnChain[s.i] = big.NewInt(1)
@@ -299,7 +295,7 @@ func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx)
if err != nil {
return nil, nil, false, err
}
return tx.FromIdx, exitAccount, newExit, nil
return &tx.FromIdx, exitAccount, newExit, nil
default:
}
@@ -314,7 +310,7 @@ func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.PoolL2
var err error
var auxToIdx common.Idx
// if tx.ToIdx==0, get toIdx by ToEthAddr or ToBJJ
if tx.ToIdx == nil || *tx.ToIdx == common.Idx(0) {
if tx.ToIdx == common.Idx(0) {
auxToIdx, err = s.GetIdxByEthAddrBJJ(tx.ToEthAddr, tx.ToBJJ)
if err != nil {
log.Error(err)
@@ -331,7 +327,7 @@ func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.PoolL2
s.zki.ToIdx[s.i] = tx.ToIdx.BigInt()
// fill AuxToIdx if needed
if tx.ToIdx == nil {
if tx.ToIdx == 0 {
// use toIdx that can have been filled by tx.ToIdx or
// if tx.Idx==0 (this case), toIdx is filled by the Idx
// from db by ToEthAddr&ToBJJ
@@ -339,12 +335,7 @@ func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.PoolL2
}
s.zki.ToBJJAy[s.i] = tx.ToBJJ.Y
if tx.ToEthAddr != nil {
s.zki.ToEthAddr[s.i] = common.EthAddrToBigInt(*tx.ToEthAddr)
} else {
// Not sure if this should throw an error
s.zki.ToEthAddr[s.i] = big.NewInt(0)
}
s.zki.ToEthAddr[s.i] = common.EthAddrToBigInt(tx.ToEthAddr)
s.zki.OnChain[s.i] = big.NewInt(0)
s.zki.NewAccount[s.i] = big.NewInt(0)
@@ -448,7 +439,7 @@ func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
// in case that the tx is a L1Tx>DepositTransfer
var accReceiver *common.Account
if transfer {
accReceiver, err = s.GetAccount(&tx.ToIdx)
accReceiver, err = s.GetAccount(tx.ToIdx)
if err != nil {
return err
}
@@ -478,7 +469,7 @@ func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
// this is done after updating Sender Account (depositer)
if transfer {
// update receiver account in localStateDB
p, err := s.UpdateAccount(&tx.ToIdx, accReceiver)
p, err := s.UpdateAccount(tx.ToIdx, accReceiver)
if err != nil {
return err
}
@@ -507,17 +498,14 @@ func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
// the real ToIdx is found trhrough the ToEthAddr or ToBJJ.
func (s *StateDB) applyTransfer(tx *common.Tx, auxToIdx common.Idx) error {
if auxToIdx == 0 {
if tx.ToIdx == nil {
return errors.New("tx.ToIdx cannot be nil if auxToIdx is 0")
}
auxToIdx = *tx.ToIdx
auxToIdx = tx.ToIdx
}
// get sender and receiver accounts from localStateDB
accSender, err := s.GetAccount(tx.FromIdx)
if err != nil {
return err
}
accReceiver, err := s.GetAccount(&auxToIdx)
accReceiver, err := s.GetAccount(auxToIdx)
if err != nil {
return err
}
@@ -548,7 +536,7 @@ func (s *StateDB) applyTransfer(tx *common.Tx, auxToIdx common.Idx) error {
}
// update receiver account in localStateDB
pReceiver, err := s.UpdateAccount(&auxToIdx, accReceiver)
pReceiver, err := s.UpdateAccount(auxToIdx, accReceiver)
if err != nil {
return err
}
@@ -578,7 +566,7 @@ func (s *StateDB) applyCreateAccountDepositTransfer(tx *common.L1Tx) error {
EthAddr: tx.FromEthAddr,
}
accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
accReceiver, err := s.GetAccount(&tx.ToIdx)
accReceiver, err := s.GetAccount(tx.ToIdx)
if err != nil {
return err
}
@@ -610,7 +598,7 @@ func (s *StateDB) applyCreateAccountDepositTransfer(tx *common.L1Tx) error {
}
// update receiver account in localStateDB
p, err = s.UpdateAccount(&tx.ToIdx, accReceiver)
p, err = s.UpdateAccount(tx.ToIdx, accReceiver)
if err != nil {
return err
}

View File

@@ -40,8 +40,7 @@ func TestProcessTxs(t *testing.T) {
require.Nil(t, err)
}
accountIdx := common.Idx(256)
acc, err := sdb.GetAccount(&accountIdx)
acc, err := sdb.GetAccount(common.Idx(256))
assert.Nil(t, err)
assert.Equal(t, "23", acc.Balance.String())
}
@@ -80,8 +79,7 @@ func TestProcessTxsSynchronizer(t *testing.T) {
// Nonce & TokenID =0, after ProcessTxs call has the expected value
assert.Equal(t, 0, len(exitInfos))
accountIdx := common.Idx(256)
acc, err := sdb.GetAccount(&accountIdx)
acc, err := sdb.GetAccount(common.Idx(256))
assert.Nil(t, err)
assert.Equal(t, "28", acc.Balance.String())
@@ -90,7 +88,7 @@ func TestProcessTxsSynchronizer(t *testing.T) {
_, exitInfos, err = sdb.ProcessTxs(l1Txs[1], coordinatorL1Txs[1], poolL2Txs[1])
require.Nil(t, err)
assert.Equal(t, 5, len(exitInfos))
acc, err = sdb.GetAccount(&accountIdx)
acc, err = sdb.GetAccount(common.Idx(256))
require.Nil(t, err)
assert.Equal(t, "48", acc.Balance.String())
@@ -99,7 +97,7 @@ func TestProcessTxsSynchronizer(t *testing.T) {
_, exitInfos, err = sdb.ProcessTxs(l1Txs[2], coordinatorL1Txs[2], poolL2Txs[2])
require.Nil(t, err)
assert.Equal(t, 1, len(exitInfos))
acc, err = sdb.GetAccount(&accountIdx)
acc, err = sdb.GetAccount(common.Idx(256))
assert.Nil(t, err)
assert.Equal(t, "23", acc.Balance.String())
}
@@ -132,8 +130,7 @@ func TestProcessTxsBatchBuilder(t *testing.T) {
_, exitInfos, err := sdb.ProcessTxs(l1Txs[0], coordinatorL1Txs[0], poolL2Txs[0])
require.Nil(t, err)
assert.Equal(t, 0, len(exitInfos))
accountIdx := common.Idx(256)
acc, err := sdb.GetAccount(&accountIdx)
acc, err := sdb.GetAccount(common.Idx(256))
assert.Nil(t, err)
assert.Equal(t, "28", acc.Balance.String())
@@ -142,7 +139,7 @@ func TestProcessTxsBatchBuilder(t *testing.T) {
_, exitInfos, err = sdb.ProcessTxs(l1Txs[1], coordinatorL1Txs[1], poolL2Txs[1])
require.Nil(t, err)
assert.Equal(t, 5, len(exitInfos))
acc, err = sdb.GetAccount(&accountIdx)
acc, err = sdb.GetAccount(common.Idx(256))
require.Nil(t, err)
assert.Equal(t, "48", acc.Balance.String())
@@ -151,7 +148,7 @@ func TestProcessTxsBatchBuilder(t *testing.T) {
_, exitInfos, err = sdb.ProcessTxs(l1Txs[2], coordinatorL1Txs[2], poolL2Txs[2])
require.Nil(t, err)
assert.Equal(t, 1, len(exitInfos))
acc, err = sdb.GetAccount(&accountIdx)
acc, err = sdb.GetAccount(common.Idx(256))
assert.Nil(t, err)
assert.Equal(t, "23", acc.Balance.String())
}

View File

@@ -2,7 +2,6 @@ package statedb
import (
"bytes"
"errors"
"math/big"
ethCommon "github.com/ethereum/go-ethereum/common"
@@ -12,7 +11,7 @@ import (
"github.com/iden3/go-merkletree"
)
func concatEthAddrBJJ(addr *ethCommon.Address, pk *babyjub.PublicKey) []byte {
func concatEthAddrBJJ(addr ethCommon.Address, pk *babyjub.PublicKey) []byte {
pkComp := pk.Compress()
var b []byte
b = append(b, addr.Bytes()...)
@@ -25,7 +24,7 @@ func concatEthAddrBJJ(addr *ethCommon.Address, pk *babyjub.PublicKey) []byte {
// - key: EthAddr & BabyJubJub PublicKey Compressed, value: idx
// If Idx already exist for the given EthAddr & BJJ, the remaining Idx will be
// always the smallest one.
func (s *StateDB) setIdxByEthAddrBJJ(idx common.Idx, addr *ethCommon.Address, pk *babyjub.PublicKey) error {
func (s *StateDB) setIdxByEthAddrBJJ(idx common.Idx, addr ethCommon.Address, pk *babyjub.PublicKey) error {
oldIdx, err := s.GetIdxByEthAddrBJJ(addr, pk)
if err == nil {
// EthAddr & BJJ already have an Idx
@@ -71,10 +70,7 @@ func (s *StateDB) setIdxByEthAddrBJJ(idx common.Idx, addr *ethCommon.Address, pk
// GetIdxByEthAddr returns the smallest Idx in the StateDB for the given
// Ethereum Address. Will return common.Idx(0) and error in case that Idx is
// not found in the StateDB.
func (s *StateDB) GetIdxByEthAddr(addr *ethCommon.Address) (common.Idx, error) {
if addr == nil {
return 0, errors.New("addr cannot be nil")
}
func (s *StateDB) GetIdxByEthAddr(addr ethCommon.Address) (common.Idx, error) {
b, err := s.db.Get(addr.Bytes())
if err != nil {
return common.Idx(0), ErrToIdxNotFound
@@ -91,10 +87,7 @@ func (s *StateDB) GetIdxByEthAddr(addr *ethCommon.Address) (common.Idx, error) {
// address, it's ignored in the query. If `pk` is nil, it's ignored in the
// query. Will return common.Idx(0) and error in case that Idx is not found in
// the StateDB.
func (s *StateDB) GetIdxByEthAddrBJJ(addr *ethCommon.Address, pk *babyjub.PublicKey) (common.Idx, error) {
if addr == nil {
return 0, errors.New("addr cannot be nil")
}
func (s *StateDB) GetIdxByEthAddrBJJ(addr ethCommon.Address, pk *babyjub.PublicKey) (common.Idx, error) {
if !bytes.Equal(addr.Bytes(), common.EmptyAddr.Bytes()) && pk == nil {
// case ToEthAddr!=0 && ToBJJ=0
return s.GetIdxByEthAddr(addr)

View File

@@ -32,47 +32,47 @@ func TestGetIdx(t *testing.T) {
idx3 := common.Idx(1233)
// store the keys for idx by Addr & BJJ
err = sdb.setIdxByEthAddrBJJ(idx, &addr, pk)
err = sdb.setIdxByEthAddrBJJ(idx, addr, pk)
require.Nil(t, err)
idxR, err := sdb.GetIdxByEthAddrBJJ(&addr, pk)
idxR, err := sdb.GetIdxByEthAddrBJJ(addr, pk)
assert.Nil(t, err)
assert.Equal(t, idx, idxR)
// expect error when getting only by EthAddr, as value does not exist
// in the db for only EthAddr
_, err = sdb.GetIdxByEthAddr(&addr)
_, err = sdb.GetIdxByEthAddr(addr)
assert.Nil(t, err)
_, err = sdb.GetIdxByEthAddr(&addr2)
_, err = sdb.GetIdxByEthAddr(addr2)
assert.NotNil(t, err)
// expect to fail
idxR, err = sdb.GetIdxByEthAddrBJJ(&addr2, pk)
idxR, err = sdb.GetIdxByEthAddrBJJ(addr2, pk)
assert.NotNil(t, err)
assert.Equal(t, common.Idx(0), idxR)
idxR, err = sdb.GetIdxByEthAddrBJJ(&addr, pk2)
idxR, err = sdb.GetIdxByEthAddrBJJ(addr, pk2)
assert.NotNil(t, err)
assert.Equal(t, common.Idx(0), idxR)
// try to store bigger idx, will not affect as already exist a smaller
// Idx for that Addr & BJJ
err = sdb.setIdxByEthAddrBJJ(idx2, &addr, pk)
err = sdb.setIdxByEthAddrBJJ(idx2, addr, pk)
assert.Nil(t, err)
// store smaller idx
err = sdb.setIdxByEthAddrBJJ(idx3, &addr, pk)
err = sdb.setIdxByEthAddrBJJ(idx3, addr, pk)
assert.Nil(t, err)
idxR, err = sdb.GetIdxByEthAddrBJJ(&addr, pk)
idxR, err = sdb.GetIdxByEthAddrBJJ(addr, pk)
assert.Nil(t, err)
assert.Equal(t, idx3, idxR)
// by EthAddr should work
idxR, err = sdb.GetIdxByEthAddr(&addr)
idxR, err = sdb.GetIdxByEthAddr(addr)
assert.Nil(t, err)
assert.Equal(t, idx3, idxR)
// expect error when trying to get Idx by addr2 & pk2
idxR, err = sdb.GetIdxByEthAddrBJJ(&addr2, pk2)
idxR, err = sdb.GetIdxByEthAddrBJJ(addr2, pk2)
assert.NotNil(t, err)
assert.Equal(t, ErrToIdxNotFound, err)
assert.Equal(t, common.Idx(0), idxR)