mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 11:26:44 +01:00
Refactor api txs
This commit is contained in:
704
api/api_test.go
704
api/api_test.go
@@ -8,7 +8,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -45,103 +44,26 @@ type testCommon struct {
|
||||
usrAddr string
|
||||
usrBjj string
|
||||
accs []common.Account
|
||||
usrTxs []historyTxAPI
|
||||
allTxs []historyTxAPI
|
||||
usrTxs []testTx
|
||||
allTxs []testTx
|
||||
exits []exitAPI
|
||||
usrExits []exitAPI
|
||||
poolTxsToSend []receivedPoolTx
|
||||
poolTxsToReceive []sendPoolTx
|
||||
poolTxsToSend []testPoolTxSend
|
||||
poolTxsToReceive []testPoolTxReceive
|
||||
auths []accountCreationAuthAPI
|
||||
router *swagger.Router
|
||||
}
|
||||
|
||||
// TxSortFields represents the fields needed to sort L1 and L2 transactions
|
||||
type txSortFields struct {
|
||||
BatchNum *common.BatchNum
|
||||
Position int
|
||||
}
|
||||
|
||||
// TxSortFielder is a interface that allows sorting L1 and L2 transactions in a combined way
|
||||
type txSortFielder interface {
|
||||
SortFields() txSortFields
|
||||
L1() *common.L1Tx
|
||||
L2() *common.L2Tx
|
||||
}
|
||||
|
||||
// TxsSort array of TxSortFielder
|
||||
type txsSort []txSortFielder
|
||||
|
||||
func (t txsSort) Len() int { return len(t) }
|
||||
func (t txsSort) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
||||
func (t txsSort) Less(i, j int) bool {
|
||||
// i not forged yet
|
||||
isf := t[i].SortFields()
|
||||
jsf := t[j].SortFields()
|
||||
if isf.BatchNum == nil {
|
||||
if jsf.BatchNum != nil { // j is already forged
|
||||
return false
|
||||
}
|
||||
// Both aren't forged, is i in a smaller position?
|
||||
return isf.Position < jsf.Position
|
||||
}
|
||||
// i is forged
|
||||
if jsf.BatchNum == nil {
|
||||
return false // j is not forged
|
||||
}
|
||||
// Both are forged
|
||||
if *isf.BatchNum == *jsf.BatchNum {
|
||||
// At the same batch, is i in a smaller position?
|
||||
return isf.Position < jsf.Position
|
||||
}
|
||||
// At different batches, is i in a smaller batch?
|
||||
return *isf.BatchNum < *jsf.BatchNum
|
||||
}
|
||||
|
||||
type wrappedL1 common.L1Tx
|
||||
|
||||
// SortFields implements TxSortFielder
|
||||
func (tx *wrappedL1) SortFields() txSortFields {
|
||||
return txSortFields{
|
||||
BatchNum: tx.BatchNum,
|
||||
Position: tx.Position,
|
||||
}
|
||||
}
|
||||
|
||||
// L1 implements TxSortFielder
|
||||
func (tx *wrappedL1) L1() *common.L1Tx {
|
||||
l1tx := common.L1Tx(*tx)
|
||||
return &l1tx
|
||||
}
|
||||
|
||||
// L2 implements TxSortFielder
|
||||
func (tx *wrappedL1) L2() *common.L2Tx { return nil }
|
||||
|
||||
type wrappedL2 common.L2Tx
|
||||
|
||||
// SortFields implements TxSortFielder
|
||||
func (tx *wrappedL2) SortFields() txSortFields {
|
||||
return txSortFields{
|
||||
BatchNum: &tx.BatchNum,
|
||||
Position: tx.Position,
|
||||
}
|
||||
}
|
||||
|
||||
// L1 implements TxSortFielder
|
||||
func (tx *wrappedL2) L1() *common.L1Tx { return nil }
|
||||
|
||||
// L2 implements TxSortFielder
|
||||
func (tx *wrappedL2) L2() *common.L2Tx {
|
||||
l2tx := common.L2Tx(*tx)
|
||||
return &l2tx
|
||||
}
|
||||
|
||||
var tc testCommon
|
||||
var config configAPI
|
||||
|
||||
// TestMain initializes the API server, and fill HistoryDB and StateDB with fake data,
|
||||
// emulating the task of the synchronizer in order to have data to be returned
|
||||
// by the API endpoints that will be tested
|
||||
func TestMain(m *testing.M) {
|
||||
// Init swagger
|
||||
// Initializations
|
||||
// Swagger
|
||||
router := swagger.NewRouter().WithSwaggerFromFile("./swagger.yml")
|
||||
// Init DBs
|
||||
// HistoryDB
|
||||
pass := os.Getenv("POSTGRES_PASS")
|
||||
database, err := db.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
|
||||
@@ -170,7 +92,7 @@ func TestMain(m *testing.M) {
|
||||
// L2DB
|
||||
l2DB := l2db.NewL2DB(database, 10, 100, 24*time.Hour)
|
||||
test.CleanL2DB(l2DB.DB())
|
||||
|
||||
// Config (smart contract constants)
|
||||
config.RollupConstants.ExchangeMultiplier = eth.RollupConstExchangeMultiplier
|
||||
config.RollupConstants.ExitIdx = eth.RollupConstExitIDx
|
||||
config.RollupConstants.ReservedIdx = eth.RollupConstReservedIDx
|
||||
@@ -213,7 +135,7 @@ func TestMain(m *testing.M) {
|
||||
config.AuctionConstants = auctionConstants
|
||||
config.WDelayerConstants = wdelayerConstants
|
||||
|
||||
// Init API
|
||||
// API
|
||||
api := gin.Default()
|
||||
if err := SetAPIEndpoints(
|
||||
true,
|
||||
@@ -235,7 +157,7 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
}()
|
||||
|
||||
// Populate DBs
|
||||
// Fill HistoryDB and StateDB with fake data
|
||||
// Clean DB
|
||||
err = h.Reorg(0)
|
||||
if err != nil {
|
||||
@@ -302,6 +224,17 @@ func TestMain(m *testing.M) {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
// helper to vinculate user related resources
|
||||
usrIdxs := []string{}
|
||||
for _, acc := range accs {
|
||||
if acc.EthAddr == usrAddr || acc.PublicKey == usrBjj {
|
||||
for _, token := range tokens {
|
||||
if token.TokenID == acc.TokenID {
|
||||
usrIdxs = append(usrIdxs, idxToHez(acc.Idx, token.Symbol))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Gen exits and add them to DB
|
||||
const totalExits = 40
|
||||
exits := test.GenExitTree(totalExits, batches, accs)
|
||||
@@ -309,15 +242,17 @@ func TestMain(m *testing.M) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Gen L1Txs and add them to DB
|
||||
|
||||
// L1 and L2 txs need to be sorted in a combined way
|
||||
// Gen L1Txs
|
||||
const totalL1Txs = 40
|
||||
const userL1Txs = 4
|
||||
usrL1Txs, othrL1Txs := test.GenL1Txs(256, totalL1Txs, userL1Txs, &usrAddr, accs, tokens, blocks, batches)
|
||||
// Gen L2Txs and add them to DB
|
||||
// Gen L2Txs
|
||||
const totalL2Txs = 20
|
||||
const userL2Txs = 4
|
||||
usrL2Txs, othrL2Txs := test.GenL2Txs(256+totalL1Txs, totalL2Txs, userL2Txs, &usrAddr, accs, tokens, blocks, batches)
|
||||
// Order txs
|
||||
// Sort txs
|
||||
sortedTxs := []txSortFielder{}
|
||||
for i := 0; i < len(usrL1Txs); i++ {
|
||||
wL1 := wrappedL1(usrL1Txs[i])
|
||||
@@ -336,161 +271,30 @@ func TestMain(m *testing.M) {
|
||||
sortedTxs = append(sortedTxs, &wL2)
|
||||
}
|
||||
sort.Sort(txsSort(sortedTxs))
|
||||
// Add txs to DB and prepare them for test commons
|
||||
usrTxs := []historyTxAPI{}
|
||||
allTxs := []historyTxAPI{}
|
||||
getTimestamp := func(blockNum int64) time.Time {
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
if blocks[i].EthBlockNum == blockNum {
|
||||
return blocks[i].Timestamp
|
||||
}
|
||||
}
|
||||
panic("timesamp not found")
|
||||
}
|
||||
getToken := func(id common.TokenID) historydb.TokenWithUSD {
|
||||
for i := 0; i < len(tokensUSD); i++ {
|
||||
if tokensUSD[i].TokenID == id {
|
||||
return tokensUSD[i]
|
||||
}
|
||||
}
|
||||
panic("token not found")
|
||||
}
|
||||
getTokenByIdx := func(idx common.Idx) historydb.TokenWithUSD {
|
||||
for _, acc := range accs {
|
||||
if idx == acc.Idx {
|
||||
return getToken(acc.TokenID)
|
||||
}
|
||||
}
|
||||
panic("token not found")
|
||||
}
|
||||
usrIdxs := []string{}
|
||||
for _, acc := range accs {
|
||||
if acc.EthAddr == usrAddr || acc.PublicKey == usrBjj {
|
||||
for _, token := range tokens {
|
||||
if token.TokenID == acc.TokenID {
|
||||
usrIdxs = append(usrIdxs, idxToHez(acc.Idx, token.Symbol))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
isUsrTx := func(tx historyTxAPI) bool {
|
||||
for _, idx := range usrIdxs {
|
||||
if tx.FromIdx != nil && *tx.FromIdx == idx {
|
||||
return true
|
||||
}
|
||||
if tx.ToIdx == idx {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
// Store txs to DB
|
||||
for _, genericTx := range sortedTxs {
|
||||
l1 := genericTx.L1()
|
||||
l2 := genericTx.L2()
|
||||
if l1 != nil {
|
||||
// Add L1 tx to DB
|
||||
err = h.AddL1Txs([]common.L1Tx{*l1})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// L1Tx ==> historyTxAPI
|
||||
token := getToken(l1.TokenID)
|
||||
tx := historyTxAPI{
|
||||
IsL1: "L1",
|
||||
TxID: l1.TxID,
|
||||
Type: l1.Type,
|
||||
Position: l1.Position,
|
||||
ToIdx: idxToHez(l1.ToIdx, token.Symbol),
|
||||
Amount: l1.Amount.String(),
|
||||
BatchNum: l1.BatchNum,
|
||||
Timestamp: getTimestamp(l1.EthBlockNum),
|
||||
L1Info: &l1Info{
|
||||
ToForgeL1TxsNum: l1.ToForgeL1TxsNum,
|
||||
UserOrigin: l1.UserOrigin,
|
||||
FromEthAddr: ethAddrToHez(l1.FromEthAddr),
|
||||
FromBJJ: bjjToString(l1.FromBJJ),
|
||||
LoadAmount: l1.LoadAmount.String(),
|
||||
EthBlockNum: l1.EthBlockNum,
|
||||
},
|
||||
Token: token,
|
||||
}
|
||||
if l1.FromIdx != 0 {
|
||||
idxStr := idxToHez(l1.FromIdx, token.Symbol)
|
||||
tx.FromIdx = &idxStr
|
||||
}
|
||||
if token.USD != nil {
|
||||
af := new(big.Float).SetInt(l1.Amount)
|
||||
amountFloat, _ := af.Float64()
|
||||
usd := *token.USD * amountFloat / math.Pow(10, float64(token.Decimals))
|
||||
tx.HistoricUSD = &usd
|
||||
laf := new(big.Float).SetInt(l1.LoadAmount)
|
||||
loadAmountFloat, _ := laf.Float64()
|
||||
loadUSD := *token.USD * loadAmountFloat / math.Pow(10, float64(token.Decimals))
|
||||
tx.L1Info.HistoricLoadAmountUSD = &loadUSD
|
||||
}
|
||||
allTxs = append(allTxs, tx)
|
||||
if isUsrTx(tx) {
|
||||
usrTxs = append(usrTxs, tx)
|
||||
}
|
||||
} else {
|
||||
// Add L2 tx to DB
|
||||
} else if l2 != nil {
|
||||
err = h.AddL2Txs([]common.L2Tx{*l2})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// L2Tx ==> historyTxAPI
|
||||
var tokenID common.TokenID
|
||||
found := false
|
||||
for _, acc := range accs {
|
||||
if acc.Idx == l2.FromIdx {
|
||||
found = true
|
||||
tokenID = acc.TokenID
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
panic("tokenID not found")
|
||||
}
|
||||
token := getToken(tokenID)
|
||||
tx := historyTxAPI{
|
||||
IsL1: "L2",
|
||||
TxID: l2.TxID,
|
||||
Type: l2.Type,
|
||||
Position: l2.Position,
|
||||
ToIdx: idxToHez(l2.ToIdx, token.Symbol),
|
||||
Amount: l2.Amount.String(),
|
||||
BatchNum: &l2.BatchNum,
|
||||
Timestamp: getTimestamp(l2.EthBlockNum),
|
||||
L2Info: &l2Info{
|
||||
Nonce: l2.Nonce,
|
||||
Fee: l2.Fee,
|
||||
},
|
||||
Token: token,
|
||||
}
|
||||
if l2.FromIdx != 0 {
|
||||
idxStr := idxToHez(l2.FromIdx, token.Symbol)
|
||||
tx.FromIdx = &idxStr
|
||||
}
|
||||
if token.USD != nil {
|
||||
af := new(big.Float).SetInt(l2.Amount)
|
||||
amountFloat, _ := af.Float64()
|
||||
usd := *token.USD * amountFloat / math.Pow(10, float64(token.Decimals))
|
||||
tx.HistoricUSD = &usd
|
||||
feeUSD := usd * l2.Fee.Percentage()
|
||||
tx.HistoricUSD = &usd
|
||||
tx.L2Info.HistoricFeeUSD = &feeUSD
|
||||
}
|
||||
allTxs = append(allTxs, tx)
|
||||
if isUsrTx(tx) {
|
||||
usrTxs = append(usrTxs, tx)
|
||||
}
|
||||
} else {
|
||||
panic("should be l1 or l2")
|
||||
}
|
||||
}
|
||||
|
||||
// Transform exits to API
|
||||
exitsToAPIExits := func(exits []common.ExitInfo, accs []common.Account, tokens []common.Token) []exitAPI {
|
||||
historyExits := []historydb.HistoryExit{}
|
||||
for _, exit := range exits {
|
||||
token := getTokenByIdx(exit.AccountIdx)
|
||||
token := getTokenByIdx(exit.AccountIdx, tokensUSD, accs)
|
||||
historyExits = append(historyExits, historydb.HistoryExit{
|
||||
BatchNum: exit.BatchNum,
|
||||
AccountIdx: exit.AccountIdx,
|
||||
@@ -521,109 +325,7 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Prepare pool Txs
|
||||
// Generate common.PoolL2Tx
|
||||
// WARNING: this should be replaced once transakcio is ready
|
||||
poolTxs := []common.PoolL2Tx{}
|
||||
amount := new(big.Int)
|
||||
amount, ok := amount.SetString("100000000000000", 10)
|
||||
if !ok {
|
||||
panic("bad amount")
|
||||
}
|
||||
poolTx := common.PoolL2Tx{
|
||||
FromIdx: accs[0].Idx,
|
||||
ToIdx: accs[1].Idx,
|
||||
Amount: amount,
|
||||
TokenID: accs[0].TokenID,
|
||||
Nonce: 6,
|
||||
}
|
||||
if _, err := common.NewPoolL2Tx(&poolTx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
h, err := poolTx.HashToSign()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
poolTx.Signature = privK.SignPoseidon(h).Compress()
|
||||
poolTxs = append(poolTxs, poolTx)
|
||||
// Transform to API formats
|
||||
poolTxsToSend := []receivedPoolTx{}
|
||||
poolTxsToReceive := []sendPoolTx{}
|
||||
for _, poolTx := range poolTxs {
|
||||
// common.PoolL2Tx ==> receivedPoolTx
|
||||
token := getToken(poolTx.TokenID)
|
||||
genSendTx := receivedPoolTx{
|
||||
TxID: poolTx.TxID,
|
||||
Type: poolTx.Type,
|
||||
TokenID: poolTx.TokenID,
|
||||
FromIdx: idxToHez(poolTx.FromIdx, token.Symbol),
|
||||
Amount: poolTx.Amount.String(),
|
||||
Fee: poolTx.Fee,
|
||||
Nonce: poolTx.Nonce,
|
||||
Signature: poolTx.Signature,
|
||||
RqFee: &poolTx.RqFee,
|
||||
RqNonce: &poolTx.RqNonce,
|
||||
}
|
||||
// common.PoolL2Tx ==> receivedPoolTx
|
||||
genReceiveTx := sendPoolTx{
|
||||
TxID: poolTx.TxID,
|
||||
Type: poolTx.Type,
|
||||
FromIdx: idxToHez(poolTx.FromIdx, token.Symbol),
|
||||
Amount: poolTx.Amount.String(),
|
||||
Fee: poolTx.Fee,
|
||||
Nonce: poolTx.Nonce,
|
||||
State: poolTx.State,
|
||||
Signature: poolTx.Signature,
|
||||
Timestamp: poolTx.Timestamp,
|
||||
// BatchNum: poolTx.BatchNum,
|
||||
RqFee: &poolTx.RqFee,
|
||||
RqNonce: &poolTx.RqNonce,
|
||||
Token: token,
|
||||
}
|
||||
if poolTx.ToIdx != 0 {
|
||||
toIdx := idxToHez(poolTx.ToIdx, token.Symbol)
|
||||
genSendTx.ToIdx = &toIdx
|
||||
genReceiveTx.ToIdx = &toIdx
|
||||
}
|
||||
if poolTx.ToEthAddr != common.EmptyAddr {
|
||||
toEth := ethAddrToHez(poolTx.ToEthAddr)
|
||||
genSendTx.ToEthAddr = &toEth
|
||||
genReceiveTx.ToEthAddr = &toEth
|
||||
}
|
||||
if poolTx.ToBJJ != nil {
|
||||
toBJJ := bjjToString(poolTx.ToBJJ)
|
||||
genSendTx.ToBJJ = &toBJJ
|
||||
genReceiveTx.ToBJJ = &toBJJ
|
||||
}
|
||||
if poolTx.RqFromIdx != 0 {
|
||||
rqFromIdx := idxToHez(poolTx.RqFromIdx, token.Symbol)
|
||||
genSendTx.RqFromIdx = &rqFromIdx
|
||||
genReceiveTx.RqFromIdx = &rqFromIdx
|
||||
genSendTx.RqTokenID = &token.TokenID
|
||||
genReceiveTx.RqTokenID = &token.TokenID
|
||||
rqAmount := poolTx.RqAmount.String()
|
||||
genSendTx.RqAmount = &rqAmount
|
||||
genReceiveTx.RqAmount = &rqAmount
|
||||
|
||||
if poolTx.RqToIdx != 0 {
|
||||
rqToIdx := idxToHez(poolTx.RqToIdx, token.Symbol)
|
||||
genSendTx.RqToIdx = &rqToIdx
|
||||
genReceiveTx.RqToIdx = &rqToIdx
|
||||
}
|
||||
if poolTx.RqToEthAddr != common.EmptyAddr {
|
||||
rqToEth := ethAddrToHez(poolTx.RqToEthAddr)
|
||||
genSendTx.RqToEthAddr = &rqToEth
|
||||
genReceiveTx.RqToEthAddr = &rqToEth
|
||||
}
|
||||
if poolTx.RqToBJJ != nil {
|
||||
rqToBJJ := bjjToString(poolTx.RqToBJJ)
|
||||
genSendTx.RqToBJJ = &rqToBJJ
|
||||
genReceiveTx.RqToBJJ = &rqToBJJ
|
||||
}
|
||||
}
|
||||
poolTxsToSend = append(poolTxsToSend, genSendTx)
|
||||
poolTxsToReceive = append(poolTxsToReceive, genReceiveTx)
|
||||
}
|
||||
// Coordinators
|
||||
const nCoords = 10
|
||||
coords := test.GenCoordinators(nCoords, blocks)
|
||||
@@ -647,6 +349,8 @@ func TestMain(m *testing.M) {
|
||||
apiAuths = append(apiAuths, *apiAuth)
|
||||
}
|
||||
// Set testCommon
|
||||
usrTxs, allTxs := genTestTxs(sortedTxs, usrIdxs, accs, tokensUSD, blocks)
|
||||
poolTxsToSend, poolTxsToReceive := genTestPoolTx(accs, []babyjub.PrivateKey{privK}, tokensUSD) // NOTE: pool txs are not inserted to the DB here. In the test they will be posted and getted.
|
||||
tc = testCommon{
|
||||
blocks: blocks,
|
||||
tokens: tokensUSD,
|
||||
@@ -667,8 +371,8 @@ func TestMain(m *testing.M) {
|
||||
// Fake server
|
||||
if os.Getenv("FAKE_SERVER") == "yes" {
|
||||
for {
|
||||
log.Info("Running fake server until ^C is received")
|
||||
time.Sleep(10 * time.Second)
|
||||
log.Info("Running fake server at " + apiURL + " until ^C is received")
|
||||
time.Sleep(30 * time.Second)
|
||||
}
|
||||
}
|
||||
// Run tests
|
||||
@@ -686,217 +390,6 @@ func TestMain(m *testing.M) {
|
||||
os.Exit(result)
|
||||
}
|
||||
|
||||
func TestGetHistoryTxs(t *testing.T) {
|
||||
endpoint := apiURL + "transactions-history"
|
||||
fetchedTxs := []historyTxAPI{}
|
||||
appendIter := func(intr interface{}) {
|
||||
for i := 0; i < len(intr.(*historyTxsAPI).Txs); i++ {
|
||||
tmp, err := copystructure.Copy(intr.(*historyTxsAPI).Txs[i])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fetchedTxs = append(fetchedTxs, tmp.(historyTxAPI))
|
||||
}
|
||||
}
|
||||
// Get all (no filters)
|
||||
limit := 8
|
||||
path := fmt.Sprintf("%s?limit=%d&fromItem=", endpoint, limit)
|
||||
err := doGoodReqPaginated(path, historydb.OrderAsc, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
assertHistoryTxAPIs(t, tc.allTxs, fetchedTxs)
|
||||
// Uncomment once tx generation for tests is fixed
|
||||
// // Get by ethAddr
|
||||
// fetchedTxs = []historyTxAPI{}
|
||||
// limit = 7
|
||||
// path = fmt.Sprintf(
|
||||
// "%s?hermezEthereumAddress=%s&limit=%d&fromItem=",
|
||||
// endpoint, tc.usrAddr, limit,
|
||||
// )
|
||||
// err = doGoodReqPaginated(path, historydb.OrderAsc, &historyTxsAPI{}, appendIter)
|
||||
// assert.NoError(t, err)
|
||||
// assertHistoryTxAPIs(t, tc.usrTxs, fetchedTxs)
|
||||
// // Get by bjj
|
||||
// fetchedTxs = []historyTxAPI{}
|
||||
// limit = 6
|
||||
// path = fmt.Sprintf(
|
||||
// "%s?BJJ=%s&limit=%d&fromItem=",
|
||||
// endpoint, tc.usrBjj, limit,
|
||||
// )
|
||||
// err = doGoodReqPaginated(path, historydb.OrderAsc, &historyTxsAPI{}, appendIter)
|
||||
// assert.NoError(t, err)
|
||||
// assertHistoryTxAPIs(t, tc.usrTxs, fetchedTxs)
|
||||
// Get by tokenID
|
||||
fetchedTxs = []historyTxAPI{}
|
||||
limit = 5
|
||||
tokenID := tc.allTxs[0].Token.TokenID
|
||||
path = fmt.Sprintf(
|
||||
"%s?tokenId=%d&limit=%d&fromItem=",
|
||||
endpoint, tokenID, limit,
|
||||
)
|
||||
err = doGoodReqPaginated(path, historydb.OrderAsc, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
tokenIDTxs := []historyTxAPI{}
|
||||
for i := 0; i < len(tc.allTxs); i++ {
|
||||
if tc.allTxs[i].Token.TokenID == tokenID {
|
||||
tokenIDTxs = append(tokenIDTxs, tc.allTxs[i])
|
||||
}
|
||||
}
|
||||
assertHistoryTxAPIs(t, tokenIDTxs, fetchedTxs)
|
||||
// idx
|
||||
fetchedTxs = []historyTxAPI{}
|
||||
limit = 4
|
||||
idx := tc.allTxs[0].ToIdx
|
||||
path = fmt.Sprintf(
|
||||
"%s?accountIndex=%s&limit=%d&fromItem=",
|
||||
endpoint, idx, limit,
|
||||
)
|
||||
err = doGoodReqPaginated(path, historydb.OrderAsc, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
idxTxs := []historyTxAPI{}
|
||||
for i := 0; i < len(tc.allTxs); i++ {
|
||||
if (tc.allTxs[i].FromIdx != nil && (*tc.allTxs[i].FromIdx)[6:] == idx[6:]) ||
|
||||
tc.allTxs[i].ToIdx[6:] == idx[6:] {
|
||||
idxTxs = append(idxTxs, tc.allTxs[i])
|
||||
}
|
||||
}
|
||||
assertHistoryTxAPIs(t, idxTxs, fetchedTxs)
|
||||
// batchNum
|
||||
fetchedTxs = []historyTxAPI{}
|
||||
limit = 3
|
||||
batchNum := tc.allTxs[0].BatchNum
|
||||
path = fmt.Sprintf(
|
||||
"%s?batchNum=%d&limit=%d&fromItem=",
|
||||
endpoint, *batchNum, limit,
|
||||
)
|
||||
err = doGoodReqPaginated(path, historydb.OrderAsc, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
batchNumTxs := []historyTxAPI{}
|
||||
for i := 0; i < len(tc.allTxs); i++ {
|
||||
if tc.allTxs[i].BatchNum != nil &&
|
||||
*tc.allTxs[i].BatchNum == *batchNum {
|
||||
batchNumTxs = append(batchNumTxs, tc.allTxs[i])
|
||||
}
|
||||
}
|
||||
assertHistoryTxAPIs(t, batchNumTxs, fetchedTxs)
|
||||
// type
|
||||
txTypes := []common.TxType{
|
||||
// Uncomment once test gen is fixed
|
||||
// common.TxTypeExit,
|
||||
// common.TxTypeTransfer,
|
||||
// common.TxTypeDeposit,
|
||||
common.TxTypeCreateAccountDeposit,
|
||||
// common.TxTypeCreateAccountDepositTransfer,
|
||||
// common.TxTypeDepositTransfer,
|
||||
common.TxTypeForceTransfer,
|
||||
// common.TxTypeForceExit,
|
||||
// common.TxTypeTransferToEthAddr,
|
||||
// common.TxTypeTransferToBJJ,
|
||||
}
|
||||
for _, txType := range txTypes {
|
||||
fetchedTxs = []historyTxAPI{}
|
||||
limit = 2
|
||||
path = fmt.Sprintf(
|
||||
"%s?type=%s&limit=%d&fromItem=",
|
||||
endpoint, txType, limit,
|
||||
)
|
||||
err = doGoodReqPaginated(path, historydb.OrderAsc, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
txTypeTxs := []historyTxAPI{}
|
||||
for i := 0; i < len(tc.allTxs); i++ {
|
||||
if tc.allTxs[i].Type == txType {
|
||||
txTypeTxs = append(txTypeTxs, tc.allTxs[i])
|
||||
}
|
||||
}
|
||||
assertHistoryTxAPIs(t, txTypeTxs, fetchedTxs)
|
||||
}
|
||||
// Multiple filters
|
||||
fetchedTxs = []historyTxAPI{}
|
||||
limit = 1
|
||||
path = fmt.Sprintf(
|
||||
"%s?batchNum=%d&tokenId=%d&limit=%d&fromItem=",
|
||||
endpoint, *batchNum, tokenID, limit,
|
||||
)
|
||||
err = doGoodReqPaginated(path, historydb.OrderAsc, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
mixedTxs := []historyTxAPI{}
|
||||
for i := 0; i < len(tc.allTxs); i++ {
|
||||
if tc.allTxs[i].BatchNum != nil {
|
||||
if *tc.allTxs[i].BatchNum == *batchNum && tc.allTxs[i].Token.TokenID == tokenID {
|
||||
mixedTxs = append(mixedTxs, tc.allTxs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
assertHistoryTxAPIs(t, mixedTxs, fetchedTxs)
|
||||
// All, in reverse order
|
||||
fetchedTxs = []historyTxAPI{}
|
||||
limit = 5
|
||||
path = fmt.Sprintf("%s?limit=%d&fromItem=", endpoint, limit)
|
||||
err = doGoodReqPaginated(path, historydb.OrderDesc, &historyTxsAPI{}, appendIter)
|
||||
assert.NoError(t, err)
|
||||
flipedTxs := []historyTxAPI{}
|
||||
for i := 0; i < len(tc.allTxs); i++ {
|
||||
flipedTxs = append(flipedTxs, tc.allTxs[len(tc.allTxs)-1-i])
|
||||
}
|
||||
assertHistoryTxAPIs(t, flipedTxs, fetchedTxs)
|
||||
// 400
|
||||
path = fmt.Sprintf(
|
||||
"%s?accountIndex=%s&hermezEthereumAddress=%s",
|
||||
endpoint, idx, tc.usrAddr,
|
||||
)
|
||||
err = doBadReq("GET", path, nil, 400)
|
||||
assert.NoError(t, err)
|
||||
path = fmt.Sprintf("%s?tokenId=X", endpoint)
|
||||
err = doBadReq("GET", path, nil, 400)
|
||||
assert.NoError(t, err)
|
||||
// 404
|
||||
path = fmt.Sprintf("%s?batchNum=999999", endpoint)
|
||||
err = doBadReq("GET", path, nil, 404)
|
||||
assert.NoError(t, err)
|
||||
path = fmt.Sprintf("%s?limit=1000&fromItem=999999", endpoint)
|
||||
err = doBadReq("GET", path, nil, 404)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestGetHistoryTx(t *testing.T) {
|
||||
// Get all txs by their ID
|
||||
endpoint := apiURL + "transactions-history/"
|
||||
fetchedTxs := []historyTxAPI{}
|
||||
for _, tx := range tc.allTxs {
|
||||
fetchedTx := historyTxAPI{}
|
||||
assert.NoError(t, doGoodReq("GET", endpoint+tx.TxID.String(), nil, &fetchedTx))
|
||||
fetchedTxs = append(fetchedTxs, fetchedTx)
|
||||
}
|
||||
assertHistoryTxAPIs(t, tc.allTxs, fetchedTxs)
|
||||
// 400
|
||||
err := doBadReq("GET", endpoint+"0x001", nil, 400)
|
||||
assert.NoError(t, err)
|
||||
// 404
|
||||
err = doBadReq("GET", endpoint+"0x00000000000001e240004700", nil, 404)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func assertHistoryTxAPIs(t *testing.T, expected, actual []historyTxAPI) {
|
||||
require.Equal(t, len(expected), len(actual))
|
||||
for i := 0; i < len(actual); i++ { //nolint len(actual) won't change within the loop
|
||||
actual[i].ItemID = 0
|
||||
assert.Equal(t, expected[i].Timestamp.Unix(), actual[i].Timestamp.Unix())
|
||||
expected[i].Timestamp = actual[i].Timestamp
|
||||
if expected[i].Token.USDUpdate == nil {
|
||||
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 {
|
||||
test.AssertUSD(t, expected[i].L2Info.HistoricFeeUSD, actual[i].L2Info.HistoricFeeUSD)
|
||||
} else {
|
||||
test.AssertUSD(t, expected[i].L1Info.HistoricLoadAmountUSD, actual[i].L1Info.HistoricLoadAmountUSD)
|
||||
}
|
||||
assert.Equal(t, expected[i], actual[i])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetExits(t *testing.T) {
|
||||
endpoint := apiURL + "exits"
|
||||
fetchedExits := []exitAPI{}
|
||||
@@ -1078,89 +571,6 @@ func TestGetConfig(t *testing.T) {
|
||||
assert.Equal(t, cg, &configTest)
|
||||
}
|
||||
|
||||
func TestPoolTxs(t *testing.T) {
|
||||
// POST
|
||||
endpoint := apiURL + "transactions-pool"
|
||||
fetchedTxID := common.TxID{}
|
||||
for _, tx := range tc.poolTxsToSend {
|
||||
jsonTxBytes, err := json.Marshal(tx)
|
||||
assert.NoError(t, err)
|
||||
jsonTxReader := bytes.NewReader(jsonTxBytes)
|
||||
assert.NoError(
|
||||
t, doGoodReq(
|
||||
"POST",
|
||||
endpoint,
|
||||
jsonTxReader, &fetchedTxID,
|
||||
),
|
||||
)
|
||||
assert.Equal(t, tx.TxID, fetchedTxID)
|
||||
}
|
||||
// 400
|
||||
// Wrong signature
|
||||
badTx := tc.poolTxsToSend[0]
|
||||
badTx.FromIdx = "hez:foo:1000"
|
||||
jsonTxBytes, err := json.Marshal(badTx)
|
||||
assert.NoError(t, err)
|
||||
jsonTxReader := bytes.NewReader(jsonTxBytes)
|
||||
err = doBadReq("POST", endpoint, jsonTxReader, 400)
|
||||
assert.NoError(t, err)
|
||||
// Wrong to
|
||||
badTx = tc.poolTxsToSend[0]
|
||||
ethAddr := "hez:0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
badTx.ToEthAddr = ðAddr
|
||||
badTx.ToIdx = nil
|
||||
jsonTxBytes, err = json.Marshal(badTx)
|
||||
assert.NoError(t, err)
|
||||
jsonTxReader = bytes.NewReader(jsonTxBytes)
|
||||
err = doBadReq("POST", endpoint, jsonTxReader, 400)
|
||||
assert.NoError(t, err)
|
||||
// Wrong rq
|
||||
badTx = tc.poolTxsToSend[0]
|
||||
rqFromIdx := "hez:foo:30"
|
||||
badTx.RqFromIdx = &rqFromIdx
|
||||
jsonTxBytes, err = json.Marshal(badTx)
|
||||
assert.NoError(t, err)
|
||||
jsonTxReader = bytes.NewReader(jsonTxBytes)
|
||||
err = doBadReq("POST", endpoint, jsonTxReader, 400)
|
||||
assert.NoError(t, err)
|
||||
// GET
|
||||
endpoint += "/"
|
||||
for _, tx := range tc.poolTxsToReceive {
|
||||
fetchedTx := sendPoolTx{}
|
||||
assert.NoError(
|
||||
t, doGoodReq(
|
||||
"GET",
|
||||
endpoint+tx.TxID.String(),
|
||||
nil, &fetchedTx,
|
||||
),
|
||||
)
|
||||
assertPoolTx(t, tx, fetchedTx)
|
||||
}
|
||||
// 400
|
||||
err = doBadReq("GET", endpoint+"0xG20000000156660000000090", nil, 400)
|
||||
assert.NoError(t, err)
|
||||
// 404
|
||||
err = doBadReq("GET", endpoint+"0x020000000156660000000090", nil, 404)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func assertPoolTx(t *testing.T, expected, actual sendPoolTx) {
|
||||
// state should be pending
|
||||
assert.Equal(t, common.PoolL2TxStatePending, actual.State)
|
||||
expected.State = actual.State
|
||||
// timestamp should be very close to now
|
||||
assert.Less(t, time.Now().UTC().Unix()-3, actual.Timestamp.Unix())
|
||||
expected.Timestamp = actual.Timestamp
|
||||
// token timestamp
|
||||
if expected.Token.USDUpdate == nil {
|
||||
assert.Equal(t, expected.Token.USDUpdate, actual.Token.USDUpdate)
|
||||
} else {
|
||||
assert.Equal(t, expected.Token.USDUpdate.Unix(), actual.Token.USDUpdate.Unix())
|
||||
expected.Token.USDUpdate = actual.Token.USDUpdate
|
||||
}
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestAccountCreationAuth(t *testing.T) {
|
||||
// POST
|
||||
endpoint := apiURL + "account-creation-authorization"
|
||||
@@ -1368,3 +778,41 @@ func doBadReq(method, path string, reqBody io.Reader, expectedResponseCode int)
|
||||
responseValidationInput = responseValidationInput.SetBodyBytes(body)
|
||||
return swagger.ValidateResponse(ctx, responseValidationInput)
|
||||
}
|
||||
|
||||
// test helpers
|
||||
|
||||
func getTimestamp(blockNum int64, blocks []common.Block) time.Time {
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
if blocks[i].EthBlockNum == blockNum {
|
||||
return blocks[i].Timestamp
|
||||
}
|
||||
}
|
||||
panic("timesamp not found")
|
||||
}
|
||||
|
||||
func getTokenByID(id common.TokenID, tokens []historydb.TokenWithUSD) historydb.TokenWithUSD {
|
||||
for i := 0; i < len(tokens); i++ {
|
||||
if tokens[i].TokenID == id {
|
||||
return tokens[i]
|
||||
}
|
||||
}
|
||||
panic("token not found")
|
||||
}
|
||||
|
||||
func getTokenByIdx(idx common.Idx, tokens []historydb.TokenWithUSD, accs []common.Account) historydb.TokenWithUSD {
|
||||
for _, acc := range accs {
|
||||
if idx == acc.Idx {
|
||||
return getTokenByID(acc.TokenID, tokens)
|
||||
}
|
||||
}
|
||||
panic("token not found")
|
||||
}
|
||||
|
||||
func getAccountByIdx(idx common.Idx, accs []common.Account) *common.Account {
|
||||
for _, acc := range accs {
|
||||
if acc.Idx == idx {
|
||||
return &acc
|
||||
}
|
||||
}
|
||||
panic("account not found")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user