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.

498 lines
20 KiB

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 txselector
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "strconv"
  7. "testing"
  8. "time"
  9. ethCommon "github.com/ethereum/go-ethereum/common"
  10. ethCrypto "github.com/ethereum/go-ethereum/crypto"
  11. "github.com/hermeznetwork/hermez-node/common"
  12. dbUtils "github.com/hermeznetwork/hermez-node/db"
  13. "github.com/hermeznetwork/hermez-node/db/historydb"
  14. "github.com/hermeznetwork/hermez-node/db/l2db"
  15. "github.com/hermeznetwork/hermez-node/db/statedb"
  16. "github.com/hermeznetwork/hermez-node/log"
  17. "github.com/hermeznetwork/hermez-node/test"
  18. "github.com/hermeznetwork/hermez-node/test/til"
  19. "github.com/hermeznetwork/hermez-node/test/txsets"
  20. "github.com/hermeznetwork/hermez-node/txprocessor"
  21. "github.com/jmoiron/sqlx"
  22. "github.com/stretchr/testify/assert"
  23. "github.com/stretchr/testify/require"
  24. )
  25. func initTest(t *testing.T, chainID uint16, hermezContractAddr ethCommon.Address, coordUser *til.User) *TxSelector {
  26. pass := os.Getenv("POSTGRES_PASS")
  27. db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
  28. require.NoError(t, err)
  29. l2DB := l2db.NewL2DB(db, 10, 100, 24*time.Hour, nil)
  30. dir, err := ioutil.TempDir("", "tmpdb")
  31. require.NoError(t, err)
  32. defer assert.NoError(t, os.RemoveAll(dir))
  33. syncStateDB, err := statedb.NewStateDB(dir, 128, statedb.TypeTxSelector, 0)
  34. require.NoError(t, err)
  35. txselDir, err := ioutil.TempDir("", "tmpTxSelDB")
  36. require.NoError(t, err)
  37. defer assert.NoError(t, os.RemoveAll(dir))
  38. // use Til Coord keys for tests compatibility
  39. coordAccount := &CoordAccount{
  40. Addr: coordUser.Addr,
  41. BJJ: coordUser.BJJ.Public().Compress(),
  42. AccountCreationAuth: nil,
  43. }
  44. fmt.Printf("%v", coordAccount)
  45. auth := common.AccountCreationAuth{
  46. EthAddr: coordUser.Addr,
  47. BJJ: coordUser.BJJ.Public().Compress(),
  48. }
  49. err = auth.Sign(func(hash []byte) ([]byte, error) {
  50. return ethCrypto.Sign(hash, coordUser.EthSk)
  51. }, chainID, hermezContractAddr)
  52. assert.NoError(t, err)
  53. coordAccount.AccountCreationAuth = auth.Signature
  54. txsel, err := NewTxSelector(coordAccount, txselDir, syncStateDB, l2DB)
  55. require.NoError(t, err)
  56. test.WipeDB(txsel.l2db.DB())
  57. return txsel
  58. }
  59. func addAccCreationAuth(t *testing.T, tc *til.Context, txsel *TxSelector, chainID uint16, hermezContractAddr ethCommon.Address, username string) []byte {
  60. user := tc.Users[username]
  61. auth := &common.AccountCreationAuth{
  62. EthAddr: user.Addr,
  63. BJJ: user.BJJ.Public().Compress(),
  64. }
  65. err := auth.Sign(func(hash []byte) ([]byte, error) {
  66. return ethCrypto.Sign(hash, user.EthSk)
  67. }, chainID, hermezContractAddr)
  68. assert.NoError(t, err)
  69. err = txsel.l2db.AddAccountCreationAuth(auth)
  70. assert.NoError(t, err)
  71. return auth.Signature
  72. }
  73. func addL2Txs(t *testing.T, txsel *TxSelector, poolL2Txs []common.PoolL2Tx) {
  74. for i := 0; i < len(poolL2Txs); i++ {
  75. err := txsel.l2db.AddTxTest(&poolL2Txs[i])
  76. if err != nil {
  77. log.Error(err)
  78. }
  79. require.NoError(t, err)
  80. }
  81. }
  82. func addTokens(t *testing.T, tc *til.Context, db *sqlx.DB) {
  83. var tokens []common.Token
  84. for i := 0; i < int(tc.LastRegisteredTokenID); i++ {
  85. tokens = append(tokens, common.Token{
  86. TokenID: common.TokenID(i + 1),
  87. EthBlockNum: 1,
  88. EthAddr: ethCommon.BytesToAddress([]byte{byte(i + 1)}),
  89. Name: strconv.Itoa(i),
  90. Symbol: strconv.Itoa(i),
  91. Decimals: 18,
  92. })
  93. }
  94. hdb := historydb.NewHistoryDB(db, nil)
  95. assert.NoError(t, hdb.AddBlock(&common.Block{
  96. Num: 1,
  97. }))
  98. assert.NoError(t, hdb.AddTokens(tokens))
  99. }
  100. func checkBalance(t *testing.T, tc *til.Context, txsel *TxSelector, username string, tokenid int, expected string) {
  101. // Accounts.Idx does not match with the TxSelector tests as we are not
  102. // using the Til L1CoordinatorTxs (as are generated by the TxSelector
  103. // itself when processing the txs, so the Idxs does not match the Til
  104. // idxs). But the Idx is obtained through StateDB.GetIdxByEthAddrBJJ
  105. user := tc.Users[username]
  106. idx, err := txsel.localAccountsDB.GetIdxByEthAddrBJJ(user.Addr, user.BJJ.Public().Compress(), common.TokenID(tokenid))
  107. require.NoError(t, err)
  108. checkBalanceByIdx(t, txsel, idx, expected)
  109. }
  110. func checkBalanceByIdx(t *testing.T, txsel *TxSelector, idx common.Idx, expected string) {
  111. acc, err := txsel.localAccountsDB.GetAccount(idx)
  112. require.NoError(t, err)
  113. assert.Equal(t, expected, acc.Balance.String())
  114. }
  115. // checkSortedByNonce takes as input testAccNonces map, and the array of
  116. // common.PoolL2Txs, and checks if the nonces correspond to the accumulated
  117. // values of the map. Also increases the Nonces computed on the map.
  118. func checkSortedByNonce(t *testing.T, testAccNonces map[common.Idx]common.Nonce, txs []common.PoolL2Tx) {
  119. for _, tx := range txs {
  120. assert.True(t, testAccNonces[tx.FromIdx] == tx.Nonce,
  121. fmt.Sprintf("Idx: %d, expected: %d, tx.Nonce: %d",
  122. tx.FromIdx, testAccNonces[tx.FromIdx], tx.Nonce))
  123. testAccNonces[tx.FromIdx] = testAccNonces[tx.FromIdx] + 1
  124. }
  125. }
  126. func TestGetL2TxSelectionMinimumFlow0(t *testing.T) {
  127. chainID := uint16(0)
  128. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  129. // generate test transactions, the L1CoordinatorTxs generated by Til
  130. // will be ignored at this test, as will be the TxSelector who
  131. // generates them when needed
  132. blocks, err := tc.GenerateBlocks(txsets.SetBlockchainMinimumFlow0)
  133. assert.NoError(t, err)
  134. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  135. txsel := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
  136. // restart nonces of TilContext, as will be set by generating directly
  137. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  138. tc.RestartNonces()
  139. testAccNonces := make(map[common.Idx]common.Nonce)
  140. // add tokens to HistoryDB to avoid breaking FK constrains
  141. addTokens(t, tc, txsel.l2db.DB())
  142. tpc := txprocessor.Config{
  143. NLevels: 16,
  144. MaxFeeTx: 10,
  145. MaxTx: 20,
  146. MaxL1Tx: 10,
  147. ChainID: chainID,
  148. }
  149. selectionConfig := &SelectionConfig{
  150. MaxL1UserTxs: 5,
  151. TxProcessorConfig: tpc,
  152. }
  153. // coordIdxs, accAuths, l1UserTxs, l1CoordTxs, l2Txs, err
  154. log.Debug("block:0 batch:1")
  155. l1UserTxs := []common.L1Tx{}
  156. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  157. require.NoError(t, err)
  158. assert.Equal(t, 0, len(oL1UserTxs))
  159. assert.Equal(t, 0, len(oL1CoordTxs))
  160. assert.Equal(t, 0, len(oL2Txs))
  161. assert.Equal(t, common.BatchNum(1), txsel.localAccountsDB.CurrentBatch())
  162. assert.Equal(t, common.Idx(255), txsel.localAccountsDB.CurrentIdx())
  163. log.Debug("block:0 batch:2")
  164. l1UserTxs = []common.L1Tx{}
  165. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  166. require.NoError(t, err)
  167. assert.Equal(t, 0, len(oL1UserTxs))
  168. assert.Equal(t, 0, len(oL1CoordTxs))
  169. assert.Equal(t, 0, len(oL2Txs))
  170. assert.Equal(t, common.BatchNum(2), txsel.localAccountsDB.CurrentBatch())
  171. assert.Equal(t, common.Idx(255), txsel.localAccountsDB.CurrentIdx())
  172. log.Debug("block:0 batch:3")
  173. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[2].Batch.ForgeL1TxsNum])
  174. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  175. require.NoError(t, err)
  176. assert.Equal(t, 2, len(oL1UserTxs))
  177. assert.Equal(t, 0, len(oL1CoordTxs))
  178. assert.Equal(t, 0, len(oL2Txs))
  179. assert.Equal(t, common.BatchNum(3), txsel.localAccountsDB.CurrentBatch())
  180. assert.Equal(t, common.Idx(257), txsel.localAccountsDB.CurrentIdx())
  181. checkBalance(t, tc, txsel, "A", 0, "500")
  182. checkBalance(t, tc, txsel, "C", 1, "0")
  183. log.Debug("block:0 batch:4")
  184. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[3].Batch.ForgeL1TxsNum])
  185. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  186. require.NoError(t, err)
  187. assert.Equal(t, 1, len(oL1UserTxs))
  188. assert.Equal(t, 0, len(oL1CoordTxs))
  189. assert.Equal(t, 0, len(oL2Txs))
  190. assert.Equal(t, common.BatchNum(4), txsel.localAccountsDB.CurrentBatch())
  191. assert.Equal(t, common.Idx(258), txsel.localAccountsDB.CurrentIdx())
  192. checkBalance(t, tc, txsel, "A", 0, "500")
  193. checkBalance(t, tc, txsel, "A", 1, "500")
  194. checkBalance(t, tc, txsel, "C", 1, "0")
  195. log.Debug("block:0 batch:5")
  196. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[4].Batch.ForgeL1TxsNum])
  197. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  198. require.NoError(t, err)
  199. assert.Equal(t, 0, len(oL1UserTxs))
  200. assert.Equal(t, 0, len(oL1CoordTxs))
  201. assert.Equal(t, 0, len(oL2Txs))
  202. assert.Equal(t, common.BatchNum(5), txsel.localAccountsDB.CurrentBatch())
  203. assert.Equal(t, common.Idx(258), txsel.localAccountsDB.CurrentIdx())
  204. checkBalance(t, tc, txsel, "A", 0, "500")
  205. checkBalance(t, tc, txsel, "A", 1, "500")
  206. checkBalance(t, tc, txsel, "C", 1, "0")
  207. log.Debug("block:0 batch:6")
  208. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[5].Batch.ForgeL1TxsNum])
  209. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  210. require.NoError(t, err)
  211. assert.Equal(t, 1, len(oL1UserTxs))
  212. assert.Equal(t, 0, len(oL1CoordTxs))
  213. assert.Equal(t, 0, len(oL2Txs))
  214. assert.Equal(t, common.BatchNum(6), txsel.localAccountsDB.CurrentBatch())
  215. assert.Equal(t, common.Idx(259), txsel.localAccountsDB.CurrentIdx())
  216. checkBalance(t, tc, txsel, "A", 0, "600")
  217. checkBalance(t, tc, txsel, "A", 1, "500")
  218. checkBalance(t, tc, txsel, "B", 0, "400")
  219. checkBalance(t, tc, txsel, "C", 1, "0")
  220. log.Debug("block:0 batch:7")
  221. // simulate the PoolL2Txs of the batch7
  222. batchPoolL2 := `
  223. Type: PoolL2
  224. PoolTransferToEthAddr(1) A-B: 200 (126)
  225. PoolTransferToEthAddr(0) B-C: 100 (126)`
  226. poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  227. require.NoError(t, err)
  228. // add AccountCreationAuths that will be used at the next batch
  229. accAuthSig0 := addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "B")
  230. accAuthSig1 := addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "C")
  231. // add the PoolL2Txs to the l2DB
  232. addL2Txs(t, txsel, poolL2Txs)
  233. // check signatures of L2Txs from the L2DB (to check that the
  234. // parameters of the PoolL2Tx match the original parameters signed
  235. // before inserting it to the L2DB)
  236. l2TxsFromDB, err := txsel.l2db.GetPendingTxs()
  237. require.NoError(t, err)
  238. assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
  239. assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
  240. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
  241. coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  242. require.NoError(t, err)
  243. assert.Equal(t, []common.Idx{261, 262}, coordIdxs)
  244. assert.Equal(t, txsel.coordAccount.AccountCreationAuth, accAuths[0])
  245. assert.Equal(t, txsel.coordAccount.AccountCreationAuth, accAuths[1])
  246. assert.Equal(t, accAuthSig0, accAuths[2])
  247. assert.Equal(t, accAuthSig1, accAuths[3])
  248. assert.Equal(t, 1, len(oL1UserTxs))
  249. assert.Equal(t, 4, len(oL1CoordTxs))
  250. assert.Equal(t, 2, len(oL2Txs))
  251. assert.Equal(t, len(oL1CoordTxs), len(accAuths))
  252. assert.Equal(t, common.BatchNum(7), txsel.localAccountsDB.CurrentBatch())
  253. assert.Equal(t, common.Idx(264), txsel.localAccountsDB.CurrentIdx())
  254. checkBalanceByIdx(t, txsel, 261, "20") // CoordIdx for TokenID=1
  255. checkBalanceByIdx(t, txsel, 262, "10") // CoordIdx for TokenID=0
  256. checkBalance(t, tc, txsel, "A", 0, "600")
  257. checkBalance(t, tc, txsel, "A", 1, "280")
  258. checkBalance(t, tc, txsel, "B", 0, "290")
  259. checkBalance(t, tc, txsel, "B", 1, "200")
  260. checkBalance(t, tc, txsel, "C", 0, "100")
  261. checkBalance(t, tc, txsel, "D", 0, "800")
  262. checkSortedByNonce(t, testAccNonces, oL2Txs)
  263. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs), txsel.localAccountsDB.CurrentBatch())
  264. require.NoError(t, err)
  265. log.Debug("block:0 batch:8")
  266. // simulate the PoolL2Txs of the batch8
  267. batchPoolL2 = `
  268. Type: PoolL2
  269. PoolTransfer(0) A-B: 100 (126)
  270. PoolTransfer(0) C-A: 50 (126)
  271. PoolTransfer(1) B-C: 100 (126)
  272. PoolExit(0) A: 100 (126)`
  273. poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  274. require.NoError(t, err)
  275. addL2Txs(t, txsel, poolL2Txs)
  276. // check signatures of L2Txs from the L2DB (to check that the
  277. // parameters of the PoolL2Tx match the original parameters signed
  278. // before inserting it to the L2DB)
  279. l2TxsFromDB, err = txsel.l2db.GetPendingTxs()
  280. require.NoError(t, err)
  281. assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
  282. assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["C"].BJJ.Public().Compress()))
  283. assert.True(t, l2TxsFromDB[2].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
  284. assert.True(t, l2TxsFromDB[3].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
  285. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
  286. coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  287. require.NoError(t, err)
  288. assert.Equal(t, []common.Idx{261, 262}, coordIdxs)
  289. assert.Equal(t, 0, len(accAuths))
  290. assert.Equal(t, 0, len(oL1UserTxs))
  291. assert.Equal(t, 0, len(oL1CoordTxs))
  292. assert.Equal(t, 4, len(oL2Txs))
  293. assert.Equal(t, len(oL1CoordTxs), len(accAuths))
  294. assert.Equal(t, common.BatchNum(8), txsel.localAccountsDB.CurrentBatch())
  295. assert.Equal(t, common.Idx(264), txsel.localAccountsDB.CurrentIdx())
  296. checkBalanceByIdx(t, txsel, 261, "30")
  297. checkBalanceByIdx(t, txsel, 262, "35")
  298. checkBalance(t, tc, txsel, "A", 0, "430")
  299. checkBalance(t, tc, txsel, "A", 1, "280")
  300. checkBalance(t, tc, txsel, "B", 0, "390")
  301. checkBalance(t, tc, txsel, "B", 1, "90")
  302. checkBalance(t, tc, txsel, "C", 0, "45")
  303. checkBalance(t, tc, txsel, "C", 1, "100")
  304. checkBalance(t, tc, txsel, "D", 0, "800")
  305. checkSortedByNonce(t, testAccNonces, oL2Txs)
  306. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs), txsel.localAccountsDB.CurrentBatch())
  307. require.NoError(t, err)
  308. log.Debug("(batch9)block:1 batch:1")
  309. // simulate the PoolL2Txs of the batch9
  310. batchPoolL2 = `
  311. Type: PoolL2
  312. PoolTransfer(0) D-A: 300 (126)
  313. PoolTransfer(0) B-D: 100 (126)
  314. `
  315. poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  316. require.NoError(t, err)
  317. addL2Txs(t, txsel, poolL2Txs)
  318. // check signatures of L2Txs from the L2DB (to check that the
  319. // parameters of the PoolL2Tx match the original parameters signed
  320. // before inserting it to the L2DB)
  321. l2TxsFromDB, err = txsel.l2db.GetPendingTxs()
  322. require.NoError(t, err)
  323. assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["D"].BJJ.Public().Compress()))
  324. assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
  325. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
  326. coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  327. require.NoError(t, err)
  328. assert.Equal(t, []common.Idx{262}, coordIdxs)
  329. assert.Equal(t, 0, len(accAuths))
  330. assert.Equal(t, 4, len(oL1UserTxs))
  331. assert.Equal(t, 0, len(oL1CoordTxs))
  332. assert.Equal(t, 2, len(oL2Txs))
  333. assert.Equal(t, len(oL1CoordTxs), len(accAuths))
  334. assert.Equal(t, common.BatchNum(9), txsel.localAccountsDB.CurrentBatch())
  335. assert.Equal(t, common.Idx(264), txsel.localAccountsDB.CurrentIdx())
  336. checkBalanceByIdx(t, txsel, 261, "30")
  337. checkBalanceByIdx(t, txsel, 262, "75")
  338. checkBalance(t, tc, txsel, "A", 0, "730")
  339. checkBalance(t, tc, txsel, "A", 1, "280")
  340. checkBalance(t, tc, txsel, "B", 0, "380")
  341. checkBalance(t, tc, txsel, "B", 1, "90")
  342. checkBalance(t, tc, txsel, "C", 0, "845")
  343. checkBalance(t, tc, txsel, "C", 1, "100")
  344. checkBalance(t, tc, txsel, "D", 0, "470")
  345. checkSortedByNonce(t, testAccNonces, oL2Txs)
  346. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs), txsel.localAccountsDB.CurrentBatch())
  347. require.NoError(t, err)
  348. }
  349. func TestPoolL2TxsWithoutEnoughBalance(t *testing.T) {
  350. set := `
  351. Type: Blockchain
  352. CreateAccountDeposit(0) Coord: 0
  353. CreateAccountDeposit(0) A: 100
  354. CreateAccountDeposit(0) B: 100
  355. > batchL1 // freeze L1User{1}
  356. > batchL1 // forge L1User{1}
  357. > block
  358. `
  359. chainID := uint16(0)
  360. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  361. // generate test transactions, the L1CoordinatorTxs generated by Til
  362. // will be ignored at this test, as will be the TxSelector who
  363. // generates them when needed
  364. blocks, err := tc.GenerateBlocks(set)
  365. assert.NoError(t, err)
  366. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  367. txsel := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
  368. // restart nonces of TilContext, as will be set by generating directly
  369. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  370. tc.RestartNonces()
  371. tpc := txprocessor.Config{
  372. NLevels: 16,
  373. MaxFeeTx: 10,
  374. MaxTx: 20,
  375. MaxL1Tx: 10,
  376. ChainID: chainID,
  377. }
  378. selectionConfig := &SelectionConfig{
  379. MaxL1UserTxs: 5,
  380. TxProcessorConfig: tpc,
  381. }
  382. // batch1
  383. l1UserTxs := []common.L1Tx{}
  384. _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  385. require.NoError(t, err)
  386. expectedTxID0 := "0x0248bae02b5c8c3847d312bfac3a33ae790616e888f2f711f22aeaff007cde92c2" // 1st TransferToEthAddr
  387. expectedTxID1 := "0x0249af018311a393c337ab9174ca2466cba489e49942b4ca4e5c530903671c4aef" // 1st Exit
  388. expectedTxID2 := "0x0228b93a261a0cdc62f35588c03bd179d31a0807c28afffdb6a7aaf0c4f017e4cf" // 2nd TransferToEthAddr
  389. // batch2
  390. // prepare the PoolL2Txs
  391. batchPoolL2 := `
  392. Type: PoolL2
  393. PoolTransferToEthAddr(0) A-B: 100 (126)
  394. PoolExit(0) B: 100 (126)`
  395. poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  396. require.NoError(t, err)
  397. // add the PoolL2Txs to the l2DB
  398. addL2Txs(t, txsel, poolL2Txs)
  399. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  400. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  401. require.NoError(t, err)
  402. assert.Equal(t, 3, len(oL1UserTxs))
  403. assert.Equal(t, 0, len(oL1CoordTxs))
  404. assert.Equal(t, 0, len(oL2Txs)) // should be 0 as the 2 PoolL2Txs does not have enough funds
  405. assert.Equal(t, 2, len(discardedL2Txs))
  406. assert.Equal(t, expectedTxID0, discardedL2Txs[0].TxID.String())
  407. assert.Equal(t, expectedTxID1, discardedL2Txs[1].TxID.String())
  408. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs), txsel.localAccountsDB.CurrentBatch())
  409. require.NoError(t, err)
  410. // as the PoolL2Txs have not been really processed, restart nonces
  411. tc.RestartNonces()
  412. // batch3
  413. // NOTE: this batch will result with 1 L2Tx, as the PoolExit tx is not
  414. // possible, as the PoolTransferToEthAddr is not processed yet when
  415. // checking availability of PoolExit. This, in a near-future iteration
  416. // of the TxSelector will return the 2 transactions as valid and
  417. // selected, as the TxSelector will handle this kind of combinations.
  418. batchPoolL2 = `
  419. Type: PoolL2
  420. PoolTransferToEthAddr(0) A-B: 50 (126)`
  421. poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  422. require.NoError(t, err)
  423. addL2Txs(t, txsel, poolL2Txs)
  424. l1UserTxs = []common.L1Tx{}
  425. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  426. require.NoError(t, err)
  427. assert.Equal(t, 0, len(oL1UserTxs))
  428. assert.Equal(t, 0, len(oL1CoordTxs))
  429. assert.Equal(t, 1, len(oL2Txs)) // see 'NOTE' at the beginning of 'batch3' of this test
  430. assert.Equal(t, 2, len(discardedL2Txs))
  431. assert.Equal(t, expectedTxID2, oL2Txs[0].TxID.String())
  432. assert.Equal(t, expectedTxID0, discardedL2Txs[0].TxID.String())
  433. assert.Equal(t, expectedTxID1, discardedL2Txs[1].TxID.String())
  434. assert.Equal(t, common.TxTypeTransferToEthAddr, oL2Txs[0].Type)
  435. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs), txsel.localAccountsDB.CurrentBatch())
  436. require.NoError(t, err)
  437. // batch4
  438. // make the selection of another batch, which should include the
  439. // initial PoolExit, which now is valid as B has enough Balance
  440. l1UserTxs = []common.L1Tx{}
  441. _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err = txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  442. require.NoError(t, err)
  443. assert.Equal(t, 0, len(oL1UserTxs))
  444. assert.Equal(t, 0, len(oL1CoordTxs))
  445. assert.Equal(t, 1, len(oL2Txs))
  446. assert.Equal(t, 1, len(discardedL2Txs))
  447. assert.Equal(t, expectedTxID1, oL2Txs[0].TxID.String()) // the Exit that was not accepted at the batch2
  448. assert.Equal(t, expectedTxID0, discardedL2Txs[0].TxID.String())
  449. assert.Equal(t, common.TxTypeExit, oL2Txs[0].Type)
  450. err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs), txsel.localAccountsDB.CurrentBatch())
  451. require.NoError(t, err)
  452. }