You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

672 lines
18 KiB

4 years ago
4 years ago
Redo coordinator structure, connect API to node - API: - Modify the constructor so that hardcoded rollup constants don't need to be passed (introduce a `Config` and use `configAPI` internally) - Common: - Update rollup constants with proper *big.Int when required - Add BidCoordinator and Slot structs used by the HistoryDB and Synchronizer. - Add helper methods to AuctionConstants - AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL table: `default_slot_set_bid_slot_num`), which indicates at which slotNum does the `DefaultSlotSetBid` specified starts applying. - Config: - Move coordinator exclusive configuration from the node config to the coordinator config - Coordinator: - Reorganize the code towards having the goroutines started and stopped from the coordinator itself instead of the node. - Remove all stop and stopped channels, and use context.Context and sync.WaitGroup instead. - Remove BatchInfo setters and assing variables directly - In ServerProof and ServerProofPool use context instead stop channel. - Use message passing to notify the coordinator about sync updates and reorgs - Introduce the Pipeline, which can be started and stopped by the Coordinator - Introduce the TxManager, which manages ethereum transactions (the TxManager is also in charge of making the forge call to the rollup smart contract). The TxManager keeps ethereum transactions and: 1. Waits for the transaction to be accepted 2. Waits for the transaction to be confirmed for N blocks - In forge logic, first prepare a batch and then wait for an available server proof to have all work ready once the proof server is ready. - Remove the `isForgeSequence` method which was querying the smart contract, and instead use notifications sent by the Synchronizer to figure out if it's forging time. - Update test (which is a minimal test to manually see if the coordinator starts) - HistoryDB: - Add method to get the number of batches in a slot (used to detect when a slot has passed the bid winner forging deadline) - Add method to get the best bid and associated coordinator of a slot (used to detect the forgerAddress that can forge the slot) - General: - Rename some instances of `currentBlock` to `lastBlock` to be more clear. - Node: - Connect the API to the node and call the methods to update cached state when the sync advances blocks. - Call methods to update Coordinator state when the sync advances blocks and finds reorgs. - Synchronizer: - Add Auction field in the Stats, which contain the current slot with info about highest bidder and other related info required to know who can forge in the current block. - Better organization of cached state: - On Sync, update the internal cached state - On Init or Reorg, load the state from HistoryDB into the internal cached state.
4 years ago
Redo coordinator structure, connect API to node - API: - Modify the constructor so that hardcoded rollup constants don't need to be passed (introduce a `Config` and use `configAPI` internally) - Common: - Update rollup constants with proper *big.Int when required - Add BidCoordinator and Slot structs used by the HistoryDB and Synchronizer. - Add helper methods to AuctionConstants - AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL table: `default_slot_set_bid_slot_num`), which indicates at which slotNum does the `DefaultSlotSetBid` specified starts applying. - Config: - Move coordinator exclusive configuration from the node config to the coordinator config - Coordinator: - Reorganize the code towards having the goroutines started and stopped from the coordinator itself instead of the node. - Remove all stop and stopped channels, and use context.Context and sync.WaitGroup instead. - Remove BatchInfo setters and assing variables directly - In ServerProof and ServerProofPool use context instead stop channel. - Use message passing to notify the coordinator about sync updates and reorgs - Introduce the Pipeline, which can be started and stopped by the Coordinator - Introduce the TxManager, which manages ethereum transactions (the TxManager is also in charge of making the forge call to the rollup smart contract). The TxManager keeps ethereum transactions and: 1. Waits for the transaction to be accepted 2. Waits for the transaction to be confirmed for N blocks - In forge logic, first prepare a batch and then wait for an available server proof to have all work ready once the proof server is ready. - Remove the `isForgeSequence` method which was querying the smart contract, and instead use notifications sent by the Synchronizer to figure out if it's forging time. - Update test (which is a minimal test to manually see if the coordinator starts) - HistoryDB: - Add method to get the number of batches in a slot (used to detect when a slot has passed the bid winner forging deadline) - Add method to get the best bid and associated coordinator of a slot (used to detect the forgerAddress that can forge the slot) - General: - Rename some instances of `currentBlock` to `lastBlock` to be more clear. - Node: - Connect the API to the node and call the methods to update cached state when the sync advances blocks. - Call methods to update Coordinator state when the sync advances blocks and finds reorgs. - Synchronizer: - Add Auction field in the Stats, which contain the current slot with info about highest bidder and other related info required to know who can forge in the current block. - Better organization of cached state: - On Sync, update the internal cached state - On Init or Reorg, load the state from HistoryDB into the internal cached state.
4 years ago
Redo coordinator structure, connect API to node - API: - Modify the constructor so that hardcoded rollup constants don't need to be passed (introduce a `Config` and use `configAPI` internally) - Common: - Update rollup constants with proper *big.Int when required - Add BidCoordinator and Slot structs used by the HistoryDB and Synchronizer. - Add helper methods to AuctionConstants - AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL table: `default_slot_set_bid_slot_num`), which indicates at which slotNum does the `DefaultSlotSetBid` specified starts applying. - Config: - Move coordinator exclusive configuration from the node config to the coordinator config - Coordinator: - Reorganize the code towards having the goroutines started and stopped from the coordinator itself instead of the node. - Remove all stop and stopped channels, and use context.Context and sync.WaitGroup instead. - Remove BatchInfo setters and assing variables directly - In ServerProof and ServerProofPool use context instead stop channel. - Use message passing to notify the coordinator about sync updates and reorgs - Introduce the Pipeline, which can be started and stopped by the Coordinator - Introduce the TxManager, which manages ethereum transactions (the TxManager is also in charge of making the forge call to the rollup smart contract). The TxManager keeps ethereum transactions and: 1. Waits for the transaction to be accepted 2. Waits for the transaction to be confirmed for N blocks - In forge logic, first prepare a batch and then wait for an available server proof to have all work ready once the proof server is ready. - Remove the `isForgeSequence` method which was querying the smart contract, and instead use notifications sent by the Synchronizer to figure out if it's forging time. - Update test (which is a minimal test to manually see if the coordinator starts) - HistoryDB: - Add method to get the number of batches in a slot (used to detect when a slot has passed the bid winner forging deadline) - Add method to get the best bid and associated coordinator of a slot (used to detect the forgerAddress that can forge the slot) - General: - Rename some instances of `currentBlock` to `lastBlock` to be more clear. - Node: - Connect the API to the node and call the methods to update cached state when the sync advances blocks. - Call methods to update Coordinator state when the sync advances blocks and finds reorgs. - Synchronizer: - Add Auction field in the Stats, which contain the current slot with info about highest bidder and other related info required to know who can forge in the current block. - Better organization of cached state: - On Sync, update the internal cached state - On Init or Reorg, load the state from HistoryDB into the internal cached state.
4 years ago
3 years ago
Update coordinator, call all api update functions - Common: - Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition - API: - Add UpdateNetworkInfoBlock to update just block information, to be used when the node is not yet synchronized - Node: - Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with configurable time intervals - Synchronizer: - When mapping events by TxHash, use an array to support the possibility of multiple calls of the same function happening in the same transaction (for example, a smart contract in a single transaction could call withdraw with delay twice, which would generate 2 withdraw events, and 2 deposit events). - In Stats, keep entire LastBlock instead of just the blockNum - In Stats, add lastL1BatchBlock - Test Stats and SCVars - Coordinator: - Enable writing the BatchInfo in every step of the pipeline to disk (with JSON text files) for debugging purposes. - Move the Pipeline functionality from the Coordinator to its own struct (Pipeline) - Implement shouldL1lL2Batch - In TxManager, implement logic to perform several attempts when doing ethereum node RPC calls before considering the error. (Both for calls to forgeBatch and transaction receipt) - In TxManager, reorganize the flow and note the specific points in which actions are made when err != nil - HistoryDB: - Implement GetLastL1BatchBlockNum: returns the blockNum of the latest forged l1Batch, to help the coordinator decide when to forge an L1Batch. - EthereumClient and test.Client: - Update EthBlockByNumber to return the last block when the passed number is -1.
4 years ago
Update coordinator, call all api update functions - Common: - Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition - API: - Add UpdateNetworkInfoBlock to update just block information, to be used when the node is not yet synchronized - Node: - Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with configurable time intervals - Synchronizer: - When mapping events by TxHash, use an array to support the possibility of multiple calls of the same function happening in the same transaction (for example, a smart contract in a single transaction could call withdraw with delay twice, which would generate 2 withdraw events, and 2 deposit events). - In Stats, keep entire LastBlock instead of just the blockNum - In Stats, add lastL1BatchBlock - Test Stats and SCVars - Coordinator: - Enable writing the BatchInfo in every step of the pipeline to disk (with JSON text files) for debugging purposes. - Move the Pipeline functionality from the Coordinator to its own struct (Pipeline) - Implement shouldL1lL2Batch - In TxManager, implement logic to perform several attempts when doing ethereum node RPC calls before considering the error. (Both for calls to forgeBatch and transaction receipt) - In TxManager, reorganize the flow and note the specific points in which actions are made when err != nil - HistoryDB: - Implement GetLastL1BatchBlockNum: returns the blockNum of the latest forged l1Batch, to help the coordinator decide when to forge an L1Batch. - EthereumClient and test.Client: - Update EthBlockByNumber to return the last block when the passed number is -1.
4 years ago
Update coordinator, call all api update functions - Common: - Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition - API: - Add UpdateNetworkInfoBlock to update just block information, to be used when the node is not yet synchronized - Node: - Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with configurable time intervals - Synchronizer: - When mapping events by TxHash, use an array to support the possibility of multiple calls of the same function happening in the same transaction (for example, a smart contract in a single transaction could call withdraw with delay twice, which would generate 2 withdraw events, and 2 deposit events). - In Stats, keep entire LastBlock instead of just the blockNum - In Stats, add lastL1BatchBlock - Test Stats and SCVars - Coordinator: - Enable writing the BatchInfo in every step of the pipeline to disk (with JSON text files) for debugging purposes. - Move the Pipeline functionality from the Coordinator to its own struct (Pipeline) - Implement shouldL1lL2Batch - In TxManager, implement logic to perform several attempts when doing ethereum node RPC calls before considering the error. (Both for calls to forgeBatch and transaction receipt) - In TxManager, reorganize the flow and note the specific points in which actions are made when err != nil - HistoryDB: - Implement GetLastL1BatchBlockNum: returns the blockNum of the latest forged l1Batch, to help the coordinator decide when to forge an L1Batch. - EthereumClient and test.Client: - Update EthBlockByNumber to return the last block when the passed number is -1.
4 years ago
  1. package api
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "math/big"
  10. "net/http"
  11. "os"
  12. "strconv"
  13. "testing"
  14. "time"
  15. ethCommon "github.com/ethereum/go-ethereum/common"
  16. swagger "github.com/getkin/kin-openapi/openapi3filter"
  17. "github.com/gin-gonic/gin"
  18. "github.com/hermeznetwork/hermez-node/common"
  19. "github.com/hermeznetwork/hermez-node/db"
  20. "github.com/hermeznetwork/hermez-node/db/historydb"
  21. "github.com/hermeznetwork/hermez-node/db/l2db"
  22. "github.com/hermeznetwork/hermez-node/db/statedb"
  23. "github.com/hermeznetwork/hermez-node/log"
  24. "github.com/hermeznetwork/hermez-node/test"
  25. "github.com/hermeznetwork/hermez-node/test/til"
  26. "github.com/hermeznetwork/tracerr"
  27. )
  28. // Pendinger is an interface that allows getting last returned item ID and PendingItems to be used for building fromItem
  29. // when testing paginated endpoints.
  30. type Pendinger interface {
  31. GetPending() (pendingItems, lastItemID uint64)
  32. Len() int
  33. New() Pendinger
  34. }
  35. const apiPort = ":4010"
  36. const apiURL = "http://localhost" + apiPort + "/"
  37. var SetBlockchain = `
  38. Type: Blockchain
  39. AddToken(1)
  40. AddToken(2)
  41. AddToken(3)
  42. AddToken(4)
  43. AddToken(5)
  44. AddToken(6)
  45. AddToken(7)
  46. AddToken(8)
  47. > block
  48. // Coordinator accounts, Idxs: 256, 257
  49. CreateAccountCoordinator(0) Coord
  50. CreateAccountCoordinator(1) Coord
  51. // close Block:0, Batch:0
  52. > batch
  53. CreateAccountDeposit(0) A: 11111111100000000000
  54. CreateAccountDeposit(1) C: 22222222200000000000
  55. CreateAccountCoordinator(0) C
  56. // close Block:0, Batch:1
  57. > batchL1
  58. // Expected balances:
  59. // Coord(0): 0, Coord(1): 0
  60. // C(0): 0
  61. CreateAccountDeposit(1) A: 33333333300000000000
  62. // close Block:0, Batch:2
  63. > batchL1
  64. // close Block:0, Batch:3
  65. > batchL1
  66. CreateAccountDepositTransfer(0) B-A: 44444444400000000000, 123444444400000000000
  67. // close Block:0, Batch:4
  68. > batchL1
  69. CreateAccountDeposit(0) D: 55555555500000000000
  70. // close Block:0, Batch:5
  71. > batchL1
  72. CreateAccountCoordinator(1) B
  73. Transfer(1) A-B: 11111100000000000 (2)
  74. Transfer(0) B-C: 22222200000000000 (3)
  75. // close Block:0, Batch:6
  76. > batchL1 // forge L1User{1}, forge L1Coord{2}, forge L2{2}
  77. Deposit(0) C: 66666666600000000000
  78. DepositTransfer(0) C-D: 77777777700000000000, 12377777700000000000
  79. Transfer(0) A-B: 33333300000000000 (111)
  80. Transfer(0) C-A: 44444400000000000 (222)
  81. Transfer(1) B-C: 55555500000000000 (123)
  82. Exit(0) A: 66666600000000000 (44)
  83. ForceTransfer(0) D-B: 77777700000000000
  84. ForceExit(0) B: 88888800000000000
  85. // close Block:0, Batch:7
  86. > batchL1
  87. > block
  88. Transfer(0) D-A: 99999900000000000 (77)
  89. Transfer(0) B-D: 12312300000000000 (55)
  90. // close Block:1, Batch:0
  91. > batchL1
  92. CreateAccountCoordinator(0) F
  93. CreateAccountCoordinator(0) G
  94. CreateAccountCoordinator(0) H
  95. CreateAccountCoordinator(0) I
  96. CreateAccountCoordinator(0) J
  97. CreateAccountCoordinator(0) K
  98. CreateAccountCoordinator(0) L
  99. CreateAccountCoordinator(0) M
  100. CreateAccountCoordinator(0) N
  101. CreateAccountCoordinator(0) O
  102. CreateAccountCoordinator(0) P
  103. CreateAccountCoordinator(5) G
  104. CreateAccountCoordinator(5) H
  105. CreateAccountCoordinator(5) I
  106. CreateAccountCoordinator(5) J
  107. CreateAccountCoordinator(5) K
  108. CreateAccountCoordinator(5) L
  109. CreateAccountCoordinator(5) M
  110. CreateAccountCoordinator(5) N
  111. CreateAccountCoordinator(5) O
  112. CreateAccountCoordinator(5) P
  113. CreateAccountCoordinator(2) G
  114. CreateAccountCoordinator(2) H
  115. CreateAccountCoordinator(2) I
  116. CreateAccountCoordinator(2) J
  117. CreateAccountCoordinator(2) K
  118. CreateAccountCoordinator(2) L
  119. CreateAccountCoordinator(2) M
  120. CreateAccountCoordinator(2) N
  121. CreateAccountCoordinator(2) O
  122. CreateAccountCoordinator(2) P
  123. > batch
  124. > block
  125. > batch
  126. > block
  127. > batch
  128. > block
  129. `
  130. type testCommon struct {
  131. blocks []common.Block
  132. tokens []historydb.TokenWithUSD
  133. batches []testBatch
  134. fullBatches []testFullBatch
  135. coordinators []historydb.CoordinatorAPI
  136. accounts []testAccount
  137. txs []testTx
  138. exits []testExit
  139. poolTxsToSend []testPoolTxSend
  140. poolTxsToReceive []testPoolTxReceive
  141. auths []testAuth
  142. router *swagger.Router
  143. bids []testBid
  144. slots []testSlot
  145. auctionVars common.AuctionVariables
  146. rollupVars common.RollupVariables
  147. wdelayerVars common.WDelayerVariables
  148. }
  149. var tc testCommon
  150. var config configAPI
  151. var api *API
  152. // TestMain initializes the API server, and fill HistoryDB and StateDB with fake data,
  153. // emulating the task of the synchronizer in order to have data to be returned
  154. // by the API endpoints that will be tested
  155. func TestMain(m *testing.M) {
  156. // Initializations
  157. // Swagger
  158. router := swagger.NewRouter().WithSwaggerFromFile("./swagger.yml")
  159. // HistoryDB
  160. pass := os.Getenv("POSTGRES_PASS")
  161. database, err := db.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
  162. if err != nil {
  163. panic(err)
  164. }
  165. hdb := historydb.NewHistoryDB(database)
  166. if err != nil {
  167. panic(err)
  168. }
  169. // StateDB
  170. dir, err := ioutil.TempDir("", "tmpdb")
  171. if err != nil {
  172. panic(err)
  173. }
  174. defer func() {
  175. if err := os.RemoveAll(dir); err != nil {
  176. panic(err)
  177. }
  178. }()
  179. chainID := uint16(0)
  180. sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeTxSelector, 0, chainID)
  181. if err != nil {
  182. panic(err)
  183. }
  184. // L2DB
  185. l2DB := l2db.NewL2DB(database, 10, 100, 24*time.Hour)
  186. test.WipeDB(l2DB.DB()) // this will clean HistoryDB and L2DB
  187. // Config (smart contract constants)
  188. _config := getConfigTest(chainID)
  189. config = configAPI{
  190. RollupConstants: *newRollupConstants(_config.RollupConstants),
  191. AuctionConstants: _config.AuctionConstants,
  192. WDelayerConstants: _config.WDelayerConstants,
  193. }
  194. // API
  195. apiGin := gin.Default()
  196. api, err = NewAPI(
  197. true,
  198. true,
  199. apiGin,
  200. hdb,
  201. sdb,
  202. l2DB,
  203. &_config,
  204. )
  205. if err != nil {
  206. panic(err)
  207. }
  208. // Start server
  209. server := &http.Server{Addr: apiPort, Handler: apiGin}
  210. go func() {
  211. if err := server.ListenAndServe(); err != nil && tracerr.Unwrap(err) != http.ErrServerClosed {
  212. panic(err)
  213. }
  214. }()
  215. // Reset DB
  216. test.WipeDB(api.h.DB())
  217. // Genratre blockchain data with til
  218. tcc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  219. tilCfgExtra := til.ConfigExtra{
  220. BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
  221. CoordUser: "Coord",
  222. }
  223. blocksData, err := tcc.GenerateBlocks(SetBlockchain)
  224. if err != nil {
  225. panic(err)
  226. }
  227. err = tcc.FillBlocksExtra(blocksData, &tilCfgExtra)
  228. if err != nil {
  229. panic(err)
  230. }
  231. AddAditionalInformation(blocksData)
  232. // Generate L2 Txs with til
  233. commonPoolTxs, err := tcc.GeneratePoolL2Txs(til.SetPoolL2MinimumFlow0)
  234. if err != nil {
  235. panic(err)
  236. }
  237. // Extract til generated data, and add it to HistoryDB
  238. var commonBlocks []common.Block
  239. var commonBatches []common.Batch
  240. var commonAccounts []common.Account
  241. var commonExitTree []common.ExitInfo
  242. var commonL1Txs []common.L1Tx
  243. var commonL2Txs []common.L2Tx
  244. // Add ETH token at the beginning of the array
  245. testTokens := []historydb.TokenWithUSD{}
  246. ethUSD := float64(500)
  247. ethNow := time.Now()
  248. testTokens = append(testTokens, historydb.TokenWithUSD{
  249. TokenID: test.EthToken.TokenID,
  250. EthBlockNum: test.EthToken.EthBlockNum,
  251. EthAddr: test.EthToken.EthAddr,
  252. Name: test.EthToken.Name,
  253. Symbol: test.EthToken.Symbol,
  254. Decimals: test.EthToken.Decimals,
  255. USD: &ethUSD,
  256. USDUpdate: &ethNow,
  257. })
  258. err = api.h.UpdateTokenValue(test.EthToken.Symbol, ethUSD)
  259. if err != nil {
  260. panic(err)
  261. }
  262. for _, block := range blocksData {
  263. // Insert block into HistoryDB
  264. // nolint reason: block is used as read only in the function
  265. if err := api.h.AddBlockSCData(&block); err != nil { //nolint:gosec
  266. panic(err)
  267. }
  268. // Extract data
  269. commonBlocks = append(commonBlocks, block.Block)
  270. for i, tkn := range block.Rollup.AddedTokens {
  271. token := historydb.TokenWithUSD{
  272. TokenID: tkn.TokenID,
  273. EthBlockNum: tkn.EthBlockNum,
  274. EthAddr: tkn.EthAddr,
  275. Name: tkn.Name,
  276. Symbol: tkn.Symbol,
  277. Decimals: tkn.Decimals,
  278. }
  279. value := float64(i + 423)
  280. now := time.Now().UTC()
  281. token.USD = &value
  282. token.USDUpdate = &now
  283. // Set value in DB
  284. err = api.h.UpdateTokenValue(token.Symbol, value)
  285. if err != nil {
  286. panic(err)
  287. }
  288. testTokens = append(testTokens, token)
  289. }
  290. // Set USD value for tokens in DB
  291. commonL1Txs = append(commonL1Txs, block.Rollup.L1UserTxs...)
  292. for _, batch := range block.Rollup.Batches {
  293. commonL2Txs = append(commonL2Txs, batch.L2Txs...)
  294. for i := range batch.CreatedAccounts {
  295. batch.CreatedAccounts[i].Nonce = common.Nonce(i)
  296. commonAccounts = append(commonAccounts, batch.CreatedAccounts[i])
  297. }
  298. commonBatches = append(commonBatches, batch.Batch)
  299. commonExitTree = append(commonExitTree, batch.ExitTree...)
  300. commonL1Txs = append(commonL1Txs, batch.L1CoordinatorTxs...)
  301. }
  302. }
  303. // lastBlockNum2 := blocksData[len(blocksData)-1].Block.EthBlockNum
  304. // Add accounts to StateDB
  305. for i := 0; i < len(commonAccounts); i++ {
  306. if _, err := api.s.CreateAccount(commonAccounts[i].Idx, &commonAccounts[i]); err != nil {
  307. panic(err)
  308. }
  309. }
  310. // Generate Coordinators and add them to HistoryDB
  311. const nCoords = 10
  312. commonCoords := test.GenCoordinators(nCoords, commonBlocks)
  313. if err := api.h.AddCoordinators(commonCoords); err != nil {
  314. panic(err)
  315. }
  316. // Generate Bids and add them to HistoryDB
  317. const nBids = 20
  318. commonBids := test.GenBids(nBids, commonBlocks, commonCoords)
  319. if err = api.h.AddBids(commonBids); err != nil {
  320. panic(err)
  321. }
  322. // Generate SC vars and add them to HistoryDB (if needed)
  323. var defaultSlotSetBid [6]*big.Int = [6]*big.Int{big.NewInt(10), big.NewInt(10), big.NewInt(10), big.NewInt(10), big.NewInt(10), big.NewInt(10)}
  324. auctionVars := common.AuctionVariables{
  325. EthBlockNum: int64(2),
  326. DonationAddress: ethCommon.HexToAddress("0x1111111111111111111111111111111111111111"),
  327. DefaultSlotSetBid: defaultSlotSetBid,
  328. Outbidding: uint16(1),
  329. SlotDeadline: uint8(20),
  330. BootCoordinator: ethCommon.HexToAddress("0x1111111111111111111111111111111111111111"),
  331. BootCoordinatorURL: "https://boot.coordinator.io",
  332. ClosedAuctionSlots: uint16(2),
  333. OpenAuctionSlots: uint16(5),
  334. }
  335. var buckets [common.RollupConstNumBuckets]common.BucketParams
  336. for i := range buckets {
  337. buckets[i].CeilUSD = big.NewInt(int64(i) * 10)
  338. buckets[i].Withdrawals = big.NewInt(int64(i) * 100)
  339. buckets[i].BlockWithdrawalRate = big.NewInt(int64(i) * 1000)
  340. buckets[i].MaxWithdrawals = big.NewInt(int64(i) * 10000)
  341. }
  342. rollupVars := common.RollupVariables{
  343. EthBlockNum: int64(3),
  344. FeeAddToken: big.NewInt(100),
  345. ForgeL1L2BatchTimeout: int64(44),
  346. WithdrawalDelay: uint64(3000),
  347. Buckets: buckets,
  348. SafeMode: false,
  349. }
  350. wdelayerVars := common.WDelayerVariables{
  351. WithdrawalDelay: uint64(3000),
  352. }
  353. err = api.h.AddAuctionVars(&auctionVars)
  354. if err != nil {
  355. panic(err)
  356. }
  357. // Generate test data, as expected to be received/sended from/to the API
  358. testCoords := genTestCoordinators(commonCoords)
  359. testBids := genTestBids(commonBlocks, testCoords, commonBids)
  360. testExits := genTestExits(commonExitTree, testTokens, commonAccounts)
  361. testTxs := genTestTxs(commonL1Txs, commonL2Txs, commonAccounts, testTokens, commonBlocks)
  362. testBatches, testFullBatches := genTestBatches(commonBlocks, commonBatches, testTxs)
  363. poolTxsToSend, poolTxsToReceive := genTestPoolTxs(commonPoolTxs, testTokens, commonAccounts)
  364. tc = testCommon{
  365. blocks: commonBlocks,
  366. tokens: testTokens,
  367. batches: testBatches,
  368. fullBatches: testFullBatches,
  369. coordinators: testCoords,
  370. accounts: genTestAccounts(commonAccounts, testTokens),
  371. txs: testTxs,
  372. exits: testExits,
  373. poolTxsToSend: poolTxsToSend,
  374. poolTxsToReceive: poolTxsToReceive,
  375. auths: genTestAuths(test.GenAuths(5, _config.ChainID, _config.HermezAddress)),
  376. router: router,
  377. bids: testBids,
  378. slots: api.genTestSlots(
  379. 20,
  380. commonBlocks[len(commonBlocks)-1].Num,
  381. testBids,
  382. auctionVars,
  383. ),
  384. auctionVars: auctionVars,
  385. rollupVars: rollupVars,
  386. wdelayerVars: wdelayerVars,
  387. }
  388. // Fake server
  389. if os.Getenv("FAKE_SERVER") == "yes" {
  390. for {
  391. log.Info("Running fake server at " + apiURL + " until ^C is received")
  392. time.Sleep(30 * time.Second)
  393. }
  394. }
  395. // Run tests
  396. result := m.Run()
  397. // Stop server
  398. if err := server.Shutdown(context.Background()); err != nil {
  399. panic(err)
  400. }
  401. if err := database.Close(); err != nil {
  402. panic(err)
  403. }
  404. if err := os.RemoveAll(dir); err != nil {
  405. panic(err)
  406. }
  407. os.Exit(result)
  408. }
  409. func doGoodReqPaginated(
  410. path, order string,
  411. iterStruct Pendinger,
  412. appendIter func(res interface{}),
  413. ) error {
  414. var next uint64
  415. firstIte := true
  416. expectedTotal := 0
  417. totalReceived := 0
  418. for {
  419. // Calculate fromItem
  420. iterPath := path
  421. if !firstIte {
  422. iterPath += "&fromItem=" + strconv.Itoa(int(next))
  423. }
  424. // Call API to get this iteration items
  425. iterStruct = iterStruct.New()
  426. if err := doGoodReq(
  427. "GET", iterPath+"&order="+order, nil,
  428. iterStruct,
  429. ); err != nil {
  430. return tracerr.Wrap(err)
  431. }
  432. appendIter(iterStruct)
  433. // Keep iterating?
  434. remaining, lastID := iterStruct.GetPending()
  435. if remaining == 0 {
  436. break
  437. }
  438. if order == historydb.OrderDesc {
  439. next = lastID - 1
  440. } else {
  441. next = lastID + 1
  442. }
  443. // Check that the expected amount of items is consistent across iterations
  444. totalReceived += iterStruct.Len()
  445. if firstIte {
  446. firstIte = false
  447. expectedTotal = totalReceived + int(remaining)
  448. }
  449. if expectedTotal != totalReceived+int(remaining) {
  450. panic(fmt.Sprintf(
  451. "pagination error, totalReceived + remaining should be %d, but is %d",
  452. expectedTotal, totalReceived+int(remaining),
  453. ))
  454. }
  455. }
  456. return nil
  457. }
  458. func doGoodReq(method, path string, reqBody io.Reader, returnStruct interface{}) error {
  459. ctx := context.Background()
  460. client := &http.Client{}
  461. httpReq, err := http.NewRequest(method, path, reqBody)
  462. if err != nil {
  463. return tracerr.Wrap(err)
  464. }
  465. if reqBody != nil {
  466. httpReq.Header.Add("Content-Type", "application/json")
  467. }
  468. route, pathParams, err := tc.router.FindRoute(httpReq.Method, httpReq.URL)
  469. if err != nil {
  470. return tracerr.Wrap(err)
  471. }
  472. // Validate request against swagger spec
  473. requestValidationInput := &swagger.RequestValidationInput{
  474. Request: httpReq,
  475. PathParams: pathParams,
  476. Route: route,
  477. }
  478. if err := swagger.ValidateRequest(ctx, requestValidationInput); err != nil {
  479. return tracerr.Wrap(err)
  480. }
  481. // Do API call
  482. resp, err := client.Do(httpReq)
  483. if err != nil {
  484. return tracerr.Wrap(err)
  485. }
  486. if resp.Body == nil && returnStruct != nil {
  487. return tracerr.Wrap(errors.New("Nil body"))
  488. }
  489. //nolint
  490. defer resp.Body.Close()
  491. body, err := ioutil.ReadAll(resp.Body)
  492. if err != nil {
  493. return tracerr.Wrap(err)
  494. }
  495. if resp.StatusCode != 200 {
  496. return tracerr.Wrap(fmt.Errorf("%d response. Body: %s", resp.StatusCode, string(body)))
  497. }
  498. if returnStruct == nil {
  499. return nil
  500. }
  501. // Unmarshal body into return struct
  502. if err := json.Unmarshal(body, returnStruct); err != nil {
  503. log.Error("invalid json: " + string(body))
  504. log.Error(err)
  505. return tracerr.Wrap(err)
  506. }
  507. // log.Info(string(body))
  508. // Validate response against swagger spec
  509. responseValidationInput := &swagger.ResponseValidationInput{
  510. RequestValidationInput: requestValidationInput,
  511. Status: resp.StatusCode,
  512. Header: resp.Header,
  513. }
  514. responseValidationInput = responseValidationInput.SetBodyBytes(body)
  515. return swagger.ValidateResponse(ctx, responseValidationInput)
  516. }
  517. func doBadReq(method, path string, reqBody io.Reader, expectedResponseCode int) error {
  518. ctx := context.Background()
  519. client := &http.Client{}
  520. httpReq, _ := http.NewRequest(method, path, reqBody)
  521. route, pathParams, err := tc.router.FindRoute(httpReq.Method, httpReq.URL)
  522. if err != nil {
  523. return tracerr.Wrap(err)
  524. }
  525. // Validate request against swagger spec
  526. requestValidationInput := &swagger.RequestValidationInput{
  527. Request: httpReq,
  528. PathParams: pathParams,
  529. Route: route,
  530. }
  531. if err := swagger.ValidateRequest(ctx, requestValidationInput); err != nil {
  532. if expectedResponseCode != 400 {
  533. return tracerr.Wrap(err)
  534. }
  535. log.Warn("The request does not match the API spec")
  536. }
  537. // Do API call
  538. resp, err := client.Do(httpReq)
  539. if err != nil {
  540. return tracerr.Wrap(err)
  541. }
  542. if resp.Body == nil {
  543. return tracerr.Wrap(errors.New("Nil body"))
  544. }
  545. //nolint
  546. defer resp.Body.Close()
  547. body, err := ioutil.ReadAll(resp.Body)
  548. if err != nil {
  549. return tracerr.Wrap(err)
  550. }
  551. if resp.StatusCode != expectedResponseCode {
  552. return tracerr.Wrap(fmt.Errorf("Unexpected response code: %d. Body: %s", resp.StatusCode, string(body)))
  553. }
  554. // Validate response against swagger spec
  555. responseValidationInput := &swagger.ResponseValidationInput{
  556. RequestValidationInput: requestValidationInput,
  557. Status: resp.StatusCode,
  558. Header: resp.Header,
  559. }
  560. responseValidationInput = responseValidationInput.SetBodyBytes(body)
  561. return swagger.ValidateResponse(ctx, responseValidationInput)
  562. }
  563. // test helpers
  564. func getTimestamp(blockNum int64, blocks []common.Block) time.Time {
  565. for i := 0; i < len(blocks); i++ {
  566. if blocks[i].Num == blockNum {
  567. return blocks[i].Timestamp
  568. }
  569. }
  570. panic("timesamp not found")
  571. }
  572. func getTokenByID(id common.TokenID, tokens []historydb.TokenWithUSD) historydb.TokenWithUSD {
  573. for i := 0; i < len(tokens); i++ {
  574. if tokens[i].TokenID == id {
  575. return tokens[i]
  576. }
  577. }
  578. panic("token not found")
  579. }
  580. func getTokenByIdx(idx common.Idx, tokens []historydb.TokenWithUSD, accs []common.Account) historydb.TokenWithUSD {
  581. for _, acc := range accs {
  582. if idx == acc.Idx {
  583. return getTokenByID(acc.TokenID, tokens)
  584. }
  585. }
  586. panic("token not found")
  587. }
  588. func getAccountByIdx(idx common.Idx, accs []common.Account) *common.Account {
  589. for _, acc := range accs {
  590. if acc.Idx == idx {
  591. return &acc
  592. }
  593. }
  594. panic("account not found")
  595. }
  596. func getBlockByNum(ethBlockNum int64, blocks []common.Block) common.Block {
  597. for _, b := range blocks {
  598. if b.Num == ethBlockNum {
  599. return b
  600. }
  601. }
  602. panic("block not found")
  603. }
  604. func getCoordinatorByBidder(bidder ethCommon.Address, coordinators []historydb.CoordinatorAPI) historydb.CoordinatorAPI {
  605. for _, c := range coordinators {
  606. if c.Bidder == bidder {
  607. return c
  608. }
  609. }
  610. panic("coordinator not found")
  611. }