@ -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 ( 1 0 * time . Second )
log . Info ( "Running fake server at " + apiURL + " until ^C is received" )
time . Sleep ( 3 0 * 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 = & ethAddr
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" )
}